diff options
131 files changed, 10638 insertions, 6786 deletions
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines index 45577117c2..57da6aadeb 100644 --- a/Documentation/CodingGuidelines +++ b/Documentation/CodingGuidelines @@ -76,11 +76,19 @@ For shell scripts specifically (not exhaustive): - We do not use Process Substitution <(list) or >(list). + - Do not write control structures on a single line with semicolon. + "then" should be on the next line for if statements, and "do" + should be on the next line for "while" and "for". + - We prefer "test" over "[ ... ]". - We do not write the noiseword "function" in front of shell functions. + - We prefer a space between the function name and the parentheses. The + opening "{" should also be on the same line. + E.g.: my_function () { + - As to use of grep, stick to a subset of BRE (namely, no \{m,n\}, [::], [==], nor [..]) for portability. diff --git a/Documentation/Makefile b/Documentation/Makefile index 063fa696c9..cf5916fe8b 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -344,4 +344,7 @@ require-htmlrepo:: quick-install-html: require-htmlrepo '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REPO) $(DESTDIR)$(htmldir) +print-man1: + @for i in $(MAN1_TXT); do echo $$i; done + .PHONY: FORCE diff --git a/Documentation/RelNotes/1.7.11.4.txt b/Documentation/RelNotes/1.7.11.4.txt new file mode 100644 index 0000000000..3a640c2d4d --- /dev/null +++ b/Documentation/RelNotes/1.7.11.4.txt @@ -0,0 +1,31 @@ +Git v1.7.11.4 Release Notes +=========================== + +Fixes since v1.7.11.3 +--------------------- + + * "$GIT_DIR/COMMIT_EDITMSG" file that is used to hold the commit log + message user edits was not documented. + + * The advise() function did not use varargs correctly to format + its message. + + * When "git am" failed, old timers knew to check .git/rebase-apply/patch + to see what went wrong, but we never told the users about it. + + * "git commit-tree" learned a more natural "-p <parent> <tree>" order + of arguments long time ago, but recently forgot it by mistake. + + * "git diff --no-ext-diff" did not output anything for a typechange + filepair when GIT_EXTERNAL_DIFF is in effect. + + * In 1.7.9 era, we taught "git rebase" about the raw timestamp format + but we did not teach the same trick to "filter-branch", which rolled + a similar logic on its own. + + * When "git submodule add" clones a submodule repository, it can get + confused where to store the resulting submodule repository in the + superproject's .git/ directory when there is a symbolic link in the + path to the current directory. + +Also contains minor typofixes and documentation updates. diff --git a/Documentation/RelNotes/1.7.11.5.txt b/Documentation/RelNotes/1.7.11.5.txt new file mode 100644 index 0000000000..0a2ed855c5 --- /dev/null +++ b/Documentation/RelNotes/1.7.11.5.txt @@ -0,0 +1,36 @@ +Git v1.7.11.5 Release Notes +=========================== + +Fixes since v1.7.11.4 +--------------------- + + * The Makefile rule to create assembly output (primarily for + debugging purposes) did not create it next to the source. + + * The code to avoid mistaken attempt to add the object directory + itself as its own alternate could read beyond end of a string while + comparison. + + * On some architectures, "block-sha1" did not compile correctly + when compilers inferred alignment guarantees from our source we + did not intend to make. + + * When talking to a remote running ssh on IPv6 enabled host, whose + address is spelled as "[HOST]:PORT", we did not parse the address + correctly and failed to connect. + + * git-blame.el (in compat/) have been updated to use Elisp more + correctly. + + * "git checkout <branchname>" to come back from a detached HEAD state + incorrectly computed reachability of the detached HEAD, resulting + in unnecessary warnings. + + * "git mergetool" did not support --tool-help option to give the list + of supported backends, like "git difftool" does. + + * "git grep" stopped spawning an external "grep" long time ago, but a + duplicated test to check internal and external "grep" was left + behind. + +Also contains minor typofixes and documentation updates. diff --git a/Documentation/RelNotes/1.7.11.6.txt b/Documentation/RelNotes/1.7.11.6.txt new file mode 100644 index 0000000000..e548a59824 --- /dev/null +++ b/Documentation/RelNotes/1.7.11.6.txt @@ -0,0 +1,34 @@ +Git v1.7.11.6 Release Notes +=========================== + +Fixes since v1.7.11.5 +--------------------- + +This is primarily documentation and low-impact code clarification. + + - "ciabot" script (in contrib/) has been updated with extensive + documentation. + + - The "--rebase" option to "git pull" can be abbreviated to "-r", + but we didn't document it. + + - It was generally understood that "--long-option"s to many of our + subcommands can be abbreviated to the unique prefix, but it was not + easy to find it described for new readers of the documentation set. + + - The "--topo-order", "--date-order" (and the lack of either means + the default order) options to "rev-list" and "log" family of + commands were poorly described in the documentation. + + - Older parts of the documentation described as if having a regular + file in .git/refs/ hierarchy were the only way to have branches and + tags, which is not true for quite some time. + + - A utility shell function test_seq has been added as a replacement + for the 'seq' utility found on some platforms. + + - Fallback 'getpass' implementation made unportable use of stdio API. + + - "git commit --amend" let the user edit the log message and then + died when the human-readable committer name was given + insufficiently by getpwent(3). diff --git a/Documentation/RelNotes/1.7.12.txt b/Documentation/RelNotes/1.7.12.txt index 904561de18..010d8c7de4 100644 --- a/Documentation/RelNotes/1.7.12.txt +++ b/Documentation/RelNotes/1.7.12.txt @@ -51,10 +51,6 @@ UI, Workflows & Features read. The error message in this case was updated to give better hints to the user. - * git native protocol agents learned to show software version over - the wire, so that the server log can be examined to see the vintage - distribution of clients. - * "git help -w $cmd" can show HTML version of documentation for "git-$cmd" by setting help.htmlpath to somewhere other than the default location where the build procedure installs them locally; @@ -117,6 +113,9 @@ Performance, Internal Implementation, etc. (please report possible regressions) cycles after showing the first change to find the next one, only to discard it. + * "git svn" got a large-looking code reorganization at the last + minute before the code freeze. + Also contains minor documentation updates and code clean-ups. @@ -128,42 +127,10 @@ Unless otherwise noted, all the fixes since v1.7.11 in the maintenance releases are contained in this release (see release notes to them for details). - * "git mergetool" did not support --tool-help option to give the list - of supported backends, like "git difftool" does. - (merge 109859e jc/mergetool-tool-help later to maint). - - * "$GIT_DIR/COMMIT_EDITMSG" file that is used to hold the commit log - message user edits was not documented. - (merge 41f597d jk/maint-commit-document-editmsg later to maint). + * "git submodule add" was confused when the superproject did not have + its repository in its usual place in the working tree and GIT_DIR + and GIT_WORK_TREE was used to access it. * "git commit --amend" let the user edit the log message and then died when the human-readable committer name was given insufficiently by getpwent(3). - (merge f20f387 jk/maint-commit-check-committer-early later to maint). - - * The advise() function did not use varargs correctly to format - its message. - (merge 447b99c jk/maint-advise-vaddf later to maint). - - * "git commit-tree" learned a more natural "-p <parent> <tree>" order - of arguments long time ago, but recently forgot it by mistake. - (merge 4b7518a kk/maint-commit-tree later to maint). - - * "git diff --no-ext-diff" did not output anything for a typechange - filepair when GIT_EXTERNAL_DIFF is in effect. - (merge c12f82a jv/maint-no-ext-diff later to maint). - - * When "git am" failed, old timers knew to check .git/rebase-apply/patch - to see what went wrong, but we never told the users about it. - (merge 14bf2d5 pg/maint-1.7.9-am-where-is-patch later to maint). - - * When "git submodule add" clones a submodule repository, it can get - confused where to store the resulting submodule repository in the - superproject's .git/ directory when there is a symbolic link in the - path to the current directory. - (merge 6eafa6d jl/maint-1.7.10-recurse-submodules-with-symlink later to maint). - - * In 1.7.9 era, we taught "git rebase" about the raw timestamp format - but we did not teach the same trick to "filter-branch", which rolled - a similar logic on its own. - (merge 44b85e89 jc/maint-filter-branch-epoch-date later to maint). diff --git a/Documentation/RelNotes/1.8.0.txt b/Documentation/RelNotes/1.8.0.txt new file mode 100644 index 0000000000..2f41e992d8 --- /dev/null +++ b/Documentation/RelNotes/1.8.0.txt @@ -0,0 +1,81 @@ +Git v1.8.0 Release Notes +======================== + +Backward compatibility notes +---------------------------- + +In the next major release, we will change the behaviour of the "git +push" command. When "git push [$there]" does not say what to push, we +have used the traditional "matching" semantics (all your branches were +sent to the remote as long as there already are branches of the same +name over there). We will use the "simple" semantics, that pushes the +current branch to the branch with the same name only when the current +branch is set to integrate with that remote branch. There is a user +preference configuration variable "push.default" to change this, and +"git push" will warn about the upcoming change until you set this +variable. + + +Updates since v1.7.12 +--------------------- + +UI, Workflows & Features + + * "git difftool --dir-diff" learned to use symbolic links to prepare + temporary copy of the working tree when available. + + * "git grep" learned to use a non-standard pattern type by default if + a configuration variable tells it to. + +Foreign Interface + + * "git svn" has been updated to work with SVN 1.7. + + +Performance, Internal Implementation, etc. (please report possible regressions) + + * The "check-docs" build target has been updated and greatly + simplified. + + * The documentation in the TeXinfo format was using indented output + for materials meant to be examples that are better typeset in + monospace. + +Also contains minor documentation updates and code clean-ups. + + +Fixes since v1.7.12 +------------------- + +Unless otherwise noted, all the fixes since v1.7.12 in the +maintenance track are contained in this release (see release notes +to them for details). + + + * When "git push" triggered the automatic gc on the receiving end, a + message from "git prune" that said it was removing cruft leaked to + the standard output, breaking the communication protocol. + (merge 4b7f2fa bc/receive-pack-stdout-protection later to maint). + + * "git diff" had a confusion between taking data from a path in the + working tree and taking data from an object that happens to have + name 0{40} recorded in a tree. + (merge c479d14 jk/maint-null-in-trees later to maint). + + * The output from "git diff -B" for a file that ends with an + incomplete line did not put "\ No newline..." on a line of its own. + + * "git send-email" did not unquote encoded words that appear on the + header correctly, and lost "_" from strings. + (merge b622d4d tr/maint-send-email-2047 later to maint). + + * When the user gives an argument that can be taken as both a + revision name and a pathname without disambiguating with "--", we + used to give a help message "Use '--' to separate". The message + has been clarified to show where that '--' goes on the command + line. + (merge 4d4b573 mm/die-with-dashdash-help later to maint). + + * "gitweb" when used with PATH_INFO failed to notice directories with + SP (and other characters that need URL-style quoting) in them. + (merge cacfc09 js/gitweb-path-info-unquote later to maint). diff --git a/Documentation/asciidoc.conf b/Documentation/asciidoc.conf index a26d245ab4..1273a85c8a 100644 --- a/Documentation/asciidoc.conf +++ b/Documentation/asciidoc.conf @@ -36,7 +36,7 @@ ifndef::git-asciidoc-no-roff[] # v1.72 breaks with this because it replaces dots not in roff requests. [listingblock] <example><title>{title}</title> -<literallayout> +<literallayout class="monospaced"> ifdef::doctype-manpage[] .ft C endif::doctype-manpage[] @@ -53,7 +53,7 @@ ifdef::doctype-manpage[] # The following two small workarounds insert a simple paragraph after screen [listingblock] <example><title>{title}</title> -<literallayout> +<literallayout class="monospaced"> | </literallayout><simpara></simpara> {title#}</example> diff --git a/Documentation/config.txt b/Documentation/config.txt index a95e5a4ac9..6416cae511 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -1210,8 +1210,16 @@ gitweb.snapshot:: grep.lineNumber:: If set to true, enable '-n' option by default. +grep.patternType:: + Set the default matching behavior. Using a value of 'basic', 'extended', + 'fixed', or 'perl' will enable the '--basic-regexp', '--extended-regexp', + '--fixed-strings', or '--perl-regexp' option accordingly, while the + value 'default' will return to the default matching behavior. + grep.extendedRegexp:: - If set to true, enable '--extended-regexp' option by default. + If set to true, enable '--extended-regexp' option by default. This + option is ignored when the 'grep.patternType' option is set to a value + other than 'default'. gpg.program:: Use this custom program instead of "gpg" found on $PATH when diff --git a/Documentation/git-credential-cache--daemon.txt b/Documentation/git-credential-cache--daemon.txt index 11edc5a173..d15db42d43 100644 --- a/Documentation/git-credential-cache--daemon.txt +++ b/Documentation/git-credential-cache--daemon.txt @@ -3,7 +3,7 @@ git-credential-cache--daemon(1) NAME ---- -git-credential-cache--daemon - temporarily store user credentials in memory +git-credential-cache--daemon - Temporarily store user credentials in memory SYNOPSIS -------- diff --git a/Documentation/git-credential-cache.txt b/Documentation/git-credential-cache.txt index f3d09c5d51..eeff5fa989 100644 --- a/Documentation/git-credential-cache.txt +++ b/Documentation/git-credential-cache.txt @@ -3,7 +3,7 @@ git-credential-cache(1) NAME ---- -git-credential-cache - helper to temporarily store passwords in memory +git-credential-cache - Helper to temporarily store passwords in memory SYNOPSIS -------- diff --git a/Documentation/git-credential-store.txt b/Documentation/git-credential-store.txt index 31093467d1..b27c03c361 100644 --- a/Documentation/git-credential-store.txt +++ b/Documentation/git-credential-store.txt @@ -3,7 +3,7 @@ git-credential-store(1) NAME ---- -git-credential-store - helper to store credentials on disk +git-credential-store - Helper to store credentials on disk SYNOPSIS -------- diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt index 53adee3203..810e957124 100644 --- a/Documentation/git-credential.txt +++ b/Documentation/git-credential.txt @@ -3,7 +3,7 @@ git-credential(1) NAME ---- -git-credential - retrieve and store user credentials +git-credential - Retrieve and store user credentials SYNOPSIS -------- diff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt index 039cce2e98..72d6bb612b 100644 --- a/Documentation/git-describe.txt +++ b/Documentation/git-describe.txt @@ -36,12 +36,12 @@ OPTIONS --all:: Instead of using only the annotated tags, use any ref - found in `.git/refs/`. This option enables matching + found in `refs/` namespace. This option enables matching any known branch, remote-tracking branch, or lightweight tag. --tags:: Instead of using only the annotated tags, use any tag - found in `.git/refs/tags`. This option enables matching + found in `refs/tags` namespace. This option enables matching a lightweight (non-annotated) tag. --contains:: diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt index 31fc2e3aed..73ca7025a3 100644 --- a/Documentation/git-difftool.txt +++ b/Documentation/git-difftool.txt @@ -69,6 +69,14 @@ with custom merge tool commands and has the same value as `$MERGED`. --tool-help:: Print a list of diff tools that may be used with `--tool`. +--symlinks:: +--no-symlinks:: + 'git difftool''s default behavior is create symlinks to the + working tree when run in `--dir-diff` mode. ++ + Specifying `--no-symlinks` instructs 'git difftool' to create + copies instead. `--no-symlinks` is the default on Windows. + -x <command>:: --extcmd=<command>:: Specify a custom command for viewing diffs. diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt index 81f58234a7..15e7ac80c0 100644 --- a/Documentation/git-filter-branch.txt +++ b/Documentation/git-filter-branch.txt @@ -32,7 +32,8 @@ changes, which would normally have no effect. Nevertheless, this may be useful in the future for compensating for some git bugs or such, therefore such a usage is permitted. -*NOTE*: This command honors `.git/info/grafts` and `.git/refs/replace/`. +*NOTE*: This command honors `.git/info/grafts` file and refs in +the `refs/replace/` namespace. If you have any grafts or replacement refs defined, running this command will make them permanent. diff --git a/Documentation/git-fsck.txt b/Documentation/git-fsck.txt index bbb25da2dd..da348fc942 100644 --- a/Documentation/git-fsck.txt +++ b/Documentation/git-fsck.txt @@ -23,8 +23,8 @@ OPTIONS An object to treat as the head of an unreachability trace. + If no objects are given, 'git fsck' defaults to using the -index file, all SHA1 references in .git/refs/*, and all reflogs (unless ---no-reflogs is given) as heads. +index file, all SHA1 references in `refs` namespace, and all reflogs +(unless --no-reflogs is given) as heads. --unreachable:: Print out objects that exist but that aren't reachable from any diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt index 3bec036883..cfecf848fb 100644 --- a/Documentation/git-grep.txt +++ b/Documentation/git-grep.txt @@ -42,8 +42,16 @@ CONFIGURATION grep.lineNumber:: If set to true, enable '-n' option by default. +grep.patternType:: + Set the default matching behavior. Using a value of 'basic', 'extended', + 'fixed', or 'perl' will enable the '--basic-regexp', '--extended-regexp', + '--fixed-strings', or '--perl-regexp' option accordingly, while the + value 'default' will return to the default matching behavior. + grep.extendedRegexp:: - If set to true, enable '--extended-regexp' option by default. + If set to true, enable '--extended-regexp' option by default. This + option is ignored when the 'grep.patternType' option is set to a value + other than 'default'. OPTIONS diff --git a/Documentation/git-lost-found.txt b/Documentation/git-lost-found.txt index c406a11001..d54932889f 100644 --- a/Documentation/git-lost-found.txt +++ b/Documentation/git-lost-found.txt @@ -48,7 +48,8 @@ $ gitk $(cd .git/lost-found/commit && echo ??*) ------------ After making sure you know which the object is the tag you are looking -for, you can reconnect it to your regular .git/refs hierarchy. +for, you can reconnect it to your regular `refs` hierarchy by using +the `update-ref` command. ------------ $ git cat-file -t 1ef2b196 diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt index d7207bd9b9..6b563c500f 100644 --- a/Documentation/git-mergetool.txt +++ b/Documentation/git-mergetool.txt @@ -64,6 +64,9 @@ variable `mergetool.<tool>.trustExitCode` can be set to `true`. Otherwise, 'git mergetool' will prompt the user to indicate the success of the resolution after the custom tool has exited. +--tool-help:: + Print a list of merge tools that may be used with `--tool`. + -y:: --no-prompt:: Don't prompt before each invocation of the merge resolution diff --git a/Documentation/git-pack-refs.txt b/Documentation/git-pack-refs.txt index 10afd4edfe..f131677478 100644 --- a/Documentation/git-pack-refs.txt +++ b/Documentation/git-pack-refs.txt @@ -14,7 +14,8 @@ DESCRIPTION ----------- Traditionally, tips of branches and tags (collectively known as -'refs') were stored one file per ref under `$GIT_DIR/refs` +'refs') were stored one file per ref in a (sub)directory +under `$GIT_DIR/refs` directory. While many branch tips tend to be updated often, most tags and some branch tips are never updated. When a repository has hundreds or thousands of tags, this @@ -22,13 +23,14 @@ one-file-per-ref format both wastes storage and hurts performance. This command is used to solve the storage and performance -problem by stashing the refs in a single file, +problem by storing the refs in a single file, `$GIT_DIR/packed-refs`. When a ref is missing from the -traditional `$GIT_DIR/refs` hierarchy, it is looked up in this +traditional `$GIT_DIR/refs` directory hierarchy, it is looked +up in this file and used if found. Subsequent updates to branches always create new files under -`$GIT_DIR/refs` hierarchy. +`$GIT_DIR/refs` directory hierarchy. A recommended practice to deal with a repository with too many refs is to pack its refs with `--all --prune` once, and @@ -57,6 +59,15 @@ a repository with many branches of historical interests. The command usually removes loose refs under `$GIT_DIR/refs` hierarchy after packing them. This option tells it not to. + +BUGS +---- + +Older documentation written before the packed-refs mechanism was +introduced may still say things like ".git/refs/heads/<branch> file +exists" when it means "branch <branch> exists". + + GIT --- Part of the linkgit:git[1] suite diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt index defb544ed0..67fa5ee195 100644 --- a/Documentation/git-pull.txt +++ b/Documentation/git-pull.txt @@ -101,6 +101,7 @@ include::merge-options.txt[] :git-pull: 1 +-r:: --rebase:: Rebase the current branch on top of the upstream branch after fetching. If there is a remote-tracking branch corresponding to diff --git a/Documentation/git-replace.txt b/Documentation/git-replace.txt index 17df525275..51131d0858 100644 --- a/Documentation/git-replace.txt +++ b/Documentation/git-replace.txt @@ -14,14 +14,13 @@ SYNOPSIS DESCRIPTION ----------- -Adds a 'replace' reference in `.git/refs/replace/` +Adds a 'replace' reference in `refs/replace/` namespace. The name of the 'replace' reference is the SHA1 of the object that is replaced. The content of the 'replace' reference is the SHA1 of the replacement object. -Unless `-f` is given, the 'replace' reference must not yet exist in -`.git/refs/replace/` directory. +Unless `-f` is given, the 'replace' reference must not yet exist. Replacement references will be used by default by all git commands except those doing reachability traversal (prune, pack transfer and diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index e36a7c3d1e..247534e908 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -20,11 +20,10 @@ SYNOPSIS DESCRIPTION ----------- -Add a tag reference in `.git/refs/tags/`, unless `-d/-l/-v` is given +Add a tag reference in `refs/tags/`, unless `-d/-l/-v` is given to delete, list or verify tags. -Unless `-f` is given, the tag to be created must not yet exist in the -`.git/refs/tags/` directory. +Unless `-f` is given, the named tag must not yet exist. If one of `-a`, `-s`, or `-u <key-id>` is passed, the command creates a 'tag' object, and requires a tag message. Unless diff --git a/Documentation/git.txt b/Documentation/git.txt index bf22ad527c..463d567a87 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -22,18 +22,17 @@ unusually rich command set that provides both high-level operations and full access to internals. See linkgit:gittutorial[7] to get started, then see -link:everyday.html[Everyday Git] for a useful minimum set of commands, and -"man git-commandname" for documentation of each command. CVS users may -also want to read linkgit:gitcvs-migration[7]. See -the link:user-manual.html[Git User's Manual] for a more in-depth -introduction. +link:everyday.html[Everyday Git] for a useful minimum set of +commands. The link:user-manual.html[Git User's Manual] has a more +in-depth introduction. -The '<command>' is either a name of a Git command (see below) or an alias -as defined in the configuration file (see linkgit:git-config[1]). +After you mastered the basic concepts, you can come back to this +page to learn what commands git offers. You can learn more about +individual git commands with "git help command". linkgit:gitcli[7] +manual page gives you an overview of the command line command syntax. -Formatted and hyperlinked version of the latest git -documentation can be viewed at -`http://www.kernel.org/pub/software/scm/git/docs/`. +Formatted and hyperlinked version of the latest git documentation +can be viewed at `http://git-htmldocs.googlecode.com/git/git.html`. ifdef::stalenotes[] [NOTE] @@ -44,9 +43,16 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.7.11.3/git.html[documentation for release 1.7.11.3] +* link:v1.7.12/git.html[documentation for release 1.7.12] * release notes for + link:RelNotes/1.7.12.txt[1.7.12]. + +* link:v1.7.11.5/git.html[documentation for release 1.7.11.5] + +* release notes for + link:RelNotes/1.7.11.5.txt[1.7.11.5], + link:RelNotes/1.7.11.4.txt[1.7.11.4], link:RelNotes/1.7.11.3.txt[1.7.11.3], link:RelNotes/1.7.11.2.txt[1.7.11.2], link:RelNotes/1.7.11.1.txt[1.7.11.1], @@ -404,24 +410,6 @@ help ...`. linkgit:git-replace[1] for more information. -FURTHER DOCUMENTATION ---------------------- - -See the references above to get started using git. The following is -probably more detail than necessary for a first-time user. - -The link:user-manual.html#git-concepts[git concepts chapter of the -user-manual] and linkgit:gitcore-tutorial[7] both provide -introductions to the underlying git architecture. - -See linkgit:gitworkflows[7] for an overview of recommended workflows. - -See also the link:howto-index.html[howto] documents for some useful -examples. - -The internals are documented in the -link:technical/api-index.html[GIT API documentation]. - GIT COMMANDS ------------ @@ -841,6 +829,29 @@ The index is also capable of storing multiple entries (called "stages") for a given pathname. These stages are used to hold the various unmerged version of a file when a merge is in progress. +FURTHER DOCUMENTATION +--------------------- + +See the references in the "description" section to get started +using git. The following is probably more detail than necessary +for a first-time user. + +The link:user-manual.html#git-concepts[git concepts chapter of the +user-manual] and linkgit:gitcore-tutorial[7] both provide +introductions to the underlying git architecture. + +See linkgit:gitworkflows[7] for an overview of recommended workflows. + +See also the link:howto-index.html[howto] documents for some useful +examples. + +The internals are documented in the +link:technical/api-index.html[GIT API documentation]. + +Users migrating from CVS may also want to +read linkgit:gitcvs-migration[7]. + + Authors ------- Git was started by Linus Torvalds, and is currently maintained by Junio diff --git a/Documentation/gitcli.txt b/Documentation/gitcli.txt index ea17f7a53b..3e72a5d68e 100644 --- a/Documentation/gitcli.txt +++ b/Documentation/gitcli.txt @@ -62,6 +62,14 @@ scripting git: `git log -1 HEAD` but write `git log -1 HEAD --`; the former will not work if you happen to have a file called `HEAD` in the work tree. + * many commands allow a long option "--option" to be abbreviated + only to their unique prefix (e.g. if there is no other option + whose name begins with "opt", you may be able to spell "--opt" to + invoke the "--option" flag), but you should fully spell them out + when writing your scripts; later versions of Git may introduce a + new option whose name shares the same prefix, e.g. "--optimize", + to make a short prefix that used to be unique no longer unique. + ENHANCED OPTION PARSER ---------------------- diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index d9b2b5b2e0..def1340ac7 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -578,16 +578,33 @@ Commit Ordering By default, the commits are shown in reverse chronological order. ---topo-order:: +--date-order:: + Show no parents before all of its children are shown, but + otherwise show commits in the commit timestamp order. - This option makes them appear in topological order (i.e. - descendant commits are shown before their parents). +--topo-order:: + Show no parents before all of its children are shown, and + avoid showing commits on multiple lines of history + intermixed. ++ +For example, in a commit history like this: ++ +---------------------------------------------------------------- ---date-order:: + ---1----2----4----7 + \ \ + 3----5----6----8--- - This option is similar to '--topo-order' in the sense that no - parent comes before all of its children, but otherwise things - are still ordered in the commit timestamp order. +---------------------------------------------------------------- ++ +where the numbers denote the order of commit timestamps, `git +rev-list` and friends with `--date-order` show the commits in the +timestamp order: 8 7 6 5 4 3 2 1. ++ +With `--topo-order`, they would show 8 6 5 3 7 4 2 1 (or 8 7 4 2 6 5 +3 1); some older commits are shown before newer ones in order to +avoid showing the commits from two parallel development track mixed +together. --reverse:: diff --git a/Documentation/user-manual.conf b/Documentation/user-manual.conf index 339b30919e..d87294de2f 100644 --- a/Documentation/user-manual.conf +++ b/Documentation/user-manual.conf @@ -14,7 +14,7 @@ ifdef::backend-docbook[] # "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this. [listingblock] <example><title>{title}</title> -<literallayout> +<literallayout class="monospaced"> | </literallayout> {title#}</example> diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 22bb2298ae..d2d2d699e1 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.7.12-rc0 +DEF_VER=v1.7.12.GIT LF=' ' @@ -1014,6 +1014,7 @@ ifeq ($(uname_S),SunOS) NO_REGEX = YesPlease NO_FNMATCH_CASEFOLD = YesPlease NO_MSGFMT_EXTENDED_OPTIONS = YesPlease + HAVE_DEV_TTY = YesPlease ifeq ($(uname_R),5.6) SOCKLEN_T = int NO_HSTRERROR = YesPlease @@ -2090,6 +2091,13 @@ $(SCRIPT_LIB) : % : %.sh GIT-SCRIPT-DEFINES ifndef NO_PERL $(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak +perl/perl.mak: perl/PM.stamp + +perl/PM.stamp: FORCE + $(QUIET_GEN)$(FIND) perl -type f -name '*.pm' | sort >$@+ && \ + { cmp $@+ $@ >/dev/null 2>/dev/null || mv $@+ $@; } && \ + $(RM) $@+ + perl/perl.mak: GIT-CFLAGS GIT-PREFIX perl/Makefile perl/Makefile.PL $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' $(@F) @@ -2387,7 +2395,8 @@ XGETTEXT_FLAGS = \ --from-code=UTF-8 XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \ --keyword=_ --keyword=N_ --keyword="Q_:1,2" -XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell +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) @@ -2796,8 +2805,13 @@ endif ### Check documentation # +ALL_COMMANDS = $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) +ALL_COMMANDS += git +ALL_COMMANDS += gitk +ALL_COMMANDS += gitweb +ALL_COMMANDS += git-gui git-citool check-docs:: - @(for v in $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git gitk; \ + @(for v in $(ALL_COMMANDS); \ do \ case "$$v" in \ git-merge-octopus | git-merge-ours | git-merge-recursive | \ @@ -2819,35 +2833,13 @@ check-docs:: sed -e '/^#/d' \ -e 's/[ ].*//' \ -e 's/^/listed /' command-list.txt; \ - ls -1 Documentation/git*txt | \ + $(MAKE) -C Documentation print-man1 | \ + grep '\.txt$$' | \ sed -e 's|Documentation/|documented |' \ -e 's/\.txt//'; \ ) | while read how cmd; \ do \ - case "$$how,$$cmd" in \ - *,git-citool | \ - *,git-gui | \ - *,git-help | \ - documented,gitattributes | \ - documented,gitignore | \ - documented,gitmodules | \ - documented,gitcli | \ - documented,git-tools | \ - documented,gitcore-tutorial | \ - documented,gitcvs-migration | \ - documented,gitdiffcore | \ - documented,gitglossary | \ - documented,githooks | \ - documented,gitrepository-layout | \ - documented,gitrevisions | \ - documented,gittutorial | \ - documented,gittutorial-2 | \ - documented,git-bisect-lk2009 | \ - documented,git-remote-helpers | \ - documented,gitworkflows | \ - sentinel,not,matching,is,ok ) continue ;; \ - esac; \ - case " $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git gitk " in \ + case " $(ALL_COMMANDS) " in \ *" $$cmd "*) ;; \ *) echo "removed but $$how: $$cmd" ;; \ esac; \ @@ -1 +1 @@ -Documentation/RelNotes/1.7.12.txt
\ No newline at end of file +Documentation/RelNotes/1.8.0.txt
\ No newline at end of file @@ -43,7 +43,7 @@ extern int check_pager_config(const char *cmd); struct diff_options; extern void setup_diff_pager(struct diff_options *); -extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, char **buf, unsigned long *buf_size); +extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, int sha1_valid, char **buf, unsigned long *buf_size); extern int cmd_add(int argc, const char **argv, const char *prefix); extern int cmd_annotate(int argc, const char **argv, const char *prefix); diff --git a/builtin/apply.c b/builtin/apply.c index d453c83378..3bf71dc452 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -188,7 +188,6 @@ struct patch { int is_new, is_delete; /* -1 = unknown, 0 = false, 1 = true */ int rejected; unsigned ws_rule; - unsigned long deflate_origlen; int lines_added, lines_deleted; int score; unsigned int is_toplevel_relative:1; diff --git a/builtin/blame.c b/builtin/blame.c index 0d50273ce9..ed5d01b36a 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -110,6 +110,7 @@ static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b, long ctxlen, int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, + int sha1_valid, char **buf, unsigned long *buf_size) { @@ -117,7 +118,7 @@ int textconv_object(const char *path, struct userdiff_driver *textconv; df = alloc_filespec(path); - fill_filespec(df, sha1, mode); + fill_filespec(df, sha1, sha1_valid, mode); textconv = get_textconv(df); if (!textconv) { free_filespec(df); @@ -142,7 +143,7 @@ static void fill_origin_blob(struct diff_options *opt, num_read_blob++; if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) && - textconv_object(o->path, o->mode, o->blob_sha1, &file->ptr, &file_size)) + textconv_object(o->path, o->mode, o->blob_sha1, 1, &file->ptr, &file_size)) ; else file->ptr = read_sha1_file(o->blob_sha1, &type, &file_size); @@ -406,8 +407,7 @@ static struct origin *find_origin(struct scoreboard *sb, paths[1] = NULL; diff_tree_setup_paths(paths, &diff_opts); - if (diff_setup_done(&diff_opts) < 0) - die("diff-setup"); + diff_setup_done(&diff_opts); if (is_null_sha1(origin->commit->object.sha1)) do_diff_cache(parent->tree->object.sha1, &diff_opts); @@ -493,8 +493,7 @@ static struct origin *find_rename(struct scoreboard *sb, diff_opts.single_follow = origin->path; paths[0] = NULL; diff_tree_setup_paths(paths, &diff_opts); - if (diff_setup_done(&diff_opts) < 0) - die("diff-setup"); + diff_setup_done(&diff_opts); if (is_null_sha1(origin->commit->object.sha1)) do_diff_cache(parent->tree->object.sha1, &diff_opts); @@ -1074,8 +1073,7 @@ static int find_copy_in_parent(struct scoreboard *sb, paths[0] = NULL; diff_tree_setup_paths(paths, &diff_opts); - if (diff_setup_done(&diff_opts) < 0) - die("diff-setup"); + diff_setup_done(&diff_opts); /* Try "find copies harder" on new path if requested; * we do not want to use diffcore_rename() actually to @@ -2123,7 +2121,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt, switch (st.st_mode & S_IFMT) { case S_IFREG: if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) && - textconv_object(read_from, mode, null_sha1, &buf_ptr, &buf_len)) + textconv_object(read_from, mode, null_sha1, 0, &buf_ptr, &buf_len)) strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1); else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size) die_errno("cannot open or read '%s'", read_from); @@ -2516,7 +2514,7 @@ parse_done: die("no such path %s in %s", path, final_commit_name); if (DIFF_OPT_TST(&sb.revs->diffopt, ALLOW_TEXTCONV) && - textconv_object(path, o->mode, o->blob_sha1, (char **) &sb.final_buf, + textconv_object(path, o->mode, o->blob_sha1, 1, (char **) &sb.final_buf, &sb.final_buf_size)) ; else diff --git a/builtin/cat-file.c b/builtin/cat-file.c index af74e775a1..0eca2d7bd0 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -146,7 +146,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name) die("git cat-file --textconv %s: <object> must be <sha1:path>", obj_name); - if (!textconv_object(obj_context.path, obj_context.mode, sha1, &buf, &size)) + if (!textconv_object(obj_context.path, obj_context.mode, sha1, 1, &buf, &size)) die("git cat-file --textconv: unable to run textconv on %s", obj_name); break; diff --git a/builtin/checkout.c b/builtin/checkout.c index 6acca75f47..7d922c612a 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -316,8 +316,7 @@ static void show_local_changes(struct object *head, struct diff_options *opts) init_revisions(&rev, NULL); rev.diffopt.flags = opts->flags; rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS; - if (diff_setup_done(&rev.diffopt) < 0) - die(_("diff_setup_done failed")); + diff_setup_done(&rev.diffopt); add_pending_object(&rev, head, NULL); run_diff_index(&rev, 0); } @@ -606,7 +605,7 @@ static int add_pending_uninteresting_ref(const char *refname, const unsigned char *sha1, int flags, void *cb_data) { - add_pending_sha1(cb_data, refname, sha1, flags | UNINTERESTING); + add_pending_sha1(cb_data, refname, sha1, UNINTERESTING); return 0; } diff --git a/builtin/diff.c b/builtin/diff.c index da8f6aac2b..9650be2c50 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -29,6 +29,8 @@ static void stuff_change(struct diff_options *opt, unsigned old_mode, unsigned new_mode, const unsigned char *old_sha1, const unsigned char *new_sha1, + int old_sha1_valid, + int new_sha1_valid, const char *old_name, const char *new_name) { @@ -54,8 +56,8 @@ static void stuff_change(struct diff_options *opt, one = alloc_filespec(old_name); two = alloc_filespec(new_name); - fill_filespec(one, old_sha1, old_mode); - fill_filespec(two, new_sha1, new_mode); + fill_filespec(one, old_sha1, old_sha1_valid, old_mode); + fill_filespec(two, new_sha1, new_sha1_valid, new_mode); diff_queue(&diff_queued_diff, one, two); } @@ -84,6 +86,7 @@ static int builtin_diff_b_f(struct rev_info *revs, stuff_change(&revs->diffopt, blob[0].mode, canon_mode(st.st_mode), blob[0].sha1, null_sha1, + 1, 0, path, path); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); @@ -108,6 +111,7 @@ static int builtin_diff_blobs(struct rev_info *revs, stuff_change(&revs->diffopt, blob[0].mode, blob[1].mode, blob[0].sha1, blob[1].sha1, + 1, 1, blob[0].name, blob[1].name); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); @@ -298,8 +302,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) argc = setup_revisions(argc, argv, &rev, NULL); if (!rev.diffopt.output_format) { rev.diffopt.output_format = DIFF_FORMAT_PATCH; - if (diff_setup_done(&rev.diffopt) < 0) - die(_("diff_setup_done failed")); + diff_setup_done(&rev.diffopt); } DIFF_OPT_SET(&rev.diffopt, RECURSIVE); diff --git a/builtin/grep.c b/builtin/grep.c index 29adb0ac93..02b9555918 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -260,6 +260,53 @@ static int wait_all(void) } #endif +static int parse_pattern_type_arg(const char *opt, const char *arg) +{ + if (!strcmp(arg, "default")) + return GREP_PATTERN_TYPE_UNSPECIFIED; + else if (!strcmp(arg, "basic")) + return GREP_PATTERN_TYPE_BRE; + else if (!strcmp(arg, "extended")) + return GREP_PATTERN_TYPE_ERE; + else if (!strcmp(arg, "fixed")) + return GREP_PATTERN_TYPE_FIXED; + else if (!strcmp(arg, "perl")) + return GREP_PATTERN_TYPE_PCRE; + die("bad %s argument: %s", opt, arg); +} + +static void grep_pattern_type_options(const int pattern_type, struct grep_opt *opt) +{ + switch (pattern_type) { + case GREP_PATTERN_TYPE_UNSPECIFIED: + /* fall through */ + + case GREP_PATTERN_TYPE_BRE: + opt->fixed = 0; + opt->pcre = 0; + opt->regflags &= ~REG_EXTENDED; + break; + + case GREP_PATTERN_TYPE_ERE: + opt->fixed = 0; + opt->pcre = 0; + opt->regflags |= REG_EXTENDED; + break; + + case GREP_PATTERN_TYPE_FIXED: + opt->fixed = 1; + opt->pcre = 0; + opt->regflags &= ~REG_EXTENDED; + break; + + case GREP_PATTERN_TYPE_PCRE: + opt->fixed = 0; + opt->pcre = 1; + opt->regflags &= ~REG_EXTENDED; + break; + } +} + static int grep_config(const char *var, const char *value, void *cb) { struct grep_opt *opt = cb; @@ -270,12 +317,17 @@ static int grep_config(const char *var, const char *value, void *cb) if (!strcmp(var, "grep.extendedregexp")) { if (git_config_bool(var, value)) - opt->regflags |= REG_EXTENDED; + opt->extended_regexp_option = 1; else - opt->regflags &= ~REG_EXTENDED; + opt->extended_regexp_option = 0; return 0; } + if (!strcmp(var, "grep.patterntype")) { + opt->pattern_type_option = parse_pattern_type_arg(var, value); + return 0; + } + if (!strcmp(var, "grep.linenumber")) { opt->linenum = git_config_bool(var, value); return 0; @@ -669,14 +721,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) int i; int dummy; int use_index = 1; - enum { - pattern_type_unspecified = 0, - pattern_type_bre, - pattern_type_ere, - pattern_type_fixed, - pattern_type_pcre, - }; - int pattern_type = pattern_type_unspecified; + int pattern_type_arg = GREP_PATTERN_TYPE_UNSPECIFIED; struct option options[] = { OPT_BOOLEAN(0, "cached", &cached, @@ -703,18 +748,18 @@ int cmd_grep(int argc, const char **argv, const char *prefix) "descend at most <depth> levels", PARSE_OPT_NONEG, NULL, 1 }, OPT_GROUP(""), - OPT_SET_INT('E', "extended-regexp", &pattern_type, + OPT_SET_INT('E', "extended-regexp", &pattern_type_arg, "use extended POSIX regular expressions", - pattern_type_ere), - OPT_SET_INT('G', "basic-regexp", &pattern_type, + GREP_PATTERN_TYPE_ERE), + OPT_SET_INT('G', "basic-regexp", &pattern_type_arg, "use basic POSIX regular expressions (default)", - pattern_type_bre), - OPT_SET_INT('F', "fixed-strings", &pattern_type, + GREP_PATTERN_TYPE_BRE), + OPT_SET_INT('F', "fixed-strings", &pattern_type_arg, "interpret patterns as fixed strings", - pattern_type_fixed), - OPT_SET_INT('P', "perl-regexp", &pattern_type, + GREP_PATTERN_TYPE_FIXED), + OPT_SET_INT('P', "perl-regexp", &pattern_type_arg, "use Perl-compatible regular expressions", - pattern_type_pcre), + GREP_PATTERN_TYPE_PCRE), OPT_GROUP(""), OPT_BOOLEAN('n', "line-number", &opt.linenum, "show line numbers"), OPT_NEGBIT('h', NULL, &opt.pathname, "don't show filenames", 1), @@ -799,6 +844,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) opt.header_tail = &opt.header_list; opt.regflags = REG_NEWLINE; opt.max_depth = -1; + opt.pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED; + opt.extended_regexp_option = 0; strcpy(opt.color_context, ""); strcpy(opt.color_filename, ""); @@ -824,28 +871,13 @@ int cmd_grep(int argc, const char **argv, const char *prefix) PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_STOP_AT_NON_OPTION | PARSE_OPT_NO_INTERNAL_HELP); - switch (pattern_type) { - case pattern_type_fixed: - opt.fixed = 1; - opt.pcre = 0; - break; - case pattern_type_bre: - opt.fixed = 0; - opt.pcre = 0; - opt.regflags &= ~REG_EXTENDED; - break; - case pattern_type_ere: - opt.fixed = 0; - opt.pcre = 0; - opt.regflags |= REG_EXTENDED; - break; - case pattern_type_pcre: - opt.fixed = 0; - opt.pcre = 1; - break; - default: - break; /* nothing */ - } + + if (pattern_type_arg != GREP_PATTERN_TYPE_UNSPECIFIED) + grep_pattern_type_options(pattern_type_arg, &opt); + else if (opt.pattern_type_option != GREP_PATTERN_TYPE_UNSPECIFIED) + grep_pattern_type_options(opt.pattern_type_option, &opt); + else if (opt.extended_regexp_option) + grep_pattern_type_options(GREP_PATTERN_TYPE_ERE, &opt); if (use_index && !startup_info->have_repository) /* die the same way as if we did it at the beginning */ diff --git a/builtin/merge.c b/builtin/merge.c index dd50a0c57b..e81fde6d79 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -404,8 +404,7 @@ static void finish(struct commit *head_commit, opts.output_format |= DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; opts.detect_rename = DIFF_DETECT_RENAME; - if (diff_setup_done(&opts) < 0) - die(_("diff_setup_done failed")); + diff_setup_done(&opts); diff_tree_sha1(head, new_head, "", &opts); diffcore_std(&opts); diff_flush(&opts); diff --git a/builtin/push.c b/builtin/push.c index fdfcc6c716..9ed558485b 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -147,12 +147,37 @@ static void setup_push_upstream(struct remote *remote, int simple) add_refspec(refspec.buf); } +static char warn_unspecified_push_default_msg[] = +N_("push.default is unset; its implicit value is changing in\n" + "Git 2.0 from 'matching' to 'simple'. To squelch this message\n" + "and maintain the current behavior after the default changes, use:\n" + "\n" + " git config --global push.default matching\n" + "\n" + "To squelch this message and adopt the new behavior now, use:\n" + "\n" + " git config --global push.default simple\n" + "\n" + "See 'git help config' and search for 'push.default' for further information.\n" + "(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode\n" + "'current' instead of 'simple' if you sometimes use older versions of Git)"); + +static void warn_unspecified_push_default_configuration(void) +{ + static int warn_once; + + if (warn_once++) + return; + warning("%s\n", _(warn_unspecified_push_default_msg)); +} + static void setup_default_push_refspecs(struct remote *remote) { switch (push_default) { default: case PUSH_DEFAULT_UNSPECIFIED: default_matching_used = 1; + warn_unspecified_push_default_configuration(); /* fallthru */ case PUSH_DEFAULT_MATCHING: add_refspec(":"); @@ -186,8 +211,8 @@ static const char message_advice_pull_before_push[] = static const char message_advice_use_upstream[] = N_("Updates were rejected because a pushed branch tip is behind its remote\n" "counterpart. If you did not intend to push that branch, you may want to\n" - "specify branches to push or set the 'push.default' configuration\n" - "variable to 'current' or 'upstream' to push only the current branch."); + "specify branches to push or set the 'push.default' configuration variable\n" + "to 'simple', 'current' or 'upstream' to push only the current branch."); static const char message_advice_checkout_pull_push[] = N_("Updates were rejected because a pushed branch tip is behind its remote\n" diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index 0afb8b2896..3f05d971ec 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -977,7 +977,8 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix) const char *argv_gc_auto[] = { "gc", "--auto", "--quiet", NULL, }; - run_command_v_opt(argv_gc_auto, RUN_GIT_CMD); + int opt = RUN_GIT_CMD | RUN_COMMAND_STDOUT_TO_STDERR; + run_command_v_opt(argv_gc_auto, opt); } if (auto_update_server_info) update_server_info(0); diff --git a/combine-diff.c b/combine-diff.c index 9786680368..bb1cc96c4e 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -111,7 +111,7 @@ static char *grab_blob(const unsigned char *sha1, unsigned int mode, return xcalloc(1, 1); } else if (textconv) { struct diff_filespec *df = alloc_filespec(path); - fill_filespec(df, sha1, mode); + fill_filespec(df, sha1, 1, mode); *size = fill_textconv(textconv, df, &blob); free_filespec(df); } else { @@ -823,7 +823,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, &result_size, NULL, NULL); } else if (textconv) { struct diff_filespec *df = alloc_filespec(elem->path); - fill_filespec(df, null_sha1, st.st_mode); + fill_filespec(df, null_sha1, 0, st.st_mode); result_size = fill_textconv(textconv, df, &result); free_filespec(df); } else if (0 <= (fd = open(elem->path, O_RDONLY))) { diff --git a/command-list.txt b/command-list.txt index 14ea67af03..7e8cfec29d 100644 --- a/command-list.txt +++ b/command-list.txt @@ -25,6 +25,9 @@ git-commit mainporcelain common git-commit-tree plumbingmanipulators git-config ancillarymanipulators git-count-objects ancillaryinterrogators +git-credential purehelpers +git-credential-cache purehelpers +git-credential-store purehelpers git-cvsexportcommit foreignscminterface git-cvsimport foreignscminterface git-cvsserver foreignscminterface @@ -113,6 +116,7 @@ git-show mainporcelain common git-show-branch ancillaryinterrogators git-show-index plumbinginterrogators git-show-ref plumbinginterrogators +git-sh-i18n purehelpers git-sh-setup purehelpers git-stash mainporcelain git-status mainporcelain common diff --git a/compat/terminal.c b/compat/terminal.c index 6d16c8fba0..bbb038dd01 100644 --- a/compat/terminal.c +++ b/compat/terminal.c @@ -59,6 +59,7 @@ char *git_terminal_prompt(const char *prompt, int echo) r = strbuf_getline(&buf, fh, '\n'); if (!echo) { + fseek(fh, SEEK_CUR, 0); putc('\n', fh); fflush(fh); } diff --git a/contrib/ciabot/INSTALL b/contrib/ciabot/INSTALL new file mode 100644 index 0000000000..7222961d35 --- /dev/null +++ b/contrib/ciabot/INSTALL @@ -0,0 +1,54 @@ += Installation instructions = + +Two scripts are included. The Python one (ciabot.py) is faster and +more capable; the shell one (ciabot.sh) is a fallback in case Python +gives your git hosting site indigestion. (I know of no such sites.) + +It is no longer necessary to modify the script in order to put it +in place; in fact, this is now discouraged. It is entirely +configurable with the following git config variables: + +ciabot.project = name of the project +ciabot.repo = name of the project repo for gitweb/cgit purposes +ciabot.xmlrpc = if true, ship notifications via XML-RPC +ciabot.revformat = format in which the revision is shown + +The revformat variable may have the following values +raw -> full hex ID of commit +short -> first 12 chars of hex ID +describe -> describe relative to last tag, falling back to short + +ciabot.project defaults to the directory name of the repository toplevel. +ciabot.repo defaults to ciabot.project lowercased. +ciabot.xmlrpc defaults to True +ciabot.revformat defaults to 'describe'. + +This means that in the normal case you need not do any configuration at all, +however setting ciabot.project will allow the hook to run slightly faster. + +Once you've set these variables, try your script with -n to see the +notification message dumped to stdout and verify that it looks sane. + +To live-test these scripts, your project needs to have been registered with +the CIA site. Here are the steps: + +1. Open an IRC window on irc://freenode/commits or your registered + project IRC channel. + +2. Run ciabot.py and/or ciabot.sh from any directory under git + control. + +You should see a notification on the channel for your most recent commit. + +After verifying correct function, install one of these scripts either +in a post-commit hook or in an update hook. + +In post-commit, run it without arguments. It will query for +current HEAD and the latest commit ID to get the information it +needs. + +In update, call it with a refname followed by a list of commits: +You want to reverse the order git rev-list emits because it lists +from most recent to oldest. + +/path/to/ciabot.py ${refname} $(git rev-list ${oldhead}..${newhead} | tac) diff --git a/contrib/ciabot/README b/contrib/ciabot/README index 3b916acece..2dfe1f91f5 100644 --- a/contrib/ciabot/README +++ b/contrib/ciabot/README @@ -8,5 +8,4 @@ You probably want the Python version; it's faster, more capable, and better documented. The shell version is maintained only as a fallback for use on hosting sites that don't permit Python hook scripts. -You will find installation instructions for each script in its comment -header. +See the file INSTALL for installation instructions. diff --git a/contrib/ciabot/ciabot.py b/contrib/ciabot/ciabot.py index 9775dffb5d..bd24395d4c 100755 --- a/contrib/ciabot/ciabot.py +++ b/contrib/ciabot/ciabot.py @@ -10,44 +10,45 @@ # usage: ciabot.py [-V] [-n] [-p projectname] [refname [commits...]] # # This script is meant to be run either in a post-commit hook or in an -# update hook. If there's nothing unusual about your hosting setup, -# you can specify the project name with a -p option and avoid having -# to modify this script. Try it with -n to see the notification mail -# dumped to stdout and verify that it looks sane. With -V it dumps its -# version and exits. +# update hook. Try it with -n to see the notification mail dumped to +# stdout and verify that it looks sane. With -V it dumps its version +# and exits. # -# In post-commit, run it without arguments (other than possibly a -p -# option). It will query for current HEAD and the latest commit ID to -# get the information it needs. +# In post-commit, run it without arguments. It will query for +# current HEAD and the latest commit ID to get the information it +# needs. # # In update, call it with a refname followed by a list of commits: -# You want to reverse the order git rev-list emits becxause it lists +# You want to reverse the order git rev-list emits because it lists # from most recent to oldest. # # /path/to/ciabot.py ${refname} $(git rev-list ${oldhead}..${newhead} | tac) # -# Note: this script uses mail, not XML-RPC, in order to avoid stalling -# until timeout when the CIA XML-RPC server is down. +# Configuration variables affecting this script: # - +# ciabot.project = name of the project +# ciabot.repo = name of the project repo for gitweb/cgit purposes +# ciabot.xmlrpc = if true (default), ship notifications via XML-RPC +# ciabot.revformat = format in which the revision is shown # -# The project as known to CIA. You will either want to change this -# or invoke the script with a -p option to set it. +# ciabot.project defaults to the directory name of the repository toplevel. +# ciabot.repo defaults to ciabot.project lowercased. # -project=None - +# This means that in the normal case you need not do any configuration at all, +# but setting the project name will speed it up slightly. # -# You may not need to change these: +# The revformat variable may have the following values +# raw -> full hex ID of commit +# short -> first 12 chars of hex ID +# describe = -> describe relative to last tag, falling back to short +# The default is 'describe'. +# +# Note: the CIA project now says only XML-RPC is reliable, so +# we default to that. # -import os, sys, commands, socket, urllib - -# Name of the repository. -# You can hardwire this to make the script faster. -repo = os.path.basename(os.getcwd()) -# Fully-qualified domain name of this host. -# You can hardwire this to make the script faster. -host = socket.getfqdn() +import os, sys, commands, socket, urllib +from xml.sax.saxutils import escape # Changeset URL prefix for your repo: when the commit ID is appended # to this, it should point at a CGI that will display the commit @@ -72,7 +73,7 @@ xml = '''\ <message> <generator> <name>CIA Python client for Git</name> - <version>%(gitver)s</version> + <version>%(version)s</version> <url>%(generator)s</url> </generator> <source> @@ -98,19 +99,18 @@ xml = '''\ # No user-serviceable parts below this line: # -# Addresses for the e-mail. The from address is a dummy, since CIA -# will never reply to this mail. -fromaddr = "CIABOT-NOREPLY@" + host -toaddr = "cia@cia.navi.cx" +# Where to ship e-mail notifications. +toaddr = "cia@cia.vc" # Identify the generator script. # Should only change when the script itself gets a new home and maintainer. -generator="http://www.catb.org/~esr/ciabot.py" +generator = "http://www.catb.org/~esr/ciabot.py" +version = "3.6" def do(command): return commands.getstatusoutput(command)[1] -def report(refname, merged): +def report(refname, merged, xmlrpc=True): "Generate a commit notification to be reported to CIA" # Try to tinyfy a reference to a web view for this commit. @@ -121,32 +121,27 @@ def report(refname, merged): branch = os.path.basename(refname) - # Compute a shortnane for the revision - rev = do("git describe '"+ merged +"' 2>/dev/null") or merged[:12] - - # Extract the neta-information for the commit - rawcommit = do("git cat-file commit " + merged) + # Compute a description for the revision + if revformat == 'raw': + rev = merged + elif revformat == 'short': + rev = '' + else: # revformat == 'describe' + rev = do("git describe %s 2>/dev/null" % merged) + if not rev: + rev = merged[:12] + + # Extract the meta-information for the commit files=do("git diff-tree -r --name-only '"+ merged +"' | sed -e '1d' -e 's-.*-<file>&</file>-'") - inheader = True - headers = {} - logmsg = "" - for line in rawcommit.split("\n"): - if inheader: - if line: - fields = line.split() - headers[fields[0]] = " ".join(fields[1:]) - else: - inheader = False - else: - logmsg = line - break - (author, ts) = headers["author"].split(">") + metainfo = do("git log -1 '--pretty=format:%an <%ae>%n%at%n%s' " + merged) + (author, ts, logmsg) = metainfo.split("\n") + logmsg = escape(logmsg) - # This discards the part of the authors addrsss after @. - # Might be bnicece to ship the full email address, if not + # This discards the part of the author's address after @. + # Might be be nice to ship the full email address, if not # for spammers' address harvesters - getting this wrong # would make the freenode #commits channel into harvester heaven. - author = author.replace("<", "").split("@")[0].split()[-1] + author = escape(author.replace("<", "").split("@")[0].split()[-1]) # This ignores the timezone. Not clear what to do with it... ts = ts.strip().split()[0] @@ -155,8 +150,7 @@ def report(refname, merged): context.update(globals()) out = xml % context - - message = '''\ + mail = '''\ Message-ID: <%(merged)s.%(author)s@%(project)s> From: %(fromaddr)s To: %(toaddr)s @@ -165,34 +159,56 @@ Subject: DeliverXML %(out)s''' % locals() - return message + if xmlrpc: + return out + else: + return mail if __name__ == "__main__": import getopt + # Get all config variables + revformat = do("git config --get ciabot.revformat") + project = do("git config --get ciabot.project") + repo = do("git config --get ciabot.repo") + xmlrpc = do("git config --get ciabot.xmlrpc") + xmlrpc = not (xmlrpc and xmlrpc == "false") + + host = socket.getfqdn() + fromaddr = "CIABOT-NOREPLY@" + host + try: - (options, arguments) = getopt.getopt(sys.argv[1:], "np:V") + (options, arguments) = getopt.getopt(sys.argv[1:], "np:xV") except getopt.GetoptError, msg: print "ciabot.py: " + str(msg) raise SystemExit, 1 - mailit = True + notify = True for (switch, val) in options: if switch == '-p': project = val elif switch == '-n': - mailit = False + notify = False + elif switch == '-x': + xmlrpc = True elif switch == '-V': - print "ciabot.py: version 3.2" + print "ciabot.py: version", version sys.exit(0) - # Cough and die if user has not specified a project + # The project variable defaults to the name of the repository toplevel. if not project: - sys.stderr.write("ciabot.py: no project specified, bailing out.\n") - sys.exit(1) - - # We'll need the git version number. - gitver = do("git --version").split()[0] + here = os.getcwd() + while True: + if os.path.exists(os.path.join(here, ".git")): + project = os.path.basename(here) + break + elif here == '/': + sys.stderr.write("ciabot.py: no .git below root!\n") + sys.exit(1) + here = os.path.dirname(here) + + if not repo: + repo = project.lower() urlprefix = urlprefix % globals() @@ -205,18 +221,29 @@ if __name__ == "__main__": refname = arguments[0] merges = arguments[1:] - if mailit: - import smtplib - server = smtplib.SMTP('localhost') + if notify: + if xmlrpc: + import xmlrpclib + server = xmlrpclib.Server('http://cia.vc/RPC2'); + else: + import smtplib + server = smtplib.SMTP('localhost') for merged in merges: - message = report(refname, merged) - if mailit: - server.sendmail(fromaddr, [toaddr], message) - else: + message = report(refname, merged, xmlrpc) + if not notify: print message + elif xmlrpc: + try: + # RPC server is flaky, this can fail due to timeout. + server.hub.deliver(message) + except socket.error, e: + sys.stderr.write("%s\n" % e) + else: + server.sendmail(fromaddr, [toaddr], message) - if mailit: - server.quit() + if notify: + if not xmlrpc: + server.quit() #End diff --git a/contrib/ciabot/ciabot.sh b/contrib/ciabot/ciabot.sh index eb87bba38e..3fbbc534ae 100755 --- a/contrib/ciabot/ciabot.sh +++ b/contrib/ciabot/ciabot.sh @@ -3,6 +3,8 @@ # Copyright (c) 2006 Fernando J. Pereda <ferdy@gentoo.org> # Copyright (c) 2008 Natanael Copa <natanael.copa@gmail.com> # Copyright (c) 2010 Eric S. Raymond <esr@thyrsus.com> +# Assistance and review by Petr Baudis, author of ciabot.pl, +# is gratefully acknowledged. # # This is a version 3.x of ciabot.sh; use -V to find the exact # version. Versions 1 and 2 were shipped in 2006 and 2008 and are not @@ -11,6 +13,7 @@ # Note: This script should be considered obsolete. # There is a faster, better-documented rewrite in Python: find it as ciabot.py # Use this only if your hosting site forbids Python hooks. +# It requires: git(1), hostname(1), cut(1), sendmail(1), and wget(1). # # Originally based on Git ciabot.pl by Petr Baudis. # This script contains porcelain and porcelain byproducts. @@ -18,15 +21,13 @@ # usage: ciabot.sh [-V] [-n] [-p projectname] [refname commit] # # This script is meant to be run either in a post-commit hook or in an -# update hook. If there's nothing unusual about your hosting setup, -# you can specify the project name with a -p option and avoid having -# to modify this script. Try it with -n first to see the notification -# mail dumped to stdout and verify that it looks sane. Use -V to dump -# the version and exit. +# update hook. Try it with -n to see the notification mail dumped to +# stdout and verify that it looks sane. With -V it dumps its version +# and exits. # -# In post-commit, run it without arguments (other than possibly a -p -# option). It will query for current HEAD and the latest commit ID to -# get the information it needs. +# In post-commit, run it without arguments. It will query for +# current HEAD and the latest commit ID to get the information it +# needs. # # In update, you have to call it once per merged commit: # @@ -34,33 +35,76 @@ # oldhead=$2 # newhead=$3 # for merged in $(git rev-list ${oldhead}..${newhead} | tac) ; do -# /path/to/ciabot.bash ${refname} ${merged} +# /path/to/ciabot.sh ${refname} ${merged} # done # -# The reason for the tac call ids that git rev-list emits commits from +# The reason for the tac call is that git rev-list emits commits from # most recent to least - better to ship notifactions from oldest to newest. # -# Note: this script uses mail, not XML-RPC, in order to avoid stalling -# until timeout when the CIA XML-RPC server is down. +# Configuration variables affecting this script: # - +# ciabot.project = name of the project +# ciabot.repo = name of the project repo for gitweb/cgit purposes +# ciabot.revformat = format in which the revision is shown # -# The project as known to CIA. You will either want to change this -# or set the project name with a -p option. +# ciabot.project defaults to the directory name of the repository toplevel. +# ciabot.repo defaults to ciabot.project lowercased. # -project= - +# This means that in the normal case you need not do any configuration at all, +# but setting the project name will speed it up slightly. # -# You may not need to change these: +# The revformat variable may have the following values +# raw -> full hex ID of commit +# short -> first 12 chars of hex ID +# describe = -> describe relative to last tag, falling back to short +# The default is 'describe'. # +# Note: the shell ancestors of this script used mail, not XML-RPC, in +# order to avoid stalling until timeout when the CIA XML-RPC server is +# down. It is unknown whether this is still an issue in 2010, but +# XML-RPC would be annoying to do from sh in any case. (XML-RPC does +# have the advantage that it guarantees notification of multiple commits +# shpped from an update in their actual order.) +# + +# The project as known to CIA. You can set this with a -p option, +# or let it default to the directory name of the repo toplevel. +project=$(git config --get ciabot.project) + +if [ -z $project ] +then + here=`pwd`; + while :; do + if [ -d $here/.git ] + then + project=`basename $here` + break + elif [ $here = '/' ] + then + echo "ciabot.sh: no .git below root!" + exit 1 + fi + here=`dirname $here` + done +fi -# Name of the repository. -# You can hardwire this to make the script faster. -repo="`basename ${PWD}`" +# Name of the repo for gitweb/cgit purposes +repo=$(git config --get ciabot.repo) +[ -z $repo] && repo=$(echo "${project}" | tr '[A-Z]' '[a-z]') -# Fully qualified domain name of the repo host. -# You can hardwire this to make the script faster. -host=`hostname --fqdn` +# What revision format do we want in the summary? +revformat=$(git config --get ciabot.revformat) + +# Fully qualified domain name of the repo host. You can hardwire this +# to make the script faster. The -f option works under Linux and FreeBSD, +# but not OpenBSD and NetBSD. But under OpenBSD and NetBSD, +# hostname without options gives the FQDN. +if hostname -f >/dev/null 2>&1 +then + hostname=`hostname -f` +else + hostname=`hostname` +fi # Changeset URL prefix for your repo: when the commit ID is appended # to this, it should point at a CGI that will display the commit @@ -73,13 +117,14 @@ urlprefix="http://${host}/cgi-bin/cgit.cgi/${repo}/commit/?id=" # You probably will not need to change the following: # -# Identify the script. Should change only when the script itself -# gets a new home and maintainer. +# Identify the script. The 'generator' variable should change only +# when the script itself gets a new home and maintainer. generator="http://www.catb.org/~esr/ciabot/ciabot.sh" +version=3.5 # Addresses for the e-mail -from="CIABOT-NOREPLY@${host}" -to="cia@cia.navi.cx" +from="CIABOT-NOREPLY@${hostname}" +to="cia@cia.vc" # SMTP client to use - may need to edit the absolute pathname for your system sendmail="sendmail -t -f ${from}" @@ -97,7 +142,7 @@ do case $opt in p) project=$2; shift ; shift ;; n) mode=dumpit; shift ;; - V) echo "ciabot.sh: version 3.2"; exit 0; shift ;; + V) echo "ciabot.sh: version $version"; exit 0; shift ;; esac done @@ -128,33 +173,29 @@ fi refname=${refname##refs/heads/} -gitver=$(git --version) -gitver=${gitver##* } - -rev=$(git describe ${merged} 2>/dev/null) -# ${merged:0:12} was the only bashism left in the 2008 version of this -# script, according to checkbashisms. Replace it with ${merged} here -# because it was just a fallback anyway, and it's worth accepting a -# longer fallback for faster execution and removing the bash -# dependency. -[ -z ${rev} ] && rev=${merged} +case $revformat in +raw) rev=$merged ;; +short) rev='' ;; +*) rev=$(git describe ${merged} 2>/dev/null) ;; +esac +[ -z ${rev} ] && rev=$(echo "$merged" | cut -c 1-12) -# This discards the part of the author's address after @. +# We discard the part of the author's address after @. # Might be nice to ship the full email address, if not # for spammers' address harvesters - getting this wrong # would make the freenode #commits channel into harvester heaven. -rawcommit=$(git cat-file commit ${merged}) -author=$(echo "$rawcommit" | sed -n -e '/^author .*<\([^@]*\).*$/s--\1-p') -logmessage=$(echo "$rawcommit" | sed -e '1,/^$/d' | head -n 1) -logmessage=$(echo "$logmessage" | sed 's/\&/&\;/g; s/</<\;/g; s/>/>\;/g') -ts=$(echo "$rawcommit" | sed -n -e '/^author .*> \([0-9]\+\).*$/s--\1-p') +author=$(git log -1 '--pretty=format:%an <%ae>' $merged) +author=$(echo "$author" | sed -n -e '/^.*<\([^@]*\).*$/s--\1-p') + +logmessage=$(git log -1 '--pretty=format:%s' $merged) +ts=$(git log -1 '--pretty=format:%at' $merged) files=$(git diff-tree -r --name-only ${merged} | sed -e '1d' -e 's-.*-<file>&</file>-') out=" <message> <generator> <name>CIA Shell client for Git</name> - <version>${gitver}</version> + <version>${version}</version> <url>${generator}</url> </generator> <source> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index ffedce751c..222b804ce4 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1071,7 +1071,7 @@ _git_diff () } __git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff - tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3 + tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3 codecompare " _git_difftool () diff --git a/contrib/mw-to-git/git-remote-mediawiki b/contrib/mw-to-git/git-remote-mediawiki index 8647c92df8..68555d4265 100755 --- a/contrib/mw-to-git/git-remote-mediawiki +++ b/contrib/mw-to-git/git-remote-mediawiki @@ -9,20 +9,7 @@ # License: GPL v2 or later # Gateway between Git and MediaWiki. -# https://github.com/Bibzball/Git-Mediawiki/wiki -# -# Known limitations: -# -# - Several strategies are provided to fetch modifications from the -# wiki, but no automatic heuristics is provided, the user has -# to understand and chose which strategy is appropriate for him. -# -# - Git renames could be turned into MediaWiki renames (see TODO -# below) -# -# - No way to import "one page, and all pages included in it" -# -# - Multiple remote MediaWikis have not been very well tested. +# Documentation & bugtracker: https://github.com/moy/Git-Mediawiki/ use strict; use MediaWiki::API; diff --git a/diff-lib.c b/diff-lib.c index fc0dff31b5..f35de0ffa0 100644 --- a/diff-lib.c +++ b/diff-lib.c @@ -206,7 +206,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option) if (silent_on_removed) continue; diff_addremove(&revs->diffopt, '-', ce->ce_mode, - ce->sha1, ce->name, 0); + ce->sha1, !is_null_sha1(ce->sha1), + ce->name, 0); continue; } changed = match_stat_with_submodule(&revs->diffopt, ce, &st, @@ -220,6 +221,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option) newmode = ce_mode_from_stat(ce, st.st_mode); diff_change(&revs->diffopt, oldmode, newmode, ce->sha1, (changed ? null_sha1 : ce->sha1), + !is_null_sha1(ce->sha1), (changed ? 0 : !is_null_sha1(ce->sha1)), ce->name, 0, dirty_submodule); } @@ -236,11 +238,12 @@ int run_diff_files(struct rev_info *revs, unsigned int option) static void diff_index_show_file(struct rev_info *revs, const char *prefix, struct cache_entry *ce, - const unsigned char *sha1, unsigned int mode, + const unsigned char *sha1, int sha1_valid, + unsigned int mode, unsigned dirty_submodule) { diff_addremove(&revs->diffopt, prefix[0], mode, - sha1, ce->name, dirty_submodule); + sha1, sha1_valid, ce->name, dirty_submodule); } static int get_stat_data(struct cache_entry *ce, @@ -295,7 +298,7 @@ static void show_new_file(struct rev_info *revs, &dirty_submodule, &revs->diffopt) < 0) return; - diff_index_show_file(revs, "+", new, sha1, mode, dirty_submodule); + diff_index_show_file(revs, "+", new, sha1, !is_null_sha1(sha1), mode, dirty_submodule); } static int show_modified(struct rev_info *revs, @@ -312,7 +315,7 @@ static int show_modified(struct rev_info *revs, &dirty_submodule, &revs->diffopt) < 0) { if (report_missing) diff_index_show_file(revs, "-", old, - old->sha1, old->ce_mode, 0); + old->sha1, 1, old->ce_mode, 0); return -1; } @@ -347,7 +350,8 @@ static int show_modified(struct rev_info *revs, return 0; diff_change(&revs->diffopt, oldmode, mode, - old->sha1, sha1, old->name, 0, dirty_submodule); + old->sha1, sha1, 1, !is_null_sha1(sha1), + old->name, 0, dirty_submodule); return 0; } @@ -380,7 +384,7 @@ static void do_oneway_diff(struct unpack_trees_options *o, struct diff_filepair *pair; pair = diff_unmerge(&revs->diffopt, idx->name); if (tree) - fill_filespec(pair->one, tree->sha1, tree->ce_mode); + fill_filespec(pair->one, tree->sha1, 1, tree->ce_mode); return; } @@ -396,7 +400,7 @@ static void do_oneway_diff(struct unpack_trees_options *o, * Something removed from the tree? */ if (!idx) { - diff_index_show_file(revs, "-", tree, tree->sha1, tree->ce_mode, 0); + diff_index_show_file(revs, "-", tree, tree->sha1, 1, tree->ce_mode, 0); return; } diff --git a/diff-no-index.c b/diff-no-index.c index 7d805a06af..74da659368 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -82,7 +82,7 @@ static struct diff_filespec *noindex_filespec(const char *name, int mode) if (!name) name = "/dev/null"; s = alloc_filespec(name); - fill_filespec(s, null_sha1, mode); + fill_filespec(s, null_sha1, 0, mode); if (name == file_from_standard_input) populate_from_stdin(s); return s; @@ -258,8 +258,7 @@ void diff_no_index(struct rev_info *revs, DIFF_OPT_SET(&revs->diffopt, NO_INDEX); revs->max_count = -2; - if (diff_setup_done(&revs->diffopt) < 0) - die("diff_setup_done failed"); + diff_setup_done(&revs->diffopt); setup_diff_pager(&revs->diffopt); DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS); @@ -574,6 +574,7 @@ static void emit_rewrite_lines(struct emit_callback *ecb, if (!endp) { const char *plain = diff_get_color(ecb->color_diff, DIFF_PLAIN); + putc('\n', ecb->opt->file); emit_line_0(ecb->opt, plain, reset, '\\', nneof, strlen(nneof)); } @@ -1397,7 +1398,7 @@ int print_stat_summary(FILE *fp, int files, int insertions, int deletions) if (!files) { assert(insertions == 0 && deletions == 0); - return fputs(_(" 0 files changed\n"), fp); + return fprintf(fp, "%s\n", _(" 0 files changed")); } strbuf_addf(&sb, @@ -2541,12 +2542,12 @@ void free_filespec(struct diff_filespec *spec) } void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1, - unsigned short mode) + int sha1_valid, unsigned short mode) { if (mode) { spec->mode = canon_mode(mode); hashcpy(spec->sha1, sha1); - spec->sha1_valid = !is_null_sha1(sha1); + spec->sha1_valid = sha1_valid; } } @@ -3187,7 +3188,7 @@ void diff_setup(struct diff_options *options) } } -int diff_setup_done(struct diff_options *options) +void diff_setup_done(struct diff_options *options) { int count = 0; @@ -3286,8 +3287,6 @@ int diff_setup_done(struct diff_options *options) options->output_format = DIFF_FORMAT_NO_OUTPUT; DIFF_OPT_SET(options, EXIT_WITH_STATUS); } - - return 0; } static int opt_arg(const char *arg, int arg_short, const char *arg_long, int *val) @@ -4693,6 +4692,7 @@ static int is_submodule_ignored(const char *path, struct diff_options *options) void diff_addremove(struct diff_options *options, int addremove, unsigned mode, const unsigned char *sha1, + int sha1_valid, const char *concatpath, unsigned dirty_submodule) { struct diff_filespec *one, *two; @@ -4724,9 +4724,9 @@ void diff_addremove(struct diff_options *options, two = alloc_filespec(concatpath); if (addremove != '+') - fill_filespec(one, sha1, mode); + fill_filespec(one, sha1, sha1_valid, mode); if (addremove != '-') { - fill_filespec(two, sha1, mode); + fill_filespec(two, sha1, sha1_valid, mode); two->dirty_submodule = dirty_submodule; } @@ -4739,6 +4739,7 @@ void diff_change(struct diff_options *options, unsigned old_mode, unsigned new_mode, const unsigned char *old_sha1, const unsigned char *new_sha1, + int old_sha1_valid, int new_sha1_valid, const char *concatpath, unsigned old_dirty_submodule, unsigned new_dirty_submodule) { @@ -4753,6 +4754,8 @@ void diff_change(struct diff_options *options, const unsigned char *tmp_c; tmp = old_mode; old_mode = new_mode; new_mode = tmp; tmp_c = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_c; + tmp = old_sha1_valid; old_sha1_valid = new_sha1_valid; + new_sha1_valid = tmp; tmp = old_dirty_submodule; old_dirty_submodule = new_dirty_submodule; new_dirty_submodule = tmp; } @@ -4763,8 +4766,8 @@ void diff_change(struct diff_options *options, one = alloc_filespec(concatpath); two = alloc_filespec(concatpath); - fill_filespec(one, old_sha1, old_mode); - fill_filespec(two, new_sha1, new_mode); + fill_filespec(one, old_sha1, old_sha1_valid, old_mode); + fill_filespec(two, new_sha1, new_sha1_valid, new_mode); one->dirty_submodule = old_dirty_submodule; two->dirty_submodule = new_dirty_submodule; @@ -19,12 +19,14 @@ typedef void (*change_fn_t)(struct diff_options *options, unsigned old_mode, unsigned new_mode, const unsigned char *old_sha1, const unsigned char *new_sha1, + int old_sha1_valid, int new_sha1_valid, const char *fullpath, unsigned old_dirty_submodule, unsigned new_dirty_submodule); typedef void (*add_remove_fn_t)(struct diff_options *options, int addremove, unsigned mode, const unsigned char *sha1, + int sha1_valid, const char *fullpath, unsigned dirty_submodule); typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, @@ -214,12 +216,15 @@ extern void diff_addremove(struct diff_options *, int addremove, unsigned mode, const unsigned char *sha1, + int sha1_valid, const char *fullpath, unsigned dirty_submodule); extern void diff_change(struct diff_options *, unsigned mode1, unsigned mode2, const unsigned char *sha1, const unsigned char *sha2, + int sha1_valid, + int sha2_valid, const char *fullpath, unsigned dirty_submodule1, unsigned dirty_submodule2); @@ -241,7 +246,7 @@ extern int git_diff_ui_config(const char *var, const char *value, void *cb); extern int diff_use_color_default; extern void diff_setup(struct diff_options *); extern int diff_opt_parse(struct diff_options *, const char **, int); -extern int diff_setup_done(struct diff_options *); +extern void diff_setup_done(struct diff_options *); #define DIFF_DETECT_RENAME 1 #define DIFF_DETECT_COPY 2 diff --git a/diffcore-rename.c b/diffcore-rename.c index 216a7a4bbc..512d0ac5fd 100644 --- a/diffcore-rename.c +++ b/diffcore-rename.c @@ -48,7 +48,7 @@ static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two, memmove(rename_dst + first + 1, rename_dst + first, (rename_dst_nr - first - 1) * sizeof(*rename_dst)); rename_dst[first].two = alloc_filespec(two->path); - fill_filespec(rename_dst[first].two, two->sha1, two->mode); + fill_filespec(rename_dst[first].two, two->sha1, two->sha1_valid, two->mode); rename_dst[first].pair = NULL; return &(rename_dst[first]); } diff --git a/diffcore.h b/diffcore.h index be0739c5c4..1c16c8595b 100644 --- a/diffcore.h +++ b/diffcore.h @@ -55,7 +55,7 @@ struct diff_filespec { extern struct diff_filespec *alloc_filespec(const char *); extern void free_filespec(struct diff_filespec *); extern void fill_filespec(struct diff_filespec *, const unsigned char *, - unsigned short); + int, unsigned short); extern int diff_populate_filespec(struct diff_filespec *, int); extern void diff_free_filespec_data(struct diff_filespec *); @@ -139,6 +139,7 @@ static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, con static int fsck_tree(struct tree *item, int strict, fsck_error error_func) { int retval; + int has_null_sha1 = 0; int has_full_path = 0; int has_empty_name = 0; int has_zero_pad = 0; @@ -157,9 +158,12 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func) while (desc.size) { unsigned mode; const char *name; + const unsigned char *sha1; - tree_entry_extract(&desc, &name, &mode); + sha1 = tree_entry_extract(&desc, &name, &mode); + if (is_null_sha1(sha1)) + has_null_sha1 = 1; if (strchr(name, '/')) has_full_path = 1; if (!*name) @@ -207,6 +211,8 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func) } retval = 0; + if (has_null_sha1) + retval += error_func(&item->object, FSCK_WARN, "contains entries pointing to null sha1"); if (has_full_path) retval += error_func(&item->object, FSCK_WARN, "contains full pathnames"); if (has_empty_name) @@ -92,7 +92,7 @@ safe_to_abort () { then return 0 fi - gettextln "You seem to have moved HEAD since the last 'am' failure. + gettextln "You seem to have moved HEAD since the last 'am' failure. Not rewinding to ORIG_HEAD" >&2 return 1 } @@ -102,9 +102,9 @@ stop_here_user_resolve () { printf '%s\n' "$resolvemsg" stop_here $1 fi - eval_gettextln "When you have resolved this problem run \"\$cmdline --resolved\". -If you would prefer to skip this patch, instead run \"\$cmdline --skip\". -To restore the original branch and stop patching run \"\$cmdline --abort\"." + eval_gettextln "When you have resolved this problem, run \"\$cmdline --resolved\". +If you prefer to skip this patch, run \"\$cmdline --skip\" instead. +To restore the original branch and stop patching, run \"\$cmdline --abort\"." stop_here $1 } @@ -136,7 +136,7 @@ fall_back_3way () { git write-tree >"$dotest/patch-merge-base+" || cannot_fallback "$(gettext "Repository lacks necessary blobs to fall back on 3-way merge.")" - say Using index info to reconstruct a base tree... + say "$(gettext "Using index info to reconstruct a base tree...")" cmd='GIT_INDEX_FILE="$dotest/patch-merge-tmp-index"' @@ -176,8 +176,7 @@ It does not apply to blobs recorded in its index.")" fi git-merge-recursive $orig_tree -- HEAD $his_tree || { git rerere $allow_rerere_autoupdate - echo Failed to merge in the changes. - exit 1 + die "$(gettext "Failed to merge in the changes.")" } unset GITHEAD_$his_tree } @@ -387,8 +386,8 @@ do -i|--interactive) interactive=t ;; -b|--binary) - echo >&2 "The $1 option has been a no-op for long time, and" - echo >&2 "it will be removed. Please do not use it anymore." + gettextln >&2 "The -b/--binary option has been a no-op for long time, and +it will be removed. Please do not use it anymore." ;; -3|--3way) threeway=t ;; @@ -414,9 +413,6 @@ do abort=t ;; --rebasing) rebasing=t threeway=t ;; - -d|--dotest) - die "$(gettext "-d option is no longer supported. Do not use.")" - ;; --resolvemsg) shift; resolvemsg=$1 ;; --whitespace|--directory|--exclude|--include) diff --git a/git-difftool.perl b/git-difftool.perl index c0798540ad..edd0493a08 100755 --- a/git-difftool.perl +++ b/git-difftool.perl @@ -18,17 +18,11 @@ use File::Copy; use File::Compare; use File::Find; use File::stat; -use File::Path qw(mkpath); +use File::Path qw(mkpath rmtree); use File::Temp qw(tempdir); use Getopt::Long qw(:config pass_through); use Git; -my @tools; -my @working_tree; -my $rc; -my $repo = Git->repository(); -my $repo_path = $repo->repo_path(); - sub usage { my $exitcode = shift; @@ -45,6 +39,8 @@ USAGE sub find_worktree { + my ($repo) = @_; + # Git->repository->wc_path() does not honor changes to the working # tree location made by $ENV{GIT_WORK_TREE} or the 'core.worktree' # config variable. @@ -63,10 +59,9 @@ sub find_worktree return $worktree; } -my $workdir = find_worktree(); - sub filter_tool_scripts { + my ($tools) = @_; if (-d $_) { if ($_ ne ".") { # Ignore files in subdirectories @@ -74,17 +69,17 @@ sub filter_tool_scripts } } else { if ((-f $_) && ($_ ne "defaults")) { - push(@tools, $_); + push(@$tools, $_); } } } sub print_tool_help { - my ($cmd, @found, @notfound); + my ($cmd, @found, @notfound, @tools); my $gitpath = Git::exec_path(); - find(\&filter_tool_scripts, "$gitpath/mergetools"); + find(sub { filter_tool_scripts(\@tools) }, "$gitpath/mergetools"); foreach my $tool (@tools) { $cmd = "TOOL_MODE=diff"; @@ -98,34 +93,52 @@ sub print_tool_help } } - print "'git difftool --tool=<tool>' may be set to one of the following:\n"; + print << 'EOF'; +'git difftool --tool=<tool>' may be set to one of the following: +EOF print "\t$_\n" for (sort(@found)); - print "\nThe following tools are valid, but not currently available:\n"; + print << 'EOF'; + +The following tools are valid, but not currently available: +EOF print "\t$_\n" for (sort(@notfound)); - print "\nNOTE: Some of the tools listed above only work in a windowed\n"; - print "environment. If run in a terminal-only session, they will fail.\n"; + print << 'EOF'; +NOTE: Some of the tools listed above only work in a windowed +environment. If run in a terminal-only session, they will fail. +EOF exit(0); } +sub exit_cleanup +{ + my ($tmpdir, $status) = @_; + my $errno = $!; + rmtree($tmpdir); + if ($status and $errno) { + my ($package, $file, $line) = caller(); + warn "$file line $line: $errno\n"; + } + exit($status | ($status >> 8)); +} + sub setup_dir_diff { + my ($repo, $workdir, $symlinks) = @_; + # Run the diff; exit immediately if no diff found # 'Repository' and 'WorkingCopy' must be explicitly set to insure that # if $GIT_DIR and $GIT_WORK_TREE are set in ENV, they are actually used # by Git->repository->command*. - my $diffrepo = Git->repository(Repository => $repo_path, WorkingCopy => $workdir); - my $diffrtn = $diffrepo->command_oneline('diff', '--raw', '--no-abbrev', '-z', @ARGV); - exit(0) if (length($diffrtn) == 0); + my $repo_path = $repo->repo_path(); + my %repo_args = (Repository => $repo_path, WorkingCopy => $workdir); + my $diffrepo = Git->repository(%repo_args); - # Setup temp directories - my $tmpdir = tempdir('git-diffall.XXXXX', CLEANUP => 1, TMPDIR => 1); - my $ldir = "$tmpdir/left"; - my $rdir = "$tmpdir/right"; - mkpath($ldir) or die $!; - mkpath($rdir) or die $!; + my @gitargs = ('diff', '--raw', '--no-abbrev', '-z', @ARGV); + my $diffrtn = $diffrepo->command_oneline(@gitargs); + exit(0) unless defined($diffrtn); # Build index info for left and right sides of the diff my $submodule_mode = '160000'; @@ -136,16 +149,21 @@ sub setup_dir_diff my $rindex = ''; my %submodule; my %symlink; + my @working_tree = (); my @rawdiff = split('\0', $diffrtn); my $i = 0; while ($i < $#rawdiff) { if ($rawdiff[$i] =~ /^::/) { - print "Combined diff formats ('-c' and '--cc') are not supported in directory diff mode.\n"; + warn << 'EOF'; +Combined diff formats ('-c' and '--cc') are not supported in +directory diff mode ('-d' and '--dir-diff'). +EOF exit(1); } - my ($lmode, $rmode, $lsha1, $rsha1, $status) = split(' ', substr($rawdiff[$i], 1)); + my ($lmode, $rmode, $lsha1, $rsha1, $status) = + split(' ', substr($rawdiff[$i], 1)); my $src_path = $rawdiff[$i + 1]; my $dst_path; @@ -157,7 +175,7 @@ sub setup_dir_diff $i += 2; } - if (($lmode eq $submodule_mode) or ($rmode eq $submodule_mode)) { + if ($lmode eq $submodule_mode or $rmode eq $submodule_mode) { $submodule{$src_path}{left} = $lsha1; if ($lsha1 ne $rsha1) { $submodule{$dst_path}{right} = $rsha1; @@ -168,14 +186,16 @@ sub setup_dir_diff } if ($lmode eq $symlink_mode) { - $symlink{$src_path}{left} = $diffrepo->command_oneline('show', "$lsha1"); + $symlink{$src_path}{left} = + $diffrepo->command_oneline('show', "$lsha1"); } if ($rmode eq $symlink_mode) { - $symlink{$dst_path}{right} = $diffrepo->command_oneline('show', "$rsha1"); + $symlink{$dst_path}{right} = + $diffrepo->command_oneline('show', "$rsha1"); } - if (($lmode ne $null_mode) and ($status !~ /^C/)) { + if ($lmode ne $null_mode and $status !~ /^C/) { $lindex .= "$lmode $lsha1\t$src_path\0"; } @@ -188,6 +208,13 @@ sub setup_dir_diff } } + # Setup temp directories + my $tmpdir = tempdir('git-difftool.XXXXX', CLEANUP => 0, TMPDIR => 1); + my $ldir = "$tmpdir/left"; + my $rdir = "$tmpdir/right"; + mkpath($ldir) or exit_cleanup($tmpdir, 1); + mkpath($rdir) or exit_cleanup($tmpdir, 1); + # If $GIT_DIR is not set prior to calling 'git update-index' and # 'git checkout-index', then those commands will fail if difftool # is called from a directory other than the repo root. @@ -200,18 +227,22 @@ sub setup_dir_diff # Populate the left and right directories based on each index file my ($inpipe, $ctx); $ENV{GIT_INDEX_FILE} = "$tmpdir/lindex"; - ($inpipe, $ctx) = $repo->command_input_pipe(qw/update-index -z --index-info/); + ($inpipe, $ctx) = + $repo->command_input_pipe(qw(update-index -z --index-info)); print($inpipe $lindex); $repo->command_close_pipe($inpipe, $ctx); - $rc = system('git', 'checkout-index', '--all', "--prefix=$ldir/"); - exit($rc | ($rc >> 8)) if ($rc != 0); + + my $rc = system('git', 'checkout-index', '--all', "--prefix=$ldir/"); + exit_cleanup($tmpdir, $rc) if $rc != 0; $ENV{GIT_INDEX_FILE} = "$tmpdir/rindex"; - ($inpipe, $ctx) = $repo->command_input_pipe(qw/update-index -z --index-info/); + ($inpipe, $ctx) = + $repo->command_input_pipe(qw(update-index -z --index-info)); print($inpipe $rindex); $repo->command_close_pipe($inpipe, $ctx); + $rc = system('git', 'checkout-index', '--all', "--prefix=$rdir/"); - exit($rc | ($rc >> 8)) if ($rc != 0); + exit_cleanup($tmpdir, $rc) if $rc != 0; # If $GIT_DIR was explicitly set just for the update/checkout # commands, then it should be unset before continuing. @@ -223,37 +254,55 @@ sub setup_dir_diff for my $file (@working_tree) { my $dir = dirname($file); unless (-d "$rdir/$dir") { - mkpath("$rdir/$dir") or die $!; + mkpath("$rdir/$dir") or + exit_cleanup($tmpdir, 1); + } + if ($symlinks) { + symlink("$workdir/$file", "$rdir/$file") or + exit_cleanup($tmpdir, 1); + } else { + copy("$workdir/$file", "$rdir/$file") or + exit_cleanup($tmpdir, 1); + + my $mode = stat("$workdir/$file")->mode; + chmod($mode, "$rdir/$file") or + exit_cleanup($tmpdir, 1); } - copy("$workdir/$file", "$rdir/$file") or die $!; - chmod(stat("$workdir/$file")->mode, "$rdir/$file") or die $!; } # Changes to submodules require special treatment. This loop writes a # temporary file to both the left and right directories to show the # change in the recorded SHA1 for the submodule. for my $path (keys %submodule) { + my $ok; if (defined($submodule{$path}{left})) { - write_to_file("$ldir/$path", "Subproject commit $submodule{$path}{left}"); + $ok = write_to_file("$ldir/$path", + "Subproject commit $submodule{$path}{left}"); } if (defined($submodule{$path}{right})) { - write_to_file("$rdir/$path", "Subproject commit $submodule{$path}{right}"); + $ok = write_to_file("$rdir/$path", + "Subproject commit $submodule{$path}{right}"); } + exit_cleanup($tmpdir, 1) if not $ok; } # Symbolic links require special treatment. The standard "git diff" # shows only the link itself, not the contents of the link target. # This loop replicates that behavior. for my $path (keys %symlink) { + my $ok; if (defined($symlink{$path}{left})) { - write_to_file("$ldir/$path", $symlink{$path}{left}); + $ok = write_to_file("$ldir/$path", + $symlink{$path}{left}); } if (defined($symlink{$path}{right})) { - write_to_file("$rdir/$path", $symlink{$path}{right}); + $ok = write_to_file("$rdir/$path", + $symlink{$path}{right}); } + exit_cleanup($tmpdir, 1) if not $ok; } - return ($ldir, $rdir); + return ($ldir, $rdir, $tmpdir, @working_tree); } sub write_to_file @@ -264,85 +313,141 @@ sub write_to_file # Make sure the path to the file exists my $dir = dirname($path); unless (-d "$dir") { - mkpath("$dir") or die $!; + mkpath("$dir") or return 0; } # If the file already exists in that location, delete it. This # is required in the case of symbolic links. - unlink("$path"); + unlink($path); - open(my $fh, '>', "$path") or die $!; + open(my $fh, '>', $path) or return 0; print($fh $value); close($fh); -} -# parse command-line options. all unrecognized options and arguments -# are passed through to the 'git diff' command. -my ($difftool_cmd, $dirdiff, $extcmd, $gui, $help, $prompt, $tool_help); -GetOptions('g|gui!' => \$gui, - 'd|dir-diff' => \$dirdiff, - 'h' => \$help, - 'prompt!' => \$prompt, - 'y' => sub { $prompt = 0; }, - 't|tool:s' => \$difftool_cmd, - 'tool-help' => \$tool_help, - 'x|extcmd:s' => \$extcmd); - -if (defined($help)) { - usage(0); -} -if (defined($tool_help)) { - print_tool_help(); + return 1; } -if (defined($difftool_cmd)) { - if (length($difftool_cmd) > 0) { - $ENV{GIT_DIFF_TOOL} = $difftool_cmd; - } else { - print "No <tool> given for --tool=<tool>\n"; - usage(1); + +sub main +{ + # parse command-line options. all unrecognized options and arguments + # are passed through to the 'git diff' command. + my %opts = ( + difftool_cmd => undef, + dirdiff => undef, + extcmd => undef, + gui => undef, + help => undef, + prompt => undef, + symlinks => $^O ne 'cygwin' && + $^O ne 'MSWin32' && $^O ne 'msys', + tool_help => undef, + ); + GetOptions('g|gui!' => \$opts{gui}, + 'd|dir-diff' => \$opts{dirdiff}, + 'h' => \$opts{help}, + 'prompt!' => \$opts{prompt}, + 'y' => sub { $opts{prompt} = 0; }, + 'symlinks' => \$opts{symlinks}, + 'no-symlinks' => sub { $opts{symlinks} = 0; }, + 't|tool:s' => \$opts{difftool_cmd}, + 'tool-help' => \$opts{tool_help}, + 'x|extcmd:s' => \$opts{extcmd}); + + if (defined($opts{help})) { + usage(0); } -} -if (defined($extcmd)) { - if (length($extcmd) > 0) { - $ENV{GIT_DIFFTOOL_EXTCMD} = $extcmd; - } else { - print "No <cmd> given for --extcmd=<cmd>\n"; - usage(1); + if (defined($opts{tool_help})) { + print_tool_help(); } -} -if ($gui) { - my $guitool = ''; - $guitool = Git::config('diff.guitool'); - if (length($guitool) > 0) { - $ENV{GIT_DIFF_TOOL} = $guitool; + if (defined($opts{difftool_cmd})) { + if (length($opts{difftool_cmd}) > 0) { + $ENV{GIT_DIFF_TOOL} = $opts{difftool_cmd}; + } else { + print "No <tool> given for --tool=<tool>\n"; + usage(1); + } + } + if (defined($opts{extcmd})) { + if (length($opts{extcmd}) > 0) { + $ENV{GIT_DIFFTOOL_EXTCMD} = $opts{extcmd}; + } else { + print "No <cmd> given for --extcmd=<cmd>\n"; + usage(1); + } + } + if ($opts{gui}) { + my $guitool = Git::config('diff.guitool'); + if (length($guitool) > 0) { + $ENV{GIT_DIFF_TOOL} = $guitool; + } + } + + # In directory diff mode, 'git-difftool--helper' is called once + # to compare the a/b directories. In file diff mode, 'git diff' + # will invoke a separate instance of 'git-difftool--helper' for + # each file that changed. + if (defined($opts{dirdiff})) { + dir_diff($opts{extcmd}, $opts{symlinks}); + } else { + file_diff($opts{prompt}); } } -# In directory diff mode, 'git-difftool--helper' is called once -# to compare the a/b directories. In file diff mode, 'git diff' -# will invoke a separate instance of 'git-difftool--helper' for -# each file that changed. -if (defined($dirdiff)) { - my ($a, $b) = setup_dir_diff(); +sub dir_diff +{ + my ($extcmd, $symlinks) = @_; + my $rc; + my $error = 0; + my $repo = Git->repository(); + my $workdir = find_worktree($repo); + my ($a, $b, $tmpdir, @worktree) = + setup_dir_diff($repo, $workdir, $symlinks); + if (defined($extcmd)) { $rc = system($extcmd, $a, $b); } else { $ENV{GIT_DIFFTOOL_DIRDIFF} = 'true'; $rc = system('git', 'difftool--helper', $a, $b); } - - exit($rc | ($rc >> 8)) if ($rc != 0); - # If the diff including working copy files and those # files were modified during the diff, then the changes - # should be copied back to the working tree - for my $file (@working_tree) { - if (-e "$b/$file" && compare("$b/$file", "$workdir/$file")) { - copy("$b/$file", "$workdir/$file") or die $!; - chmod(stat("$b/$file")->mode, "$workdir/$file") or die $!; + # should be copied back to the working tree. + # Do not copy back files when symlinks are used and the + # external tool did not replace the original link with a file. + for my $file (@worktree) { + next if $symlinks && -l "$b/$file"; + next if ! -f "$b/$file"; + + my $diff = compare("$b/$file", "$workdir/$file"); + if ($diff == 0) { + next; + } elsif ($diff == -1) { + my $errmsg = "warning: Could not compare "; + $errmsg += "'$b/$file' with '$workdir/$file'\n"; + warn $errmsg; + $error = 1; + } elsif ($diff == 1) { + my $mode = stat("$b/$file")->mode; + copy("$b/$file", "$workdir/$file") or + exit_cleanup($tmpdir, 1); + + chmod($mode, "$workdir/$file") or + exit_cleanup($tmpdir, 1); } } -} else { + if ($error) { + warn "warning: Temporary files exist in '$tmpdir'.\n"; + warn "warning: You may want to cleanup or recover these.\n"; + exit(1); + } else { + exit_cleanup($tmpdir, $rc); + } +} + +sub file_diff +{ + my ($prompt) = @_; + if (defined($prompt)) { if ($prompt) { $ENV{GIT_DIFFTOOL_PROMPT} = 'true'; @@ -362,3 +467,5 @@ if (defined($dirdiff)) { my $rc = system('git', 'diff', @ARGV); exit($rc | ($rc >> 8)); } + +main(); diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh index f730253c0e..54cb708254 100644 --- a/git-mergetool--lib.sh +++ b/git-mergetool--lib.sh @@ -126,7 +126,7 @@ list_merge_tool_candidates () { else tools="opendiff kdiff3 tkdiff xxdiff meld $tools" fi - tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3" + tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3 codecompare" fi case "${VISUAL:-$EDITOR}" in *vim*) diff --git a/git-rebase.sh b/git-rebase.sh index 1cd0633b80..15da926ce0 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -3,31 +3,6 @@ # Copyright (c) 2005 Junio C Hamano. # -USAGE='[--interactive | -i] [--exec | -x <cmd>] [-v] [--force-rebase | -f] - [--no-ff] [--onto <newbase>] [<upstream>|--root] [<branch>] [--quiet | -q]' -LONG_USAGE='git-rebase replaces <branch> with a new branch of the -same name. When the --onto option is provided the new branch starts -out with a HEAD equal to <newbase>, otherwise it is equal to <upstream> -It then attempts to create a new commit for each commit from the original -<branch> that does not exist in the <upstream> branch. - -It is possible that a merge failure will prevent this process from being -completely automatic. You will have to resolve any such merge failure -and run git rebase --continue. Another option is to bypass the commit -that caused the merge failure with git rebase --skip. To check out the -original <branch> and remove the .git/rebase-apply working files, use the -command git rebase --abort instead. - -Note that if <branch> is not specified on the command line, the -currently checked out branch is used. - -Example: git-rebase master~1 topic - - A---B---C topic A'\''--B'\''--C'\'' topic - / --> / - D---E---F---G master D---E---F---G master -' - SUBDIRECTORY_OK=Yes OPTIONS_KEEPDASHDASH= OPTIONS_SPEC="\ @@ -65,6 +40,7 @@ abort! abort and check out the original branch skip! skip current patch and continue " . git-sh-setup +. git-sh-i18n set_reflog_action rebase require_work_tree_exists cd_to_toplevel @@ -73,9 +49,9 @@ LF=' ' ok_to_skip_pre_rebase= resolvemsg=" -When you have resolved this problem run \"git rebase --continue\". -If you would prefer to skip this patch, instead run \"git rebase --skip\". -To check out the original branch and stop rebasing run \"git rebase --abort\". +$(gettext 'When you have resolved this problem, run "git rebase --continue". +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 cmd= @@ -161,7 +137,7 @@ move_to_original_branch () { git symbolic-ref \ -m "rebase finished: returning to $head_name" \ HEAD $head_name || - die "Could not move back to $head_name" + die "$(gettext "Could not move back to $head_name")" ;; esac } @@ -180,12 +156,12 @@ run_pre_rebase_hook () { test -x "$GIT_DIR/hooks/pre-rebase" then "$GIT_DIR/hooks/pre-rebase" ${1+"$@"} || - die "The pre-rebase hook refused to rebase." + die "$(gettext "The pre-rebase hook refused to rebase.")" fi } test -f "$apply_dir"/applying && - die 'It looks like git-am is in progress. Cannot rebase.' + die "$(gettext "It looks like git-am is in progress. Cannot rebase.")" if test -d "$apply_dir" then @@ -316,12 +292,12 @@ test $# -gt 2 && usage if test -n "$cmd" && test "$interactive_rebase" != explicit then - die "--exec option must be used with --interactive option" + die "$(gettext "The --exec option must be used with the --interactive option")" fi if test -n "$action" then - test -z "$in_progress" && die "No rebase in progress?" + test -z "$in_progress" && die "$(gettext "No rebase in progress?")" # Only interactive rebase uses detailed reflog messages if test "$type" = interactive && test "$GIT_REFLOG_ACTION" = rebase then @@ -334,11 +310,11 @@ case "$action" in continue) # Sanity check git rev-parse --verify HEAD >/dev/null || - die "Cannot read HEAD" + die "$(gettext "Cannot read HEAD")" git update-index --ignore-submodules --refresh && git diff-files --quiet --ignore-submodules || { - echo "You must edit all merge conflicts and then" - echo "mark them as resolved using git add" + echo "$(gettext "You must edit all merge conflicts and then +mark them as resolved using git add")" exit 1 } read_basic_state @@ -355,7 +331,7 @@ abort) case "$head_name" in refs/*) git symbolic-ref -m "rebase: aborting" HEAD $head_name || - die "Could not move back to $head_name" + die "$(eval_gettext "Could not move back to \$head_name")" ;; esac output git reset --hard $orig_head @@ -367,15 +343,18 @@ esac # Make sure no rebase is in progress if test -n "$in_progress" then - die ' -It seems that there is already a '"${state_dir##*/}"' directory, and + state_dir_base=${state_dir##*/} + cmd_live_rebase="git rebase (--continue | --abort | --skip)" + cmd_clear_stale_rebase="rm -fr \"$state_dir\"" + die " +$(eval_gettext 'It seems that there is already a $state_dir_base directory, and I wonder if you are in the middle of another rebase. If that is the case, please try - git rebase (--continue | --abort | --skip) + $cmd_live_rebase If that is not the case, please - rm -fr '"$state_dir"' + $cmd_clear_stale_rebase and run me again. I am stopping in case you still have something -valuable there.' +valuable there.')" fi if test -n "$rebase_root" && test -z "$onto" @@ -413,7 +392,7 @@ then ;; esac upstream=`git rev-parse --verify "${upstream_name}^0"` || - die "invalid upstream $upstream_name" + die "$(eval_gettext "invalid upstream \$upstream_name")" upstream_arg="$upstream_name" else if test -z "$onto" @@ -437,19 +416,19 @@ case "$onto_name" in then case "$onto" in ?*"$LF"?*) - die "$onto_name: there are more than one merge bases" + die "$(eval_gettext "\$onto_name: there are more than one merge bases")" ;; '') - die "$onto_name: there is no merge base" + die "$(eval_gettext "\$onto_name: there is no merge base")" ;; esac else - die "$onto_name: there is no merge base" + die "$(eval_gettext "\$onto_name: there is no merge base")" fi ;; *) onto=$(git rev-parse --verify "${onto_name}^0") || - die "Does not point to a valid commit: $onto_name" + die "$(eval_gettext "Does not point to a valid commit: \$onto_name")" ;; esac @@ -472,7 +451,7 @@ case "$#" in then head_name="detached HEAD" else - die "fatal: no such branch: $1" + die "$(eval_gettext "fatal: no such branch: \$branch_name")" fi ;; 0) @@ -492,7 +471,7 @@ case "$#" in ;; esac -require_clean_work_tree "rebase" "Please commit or stash them." +require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")" # Now we are rebasing commits $upstream..$orig_head (or with --root, # everything leading up to $orig_head) on top of $onto @@ -510,10 +489,10 @@ then then # Lazily switch to the target branch if needed... test -z "$switch_to" || git checkout "$switch_to" -- - say "Current branch $branch_name is up to date." + say "$(eval_gettext "Current branch \$branch_name is up to date.")" exit 0 else - say "Current branch $branch_name is up to date, rebase forced." + say "$(eval_gettext "Current branch \$branch_name is up to date, rebase forced.")" fi fi @@ -524,7 +503,7 @@ if test -n "$diffstat" then if test -n "$verbose" then - echo "Changes from $mb to $onto:" + echo "$(eval_gettext "Changes from \$mb to \$onto:")" fi # We want color (if set), but no pager GIT_PAGER='' git diff --stat --summary "$mb" "$onto" @@ -533,7 +512,7 @@ fi test "$type" = interactive && run_specific_rebase # Detach HEAD and reset the tree -say "First, rewinding head to replay your work on top of it..." +say "$(gettext "First, rewinding head to replay your work on top of it...")" git checkout -q "$onto^0" || die "could not detach HEAD" git update-ref ORIG_HEAD $orig_head @@ -541,7 +520,7 @@ git update-ref ORIG_HEAD $orig_head # we just fast-forwarded. if test "$mb" = "$orig_head" then - say "Fast-forwarded $branch_name to $onto_name." + say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")" move_to_original_branch exit 0 fi diff --git a/git-send-email.perl b/git-send-email.perl index ef30c557c7..664713709c 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -862,11 +862,13 @@ $time = time - scalar $#files; sub unquote_rfc2047 { local ($_) = @_; my $encoding; - if (s/=\?([^?]+)\?q\?(.*)\?=/$2/g) { + s{=\?([^?]+)\?q\?(.*?)\?=}{ $encoding = $1; - s/_/ /g; - s/=([0-9A-F]{2})/chr(hex($1))/eg; - } + my $e = $2; + $e =~ s/_/ /g; + $e =~ s/=([0-9A-F]{2})/chr(hex($1))/eg; + $e; + }eg; return wantarray ? ($_, $encoding) : $_; } diff --git a/git-submodule.sh b/git-submodule.sh index dba4d39e1f..aac575e74f 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -181,8 +181,11 @@ module_clone() rm -f "$gitdir/index" else mkdir -p "$gitdir_base" - git clone $quiet -n ${reference:+"$reference"} \ - --separate-git-dir "$gitdir" "$url" "$sm_path" || + ( + clear_local_git_env + git clone $quiet -n ${reference:+"$reference"} \ + --separate-git-dir "$gitdir" "$url" "$sm_path" + ) || die "$(eval_gettext "Clone of '\$url' into submodule path '\$sm_path' failed")" fi @@ -748,7 +751,7 @@ cmd_summary() { if [ -n "$files" ] then test -n "$cached" && - die "$(gettext -- "--cached cannot be used with --files")" + die "$(gettext "The --cached option cannot be used with the --files option")" diff_cmd=diff-files head= fi diff --git a/git-svn.perl b/git-svn.perl index 6673d21f84..0d77ffb0b9 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -10,6 +10,52 @@ use vars qw/ $AUTHOR $VERSION $AUTHOR = 'Eric Wong <normalperson@yhbt.net>'; $VERSION = '@@GIT_VERSION@@'; +use Carp qw/croak/; +use Digest::MD5; +use IO::File qw//; +use File::Basename qw/dirname basename/; +use File::Path qw/mkpath/; +use File::Spec; +use File::Find; +use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/; +use IPC::Open3; +use Memoize; + +use Git::SVN; +use Git::SVN::Editor; +use Git::SVN::Fetcher; +use Git::SVN::Ra; +use Git::SVN::Prompt; +use Git::SVN::Log; +use Git::SVN::Migration; + +use Git::SVN::Utils qw( + fatal + can_compress + canonicalize_path + canonicalize_url + join_paths + add_path_to_url + join_paths +); + +use Git qw( + git_cmd_try + command + command_oneline + command_noisy + command_output_pipe + command_close_pipe + command_bidi_pipe + command_close_bidi_pipe +); + +BEGIN { + Memoize::memoize 'Git::config'; + Memoize::memoize 'Git::config_bool'; +} + + # From which subdir have we been invoked? my $cmd_dir_prefix = eval { command_oneline([qw/rev-parse --show-prefix/], STDERR => 0) @@ -17,10 +63,7 @@ my $cmd_dir_prefix = eval { my $git_dir_user_set = 1 if defined $ENV{GIT_DIR}; $ENV{GIT_DIR} ||= '.git'; -$Git::SVN::default_repo_id = 'svn'; -$Git::SVN::default_ref_id = $ENV{GIT_SVN_ID} || 'git-svn'; $Git::SVN::Ra::_log_window_size = 100; -$Git::SVN::_minimize_url = 'unset'; if (! exists $ENV{SVN_SSH} && exists $ENV{GIT_SSH}) { $ENV{SVN_SSH} = $ENV{GIT_SSH}; @@ -35,8 +78,6 @@ $Git::SVN::Log::TZ = $ENV{TZ}; $ENV{TZ} = 'UTC'; $| = 1; # unbuffer STDOUT -sub fatal (@) { print STDERR "@_\n"; exit 1 } - # All SVN commands do it. Otherwise we may die on SIGPIPE when the remote # repository decides to close the connection which we expect to be kept alive. $SIG{PIPE} = 'IGNORE'; @@ -66,39 +107,6 @@ sub _req_svn { fatal "Need SVN::Core 1.1.0 or better (got $SVN::Core::VERSION)"; } } -my $can_compress = eval { require Compress::Zlib; 1}; -use Carp qw/croak/; -use Digest::MD5; -use IO::File qw//; -use File::Basename qw/dirname basename/; -use File::Path qw/mkpath/; -use File::Spec; -use File::Find; -use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/; -use IPC::Open3; -use Git; -use Git::SVN::Editor qw//; -use Git::SVN::Fetcher qw//; -use Git::SVN::Ra qw//; -use Git::SVN::Prompt qw//; -use Memoize; # core since 5.8.0, Jul 2002 - -BEGIN { - # import functions from Git into our packages, en masse - no strict 'refs'; - foreach (qw/command command_oneline command_noisy command_output_pipe - command_input_pipe command_close_pipe - command_bidi_pipe command_close_bidi_pipe/) { - for my $package ( qw(Git::SVN::Migration Git::SVN::Log Git::SVN), - __PACKAGE__) { - *{"${package}::$_"} = \&{"Git::$_"}; - } - } - Memoize::memoize 'Git::config'; - Memoize::memoize 'Git::config_bool'; -} - -my ($SVN); $sha1 = qr/[a-f\d]{40}/; $sha1_short = qr/[a-f\d]{4,40}/; @@ -108,8 +116,11 @@ my ($_stdin, $_help, $_edit, $_version, $_fetch_all, $_no_rebase, $_fetch_parent, $_merge, $_strategy, $_preserve_merges, $_dry_run, $_local, $_prefix, $_no_checkout, $_url, $_verbose, - $_git_format, $_commit_url, $_tag, $_merge_info, $_interactive); -$Git::SVN::_follow_parent = 1; + $_commit_url, $_tag, $_merge_info, $_interactive); + +# This is a refactoring artifact so Git::SVN can get at this git-svn switch. +sub opt_prefix { return $_prefix || '' } + $Git::SVN::Fetcher::_placeholder_filename = ".gitignore"; $_q ||= 0; my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username, @@ -269,7 +280,7 @@ my %cmd = ( { 'url' => \$_url, } ], 'blame' => [ \&Git::SVN::Log::cmd_blame, "Show what revision and author last modified each line of a file", - { 'git-format' => \$_git_format } ], + { 'git-format' => \$Git::SVN::Log::_git_format } ], 'reset' => [ \&cmd_reset, "Undo fetches back to the specified SVN revision", { 'revision|r=s' => \$_revision, @@ -775,6 +786,44 @@ sub populate_merge_info { return undef; } +sub dcommit_rebase { + my ($is_last, $current, $fetched_ref, $svn_error) = @_; + my @diff; + + if ($svn_error) { + print STDERR "\nERROR from SVN:\n", + $svn_error->expanded_message, "\n"; + } + unless ($_no_rebase) { + # we always want to rebase against the current HEAD, + # not any head that was passed to us + @diff = command('diff-tree', $current, + $fetched_ref, '--'); + my @finish; + if (@diff) { + @finish = rebase_cmd(); + print STDERR "W: $current and ", $fetched_ref, + " differ, using @finish:\n", + join("\n", @diff), "\n"; + } elsif ($is_last) { + print "No changes between ", $current, " and ", + $fetched_ref, + "\nResetting to the latest ", + $fetched_ref, "\n"; + @finish = qw/reset --mixed/; + } + command_noisy(@finish, $fetched_ref) if @finish; + } + if ($svn_error) { + die "ERROR: Not all changes have been committed into SVN" + .($_no_rebase ? ".\n" : ", however the committed\n" + ."ones (if any) seem to be successfully integrated " + ."into the working tree.\n") + ."Please see the above messages for details.\n"; + } + return @diff; +} + sub cmd_dcommit { my $head = shift; command_noisy(qw/update-index --refresh/); @@ -902,6 +951,7 @@ sub cmd_dcommit { } my $rewritten_parent; + my $current_head = command_oneline(qw/rev-parse HEAD/); Git::SVN::remove_username($expect_url); if (defined($_merge_info)) { $_merge_info =~ tr{ }{\n}; @@ -941,6 +991,14 @@ sub cmd_dcommit { }, mergeinfo => $_merge_info, svn_path => ''); + + my $err_handler = $SVN::Error::handler; + $SVN::Error::handler = sub { + my $err = shift; + dcommit_rebase(1, $current_head, $gs->refname, + $err); + }; + if (!Git::SVN::Editor->new(\%ed_opts)->apply_diff) { print "No changes\n$d~1 == $d\n"; } elsif ($parents->{$d} && @{$parents->{$d}}) { @@ -948,31 +1006,19 @@ sub cmd_dcommit { $parents->{$d}; } $_fetch_all ? $gs->fetch_all : $gs->fetch; + $SVN::Error::handler = $err_handler; $last_rev = $cmt_rev; next if $_no_rebase; - # we always want to rebase against the current HEAD, - # not any head that was passed to us - my @diff = command('diff-tree', $d, - $gs->refname, '--'); - my @finish; - if (@diff) { - @finish = rebase_cmd(); - print STDERR "W: $d and ", $gs->refname, - " differ, using @finish:\n", - join("\n", @diff), "\n"; - } else { - print "No changes between current HEAD and ", - $gs->refname, - "\nResetting to the latest ", - $gs->refname, "\n"; - @finish = qw/reset --mixed/; - } - command_noisy(@finish, $gs->refname); + my @diff = dcommit_rebase(@$linear_refs == 0, $d, + $gs->refname, undef); - $rewritten_parent = command_oneline(qw/rev-parse HEAD/); + $rewritten_parent = command_oneline(qw/rev-parse/, + $gs->refname); if (@diff) { + $current_head = command_oneline(qw/rev-parse + HEAD/); @refs = (); my ($url_, $rev_, $uuid_, $gs_) = working_head_info('HEAD', \@refs); @@ -1017,6 +1063,7 @@ sub cmd_dcommit { } $parents = \%p; $linear_refs = \@l; + undef $last_rev; } } } @@ -1193,7 +1240,7 @@ sub cmd_show_ignore { my ($url, $rev, $uuid, $gs) = working_head_info('HEAD'); $gs ||= Git::SVN->new; my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum); - $gs->prop_walk($gs->{path}, $r, sub { + $gs->prop_walk($gs->path, $r, sub { my ($gs, $path, $props) = @_; print STDOUT "\n# $path\n"; my $s = $props->{'svn:ignore'} or return; @@ -1209,7 +1256,7 @@ sub cmd_show_externals { my ($url, $rev, $uuid, $gs) = working_head_info('HEAD'); $gs ||= Git::SVN->new; my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum); - $gs->prop_walk($gs->{path}, $r, sub { + $gs->prop_walk($gs->path, $r, sub { my ($gs, $path, $props) = @_; print STDOUT "\n# $path\n"; my $s = $props->{'svn:externals'} or return; @@ -1224,7 +1271,7 @@ sub cmd_create_ignore { my ($url, $rev, $uuid, $gs) = working_head_info('HEAD'); $gs ||= Git::SVN->new; my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum); - $gs->prop_walk($gs->{path}, $r, sub { + $gs->prop_walk($gs->path, $r, sub { my ($gs, $path, $props) = @_; # $path is of the form /path/to/dir/ $path = '.' . $path; @@ -1254,31 +1301,6 @@ sub cmd_mkdirs { $gs->mkemptydirs($_revision); } -sub canonicalize_path { - my ($path) = @_; - my $dot_slash_added = 0; - if (substr($path, 0, 1) ne "/") { - $path = "./" . $path; - $dot_slash_added = 1; - } - # File::Spec->canonpath doesn't collapse x/../y into y (for a - # good reason), so let's do this manually. - $path =~ s#/+#/#g; - $path =~ s#/\.(?:/|$)#/#g; - $path =~ s#/[^/]+/\.\.##g; - $path =~ s#/$##g; - $path =~ s#^\./## if $dot_slash_added; - $path =~ s#^/##; - $path =~ s#^\.$##; - return $path; -} - -sub canonicalize_url { - my ($url) = @_; - $url =~ s#^([^:]+://[^/]*/)(.*)$#$1 . canonicalize_path($2)#e; - return $url; -} - # get_svnprops(PATH) # ------------------ # Helper for cmd_propget and cmd_proplist below. @@ -1292,7 +1314,7 @@ sub get_svnprops { $path = $cmd_dir_prefix . $path; fatal("No such file or directory: $path") unless -e $path; my $is_dir = -d $path ? 1 : 0; - $path = $gs->{path} . '/' . $path; + $path = join_paths($gs->{path}, $path); # canonicalize the path (otherwise libsvn will abort or fail to # find the file) @@ -1393,8 +1415,8 @@ sub cmd_commit_diff { fatal("Needed URL or usable git-svn --id in ", "the command-line\n", $usage); } - $url = $gs->{url}; - $svn_path = $gs->{path}; + $url = $gs->url; + $svn_path = $gs->path; } unless (defined $_revision) { fatal("-r|--revision is a required argument\n", $usage); @@ -1428,24 +1450,6 @@ sub cmd_commit_diff { } } -sub escape_uri_only { - my ($uri) = @_; - my @tmp; - foreach (split m{/}, $uri) { - s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg; - push @tmp, $_; - } - join('/', @tmp); -} - -sub escape_url { - my ($url) = @_; - if ($url =~ m#^([^:]+)://([^/]*)(.*)$#) { - my ($scheme, $domain, $uri) = ($1, $2, escape_uri_only($3)); - $url = "$scheme://$domain$uri"; - } - $url; -} sub cmd_info { my $path = canonicalize_path(defined($_[0]) ? $_[0] : "."); @@ -1470,21 +1474,21 @@ sub cmd_info { # canonicalize_path() will return "" to make libsvn 1.5.x happy, $path = "." if $path eq ""; - my $full_url = $url . ($fullpath eq "" ? "" : "/$fullpath"); + my $full_url = canonicalize_url( add_path_to_url( $url, $fullpath ) ); if ($_url) { - print escape_url($full_url), "\n"; + print "$full_url\n"; return; } my $result = "Path: $path\n"; $result .= "Name: " . basename($path) . "\n" if $file_type ne "dir"; - $result .= "URL: " . escape_url($full_url) . "\n"; + $result .= "URL: $full_url\n"; eval { my $repos_root = $gs->repos_root; Git::SVN::remove_username($repos_root); - $result .= "Repository Root: " . escape_url($repos_root) . "\n"; + $result .= "Repository Root: " . canonicalize_url($repos_root) . "\n"; }; if ($@) { $result .= "Repository Root: (offline)\n"; @@ -1578,7 +1582,7 @@ sub cmd_reset { } sub cmd_gc { - if (!$can_compress) { + if (!can_compress()) { warn "Compress::Zlib could not be found; unhandled.log " . "files will not be compressed.\n"; } @@ -1631,7 +1635,9 @@ sub post_fetch_checkout { sub complete_svn_url { my ($url, $path) = @_; - $path =~ s#/+$##; + $path = canonicalize_path($path); + + # If the path is not a URL... if ($path !~ m#^[a-z\+]+://#) { if (!defined $url || $url !~ m#^[a-z\+]+://#) { fatal("E: '$path' is not a complete URL ", @@ -1648,7 +1654,7 @@ sub complete_url_ls_init { print STDERR "W: $switch not specified\n"; return; } - $repo_path =~ s#/+$##; + $repo_path = canonicalize_path($repo_path); if ($repo_path =~ m#^[a-z\+]+://#) { $ra = Git::SVN::Ra->new($repo_path); $repo_path = ''; @@ -1659,18 +1665,18 @@ sub complete_url_ls_init { "and a separate URL is not specified"); } } - my $url = $ra->{url}; + my $url = $ra->url; my $gs = Git::SVN->init($url, undef, undef, undef, 1); my $k = "svn-remote.$gs->{repo_id}.url"; my $orig_url = eval { command_oneline(qw/config --get/, $k) }; - if ($orig_url && ($orig_url ne $gs->{url})) { + if ($orig_url && ($orig_url ne $gs->url)) { die "$k already set: $orig_url\n", - "wanted to set to: $gs->{url}\n"; + "wanted to set to: $gs->url\n"; } - command_oneline('config', $k, $gs->{url}) unless $orig_url; - my $remote_path = "$gs->{path}/$repo_path"; + command_oneline('config', $k, $gs->url) unless $orig_url; + + my $remote_path = join_paths( $gs->path, $repo_path ); $remote_path =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg; - $remote_path =~ s#/+#/#g; $remote_path =~ s#^/##g; $remote_path .= "/*" if $remote_path !~ /\*/; my ($n) = ($switch =~ /^--(\w+)/); @@ -2013,13 +2019,13 @@ sub md5sum { } elsif (!$ref) { $md5->add($arg) or croak $!; } else { - ::fatal "Can't provide MD5 hash for unknown ref type: '", $ref, "'"; + fatal "Can't provide MD5 hash for unknown ref type: '", $ref, "'"; } return $md5->hexdigest(); } sub gc_directory { - if ($can_compress && -f $_ && basename($_) eq "unhandled.log") { + if (can_compress() && -f $_ && basename($_) eq "unhandled.log") { my $out_filename = $_ . ".gz"; open my $in_fh, "<", $_ or die "Unable to open $_: $!\n"; binmode $in_fh; @@ -2037,3035 +2043,6 @@ sub gc_directory { } } -package Git::SVN; -use strict; -use warnings; -use Fcntl qw/:DEFAULT :seek/; -use constant rev_map_fmt => 'NH40'; -use vars qw/$default_repo_id $default_ref_id $_no_metadata $_follow_parent - $_repack $_repack_flags $_use_svm_props $_head - $_use_svnsync_props $no_reuse_existing $_minimize_url - $_use_log_author $_add_author_from $_localtime/; -use Carp qw/croak/; -use File::Path qw/mkpath/; -use File::Copy qw/copy/; -use IPC::Open3; -use Time::Local; -use Memoize; # core since 5.8.0, Jul 2002 -use Memoize::Storable; -use POSIX qw(:signal_h); -my $can_use_yaml; -BEGIN { - $can_use_yaml = eval { require Git::SVN::Memoize::YAML; 1}; -} - -my ($_gc_nr, $_gc_period); - -# properties that we do not log: -my %SKIP_PROP; -BEGIN { - %SKIP_PROP = map { $_ => 1 } qw/svn:wc:ra_dav:version-url - svn:special svn:executable - svn:entry:committed-rev - svn:entry:last-author - svn:entry:uuid - svn:entry:committed-date/; - - # some options are read globally, but can be overridden locally - # per [svn-remote "..."] section. Command-line options will *NOT* - # override options set in an [svn-remote "..."] section - no strict 'refs'; - for my $option (qw/follow_parent no_metadata use_svm_props - use_svnsync_props/) { - my $key = $option; - $key =~ tr/_//d; - my $prop = "-$option"; - *$option = sub { - my ($self) = @_; - return $self->{$prop} if exists $self->{$prop}; - my $k = "svn-remote.$self->{repo_id}.$key"; - eval { command_oneline(qw/config --get/, $k) }; - if ($@) { - $self->{$prop} = ${"Git::SVN::_$option"}; - } else { - my $v = command_oneline(qw/config --bool/,$k); - $self->{$prop} = $v eq 'false' ? 0 : 1; - } - return $self->{$prop}; - } - } -} - - -my (%LOCKFILES, %INDEX_FILES); -END { - unlink keys %LOCKFILES if %LOCKFILES; - unlink keys %INDEX_FILES if %INDEX_FILES; -} - -sub resolve_local_globs { - my ($url, $fetch, $glob_spec) = @_; - return unless defined $glob_spec; - my $ref = $glob_spec->{ref}; - my $path = $glob_spec->{path}; - foreach (command(qw#for-each-ref --format=%(refname) refs/#)) { - next unless m#^$ref->{regex}$#; - my $p = $1; - my $pathname = desanitize_refname($path->full_path($p)); - my $refname = desanitize_refname($ref->full_path($p)); - if (my $existing = $fetch->{$pathname}) { - if ($existing ne $refname) { - die "Refspec conflict:\n", - "existing: $existing\n", - " globbed: $refname\n"; - } - my $u = (::cmt_metadata("$refname"))[0]; - $u =~ s!^\Q$url\E(/|$)!! or die - "$refname: '$url' not found in '$u'\n"; - if ($pathname ne $u) { - warn "W: Refspec glob conflict ", - "(ref: $refname):\n", - "expected path: $pathname\n", - " real path: $u\n", - "Continuing ahead with $u\n"; - next; - } - } else { - $fetch->{$pathname} = $refname; - } - } -} - -sub parse_revision_argument { - my ($base, $head) = @_; - if (!defined $::_revision || $::_revision eq 'BASE:HEAD') { - return ($base, $head); - } - return ($1, $2) if ($::_revision =~ /^(\d+):(\d+)$/); - return ($::_revision, $::_revision) if ($::_revision =~ /^\d+$/); - return ($head, $head) if ($::_revision eq 'HEAD'); - return ($base, $1) if ($::_revision =~ /^BASE:(\d+)$/); - return ($1, $head) if ($::_revision =~ /^(\d+):HEAD$/); - die "revision argument: $::_revision not understood by git-svn\n"; -} - -sub fetch_all { - my ($repo_id, $remotes) = @_; - if (ref $repo_id) { - my $gs = $repo_id; - $repo_id = undef; - $repo_id = $gs->{repo_id}; - } - $remotes ||= read_all_remotes(); - my $remote = $remotes->{$repo_id} or - die "[svn-remote \"$repo_id\"] unknown\n"; - my $fetch = $remote->{fetch}; - my $url = $remote->{url} or die "svn-remote.$repo_id.url not defined\n"; - my (@gs, @globs); - my $ra = Git::SVN::Ra->new($url); - my $uuid = $ra->get_uuid; - my $head = $ra->get_latest_revnum; - - # ignore errors, $head revision may not even exist anymore - eval { $ra->get_log("", $head, 0, 1, 0, 1, sub { $head = $_[1] }) }; - warn "W: $@\n" if $@; - - my $base = defined $fetch ? $head : 0; - - # read the max revs for wildcard expansion (branches/*, tags/*) - foreach my $t (qw/branches tags/) { - defined $remote->{$t} or next; - push @globs, @{$remote->{$t}}; - - my $max_rev = eval { tmp_config(qw/--int --get/, - "svn-remote.$repo_id.${t}-maxRev") }; - if (defined $max_rev && ($max_rev < $base)) { - $base = $max_rev; - } elsif (!defined $max_rev) { - $base = 0; - } - } - - if ($fetch) { - foreach my $p (sort keys %$fetch) { - my $gs = Git::SVN->new($fetch->{$p}, $repo_id, $p); - my $lr = $gs->rev_map_max; - if (defined $lr) { - $base = $lr if ($lr < $base); - } - push @gs, $gs; - } - } - - ($base, $head) = parse_revision_argument($base, $head); - $ra->gs_fetch_loop_common($base, $head, \@gs, \@globs); -} - -sub read_all_remotes { - my $r = {}; - my $use_svm_props = eval { command_oneline(qw/config --bool - svn.useSvmProps/) }; - $use_svm_props = $use_svm_props eq 'true' if $use_svm_props; - my $svn_refspec = qr{\s*(.*?)\s*:\s*(.+?)\s*}; - foreach (grep { s/^svn-remote\.// } command(qw/config -l/)) { - if (m!^(.+)\.fetch=$svn_refspec$!) { - my ($remote, $local_ref, $remote_ref) = ($1, $2, $3); - die("svn-remote.$remote: remote ref '$remote_ref' " - . "must start with 'refs/'\n") - unless $remote_ref =~ m{^refs/}; - $local_ref = uri_decode($local_ref); - $r->{$remote}->{fetch}->{$local_ref} = $remote_ref; - $r->{$remote}->{svm} = {} if $use_svm_props; - } elsif (m!^(.+)\.usesvmprops=\s*(.*)\s*$!) { - $r->{$1}->{svm} = {}; - } elsif (m!^(.+)\.url=\s*(.*)\s*$!) { - $r->{$1}->{url} = $2; - } elsif (m!^(.+)\.pushurl=\s*(.*)\s*$!) { - $r->{$1}->{pushurl} = $2; - } elsif (m!^(.+)\.ignore-refs=\s*(.*)\s*$!) { - $r->{$1}->{ignore_refs_regex} = $2; - } elsif (m!^(.+)\.(branches|tags)=$svn_refspec$!) { - my ($remote, $t, $local_ref, $remote_ref) = - ($1, $2, $3, $4); - die("svn-remote.$remote: remote ref '$remote_ref' ($t) " - . "must start with 'refs/'\n") - unless $remote_ref =~ m{^refs/}; - $local_ref = uri_decode($local_ref); - my $rs = { - t => $t, - remote => $remote, - path => Git::SVN::GlobSpec->new($local_ref, 1), - ref => Git::SVN::GlobSpec->new($remote_ref, 0) }; - if (length($rs->{ref}->{right}) != 0) { - die "The '*' glob character must be the last ", - "character of '$remote_ref'\n"; - } - push @{ $r->{$remote}->{$t} }, $rs; - } - } - - map { - if (defined $r->{$_}->{svm}) { - my $svm; - eval { - my $section = "svn-remote.$_"; - $svm = { - source => tmp_config('--get', - "$section.svm-source"), - replace => tmp_config('--get', - "$section.svm-replace"), - } - }; - $r->{$_}->{svm} = $svm; - } - } keys %$r; - - foreach my $remote (keys %$r) { - foreach ( grep { defined $_ } - map { $r->{$remote}->{$_} } qw(branches tags) ) { - foreach my $rs ( @$_ ) { - $rs->{ignore_refs_regex} = - $r->{$remote}->{ignore_refs_regex}; - } - } - } - - $r; -} - -sub init_vars { - $_gc_nr = $_gc_period = 1000; - if (defined $_repack || defined $_repack_flags) { - warn "Repack options are obsolete; they have no effect.\n"; - } -} - -sub verify_remotes_sanity { - return unless -d $ENV{GIT_DIR}; - my %seen; - foreach (command(qw/config -l/)) { - if (m!^svn-remote\.(?:.+)\.fetch=.*:refs/remotes/(\S+)\s*$!) { - if ($seen{$1}) { - die "Remote ref refs/remote/$1 is tracked by", - "\n \"$_\"\nand\n \"$seen{$1}\"\n", - "Please resolve this ambiguity in ", - "your git configuration file before ", - "continuing\n"; - } - $seen{$1} = $_; - } - } -} - -sub find_existing_remote { - my ($url, $remotes) = @_; - return undef if $no_reuse_existing; - my $existing; - foreach my $repo_id (keys %$remotes) { - my $u = $remotes->{$repo_id}->{url} or next; - next if $u ne $url; - $existing = $repo_id; - last; - } - $existing; -} - -sub init_remote_config { - my ($self, $url, $no_write) = @_; - $url =~ s!/+$!!; # strip trailing slash - my $r = read_all_remotes(); - my $existing = find_existing_remote($url, $r); - if ($existing) { - unless ($no_write) { - print STDERR "Using existing ", - "[svn-remote \"$existing\"]\n"; - } - $self->{repo_id} = $existing; - } elsif ($_minimize_url) { - my $min_url = Git::SVN::Ra->new($url)->minimize_url; - $existing = find_existing_remote($min_url, $r); - if ($existing) { - unless ($no_write) { - print STDERR "Using existing ", - "[svn-remote \"$existing\"]\n"; - } - $self->{repo_id} = $existing; - } - if ($min_url ne $url) { - unless ($no_write) { - print STDERR "Using higher level of URL: ", - "$url => $min_url\n"; - } - my $old_path = $self->{path}; - $self->{path} = $url; - $self->{path} =~ s!^\Q$min_url\E(/|$)!!; - if (length $old_path) { - $self->{path} .= "/$old_path"; - } - $url = $min_url; - } - } - my $orig_url; - if (!$existing) { - # verify that we aren't overwriting anything: - $orig_url = eval { - command_oneline('config', '--get', - "svn-remote.$self->{repo_id}.url") - }; - if ($orig_url && ($orig_url ne $url)) { - die "svn-remote.$self->{repo_id}.url already set: ", - "$orig_url\nwanted to set to: $url\n"; - } - } - my ($xrepo_id, $xpath) = find_ref($self->refname); - if (!$no_write && defined $xpath) { - die "svn-remote.$xrepo_id.fetch already set to track ", - "$xpath:", $self->refname, "\n"; - } - unless ($no_write) { - command_noisy('config', - "svn-remote.$self->{repo_id}.url", $url); - $self->{path} =~ s{^/}{}; - $self->{path} =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg; - command_noisy('config', '--add', - "svn-remote.$self->{repo_id}.fetch", - "$self->{path}:".$self->refname); - } - $self->{url} = $url; -} - -sub find_by_url { # repos_root and, path are optional - my ($class, $full_url, $repos_root, $path) = @_; - - return undef unless defined $full_url; - remove_username($full_url); - remove_username($repos_root) if defined $repos_root; - my $remotes = read_all_remotes(); - if (defined $full_url && defined $repos_root && !defined $path) { - $path = $full_url; - $path =~ s#^\Q$repos_root\E(?:/|$)##; - } - foreach my $repo_id (keys %$remotes) { - my $u = $remotes->{$repo_id}->{url} or next; - remove_username($u); - next if defined $repos_root && $repos_root ne $u; - - my $fetch = $remotes->{$repo_id}->{fetch} || {}; - foreach my $t (qw/branches tags/) { - foreach my $globspec (@{$remotes->{$repo_id}->{$t}}) { - resolve_local_globs($u, $fetch, $globspec); - } - } - my $p = $path; - my $rwr = rewrite_root({repo_id => $repo_id}); - my $svm = $remotes->{$repo_id}->{svm} - if defined $remotes->{$repo_id}->{svm}; - unless (defined $p) { - $p = $full_url; - my $z = $u; - my $prefix = ''; - if ($rwr) { - $z = $rwr; - remove_username($z); - } elsif (defined $svm) { - $z = $svm->{source}; - $prefix = $svm->{replace}; - $prefix =~ s#^\Q$u\E(?:/|$)##; - $prefix =~ s#/$##; - } - $p =~ s#^\Q$z\E(?:/|$)#$prefix# or next; - } - foreach my $f (keys %$fetch) { - next if $f ne $p; - return Git::SVN->new($fetch->{$f}, $repo_id, $f); - } - } - undef; -} - -sub init { - my ($class, $url, $path, $repo_id, $ref_id, $no_write) = @_; - my $self = _new($class, $repo_id, $ref_id, $path); - if (defined $url) { - $self->init_remote_config($url, $no_write); - } - $self; -} - -sub find_ref { - my ($ref_id) = @_; - foreach (command(qw/config -l/)) { - next unless m!^svn-remote\.(.+)\.fetch= - \s*(.*?)\s*:\s*(.+?)\s*$!x; - my ($repo_id, $path, $ref) = ($1, $2, $3); - if ($ref eq $ref_id) { - $path = '' if ($path =~ m#^\./?#); - return ($repo_id, $path); - } - } - (undef, undef, undef); -} - -sub new { - my ($class, $ref_id, $repo_id, $path) = @_; - if (defined $ref_id && !defined $repo_id && !defined $path) { - ($repo_id, $path) = find_ref($ref_id); - if (!defined $repo_id) { - die "Could not find a \"svn-remote.*.fetch\" key ", - "in the repository configuration matching: ", - "$ref_id\n"; - } - } - my $self = _new($class, $repo_id, $ref_id, $path); - if (!defined $self->{path} || !length $self->{path}) { - my $fetch = command_oneline('config', '--get', - "svn-remote.$repo_id.fetch", - ":$ref_id\$") or - die "Failed to read \"svn-remote.$repo_id.fetch\" ", - "\":$ref_id\$\" in config\n"; - ($self->{path}, undef) = split(/\s*:\s*/, $fetch); - } - $self->{path} =~ s{/+}{/}g; - $self->{path} =~ s{\A/}{}; - $self->{path} =~ s{/\z}{}; - $self->{url} = command_oneline('config', '--get', - "svn-remote.$repo_id.url") or - die "Failed to read \"svn-remote.$repo_id.url\" in config\n"; - $self->{pushurl} = eval { command_oneline('config', '--get', - "svn-remote.$repo_id.pushurl") }; - $self->rebuild; - $self; -} - -sub refname { - my ($refname) = $_[0]->{ref_id} ; - - # It cannot end with a slash /, we'll throw up on this because - # SVN can't have directories with a slash in their name, either: - if ($refname =~ m{/$}) { - die "ref: '$refname' ends with a trailing slash, this is ", - "not permitted by git nor Subversion\n"; - } - - # It cannot have ASCII control character space, tilde ~, caret ^, - # colon :, question-mark ?, asterisk *, space, or open bracket [ - # anywhere. - # - # Additionally, % must be escaped because it is used for escaping - # and we want our escaped refname to be reversible - $refname =~ s{([ \%~\^:\?\*\[\t])}{uc sprintf('%%%02x',ord($1))}eg; - - # no slash-separated component can begin with a dot . - # /.* becomes /%2E* - $refname =~ s{/\.}{/%2E}g; - - # It cannot have two consecutive dots .. anywhere - # .. becomes %2E%2E - $refname =~ s{\.\.}{%2E%2E}g; - - # trailing dots and .lock are not allowed - # .$ becomes %2E and .lock becomes %2Elock - $refname =~ s{\.(?=$|lock$)}{%2E}; - - # the sequence @{ is used to access the reflog - # @{ becomes %40{ - $refname =~ s{\@\{}{%40\{}g; - - return $refname; -} - -sub desanitize_refname { - my ($refname) = @_; - $refname =~ s{%(?:([0-9A-F]{2}))}{chr hex($1)}eg; - return $refname; -} - -sub svm_uuid { - my ($self) = @_; - return $self->{svm}->{uuid} if $self->svm; - $self->ra; - unless ($self->{svm}) { - die "SVM UUID not cached, and reading remotely failed\n"; - } - $self->{svm}->{uuid}; -} - -sub svm { - my ($self) = @_; - return $self->{svm} if $self->{svm}; - my $svm; - # see if we have it in our config, first: - eval { - my $section = "svn-remote.$self->{repo_id}"; - $svm = { - source => tmp_config('--get', "$section.svm-source"), - uuid => tmp_config('--get', "$section.svm-uuid"), - replace => tmp_config('--get', "$section.svm-replace"), - } - }; - if ($svm && $svm->{source} && $svm->{uuid} && $svm->{replace}) { - $self->{svm} = $svm; - } - $self->{svm}; -} - -sub _set_svm_vars { - my ($self, $ra) = @_; - return $ra if $self->svm; - - my @err = ( "useSvmProps set, but failed to read SVM properties\n", - "(svm:source, svm:uuid) ", - "from the following URLs:\n" ); - sub read_svm_props { - my ($self, $ra, $path, $r) = @_; - my $props = ($ra->get_dir($path, $r))[2]; - my $src = $props->{'svm:source'}; - my $uuid = $props->{'svm:uuid'}; - return undef if (!$src || !$uuid); - - chomp($src, $uuid); - - $uuid =~ m{^[0-9a-f\-]{30,}$}i - or die "doesn't look right - svm:uuid is '$uuid'\n"; - - # the '!' is used to mark the repos_root!/relative/path - $src =~ s{/?!/?}{/}; - $src =~ s{/+$}{}; # no trailing slashes please - # username is of no interest - $src =~ s{(^[a-z\+]*://)[^/@]*@}{$1}; - - my $replace = $ra->{url}; - $replace .= "/$path" if length $path; - - my $section = "svn-remote.$self->{repo_id}"; - tmp_config("$section.svm-source", $src); - tmp_config("$section.svm-replace", $replace); - tmp_config("$section.svm-uuid", $uuid); - $self->{svm} = { - source => $src, - uuid => $uuid, - replace => $replace - }; - } - - my $r = $ra->get_latest_revnum; - my $path = $self->{path}; - my %tried; - while (length $path) { - unless ($tried{"$self->{url}/$path"}) { - return $ra if $self->read_svm_props($ra, $path, $r); - $tried{"$self->{url}/$path"} = 1; - } - $path =~ s#/?[^/]+$##; - } - die "Path: '$path' should be ''\n" if $path ne ''; - return $ra if $self->read_svm_props($ra, $path, $r); - $tried{"$self->{url}/$path"} = 1; - - if ($ra->{repos_root} eq $self->{url}) { - die @err, (map { " $_\n" } keys %tried), "\n"; - } - - # nope, make sure we're connected to the repository root: - my $ok; - my @tried_b; - $path = $ra->{svn_path}; - $ra = Git::SVN::Ra->new($ra->{repos_root}); - while (length $path) { - unless ($tried{"$ra->{url}/$path"}) { - $ok = $self->read_svm_props($ra, $path, $r); - last if $ok; - $tried{"$ra->{url}/$path"} = 1; - } - $path =~ s#/?[^/]+$##; - } - die "Path: '$path' should be ''\n" if $path ne ''; - $ok ||= $self->read_svm_props($ra, $path, $r); - $tried{"$ra->{url}/$path"} = 1; - if (!$ok) { - die @err, (map { " $_\n" } keys %tried), "\n"; - } - Git::SVN::Ra->new($self->{url}); -} - -sub svnsync { - my ($self) = @_; - return $self->{svnsync} if $self->{svnsync}; - - if ($self->no_metadata) { - die "Can't have both 'noMetadata' and ", - "'useSvnsyncProps' options set!\n"; - } - if ($self->rewrite_root) { - die "Can't have both 'useSvnsyncProps' and 'rewriteRoot' ", - "options set!\n"; - } - if ($self->rewrite_uuid) { - die "Can't have both 'useSvnsyncProps' and 'rewriteUUID' ", - "options set!\n"; - } - - my $svnsync; - # see if we have it in our config, first: - eval { - my $section = "svn-remote.$self->{repo_id}"; - - my $url = tmp_config('--get', "$section.svnsync-url"); - ($url) = ($url =~ m{^([a-z\+]+://\S+)$}) or - die "doesn't look right - svn:sync-from-url is '$url'\n"; - - my $uuid = tmp_config('--get', "$section.svnsync-uuid"); - ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or - die "doesn't look right - svn:sync-from-uuid is '$uuid'\n"; - - $svnsync = { url => $url, uuid => $uuid } - }; - if ($svnsync && $svnsync->{url} && $svnsync->{uuid}) { - return $self->{svnsync} = $svnsync; - } - - my $err = "useSvnsyncProps set, but failed to read " . - "svnsync property: svn:sync-from-"; - my $rp = $self->ra->rev_proplist(0); - - my $url = $rp->{'svn:sync-from-url'} or die $err . "url\n"; - ($url) = ($url =~ m{^([a-z\+]+://\S+)$}) or - die "doesn't look right - svn:sync-from-url is '$url'\n"; - - my $uuid = $rp->{'svn:sync-from-uuid'} or die $err . "uuid\n"; - ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or - die "doesn't look right - svn:sync-from-uuid is '$uuid'\n"; - - my $section = "svn-remote.$self->{repo_id}"; - tmp_config('--add', "$section.svnsync-uuid", $uuid); - tmp_config('--add', "$section.svnsync-url", $url); - return $self->{svnsync} = { url => $url, uuid => $uuid }; -} - -# this allows us to memoize our SVN::Ra UUID locally and avoid a -# remote lookup (useful for 'git svn log'). -sub ra_uuid { - my ($self) = @_; - unless ($self->{ra_uuid}) { - my $key = "svn-remote.$self->{repo_id}.uuid"; - my $uuid = eval { tmp_config('--get', $key) }; - if (!$@ && $uuid && $uuid =~ /^([a-f\d\-]{30,})$/i) { - $self->{ra_uuid} = $uuid; - } else { - die "ra_uuid called without URL\n" unless $self->{url}; - $self->{ra_uuid} = $self->ra->get_uuid; - tmp_config('--add', $key, $self->{ra_uuid}); - } - } - $self->{ra_uuid}; -} - -sub _set_repos_root { - my ($self, $repos_root) = @_; - my $k = "svn-remote.$self->{repo_id}.reposRoot"; - $repos_root ||= $self->ra->{repos_root}; - tmp_config($k, $repos_root); - $repos_root; -} - -sub repos_root { - my ($self) = @_; - my $k = "svn-remote.$self->{repo_id}.reposRoot"; - eval { tmp_config('--get', $k) } || $self->_set_repos_root; -} - -sub ra { - my ($self) = shift; - my $ra = Git::SVN::Ra->new($self->{url}); - $self->_set_repos_root($ra->{repos_root}); - if ($self->use_svm_props && !$self->{svm}) { - if ($self->no_metadata) { - die "Can't have both 'noMetadata' and ", - "'useSvmProps' options set!\n"; - } elsif ($self->use_svnsync_props) { - die "Can't have both 'useSvnsyncProps' and ", - "'useSvmProps' options set!\n"; - } - $ra = $self->_set_svm_vars($ra); - $self->{-want_revprops} = 1; - } - $ra; -} - -# prop_walk(PATH, REV, SUB) -# ------------------------- -# Recursively traverse PATH at revision REV and invoke SUB for each -# directory that contains a SVN property. SUB will be invoked as -# follows: &SUB(gs, path, props); where `gs' is this instance of -# Git::SVN, `path' the path to the directory where the properties -# `props' were found. The `path' will be relative to point of checkout, -# that is, if url://repo/trunk is the current Git branch, and that -# directory contains a sub-directory `d', SUB will be invoked with `/d/' -# as `path' (note the trailing `/'). -sub prop_walk { - my ($self, $path, $rev, $sub) = @_; - - $path =~ s#^/##; - my ($dirent, undef, $props) = $self->ra->get_dir($path, $rev); - $path =~ s#^/*#/#g; - my $p = $path; - # Strip the irrelevant part of the path. - $p =~ s#^/+\Q$self->{path}\E(/|$)#/#; - # Ensure the path is terminated by a `/'. - $p =~ s#/*$#/#; - - # The properties contain all the internal SVN stuff nobody - # (usually) cares about. - my $interesting_props = 0; - foreach (keys %{$props}) { - # If it doesn't start with `svn:', it must be a - # user-defined property. - ++$interesting_props and next if $_ !~ /^svn:/; - # FIXME: Fragile, if SVN adds new public properties, - # this needs to be updated. - ++$interesting_props if /^svn:(?:ignore|keywords|executable - |eol-style|mime-type - |externals|needs-lock)$/x; - } - &$sub($self, $p, $props) if $interesting_props; - - foreach (sort keys %$dirent) { - next if $dirent->{$_}->{kind} != $SVN::Node::dir; - $self->prop_walk($self->{path} . $p . $_, $rev, $sub); - } -} - -sub last_rev { ($_[0]->last_rev_commit)[0] } -sub last_commit { ($_[0]->last_rev_commit)[1] } - -# returns the newest SVN revision number and newest commit SHA1 -sub last_rev_commit { - my ($self) = @_; - if (defined $self->{last_rev} && defined $self->{last_commit}) { - return ($self->{last_rev}, $self->{last_commit}); - } - my $c = ::verify_ref($self->refname.'^0'); - if ($c && !$self->use_svm_props && !$self->no_metadata) { - my $rev = (::cmt_metadata($c))[1]; - if (defined $rev) { - ($self->{last_rev}, $self->{last_commit}) = ($rev, $c); - return ($rev, $c); - } - } - my $map_path = $self->map_path; - unless (-e $map_path) { - ($self->{last_rev}, $self->{last_commit}) = (undef, undef); - return (undef, undef); - } - my ($rev, $commit) = $self->rev_map_max(1); - ($self->{last_rev}, $self->{last_commit}) = ($rev, $commit); - return ($rev, $commit); -} - -sub get_fetch_range { - my ($self, $min, $max) = @_; - $max ||= $self->ra->get_latest_revnum; - $min ||= $self->rev_map_max; - (++$min, $max); -} - -sub tmp_config { - my (@args) = @_; - my $old_def_config = "$ENV{GIT_DIR}/svn/config"; - my $config = "$ENV{GIT_DIR}/svn/.metadata"; - if (! -f $config && -f $old_def_config) { - rename $old_def_config, $config or - die "Failed rename $old_def_config => $config: $!\n"; - } - my $old_config = $ENV{GIT_CONFIG}; - $ENV{GIT_CONFIG} = $config; - $@ = undef; - my @ret = eval { - unless (-f $config) { - mkfile($config); - open my $fh, '>', $config or - die "Can't open $config: $!\n"; - print $fh "; This file is used internally by ", - "git-svn\n" or die - "Couldn't write to $config: $!\n"; - print $fh "; You should not have to edit it\n" or - die "Couldn't write to $config: $!\n"; - close $fh or die "Couldn't close $config: $!\n"; - } - command('config', @args); - }; - my $err = $@; - if (defined $old_config) { - $ENV{GIT_CONFIG} = $old_config; - } else { - delete $ENV{GIT_CONFIG}; - } - die $err if $err; - wantarray ? @ret : $ret[0]; -} - -sub tmp_index_do { - my ($self, $sub) = @_; - my $old_index = $ENV{GIT_INDEX_FILE}; - $ENV{GIT_INDEX_FILE} = $self->{index}; - $@ = undef; - my @ret = eval { - my ($dir, $base) = ($self->{index} =~ m#^(.*?)/?([^/]+)$#); - mkpath([$dir]) unless -d $dir; - &$sub; - }; - my $err = $@; - if (defined $old_index) { - $ENV{GIT_INDEX_FILE} = $old_index; - } else { - delete $ENV{GIT_INDEX_FILE}; - } - die $err if $err; - wantarray ? @ret : $ret[0]; -} - -sub assert_index_clean { - my ($self, $treeish) = @_; - - $self->tmp_index_do(sub { - command_noisy('read-tree', $treeish) unless -e $self->{index}; - my $x = command_oneline('write-tree'); - my ($y) = (command(qw/cat-file commit/, $treeish) =~ - /^tree ($::sha1)/mo); - return if $y eq $x; - - warn "Index mismatch: $y != $x\nrereading $treeish\n"; - unlink $self->{index} or die "unlink $self->{index}: $!\n"; - command_noisy('read-tree', $treeish); - $x = command_oneline('write-tree'); - if ($y ne $x) { - ::fatal "trees ($treeish) $y != $x\n", - "Something is seriously wrong..."; - } - }); -} - -sub get_commit_parents { - my ($self, $log_entry) = @_; - my (%seen, @ret, @tmp); - # legacy support for 'set-tree'; this is only used by set_tree_cb: - if (my $ip = $self->{inject_parents}) { - if (my $commit = delete $ip->{$log_entry->{revision}}) { - push @tmp, $commit; - } - } - if (my $cur = ::verify_ref($self->refname.'^0')) { - push @tmp, $cur; - } - if (my $ipd = $self->{inject_parents_dcommit}) { - if (my $commit = delete $ipd->{$log_entry->{revision}}) { - push @tmp, @$commit; - } - } - push @tmp, $_ foreach (@{$log_entry->{parents}}, @tmp); - while (my $p = shift @tmp) { - next if $seen{$p}; - $seen{$p} = 1; - push @ret, $p; - } - @ret; -} - -sub rewrite_root { - my ($self) = @_; - return $self->{-rewrite_root} if exists $self->{-rewrite_root}; - my $k = "svn-remote.$self->{repo_id}.rewriteRoot"; - my $rwr = eval { command_oneline(qw/config --get/, $k) }; - if ($rwr) { - $rwr =~ s#/+$##; - if ($rwr !~ m#^[a-z\+]+://#) { - die "$rwr is not a valid URL (key: $k)\n"; - } - } - $self->{-rewrite_root} = $rwr; -} - -sub rewrite_uuid { - my ($self) = @_; - return $self->{-rewrite_uuid} if exists $self->{-rewrite_uuid}; - my $k = "svn-remote.$self->{repo_id}.rewriteUUID"; - my $rwid = eval { command_oneline(qw/config --get/, $k) }; - if ($rwid) { - $rwid =~ s#/+$##; - if ($rwid !~ m#^[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$#) { - die "$rwid is not a valid UUID (key: $k)\n"; - } - } - $self->{-rewrite_uuid} = $rwid; -} - -sub metadata_url { - my ($self) = @_; - ($self->rewrite_root || $self->{url}) . - (length $self->{path} ? '/' . $self->{path} : ''); -} - -sub full_url { - my ($self) = @_; - $self->{url} . (length $self->{path} ? '/' . $self->{path} : ''); -} - -sub full_pushurl { - my ($self) = @_; - if ($self->{pushurl}) { - return $self->{pushurl} . (length $self->{path} ? '/' . - $self->{path} : ''); - } else { - return $self->full_url; - } -} - -sub set_commit_header_env { - my ($log_entry) = @_; - my %env; - foreach my $ned (qw/NAME EMAIL DATE/) { - foreach my $ac (qw/AUTHOR COMMITTER/) { - $env{"GIT_${ac}_${ned}"} = $ENV{"GIT_${ac}_${ned}"}; - } - } - - $ENV{GIT_AUTHOR_NAME} = $log_entry->{name}; - $ENV{GIT_AUTHOR_EMAIL} = $log_entry->{email}; - $ENV{GIT_AUTHOR_DATE} = $ENV{GIT_COMMITTER_DATE} = $log_entry->{date}; - - $ENV{GIT_COMMITTER_NAME} = (defined $log_entry->{commit_name}) - ? $log_entry->{commit_name} - : $log_entry->{name}; - $ENV{GIT_COMMITTER_EMAIL} = (defined $log_entry->{commit_email}) - ? $log_entry->{commit_email} - : $log_entry->{email}; - \%env; -} - -sub restore_commit_header_env { - my ($env) = @_; - foreach my $ned (qw/NAME EMAIL DATE/) { - foreach my $ac (qw/AUTHOR COMMITTER/) { - my $k = "GIT_${ac}_${ned}"; - if (defined $env->{$k}) { - $ENV{$k} = $env->{$k}; - } else { - delete $ENV{$k}; - } - } - } -} - -sub gc { - command_noisy('gc', '--auto'); -}; - -sub do_git_commit { - my ($self, $log_entry) = @_; - my $lr = $self->last_rev; - if (defined $lr && $lr >= $log_entry->{revision}) { - die "Last fetched revision of ", $self->refname, - " was r$lr, but we are about to fetch: ", - "r$log_entry->{revision}!\n"; - } - if (my $c = $self->rev_map_get($log_entry->{revision})) { - croak "$log_entry->{revision} = $c already exists! ", - "Why are we refetching it?\n"; - } - my $old_env = set_commit_header_env($log_entry); - my $tree = $log_entry->{tree}; - if (!defined $tree) { - $tree = $self->tmp_index_do(sub { - command_oneline('write-tree') }); - } - die "Tree is not a valid sha1: $tree\n" if $tree !~ /^$::sha1$/o; - - my @exec = ('git', 'commit-tree', $tree); - foreach ($self->get_commit_parents($log_entry)) { - push @exec, '-p', $_; - } - defined(my $pid = open3(my $msg_fh, my $out_fh, '>&STDERR', @exec)) - or croak $!; - binmode $msg_fh; - - # we always get UTF-8 from SVN, but we may want our commits in - # a different encoding. - if (my $enc = Git::config('i18n.commitencoding')) { - require Encode; - Encode::from_to($log_entry->{log}, 'UTF-8', $enc); - } - print $msg_fh $log_entry->{log} or croak $!; - restore_commit_header_env($old_env); - unless ($self->no_metadata) { - print $msg_fh "\ngit-svn-id: $log_entry->{metadata}\n" - or croak $!; - } - $msg_fh->flush == 0 or croak $!; - close $msg_fh or croak $!; - chomp(my $commit = do { local $/; <$out_fh> }); - close $out_fh or croak $!; - waitpid $pid, 0; - croak $? if $?; - if ($commit !~ /^$::sha1$/o) { - die "Failed to commit, invalid sha1: $commit\n"; - } - - $self->rev_map_set($log_entry->{revision}, $commit, 1); - - $self->{last_rev} = $log_entry->{revision}; - $self->{last_commit} = $commit; - print "r$log_entry->{revision}" unless $::_q > 1; - if (defined $log_entry->{svm_revision}) { - print " (\@$log_entry->{svm_revision})" unless $::_q > 1; - $self->rev_map_set($log_entry->{svm_revision}, $commit, - 0, $self->svm_uuid); - } - print " = $commit ($self->{ref_id})\n" unless $::_q > 1; - if (--$_gc_nr == 0) { - $_gc_nr = $_gc_period; - gc(); - } - return $commit; -} - -sub match_paths { - my ($self, $paths, $r) = @_; - return 1 if $self->{path} eq ''; - if (my $path = $paths->{"/$self->{path}"}) { - return ($path->{action} eq 'D') ? 0 : 1; - } - $self->{path_regex} ||= qr/^\/\Q$self->{path}\E\//; - if (grep /$self->{path_regex}/, keys %$paths) { - return 1; - } - my $c = ''; - foreach (split m#/#, $self->{path}) { - $c .= "/$_"; - next unless ($paths->{$c} && - ($paths->{$c}->{action} =~ /^[AR]$/)); - if ($self->ra->check_path($self->{path}, $r) == - $SVN::Node::dir) { - return 1; - } - } - return 0; -} - -sub find_parent_branch { - my ($self, $paths, $rev) = @_; - return undef unless $self->follow_parent; - unless (defined $paths) { - my $err_handler = $SVN::Error::handler; - $SVN::Error::handler = \&Git::SVN::Ra::skip_unknown_revs; - $self->ra->get_log([$self->{path}], $rev, $rev, 0, 1, 1, - sub { $paths = $_[0] }); - $SVN::Error::handler = $err_handler; - } - return undef unless defined $paths; - - # look for a parent from another branch: - my @b_path_components = split m#/#, $self->{path}; - my @a_path_components; - my $i; - while (@b_path_components) { - $i = $paths->{'/'.join('/', @b_path_components)}; - last if $i && defined $i->{copyfrom_path}; - unshift(@a_path_components, pop(@b_path_components)); - } - return undef unless defined $i && defined $i->{copyfrom_path}; - my $branch_from = $i->{copyfrom_path}; - if (@a_path_components) { - print STDERR "branch_from: $branch_from => "; - $branch_from .= '/'.join('/', @a_path_components); - print STDERR $branch_from, "\n"; - } - my $r = $i->{copyfrom_rev}; - my $repos_root = $self->ra->{repos_root}; - my $url = $self->ra->{url}; - my $new_url = $url . $branch_from; - print STDERR "Found possible branch point: ", - "$new_url => ", $self->full_url, ", $r\n" - unless $::_q > 1; - $branch_from =~ s#^/##; - my $gs = $self->other_gs($new_url, $url, - $branch_from, $r, $self->{ref_id}); - my ($r0, $parent) = $gs->find_rev_before($r, 1); - { - my ($base, $head); - if (!defined $r0 || !defined $parent) { - ($base, $head) = parse_revision_argument(0, $r); - } else { - if ($r0 < $r) { - $gs->ra->get_log([$gs->{path}], $r0 + 1, $r, 1, - 0, 1, sub { $base = $_[1] - 1 }); - } - } - if (defined $base && $base <= $r) { - $gs->fetch($base, $r); - } - ($r0, $parent) = $gs->find_rev_before($r, 1); - } - if (defined $r0 && defined $parent) { - print STDERR "Found branch parent: ($self->{ref_id}) $parent\n" - unless $::_q > 1; - my $ed; - if ($self->ra->can_do_switch) { - $self->assert_index_clean($parent); - print STDERR "Following parent with do_switch\n" - unless $::_q > 1; - # do_switch works with svn/trunk >= r22312, but that - # is not included with SVN 1.4.3 (the latest version - # at the moment), so we can't rely on it - $self->{last_rev} = $r0; - $self->{last_commit} = $parent; - $ed = Git::SVN::Fetcher->new($self, $gs->{path}); - $gs->ra->gs_do_switch($r0, $rev, $gs, - $self->full_url, $ed) - or die "SVN connection failed somewhere...\n"; - } elsif ($self->ra->trees_match($new_url, $r0, - $self->full_url, $rev)) { - print STDERR "Trees match:\n", - " $new_url\@$r0\n", - " ${\$self->full_url}\@$rev\n", - "Following parent with no changes\n" - unless $::_q > 1; - $self->tmp_index_do(sub { - command_noisy('read-tree', $parent); - }); - $self->{last_commit} = $parent; - } else { - print STDERR "Following parent with do_update\n" - unless $::_q > 1; - $ed = Git::SVN::Fetcher->new($self); - $self->ra->gs_do_update($rev, $rev, $self, $ed) - or die "SVN connection failed somewhere...\n"; - } - print STDERR "Successfully followed parent\n" unless $::_q > 1; - return $self->make_log_entry($rev, [$parent], $ed); - } - return undef; -} - -sub do_fetch { - my ($self, $paths, $rev) = @_; - my $ed; - my ($last_rev, @parents); - if (my $lc = $self->last_commit) { - # we can have a branch that was deleted, then re-added - # under the same name but copied from another path, in - # which case we'll have multiple parents (we don't - # want to break the original ref, nor lose copypath info): - if (my $log_entry = $self->find_parent_branch($paths, $rev)) { - push @{$log_entry->{parents}}, $lc; - return $log_entry; - } - $ed = Git::SVN::Fetcher->new($self); - $last_rev = $self->{last_rev}; - $ed->{c} = $lc; - @parents = ($lc); - } else { - $last_rev = $rev; - if (my $log_entry = $self->find_parent_branch($paths, $rev)) { - return $log_entry; - } - $ed = Git::SVN::Fetcher->new($self); - } - unless ($self->ra->gs_do_update($last_rev, $rev, $self, $ed)) { - die "SVN connection failed somewhere...\n"; - } - $self->make_log_entry($rev, \@parents, $ed); -} - -sub mkemptydirs { - my ($self, $r) = @_; - - sub scan { - my ($r, $empty_dirs, $line) = @_; - if (defined $r && $line =~ /^r(\d+)$/) { - return 0 if $1 > $r; - } elsif ($line =~ /^ \+empty_dir: (.+)$/) { - $empty_dirs->{$1} = 1; - } elsif ($line =~ /^ \-empty_dir: (.+)$/) { - my @d = grep {m[^\Q$1\E(/|$)]} (keys %$empty_dirs); - delete @$empty_dirs{@d}; - } - 1; # continue - }; - - my %empty_dirs = (); - my $gz_file = "$self->{dir}/unhandled.log.gz"; - if (-f $gz_file) { - if (!$can_compress) { - warn "Compress::Zlib could not be found; ", - "empty directories in $gz_file will not be read\n"; - } else { - my $gz = Compress::Zlib::gzopen($gz_file, "rb") or - die "Unable to open $gz_file: $!\n"; - my $line; - while ($gz->gzreadline($line) > 0) { - scan($r, \%empty_dirs, $line) or last; - } - $gz->gzclose; - } - } - - if (open my $fh, '<', "$self->{dir}/unhandled.log") { - binmode $fh or croak "binmode: $!"; - while (<$fh>) { - scan($r, \%empty_dirs, $_) or last; - } - close $fh; - } - - my $strip = qr/\A\Q$self->{path}\E(?:\/|$)/; - foreach my $d (sort keys %empty_dirs) { - $d = uri_decode($d); - $d =~ s/$strip//; - next unless length($d); - next if -d $d; - if (-e $d) { - warn "$d exists but is not a directory\n"; - } else { - print "creating empty directory: $d\n"; - mkpath([$d]); - } - } -} - -sub get_untracked { - my ($self, $ed) = @_; - my @out; - my $h = $ed->{empty}; - foreach (sort keys %$h) { - my $act = $h->{$_} ? '+empty_dir' : '-empty_dir'; - push @out, " $act: " . uri_encode($_); - warn "W: $act: $_\n"; - } - foreach my $t (qw/dir_prop file_prop/) { - $h = $ed->{$t} or next; - foreach my $path (sort keys %$h) { - my $ppath = $path eq '' ? '.' : $path; - foreach my $prop (sort keys %{$h->{$path}}) { - next if $SKIP_PROP{$prop}; - my $v = $h->{$path}->{$prop}; - my $t_ppath_prop = "$t: " . - uri_encode($ppath) . ' ' . - uri_encode($prop); - if (defined $v) { - push @out, " +$t_ppath_prop " . - uri_encode($v); - } else { - push @out, " -$t_ppath_prop"; - } - } - } - } - foreach my $t (qw/absent_file absent_directory/) { - $h = $ed->{$t} or next; - foreach my $parent (sort keys %$h) { - foreach my $path (sort @{$h->{$parent}}) { - push @out, " $t: " . - uri_encode("$parent/$path"); - warn "W: $t: $parent/$path ", - "Insufficient permissions?\n"; - } - } - } - \@out; -} - -sub get_tz { - # some systmes don't handle or mishandle %z, so be creative. - my $t = shift || time; - my $gm = timelocal(gmtime($t)); - my $sign = qw( + + - )[ $t <=> $gm ]; - return sprintf("%s%02d%02d", $sign, (gmtime(abs($t - $gm)))[2,1]); -} - -# parse_svn_date(DATE) -# -------------------- -# Given a date (in UTC) from Subversion, return a string in the format -# "<TZ Offset> <local date/time>" that Git will use. -# -# By default the parsed date will be in UTC; if $Git::SVN::_localtime -# is true we'll convert it to the local timezone instead. -sub parse_svn_date { - my $date = shift || return '+0000 1970-01-01 00:00:00'; - my ($Y,$m,$d,$H,$M,$S) = ($date =~ /^(\d{4})\-(\d\d)\-(\d\d)T - (\d\d)\:(\d\d)\:(\d\d)\.\d*Z$/x) or - croak "Unable to parse date: $date\n"; - my $parsed_date; # Set next. - - if ($Git::SVN::_localtime) { - # Translate the Subversion datetime to an epoch time. - # Begin by switching ourselves to $date's timezone, UTC. - my $old_env_TZ = $ENV{TZ}; - $ENV{TZ} = 'UTC'; - - my $epoch_in_UTC = - POSIX::strftime('%s', $S, $M, $H, $d, $m - 1, $Y - 1900); - - # Determine our local timezone (including DST) at the - # time of $epoch_in_UTC. $Git::SVN::Log::TZ stored the - # value of TZ, if any, at the time we were run. - if (defined $Git::SVN::Log::TZ) { - $ENV{TZ} = $Git::SVN::Log::TZ; - } else { - delete $ENV{TZ}; - } - - my $our_TZ = get_tz(); - - # This converts $epoch_in_UTC into our local timezone. - my ($sec, $min, $hour, $mday, $mon, $year, - $wday, $yday, $isdst) = localtime($epoch_in_UTC); - - $parsed_date = sprintf('%s %04d-%02d-%02d %02d:%02d:%02d', - $our_TZ, $year + 1900, $mon + 1, - $mday, $hour, $min, $sec); - - # Reset us to the timezone in effect when we entered - # this routine. - if (defined $old_env_TZ) { - $ENV{TZ} = $old_env_TZ; - } else { - delete $ENV{TZ}; - } - } else { - $parsed_date = "+0000 $Y-$m-$d $H:$M:$S"; - } - - return $parsed_date; -} - -sub other_gs { - my ($self, $new_url, $url, - $branch_from, $r, $old_ref_id) = @_; - my $gs = Git::SVN->find_by_url($new_url, $url, $branch_from); - unless ($gs) { - my $ref_id = $old_ref_id; - $ref_id =~ s/\@\d+-*$//; - $ref_id .= "\@$r"; - # just grow a tail if we're not unique enough :x - $ref_id .= '-' while find_ref($ref_id); - my ($u, $p, $repo_id) = ($new_url, '', $ref_id); - if ($u =~ s#^\Q$url\E(/|$)##) { - $p = $u; - $u = $url; - $repo_id = $self->{repo_id}; - } - while (1) { - # It is possible to tag two different subdirectories at - # the same revision. If the url for an existing ref - # does not match, we must either find a ref with a - # matching url or create a new ref by growing a tail. - $gs = Git::SVN->init($u, $p, $repo_id, $ref_id, 1); - my (undef, $max_commit) = $gs->rev_map_max(1); - last if (!$max_commit); - my ($url) = ::cmt_metadata($max_commit); - last if ($url eq $gs->metadata_url); - $ref_id .= '-'; - } - print STDERR "Initializing parent: $ref_id\n" unless $::_q > 1; - } - $gs -} - -sub call_authors_prog { - my ($orig_author) = @_; - $orig_author = command_oneline('rev-parse', '--sq-quote', $orig_author); - my $author = `$::_authors_prog $orig_author`; - if ($? != 0) { - die "$::_authors_prog failed with exit code $?\n" - } - if ($author =~ /^\s*(.+?)\s*<(.*)>\s*$/) { - my ($name, $email) = ($1, $2); - $email = undef if length $2 == 0; - return [$name, $email]; - } else { - die "Author: $orig_author: $::_authors_prog returned " - . "invalid author format: $author\n"; - } -} - -sub check_author { - my ($author) = @_; - if (!defined $author || length $author == 0) { - $author = '(no author)'; - } - if (!defined $::users{$author}) { - if (defined $::_authors_prog) { - $::users{$author} = call_authors_prog($author); - } elsif (defined $::_authors) { - die "Author: $author not defined in $::_authors file\n"; - } - } - $author; -} - -sub find_extra_svk_parents { - my ($self, $ed, $tickets, $parents) = @_; - # aha! svk:merge property changed... - my @tickets = split "\n", $tickets; - my @known_parents; - for my $ticket ( @tickets ) { - my ($uuid, $path, $rev) = split /:/, $ticket; - if ( $uuid eq $self->ra_uuid ) { - my $url = $self->{url}; - my $repos_root = $url; - my $branch_from = $path; - $branch_from =~ s{^/}{}; - my $gs = $self->other_gs($repos_root."/".$branch_from, - $url, - $branch_from, - $rev, - $self->{ref_id}); - if ( my $commit = $gs->rev_map_get($rev, $uuid) ) { - # wahey! we found it, but it might be - # an old one (!) - push @known_parents, [ $rev, $commit ]; - } - } - } - # Ordering matters; highest-numbered commit merge tickets - # first, as they may account for later merge ticket additions - # or changes. - @known_parents = map {$_->[1]} sort {$b->[0] <=> $a->[0]} @known_parents; - for my $parent ( @known_parents ) { - my @cmd = ('rev-list', $parent, map { "^$_" } @$parents ); - my ($msg_fh, $ctx) = command_output_pipe(@cmd); - my $new; - while ( <$msg_fh> ) { - $new=1;last; - } - command_close_pipe($msg_fh, $ctx); - if ( $new ) { - print STDERR - "Found merge parent (svk:merge ticket): $parent\n"; - push @$parents, $parent; - } - } -} - -sub lookup_svn_merge { - my $uuid = shift; - my $url = shift; - my $merge = shift; - - my ($source, $revs) = split ":", $merge; - my $path = $source; - $path =~ s{^/}{}; - my $gs = Git::SVN->find_by_url($url.$source, $url, $path); - if ( !$gs ) { - warn "Couldn't find revmap for $url$source\n"; - return; - } - my @ranges = split ",", $revs; - my ($tip, $tip_commit); - my @merged_commit_ranges; - # find the tip - for my $range ( @ranges ) { - my ($bottom, $top) = split "-", $range; - $top ||= $bottom; - my $bottom_commit = $gs->find_rev_after( $bottom, 1, $top ); - my $top_commit = $gs->find_rev_before( $top, 1, $bottom ); - - unless ($top_commit and $bottom_commit) { - warn "W:unknown path/rev in svn:mergeinfo " - ."dirprop: $source:$range\n"; - next; - } - - if (scalar(command('rev-parse', "$bottom_commit^@"))) { - push @merged_commit_ranges, - "$bottom_commit^..$top_commit"; - } else { - push @merged_commit_ranges, "$top_commit"; - } - - if ( !defined $tip or $top > $tip ) { - $tip = $top; - $tip_commit = $top_commit; - } - } - return ($tip_commit, @merged_commit_ranges); -} - -sub _rev_list { - my ($msg_fh, $ctx) = command_output_pipe( - "rev-list", @_, - ); - my @rv; - while ( <$msg_fh> ) { - chomp; - push @rv, $_; - } - command_close_pipe($msg_fh, $ctx); - @rv; -} - -sub check_cherry_pick { - my $base = shift; - my $tip = shift; - my $parents = shift; - my @ranges = @_; - my %commits = map { $_ => 1 } - _rev_list("--no-merges", $tip, "--not", $base, @$parents, "--"); - for my $range ( @ranges ) { - delete @commits{_rev_list($range, "--")}; - } - for my $commit (keys %commits) { - if (has_no_changes($commit)) { - delete $commits{$commit}; - } - } - return (keys %commits); -} - -sub has_no_changes { - my $commit = shift; - - my @revs = split / /, command_oneline( - qw(rev-list --parents -1 -m), $commit); - - # Commits with no parents, e.g. the start of a partial branch, - # have changes by definition. - return 1 if (@revs < 2); - - # Commits with multiple parents, e.g a merge, have no changes - # by definition. - return 0 if (@revs > 2); - - return (command_oneline("rev-parse", "$commit^{tree}") eq - command_oneline("rev-parse", "$commit~1^{tree}")); -} - -sub tie_for_persistent_memoization { - my $hash = shift; - my $path = shift; - - if ($can_use_yaml) { - tie %$hash => 'Git::SVN::Memoize::YAML', "$path.yaml"; - } else { - tie %$hash => 'Memoize::Storable', "$path.db", 'nstore'; - } -} - -# The GIT_DIR environment variable is not always set until after the command -# line arguments are processed, so we can't memoize in a BEGIN block. -{ - my $memoized = 0; - - sub memoize_svn_mergeinfo_functions { - return if $memoized; - $memoized = 1; - - my $cache_path = "$ENV{GIT_DIR}/svn/.caches/"; - mkpath([$cache_path]) unless -d $cache_path; - - my %lookup_svn_merge_cache; - my %check_cherry_pick_cache; - my %has_no_changes_cache; - - tie_for_persistent_memoization(\%lookup_svn_merge_cache, - "$cache_path/lookup_svn_merge"); - memoize 'lookup_svn_merge', - SCALAR_CACHE => 'FAULT', - LIST_CACHE => ['HASH' => \%lookup_svn_merge_cache], - ; - - tie_for_persistent_memoization(\%check_cherry_pick_cache, - "$cache_path/check_cherry_pick"); - memoize 'check_cherry_pick', - SCALAR_CACHE => 'FAULT', - LIST_CACHE => ['HASH' => \%check_cherry_pick_cache], - ; - - tie_for_persistent_memoization(\%has_no_changes_cache, - "$cache_path/has_no_changes"); - memoize 'has_no_changes', - SCALAR_CACHE => ['HASH' => \%has_no_changes_cache], - LIST_CACHE => 'FAULT', - ; - } - - sub unmemoize_svn_mergeinfo_functions { - return if not $memoized; - $memoized = 0; - - Memoize::unmemoize 'lookup_svn_merge'; - Memoize::unmemoize 'check_cherry_pick'; - Memoize::unmemoize 'has_no_changes'; - } - - Memoize::memoize 'Git::SVN::repos_root'; -} - -END { - # Force cache writeout explicitly instead of waiting for - # global destruction to avoid segfault in Storable: - # http://rt.cpan.org/Public/Bug/Display.html?id=36087 - unmemoize_svn_mergeinfo_functions(); -} - -sub parents_exclude { - my $parents = shift; - my @commits = @_; - return unless @commits; - - my @excluded; - my $excluded; - do { - my @cmd = ('rev-list', "-1", @commits, "--not", @$parents ); - $excluded = command_oneline(@cmd); - if ( $excluded ) { - my @new; - my $found; - for my $commit ( @commits ) { - if ( $commit eq $excluded ) { - push @excluded, $commit; - $found++; - last; - } - else { - push @new, $commit; - } - } - die "saw commit '$excluded' in rev-list output, " - ."but we didn't ask for that commit (wanted: @commits --not @$parents)" - unless $found; - @commits = @new; - } - } - while ($excluded and @commits); - - return @excluded; -} - - -# note: this function should only be called if the various dirprops -# have actually changed -sub find_extra_svn_parents { - my ($self, $ed, $mergeinfo, $parents) = @_; - # aha! svk:merge property changed... - - memoize_svn_mergeinfo_functions(); - - # We first search for merged tips which are not in our - # history. Then, we figure out which git revisions are in - # that tip, but not this revision. If all of those revisions - # are now marked as merge, we can add the tip as a parent. - my @merges = split "\n", $mergeinfo; - my @merge_tips; - my $url = $self->{url}; - my $uuid = $self->ra_uuid; - my %ranges; - for my $merge ( @merges ) { - my ($tip_commit, @ranges) = - lookup_svn_merge( $uuid, $url, $merge ); - unless (!$tip_commit or - grep { $_ eq $tip_commit } @$parents ) { - push @merge_tips, $tip_commit; - $ranges{$tip_commit} = \@ranges; - } else { - push @merge_tips, undef; - } - } - - my %excluded = map { $_ => 1 } - parents_exclude($parents, grep { defined } @merge_tips); - - # check merge tips for new parents - my @new_parents; - for my $merge_tip ( @merge_tips ) { - my $spec = shift @merges; - next unless $merge_tip and $excluded{$merge_tip}; - - my $ranges = $ranges{$merge_tip}; - - # check out 'new' tips - my $merge_base; - eval { - $merge_base = command_oneline( - "merge-base", - @$parents, $merge_tip, - ); - }; - if ($@) { - die "An error occurred during merge-base" - unless $@->isa("Git::Error::Command"); - - warn "W: Cannot find common ancestor between ". - "@$parents and $merge_tip. Ignoring merge info.\n"; - next; - } - - # double check that there are no missing non-merge commits - my (@incomplete) = check_cherry_pick( - $merge_base, $merge_tip, - $parents, - @$ranges, - ); - - if ( @incomplete ) { - warn "W:svn cherry-pick ignored ($spec) - missing " - .@incomplete." commit(s) (eg $incomplete[0])\n"; - } else { - warn - "Found merge parent (svn:mergeinfo prop): ", - $merge_tip, "\n"; - push @new_parents, $merge_tip; - } - } - - # cater for merges which merge commits from multiple branches - if ( @new_parents > 1 ) { - for ( my $i = 0; $i <= $#new_parents; $i++ ) { - for ( my $j = 0; $j <= $#new_parents; $j++ ) { - next if $i == $j; - next unless $new_parents[$i]; - next unless $new_parents[$j]; - my $revs = command_oneline( - "rev-list", "-1", - "$new_parents[$i]..$new_parents[$j]", - ); - if ( !$revs ) { - undef($new_parents[$j]); - } - } - } - } - push @$parents, grep { defined } @new_parents; -} - -sub make_log_entry { - my ($self, $rev, $parents, $ed) = @_; - my $untracked = $self->get_untracked($ed); - - my @parents = @$parents; - my $ps = $ed->{path_strip} || ""; - for my $path ( grep { m/$ps/ } %{$ed->{dir_prop}} ) { - my $props = $ed->{dir_prop}{$path}; - if ( $props->{"svk:merge"} ) { - $self->find_extra_svk_parents - ($ed, $props->{"svk:merge"}, \@parents); - } - if ( $props->{"svn:mergeinfo"} ) { - $self->find_extra_svn_parents - ($ed, - $props->{"svn:mergeinfo"}, - \@parents); - } - } - - open my $un, '>>', "$self->{dir}/unhandled.log" or croak $!; - print $un "r$rev\n" or croak $!; - print $un $_, "\n" foreach @$untracked; - my %log_entry = ( parents => \@parents, revision => $rev, - log => ''); - - my $headrev; - my $logged = delete $self->{logged_rev_props}; - if (!$logged || $self->{-want_revprops}) { - my $rp = $self->ra->rev_proplist($rev); - foreach (sort keys %$rp) { - my $v = $rp->{$_}; - if (/^svn:(author|date|log)$/) { - $log_entry{$1} = $v; - } elsif ($_ eq 'svm:headrev') { - $headrev = $v; - } else { - print $un " rev_prop: ", uri_encode($_), ' ', - uri_encode($v), "\n"; - } - } - } else { - map { $log_entry{$_} = $logged->{$_} } keys %$logged; - } - close $un or croak $!; - - $log_entry{date} = parse_svn_date($log_entry{date}); - $log_entry{log} .= "\n"; - my $author = $log_entry{author} = check_author($log_entry{author}); - my ($name, $email) = defined $::users{$author} ? @{$::users{$author}} - : ($author, undef); - - my ($commit_name, $commit_email) = ($name, $email); - if ($_use_log_author) { - my $name_field; - if ($log_entry{log} =~ /From:\s+(.*\S)\s*\n/i) { - $name_field = $1; - } elsif ($log_entry{log} =~ /Signed-off-by:\s+(.*\S)\s*\n/i) { - $name_field = $1; - } - if (!defined $name_field) { - if (!defined $email) { - $email = $name; - } - } elsif ($name_field =~ /(.*?)\s+<(.*)>/) { - ($name, $email) = ($1, $2); - } elsif ($name_field =~ /(.*)@/) { - ($name, $email) = ($1, $name_field); - } else { - ($name, $email) = ($name_field, $name_field); - } - } - if (defined $headrev && $self->use_svm_props) { - if ($self->rewrite_root) { - die "Can't have both 'useSvmProps' and 'rewriteRoot' ", - "options set!\n"; - } - if ($self->rewrite_uuid) { - die "Can't have both 'useSvmProps' and 'rewriteUUID' ", - "options set!\n"; - } - my ($uuid, $r) = $headrev =~ m{^([a-f\d\-]{30,}):(\d+)$}i; - # we don't want "SVM: initializing mirror for junk" ... - return undef if $r == 0; - my $svm = $self->svm; - if ($uuid ne $svm->{uuid}) { - die "UUID mismatch on SVM path:\n", - "expected: $svm->{uuid}\n", - " got: $uuid\n"; - } - my $full_url = $self->full_url; - $full_url =~ s#^\Q$svm->{replace}\E(/|$)#$svm->{source}$1# or - die "Failed to replace '$svm->{replace}' with ", - "'$svm->{source}' in $full_url\n"; - # throw away username for storing in records - remove_username($full_url); - $log_entry{metadata} = "$full_url\@$r $uuid"; - $log_entry{svm_revision} = $r; - $email ||= "$author\@$uuid"; - $commit_email ||= "$author\@$uuid"; - } elsif ($self->use_svnsync_props) { - my $full_url = $self->svnsync->{url}; - $full_url .= "/$self->{path}" if length $self->{path}; - remove_username($full_url); - my $uuid = $self->svnsync->{uuid}; - $log_entry{metadata} = "$full_url\@$rev $uuid"; - $email ||= "$author\@$uuid"; - $commit_email ||= "$author\@$uuid"; - } else { - my $url = $self->metadata_url; - remove_username($url); - my $uuid = $self->rewrite_uuid || $self->ra->get_uuid; - $log_entry{metadata} = "$url\@$rev " . $uuid; - $email ||= "$author\@" . $uuid; - $commit_email ||= "$author\@" . $uuid; - } - $log_entry{name} = $name; - $log_entry{email} = $email; - $log_entry{commit_name} = $commit_name; - $log_entry{commit_email} = $commit_email; - \%log_entry; -} - -sub fetch { - my ($self, $min_rev, $max_rev, @parents) = @_; - my ($last_rev, $last_commit) = $self->last_rev_commit; - my ($base, $head) = $self->get_fetch_range($min_rev, $max_rev); - $self->ra->gs_fetch_loop_common($base, $head, [$self]); -} - -sub set_tree_cb { - my ($self, $log_entry, $tree, $rev, $date, $author) = @_; - $self->{inject_parents} = { $rev => $tree }; - $self->fetch(undef, undef); -} - -sub set_tree { - my ($self, $tree) = (shift, shift); - my $log_entry = ::get_commit_entry($tree); - unless ($self->{last_rev}) { - ::fatal("Must have an existing revision to commit"); - } - my %ed_opts = ( r => $self->{last_rev}, - log => $log_entry->{log}, - ra => $self->ra, - tree_a => $self->{last_commit}, - tree_b => $tree, - editor_cb => sub { - $self->set_tree_cb($log_entry, $tree, @_) }, - svn_path => $self->{path} ); - if (!Git::SVN::Editor->new(\%ed_opts)->apply_diff) { - print "No changes\nr$self->{last_rev} = $tree\n"; - } -} - -sub rebuild_from_rev_db { - my ($self, $path) = @_; - my $r = -1; - open my $fh, '<', $path or croak "open: $!"; - binmode $fh or croak "binmode: $!"; - while (<$fh>) { - length($_) == 41 or croak "inconsistent size in ($_) != 41"; - chomp($_); - ++$r; - next if $_ eq ('0' x 40); - $self->rev_map_set($r, $_); - print "r$r = $_\n"; - } - close $fh or croak "close: $!"; - unlink $path or croak "unlink: $!"; -} - -sub rebuild { - my ($self) = @_; - my $map_path = $self->map_path; - my $partial = (-e $map_path && ! -z $map_path); - return unless ::verify_ref($self->refname.'^0'); - if (!$partial && ($self->use_svm_props || $self->no_metadata)) { - my $rev_db = $self->rev_db_path; - $self->rebuild_from_rev_db($rev_db); - if ($self->use_svm_props) { - my $svm_rev_db = $self->rev_db_path($self->svm_uuid); - $self->rebuild_from_rev_db($svm_rev_db); - } - $self->unlink_rev_db_symlink; - return; - } - print "Rebuilding $map_path ...\n" if (!$partial); - my ($base_rev, $head) = ($partial ? $self->rev_map_max_norebuild(1) : - (undef, undef)); - my ($log, $ctx) = - command_output_pipe(qw/rev-list --pretty=raw --reverse/, - ($head ? "$head.." : "") . $self->refname, - '--'); - my $metadata_url = $self->metadata_url; - remove_username($metadata_url); - my $svn_uuid = $self->rewrite_uuid || $self->ra_uuid; - my $c; - while (<$log>) { - if ( m{^commit ($::sha1)$} ) { - $c = $1; - next; - } - next unless s{^\s*(git-svn-id:)}{$1}; - my ($url, $rev, $uuid) = ::extract_metadata($_); - remove_username($url); - - # ignore merges (from set-tree) - next if (!defined $rev || !$uuid); - - # if we merged or otherwise started elsewhere, this is - # how we break out of it - if (($uuid ne $svn_uuid) || - ($metadata_url && $url && ($url ne $metadata_url))) { - next; - } - if ($partial && $head) { - print "Partial-rebuilding $map_path ...\n"; - print "Currently at $base_rev = $head\n"; - $head = undef; - } - - $self->rev_map_set($rev, $c); - print "r$rev = $c\n"; - } - command_close_pipe($log, $ctx); - print "Done rebuilding $map_path\n" if (!$partial || !$head); - my $rev_db_path = $self->rev_db_path; - if (-f $self->rev_db_path) { - unlink $self->rev_db_path or croak "unlink: $!"; - } - $self->unlink_rev_db_symlink; -} - -# rev_map: -# Tie::File seems to be prone to offset errors if revisions get sparse, -# it's not that fast, either. Tie::File is also not in Perl 5.6. So -# one of my favorite modules is out :< Next up would be one of the DBM -# modules, but I'm not sure which is most portable... -# -# This is the replacement for the rev_db format, which was too big -# and inefficient for large repositories with a lot of sparse history -# (mainly tags) -# -# The format is this: -# - 24 bytes for every record, -# * 4 bytes for the integer representing an SVN revision number -# * 20 bytes representing the sha1 of a git commit -# - No empty padding records like the old format -# (except the last record, which can be overwritten) -# - new records are written append-only since SVN revision numbers -# increase monotonically -# - lookups on SVN revision number are done via a binary search -# - Piping the file to xxd -c24 is a good way of dumping it for -# viewing or editing (piped back through xxd -r), should the need -# ever arise. -# - The last record can be padding revision with an all-zero sha1 -# This is used to optimize fetch performance when using multiple -# "fetch" directives in .git/config -# -# These files are disposable unless noMetadata or useSvmProps is set - -sub _rev_map_set { - my ($fh, $rev, $commit) = @_; - - binmode $fh or croak "binmode: $!"; - my $size = (stat($fh))[7]; - ($size % 24) == 0 or croak "inconsistent size: $size"; - - my $wr_offset = 0; - if ($size > 0) { - sysseek($fh, -24, SEEK_END) or croak "seek: $!"; - my $read = sysread($fh, my $buf, 24) or croak "read: $!"; - $read == 24 or croak "read only $read bytes (!= 24)"; - my ($last_rev, $last_commit) = unpack(rev_map_fmt, $buf); - if ($last_commit eq ('0' x40)) { - if ($size >= 48) { - sysseek($fh, -48, SEEK_END) or croak "seek: $!"; - $read = sysread($fh, $buf, 24) or - croak "read: $!"; - $read == 24 or - croak "read only $read bytes (!= 24)"; - ($last_rev, $last_commit) = - unpack(rev_map_fmt, $buf); - if ($last_commit eq ('0' x40)) { - croak "inconsistent .rev_map\n"; - } - } - if ($last_rev >= $rev) { - croak "last_rev is higher!: $last_rev >= $rev"; - } - $wr_offset = -24; - } - } - sysseek($fh, $wr_offset, SEEK_END) or croak "seek: $!"; - syswrite($fh, pack(rev_map_fmt, $rev, $commit), 24) == 24 or - croak "write: $!"; -} - -sub _rev_map_reset { - my ($fh, $rev, $commit) = @_; - my $c = _rev_map_get($fh, $rev); - $c eq $commit or die "_rev_map_reset(@_) commit $c does not match!\n"; - my $offset = sysseek($fh, 0, SEEK_CUR) or croak "seek: $!"; - truncate $fh, $offset or croak "truncate: $!"; -} - -sub mkfile { - my ($path) = @_; - unless (-e $path) { - my ($dir, $base) = ($path =~ m#^(.*?)/?([^/]+)$#); - mkpath([$dir]) unless -d $dir; - open my $fh, '>>', $path or die "Couldn't create $path: $!\n"; - close $fh or die "Couldn't close (create) $path: $!\n"; - } -} - -sub rev_map_set { - my ($self, $rev, $commit, $update_ref, $uuid) = @_; - defined $commit or die "missing arg3\n"; - length $commit == 40 or die "arg3 must be a full SHA1 hexsum\n"; - my $db = $self->map_path($uuid); - my $db_lock = "$db.lock"; - my $sigmask; - $update_ref ||= 0; - if ($update_ref) { - $sigmask = POSIX::SigSet->new(); - my $signew = POSIX::SigSet->new(SIGINT, SIGHUP, SIGTERM, - SIGALRM, SIGUSR1, SIGUSR2); - sigprocmask(SIG_BLOCK, $signew, $sigmask) or - croak "Can't block signals: $!"; - } - mkfile($db); - - $LOCKFILES{$db_lock} = 1; - my $sync; - # both of these options make our .rev_db file very, very important - # and we can't afford to lose it because rebuild() won't work - if ($self->use_svm_props || $self->no_metadata) { - $sync = 1; - copy($db, $db_lock) or die "rev_map_set(@_): ", - "Failed to copy: ", - "$db => $db_lock ($!)\n"; - } else { - rename $db, $db_lock or die "rev_map_set(@_): ", - "Failed to rename: ", - "$db => $db_lock ($!)\n"; - } - - sysopen(my $fh, $db_lock, O_RDWR | O_CREAT) - or croak "Couldn't open $db_lock: $!\n"; - $update_ref eq 'reset' ? _rev_map_reset($fh, $rev, $commit) : - _rev_map_set($fh, $rev, $commit); - if ($sync) { - $fh->flush or die "Couldn't flush $db_lock: $!\n"; - $fh->sync or die "Couldn't sync $db_lock: $!\n"; - } - close $fh or croak $!; - if ($update_ref) { - $_head = $self; - my $note = ""; - $note = " ($update_ref)" if ($update_ref !~ /^\d*$/); - command_noisy('update-ref', '-m', "r$rev$note", - $self->refname, $commit); - } - rename $db_lock, $db or die "rev_map_set(@_): ", "Failed to rename: ", - "$db_lock => $db ($!)\n"; - delete $LOCKFILES{$db_lock}; - if ($update_ref) { - sigprocmask(SIG_SETMASK, $sigmask) or - croak "Can't restore signal mask: $!"; - } -} - -# If want_commit, this will return an array of (rev, commit) where -# commit _must_ be a valid commit in the archive. -# Otherwise, it'll return the max revision (whether or not the -# commit is valid or just a 0x40 placeholder). -sub rev_map_max { - my ($self, $want_commit) = @_; - $self->rebuild; - my ($r, $c) = $self->rev_map_max_norebuild($want_commit); - $want_commit ? ($r, $c) : $r; -} - -sub rev_map_max_norebuild { - my ($self, $want_commit) = @_; - my $map_path = $self->map_path; - stat $map_path or return $want_commit ? (0, undef) : 0; - sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!"; - binmode $fh or croak "binmode: $!"; - my $size = (stat($fh))[7]; - ($size % 24) == 0 or croak "inconsistent size: $size"; - - if ($size == 0) { - close $fh or croak "close: $!"; - return $want_commit ? (0, undef) : 0; - } - - sysseek($fh, -24, SEEK_END) or croak "seek: $!"; - sysread($fh, my $buf, 24) == 24 or croak "read: $!"; - my ($r, $c) = unpack(rev_map_fmt, $buf); - if ($want_commit && $c eq ('0' x40)) { - if ($size < 48) { - return $want_commit ? (0, undef) : 0; - } - sysseek($fh, -48, SEEK_END) or croak "seek: $!"; - sysread($fh, $buf, 24) == 24 or croak "read: $!"; - ($r, $c) = unpack(rev_map_fmt, $buf); - if ($c eq ('0'x40)) { - croak "Penultimate record is all-zeroes in $map_path"; - } - } - close $fh or croak "close: $!"; - $want_commit ? ($r, $c) : $r; -} - -sub rev_map_get { - my ($self, $rev, $uuid) = @_; - my $map_path = $self->map_path($uuid); - return undef unless -e $map_path; - - sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!"; - my $c = _rev_map_get($fh, $rev); - close($fh) or croak "close: $!"; - $c -} - -sub _rev_map_get { - my ($fh, $rev) = @_; - - binmode $fh or croak "binmode: $!"; - my $size = (stat($fh))[7]; - ($size % 24) == 0 or croak "inconsistent size: $size"; - - if ($size == 0) { - return undef; - } - - my ($l, $u) = (0, $size - 24); - my ($r, $c, $buf); - - while ($l <= $u) { - my $i = int(($l/24 + $u/24) / 2) * 24; - sysseek($fh, $i, SEEK_SET) or croak "seek: $!"; - sysread($fh, my $buf, 24) == 24 or croak "read: $!"; - my ($r, $c) = unpack(rev_map_fmt, $buf); - - if ($r < $rev) { - $l = $i + 24; - } elsif ($r > $rev) { - $u = $i - 24; - } else { # $r == $rev - return $c eq ('0' x 40) ? undef : $c; - } - } - undef; -} - -# Finds the first svn revision that exists on (if $eq_ok is true) or -# before $rev for the current branch. It will not search any lower -# than $min_rev. Returns the git commit hash and svn revision number -# if found, else (undef, undef). -sub find_rev_before { - my ($self, $rev, $eq_ok, $min_rev) = @_; - --$rev unless $eq_ok; - $min_rev ||= 1; - my $max_rev = $self->rev_map_max; - $rev = $max_rev if ($rev > $max_rev); - while ($rev >= $min_rev) { - if (my $c = $self->rev_map_get($rev)) { - return ($rev, $c); - } - --$rev; - } - return (undef, undef); -} - -# Finds the first svn revision that exists on (if $eq_ok is true) or -# after $rev for the current branch. It will not search any higher -# than $max_rev. Returns the git commit hash and svn revision number -# if found, else (undef, undef). -sub find_rev_after { - my ($self, $rev, $eq_ok, $max_rev) = @_; - ++$rev unless $eq_ok; - $max_rev ||= $self->rev_map_max; - while ($rev <= $max_rev) { - if (my $c = $self->rev_map_get($rev)) { - return ($rev, $c); - } - ++$rev; - } - return (undef, undef); -} - -sub _new { - my ($class, $repo_id, $ref_id, $path) = @_; - unless (defined $repo_id && length $repo_id) { - $repo_id = $Git::SVN::default_repo_id; - } - unless (defined $ref_id && length $ref_id) { - $_prefix = '' unless defined($_prefix); - $_[2] = $ref_id = - "refs/remotes/$_prefix$Git::SVN::default_ref_id"; - } - $_[1] = $repo_id; - my $dir = "$ENV{GIT_DIR}/svn/$ref_id"; - - # Older repos imported by us used $GIT_DIR/svn/foo instead of - # $GIT_DIR/svn/refs/remotes/foo when tracking refs/remotes/foo - if ($ref_id =~ m{^refs/remotes/(.*)}) { - my $old_dir = "$ENV{GIT_DIR}/svn/$1"; - if (-d $old_dir && ! -d $dir) { - $dir = $old_dir; - } - } - - $_[3] = $path = '' unless (defined $path); - mkpath([$dir]); - bless { - ref_id => $ref_id, dir => $dir, index => "$dir/index", - path => $path, config => "$ENV{GIT_DIR}/svn/config", - map_root => "$dir/.rev_map", repo_id => $repo_id }, $class; -} - -# for read-only access of old .rev_db formats -sub unlink_rev_db_symlink { - my ($self) = @_; - my $link = $self->rev_db_path; - $link =~ s/\.[\w-]+$// or croak "missing UUID at the end of $link"; - if (-l $link) { - unlink $link or croak "unlink: $link failed!"; - } -} - -sub rev_db_path { - my ($self, $uuid) = @_; - my $db_path = $self->map_path($uuid); - $db_path =~ s{/\.rev_map\.}{/\.rev_db\.} - or croak "map_path: $db_path does not contain '/.rev_map.' !"; - $db_path; -} - -# the new replacement for .rev_db -sub map_path { - my ($self, $uuid) = @_; - $uuid ||= $self->ra_uuid; - "$self->{map_root}.$uuid"; -} - -sub uri_encode { - my ($f) = @_; - $f =~ s#([^a-zA-Z0-9\*!\:_\./\-])#uc sprintf("%%%02x",ord($1))#eg; - $f -} - -sub uri_decode { - my ($f) = @_; - $f =~ s#%([0-9a-fA-F]{2})#chr(hex($1))#eg; - $f -} - -sub remove_username { - $_[0] =~ s{^([^:]*://)[^@]+@}{$1}; -} - -package Git::SVN::Log; -use strict; -use warnings; -use POSIX qw/strftime/; -use constant commit_log_separator => ('-' x 72) . "\n"; -use vars qw/$TZ $limit $color $pager $non_recursive $verbose $oneline - %rusers $show_commit $incremental/; -my $l_fmt; - -sub cmt_showable { - my ($c) = @_; - return 1 if defined $c->{r}; - - # big commit message got truncated by the 16k pretty buffer in rev-list - if ($c->{l} && $c->{l}->[-1] eq "...\n" && - $c->{a_raw} =~ /\@([a-f\d\-]+)>$/) { - @{$c->{l}} = (); - my @log = command(qw/cat-file commit/, $c->{c}); - - # shift off the headers - shift @log while ($log[0] ne ''); - shift @log; - - # TODO: make $c->{l} not have a trailing newline in the future - @{$c->{l}} = map { "$_\n" } grep !/^git-svn-id: /, @log; - - (undef, $c->{r}, undef) = ::extract_metadata( - (grep(/^git-svn-id: /, @log))[-1]); - } - return defined $c->{r}; -} - -sub log_use_color { - return $color || Git->repository->get_colorbool('color.diff'); -} - -sub git_svn_log_cmd { - my ($r_min, $r_max, @args) = @_; - my $head = 'HEAD'; - my (@files, @log_opts); - foreach my $x (@args) { - if ($x eq '--' || @files) { - push @files, $x; - } else { - if (::verify_ref("$x^0")) { - $head = $x; - } else { - push @log_opts, $x; - } - } - } - - my ($url, $rev, $uuid, $gs) = ::working_head_info($head); - $gs ||= Git::SVN->_new; - my @cmd = (qw/log --abbrev-commit --pretty=raw --default/, - $gs->refname); - push @cmd, '-r' unless $non_recursive; - push @cmd, qw/--raw --name-status/ if $verbose; - push @cmd, '--color' if log_use_color(); - push @cmd, @log_opts; - if (defined $r_max && $r_max == $r_min) { - push @cmd, '--max-count=1'; - if (my $c = $gs->rev_map_get($r_max)) { - push @cmd, $c; - } - } elsif (defined $r_max) { - if ($r_max < $r_min) { - ($r_min, $r_max) = ($r_max, $r_min); - } - my (undef, $c_max) = $gs->find_rev_before($r_max, 1, $r_min); - my (undef, $c_min) = $gs->find_rev_after($r_min, 1, $r_max); - # If there are no commits in the range, both $c_max and $c_min - # will be undefined. If there is at least 1 commit in the - # range, both will be defined. - return () if !defined $c_min || !defined $c_max; - if ($c_min eq $c_max) { - push @cmd, '--max-count=1', $c_min; - } else { - push @cmd, '--boundary', "$c_min..$c_max"; - } - } - return (@cmd, @files); -} - -# adapted from pager.c -sub config_pager { - if (! -t *STDOUT) { - $ENV{GIT_PAGER_IN_USE} = 'false'; - $pager = undef; - return; - } - chomp($pager = command_oneline(qw(var GIT_PAGER))); - if ($pager eq 'cat') { - $pager = undef; - } - $ENV{GIT_PAGER_IN_USE} = defined($pager); -} - -sub run_pager { - return unless defined $pager; - pipe my ($rfd, $wfd) or return; - defined(my $pid = fork) or ::fatal "Can't fork: $!"; - if (!$pid) { - open STDOUT, '>&', $wfd or - ::fatal "Can't redirect to stdout: $!"; - return; - } - open STDIN, '<&', $rfd or ::fatal "Can't redirect stdin: $!"; - $ENV{LESS} ||= 'FRSX'; - exec $pager or ::fatal "Can't run pager: $! ($pager)"; -} - -sub format_svn_date { - my $t = shift || time; - my $gmoff = Git::SVN::get_tz($t); - return strftime("%Y-%m-%d %H:%M:%S $gmoff (%a, %d %b %Y)", localtime($t)); -} - -sub parse_git_date { - my ($t, $tz) = @_; - # Date::Parse isn't in the standard Perl distro :( - if ($tz =~ s/^\+//) { - $t += tz_to_s_offset($tz); - } elsif ($tz =~ s/^\-//) { - $t -= tz_to_s_offset($tz); - } - return $t; -} - -sub set_local_timezone { - if (defined $TZ) { - $ENV{TZ} = $TZ; - } else { - delete $ENV{TZ}; - } -} - -sub tz_to_s_offset { - my ($tz) = @_; - $tz =~ s/(\d\d)$//; - return ($1 * 60) + ($tz * 3600); -} - -sub get_author_info { - my ($dest, $author, $t, $tz) = @_; - $author =~ s/(?:^\s*|\s*$)//g; - $dest->{a_raw} = $author; - my $au; - if ($::_authors) { - $au = $rusers{$author} || undef; - } - if (!$au) { - ($au) = ($author =~ /<([^>]+)\@[^>]+>$/); - } - $dest->{t} = $t; - $dest->{tz} = $tz; - $dest->{a} = $au; - $dest->{t_utc} = parse_git_date($t, $tz); -} - -sub process_commit { - my ($c, $r_min, $r_max, $defer) = @_; - if (defined $r_min && defined $r_max) { - if ($r_min == $c->{r} && $r_min == $r_max) { - show_commit($c); - return 0; - } - return 1 if $r_min == $r_max; - if ($r_min < $r_max) { - # we need to reverse the print order - return 0 if (defined $limit && --$limit < 0); - push @$defer, $c; - return 1; - } - if ($r_min != $r_max) { - return 1 if ($r_min < $c->{r}); - return 1 if ($r_max > $c->{r}); - } - } - return 0 if (defined $limit && --$limit < 0); - show_commit($c); - return 1; -} - -sub show_commit { - my $c = shift; - if ($oneline) { - my $x = "\n"; - if (my $l = $c->{l}) { - while ($l->[0] =~ /^\s*$/) { shift @$l } - $x = $l->[0]; - } - $l_fmt ||= 'A' . length($c->{r}); - print 'r',pack($l_fmt, $c->{r}),' | '; - print "$c->{c} | " if $show_commit; - print $x; - } else { - show_commit_normal($c); - } -} - -sub show_commit_changed_paths { - my ($c) = @_; - return unless $c->{changed}; - print "Changed paths:\n", @{$c->{changed}}; -} - -sub show_commit_normal { - my ($c) = @_; - print commit_log_separator, "r$c->{r} | "; - print "$c->{c} | " if $show_commit; - print "$c->{a} | ", format_svn_date($c->{t_utc}), ' | '; - my $nr_line = 0; - - if (my $l = $c->{l}) { - while ($l->[$#$l] eq "\n" && $#$l > 0 - && $l->[($#$l - 1)] eq "\n") { - pop @$l; - } - $nr_line = scalar @$l; - if (!$nr_line) { - print "1 line\n\n\n"; - } else { - if ($nr_line == 1) { - $nr_line = '1 line'; - } else { - $nr_line .= ' lines'; - } - print $nr_line, "\n"; - show_commit_changed_paths($c); - print "\n"; - print $_ foreach @$l; - } - } else { - print "1 line\n"; - show_commit_changed_paths($c); - print "\n"; - - } - foreach my $x (qw/raw stat diff/) { - if ($c->{$x}) { - print "\n"; - print $_ foreach @{$c->{$x}} - } - } -} - -sub cmd_show_log { - my (@args) = @_; - my ($r_min, $r_max); - my $r_last = -1; # prevent dupes - set_local_timezone(); - if (defined $::_revision) { - if ($::_revision =~ /^(\d+):(\d+)$/) { - ($r_min, $r_max) = ($1, $2); - } elsif ($::_revision =~ /^\d+$/) { - $r_min = $r_max = $::_revision; - } else { - ::fatal "-r$::_revision is not supported, use ", - "standard 'git log' arguments instead"; - } - } - - config_pager(); - @args = git_svn_log_cmd($r_min, $r_max, @args); - if (!@args) { - print commit_log_separator unless $incremental || $oneline; - return; - } - my $log = command_output_pipe(@args); - run_pager(); - my (@k, $c, $d, $stat); - my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/; - while (<$log>) { - if (/^${esc_color}commit (?:- )?($::sha1_short)/o) { - my $cmt = $1; - if ($c && cmt_showable($c) && $c->{r} != $r_last) { - $r_last = $c->{r}; - process_commit($c, $r_min, $r_max, \@k) or - goto out; - } - $d = undef; - $c = { c => $cmt }; - } elsif (/^${esc_color}author (.+) (\d+) ([\-\+]?\d+)$/o) { - get_author_info($c, $1, $2, $3); - } elsif (/^${esc_color}(?:tree|parent|committer) /o) { - # ignore - } elsif (/^${esc_color}:\d{6} \d{6} $::sha1_short/o) { - push @{$c->{raw}}, $_; - } elsif (/^${esc_color}[ACRMDT]\t/) { - # we could add $SVN->{svn_path} here, but that requires - # remote access at the moment (repo_path_split)... - s#^(${esc_color})([ACRMDT])\t#$1 $2 #o; - push @{$c->{changed}}, $_; - } elsif (/^${esc_color}diff /o) { - $d = 1; - push @{$c->{diff}}, $_; - } elsif ($d) { - push @{$c->{diff}}, $_; - } elsif (/^\ .+\ \|\s*\d+\ $esc_color[\+\-]* - $esc_color*[\+\-]*$esc_color$/x) { - $stat = 1; - push @{$c->{stat}}, $_; - } elsif ($stat && /^ \d+ files changed, \d+ insertions/) { - push @{$c->{stat}}, $_; - $stat = undef; - } elsif (/^${esc_color} (git-svn-id:.+)$/o) { - ($c->{url}, $c->{r}, undef) = ::extract_metadata($1); - } elsif (s/^${esc_color} //o) { - push @{$c->{l}}, $_; - } - } - if ($c && defined $c->{r} && $c->{r} != $r_last) { - $r_last = $c->{r}; - process_commit($c, $r_min, $r_max, \@k); - } - if (@k) { - ($r_min, $r_max) = ($r_max, $r_min); - process_commit($_, $r_min, $r_max) foreach reverse @k; - } -out: - close $log; - print commit_log_separator unless $incremental || $oneline; -} - -sub cmd_blame { - my $path = pop; - - config_pager(); - run_pager(); - - my ($fh, $ctx, $rev); - - if ($_git_format) { - ($fh, $ctx) = command_output_pipe('blame', @_, $path); - while (my $line = <$fh>) { - if ($line =~ /^\^?([[:xdigit:]]+)\s/) { - # Uncommitted edits show up as a rev ID of - # all zeros, which we can't look up with - # cmt_metadata - if ($1 !~ /^0+$/) { - (undef, $rev, undef) = - ::cmt_metadata($1); - $rev = '0' if (!$rev); - } else { - $rev = '0'; - } - $rev = sprintf('%-10s', $rev); - $line =~ s/^\^?[[:xdigit:]]+(\s)/$rev$1/; - } - print $line; - } - } else { - ($fh, $ctx) = command_output_pipe('blame', '-p', @_, 'HEAD', - '--', $path); - my ($sha1); - my %authors; - my @buffer; - my %dsha; #distinct sha keys - - while (my $line = <$fh>) { - push @buffer, $line; - if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) { - $dsha{$1} = 1; - } - } - - my $s2r = ::cmt_sha2rev_batch([keys %dsha]); - - foreach my $line (@buffer) { - if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) { - $rev = $s2r->{$1}; - $rev = '0' if (!$rev) - } - elsif ($line =~ /^author (.*)/) { - $authors{$rev} = $1; - $authors{$rev} =~ s/\s/_/g; - } - elsif ($line =~ /^\t(.*)$/) { - printf("%6s %10s %s\n", $rev, $authors{$rev}, $1); - } - } - } - command_close_pipe($fh, $ctx); -} - -package Git::SVN::Migration; -# these version numbers do NOT correspond to actual version numbers -# of git nor git-svn. They are just relative. -# -# v0 layout: .git/$id/info/url, refs/heads/$id-HEAD -# -# v1 layout: .git/$id/info/url, refs/remotes/$id -# -# v2 layout: .git/svn/$id/info/url, refs/remotes/$id -# -# v3 layout: .git/svn/$id, refs/remotes/$id -# - info/url may remain for backwards compatibility -# - this is what we migrate up to this layout automatically, -# - this will be used by git svn init on single branches -# v3.1 layout (auto migrated): -# - .rev_db => .rev_db.$UUID, .rev_db will remain as a symlink -# for backwards compatibility -# -# v4 layout: .git/svn/$repo_id/$id, refs/remotes/$repo_id/$id -# - this is only created for newly multi-init-ed -# repositories. Similar in spirit to the -# --use-separate-remotes option in git-clone (now default) -# - we do not automatically migrate to this (following -# the example set by core git) -# -# v5 layout: .rev_db.$UUID => .rev_map.$UUID -# - newer, more-efficient format that uses 24-bytes per record -# with no filler space. -# - use xxd -c24 < .rev_map.$UUID to view and debug -# - This is a one-way migration, repositories updated to the -# new format will not be able to use old git-svn without -# rebuilding the .rev_db. Rebuilding the rev_db is not -# possible if noMetadata or useSvmProps are set; but should -# be no problem for users that use the (sensible) defaults. -use strict; -use warnings; -use Carp qw/croak/; -use File::Path qw/mkpath/; -use File::Basename qw/dirname basename/; -use vars qw/$_minimize/; - -sub migrate_from_v0 { - my $git_dir = $ENV{GIT_DIR}; - return undef unless -d $git_dir; - my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/); - my $migrated = 0; - while (<$fh>) { - chomp; - my ($id, $orig_ref) = ($_, $_); - next unless $id =~ s#^refs/heads/(.+)-HEAD$#$1#; - next unless -f "$git_dir/$id/info/url"; - my $new_ref = "refs/remotes/$id"; - if (::verify_ref("$new_ref^0")) { - print STDERR "W: $orig_ref is probably an old ", - "branch used by an ancient version of ", - "git-svn.\n", - "However, $new_ref also exists.\n", - "We will not be able ", - "to use this branch until this ", - "ambiguity is resolved.\n"; - next; - } - print STDERR "Migrating from v0 layout...\n" if !$migrated; - print STDERR "Renaming ref: $orig_ref => $new_ref\n"; - command_noisy('update-ref', $new_ref, $orig_ref); - command_noisy('update-ref', '-d', $orig_ref, $orig_ref); - $migrated++; - } - command_close_pipe($fh, $ctx); - print STDERR "Done migrating from v0 layout...\n" if $migrated; - $migrated; -} - -sub migrate_from_v1 { - my $git_dir = $ENV{GIT_DIR}; - my $migrated = 0; - return $migrated unless -d $git_dir; - my $svn_dir = "$git_dir/svn"; - - # just in case somebody used 'svn' as their $id at some point... - return $migrated if -d $svn_dir && ! -f "$svn_dir/info/url"; - - print STDERR "Migrating from a git-svn v1 layout...\n"; - mkpath([$svn_dir]); - print STDERR "Data from a previous version of git-svn exists, but\n\t", - "$svn_dir\n\t(required for this version ", - "($::VERSION) of git-svn) does not exist.\n"; - my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/); - while (<$fh>) { - my $x = $_; - next unless $x =~ s#^refs/remotes/##; - chomp $x; - next unless -f "$git_dir/$x/info/url"; - my $u = eval { ::file_to_s("$git_dir/$x/info/url") }; - next unless $u; - my $dn = dirname("$git_dir/svn/$x"); - mkpath([$dn]) unless -d $dn; - if ($x eq 'svn') { # they used 'svn' as GIT_SVN_ID: - mkpath(["$git_dir/svn/svn"]); - print STDERR " - $git_dir/$x/info => ", - "$git_dir/svn/$x/info\n"; - rename "$git_dir/$x/info", "$git_dir/svn/$x/info" or - croak "$!: $x"; - # don't worry too much about these, they probably - # don't exist with repos this old (save for index, - # and we can easily regenerate that) - foreach my $f (qw/unhandled.log index .rev_db/) { - rename "$git_dir/$x/$f", "$git_dir/svn/$x/$f"; - } - } else { - print STDERR " - $git_dir/$x => $git_dir/svn/$x\n"; - rename "$git_dir/$x", "$git_dir/svn/$x" or - croak "$!: $x"; - } - $migrated++; - } - command_close_pipe($fh, $ctx); - print STDERR "Done migrating from a git-svn v1 layout\n"; - $migrated; -} - -sub read_old_urls { - my ($l_map, $pfx, $path) = @_; - my @dir; - foreach (<$path/*>) { - if (-r "$_/info/url") { - $pfx .= '/' if $pfx && $pfx !~ m!/$!; - my $ref_id = $pfx . basename $_; - my $url = ::file_to_s("$_/info/url"); - $l_map->{$ref_id} = $url; - } elsif (-d $_) { - push @dir, $_; - } - } - foreach (@dir) { - my $x = $_; - $x =~ s!^\Q$ENV{GIT_DIR}\E/svn/!!o; - read_old_urls($l_map, $x, $_); - } -} - -sub migrate_from_v2 { - my @cfg = command(qw/config -l/); - return if grep /^svn-remote\..+\.url=/, @cfg; - my %l_map; - read_old_urls(\%l_map, '', "$ENV{GIT_DIR}/svn"); - my $migrated = 0; - - foreach my $ref_id (sort keys %l_map) { - eval { Git::SVN->init($l_map{$ref_id}, '', undef, $ref_id) }; - if ($@) { - Git::SVN->init($l_map{$ref_id}, '', $ref_id, $ref_id); - } - $migrated++; - } - $migrated; -} - -sub minimize_connections { - my $r = Git::SVN::read_all_remotes(); - my $new_urls = {}; - my $root_repos = {}; - foreach my $repo_id (keys %$r) { - my $url = $r->{$repo_id}->{url} or next; - my $fetch = $r->{$repo_id}->{fetch} or next; - my $ra = Git::SVN::Ra->new($url); - - # skip existing cases where we already connect to the root - if (($ra->{url} eq $ra->{repos_root}) || - ($ra->{repos_root} eq $repo_id)) { - $root_repos->{$ra->{url}} = $repo_id; - next; - } - - my $root_ra = Git::SVN::Ra->new($ra->{repos_root}); - my $root_path = $ra->{url}; - $root_path =~ s#^\Q$ra->{repos_root}\E(/|$)##; - foreach my $path (keys %$fetch) { - my $ref_id = $fetch->{$path}; - my $gs = Git::SVN->new($ref_id, $repo_id, $path); - - # make sure we can read when connecting to - # a higher level of a repository - my ($last_rev, undef) = $gs->last_rev_commit; - if (!defined $last_rev) { - $last_rev = eval { - $root_ra->get_latest_revnum; - }; - next if $@; - } - my $new = $root_path; - $new .= length $path ? "/$path" : ''; - eval { - $root_ra->get_log([$new], $last_rev, $last_rev, - 0, 0, 1, sub { }); - }; - next if $@; - $new_urls->{$ra->{repos_root}}->{$new} = - { ref_id => $ref_id, - old_repo_id => $repo_id, - old_path => $path }; - } - } - - my @emptied; - foreach my $url (keys %$new_urls) { - # see if we can re-use an existing [svn-remote "repo_id"] - # instead of creating a(n ugly) new section: - my $repo_id = $root_repos->{$url} || $url; - - my $fetch = $new_urls->{$url}; - foreach my $path (keys %$fetch) { - my $x = $fetch->{$path}; - Git::SVN->init($url, $path, $repo_id, $x->{ref_id}); - my $pfx = "svn-remote.$x->{old_repo_id}"; - - my $old_fetch = quotemeta("$x->{old_path}:". - "$x->{ref_id}"); - command_noisy(qw/config --unset/, - "$pfx.fetch", '^'. $old_fetch . '$'); - delete $r->{$x->{old_repo_id}}-> - {fetch}->{$x->{old_path}}; - if (!keys %{$r->{$x->{old_repo_id}}->{fetch}}) { - command_noisy(qw/config --unset/, - "$pfx.url"); - push @emptied, $x->{old_repo_id} - } - } - } - if (@emptied) { - my $file = $ENV{GIT_CONFIG} || "$ENV{GIT_DIR}/config"; - print STDERR <<EOF; -The following [svn-remote] sections in your config file ($file) are empty -and can be safely removed: -EOF - print STDERR "[svn-remote \"$_\"]\n" foreach @emptied; - } -} - -sub migration_check { - migrate_from_v0(); - migrate_from_v1(); - migrate_from_v2(); - minimize_connections() if $_minimize; -} - -package Git::IndexInfo; -use strict; -use warnings; -use Git qw/command_input_pipe command_close_pipe/; - -sub new { - my ($class) = @_; - my ($gui, $ctx) = command_input_pipe(qw/update-index -z --index-info/); - bless { gui => $gui, ctx => $ctx, nr => 0}, $class; -} - -sub remove { - my ($self, $path) = @_; - if (print { $self->{gui} } '0 ', 0 x 40, "\t", $path, "\0") { - return ++$self->{nr}; - } - undef; -} - -sub update { - my ($self, $mode, $hash, $path) = @_; - if (print { $self->{gui} } $mode, ' ', $hash, "\t", $path, "\0") { - return ++$self->{nr}; - } - undef; -} - -sub DESTROY { - my ($self) = @_; - command_close_pipe($self->{gui}, $self->{ctx}); -} - -package Git::SVN::GlobSpec; -use strict; -use warnings; - -sub new { - my ($class, $glob, $pattern_ok) = @_; - my $re = $glob; - $re =~ s!/+$!!g; # no need for trailing slashes - my (@left, @right, @patterns); - my $state = "left"; - my $die_msg = "Only one set of wildcard directories " . - "(e.g. '*' or '*/*/*') is supported: '$glob'\n"; - for my $part (split(m|/|, $glob)) { - if ($part =~ /\*/ && $part ne "*") { - die "Invalid pattern in '$glob': $part\n"; - } elsif ($pattern_ok && $part =~ /[{}]/ && - $part !~ /^\{[^{}]+\}/) { - die "Invalid pattern in '$glob': $part\n"; - } - if ($part eq "*") { - die $die_msg if $state eq "right"; - $state = "pattern"; - push(@patterns, "[^/]*"); - } elsif ($pattern_ok && $part =~ /^\{(.*)\}$/) { - die $die_msg if $state eq "right"; - $state = "pattern"; - my $p = quotemeta($1); - $p =~ s/\\,/|/g; - push(@patterns, "(?:$p)"); - } else { - if ($state eq "left") { - push(@left, $part); - } else { - push(@right, $part); - $state = "right"; - } - } - } - my $depth = @patterns; - if ($depth == 0) { - die "One '*' is needed in glob: '$glob'\n"; - } - my $left = join('/', @left); - my $right = join('/', @right); - $re = join('/', @patterns); - $re = join('\/', - grep(length, quotemeta($left), "($re)", quotemeta($right))); - my $left_re = qr/^\/\Q$left\E(\/|$)/; - bless { left => $left, right => $right, left_regex => $left_re, - regex => qr/$re/, glob => $glob, depth => $depth }, $class; -} - -sub full_path { - my ($self, $path) = @_; - return (length $self->{left} ? "$self->{left}/" : '') . - $path . (length $self->{right} ? "/$self->{right}" : ''); -} - __END__ Data structures: diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 3d6a705388..7f8c1878d4 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -54,6 +54,11 @@ sub evaluate_uri { # to build the base URL ourselves: our $path_info = decode_utf8($ENV{"PATH_INFO"}); if ($path_info) { + # $path_info has already been URL-decoded by the web server, but + # $my_url and $my_uri have not. URL-decode them so we can properly + # strip $path_info. + $my_url = unescape($my_url); + $my_uri = unescape($my_uri); if ($my_url =~ s,\Q$path_info\E$,, && $my_uri =~ s,\Q$path_info\E$,, && defined $ENV{'SCRIPT_NAME'}) { @@ -58,6 +58,14 @@ enum grep_expr_node { GREP_NODE_OR }; +enum grep_pattern_type { + GREP_PATTERN_TYPE_UNSPECIFIED = 0, + GREP_PATTERN_TYPE_BRE, + GREP_PATTERN_TYPE_ERE, + GREP_PATTERN_TYPE_FIXED, + GREP_PATTERN_TYPE_PCRE +}; + struct grep_expr { enum grep_expr_node node; unsigned hit; @@ -103,6 +111,8 @@ struct grep_opt { int max_depth; int funcname; int funcbody; + int extended_regexp_option; + int pattern_type_option; char color_context[COLOR_MAXLEN]; char color_filename[COLOR_MAXLEN]; char color_function[COLOR_MAXLEN]; @@ -44,9 +44,12 @@ static void uniq(struct cmdnames *cmds) if (!cmds->cnt) return; - for (i = j = 1; i < cmds->cnt; i++) - if (strcmp(cmds->names[i]->name, cmds->names[i-1]->name)) + for (i = j = 1; i < cmds->cnt; i++) { + if (!strcmp(cmds->names[i]->name, cmds->names[j-1]->name)) + free(cmds->names[i]); + else cmds->names[j++] = cmds->names[i]; + } cmds->cnt = j; } @@ -61,9 +64,10 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes) cmp = strcmp(cmds->names[ci]->name, excludes->names[ei]->name); if (cmp < 0) cmds->names[cj++] = cmds->names[ci++]; - else if (cmp == 0) - ci++, ei++; - else if (cmp > 0) + else if (cmp == 0) { + ei++; + free(cmds->names[ci++]); + } else if (cmp > 0) ei++; } diff --git a/merge-recursive.c b/merge-recursive.c index 680937c39e..7866ca1026 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -187,7 +187,7 @@ static void output_commit_title(struct merge_options *o, struct commit *commit) else { printf("%s ", find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV)); if (parse_commit(commit) != 0) - printf("(bad commit)\n"); + printf(_("(bad commit)\n")); else { const char *title; int len = find_commit_subject(commit->buffer, &title); @@ -203,7 +203,7 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1, struct cache_entry *ce; ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh); if (!ce) - return error("addinfo_cache failed for path '%s'", path); + return error(_("addinfo_cache failed for path '%s'"), path); return add_cache_entry(ce, options); } @@ -265,7 +265,7 @@ struct tree *write_tree_from_memory(struct merge_options *o) if (!cache_tree_fully_valid(active_cache_tree) && cache_tree_update(active_cache_tree, active_cache, active_nr, 0) < 0) - die("error building trees"); + die(_("error building trees")); result = lookup_tree(active_cache_tree->sha1); @@ -493,8 +493,7 @@ static struct string_list *get_renames(struct merge_options *o, opts.rename_score = o->rename_score; opts.show_rename_progress = o->show_rename_progress; opts.output_format = DIFF_FORMAT_NO_OUTPUT; - if (diff_setup_done(&opts) < 0) - die("diff setup failed"); + diff_setup_done(&opts); diff_tree_sha1(o_tree->object.sha1, tree->object.sha1, "", &opts); diffcore_std(&opts); if (opts.needed_rename_limit > o->needed_rename_limit) @@ -614,23 +613,6 @@ static char *unique_path(struct merge_options *o, const char *path, const char * return newpath; } -static void flush_buffer(int fd, const char *buf, unsigned long size) -{ - while (size > 0) { - long ret = write_in_full(fd, buf, size); - if (ret < 0) { - /* Ignore epipe */ - if (errno == EPIPE) - break; - die_errno("merge-recursive"); - } else if (!ret) { - die("merge-recursive: disk full?"); - } - size -= ret; - buf += ret; - } -} - static int dir_in_way(const char *path, int check_working_copy) { int pos, pathlen = strlen(path); @@ -687,7 +669,7 @@ static int would_lose_untracked(const char *path) static int make_room_for_path(struct merge_options *o, const char *path) { int status, i; - const char *msg = "failed to create path '%s'%s"; + const char *msg = _("failed to create path '%s'%s"); /* Unlink any D/F conflict files that are in the way */ for (i = 0; i < o->df_conflict_file_set.nr; i++) { @@ -698,7 +680,7 @@ static int make_room_for_path(struct merge_options *o, const char *path) path[df_pathlen] == '/' && strncmp(path, df_path, df_pathlen) == 0) { output(o, 3, - "Removing %s to make room for subdirectory\n", + _("Removing %s to make room for subdirectory\n"), df_path); unlink(df_path); unsorted_string_list_delete_item(&o->df_conflict_file_set, @@ -712,7 +694,7 @@ static int make_room_for_path(struct merge_options *o, const char *path) if (status) { if (status == -3) { /* something else exists */ - error(msg, path, ": perhaps a D/F conflict?"); + error(msg, path, _(": perhaps a D/F conflict?")); return -1; } die(msg, path, ""); @@ -723,7 +705,7 @@ static int make_room_for_path(struct merge_options *o, const char *path) * tracking it. */ if (would_lose_untracked(path)) - return error("refusing to lose untracked file at '%s'", + return error(_("refusing to lose untracked file at '%s'"), path); /* Successful unlink is good.. */ @@ -733,7 +715,7 @@ static int make_room_for_path(struct merge_options *o, const char *path) if (errno == ENOENT) return 0; /* .. but not some other error (who really cares what?) */ - return error(msg, path, ": perhaps a D/F conflict?"); + return error(msg, path, _(": perhaps a D/F conflict?")); } static void update_file_flags(struct merge_options *o, @@ -763,9 +745,9 @@ static void update_file_flags(struct merge_options *o, buf = read_sha1_file(sha, &type, &size); if (!buf) - die("cannot read object %s '%s'", sha1_to_hex(sha), path); + die(_("cannot read object %s '%s'"), sha1_to_hex(sha), path); if (type != OBJ_BLOB) - die("blob expected for %s '%s'", sha1_to_hex(sha), path); + die(_("blob expected for %s '%s'"), sha1_to_hex(sha), path); if (S_ISREG(mode)) { struct strbuf strbuf = STRBUF_INIT; if (convert_to_working_tree(path, buf, size, &strbuf)) { @@ -788,18 +770,18 @@ static void update_file_flags(struct merge_options *o, mode = 0666; fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode); if (fd < 0) - die_errno("failed to open '%s'", path); - flush_buffer(fd, buf, size); + die_errno(_("failed to open '%s'"), path); + write_in_full(fd, buf, size); close(fd); } else if (S_ISLNK(mode)) { char *lnk = xmemdupz(buf, size); safe_create_leading_directories_const(path); unlink(path); if (symlink(lnk, path)) - die_errno("failed to symlink '%s'", path); + die_errno(_("failed to symlink '%s'"), path); free(lnk); } else - die("do not know what to do with %06o %s '%s'", + die(_("do not know what to do with %06o %s '%s'"), mode, sha1_to_hex(sha), path); free(buf); } @@ -936,11 +918,11 @@ static struct merge_file_info merge_file_1(struct merge_options *o, branch1, branch2); if ((merge_status < 0) || !result_buf.ptr) - die("Failed to execute internal merge"); + die(_("Failed to execute internal merge")); if (write_sha1_file(result_buf.ptr, result_buf.size, blob_type, result.sha)) - die("Unable to add %s to database", + die(_("Unable to add %s to database"), a->path); free(result_buf.ptr); @@ -956,7 +938,7 @@ static struct merge_file_info merge_file_1(struct merge_options *o, if (!sha_eq(a->sha1, b->sha1)) result.clean = 0; } else { - die("unsupported object type in the tree"); + die(_("unsupported object type in the tree")); } } @@ -1034,22 +1016,32 @@ static void handle_change_delete(struct merge_options *o, remove_file_from_cache(path); update_file(o, 0, o_sha, o_mode, renamed ? renamed : path); } else if (!a_sha) { - output(o, 1, "CONFLICT (%s/delete): %s deleted in %s " - "and %s in %s. Version %s of %s left in tree%s%s.", - change, path, o->branch1, - change_past, o->branch2, o->branch2, path, - NULL == renamed ? "" : " at ", - NULL == renamed ? "" : renamed); - update_file(o, 0, b_sha, b_mode, renamed ? renamed : path); + if (!renamed) { + output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s " + "and %s in %s. Version %s of %s left in tree."), + change, path, o->branch1, change_past, + o->branch2, o->branch2, path); + update_file(o, 0, b_sha, b_mode, path); + } else { + output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s " + "and %s in %s. Version %s of %s left in tree at %s."), + change, path, o->branch1, change_past, + o->branch2, o->branch2, path, renamed); + update_file(o, 0, b_sha, b_mode, renamed); + } } else { - output(o, 1, "CONFLICT (%s/delete): %s deleted in %s " - "and %s in %s. Version %s of %s left in tree%s%s.", - change, path, o->branch2, - change_past, o->branch1, o->branch1, path, - NULL == renamed ? "" : " at ", - NULL == renamed ? "" : renamed); - if (renamed) + if (!renamed) { + output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s " + "and %s in %s. Version %s of %s left in tree."), + change, path, o->branch2, change_past, + o->branch1, o->branch1, path); + } else { + output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s " + "and %s in %s. Version %s of %s left in tree at %s."), + change, path, o->branch2, change_past, + o->branch1, o->branch1, path, renamed); update_file(o, 0, a_sha, a_mode, renamed); + } /* * No need to call update_file() on path when !renamed, since * that would needlessly touch path. We could call @@ -1085,7 +1077,7 @@ static void conflict_rename_delete(struct merge_options *o, orig->sha1, orig->mode, a_sha, a_mode, b_sha, b_mode, - "rename", "renamed"); + _("rename"), _("renamed")); if (o->call_depth) { remove_file_from_cache(dest->path); @@ -1141,7 +1133,7 @@ static void handle_file(struct merge_options *o, } else { if (dir_in_way(rename->path, !o->call_depth)) { dst_name = unique_path(o, rename->path, cur_branch); - output(o, 1, "%s is a directory in %s adding as %s instead", + output(o, 1, _("%s is a directory in %s adding as %s instead"), rename->path, other_branch, dst_name); } } @@ -1163,12 +1155,12 @@ static void conflict_rename_rename_1to2(struct merge_options *o, struct diff_filespec *a = ci->pair1->two; struct diff_filespec *b = ci->pair2->two; - output(o, 1, "CONFLICT (rename/rename): " + output(o, 1, _("CONFLICT (rename/rename): " "Rename \"%s\"->\"%s\" in branch \"%s\" " - "rename \"%s\"->\"%s\" in \"%s\"%s", + "rename \"%s\"->\"%s\" in \"%s\"%s"), one->path, a->path, ci->branch1, one->path, b->path, ci->branch2, - o->call_depth ? " (left unresolved)" : ""); + o->call_depth ? _(" (left unresolved)") : ""); if (o->call_depth) { struct merge_file_info mfi; struct diff_filespec other; @@ -1222,9 +1214,9 @@ static void conflict_rename_rename_2to1(struct merge_options *o, struct merge_file_info mfi_c1; struct merge_file_info mfi_c2; - output(o, 1, "CONFLICT (rename/rename): " + output(o, 1, _("CONFLICT (rename/rename): " "Rename %s->%s in %s. " - "Rename %s->%s in %s", + "Rename %s->%s in %s"), a->path, c1->path, ci->branch1, b->path, c2->path, ci->branch2); @@ -1252,7 +1244,7 @@ static void conflict_rename_rename_2to1(struct merge_options *o, } else { char *new_path1 = unique_path(o, path, ci->branch1); char *new_path2 = unique_path(o, path, ci->branch2); - output(o, 1, "Renaming %s to %s and %s to %s instead", + output(o, 1, _("Renaming %s to %s and %s to %s instead"), a->path, new_path1, b->path, new_path2); remove_file(o, 0, path, 0); update_file(o, 0, mfi_c1.sha, mfi_c1.mode, new_path1); @@ -1451,8 +1443,8 @@ static int process_renames(struct merge_options *o, } else if (!sha_eq(dst_other.sha1, null_sha1)) { clean_merge = 0; try_merge = 1; - output(o, 1, "CONFLICT (rename/add): Rename %s->%s in %s. " - "%s added in %s", + output(o, 1, _("CONFLICT (rename/add): Rename %s->%s in %s. " + "%s added in %s"), ren1_src, ren1_dst, branch1, ren1_dst, branch2); if (o->call_depth) { @@ -1461,12 +1453,12 @@ static int process_renames(struct merge_options *o, ren1->pair->two->sha1, ren1->pair->two->mode, dst_other.sha1, dst_other.mode, branch1, branch2); - output(o, 1, "Adding merged %s", ren1_dst); + output(o, 1, _("Adding merged %s"), ren1_dst); update_file(o, 0, mfi.sha, mfi.mode, ren1_dst); try_merge = 0; } else { char *new_path = unique_path(o, ren1_dst, branch2); - output(o, 1, "Adding as %s instead", new_path); + output(o, 1, _("Adding as %s instead"), new_path); update_file(o, 0, dst_other.sha1, dst_other.mode, new_path); free(new_path); } @@ -1517,10 +1509,10 @@ static int read_sha1_strbuf(const unsigned char *sha1, struct strbuf *dst) unsigned long size; buf = read_sha1_file(sha1, &type, &size); if (!buf) - return error("cannot read object %s", sha1_to_hex(sha1)); + return error(_("cannot read object %s"), sha1_to_hex(sha1)); if (type != OBJ_BLOB) { free(buf); - return error("object %s is not a blob", sha1_to_hex(sha1)); + return error(_("object %s is not a blob"), sha1_to_hex(sha1)); } strbuf_attach(dst, buf, size, size + 1); return 0; @@ -1568,7 +1560,7 @@ static void handle_modify_delete(struct merge_options *o, o_sha, o_mode, a_sha, a_mode, b_sha, b_mode, - "modify", "modified"); + _("modify"), _("modified")); } static int merge_content(struct merge_options *o, @@ -1578,14 +1570,14 @@ static int merge_content(struct merge_options *o, unsigned char *b_sha, int b_mode, struct rename_conflict_info *rename_conflict_info) { - const char *reason = "content"; + const char *reason = _("content"); const char *path1 = NULL, *path2 = NULL; struct merge_file_info mfi; struct diff_filespec one, a, b; unsigned df_conflict_remains = 0; if (!o_sha) { - reason = "add/add"; + reason = _("add/add"); o_sha = (unsigned char *)null_sha1; } one.path = a.path = b.path = (char *)path; @@ -1619,7 +1611,7 @@ static int merge_content(struct merge_options *o, if (mfi.clean && !df_conflict_remains && sha_eq(mfi.sha, a_sha) && mfi.mode == a_mode) { int path_renamed_outside_HEAD; - output(o, 3, "Skipped %s (merged same as existing)", path); + output(o, 3, _("Skipped %s (merged same as existing)"), path); /* * The content merge resulted in the same file contents we * already had. We can return early if those file contents @@ -1633,12 +1625,12 @@ static int merge_content(struct merge_options *o, return mfi.clean; } } else - output(o, 2, "Auto-merging %s", path); + output(o, 2, _("Auto-merging %s"), path); if (!mfi.clean) { if (S_ISGITLINK(mfi.mode)) - reason = "submodule"; - output(o, 1, "CONFLICT (%s): Merge conflict in %s", + reason = _("submodule"); + output(o, 1, _("CONFLICT (%s): Merge conflict in %s"), reason, path); if (rename_conflict_info && !df_conflict_remains) update_stages(path, &one, &a, &b); @@ -1664,7 +1656,7 @@ static int merge_content(struct merge_options *o, } new_path = unique_path(o, path, rename_conflict_info->branch1); - output(o, 1, "Adding as %s instead", new_path); + output(o, 1, _("Adding as %s instead"), new_path); update_file(o, 0, mfi.sha, mfi.mode, new_path); free(new_path); mfi.clean = 0; @@ -1728,7 +1720,7 @@ static int process_entry(struct merge_options *o, /* Deleted in both or deleted in one and * unchanged in the other */ if (a_sha) - output(o, 2, "Removing %s", path); + output(o, 2, _("Removing %s"), path); /* do not touch working file if it did not exist */ remove_file(o, 1, path, !a_sha); } else { @@ -1753,19 +1745,19 @@ static int process_entry(struct merge_options *o, other_branch = o->branch2; mode = a_mode; sha = a_sha; - conf = "file/directory"; + conf = _("file/directory"); } else { add_branch = o->branch2; other_branch = o->branch1; mode = b_mode; sha = b_sha; - conf = "directory/file"; + conf = _("directory/file"); } if (dir_in_way(path, !o->call_depth)) { char *new_path = unique_path(o, path, add_branch); clean_merge = 0; - output(o, 1, "CONFLICT (%s): There is a directory with name %s in %s. " - "Adding %s as %s", + output(o, 1, _("CONFLICT (%s): There is a directory with name %s in %s. " + "Adding %s as %s"), conf, path, other_branch, path, new_path); if (o->call_depth) remove_file_from_cache(path); @@ -1774,7 +1766,7 @@ static int process_entry(struct merge_options *o, remove_file_from_cache(path); free(new_path); } else { - output(o, 2, "Adding %s", path); + output(o, 2, _("Adding %s"), path); /* do not overwrite file if already present */ update_file_flags(o, sha, mode, path, 1, !a_sha); } @@ -1791,7 +1783,7 @@ static int process_entry(struct merge_options *o, */ remove_file(o, 1, path, !a_mode); } else - die("Fatal merge failure, shouldn't happen."); + die(_("Fatal merge failure, shouldn't happen.")); return clean_merge; } @@ -1810,7 +1802,7 @@ int merge_trees(struct merge_options *o, } if (sha_eq(common->object.sha1, merge->object.sha1)) { - output(o, 0, "Already up-to-date!"); + output(o, 0, _("Already up-to-date!")); *result = head; return 1; } @@ -1819,7 +1811,7 @@ int merge_trees(struct merge_options *o, if (code != 0) { if (show(o, 4) || o->call_depth) - die("merging of trees %s and %s failed", + die(_("merging of trees %s and %s failed"), sha1_to_hex(head->object.sha1), sha1_to_hex(merge->object.sha1)); else @@ -1849,7 +1841,7 @@ int merge_trees(struct merge_options *o, for (i = 0; i < entries->nr; i++) { struct stage_data *e = entries->items[i].util; if (!e->processed) - die("Unprocessed path??? %s", + die(_("Unprocessed path??? %s"), entries->items[i].string); } @@ -1894,7 +1886,7 @@ int merge_recursive(struct merge_options *o, int clean; if (show(o, 4)) { - output(o, 4, "Merging:"); + output(o, 4, _("Merging:")); output_commit_title(o, h1); output_commit_title(o, h2); } @@ -1905,7 +1897,10 @@ int merge_recursive(struct merge_options *o, } if (show(o, 5)) { - output(o, 5, "found %u common ancestor(s):", commit_list_count(ca)); + unsigned cnt = commit_list_count(ca); + + output(o, 5, Q_("found %u common ancestor:", + "found %u common ancestors:", cnt), cnt); for (iter = ca; iter; iter = iter->next) output_commit_title(o, iter->item); } @@ -1941,7 +1936,7 @@ int merge_recursive(struct merge_options *o, o->call_depth--; if (!merged_common_ancestors) - die("merge returned no commit"); + die(_("merge returned no commit")); } discard_cache(); @@ -1998,7 +1993,7 @@ int merge_recursive_generic(struct merge_options *o, for (i = 0; i < num_base_list; ++i) { struct commit *base; if (!(base = get_ref(base_list[i], sha1_to_hex(base_list[i])))) - return error("Could not parse object '%s'", + return error(_("Could not parse object '%s'"), sha1_to_hex(base_list[i])); commit_list_insert(base, &ca); } @@ -2010,7 +2005,7 @@ int merge_recursive_generic(struct merge_options *o, if (active_cache_changed && (write_cache(index_fd, active_cache, active_nr) || commit_locked_index(lock))) - return error("Unable to write index."); + return error(_("Unable to write index.")); return clean ? 0 : 1; } diff --git a/mergetools/codecompare b/mergetools/codecompare new file mode 100644 index 0000000000..3f0486bc80 --- /dev/null +++ b/mergetools/codecompare @@ -0,0 +1,25 @@ +diff_cmd () { + "$merge_tool_path" "$LOCAL" "$REMOTE" +} + +merge_cmd () { + touch "$BACKUP" + if $base_present + then + "$merge_tool_path" -MF="$LOCAL" -TF="$REMOTE" -BF="$BASE" \ + -RF="$MERGED" + else + "$merge_tool_path" -MF="$LOCAL" -TF="$REMOTE" \ + -RF="$MERGED" + fi + check_unchanged +} + +translate_merge_tool_path() { + if merge_mode + then + echo CodeMerge + else + echo CodeCompare + fi +} diff --git a/notes-merge.c b/notes-merge.c index 29c6411fc6..0f67bd3f96 100644 --- a/notes-merge.c +++ b/notes-merge.c @@ -126,8 +126,7 @@ static struct notes_merge_pair *diff_tree_remote(struct notes_merge_options *o, diff_setup(&opt); DIFF_OPT_SET(&opt, RECURSIVE); opt.output_format = DIFF_FORMAT_NO_OUTPUT; - if (diff_setup_done(&opt) < 0) - die("diff_setup_done failed"); + diff_setup_done(&opt); diff_tree_sha1(base, remote, "", &opt); diffcore_std(&opt); @@ -190,8 +189,7 @@ static void diff_tree_local(struct notes_merge_options *o, diff_setup(&opt); DIFF_OPT_SET(&opt, RECURSIVE); opt.output_format = DIFF_FORMAT_NO_OUTPUT; - if (diff_setup_done(&opt) < 0) - die("diff_setup_done failed"); + diff_setup_done(&opt); diff_tree_sha1(base, local, "", &opt); diffcore_std(&opt); diff --git a/patch-ids.c b/patch-ids.c index 5717257051..bc8a28fdd7 100644 --- a/patch-ids.c +++ b/patch-ids.c @@ -39,8 +39,7 @@ int init_patch_ids(struct patch_ids *ids) memset(ids, 0, sizeof(*ids)); diff_setup(&ids->diffopts); DIFF_OPT_SET(&ids->diffopts, RECURSIVE); - if (diff_setup_done(&ids->diffopts) < 0) - return error("diff_setup_done failed"); + diff_setup_done(&ids->diffopts); return 0; } diff --git a/perl/.gitignore b/perl/.gitignore index d5c6e22d0f..0f1fc27f86 100644 --- a/perl/.gitignore +++ b/perl/.gitignore @@ -5,3 +5,4 @@ MYMETA.yml blib blibdirs pm_to_blib +PM.stamp diff --git a/perl/Git/IndexInfo.pm b/perl/Git/IndexInfo.pm new file mode 100644 index 0000000000..a43108c985 --- /dev/null +++ b/perl/Git/IndexInfo.pm @@ -0,0 +1,33 @@ +package Git::IndexInfo; +use strict; +use warnings; +use Git qw/command_input_pipe command_close_pipe/; + +sub new { + my ($class) = @_; + my ($gui, $ctx) = command_input_pipe(qw/update-index -z --index-info/); + bless { gui => $gui, ctx => $ctx, nr => 0}, $class; +} + +sub remove { + my ($self, $path) = @_; + if (print { $self->{gui} } '0 ', 0 x 40, "\t", $path, "\0") { + return ++$self->{nr}; + } + undef; +} + +sub update { + my ($self, $mode, $hash, $path) = @_; + if (print { $self->{gui} } $mode, ' ', $hash, "\t", $path, "\0") { + return ++$self->{nr}; + } + undef; +} + +sub DESTROY { + my ($self) = @_; + command_close_pipe($self->{gui}, $self->{ctx}); +} + +1; diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm new file mode 100644 index 0000000000..acb25394f4 --- /dev/null +++ b/perl/Git/SVN.pm @@ -0,0 +1,2397 @@ +package Git::SVN; +use strict; +use warnings; +use Fcntl qw/:DEFAULT :seek/; +use constant rev_map_fmt => 'NH40'; +use vars qw/$_no_metadata + $_repack $_repack_flags $_use_svm_props $_head + $_use_svnsync_props $no_reuse_existing + $_use_log_author $_add_author_from $_localtime/; +use Carp qw/croak/; +use File::Path qw/mkpath/; +use File::Copy qw/copy/; +use IPC::Open3; +use Time::Local; +use Memoize; # core since 5.8.0, Jul 2002 +use Memoize::Storable; +use POSIX qw(:signal_h); + +use Git qw( + command + command_oneline + command_noisy + command_output_pipe + command_close_pipe +); +use Git::SVN::Utils qw( + fatal + can_compress + join_paths + canonicalize_path + canonicalize_url + add_path_to_url +); + +my $can_use_yaml; +BEGIN { + $can_use_yaml = eval { require Git::SVN::Memoize::YAML; 1}; +} + +our $_follow_parent = 1; +our $_minimize_url = 'unset'; +our $default_repo_id = 'svn'; +our $default_ref_id = $ENV{GIT_SVN_ID} || 'git-svn'; + +my ($_gc_nr, $_gc_period); + +# properties that we do not log: +my %SKIP_PROP; +BEGIN { + %SKIP_PROP = map { $_ => 1 } qw/svn:wc:ra_dav:version-url + svn:special svn:executable + svn:entry:committed-rev + svn:entry:last-author + svn:entry:uuid + svn:entry:committed-date/; + + # some options are read globally, but can be overridden locally + # per [svn-remote "..."] section. Command-line options will *NOT* + # override options set in an [svn-remote "..."] section + no strict 'refs'; + for my $option (qw/follow_parent no_metadata use_svm_props + use_svnsync_props/) { + my $key = $option; + $key =~ tr/_//d; + my $prop = "-$option"; + *$option = sub { + my ($self) = @_; + return $self->{$prop} if exists $self->{$prop}; + my $k = "svn-remote.$self->{repo_id}.$key"; + eval { command_oneline(qw/config --get/, $k) }; + if ($@) { + $self->{$prop} = ${"Git::SVN::_$option"}; + } else { + my $v = command_oneline(qw/config --bool/,$k); + $self->{$prop} = $v eq 'false' ? 0 : 1; + } + return $self->{$prop}; + } + } +} + + +my (%LOCKFILES, %INDEX_FILES); +END { + unlink keys %LOCKFILES if %LOCKFILES; + unlink keys %INDEX_FILES if %INDEX_FILES; +} + +sub resolve_local_globs { + my ($url, $fetch, $glob_spec) = @_; + return unless defined $glob_spec; + my $ref = $glob_spec->{ref}; + my $path = $glob_spec->{path}; + foreach (command(qw#for-each-ref --format=%(refname) refs/#)) { + next unless m#^$ref->{regex}$#; + my $p = $1; + my $pathname = desanitize_refname($path->full_path($p)); + my $refname = desanitize_refname($ref->full_path($p)); + if (my $existing = $fetch->{$pathname}) { + if ($existing ne $refname) { + die "Refspec conflict:\n", + "existing: $existing\n", + " globbed: $refname\n"; + } + my $u = (::cmt_metadata("$refname"))[0]; + $u =~ s!^\Q$url\E(/|$)!! or die + "$refname: '$url' not found in '$u'\n"; + if ($pathname ne $u) { + warn "W: Refspec glob conflict ", + "(ref: $refname):\n", + "expected path: $pathname\n", + " real path: $u\n", + "Continuing ahead with $u\n"; + next; + } + } else { + $fetch->{$pathname} = $refname; + } + } +} + +sub parse_revision_argument { + my ($base, $head) = @_; + if (!defined $::_revision || $::_revision eq 'BASE:HEAD') { + return ($base, $head); + } + return ($1, $2) if ($::_revision =~ /^(\d+):(\d+)$/); + return ($::_revision, $::_revision) if ($::_revision =~ /^\d+$/); + return ($head, $head) if ($::_revision eq 'HEAD'); + return ($base, $1) if ($::_revision =~ /^BASE:(\d+)$/); + return ($1, $head) if ($::_revision =~ /^(\d+):HEAD$/); + die "revision argument: $::_revision not understood by git-svn\n"; +} + +sub fetch_all { + my ($repo_id, $remotes) = @_; + if (ref $repo_id) { + my $gs = $repo_id; + $repo_id = undef; + $repo_id = $gs->{repo_id}; + } + $remotes ||= read_all_remotes(); + my $remote = $remotes->{$repo_id} or + die "[svn-remote \"$repo_id\"] unknown\n"; + my $fetch = $remote->{fetch}; + my $url = $remote->{url} or die "svn-remote.$repo_id.url not defined\n"; + my (@gs, @globs); + my $ra = Git::SVN::Ra->new($url); + my $uuid = $ra->get_uuid; + my $head = $ra->get_latest_revnum; + + # ignore errors, $head revision may not even exist anymore + eval { $ra->get_log("", $head, 0, 1, 0, 1, sub { $head = $_[1] }) }; + warn "W: $@\n" if $@; + + my $base = defined $fetch ? $head : 0; + + # read the max revs for wildcard expansion (branches/*, tags/*) + foreach my $t (qw/branches tags/) { + defined $remote->{$t} or next; + push @globs, @{$remote->{$t}}; + + my $max_rev = eval { tmp_config(qw/--int --get/, + "svn-remote.$repo_id.${t}-maxRev") }; + if (defined $max_rev && ($max_rev < $base)) { + $base = $max_rev; + } elsif (!defined $max_rev) { + $base = 0; + } + } + + if ($fetch) { + foreach my $p (sort keys %$fetch) { + my $gs = Git::SVN->new($fetch->{$p}, $repo_id, $p); + my $lr = $gs->rev_map_max; + if (defined $lr) { + $base = $lr if ($lr < $base); + } + push @gs, $gs; + } + } + + ($base, $head) = parse_revision_argument($base, $head); + $ra->gs_fetch_loop_common($base, $head, \@gs, \@globs); +} + +sub read_all_remotes { + my $r = {}; + my $use_svm_props = eval { command_oneline(qw/config --bool + svn.useSvmProps/) }; + $use_svm_props = $use_svm_props eq 'true' if $use_svm_props; + my $svn_refspec = qr{\s*(.*?)\s*:\s*(.+?)\s*}; + foreach (grep { s/^svn-remote\.// } command(qw/config -l/)) { + if (m!^(.+)\.fetch=$svn_refspec$!) { + my ($remote, $local_ref, $remote_ref) = ($1, $2, $3); + die("svn-remote.$remote: remote ref '$remote_ref' " + . "must start with 'refs/'\n") + unless $remote_ref =~ m{^refs/}; + $local_ref = uri_decode($local_ref); + $r->{$remote}->{fetch}->{$local_ref} = $remote_ref; + $r->{$remote}->{svm} = {} if $use_svm_props; + } elsif (m!^(.+)\.usesvmprops=\s*(.*)\s*$!) { + $r->{$1}->{svm} = {}; + } elsif (m!^(.+)\.url=\s*(.*)\s*$!) { + $r->{$1}->{url} = canonicalize_url($2); + } elsif (m!^(.+)\.pushurl=\s*(.*)\s*$!) { + $r->{$1}->{pushurl} = canonicalize_url($2); + } elsif (m!^(.+)\.ignore-refs=\s*(.*)\s*$!) { + $r->{$1}->{ignore_refs_regex} = $2; + } elsif (m!^(.+)\.(branches|tags)=$svn_refspec$!) { + my ($remote, $t, $local_ref, $remote_ref) = + ($1, $2, $3, $4); + die("svn-remote.$remote: remote ref '$remote_ref' ($t) " + . "must start with 'refs/'\n") + unless $remote_ref =~ m{^refs/}; + $local_ref = uri_decode($local_ref); + + require Git::SVN::GlobSpec; + my $rs = { + t => $t, + remote => $remote, + path => Git::SVN::GlobSpec->new($local_ref, 1), + ref => Git::SVN::GlobSpec->new($remote_ref, 0) }; + if (length($rs->{ref}->{right}) != 0) { + die "The '*' glob character must be the last ", + "character of '$remote_ref'\n"; + } + push @{ $r->{$remote}->{$t} }, $rs; + } + } + + map { + if (defined $r->{$_}->{svm}) { + my $svm; + eval { + my $section = "svn-remote.$_"; + $svm = { + source => tmp_config('--get', + "$section.svm-source"), + replace => tmp_config('--get', + "$section.svm-replace"), + } + }; + $r->{$_}->{svm} = $svm; + } + } keys %$r; + + foreach my $remote (keys %$r) { + foreach ( grep { defined $_ } + map { $r->{$remote}->{$_} } qw(branches tags) ) { + foreach my $rs ( @$_ ) { + $rs->{ignore_refs_regex} = + $r->{$remote}->{ignore_refs_regex}; + } + } + } + + $r; +} + +sub init_vars { + $_gc_nr = $_gc_period = 1000; + if (defined $_repack || defined $_repack_flags) { + warn "Repack options are obsolete; they have no effect.\n"; + } +} + +sub verify_remotes_sanity { + return unless -d $ENV{GIT_DIR}; + my %seen; + foreach (command(qw/config -l/)) { + if (m!^svn-remote\.(?:.+)\.fetch=.*:refs/remotes/(\S+)\s*$!) { + if ($seen{$1}) { + die "Remote ref refs/remote/$1 is tracked by", + "\n \"$_\"\nand\n \"$seen{$1}\"\n", + "Please resolve this ambiguity in ", + "your git configuration file before ", + "continuing\n"; + } + $seen{$1} = $_; + } + } +} + +sub find_existing_remote { + my ($url, $remotes) = @_; + return undef if $no_reuse_existing; + my $existing; + foreach my $repo_id (keys %$remotes) { + my $u = $remotes->{$repo_id}->{url} or next; + next if $u ne $url; + $existing = $repo_id; + last; + } + $existing; +} + +sub init_remote_config { + my ($self, $url, $no_write) = @_; + $url = canonicalize_url($url); + my $r = read_all_remotes(); + my $existing = find_existing_remote($url, $r); + if ($existing) { + unless ($no_write) { + print STDERR "Using existing ", + "[svn-remote \"$existing\"]\n"; + } + $self->{repo_id} = $existing; + } elsif ($_minimize_url) { + my $min_url = Git::SVN::Ra->new($url)->minimize_url; + $existing = find_existing_remote($min_url, $r); + if ($existing) { + unless ($no_write) { + print STDERR "Using existing ", + "[svn-remote \"$existing\"]\n"; + } + $self->{repo_id} = $existing; + } + if ($min_url ne $url) { + unless ($no_write) { + print STDERR "Using higher level of URL: ", + "$url => $min_url\n"; + } + my $old_path = $self->path; + $url =~ s!^\Q$min_url\E(/|$)!!; + $url = join_paths($url, $old_path); + $self->path($url); + $url = $min_url; + } + } + my $orig_url; + if (!$existing) { + # verify that we aren't overwriting anything: + $orig_url = eval { + command_oneline('config', '--get', + "svn-remote.$self->{repo_id}.url") + }; + if ($orig_url && ($orig_url ne $url)) { + die "svn-remote.$self->{repo_id}.url already set: ", + "$orig_url\nwanted to set to: $url\n"; + } + } + my ($xrepo_id, $xpath) = find_ref($self->refname); + if (!$no_write && defined $xpath) { + die "svn-remote.$xrepo_id.fetch already set to track ", + "$xpath:", $self->refname, "\n"; + } + unless ($no_write) { + command_noisy('config', + "svn-remote.$self->{repo_id}.url", $url); + my $path = $self->path; + $path =~ s{^/}{}; + $path =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg; + $self->path($path); + command_noisy('config', '--add', + "svn-remote.$self->{repo_id}.fetch", + $self->path.":".$self->refname); + } + $self->url($url); +} + +sub find_by_url { # repos_root and, path are optional + my ($class, $full_url, $repos_root, $path) = @_; + + $full_url = canonicalize_url($full_url); + + return undef unless defined $full_url; + remove_username($full_url); + remove_username($repos_root) if defined $repos_root; + my $remotes = read_all_remotes(); + if (defined $full_url && defined $repos_root && !defined $path) { + $path = $full_url; + $path =~ s#^\Q$repos_root\E(?:/|$)##; + } + foreach my $repo_id (keys %$remotes) { + my $u = $remotes->{$repo_id}->{url} or next; + remove_username($u); + next if defined $repos_root && $repos_root ne $u; + + my $fetch = $remotes->{$repo_id}->{fetch} || {}; + foreach my $t (qw/branches tags/) { + foreach my $globspec (@{$remotes->{$repo_id}->{$t}}) { + resolve_local_globs($u, $fetch, $globspec); + } + } + my $p = $path; + my $rwr = rewrite_root({repo_id => $repo_id}); + my $svm = $remotes->{$repo_id}->{svm} + if defined $remotes->{$repo_id}->{svm}; + unless (defined $p) { + $p = $full_url; + my $z = $u; + my $prefix = ''; + if ($rwr) { + $z = $rwr; + remove_username($z); + } elsif (defined $svm) { + $z = $svm->{source}; + $prefix = $svm->{replace}; + $prefix =~ s#^\Q$u\E(?:/|$)##; + $prefix =~ s#/$##; + } + $p =~ s#^\Q$z\E(?:/|$)#$prefix# or next; + } + + # remote fetch paths are not URI escaped. Decode ours + # so they match + $p = uri_decode($p); + + foreach my $f (keys %$fetch) { + next if $f ne $p; + return Git::SVN->new($fetch->{$f}, $repo_id, $f); + } + } + undef; +} + +sub init { + my ($class, $url, $path, $repo_id, $ref_id, $no_write) = @_; + my $self = _new($class, $repo_id, $ref_id, $path); + if (defined $url) { + $self->init_remote_config($url, $no_write); + } + $self; +} + +sub find_ref { + my ($ref_id) = @_; + foreach (command(qw/config -l/)) { + next unless m!^svn-remote\.(.+)\.fetch= + \s*(.*?)\s*:\s*(.+?)\s*$!x; + my ($repo_id, $path, $ref) = ($1, $2, $3); + if ($ref eq $ref_id) { + $path = '' if ($path =~ m#^\./?#); + return ($repo_id, $path); + } + } + (undef, undef, undef); +} + +sub new { + my ($class, $ref_id, $repo_id, $path) = @_; + if (defined $ref_id && !defined $repo_id && !defined $path) { + ($repo_id, $path) = find_ref($ref_id); + if (!defined $repo_id) { + die "Could not find a \"svn-remote.*.fetch\" key ", + "in the repository configuration matching: ", + "$ref_id\n"; + } + } + my $self = _new($class, $repo_id, $ref_id, $path); + if (!defined $self->path || !length $self->path) { + my $fetch = command_oneline('config', '--get', + "svn-remote.$repo_id.fetch", + ":$ref_id\$") or + die "Failed to read \"svn-remote.$repo_id.fetch\" ", + "\":$ref_id\$\" in config\n"; + my($path) = split(/\s*:\s*/, $fetch); + $self->path($path); + } + { + my $path = $self->path; + $path =~ s{\A/}{}; + $path =~ s{/\z}{}; + $self->path($path); + } + my $url = command_oneline('config', '--get', + "svn-remote.$repo_id.url") or + die "Failed to read \"svn-remote.$repo_id.url\" in config\n"; + $self->url($url); + $self->{pushurl} = eval { command_oneline('config', '--get', + "svn-remote.$repo_id.pushurl") }; + $self->rebuild; + $self; +} + +sub refname { + my ($refname) = $_[0]->{ref_id} ; + + # It cannot end with a slash /, we'll throw up on this because + # SVN can't have directories with a slash in their name, either: + if ($refname =~ m{/$}) { + die "ref: '$refname' ends with a trailing slash, this is ", + "not permitted by git nor Subversion\n"; + } + + # It cannot have ASCII control character space, tilde ~, caret ^, + # colon :, question-mark ?, asterisk *, space, or open bracket [ + # anywhere. + # + # Additionally, % must be escaped because it is used for escaping + # and we want our escaped refname to be reversible + $refname =~ s{([ \%~\^:\?\*\[\t])}{uc sprintf('%%%02x',ord($1))}eg; + + # no slash-separated component can begin with a dot . + # /.* becomes /%2E* + $refname =~ s{/\.}{/%2E}g; + + # It cannot have two consecutive dots .. anywhere + # .. becomes %2E%2E + $refname =~ s{\.\.}{%2E%2E}g; + + # trailing dots and .lock are not allowed + # .$ becomes %2E and .lock becomes %2Elock + $refname =~ s{\.(?=$|lock$)}{%2E}; + + # the sequence @{ is used to access the reflog + # @{ becomes %40{ + $refname =~ s{\@\{}{%40\{}g; + + return $refname; +} + +sub desanitize_refname { + my ($refname) = @_; + $refname =~ s{%(?:([0-9A-F]{2}))}{chr hex($1)}eg; + return $refname; +} + +sub svm_uuid { + my ($self) = @_; + return $self->{svm}->{uuid} if $self->svm; + $self->ra; + unless ($self->{svm}) { + die "SVM UUID not cached, and reading remotely failed\n"; + } + $self->{svm}->{uuid}; +} + +sub svm { + my ($self) = @_; + return $self->{svm} if $self->{svm}; + my $svm; + # see if we have it in our config, first: + eval { + my $section = "svn-remote.$self->{repo_id}"; + $svm = { + source => tmp_config('--get', "$section.svm-source"), + uuid => tmp_config('--get', "$section.svm-uuid"), + replace => tmp_config('--get', "$section.svm-replace"), + } + }; + if ($svm && $svm->{source} && $svm->{uuid} && $svm->{replace}) { + $self->{svm} = $svm; + } + $self->{svm}; +} + +sub _set_svm_vars { + my ($self, $ra) = @_; + return $ra if $self->svm; + + my @err = ( "useSvmProps set, but failed to read SVM properties\n", + "(svm:source, svm:uuid) ", + "from the following URLs:\n" ); + sub read_svm_props { + my ($self, $ra, $path, $r) = @_; + my $props = ($ra->get_dir($path, $r))[2]; + my $src = $props->{'svm:source'}; + my $uuid = $props->{'svm:uuid'}; + return undef if (!$src || !$uuid); + + chomp($src, $uuid); + + $uuid =~ m{^[0-9a-f\-]{30,}$}i + or die "doesn't look right - svm:uuid is '$uuid'\n"; + + # the '!' is used to mark the repos_root!/relative/path + $src =~ s{/?!/?}{/}; + $src =~ s{/+$}{}; # no trailing slashes please + # username is of no interest + $src =~ s{(^[a-z\+]*://)[^/@]*@}{$1}; + + my $replace = add_path_to_url($ra->url, $path); + + my $section = "svn-remote.$self->{repo_id}"; + tmp_config("$section.svm-source", $src); + tmp_config("$section.svm-replace", $replace); + tmp_config("$section.svm-uuid", $uuid); + $self->{svm} = { + source => $src, + uuid => $uuid, + replace => $replace + }; + } + + my $r = $ra->get_latest_revnum; + my $path = $self->path; + my %tried; + while (length $path) { + my $try = add_path_to_url($self->url, $path); + unless ($tried{$try}) { + return $ra if $self->read_svm_props($ra, $path, $r); + $tried{$try} = 1; + } + $path =~ s#/?[^/]+$##; + } + die "Path: '$path' should be ''\n" if $path ne ''; + return $ra if $self->read_svm_props($ra, $path, $r); + $tried{ add_path_to_url($self->url, $path) } = 1; + + if ($ra->{repos_root} eq $self->url) { + die @err, (map { " $_\n" } keys %tried), "\n"; + } + + # nope, make sure we're connected to the repository root: + my $ok; + my @tried_b; + $path = $ra->{svn_path}; + $ra = Git::SVN::Ra->new($ra->{repos_root}); + while (length $path) { + my $try = add_path_to_url($ra->url, $path); + unless ($tried{$try}) { + $ok = $self->read_svm_props($ra, $path, $r); + last if $ok; + $tried{$try} = 1; + } + $path =~ s#/?[^/]+$##; + } + die "Path: '$path' should be ''\n" if $path ne ''; + $ok ||= $self->read_svm_props($ra, $path, $r); + $tried{ add_path_to_url($ra->url, $path) } = 1; + if (!$ok) { + die @err, (map { " $_\n" } keys %tried), "\n"; + } + Git::SVN::Ra->new($self->url); +} + +sub svnsync { + my ($self) = @_; + return $self->{svnsync} if $self->{svnsync}; + + if ($self->no_metadata) { + die "Can't have both 'noMetadata' and ", + "'useSvnsyncProps' options set!\n"; + } + if ($self->rewrite_root) { + die "Can't have both 'useSvnsyncProps' and 'rewriteRoot' ", + "options set!\n"; + } + if ($self->rewrite_uuid) { + die "Can't have both 'useSvnsyncProps' and 'rewriteUUID' ", + "options set!\n"; + } + + my $svnsync; + # see if we have it in our config, first: + eval { + my $section = "svn-remote.$self->{repo_id}"; + + my $url = tmp_config('--get', "$section.svnsync-url"); + ($url) = ($url =~ m{^([a-z\+]+://\S+)$}) or + die "doesn't look right - svn:sync-from-url is '$url'\n"; + + my $uuid = tmp_config('--get', "$section.svnsync-uuid"); + ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or + die "doesn't look right - svn:sync-from-uuid is '$uuid'\n"; + + $svnsync = { url => $url, uuid => $uuid } + }; + if ($svnsync && $svnsync->{url} && $svnsync->{uuid}) { + return $self->{svnsync} = $svnsync; + } + + my $err = "useSvnsyncProps set, but failed to read " . + "svnsync property: svn:sync-from-"; + my $rp = $self->ra->rev_proplist(0); + + my $url = $rp->{'svn:sync-from-url'} or die $err . "url\n"; + ($url) = ($url =~ m{^([a-z\+]+://\S+)$}) or + die "doesn't look right - svn:sync-from-url is '$url'\n"; + + my $uuid = $rp->{'svn:sync-from-uuid'} or die $err . "uuid\n"; + ($uuid) = ($uuid =~ m{^([0-9a-f\-]{30,})$}i) or + die "doesn't look right - svn:sync-from-uuid is '$uuid'\n"; + + my $section = "svn-remote.$self->{repo_id}"; + tmp_config('--add', "$section.svnsync-uuid", $uuid); + tmp_config('--add', "$section.svnsync-url", $url); + return $self->{svnsync} = { url => $url, uuid => $uuid }; +} + +# this allows us to memoize our SVN::Ra UUID locally and avoid a +# remote lookup (useful for 'git svn log'). +sub ra_uuid { + my ($self) = @_; + unless ($self->{ra_uuid}) { + my $key = "svn-remote.$self->{repo_id}.uuid"; + my $uuid = eval { tmp_config('--get', $key) }; + if (!$@ && $uuid && $uuid =~ /^([a-f\d\-]{30,})$/i) { + $self->{ra_uuid} = $uuid; + } else { + die "ra_uuid called without URL\n" unless $self->url; + $self->{ra_uuid} = $self->ra->get_uuid; + tmp_config('--add', $key, $self->{ra_uuid}); + } + } + $self->{ra_uuid}; +} + +sub _set_repos_root { + my ($self, $repos_root) = @_; + my $k = "svn-remote.$self->{repo_id}.reposRoot"; + $repos_root ||= $self->ra->{repos_root}; + tmp_config($k, $repos_root); + $repos_root; +} + +sub repos_root { + my ($self) = @_; + my $k = "svn-remote.$self->{repo_id}.reposRoot"; + eval { tmp_config('--get', $k) } || $self->_set_repos_root; +} + +sub ra { + my ($self) = shift; + my $ra = Git::SVN::Ra->new($self->url); + $self->_set_repos_root($ra->{repos_root}); + if ($self->use_svm_props && !$self->{svm}) { + if ($self->no_metadata) { + die "Can't have both 'noMetadata' and ", + "'useSvmProps' options set!\n"; + } elsif ($self->use_svnsync_props) { + die "Can't have both 'useSvnsyncProps' and ", + "'useSvmProps' options set!\n"; + } + $ra = $self->_set_svm_vars($ra); + $self->{-want_revprops} = 1; + } + $ra; +} + +# prop_walk(PATH, REV, SUB) +# ------------------------- +# Recursively traverse PATH at revision REV and invoke SUB for each +# directory that contains a SVN property. SUB will be invoked as +# follows: &SUB(gs, path, props); where `gs' is this instance of +# Git::SVN, `path' the path to the directory where the properties +# `props' were found. The `path' will be relative to point of checkout, +# that is, if url://repo/trunk is the current Git branch, and that +# directory contains a sub-directory `d', SUB will be invoked with `/d/' +# as `path' (note the trailing `/'). +sub prop_walk { + my ($self, $path, $rev, $sub) = @_; + + $path =~ s#^/##; + my ($dirent, undef, $props) = $self->ra->get_dir($path, $rev); + $path =~ s#^/*#/#g; + my $p = $path; + # Strip the irrelevant part of the path. + $p =~ s#^/+\Q@{[$self->path]}\E(/|$)#/#; + # Ensure the path is terminated by a `/'. + $p =~ s#/*$#/#; + + # The properties contain all the internal SVN stuff nobody + # (usually) cares about. + my $interesting_props = 0; + foreach (keys %{$props}) { + # If it doesn't start with `svn:', it must be a + # user-defined property. + ++$interesting_props and next if $_ !~ /^svn:/; + # FIXME: Fragile, if SVN adds new public properties, + # this needs to be updated. + ++$interesting_props if /^svn:(?:ignore|keywords|executable + |eol-style|mime-type + |externals|needs-lock)$/x; + } + &$sub($self, $p, $props) if $interesting_props; + + foreach (sort keys %$dirent) { + next if $dirent->{$_}->{kind} != $SVN::Node::dir; + $self->prop_walk($self->path . $p . $_, $rev, $sub); + } +} + +sub last_rev { ($_[0]->last_rev_commit)[0] } +sub last_commit { ($_[0]->last_rev_commit)[1] } + +# returns the newest SVN revision number and newest commit SHA1 +sub last_rev_commit { + my ($self) = @_; + if (defined $self->{last_rev} && defined $self->{last_commit}) { + return ($self->{last_rev}, $self->{last_commit}); + } + my $c = ::verify_ref($self->refname.'^0'); + if ($c && !$self->use_svm_props && !$self->no_metadata) { + my $rev = (::cmt_metadata($c))[1]; + if (defined $rev) { + ($self->{last_rev}, $self->{last_commit}) = ($rev, $c); + return ($rev, $c); + } + } + my $map_path = $self->map_path; + unless (-e $map_path) { + ($self->{last_rev}, $self->{last_commit}) = (undef, undef); + return (undef, undef); + } + my ($rev, $commit) = $self->rev_map_max(1); + ($self->{last_rev}, $self->{last_commit}) = ($rev, $commit); + return ($rev, $commit); +} + +sub get_fetch_range { + my ($self, $min, $max) = @_; + $max ||= $self->ra->get_latest_revnum; + $min ||= $self->rev_map_max; + (++$min, $max); +} + +sub tmp_config { + my (@args) = @_; + my $old_def_config = "$ENV{GIT_DIR}/svn/config"; + my $config = "$ENV{GIT_DIR}/svn/.metadata"; + if (! -f $config && -f $old_def_config) { + rename $old_def_config, $config or + die "Failed rename $old_def_config => $config: $!\n"; + } + my $old_config = $ENV{GIT_CONFIG}; + $ENV{GIT_CONFIG} = $config; + $@ = undef; + my @ret = eval { + unless (-f $config) { + mkfile($config); + open my $fh, '>', $config or + die "Can't open $config: $!\n"; + print $fh "; This file is used internally by ", + "git-svn\n" or die + "Couldn't write to $config: $!\n"; + print $fh "; You should not have to edit it\n" or + die "Couldn't write to $config: $!\n"; + close $fh or die "Couldn't close $config: $!\n"; + } + command('config', @args); + }; + my $err = $@; + if (defined $old_config) { + $ENV{GIT_CONFIG} = $old_config; + } else { + delete $ENV{GIT_CONFIG}; + } + die $err if $err; + wantarray ? @ret : $ret[0]; +} + +sub tmp_index_do { + my ($self, $sub) = @_; + my $old_index = $ENV{GIT_INDEX_FILE}; + $ENV{GIT_INDEX_FILE} = $self->{index}; + $@ = undef; + my @ret = eval { + my ($dir, $base) = ($self->{index} =~ m#^(.*?)/?([^/]+)$#); + mkpath([$dir]) unless -d $dir; + &$sub; + }; + my $err = $@; + if (defined $old_index) { + $ENV{GIT_INDEX_FILE} = $old_index; + } else { + delete $ENV{GIT_INDEX_FILE}; + } + die $err if $err; + wantarray ? @ret : $ret[0]; +} + +sub assert_index_clean { + my ($self, $treeish) = @_; + + $self->tmp_index_do(sub { + command_noisy('read-tree', $treeish) unless -e $self->{index}; + my $x = command_oneline('write-tree'); + my ($y) = (command(qw/cat-file commit/, $treeish) =~ + /^tree ($::sha1)/mo); + return if $y eq $x; + + warn "Index mismatch: $y != $x\nrereading $treeish\n"; + unlink $self->{index} or die "unlink $self->{index}: $!\n"; + command_noisy('read-tree', $treeish); + $x = command_oneline('write-tree'); + if ($y ne $x) { + fatal "trees ($treeish) $y != $x\n", + "Something is seriously wrong..."; + } + }); +} + +sub get_commit_parents { + my ($self, $log_entry) = @_; + my (%seen, @ret, @tmp); + # legacy support for 'set-tree'; this is only used by set_tree_cb: + if (my $ip = $self->{inject_parents}) { + if (my $commit = delete $ip->{$log_entry->{revision}}) { + push @tmp, $commit; + } + } + if (my $cur = ::verify_ref($self->refname.'^0')) { + push @tmp, $cur; + } + if (my $ipd = $self->{inject_parents_dcommit}) { + if (my $commit = delete $ipd->{$log_entry->{revision}}) { + push @tmp, @$commit; + } + } + push @tmp, $_ foreach (@{$log_entry->{parents}}, @tmp); + while (my $p = shift @tmp) { + next if $seen{$p}; + $seen{$p} = 1; + push @ret, $p; + } + @ret; +} + +sub rewrite_root { + my ($self) = @_; + return $self->{-rewrite_root} if exists $self->{-rewrite_root}; + my $k = "svn-remote.$self->{repo_id}.rewriteRoot"; + my $rwr = eval { command_oneline(qw/config --get/, $k) }; + if ($rwr) { + $rwr =~ s#/+$##; + if ($rwr !~ m#^[a-z\+]+://#) { + die "$rwr is not a valid URL (key: $k)\n"; + } + } + $self->{-rewrite_root} = $rwr; +} + +sub rewrite_uuid { + my ($self) = @_; + return $self->{-rewrite_uuid} if exists $self->{-rewrite_uuid}; + my $k = "svn-remote.$self->{repo_id}.rewriteUUID"; + my $rwid = eval { command_oneline(qw/config --get/, $k) }; + if ($rwid) { + $rwid =~ s#/+$##; + if ($rwid !~ m#^[a-f0-9]{8}-(?:[a-f0-9]{4}-){3}[a-f0-9]{12}$#) { + die "$rwid is not a valid UUID (key: $k)\n"; + } + } + $self->{-rewrite_uuid} = $rwid; +} + +sub metadata_url { + my ($self) = @_; + my $url = $self->rewrite_root || $self->url; + return canonicalize_url( add_path_to_url( $url, $self->path ) ); +} + +sub full_url { + my ($self) = @_; + return canonicalize_url( add_path_to_url( $self->url, $self->path ) ); +} + +sub full_pushurl { + my ($self) = @_; + if ($self->{pushurl}) { + return canonicalize_url( add_path_to_url( $self->{pushurl}, $self->path ) ); + } else { + return $self->full_url; + } +} + +sub set_commit_header_env { + my ($log_entry) = @_; + my %env; + foreach my $ned (qw/NAME EMAIL DATE/) { + foreach my $ac (qw/AUTHOR COMMITTER/) { + $env{"GIT_${ac}_${ned}"} = $ENV{"GIT_${ac}_${ned}"}; + } + } + + $ENV{GIT_AUTHOR_NAME} = $log_entry->{name}; + $ENV{GIT_AUTHOR_EMAIL} = $log_entry->{email}; + $ENV{GIT_AUTHOR_DATE} = $ENV{GIT_COMMITTER_DATE} = $log_entry->{date}; + + $ENV{GIT_COMMITTER_NAME} = (defined $log_entry->{commit_name}) + ? $log_entry->{commit_name} + : $log_entry->{name}; + $ENV{GIT_COMMITTER_EMAIL} = (defined $log_entry->{commit_email}) + ? $log_entry->{commit_email} + : $log_entry->{email}; + \%env; +} + +sub restore_commit_header_env { + my ($env) = @_; + foreach my $ned (qw/NAME EMAIL DATE/) { + foreach my $ac (qw/AUTHOR COMMITTER/) { + my $k = "GIT_${ac}_${ned}"; + if (defined $env->{$k}) { + $ENV{$k} = $env->{$k}; + } else { + delete $ENV{$k}; + } + } + } +} + +sub gc { + command_noisy('gc', '--auto'); +}; + +sub do_git_commit { + my ($self, $log_entry) = @_; + my $lr = $self->last_rev; + if (defined $lr && $lr >= $log_entry->{revision}) { + die "Last fetched revision of ", $self->refname, + " was r$lr, but we are about to fetch: ", + "r$log_entry->{revision}!\n"; + } + if (my $c = $self->rev_map_get($log_entry->{revision})) { + croak "$log_entry->{revision} = $c already exists! ", + "Why are we refetching it?\n"; + } + my $old_env = set_commit_header_env($log_entry); + my $tree = $log_entry->{tree}; + if (!defined $tree) { + $tree = $self->tmp_index_do(sub { + command_oneline('write-tree') }); + } + die "Tree is not a valid sha1: $tree\n" if $tree !~ /^$::sha1$/o; + + my @exec = ('git', 'commit-tree', $tree); + foreach ($self->get_commit_parents($log_entry)) { + push @exec, '-p', $_; + } + defined(my $pid = open3(my $msg_fh, my $out_fh, '>&STDERR', @exec)) + or croak $!; + binmode $msg_fh; + + # we always get UTF-8 from SVN, but we may want our commits in + # a different encoding. + if (my $enc = Git::config('i18n.commitencoding')) { + require Encode; + Encode::from_to($log_entry->{log}, 'UTF-8', $enc); + } + print $msg_fh $log_entry->{log} or croak $!; + restore_commit_header_env($old_env); + unless ($self->no_metadata) { + print $msg_fh "\ngit-svn-id: $log_entry->{metadata}\n" + or croak $!; + } + $msg_fh->flush == 0 or croak $!; + close $msg_fh or croak $!; + chomp(my $commit = do { local $/; <$out_fh> }); + close $out_fh or croak $!; + waitpid $pid, 0; + croak $? if $?; + if ($commit !~ /^$::sha1$/o) { + die "Failed to commit, invalid sha1: $commit\n"; + } + + $self->rev_map_set($log_entry->{revision}, $commit, 1); + + $self->{last_rev} = $log_entry->{revision}; + $self->{last_commit} = $commit; + print "r$log_entry->{revision}" unless $::_q > 1; + if (defined $log_entry->{svm_revision}) { + print " (\@$log_entry->{svm_revision})" unless $::_q > 1; + $self->rev_map_set($log_entry->{svm_revision}, $commit, + 0, $self->svm_uuid); + } + print " = $commit ($self->{ref_id})\n" unless $::_q > 1; + if (--$_gc_nr == 0) { + $_gc_nr = $_gc_period; + gc(); + } + return $commit; +} + +sub match_paths { + my ($self, $paths, $r) = @_; + return 1 if $self->path eq ''; + if (my $path = $paths->{"/".$self->path}) { + return ($path->{action} eq 'D') ? 0 : 1; + } + $self->{path_regex} ||= qr{^/\Q@{[$self->path]}\E/}; + if (grep /$self->{path_regex}/, keys %$paths) { + return 1; + } + my $c = ''; + foreach (split m#/#, $self->path) { + $c .= "/$_"; + next unless ($paths->{$c} && + ($paths->{$c}->{action} =~ /^[AR]$/)); + if ($self->ra->check_path($self->path, $r) == + $SVN::Node::dir) { + return 1; + } + } + return 0; +} + +sub find_parent_branch { + my ($self, $paths, $rev) = @_; + return undef unless $self->follow_parent; + unless (defined $paths) { + my $err_handler = $SVN::Error::handler; + $SVN::Error::handler = \&Git::SVN::Ra::skip_unknown_revs; + $self->ra->get_log([$self->path], $rev, $rev, 0, 1, 1, + sub { $paths = $_[0] }); + $SVN::Error::handler = $err_handler; + } + return undef unless defined $paths; + + # look for a parent from another branch: + my @b_path_components = split m#/#, $self->path; + my @a_path_components; + my $i; + while (@b_path_components) { + $i = $paths->{'/'.join('/', @b_path_components)}; + last if $i && defined $i->{copyfrom_path}; + unshift(@a_path_components, pop(@b_path_components)); + } + return undef unless defined $i && defined $i->{copyfrom_path}; + my $branch_from = $i->{copyfrom_path}; + if (@a_path_components) { + print STDERR "branch_from: $branch_from => "; + $branch_from .= '/'.join('/', @a_path_components); + print STDERR $branch_from, "\n"; + } + my $r = $i->{copyfrom_rev}; + my $repos_root = $self->ra->{repos_root}; + my $url = $self->ra->url; + my $new_url = canonicalize_url( add_path_to_url( $url, $branch_from ) ); + print STDERR "Found possible branch point: ", + "$new_url => ", $self->full_url, ", $r\n" + unless $::_q > 1; + $branch_from =~ s#^/##; + my $gs = $self->other_gs($new_url, $url, + $branch_from, $r, $self->{ref_id}); + my ($r0, $parent) = $gs->find_rev_before($r, 1); + { + my ($base, $head); + if (!defined $r0 || !defined $parent) { + ($base, $head) = parse_revision_argument(0, $r); + } else { + if ($r0 < $r) { + $gs->ra->get_log([$gs->path], $r0 + 1, $r, 1, + 0, 1, sub { $base = $_[1] - 1 }); + } + } + if (defined $base && $base <= $r) { + $gs->fetch($base, $r); + } + ($r0, $parent) = $gs->find_rev_before($r, 1); + } + if (defined $r0 && defined $parent) { + print STDERR "Found branch parent: ($self->{ref_id}) $parent\n" + unless $::_q > 1; + my $ed; + if ($self->ra->can_do_switch) { + $self->assert_index_clean($parent); + print STDERR "Following parent with do_switch\n" + unless $::_q > 1; + # do_switch works with svn/trunk >= r22312, but that + # is not included with SVN 1.4.3 (the latest version + # at the moment), so we can't rely on it + $self->{last_rev} = $r0; + $self->{last_commit} = $parent; + $ed = Git::SVN::Fetcher->new($self, $gs->path); + $gs->ra->gs_do_switch($r0, $rev, $gs, + $self->full_url, $ed) + or die "SVN connection failed somewhere...\n"; + } elsif ($self->ra->trees_match($new_url, $r0, + $self->full_url, $rev)) { + print STDERR "Trees match:\n", + " $new_url\@$r0\n", + " ${\$self->full_url}\@$rev\n", + "Following parent with no changes\n" + unless $::_q > 1; + $self->tmp_index_do(sub { + command_noisy('read-tree', $parent); + }); + $self->{last_commit} = $parent; + } else { + print STDERR "Following parent with do_update\n" + unless $::_q > 1; + $ed = Git::SVN::Fetcher->new($self); + $self->ra->gs_do_update($rev, $rev, $self, $ed) + or die "SVN connection failed somewhere...\n"; + } + print STDERR "Successfully followed parent\n" unless $::_q > 1; + return $self->make_log_entry($rev, [$parent], $ed); + } + return undef; +} + +sub do_fetch { + my ($self, $paths, $rev) = @_; + my $ed; + my ($last_rev, @parents); + if (my $lc = $self->last_commit) { + # we can have a branch that was deleted, then re-added + # under the same name but copied from another path, in + # which case we'll have multiple parents (we don't + # want to break the original ref, nor lose copypath info): + if (my $log_entry = $self->find_parent_branch($paths, $rev)) { + push @{$log_entry->{parents}}, $lc; + return $log_entry; + } + $ed = Git::SVN::Fetcher->new($self); + $last_rev = $self->{last_rev}; + $ed->{c} = $lc; + @parents = ($lc); + } else { + $last_rev = $rev; + if (my $log_entry = $self->find_parent_branch($paths, $rev)) { + return $log_entry; + } + $ed = Git::SVN::Fetcher->new($self); + } + unless ($self->ra->gs_do_update($last_rev, $rev, $self, $ed)) { + die "SVN connection failed somewhere...\n"; + } + $self->make_log_entry($rev, \@parents, $ed); +} + +sub mkemptydirs { + my ($self, $r) = @_; + + sub scan { + my ($r, $empty_dirs, $line) = @_; + if (defined $r && $line =~ /^r(\d+)$/) { + return 0 if $1 > $r; + } elsif ($line =~ /^ \+empty_dir: (.+)$/) { + $empty_dirs->{$1} = 1; + } elsif ($line =~ /^ \-empty_dir: (.+)$/) { + my @d = grep {m[^\Q$1\E(/|$)]} (keys %$empty_dirs); + delete @$empty_dirs{@d}; + } + 1; # continue + }; + + my %empty_dirs = (); + my $gz_file = "$self->{dir}/unhandled.log.gz"; + if (-f $gz_file) { + if (!can_compress()) { + warn "Compress::Zlib could not be found; ", + "empty directories in $gz_file will not be read\n"; + } else { + my $gz = Compress::Zlib::gzopen($gz_file, "rb") or + die "Unable to open $gz_file: $!\n"; + my $line; + while ($gz->gzreadline($line) > 0) { + scan($r, \%empty_dirs, $line) or last; + } + $gz->gzclose; + } + } + + if (open my $fh, '<', "$self->{dir}/unhandled.log") { + binmode $fh or croak "binmode: $!"; + while (<$fh>) { + scan($r, \%empty_dirs, $_) or last; + } + close $fh; + } + + my $strip = qr/\A\Q@{[$self->path]}\E(?:\/|$)/; + foreach my $d (sort keys %empty_dirs) { + $d = uri_decode($d); + $d =~ s/$strip//; + next unless length($d); + next if -d $d; + if (-e $d) { + warn "$d exists but is not a directory\n"; + } else { + print "creating empty directory: $d\n"; + mkpath([$d]); + } + } +} + +sub get_untracked { + my ($self, $ed) = @_; + my @out; + my $h = $ed->{empty}; + foreach (sort keys %$h) { + my $act = $h->{$_} ? '+empty_dir' : '-empty_dir'; + push @out, " $act: " . uri_encode($_); + warn "W: $act: $_\n"; + } + foreach my $t (qw/dir_prop file_prop/) { + $h = $ed->{$t} or next; + foreach my $path (sort keys %$h) { + my $ppath = $path eq '' ? '.' : $path; + foreach my $prop (sort keys %{$h->{$path}}) { + next if $SKIP_PROP{$prop}; + my $v = $h->{$path}->{$prop}; + my $t_ppath_prop = "$t: " . + uri_encode($ppath) . ' ' . + uri_encode($prop); + if (defined $v) { + push @out, " +$t_ppath_prop " . + uri_encode($v); + } else { + push @out, " -$t_ppath_prop"; + } + } + } + } + foreach my $t (qw/absent_file absent_directory/) { + $h = $ed->{$t} or next; + foreach my $parent (sort keys %$h) { + foreach my $path (sort @{$h->{$parent}}) { + push @out, " $t: " . + uri_encode("$parent/$path"); + warn "W: $t: $parent/$path ", + "Insufficient permissions?\n"; + } + } + } + \@out; +} + +sub get_tz { + # some systmes don't handle or mishandle %z, so be creative. + my $t = shift || time; + my $gm = timelocal(gmtime($t)); + my $sign = qw( + + - )[ $t <=> $gm ]; + return sprintf("%s%02d%02d", $sign, (gmtime(abs($t - $gm)))[2,1]); +} + +# parse_svn_date(DATE) +# -------------------- +# Given a date (in UTC) from Subversion, return a string in the format +# "<TZ Offset> <local date/time>" that Git will use. +# +# By default the parsed date will be in UTC; if $Git::SVN::_localtime +# is true we'll convert it to the local timezone instead. +sub parse_svn_date { + my $date = shift || return '+0000 1970-01-01 00:00:00'; + my ($Y,$m,$d,$H,$M,$S) = ($date =~ /^(\d{4})\-(\d\d)\-(\d\d)T + (\d\d)\:(\d\d)\:(\d\d)\.\d*Z$/x) or + croak "Unable to parse date: $date\n"; + my $parsed_date; # Set next. + + if ($Git::SVN::_localtime) { + # Translate the Subversion datetime to an epoch time. + # Begin by switching ourselves to $date's timezone, UTC. + my $old_env_TZ = $ENV{TZ}; + $ENV{TZ} = 'UTC'; + + my $epoch_in_UTC = + POSIX::strftime('%s', $S, $M, $H, $d, $m - 1, $Y - 1900); + + # Determine our local timezone (including DST) at the + # time of $epoch_in_UTC. $Git::SVN::Log::TZ stored the + # value of TZ, if any, at the time we were run. + if (defined $Git::SVN::Log::TZ) { + $ENV{TZ} = $Git::SVN::Log::TZ; + } else { + delete $ENV{TZ}; + } + + my $our_TZ = get_tz(); + + # This converts $epoch_in_UTC into our local timezone. + my ($sec, $min, $hour, $mday, $mon, $year, + $wday, $yday, $isdst) = localtime($epoch_in_UTC); + + $parsed_date = sprintf('%s %04d-%02d-%02d %02d:%02d:%02d', + $our_TZ, $year + 1900, $mon + 1, + $mday, $hour, $min, $sec); + + # Reset us to the timezone in effect when we entered + # this routine. + if (defined $old_env_TZ) { + $ENV{TZ} = $old_env_TZ; + } else { + delete $ENV{TZ}; + } + } else { + $parsed_date = "+0000 $Y-$m-$d $H:$M:$S"; + } + + return $parsed_date; +} + +sub other_gs { + my ($self, $new_url, $url, + $branch_from, $r, $old_ref_id) = @_; + my $gs = Git::SVN->find_by_url($new_url, $url, $branch_from); + unless ($gs) { + my $ref_id = $old_ref_id; + $ref_id =~ s/\@\d+-*$//; + $ref_id .= "\@$r"; + # just grow a tail if we're not unique enough :x + $ref_id .= '-' while find_ref($ref_id); + my ($u, $p, $repo_id) = ($new_url, '', $ref_id); + if ($u =~ s#^\Q$url\E(/|$)##) { + $p = $u; + $u = $url; + $repo_id = $self->{repo_id}; + } + while (1) { + # It is possible to tag two different subdirectories at + # the same revision. If the url for an existing ref + # does not match, we must either find a ref with a + # matching url or create a new ref by growing a tail. + $gs = Git::SVN->init($u, $p, $repo_id, $ref_id, 1); + my (undef, $max_commit) = $gs->rev_map_max(1); + last if (!$max_commit); + my ($url) = ::cmt_metadata($max_commit); + last if ($url eq $gs->metadata_url); + $ref_id .= '-'; + } + print STDERR "Initializing parent: $ref_id\n" unless $::_q > 1; + } + $gs +} + +sub call_authors_prog { + my ($orig_author) = @_; + $orig_author = command_oneline('rev-parse', '--sq-quote', $orig_author); + my $author = `$::_authors_prog $orig_author`; + if ($? != 0) { + die "$::_authors_prog failed with exit code $?\n" + } + if ($author =~ /^\s*(.+?)\s*<(.*)>\s*$/) { + my ($name, $email) = ($1, $2); + $email = undef if length $2 == 0; + return [$name, $email]; + } else { + die "Author: $orig_author: $::_authors_prog returned " + . "invalid author format: $author\n"; + } +} + +sub check_author { + my ($author) = @_; + if (!defined $author || length $author == 0) { + $author = '(no author)'; + } + if (!defined $::users{$author}) { + if (defined $::_authors_prog) { + $::users{$author} = call_authors_prog($author); + } elsif (defined $::_authors) { + die "Author: $author not defined in $::_authors file\n"; + } + } + $author; +} + +sub find_extra_svk_parents { + my ($self, $ed, $tickets, $parents) = @_; + # aha! svk:merge property changed... + my @tickets = split "\n", $tickets; + my @known_parents; + for my $ticket ( @tickets ) { + my ($uuid, $path, $rev) = split /:/, $ticket; + if ( $uuid eq $self->ra_uuid ) { + my $repos_root = $self->url; + my $branch_from = $path; + $branch_from =~ s{^/}{}; + my $gs = $self->other_gs(add_path_to_url( $repos_root, $branch_from ), + $repos_root, + $branch_from, + $rev, + $self->{ref_id}); + if ( my $commit = $gs->rev_map_get($rev, $uuid) ) { + # wahey! we found it, but it might be + # an old one (!) + push @known_parents, [ $rev, $commit ]; + } + } + } + # Ordering matters; highest-numbered commit merge tickets + # first, as they may account for later merge ticket additions + # or changes. + @known_parents = map {$_->[1]} sort {$b->[0] <=> $a->[0]} @known_parents; + for my $parent ( @known_parents ) { + my @cmd = ('rev-list', $parent, map { "^$_" } @$parents ); + my ($msg_fh, $ctx) = command_output_pipe(@cmd); + my $new; + while ( <$msg_fh> ) { + $new=1;last; + } + command_close_pipe($msg_fh, $ctx); + if ( $new ) { + print STDERR + "Found merge parent (svk:merge ticket): $parent\n"; + push @$parents, $parent; + } + } +} + +sub lookup_svn_merge { + my $uuid = shift; + my $url = shift; + my $merge = shift; + + my ($source, $revs) = split ":", $merge; + my $path = $source; + $path =~ s{^/}{}; + my $gs = Git::SVN->find_by_url($url.$source, $url, $path); + if ( !$gs ) { + warn "Couldn't find revmap for $url$source\n"; + return; + } + my @ranges = split ",", $revs; + my ($tip, $tip_commit); + my @merged_commit_ranges; + # find the tip + for my $range ( @ranges ) { + my ($bottom, $top) = split "-", $range; + $top ||= $bottom; + my $bottom_commit = $gs->find_rev_after( $bottom, 1, $top ); + my $top_commit = $gs->find_rev_before( $top, 1, $bottom ); + + unless ($top_commit and $bottom_commit) { + warn "W:unknown path/rev in svn:mergeinfo " + ."dirprop: $source:$range\n"; + next; + } + + if (scalar(command('rev-parse', "$bottom_commit^@"))) { + push @merged_commit_ranges, + "$bottom_commit^..$top_commit"; + } else { + push @merged_commit_ranges, "$top_commit"; + } + + if ( !defined $tip or $top > $tip ) { + $tip = $top; + $tip_commit = $top_commit; + } + } + return ($tip_commit, @merged_commit_ranges); +} + +sub _rev_list { + my ($msg_fh, $ctx) = command_output_pipe( + "rev-list", @_, + ); + my @rv; + while ( <$msg_fh> ) { + chomp; + push @rv, $_; + } + command_close_pipe($msg_fh, $ctx); + @rv; +} + +sub check_cherry_pick { + my $base = shift; + my $tip = shift; + my $parents = shift; + my @ranges = @_; + my %commits = map { $_ => 1 } + _rev_list("--no-merges", $tip, "--not", $base, @$parents, "--"); + for my $range ( @ranges ) { + delete @commits{_rev_list($range, "--")}; + } + for my $commit (keys %commits) { + if (has_no_changes($commit)) { + delete $commits{$commit}; + } + } + return (keys %commits); +} + +sub has_no_changes { + my $commit = shift; + + my @revs = split / /, command_oneline( + qw(rev-list --parents -1 -m), $commit); + + # Commits with no parents, e.g. the start of a partial branch, + # have changes by definition. + return 1 if (@revs < 2); + + # Commits with multiple parents, e.g a merge, have no changes + # by definition. + return 0 if (@revs > 2); + + return (command_oneline("rev-parse", "$commit^{tree}") eq + command_oneline("rev-parse", "$commit~1^{tree}")); +} + +sub tie_for_persistent_memoization { + my $hash = shift; + my $path = shift; + + if ($can_use_yaml) { + tie %$hash => 'Git::SVN::Memoize::YAML', "$path.yaml"; + } else { + tie %$hash => 'Memoize::Storable', "$path.db", 'nstore'; + } +} + +# The GIT_DIR environment variable is not always set until after the command +# line arguments are processed, so we can't memoize in a BEGIN block. +{ + my $memoized = 0; + + sub memoize_svn_mergeinfo_functions { + return if $memoized; + $memoized = 1; + + my $cache_path = "$ENV{GIT_DIR}/svn/.caches/"; + mkpath([$cache_path]) unless -d $cache_path; + + my %lookup_svn_merge_cache; + my %check_cherry_pick_cache; + my %has_no_changes_cache; + + tie_for_persistent_memoization(\%lookup_svn_merge_cache, + "$cache_path/lookup_svn_merge"); + memoize 'lookup_svn_merge', + SCALAR_CACHE => 'FAULT', + LIST_CACHE => ['HASH' => \%lookup_svn_merge_cache], + ; + + tie_for_persistent_memoization(\%check_cherry_pick_cache, + "$cache_path/check_cherry_pick"); + memoize 'check_cherry_pick', + SCALAR_CACHE => 'FAULT', + LIST_CACHE => ['HASH' => \%check_cherry_pick_cache], + ; + + tie_for_persistent_memoization(\%has_no_changes_cache, + "$cache_path/has_no_changes"); + memoize 'has_no_changes', + SCALAR_CACHE => ['HASH' => \%has_no_changes_cache], + LIST_CACHE => 'FAULT', + ; + } + + sub unmemoize_svn_mergeinfo_functions { + return if not $memoized; + $memoized = 0; + + Memoize::unmemoize 'lookup_svn_merge'; + Memoize::unmemoize 'check_cherry_pick'; + Memoize::unmemoize 'has_no_changes'; + } + + sub clear_memoized_mergeinfo_caches { + die "Only call this method in non-memoized context" if ($memoized); + + my $cache_path = "$ENV{GIT_DIR}/svn/.caches/"; + return unless -d $cache_path; + + for my $cache_file (("$cache_path/lookup_svn_merge", + "$cache_path/check_cherry_pick", + "$cache_path/has_no_changes")) { + for my $suffix (qw(yaml db)) { + my $file = "$cache_file.$suffix"; + next unless -e $file; + unlink($file) or die "unlink($file) failed: $!\n"; + } + } + } + + + Memoize::memoize 'Git::SVN::repos_root'; +} + +END { + # Force cache writeout explicitly instead of waiting for + # global destruction to avoid segfault in Storable: + # http://rt.cpan.org/Public/Bug/Display.html?id=36087 + unmemoize_svn_mergeinfo_functions(); +} + +sub parents_exclude { + my $parents = shift; + my @commits = @_; + return unless @commits; + + my @excluded; + my $excluded; + do { + my @cmd = ('rev-list', "-1", @commits, "--not", @$parents ); + $excluded = command_oneline(@cmd); + if ( $excluded ) { + my @new; + my $found; + for my $commit ( @commits ) { + if ( $commit eq $excluded ) { + push @excluded, $commit; + $found++; + last; + } + else { + push @new, $commit; + } + } + die "saw commit '$excluded' in rev-list output, " + ."but we didn't ask for that commit (wanted: @commits --not @$parents)" + unless $found; + @commits = @new; + } + } + while ($excluded and @commits); + + return @excluded; +} + + +# note: this function should only be called if the various dirprops +# have actually changed +sub find_extra_svn_parents { + my ($self, $ed, $mergeinfo, $parents) = @_; + # aha! svk:merge property changed... + + memoize_svn_mergeinfo_functions(); + + # We first search for merged tips which are not in our + # history. Then, we figure out which git revisions are in + # that tip, but not this revision. If all of those revisions + # are now marked as merge, we can add the tip as a parent. + my @merges = split "\n", $mergeinfo; + my @merge_tips; + my $url = $self->url; + my $uuid = $self->ra_uuid; + my %ranges; + for my $merge ( @merges ) { + my ($tip_commit, @ranges) = + lookup_svn_merge( $uuid, $url, $merge ); + unless (!$tip_commit or + grep { $_ eq $tip_commit } @$parents ) { + push @merge_tips, $tip_commit; + $ranges{$tip_commit} = \@ranges; + } else { + push @merge_tips, undef; + } + } + + my %excluded = map { $_ => 1 } + parents_exclude($parents, grep { defined } @merge_tips); + + # check merge tips for new parents + my @new_parents; + for my $merge_tip ( @merge_tips ) { + my $spec = shift @merges; + next unless $merge_tip and $excluded{$merge_tip}; + + my $ranges = $ranges{$merge_tip}; + + # check out 'new' tips + my $merge_base; + eval { + $merge_base = command_oneline( + "merge-base", + @$parents, $merge_tip, + ); + }; + if ($@) { + die "An error occurred during merge-base" + unless $@->isa("Git::Error::Command"); + + warn "W: Cannot find common ancestor between ". + "@$parents and $merge_tip. Ignoring merge info.\n"; + next; + } + + # double check that there are no missing non-merge commits + my (@incomplete) = check_cherry_pick( + $merge_base, $merge_tip, + $parents, + @$ranges, + ); + + if ( @incomplete ) { + warn "W:svn cherry-pick ignored ($spec) - missing " + .@incomplete." commit(s) (eg $incomplete[0])\n"; + } else { + warn + "Found merge parent (svn:mergeinfo prop): ", + $merge_tip, "\n"; + push @new_parents, $merge_tip; + } + } + + # cater for merges which merge commits from multiple branches + if ( @new_parents > 1 ) { + for ( my $i = 0; $i <= $#new_parents; $i++ ) { + for ( my $j = 0; $j <= $#new_parents; $j++ ) { + next if $i == $j; + next unless $new_parents[$i]; + next unless $new_parents[$j]; + my $revs = command_oneline( + "rev-list", "-1", + "$new_parents[$i]..$new_parents[$j]", + ); + if ( !$revs ) { + undef($new_parents[$j]); + } + } + } + } + push @$parents, grep { defined } @new_parents; +} + +sub make_log_entry { + my ($self, $rev, $parents, $ed) = @_; + my $untracked = $self->get_untracked($ed); + + my @parents = @$parents; + my $ps = $ed->{path_strip} || ""; + for my $path ( grep { m/$ps/ } %{$ed->{dir_prop}} ) { + my $props = $ed->{dir_prop}{$path}; + if ( $props->{"svk:merge"} ) { + $self->find_extra_svk_parents + ($ed, $props->{"svk:merge"}, \@parents); + } + if ( $props->{"svn:mergeinfo"} ) { + $self->find_extra_svn_parents + ($ed, + $props->{"svn:mergeinfo"}, + \@parents); + } + } + + open my $un, '>>', "$self->{dir}/unhandled.log" or croak $!; + print $un "r$rev\n" or croak $!; + print $un $_, "\n" foreach @$untracked; + my %log_entry = ( parents => \@parents, revision => $rev, + log => ''); + + my $headrev; + my $logged = delete $self->{logged_rev_props}; + if (!$logged || $self->{-want_revprops}) { + my $rp = $self->ra->rev_proplist($rev); + foreach (sort keys %$rp) { + my $v = $rp->{$_}; + if (/^svn:(author|date|log)$/) { + $log_entry{$1} = $v; + } elsif ($_ eq 'svm:headrev') { + $headrev = $v; + } else { + print $un " rev_prop: ", uri_encode($_), ' ', + uri_encode($v), "\n"; + } + } + } else { + map { $log_entry{$_} = $logged->{$_} } keys %$logged; + } + close $un or croak $!; + + $log_entry{date} = parse_svn_date($log_entry{date}); + $log_entry{log} .= "\n"; + my $author = $log_entry{author} = check_author($log_entry{author}); + my ($name, $email) = defined $::users{$author} ? @{$::users{$author}} + : ($author, undef); + + my ($commit_name, $commit_email) = ($name, $email); + if ($_use_log_author) { + my $name_field; + if ($log_entry{log} =~ /From:\s+(.*\S)\s*\n/i) { + $name_field = $1; + } elsif ($log_entry{log} =~ /Signed-off-by:\s+(.*\S)\s*\n/i) { + $name_field = $1; + } + if (!defined $name_field) { + if (!defined $email) { + $email = $name; + } + } elsif ($name_field =~ /(.*?)\s+<(.*)>/) { + ($name, $email) = ($1, $2); + } elsif ($name_field =~ /(.*)@/) { + ($name, $email) = ($1, $name_field); + } else { + ($name, $email) = ($name_field, $name_field); + } + } + if (defined $headrev && $self->use_svm_props) { + if ($self->rewrite_root) { + die "Can't have both 'useSvmProps' and 'rewriteRoot' ", + "options set!\n"; + } + if ($self->rewrite_uuid) { + die "Can't have both 'useSvmProps' and 'rewriteUUID' ", + "options set!\n"; + } + my ($uuid, $r) = $headrev =~ m{^([a-f\d\-]{30,}):(\d+)$}i; + # we don't want "SVM: initializing mirror for junk" ... + return undef if $r == 0; + my $svm = $self->svm; + if ($uuid ne $svm->{uuid}) { + die "UUID mismatch on SVM path:\n", + "expected: $svm->{uuid}\n", + " got: $uuid\n"; + } + my $full_url = $self->full_url; + $full_url =~ s#^\Q$svm->{replace}\E(/|$)#$svm->{source}$1# or + die "Failed to replace '$svm->{replace}' with ", + "'$svm->{source}' in $full_url\n"; + # throw away username for storing in records + remove_username($full_url); + $log_entry{metadata} = "$full_url\@$r $uuid"; + $log_entry{svm_revision} = $r; + $email ||= "$author\@$uuid"; + $commit_email ||= "$author\@$uuid"; + } elsif ($self->use_svnsync_props) { + my $full_url = canonicalize_url( + add_path_to_url( $self->svnsync->{url}, $self->path ) + ); + remove_username($full_url); + my $uuid = $self->svnsync->{uuid}; + $log_entry{metadata} = "$full_url\@$rev $uuid"; + $email ||= "$author\@$uuid"; + $commit_email ||= "$author\@$uuid"; + } else { + my $url = $self->metadata_url; + remove_username($url); + my $uuid = $self->rewrite_uuid || $self->ra->get_uuid; + $log_entry{metadata} = "$url\@$rev " . $uuid; + $email ||= "$author\@" . $uuid; + $commit_email ||= "$author\@" . $uuid; + } + $log_entry{name} = $name; + $log_entry{email} = $email; + $log_entry{commit_name} = $commit_name; + $log_entry{commit_email} = $commit_email; + \%log_entry; +} + +sub fetch { + my ($self, $min_rev, $max_rev, @parents) = @_; + my ($last_rev, $last_commit) = $self->last_rev_commit; + my ($base, $head) = $self->get_fetch_range($min_rev, $max_rev); + $self->ra->gs_fetch_loop_common($base, $head, [$self]); +} + +sub set_tree_cb { + my ($self, $log_entry, $tree, $rev, $date, $author) = @_; + $self->{inject_parents} = { $rev => $tree }; + $self->fetch(undef, undef); +} + +sub set_tree { + my ($self, $tree) = (shift, shift); + my $log_entry = ::get_commit_entry($tree); + unless ($self->{last_rev}) { + fatal("Must have an existing revision to commit"); + } + my %ed_opts = ( r => $self->{last_rev}, + log => $log_entry->{log}, + ra => $self->ra, + tree_a => $self->{last_commit}, + tree_b => $tree, + editor_cb => sub { + $self->set_tree_cb($log_entry, $tree, @_) }, + svn_path => $self->path ); + if (!Git::SVN::Editor->new(\%ed_opts)->apply_diff) { + print "No changes\nr$self->{last_rev} = $tree\n"; + } +} + +sub rebuild_from_rev_db { + my ($self, $path) = @_; + my $r = -1; + open my $fh, '<', $path or croak "open: $!"; + binmode $fh or croak "binmode: $!"; + while (<$fh>) { + length($_) == 41 or croak "inconsistent size in ($_) != 41"; + chomp($_); + ++$r; + next if $_ eq ('0' x 40); + $self->rev_map_set($r, $_); + print "r$r = $_\n"; + } + close $fh or croak "close: $!"; + unlink $path or croak "unlink: $!"; +} + +sub rebuild { + my ($self) = @_; + my $map_path = $self->map_path; + my $partial = (-e $map_path && ! -z $map_path); + return unless ::verify_ref($self->refname.'^0'); + if (!$partial && ($self->use_svm_props || $self->no_metadata)) { + my $rev_db = $self->rev_db_path; + $self->rebuild_from_rev_db($rev_db); + if ($self->use_svm_props) { + my $svm_rev_db = $self->rev_db_path($self->svm_uuid); + $self->rebuild_from_rev_db($svm_rev_db); + } + $self->unlink_rev_db_symlink; + return; + } + print "Rebuilding $map_path ...\n" if (!$partial); + my ($base_rev, $head) = ($partial ? $self->rev_map_max_norebuild(1) : + (undef, undef)); + my ($log, $ctx) = + command_output_pipe(qw/rev-list --pretty=raw --reverse/, + ($head ? "$head.." : "") . $self->refname, + '--'); + my $metadata_url = $self->metadata_url; + remove_username($metadata_url); + my $svn_uuid = $self->rewrite_uuid || $self->ra_uuid; + my $c; + while (<$log>) { + if ( m{^commit ($::sha1)$} ) { + $c = $1; + next; + } + next unless s{^\s*(git-svn-id:)}{$1}; + my ($url, $rev, $uuid) = ::extract_metadata($_); + remove_username($url); + + # ignore merges (from set-tree) + next if (!defined $rev || !$uuid); + + # if we merged or otherwise started elsewhere, this is + # how we break out of it + if (($uuid ne $svn_uuid) || + ($metadata_url && $url && ($url ne $metadata_url))) { + next; + } + if ($partial && $head) { + print "Partial-rebuilding $map_path ...\n"; + print "Currently at $base_rev = $head\n"; + $head = undef; + } + + $self->rev_map_set($rev, $c); + print "r$rev = $c\n"; + } + command_close_pipe($log, $ctx); + print "Done rebuilding $map_path\n" if (!$partial || !$head); + my $rev_db_path = $self->rev_db_path; + if (-f $self->rev_db_path) { + unlink $self->rev_db_path or croak "unlink: $!"; + } + $self->unlink_rev_db_symlink; +} + +# rev_map: +# Tie::File seems to be prone to offset errors if revisions get sparse, +# it's not that fast, either. Tie::File is also not in Perl 5.6. So +# one of my favorite modules is out :< Next up would be one of the DBM +# modules, but I'm not sure which is most portable... +# +# This is the replacement for the rev_db format, which was too big +# and inefficient for large repositories with a lot of sparse history +# (mainly tags) +# +# The format is this: +# - 24 bytes for every record, +# * 4 bytes for the integer representing an SVN revision number +# * 20 bytes representing the sha1 of a git commit +# - No empty padding records like the old format +# (except the last record, which can be overwritten) +# - new records are written append-only since SVN revision numbers +# increase monotonically +# - lookups on SVN revision number are done via a binary search +# - Piping the file to xxd -c24 is a good way of dumping it for +# viewing or editing (piped back through xxd -r), should the need +# ever arise. +# - The last record can be padding revision with an all-zero sha1 +# This is used to optimize fetch performance when using multiple +# "fetch" directives in .git/config +# +# These files are disposable unless noMetadata or useSvmProps is set + +sub _rev_map_set { + my ($fh, $rev, $commit) = @_; + + binmode $fh or croak "binmode: $!"; + my $size = (stat($fh))[7]; + ($size % 24) == 0 or croak "inconsistent size: $size"; + + my $wr_offset = 0; + if ($size > 0) { + sysseek($fh, -24, SEEK_END) or croak "seek: $!"; + my $read = sysread($fh, my $buf, 24) or croak "read: $!"; + $read == 24 or croak "read only $read bytes (!= 24)"; + my ($last_rev, $last_commit) = unpack(rev_map_fmt, $buf); + if ($last_commit eq ('0' x40)) { + if ($size >= 48) { + sysseek($fh, -48, SEEK_END) or croak "seek: $!"; + $read = sysread($fh, $buf, 24) or + croak "read: $!"; + $read == 24 or + croak "read only $read bytes (!= 24)"; + ($last_rev, $last_commit) = + unpack(rev_map_fmt, $buf); + if ($last_commit eq ('0' x40)) { + croak "inconsistent .rev_map\n"; + } + } + if ($last_rev >= $rev) { + croak "last_rev is higher!: $last_rev >= $rev"; + } + $wr_offset = -24; + } + } + sysseek($fh, $wr_offset, SEEK_END) or croak "seek: $!"; + syswrite($fh, pack(rev_map_fmt, $rev, $commit), 24) == 24 or + croak "write: $!"; +} + +sub _rev_map_reset { + my ($fh, $rev, $commit) = @_; + my $c = _rev_map_get($fh, $rev); + $c eq $commit or die "_rev_map_reset(@_) commit $c does not match!\n"; + my $offset = sysseek($fh, 0, SEEK_CUR) or croak "seek: $!"; + truncate $fh, $offset or croak "truncate: $!"; +} + +sub mkfile { + my ($path) = @_; + unless (-e $path) { + my ($dir, $base) = ($path =~ m#^(.*?)/?([^/]+)$#); + mkpath([$dir]) unless -d $dir; + open my $fh, '>>', $path or die "Couldn't create $path: $!\n"; + close $fh or die "Couldn't close (create) $path: $!\n"; + } +} + +sub rev_map_set { + my ($self, $rev, $commit, $update_ref, $uuid) = @_; + defined $commit or die "missing arg3\n"; + length $commit == 40 or die "arg3 must be a full SHA1 hexsum\n"; + my $db = $self->map_path($uuid); + my $db_lock = "$db.lock"; + my $sigmask; + $update_ref ||= 0; + if ($update_ref) { + $sigmask = POSIX::SigSet->new(); + my $signew = POSIX::SigSet->new(SIGINT, SIGHUP, SIGTERM, + SIGALRM, SIGUSR1, SIGUSR2); + sigprocmask(SIG_BLOCK, $signew, $sigmask) or + croak "Can't block signals: $!"; + } + mkfile($db); + + $LOCKFILES{$db_lock} = 1; + my $sync; + # both of these options make our .rev_db file very, very important + # and we can't afford to lose it because rebuild() won't work + if ($self->use_svm_props || $self->no_metadata) { + $sync = 1; + copy($db, $db_lock) or die "rev_map_set(@_): ", + "Failed to copy: ", + "$db => $db_lock ($!)\n"; + } else { + rename $db, $db_lock or die "rev_map_set(@_): ", + "Failed to rename: ", + "$db => $db_lock ($!)\n"; + } + + sysopen(my $fh, $db_lock, O_RDWR | O_CREAT) + or croak "Couldn't open $db_lock: $!\n"; + if ($update_ref eq 'reset') { + clear_memoized_mergeinfo_caches(); + _rev_map_reset($fh, $rev, $commit); + } else { + _rev_map_set($fh, $rev, $commit); + } + + if ($sync) { + $fh->flush or die "Couldn't flush $db_lock: $!\n"; + $fh->sync or die "Couldn't sync $db_lock: $!\n"; + } + close $fh or croak $!; + if ($update_ref) { + $_head = $self; + my $note = ""; + $note = " ($update_ref)" if ($update_ref !~ /^\d*$/); + command_noisy('update-ref', '-m', "r$rev$note", + $self->refname, $commit); + } + rename $db_lock, $db or die "rev_map_set(@_): ", "Failed to rename: ", + "$db_lock => $db ($!)\n"; + delete $LOCKFILES{$db_lock}; + if ($update_ref) { + sigprocmask(SIG_SETMASK, $sigmask) or + croak "Can't restore signal mask: $!"; + } +} + +# If want_commit, this will return an array of (rev, commit) where +# commit _must_ be a valid commit in the archive. +# Otherwise, it'll return the max revision (whether or not the +# commit is valid or just a 0x40 placeholder). +sub rev_map_max { + my ($self, $want_commit) = @_; + $self->rebuild; + my ($r, $c) = $self->rev_map_max_norebuild($want_commit); + $want_commit ? ($r, $c) : $r; +} + +sub rev_map_max_norebuild { + my ($self, $want_commit) = @_; + my $map_path = $self->map_path; + stat $map_path or return $want_commit ? (0, undef) : 0; + sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!"; + binmode $fh or croak "binmode: $!"; + my $size = (stat($fh))[7]; + ($size % 24) == 0 or croak "inconsistent size: $size"; + + if ($size == 0) { + close $fh or croak "close: $!"; + return $want_commit ? (0, undef) : 0; + } + + sysseek($fh, -24, SEEK_END) or croak "seek: $!"; + sysread($fh, my $buf, 24) == 24 or croak "read: $!"; + my ($r, $c) = unpack(rev_map_fmt, $buf); + if ($want_commit && $c eq ('0' x40)) { + if ($size < 48) { + return $want_commit ? (0, undef) : 0; + } + sysseek($fh, -48, SEEK_END) or croak "seek: $!"; + sysread($fh, $buf, 24) == 24 or croak "read: $!"; + ($r, $c) = unpack(rev_map_fmt, $buf); + if ($c eq ('0'x40)) { + croak "Penultimate record is all-zeroes in $map_path"; + } + } + close $fh or croak "close: $!"; + $want_commit ? ($r, $c) : $r; +} + +sub rev_map_get { + my ($self, $rev, $uuid) = @_; + my $map_path = $self->map_path($uuid); + return undef unless -e $map_path; + + sysopen(my $fh, $map_path, O_RDONLY) or croak "open: $!"; + my $c = _rev_map_get($fh, $rev); + close($fh) or croak "close: $!"; + $c +} + +sub _rev_map_get { + my ($fh, $rev) = @_; + + binmode $fh or croak "binmode: $!"; + my $size = (stat($fh))[7]; + ($size % 24) == 0 or croak "inconsistent size: $size"; + + if ($size == 0) { + return undef; + } + + my ($l, $u) = (0, $size - 24); + my ($r, $c, $buf); + + while ($l <= $u) { + my $i = int(($l/24 + $u/24) / 2) * 24; + sysseek($fh, $i, SEEK_SET) or croak "seek: $!"; + sysread($fh, my $buf, 24) == 24 or croak "read: $!"; + my ($r, $c) = unpack(rev_map_fmt, $buf); + + if ($r < $rev) { + $l = $i + 24; + } elsif ($r > $rev) { + $u = $i - 24; + } else { # $r == $rev + return $c eq ('0' x 40) ? undef : $c; + } + } + undef; +} + +# Finds the first svn revision that exists on (if $eq_ok is true) or +# before $rev for the current branch. It will not search any lower +# than $min_rev. Returns the git commit hash and svn revision number +# if found, else (undef, undef). +sub find_rev_before { + my ($self, $rev, $eq_ok, $min_rev) = @_; + --$rev unless $eq_ok; + $min_rev ||= 1; + my $max_rev = $self->rev_map_max; + $rev = $max_rev if ($rev > $max_rev); + while ($rev >= $min_rev) { + if (my $c = $self->rev_map_get($rev)) { + return ($rev, $c); + } + --$rev; + } + return (undef, undef); +} + +# Finds the first svn revision that exists on (if $eq_ok is true) or +# after $rev for the current branch. It will not search any higher +# than $max_rev. Returns the git commit hash and svn revision number +# if found, else (undef, undef). +sub find_rev_after { + my ($self, $rev, $eq_ok, $max_rev) = @_; + ++$rev unless $eq_ok; + $max_rev ||= $self->rev_map_max; + while ($rev <= $max_rev) { + if (my $c = $self->rev_map_get($rev)) { + return ($rev, $c); + } + ++$rev; + } + return (undef, undef); +} + +sub _new { + my ($class, $repo_id, $ref_id, $path) = @_; + unless (defined $repo_id && length $repo_id) { + $repo_id = $default_repo_id; + } + unless (defined $ref_id && length $ref_id) { + # Access the prefix option from the git-svn main program if it's loaded. + my $prefix = defined &::opt_prefix ? ::opt_prefix() : ""; + $_[2] = $ref_id = + "refs/remotes/$prefix$default_ref_id"; + } + $_[1] = $repo_id; + my $dir = "$ENV{GIT_DIR}/svn/$ref_id"; + + # Older repos imported by us used $GIT_DIR/svn/foo instead of + # $GIT_DIR/svn/refs/remotes/foo when tracking refs/remotes/foo + if ($ref_id =~ m{^refs/remotes/(.*)}) { + my $old_dir = "$ENV{GIT_DIR}/svn/$1"; + if (-d $old_dir && ! -d $dir) { + $dir = $old_dir; + } + } + + $_[3] = $path = '' unless (defined $path); + mkpath([$dir]); + my $obj = bless { + ref_id => $ref_id, dir => $dir, index => "$dir/index", + config => "$ENV{GIT_DIR}/svn/config", + map_root => "$dir/.rev_map", repo_id => $repo_id }, $class; + + # Ensure it gets canonicalized + $obj->path($path); + + return $obj; +} + +sub path { + my $self = shift; + + if (@_) { + my $path = shift; + $self->{path} = canonicalize_path($path); + return; + } + + return $self->{path}; +} + +sub url { + my $self = shift; + + if (@_) { + my $url = shift; + $self->{url} = canonicalize_url($url); + return; + } + + return $self->{url}; +} + +# for read-only access of old .rev_db formats +sub unlink_rev_db_symlink { + my ($self) = @_; + my $link = $self->rev_db_path; + $link =~ s/\.[\w-]+$// or croak "missing UUID at the end of $link"; + if (-l $link) { + unlink $link or croak "unlink: $link failed!"; + } +} + +sub rev_db_path { + my ($self, $uuid) = @_; + my $db_path = $self->map_path($uuid); + $db_path =~ s{/\.rev_map\.}{/\.rev_db\.} + or croak "map_path: $db_path does not contain '/.rev_map.' !"; + $db_path; +} + +# the new replacement for .rev_db +sub map_path { + my ($self, $uuid) = @_; + $uuid ||= $self->ra_uuid; + "$self->{map_root}.$uuid"; +} + +sub uri_encode { + my ($f) = @_; + $f =~ s#([^a-zA-Z0-9\*!\:_\./\-])#uc sprintf("%%%02x",ord($1))#eg; + $f +} + +sub uri_decode { + my ($f) = @_; + $f =~ s#%([0-9a-fA-F]{2})#chr(hex($1))#eg; + $f +} + +sub remove_username { + $_[0] =~ s{^([^:]*://)[^@]+@}{$1}; +} + +1; diff --git a/perl/Git/SVN/Fetcher.pm b/perl/Git/SVN/Fetcher.pm index ef8e9ed2a5..046a7a2f31 100644 --- a/perl/Git/SVN/Fetcher.pm +++ b/perl/Git/SVN/Fetcher.pm @@ -57,6 +57,7 @@ sub new { $self->{file_prop} = {}; $self->{absent_dir} = {}; $self->{absent_file} = {}; + require Git::IndexInfo; $self->{gii} = $git_svn->tmp_index_do(sub { Git::IndexInfo->new }); $self->{pathnameencoding} = Git::config('svn.pathnameencoding'); $self; @@ -82,7 +83,7 @@ sub _mark_empty_symlinks { chomp(my $empty_blob = `git hash-object -t blob --stdin < /dev/null`); my ($ls, $ctx) = command_output_pipe(qw/ls-tree -r -z/, $cmt); local $/ = "\0"; - my $pfx = defined($switch_path) ? $switch_path : $git_svn->{path}; + my $pfx = defined($switch_path) ? $switch_path : $git_svn->path; $pfx .= '/' if length($pfx); while (<$ls>) { chomp; diff --git a/perl/Git/SVN/GlobSpec.pm b/perl/Git/SVN/GlobSpec.pm new file mode 100644 index 0000000000..96cfd9896e --- /dev/null +++ b/perl/Git/SVN/GlobSpec.pm @@ -0,0 +1,59 @@ +package Git::SVN::GlobSpec; +use strict; +use warnings; + +sub new { + my ($class, $glob, $pattern_ok) = @_; + my $re = $glob; + $re =~ s!/+$!!g; # no need for trailing slashes + my (@left, @right, @patterns); + my $state = "left"; + my $die_msg = "Only one set of wildcard directories " . + "(e.g. '*' or '*/*/*') is supported: '$glob'\n"; + for my $part (split(m|/|, $glob)) { + if ($part =~ /\*/ && $part ne "*") { + die "Invalid pattern in '$glob': $part\n"; + } elsif ($pattern_ok && $part =~ /[{}]/ && + $part !~ /^\{[^{}]+\}/) { + die "Invalid pattern in '$glob': $part\n"; + } + if ($part eq "*") { + die $die_msg if $state eq "right"; + $state = "pattern"; + push(@patterns, "[^/]*"); + } elsif ($pattern_ok && $part =~ /^\{(.*)\}$/) { + die $die_msg if $state eq "right"; + $state = "pattern"; + my $p = quotemeta($1); + $p =~ s/\\,/|/g; + push(@patterns, "(?:$p)"); + } else { + if ($state eq "left") { + push(@left, $part); + } else { + push(@right, $part); + $state = "right"; + } + } + } + my $depth = @patterns; + if ($depth == 0) { + die "One '*' is needed in glob: '$glob'\n"; + } + my $left = join('/', @left); + my $right = join('/', @right); + $re = join('/', @patterns); + $re = join('\/', + grep(length, quotemeta($left), "($re)", quotemeta($right))); + my $left_re = qr/^\/\Q$left\E(\/|$)/; + bless { left => $left, right => $right, left_regex => $left_re, + regex => qr/$re/, glob => $glob, depth => $depth }, $class; +} + +sub full_path { + my ($self, $path) = @_; + return (length $self->{left} ? "$self->{left}/" : '') . + $path . (length $self->{right} ? "/$self->{right}" : ''); +} + +1; diff --git a/perl/Git/SVN/Log.pm b/perl/Git/SVN/Log.pm new file mode 100644 index 0000000000..3cc1c6f081 --- /dev/null +++ b/perl/Git/SVN/Log.pm @@ -0,0 +1,395 @@ +package Git::SVN::Log; +use strict; +use warnings; +use Git::SVN::Utils qw(fatal); +use Git qw(command command_oneline command_output_pipe command_close_pipe); +use POSIX qw/strftime/; +use constant commit_log_separator => ('-' x 72) . "\n"; +use vars qw/$TZ $limit $color $pager $non_recursive $verbose $oneline + %rusers $show_commit $incremental/; + +# Option set in git-svn +our $_git_format; + +sub cmt_showable { + my ($c) = @_; + return 1 if defined $c->{r}; + + # big commit message got truncated by the 16k pretty buffer in rev-list + if ($c->{l} && $c->{l}->[-1] eq "...\n" && + $c->{a_raw} =~ /\@([a-f\d\-]+)>$/) { + @{$c->{l}} = (); + my @log = command(qw/cat-file commit/, $c->{c}); + + # shift off the headers + shift @log while ($log[0] ne ''); + shift @log; + + # TODO: make $c->{l} not have a trailing newline in the future + @{$c->{l}} = map { "$_\n" } grep !/^git-svn-id: /, @log; + + (undef, $c->{r}, undef) = ::extract_metadata( + (grep(/^git-svn-id: /, @log))[-1]); + } + return defined $c->{r}; +} + +sub log_use_color { + return $color || Git->repository->get_colorbool('color.diff'); +} + +sub git_svn_log_cmd { + my ($r_min, $r_max, @args) = @_; + my $head = 'HEAD'; + my (@files, @log_opts); + foreach my $x (@args) { + if ($x eq '--' || @files) { + push @files, $x; + } else { + if (::verify_ref("$x^0")) { + $head = $x; + } else { + push @log_opts, $x; + } + } + } + + my ($url, $rev, $uuid, $gs) = ::working_head_info($head); + + require Git::SVN; + $gs ||= Git::SVN->_new; + my @cmd = (qw/log --abbrev-commit --pretty=raw --default/, + $gs->refname); + push @cmd, '-r' unless $non_recursive; + push @cmd, qw/--raw --name-status/ if $verbose; + push @cmd, '--color' if log_use_color(); + push @cmd, @log_opts; + if (defined $r_max && $r_max == $r_min) { + push @cmd, '--max-count=1'; + if (my $c = $gs->rev_map_get($r_max)) { + push @cmd, $c; + } + } elsif (defined $r_max) { + if ($r_max < $r_min) { + ($r_min, $r_max) = ($r_max, $r_min); + } + my (undef, $c_max) = $gs->find_rev_before($r_max, 1, $r_min); + my (undef, $c_min) = $gs->find_rev_after($r_min, 1, $r_max); + # If there are no commits in the range, both $c_max and $c_min + # will be undefined. If there is at least 1 commit in the + # range, both will be defined. + return () if !defined $c_min || !defined $c_max; + if ($c_min eq $c_max) { + push @cmd, '--max-count=1', $c_min; + } else { + push @cmd, '--boundary', "$c_min..$c_max"; + } + } + return (@cmd, @files); +} + +# adapted from pager.c +sub config_pager { + if (! -t *STDOUT) { + $ENV{GIT_PAGER_IN_USE} = 'false'; + $pager = undef; + return; + } + chomp($pager = command_oneline(qw(var GIT_PAGER))); + if ($pager eq 'cat') { + $pager = undef; + } + $ENV{GIT_PAGER_IN_USE} = defined($pager); +} + +sub run_pager { + return unless defined $pager; + pipe my ($rfd, $wfd) or return; + defined(my $pid = fork) or fatal "Can't fork: $!"; + if (!$pid) { + open STDOUT, '>&', $wfd or + fatal "Can't redirect to stdout: $!"; + return; + } + open STDIN, '<&', $rfd or fatal "Can't redirect stdin: $!"; + $ENV{LESS} ||= 'FRSX'; + exec $pager or fatal "Can't run pager: $! ($pager)"; +} + +sub format_svn_date { + my $t = shift || time; + require Git::SVN; + my $gmoff = Git::SVN::get_tz($t); + return strftime("%Y-%m-%d %H:%M:%S $gmoff (%a, %d %b %Y)", localtime($t)); +} + +sub parse_git_date { + my ($t, $tz) = @_; + # Date::Parse isn't in the standard Perl distro :( + if ($tz =~ s/^\+//) { + $t += tz_to_s_offset($tz); + } elsif ($tz =~ s/^\-//) { + $t -= tz_to_s_offset($tz); + } + return $t; +} + +sub set_local_timezone { + if (defined $TZ) { + $ENV{TZ} = $TZ; + } else { + delete $ENV{TZ}; + } +} + +sub tz_to_s_offset { + my ($tz) = @_; + $tz =~ s/(\d\d)$//; + return ($1 * 60) + ($tz * 3600); +} + +sub get_author_info { + my ($dest, $author, $t, $tz) = @_; + $author =~ s/(?:^\s*|\s*$)//g; + $dest->{a_raw} = $author; + my $au; + if ($::_authors) { + $au = $rusers{$author} || undef; + } + if (!$au) { + ($au) = ($author =~ /<([^>]+)\@[^>]+>$/); + } + $dest->{t} = $t; + $dest->{tz} = $tz; + $dest->{a} = $au; + $dest->{t_utc} = parse_git_date($t, $tz); +} + +sub process_commit { + my ($c, $r_min, $r_max, $defer) = @_; + if (defined $r_min && defined $r_max) { + if ($r_min == $c->{r} && $r_min == $r_max) { + show_commit($c); + return 0; + } + return 1 if $r_min == $r_max; + if ($r_min < $r_max) { + # we need to reverse the print order + return 0 if (defined $limit && --$limit < 0); + push @$defer, $c; + return 1; + } + if ($r_min != $r_max) { + return 1 if ($r_min < $c->{r}); + return 1 if ($r_max > $c->{r}); + } + } + return 0 if (defined $limit && --$limit < 0); + show_commit($c); + return 1; +} + +my $l_fmt; +sub show_commit { + my $c = shift; + if ($oneline) { + my $x = "\n"; + if (my $l = $c->{l}) { + while ($l->[0] =~ /^\s*$/) { shift @$l } + $x = $l->[0]; + } + $l_fmt ||= 'A' . length($c->{r}); + print 'r',pack($l_fmt, $c->{r}),' | '; + print "$c->{c} | " if $show_commit; + print $x; + } else { + show_commit_normal($c); + } +} + +sub show_commit_changed_paths { + my ($c) = @_; + return unless $c->{changed}; + print "Changed paths:\n", @{$c->{changed}}; +} + +sub show_commit_normal { + my ($c) = @_; + print commit_log_separator, "r$c->{r} | "; + print "$c->{c} | " if $show_commit; + print "$c->{a} | ", format_svn_date($c->{t_utc}), ' | '; + my $nr_line = 0; + + if (my $l = $c->{l}) { + while ($l->[$#$l] eq "\n" && $#$l > 0 + && $l->[($#$l - 1)] eq "\n") { + pop @$l; + } + $nr_line = scalar @$l; + if (!$nr_line) { + print "1 line\n\n\n"; + } else { + if ($nr_line == 1) { + $nr_line = '1 line'; + } else { + $nr_line .= ' lines'; + } + print $nr_line, "\n"; + show_commit_changed_paths($c); + print "\n"; + print $_ foreach @$l; + } + } else { + print "1 line\n"; + show_commit_changed_paths($c); + print "\n"; + + } + foreach my $x (qw/raw stat diff/) { + if ($c->{$x}) { + print "\n"; + print $_ foreach @{$c->{$x}} + } + } +} + +sub cmd_show_log { + my (@args) = @_; + my ($r_min, $r_max); + my $r_last = -1; # prevent dupes + set_local_timezone(); + if (defined $::_revision) { + if ($::_revision =~ /^(\d+):(\d+)$/) { + ($r_min, $r_max) = ($1, $2); + } elsif ($::_revision =~ /^\d+$/) { + $r_min = $r_max = $::_revision; + } else { + fatal "-r$::_revision is not supported, use ", + "standard 'git log' arguments instead"; + } + } + + config_pager(); + @args = git_svn_log_cmd($r_min, $r_max, @args); + if (!@args) { + print commit_log_separator unless $incremental || $oneline; + return; + } + my $log = command_output_pipe(@args); + run_pager(); + my (@k, $c, $d, $stat); + my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/; + while (<$log>) { + if (/^${esc_color}commit (?:- )?($::sha1_short)/o) { + my $cmt = $1; + if ($c && cmt_showable($c) && $c->{r} != $r_last) { + $r_last = $c->{r}; + process_commit($c, $r_min, $r_max, \@k) or + goto out; + } + $d = undef; + $c = { c => $cmt }; + } elsif (/^${esc_color}author (.+) (\d+) ([\-\+]?\d+)$/o) { + get_author_info($c, $1, $2, $3); + } elsif (/^${esc_color}(?:tree|parent|committer) /o) { + # ignore + } elsif (/^${esc_color}:\d{6} \d{6} $::sha1_short/o) { + push @{$c->{raw}}, $_; + } elsif (/^${esc_color}[ACRMDT]\t/) { + # we could add $SVN->{svn_path} here, but that requires + # remote access at the moment (repo_path_split)... + s#^(${esc_color})([ACRMDT])\t#$1 $2 #o; + push @{$c->{changed}}, $_; + } elsif (/^${esc_color}diff /o) { + $d = 1; + push @{$c->{diff}}, $_; + } elsif ($d) { + push @{$c->{diff}}, $_; + } elsif (/^\ .+\ \|\s*\d+\ $esc_color[\+\-]* + $esc_color*[\+\-]*$esc_color$/x) { + $stat = 1; + push @{$c->{stat}}, $_; + } elsif ($stat && /^ \d+ files changed, \d+ insertions/) { + push @{$c->{stat}}, $_; + $stat = undef; + } elsif (/^${esc_color} (git-svn-id:.+)$/o) { + ($c->{url}, $c->{r}, undef) = ::extract_metadata($1); + } elsif (s/^${esc_color} //o) { + push @{$c->{l}}, $_; + } + } + if ($c && defined $c->{r} && $c->{r} != $r_last) { + $r_last = $c->{r}; + process_commit($c, $r_min, $r_max, \@k); + } + if (@k) { + ($r_min, $r_max) = ($r_max, $r_min); + process_commit($_, $r_min, $r_max) foreach reverse @k; + } +out: + close $log; + print commit_log_separator unless $incremental || $oneline; +} + +sub cmd_blame { + my $path = pop; + + config_pager(); + run_pager(); + + my ($fh, $ctx, $rev); + + if ($_git_format) { + ($fh, $ctx) = command_output_pipe('blame', @_, $path); + while (my $line = <$fh>) { + if ($line =~ /^\^?([[:xdigit:]]+)\s/) { + # Uncommitted edits show up as a rev ID of + # all zeros, which we can't look up with + # cmt_metadata + if ($1 !~ /^0+$/) { + (undef, $rev, undef) = + ::cmt_metadata($1); + $rev = '0' if (!$rev); + } else { + $rev = '0'; + } + $rev = sprintf('%-10s', $rev); + $line =~ s/^\^?[[:xdigit:]]+(\s)/$rev$1/; + } + print $line; + } + } else { + ($fh, $ctx) = command_output_pipe('blame', '-p', @_, 'HEAD', + '--', $path); + my ($sha1); + my %authors; + my @buffer; + my %dsha; #distinct sha keys + + while (my $line = <$fh>) { + push @buffer, $line; + if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) { + $dsha{$1} = 1; + } + } + + my $s2r = ::cmt_sha2rev_batch([keys %dsha]); + + foreach my $line (@buffer) { + if ($line =~ /^([[:xdigit:]]{40})\s\d+\s\d+/) { + $rev = $s2r->{$1}; + $rev = '0' if (!$rev) + } + elsif ($line =~ /^author (.*)/) { + $authors{$rev} = $1; + $authors{$rev} =~ s/\s/_/g; + } + elsif ($line =~ /^\t(.*)$/) { + printf("%6s %10s %s\n", $rev, $authors{$rev}, $1); + } + } + } + command_close_pipe($fh, $ctx); +} + +1; diff --git a/perl/Git/SVN/Migration.pm b/perl/Git/SVN/Migration.pm new file mode 100644 index 0000000000..30daf35465 --- /dev/null +++ b/perl/Git/SVN/Migration.pm @@ -0,0 +1,258 @@ +package Git::SVN::Migration; +# these version numbers do NOT correspond to actual version numbers +# of git nor git-svn. They are just relative. +# +# v0 layout: .git/$id/info/url, refs/heads/$id-HEAD +# +# v1 layout: .git/$id/info/url, refs/remotes/$id +# +# v2 layout: .git/svn/$id/info/url, refs/remotes/$id +# +# v3 layout: .git/svn/$id, refs/remotes/$id +# - info/url may remain for backwards compatibility +# - this is what we migrate up to this layout automatically, +# - this will be used by git svn init on single branches +# v3.1 layout (auto migrated): +# - .rev_db => .rev_db.$UUID, .rev_db will remain as a symlink +# for backwards compatibility +# +# v4 layout: .git/svn/$repo_id/$id, refs/remotes/$repo_id/$id +# - this is only created for newly multi-init-ed +# repositories. Similar in spirit to the +# --use-separate-remotes option in git-clone (now default) +# - we do not automatically migrate to this (following +# the example set by core git) +# +# v5 layout: .rev_db.$UUID => .rev_map.$UUID +# - newer, more-efficient format that uses 24-bytes per record +# with no filler space. +# - use xxd -c24 < .rev_map.$UUID to view and debug +# - This is a one-way migration, repositories updated to the +# new format will not be able to use old git-svn without +# rebuilding the .rev_db. Rebuilding the rev_db is not +# possible if noMetadata or useSvmProps are set; but should +# be no problem for users that use the (sensible) defaults. +use strict; +use warnings; +use Carp qw/croak/; +use File::Path qw/mkpath/; +use File::Basename qw/dirname basename/; + +our $_minimize; +use Git qw( + command + command_noisy + command_output_pipe + command_close_pipe +); + +sub migrate_from_v0 { + my $git_dir = $ENV{GIT_DIR}; + return undef unless -d $git_dir; + my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/); + my $migrated = 0; + while (<$fh>) { + chomp; + my ($id, $orig_ref) = ($_, $_); + next unless $id =~ s#^refs/heads/(.+)-HEAD$#$1#; + next unless -f "$git_dir/$id/info/url"; + my $new_ref = "refs/remotes/$id"; + if (::verify_ref("$new_ref^0")) { + print STDERR "W: $orig_ref is probably an old ", + "branch used by an ancient version of ", + "git-svn.\n", + "However, $new_ref also exists.\n", + "We will not be able ", + "to use this branch until this ", + "ambiguity is resolved.\n"; + next; + } + print STDERR "Migrating from v0 layout...\n" if !$migrated; + print STDERR "Renaming ref: $orig_ref => $new_ref\n"; + command_noisy('update-ref', $new_ref, $orig_ref); + command_noisy('update-ref', '-d', $orig_ref, $orig_ref); + $migrated++; + } + command_close_pipe($fh, $ctx); + print STDERR "Done migrating from v0 layout...\n" if $migrated; + $migrated; +} + +sub migrate_from_v1 { + my $git_dir = $ENV{GIT_DIR}; + my $migrated = 0; + return $migrated unless -d $git_dir; + my $svn_dir = "$git_dir/svn"; + + # just in case somebody used 'svn' as their $id at some point... + return $migrated if -d $svn_dir && ! -f "$svn_dir/info/url"; + + print STDERR "Migrating from a git-svn v1 layout...\n"; + mkpath([$svn_dir]); + print STDERR "Data from a previous version of git-svn exists, but\n\t", + "$svn_dir\n\t(required for this version ", + "($::VERSION) of git-svn) does not exist.\n"; + my ($fh, $ctx) = command_output_pipe(qw/rev-parse --symbolic --all/); + while (<$fh>) { + my $x = $_; + next unless $x =~ s#^refs/remotes/##; + chomp $x; + next unless -f "$git_dir/$x/info/url"; + my $u = eval { ::file_to_s("$git_dir/$x/info/url") }; + next unless $u; + my $dn = dirname("$git_dir/svn/$x"); + mkpath([$dn]) unless -d $dn; + if ($x eq 'svn') { # they used 'svn' as GIT_SVN_ID: + mkpath(["$git_dir/svn/svn"]); + print STDERR " - $git_dir/$x/info => ", + "$git_dir/svn/$x/info\n"; + rename "$git_dir/$x/info", "$git_dir/svn/$x/info" or + croak "$!: $x"; + # don't worry too much about these, they probably + # don't exist with repos this old (save for index, + # and we can easily regenerate that) + foreach my $f (qw/unhandled.log index .rev_db/) { + rename "$git_dir/$x/$f", "$git_dir/svn/$x/$f"; + } + } else { + print STDERR " - $git_dir/$x => $git_dir/svn/$x\n"; + rename "$git_dir/$x", "$git_dir/svn/$x" or + croak "$!: $x"; + } + $migrated++; + } + command_close_pipe($fh, $ctx); + print STDERR "Done migrating from a git-svn v1 layout\n"; + $migrated; +} + +sub read_old_urls { + my ($l_map, $pfx, $path) = @_; + my @dir; + foreach (<$path/*>) { + if (-r "$_/info/url") { + $pfx .= '/' if $pfx && $pfx !~ m!/$!; + my $ref_id = $pfx . basename $_; + my $url = ::file_to_s("$_/info/url"); + $l_map->{$ref_id} = $url; + } elsif (-d $_) { + push @dir, $_; + } + } + foreach (@dir) { + my $x = $_; + $x =~ s!^\Q$ENV{GIT_DIR}\E/svn/!!o; + read_old_urls($l_map, $x, $_); + } +} + +sub migrate_from_v2 { + my @cfg = command(qw/config -l/); + return if grep /^svn-remote\..+\.url=/, @cfg; + my %l_map; + read_old_urls(\%l_map, '', "$ENV{GIT_DIR}/svn"); + my $migrated = 0; + + require Git::SVN; + foreach my $ref_id (sort keys %l_map) { + eval { Git::SVN->init($l_map{$ref_id}, '', undef, $ref_id) }; + if ($@) { + Git::SVN->init($l_map{$ref_id}, '', $ref_id, $ref_id); + } + $migrated++; + } + $migrated; +} + +sub minimize_connections { + require Git::SVN; + require Git::SVN::Ra; + + my $r = Git::SVN::read_all_remotes(); + my $new_urls = {}; + my $root_repos = {}; + foreach my $repo_id (keys %$r) { + my $url = $r->{$repo_id}->{url} or next; + my $fetch = $r->{$repo_id}->{fetch} or next; + my $ra = Git::SVN::Ra->new($url); + + # skip existing cases where we already connect to the root + if (($ra->url eq $ra->{repos_root}) || + ($ra->{repos_root} eq $repo_id)) { + $root_repos->{$ra->url} = $repo_id; + next; + } + + my $root_ra = Git::SVN::Ra->new($ra->{repos_root}); + my $root_path = $ra->url; + $root_path =~ s#^\Q$ra->{repos_root}\E(/|$)##; + foreach my $path (keys %$fetch) { + my $ref_id = $fetch->{$path}; + my $gs = Git::SVN->new($ref_id, $repo_id, $path); + + # make sure we can read when connecting to + # a higher level of a repository + my ($last_rev, undef) = $gs->last_rev_commit; + if (!defined $last_rev) { + $last_rev = eval { + $root_ra->get_latest_revnum; + }; + next if $@; + } + my $new = $root_path; + $new .= length $path ? "/$path" : ''; + eval { + $root_ra->get_log([$new], $last_rev, $last_rev, + 0, 0, 1, sub { }); + }; + next if $@; + $new_urls->{$ra->{repos_root}}->{$new} = + { ref_id => $ref_id, + old_repo_id => $repo_id, + old_path => $path }; + } + } + + my @emptied; + foreach my $url (keys %$new_urls) { + # see if we can re-use an existing [svn-remote "repo_id"] + # instead of creating a(n ugly) new section: + my $repo_id = $root_repos->{$url} || $url; + + my $fetch = $new_urls->{$url}; + foreach my $path (keys %$fetch) { + my $x = $fetch->{$path}; + Git::SVN->init($url, $path, $repo_id, $x->{ref_id}); + my $pfx = "svn-remote.$x->{old_repo_id}"; + + my $old_fetch = quotemeta("$x->{old_path}:". + "$x->{ref_id}"); + command_noisy(qw/config --unset/, + "$pfx.fetch", '^'. $old_fetch . '$'); + delete $r->{$x->{old_repo_id}}-> + {fetch}->{$x->{old_path}}; + if (!keys %{$r->{$x->{old_repo_id}}->{fetch}}) { + command_noisy(qw/config --unset/, + "$pfx.url"); + push @emptied, $x->{old_repo_id} + } + } + } + if (@emptied) { + my $file = $ENV{GIT_CONFIG} || "$ENV{GIT_DIR}/config"; + print STDERR <<EOF; +The following [svn-remote] sections in your config file ($file) are empty +and can be safely removed: +EOF + print STDERR "[svn-remote \"$_\"]\n" foreach @emptied; + } +} + +sub migration_check { + migrate_from_v0(); + migrate_from_v1(); + migrate_from_v2(); + minimize_connections() if $_minimize; +} + +1; diff --git a/perl/Git/SVN/Ra.pm b/perl/Git/SVN/Ra.pm index 23ff43e86b..90ec30bfff 100644 --- a/perl/Git/SVN/Ra.pm +++ b/perl/Git/SVN/Ra.pm @@ -3,6 +3,12 @@ use vars qw/@ISA $config_dir $_ignore_refs_regex $_log_window_size/; use strict; use warnings; use SVN::Client; +use Git::SVN::Utils qw( + canonicalize_url + canonicalize_path + add_path_to_url +); + use SVN::Ra; BEGIN { @ISA = qw(SVN::Ra); @@ -62,29 +68,11 @@ sub _auth_providers () { \@rv; } -sub escape_uri_only { - my ($uri) = @_; - my @tmp; - foreach (split m{/}, $uri) { - s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg; - push @tmp, $_; - } - join('/', @tmp); -} - -sub escape_url { - my ($url) = @_; - if ($url =~ m#^(https?)://([^/]+)(.*)$#) { - my ($scheme, $domain, $uri) = ($1, $2, escape_uri_only($3)); - $url = "$scheme://$domain$uri"; - } - $url; -} sub new { my ($class, $url) = @_; - $url =~ s!/+$!!; - return $RA if ($RA && $RA->{url} eq $url); + $url = canonicalize_url($url); + return $RA if ($RA && $RA->url eq $url); ::_req_svn(); @@ -115,17 +103,34 @@ sub new { $Git::SVN::Prompt::_no_auth_cache = 1; } } # no warnings 'once' - my $self = SVN::Ra->new(url => escape_url($url), auth => $baton, + + my $self = SVN::Ra->new(url => $url, auth => $baton, config => $config, pool => SVN::Pool->new, auth_provider_callbacks => $callbacks); - $self->{url} = $url; + $RA = bless $self, $class; + + # Make sure its canonicalized + $self->url($url); $self->{svn_path} = $url; $self->{repos_root} = $self->get_repos_root; $self->{svn_path} =~ s#^\Q$self->{repos_root}\E(/|$)##; $self->{cache} = { check_path => { r => 0, data => {} }, get_dir => { r => 0, data => {} } }; - $RA = bless $self, $class; + + return $RA; +} + +sub url { + my $self = shift; + + if (@_) { + my $url = shift; + $self->{url} = canonicalize_url($url); + return; + } + + return $self->{url}; } sub check_path { @@ -195,6 +200,7 @@ sub get_log { qw/copyfrom_path copyfrom_rev action/; if ($s{'copyfrom_path'}) { $s{'copyfrom_path'} =~ s/$prefix_regex//; + $s{'copyfrom_path'} = canonicalize_path($s{'copyfrom_path'}); } $_[0]{$p} = \%s; } @@ -246,7 +252,7 @@ sub get_commit_editor { sub gs_do_update { my ($self, $rev_a, $rev_b, $gs, $editor) = @_; my $new = ($rev_a == $rev_b); - my $path = $gs->{path}; + my $path = $gs->path; if ($new && -e $gs->{index}) { unlink $gs->{index} or die @@ -282,30 +288,33 @@ sub gs_do_update { # svn_ra_reparent didn't work before 1.4) sub gs_do_switch { my ($self, $rev_a, $rev_b, $gs, $url_b, $editor) = @_; - my $path = $gs->{path}; + my $path = $gs->path; my $pool = SVN::Pool->new; - my $full_url = $self->{url}; - my $old_url = $full_url; - $full_url .= '/' . $path if length $path; + my $old_url = $self->url; + my $full_url = add_path_to_url( $self->url, $path ); my ($ra, $reparented); if ($old_url =~ m#^svn(\+ssh)?://# || ($full_url =~ m#^https?://# && - escape_url($full_url) ne $full_url)) { + canonicalize_url($full_url) ne $full_url)) { $_[0] = undef; $self = undef; $RA = undef; $ra = Git::SVN::Ra->new($full_url); $ra_invalid = 1; } elsif ($old_url ne $full_url) { - SVN::_Ra::svn_ra_reparent($self->{session}, $full_url, $pool); - $self->{url} = $full_url; + SVN::_Ra::svn_ra_reparent( + $self->{session}, + canonicalize_url($full_url), + $pool + ); + $self->url($full_url); $reparented = 1; } $ra ||= $self; - $url_b = escape_url($url_b); + $url_b = canonicalize_url($url_b); my $reporter = $ra->do_switch($rev_b, '', 1, $url_b, $editor, $pool); my @lock = (::compare_svn_version('1.2.0') >= 0) ? (undef) : (); $reporter->set_path('', $rev_a, 0, @lock, $pool); @@ -313,7 +322,7 @@ sub gs_do_switch { if ($reparented) { SVN::_Ra::svn_ra_reparent($self->{session}, $old_url, $pool); - $self->{url} = $old_url; + $self->url($old_url); } $pool->clear; @@ -326,7 +335,7 @@ sub longest_common_path { my $common_max = scalar @$gsv; foreach my $gs (@$gsv) { - my @tmp = split m#/#, $gs->{path}; + my @tmp = split m#/#, $gs->path; my $p = ''; foreach (@tmp) { $p .= length($p) ? "/$_" : $_; @@ -362,7 +371,7 @@ sub gs_fetch_loop_common { my $inc = $_log_window_size; my ($min, $max) = ($base, $head < $base + $inc ? $head : $base + $inc); my $longest_path = longest_common_path($gsv, $globs); - my $ra_url = $self->{url}; + my $ra_url = $self->url; my $find_trailing_edge; while (1) { my %revs; @@ -508,7 +517,7 @@ sub match_globs { ($self->check_path($p, $r) != $SVN::Node::dir)); next unless $p =~ /$g->{path}->{regex}/; - $exists->{$p} = Git::SVN->init($self->{url}, $p, undef, + $exists->{$p} = Git::SVN->init($self->url, $p, undef, $g->{ref}->full_path($de), 1); } } @@ -532,7 +541,7 @@ sub match_globs { next if ($self->check_path($pathname, $r) != $SVN::Node::dir); $exists->{$pathname} = Git::SVN->init( - $self->{url}, $pathname, undef, + $self->url, $pathname, undef, $g->{ref}->full_path($p), 1); } my $c = ''; @@ -548,19 +557,20 @@ sub match_globs { sub minimize_url { my ($self) = @_; - return $self->{url} if ($self->{url} eq $self->{repos_root}); + return $self->url if ($self->url eq $self->{repos_root}); my $url = $self->{repos_root}; my @components = split(m!/!, $self->{svn_path}); my $c = ''; do { - $url .= "/$c" if length $c; + $url = add_path_to_url($url, $c); eval { my $ra = (ref $self)->new($url); my $latest = $ra->get_latest_revnum; $ra->get_log("", $latest, 0, 1, 0, 1, sub {}); }; } while ($@ && ($c = shift @components)); - $url; + + return canonicalize_url($url); } sub can_do_switch { @@ -568,7 +578,7 @@ sub can_do_switch { unless (defined $can_do_switch) { my $pool = SVN::Pool->new; my $rep = eval { - $self->do_switch(1, '', 0, $self->{url}, + $self->do_switch(1, '', 0, $self->url, SVN::Delta::Editor->new, $pool); }; if ($@) { diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm new file mode 100644 index 0000000000..4bb4dde89a --- /dev/null +++ b/perl/Git/SVN/Utils.pm @@ -0,0 +1,233 @@ +package Git::SVN::Utils; + +use strict; +use warnings; + +use SVN::Core; + +use base qw(Exporter); + +our @EXPORT_OK = qw( + fatal + can_compress + canonicalize_path + canonicalize_url + join_paths + add_path_to_url +); + + +=head1 NAME + +Git::SVN::Utils - utility functions used across Git::SVN + +=head1 SYNOPSIS + + use Git::SVN::Utils qw(functions to import); + +=head1 DESCRIPTION + +This module contains functions which are useful across many different +parts of Git::SVN. Mostly it's a place to put utility functions +rather than duplicate the code or have classes grabbing at other +classes. + +=head1 FUNCTIONS + +All functions can be imported only on request. + +=head3 fatal + + fatal(@message); + +Display a message and exit with a fatal error code. + +=cut + +# Note: not certain why this is in use instead of die. Probably because +# the exit code of die is 255? Doesn't appear to be used consistently. +sub fatal (@) { print STDERR "@_\n"; exit 1 } + + +=head3 can_compress + + my $can_compress = can_compress; + +Returns true if Compress::Zlib is available, false otherwise. + +=cut + +my $can_compress; +sub can_compress { + return $can_compress if defined $can_compress; + + return $can_compress = eval { require Compress::Zlib; }; +} + + +=head3 canonicalize_path + + my $canoncalized_path = canonicalize_path($path); + +Converts $path into a canonical form which is safe to pass to the SVN +API as a file path. + +=cut + +# Turn foo/../bar into bar +sub _collapse_dotdot { + my $path = shift; + + 1 while $path =~ s{/[^/]+/+\.\.}{}; + 1 while $path =~ s{[^/]+/+\.\./}{}; + 1 while $path =~ s{[^/]+/+\.\.}{}; + + return $path; +} + + +sub canonicalize_path { + my $path = shift; + my $rv; + + # The 1.7 way to do it + if ( defined &SVN::_Core::svn_dirent_canonicalize ) { + $path = _collapse_dotdot($path); + $rv = SVN::_Core::svn_dirent_canonicalize($path); + } + # The 1.6 way to do it + # This can return undef on subversion-perl-1.4.2-2.el5 (CentOS 5.2) + elsif ( defined &SVN::_Core::svn_path_canonicalize ) { + $path = _collapse_dotdot($path); + $rv = SVN::_Core::svn_path_canonicalize($path); + } + + return $rv if defined $rv; + + # No SVN API canonicalization is available, or the SVN API + # didn't return a successful result, do it ourselves + return _canonicalize_path_ourselves($path); +} + + +sub _canonicalize_path_ourselves { + my ($path) = @_; + my $dot_slash_added = 0; + if (substr($path, 0, 1) ne "/") { + $path = "./" . $path; + $dot_slash_added = 1; + } + $path =~ s#/+#/#g; + $path =~ s#/\.(?:/|$)#/#g; + $path = _collapse_dotdot($path); + $path =~ s#/$##g; + $path =~ s#^\./## if $dot_slash_added; + $path =~ s#^/##; + $path =~ s#^\.$##; + return $path; +} + + +=head3 canonicalize_url + + my $canonicalized_url = canonicalize_url($url); + +Converts $url into a canonical form which is safe to pass to the SVN +API as a URL. + +=cut + +sub canonicalize_url { + my $url = shift; + + # The 1.7 way to do it + if ( defined &SVN::_Core::svn_uri_canonicalize ) { + return SVN::_Core::svn_uri_canonicalize($url); + } + # There wasn't a 1.6 way to do it, so we do it ourself. + else { + return _canonicalize_url_ourselves($url); + } +} + + +sub _canonicalize_url_path { + my ($uri_path) = @_; + + my @parts; + foreach my $part (split m{/+}, $uri_path) { + $part =~ s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg; + push @parts, $part; + } + + return join('/', @parts); +} + +sub _canonicalize_url_ourselves { + my ($url) = @_; + if ($url =~ m#^([^:]+)://([^/]*)(.*)$#) { + my ($scheme, $domain, $uri) = ($1, $2, _canonicalize_url_path(canonicalize_path($3))); + $url = "$scheme://$domain$uri"; + } + $url; +} + + +=head3 join_paths + + my $new_path = join_paths(@paths); + +Appends @paths together into a single path. Any empty paths are ignored. + +=cut + +sub join_paths { + my @paths = @_; + + @paths = grep { defined $_ && length $_ } @paths; + + return '' unless @paths; + return $paths[0] if @paths == 1; + + my $new_path = shift @paths; + $new_path =~ s{/+$}{}; + + my $last_path = pop @paths; + $last_path =~ s{^/+}{}; + + for my $path (@paths) { + $path =~ s{^/+}{}; + $path =~ s{/+$}{}; + $new_path .= "/$path"; + } + + return $new_path .= "/$last_path"; +} + + +=head3 add_path_to_url + + my $new_url = add_path_to_url($url, $path); + +Appends $path onto the $url. If $path is empty, $url is returned unchanged. + +=cut + +sub add_path_to_url { + my($url, $path) = @_; + + return $url if !defined $path or !length $path; + + # Strip trailing and leading slashes so we don't + # wind up with http://x.com///path + $url =~ s{/+$}{}; + $path =~ s{^/+}{}; + + # If a path has a % in it, URI escape it so it's not + # mistaken for a URI escape later. + $path =~ s{%}{%25}g; + + return join '/', $url, $path; +} + +1; diff --git a/perl/Makefile b/perl/Makefile index 6ca7d472eb..15d96fcc7a 100644 --- a/perl/Makefile +++ b/perl/Makefile @@ -20,17 +20,26 @@ clean: $(RM) ppport.h $(RM) $(makfile) $(RM) $(makfile).old + $(RM) PM.stamp + +$(makfile): PM.stamp ifdef NO_PERL_MAKEMAKER instdir_SQ = $(subst ','\'',$(prefix)/lib) modules += Git modules += Git/I18N +modules += Git/IndexInfo +modules += Git/SVN modules += Git/SVN/Memoize/YAML modules += Git/SVN/Fetcher modules += Git/SVN/Editor +modules += Git/SVN/GlobSpec +modules += Git/SVN/Log +modules += Git/SVN/Migration modules += Git/SVN/Prompt modules += Git/SVN/Ra +modules += Git/SVN/Utils $(makfile): ../GIT-CFLAGS Makefile echo all: private-Error.pm Git.pm Git/I18N.pm > $@ diff --git a/perl/Makefile.PL b/perl/Makefile.PL index b54b04a619..3f29ba98a6 100644 --- a/perl/Makefile.PL +++ b/perl/Makefile.PL @@ -2,11 +2,16 @@ use strict; use warnings; use ExtUtils::MakeMaker; use Getopt::Long; +use File::Find; + +# Don't forget to update the perl/Makefile, too. +# Don't forget to test with NO_PERL_MAKEMAKER=YesPlease # Sanity: die at first unknown option Getopt::Long::Configure qw/ pass_through /; -GetOptions("localedir=s" => \my $localedir); +my $localedir = ''; +GetOptions("localedir=s" => \$localedir); sub MY::postamble { return <<'MAKE_FRAG'; @@ -24,24 +29,22 @@ endif MAKE_FRAG } -# XXX. When editing this list: -# -# * Please update perl/Makefile, too. -# * Don't forget to test with NO_PERL_MAKEMAKER=YesPlease -my %pm = ( - 'Git.pm' => '$(INST_LIBDIR)/Git.pm', - 'Git/I18N.pm' => '$(INST_LIBDIR)/Git/I18N.pm', - 'Git/SVN/Memoize/YAML.pm' => '$(INST_LIBDIR)/Git/SVN/Memoize/YAML.pm', - 'Git/SVN/Fetcher.pm' => '$(INST_LIBDIR)/Git/SVN/Fetcher.pm', - 'Git/SVN/Editor.pm' => '$(INST_LIBDIR)/Git/SVN/Editor.pm', - 'Git/SVN/Prompt.pm' => '$(INST_LIBDIR)/Git/SVN/Prompt.pm', - 'Git/SVN/Ra.pm' => '$(INST_LIBDIR)/Git/SVN/Ra.pm', -); +# Find all the .pm files in "Git/" and Git.pm +my %pm; +find sub { + return unless /\.pm$/; + + # sometimes File::Find prepends a ./ Strip it. + my $pm_path = $File::Find::name; + $pm_path =~ s{^\./}{}; + + $pm{$pm_path} = '$(INST_LIBDIR)/'.$pm_path; +}, "Git", "Git.pm"; + # We come with our own bundled Error.pm. It's not in the set of default # Perl modules so install it if it's not available on the system yet. -eval { require Error }; -if ($@ || $Error::VERSION < 0.15009) { +if ( !eval { require Error } || $Error::VERSION < 0.15009) { $pm{'private-Error.pm'} = '$(INST_LIBDIR)/Error.pm'; } @@ -5,9 +5,9 @@ # msgid "" msgstr "" -"Project-Id-Version: git 1.7.11\n" +"Project-Id-Version: git 1.7.12\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2012-07-03 10:23+0800\n" +"POT-Creation-Date: 2012-08-06 23:47+0800\n" "PO-Revision-Date: 2012-03-28 18:46+0200\n" "Last-Translator: Ralf Thielow <ralf.thielow@googlemail.com>\n" "Language-Team: German\n" @@ -48,7 +48,7 @@ msgstr "'%s' sieht nicht wie eine v2 Paketdatei aus" msgid "unrecognized header: %s%s (%d)" msgstr "nicht erkannter Kopfbereich: %s%s (%d)" -#: bundle.c:89 builtin/commit.c:696 +#: bundle.c:89 builtin/commit.c:699 #, c-format msgid "could not open '%s'" msgstr "Konnte '%s' nicht öffnen" @@ -58,7 +58,7 @@ msgid "Repository lacks these prerequisite commits:" msgstr "Dem Projektarchiv fehlen folgende vorrausgesetzte Versionen:" #: bundle.c:164 sequencer.c:550 sequencer.c:982 builtin/log.c:290 -#: builtin/log.c:721 builtin/log.c:1310 builtin/log.c:1529 builtin/merge.c:347 +#: builtin/log.c:726 builtin/log.c:1316 builtin/log.c:1535 builtin/merge.c:347 #: builtin/shortlog.c:181 msgid "revision walk setup failed" msgstr "Einrichtung des Revisionsgangs fehlgeschlagen" @@ -85,7 +85,7 @@ msgstr[1] "Das Paket benötigt diese %d Referenzen" msgid "rev-list died" msgstr "\"rev-list\" abgebrochen" -#: bundle.c:300 builtin/log.c:1206 builtin/shortlog.c:284 +#: bundle.c:300 builtin/log.c:1212 builtin/shortlog.c:284 #, c-format msgid "unrecognized argument: %s" msgstr "nicht erkanntes Argument: %s" @@ -232,8 +232,8 @@ msgstr "" "%s" #: diff.c:1400 -msgid " 0 files changed\n" -msgstr " 0 Dateien geändert\n" +msgid " 0 files changed" +msgstr " 0 Dateien geändert" #: diff.c:1404 #, c-format @@ -256,7 +256,7 @@ msgid_plural ", %d deletions(-)" msgstr[0] ", %d Zeile entfernt(-)" msgstr[1] ", %d Zeilen entfernt(-)" -#: diff.c:3478 +#: diff.c:3461 #, c-format msgid "" "Failed to parse --dirstat/-X option parameter:\n" @@ -292,16 +292,16 @@ msgstr "'%s': %s" msgid "'%s': short read %s" msgstr "'%s': read() zu kurz %s" -#: help.c:208 +#: help.c:212 #, c-format msgid "available git commands in '%s'" msgstr "Vorhandene Git-Kommandos in '%s'" -#: help.c:215 +#: help.c:219 msgid "git commands available from elsewhere on your $PATH" msgstr "Vorhandene Git-Kommandos irgendwo in deinem $PATH" -#: help.c:271 +#: help.c:275 #, c-format msgid "" "'%s' appears to be a git command, but we were not\n" @@ -310,11 +310,11 @@ msgstr "" "'%s' scheint ein git-Kommando zu sein, konnte aber\n" "nicht ausgeführt werden. Vielleicht ist git-%s fehlerhaft?" -#: help.c:328 +#: help.c:332 msgid "Uh oh. Your system reports no Git commands at all." msgstr "Uh oh. Keine Git-Kommandos auf deinem System vorhanden." -#: help.c:350 +#: help.c:354 #, c-format msgid "" "WARNING: You called a Git command named '%s', which does not exist.\n" @@ -323,17 +323,17 @@ msgstr "" "Warnung: Du hast das nicht existierende Git-Kommando '%s' ausgeführt.\n" "Setze fort unter der Annahme das du '%s' gemeint hast" -#: help.c:355 +#: help.c:359 #, c-format msgid "in %0.1f seconds automatically..." msgstr "automatisch in %0.1f Sekunden..." -#: help.c:362 +#: help.c:366 #, c-format msgid "git: '%s' is not a git command. See 'git --help'." msgstr "git: '%s' ist kein Git-Kommando. Siehe 'git --help'." -#: help.c:366 +#: help.c:370 msgid "" "\n" "Did you mean this?" @@ -347,35 +347,301 @@ msgstr[1] "" "\n" "Hast du eines von diesen gemeint?" -#: parse-options.c:493 +#: merge-recursive.c:190 +#, c-format +msgid "(bad commit)\n" +msgstr "(ungültige Version)\n" + +#: merge-recursive.c:206 +#, c-format +msgid "addinfo_cache failed for path '%s'" +msgstr "addinfo_cache für Pfad '%s' fehlgeschlagen" + +#: merge-recursive.c:268 +msgid "error building trees" +msgstr "Fehler beim Erstellen der Bäume" + +#: merge-recursive.c:497 +msgid "diff setup failed" +msgstr "diff_setup_done fehlgeschlagen" + +#: merge-recursive.c:627 +msgid "merge-recursive: disk full?" +msgstr "merge-recursive: Festplatte voll?" + +#: merge-recursive.c:690 +#, c-format +msgid "failed to create path '%s'%s" +msgstr "Fehler beim Erstellen des Pfades '%s'%s" + +#: merge-recursive.c:701 +#, c-format +msgid "Removing %s to make room for subdirectory\n" +msgstr "Entferne %s um Platz für Unterverzeichnis zu schaffen\n" + +#. something else exists +#. .. but not some other error (who really cares what?) +#: merge-recursive.c:715 merge-recursive.c:736 +msgid ": perhaps a D/F conflict?" +msgstr ": vielleicht ein Verzeichnis/Datei-Konflikt?" + +#: merge-recursive.c:726 +#, c-format +msgid "refusing to lose untracked file at '%s'" +msgstr "verweigere, da unbeobachtete Dateien in '%s' verloren gehen würden" + +#: merge-recursive.c:766 +#, c-format +msgid "cannot read object %s '%s'" +msgstr "kann Objekt %s '%s' nicht lesen" + +#: merge-recursive.c:768 +#, c-format +msgid "blob expected for %s '%s'" +msgstr "Blob erwartet für %s '%s'" + +#: merge-recursive.c:791 builtin/clone.c:302 +#, c-format +msgid "failed to open '%s'" +msgstr "Fehler beim Öffnen von '%s'" + +#: merge-recursive.c:799 +#, c-format +msgid "failed to symlink '%s'" +msgstr "Fehler beim Erstellen einer symbolischen Verknüpfung für '%s'" + +#: merge-recursive.c:802 +#, c-format +msgid "do not know what to do with %06o %s '%s'" +msgstr "weiß nicht was mit %06o %s '%s' zu machen ist" + +#: merge-recursive.c:939 +msgid "Failed to execute internal merge" +msgstr "Fehler bei Ausführung der internen Zusammenführung" + +#: merge-recursive.c:943 +#, c-format +msgid "Unable to add %s to database" +msgstr "Konnte %s nicht zur Datenbank hinzufügen" + +#: merge-recursive.c:959 +msgid "unsupported object type in the tree" +msgstr "nicht unterstützter Objekttyp im Baum" + +#: merge-recursive.c:1038 merge-recursive.c:1052 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree." +msgstr "" +"KONFLIKT (%s/löschen): %s gelöscht in %s und %s in %s. Stand %s von %s wurde " +"im Arbeitsbereich gelassen." + +#: merge-recursive.c:1044 merge-recursive.c:1057 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree at %s." +msgstr "" +"KONFLIKT (%s/löschen): %s gelöscht in %s und %s in %s. Stand %s von %s wurde " +"im Arbeitsbereich bei %s gelassen." + +#: merge-recursive.c:1098 +msgid "rename" +msgstr "umbenennen" + +#: merge-recursive.c:1098 +msgid "renamed" +msgstr "umbenannt" + +#: merge-recursive.c:1154 +#, c-format +msgid "%s is a directory in %s adding as %s instead" +msgstr "%s ist ein Verzeichnis in %s, füge es stattdessen als %s hinzu" + +#: merge-recursive.c:1176 +#, c-format +msgid "" +"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s" +"\"->\"%s\" in \"%s\"%s" +msgstr "" +"KONFLIKT (umbenennen/umbenennen): Benenne um \"%s\"->\"%s\" in Zweig \"%s\" " +"und \"%s\"->\"%s\" in Zweig \"%s\"%s" + +#: merge-recursive.c:1181 +msgid " (left unresolved)" +msgstr " (bleibt unaufgelöst)" + +#: merge-recursive.c:1235 +#, c-format +msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s" +msgstr "" +"KONFLIKT (umbenennen/umbenennen): Benenne um %s->%s in %s. Benenne um %s->%s " +"in %s" + +#: merge-recursive.c:1265 +#, c-format +msgid "Renaming %s to %s and %s to %s instead" +msgstr "Benenne stattdessen %s nach %s und %s nach %s um" + +#: merge-recursive.c:1464 +#, c-format +msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s" +msgstr "" +"KONFLIKT (umbenennen/hinzufügen): Benenne um %s->%s in %s. %s hinzugefügt in " +"%s" + +#: merge-recursive.c:1474 +#, c-format +msgid "Adding merged %s" +msgstr "Füge zusammengeführte Datei %s hinzu" + +#: merge-recursive.c:1479 merge-recursive.c:1677 +#, c-format +msgid "Adding as %s instead" +msgstr "Füge stattdessen als %s hinzu" + +#: merge-recursive.c:1530 +#, c-format +msgid "cannot read object %s" +msgstr "kann Objekt %s nicht lesen" + +#: merge-recursive.c:1533 +#, c-format +msgid "object %s is not a blob" +msgstr "Objekt %s ist kein Blob" + +#: merge-recursive.c:1581 +msgid "modify" +msgstr "ändern" + +#: merge-recursive.c:1581 +msgid "modified" +msgstr "geändert" + +#: merge-recursive.c:1591 +msgid "content" +msgstr "Inhalt" + +#: merge-recursive.c:1598 +msgid "add/add" +msgstr "hinzufügen/hinzufügen" + +#: merge-recursive.c:1632 +#, c-format +msgid "Skipped %s (merged same as existing)" +msgstr "%s ausgelassen (Ergebnis der Zusammenführung existiert bereits)" + +#: merge-recursive.c:1646 +#, c-format +msgid "Auto-merging %s" +msgstr "automatische Zusammenführung von %s" + +#: merge-recursive.c:1650 git-submodule.sh:844 +msgid "submodule" +msgstr "Unterprojekt" + +#: merge-recursive.c:1651 +#, c-format +msgid "CONFLICT (%s): Merge conflict in %s" +msgstr "KONFLIKT (%s): Zusammenführungskonflikt in %s" + +#: merge-recursive.c:1741 +#, c-format +msgid "Removing %s" +msgstr "Entferne %s" + +#: merge-recursive.c:1766 +msgid "file/directory" +msgstr "Datei/Verzeichnis" + +#: merge-recursive.c:1772 +msgid "directory/file" +msgstr "Verzeichnis/Datei" + +#: merge-recursive.c:1777 +#, c-format +msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s" +msgstr "" +"KONFLIKT (%s): Es existiert bereits ein Verzeichnis %s in %s. Füge %s als %s " +"hinzu." + +#: merge-recursive.c:1787 +#, c-format +msgid "Adding %s" +msgstr "Füge %s hinzu" + +#: merge-recursive.c:1804 +msgid "Fatal merge failure, shouldn't happen." +msgstr "Fataler Fehler bei der Zusammenführung. Sollte nicht passieren." + +#: merge-recursive.c:1823 +msgid "Already up-to-date!" +msgstr "Bereits aktuell!" + +#: merge-recursive.c:1832 +#, c-format +msgid "merging of trees %s and %s failed" +msgstr "Zusammenführen der Bäume %s und %s fehlgeschlagen" + +#: merge-recursive.c:1862 +#, c-format +msgid "Unprocessed path??? %s" +msgstr "unverarbeiteter Pfad??? %s" + +#: merge-recursive.c:1907 +msgid "Merging:" +msgstr "Zusammenführung:" + +#: merge-recursive.c:1920 +#, c-format +msgid "found %u common ancestor:" +msgid_plural "found %u common ancestors:" +msgstr[0] "%u gemeinsamen Vorfahren gefunden" +msgstr[1] "%u gemeinsame Vorfahren gefunden" + +#: merge-recursive.c:1957 +msgid "merge returned no commit" +msgstr "Zusammenführung hat keine Version zurückgegeben" + +#: merge-recursive.c:2014 +#, c-format +msgid "Could not parse object '%s'" +msgstr "Konnte Objekt '%s' nicht parsen." + +#: merge-recursive.c:2026 builtin/merge.c:697 +msgid "Unable to write index." +msgstr "Konnte Bereitstellung nicht schreiben." + +#: parse-options.c:494 msgid "..." msgstr "..." -#: parse-options.c:511 +#: parse-options.c:512 #, c-format msgid "usage: %s" msgstr "Verwendung: %s" #. TRANSLATORS: the colon here should align with the #. one in "usage: %s" translation -#: parse-options.c:515 +#: parse-options.c:516 #, c-format msgid " or: %s" msgstr " oder: %s" -#: parse-options.c:518 +#: parse-options.c:519 #, c-format msgid " %s" msgstr " %s" -#: remote.c:1629 +#: remote.c:1632 #, 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] "Dein Zweig ist vor '%s' um %d Version.\n" msgstr[1] "Dein Zweig ist vor '%s' um %d Versionen.\n" -#: remote.c:1635 +#: remote.c:1638 #, c-format msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n" msgid_plural "" @@ -386,7 +652,7 @@ msgstr[1] "" "Dein Zweig ist zu '%s' um %d Versionen hinterher, und kann vorgespult " "werden.\n" -#: remote.c:1643 +#: remote.c:1646 #, c-format msgid "" "Your branch and '%s' have diverged,\n" @@ -614,7 +880,7 @@ msgstr "kann Zweigspitze (HEAD) nicht auflösen" msgid "cannot abort from a branch yet to be born" msgstr "kann nicht abbrechen: bin auf einem Zweig, der noch geboren wird" -#: sequencer.c:805 builtin/apply.c:3697 +#: sequencer.c:805 builtin/apply.c:3988 #, c-format msgid "cannot open %s: %s" msgstr "Kann %s nicht öffnen: %s" @@ -648,21 +914,21 @@ msgstr "Kann nicht zu initialer Version zurücksetzen." msgid "Can't cherry-pick into empty head" msgstr "Kann \"cherry-pick\" nicht in einem leerem Kopf ausführen." -#: sha1_name.c:864 +#: sha1_name.c:1044 msgid "HEAD does not point to a branch" msgstr "Zweigspitze (HEAD) zeigt auf keinen Zweig" -#: sha1_name.c:867 +#: sha1_name.c:1047 #, c-format msgid "No such branch: '%s'" msgstr "Kein solcher Zweig '%s'" -#: sha1_name.c:869 +#: sha1_name.c:1049 #, c-format msgid "No upstream configured for branch '%s'" msgstr "Kein entferntes Projektarchiv für Zweig '%s' konfiguriert." -#: sha1_name.c:872 +#: sha1_name.c:1052 #, c-format msgid "Upstream branch '%s' not stored as a remote-tracking branch" msgstr "" @@ -677,351 +943,353 @@ msgstr "konnte aktuellen Benutzer nicht in Passwort-Datei finden: %s" msgid "no such user" msgstr "kein solcher Benutzer" -#: wt-status.c:141 +#: wt-status.c:140 msgid "Unmerged paths:" msgstr "Nicht zusammengeführte Pfade:" -#: wt-status.c:168 wt-status.c:195 +#: wt-status.c:167 wt-status.c:194 #, c-format msgid " (use \"git reset %s <file>...\" to unstage)" msgstr "" " (benutze \"git reset %s <Datei>...\" zum Herausnehmen aus der " "Bereitstellung)" -#: wt-status.c:170 wt-status.c:197 +#: wt-status.c:169 wt-status.c:196 msgid " (use \"git rm --cached <file>...\" to unstage)" msgstr "" " (benutze \"git rm --cached <Datei>...\" zum Herausnehmen aus der " "Bereitstellung)" -#: wt-status.c:174 +#: wt-status.c:173 msgid " (use \"git add <file>...\" to mark resolution)" msgstr " (benutze \"git add/rm <Datei>...\" um die Auflösung zu markieren)" -#: wt-status.c:176 wt-status.c:180 +#: wt-status.c:175 wt-status.c:179 msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)" msgstr "" " (benutze \"git add/rm <Datei>...\" um die Auflösung entsprechend zu " "markieren)" -#: wt-status.c:178 +#: wt-status.c:177 msgid " (use \"git rm <file>...\" to mark resolution)" msgstr " (benutze \"git add/rm <Datei>...\" um die Auflösung zu markieren)" -#: wt-status.c:189 +#: wt-status.c:188 msgid "Changes to be committed:" msgstr "zum Eintragen bereitgestellte Änderungen:" -#: wt-status.c:207 +#: wt-status.c:206 msgid "Changes not staged for commit:" msgstr "Änderungen, die nicht zum Eintragen bereitgestellt sind:" -#: wt-status.c:211 +#: wt-status.c:210 msgid " (use \"git add <file>...\" to update what will be committed)" msgstr " (benutze \"git add <Datei>...\" zum Bereitstellen)" -#: wt-status.c:213 +#: wt-status.c:212 msgid " (use \"git add/rm <file>...\" to update what will be committed)" msgstr " (benutze \"git add/rm <Datei>...\" zum Bereitstellen)" -#: wt-status.c:214 +#: wt-status.c:213 msgid "" " (use \"git checkout -- <file>...\" to discard changes in working directory)" msgstr "" " (benutze \"git checkout -- <Datei>...\" um die Änderungen im " "Arbeitsverzeichnis zu verwerfen)" -#: wt-status.c:216 +#: wt-status.c:215 msgid " (commit or discard the untracked or modified content in submodules)" msgstr "" " (trage ein oder verwerfe den unbeobachteten oder geänderten Inhalt in den " "Unterprojekten)" -#: wt-status.c:225 +#: wt-status.c:224 #, c-format msgid "%s files:" msgstr "%s Dateien:" -#: wt-status.c:228 +#: wt-status.c:227 #, c-format msgid " (use \"git %s <file>...\" to include in what will be committed)" msgstr " (benutze \"git %s <Datei>...\" zum Einfügen in die Eintragung)" -#: wt-status.c:245 +#: wt-status.c:244 msgid "bug" msgstr "Fehler" -#: wt-status.c:250 +#: wt-status.c:249 msgid "both deleted:" msgstr "beide gelöscht:" -#: wt-status.c:251 +#: wt-status.c:250 msgid "added by us:" msgstr "von uns hinzugefügt:" -#: wt-status.c:252 +#: wt-status.c:251 msgid "deleted by them:" msgstr "von denen gelöscht:" -#: wt-status.c:253 +#: wt-status.c:252 msgid "added by them:" msgstr "von denen hinzugefügt:" -#: wt-status.c:254 +#: wt-status.c:253 msgid "deleted by us:" msgstr "von uns gelöscht:" -#: wt-status.c:255 +#: wt-status.c:254 msgid "both added:" msgstr "von beiden hinzugefügt:" -#: wt-status.c:256 +#: wt-status.c:255 msgid "both modified:" msgstr "von beiden geändert:" -#: wt-status.c:286 +#: wt-status.c:285 msgid "new commits, " msgstr "neue Versionen, " -#: wt-status.c:288 +#: wt-status.c:287 msgid "modified content, " msgstr "geänderter Inhalt, " -#: wt-status.c:290 +#: wt-status.c:289 msgid "untracked content, " msgstr "unbeobachteter Inhalt, " -#: wt-status.c:304 +#: wt-status.c:303 #, c-format msgid "new file: %s" msgstr "neue Datei: %s" -#: wt-status.c:307 +#: wt-status.c:306 #, c-format msgid "copied: %s -> %s" msgstr "kopiert: %s -> %s" -#: wt-status.c:310 +#: wt-status.c:309 #, c-format msgid "deleted: %s" msgstr "gelöscht: %s" -#: wt-status.c:313 +#: wt-status.c:312 #, c-format msgid "modified: %s" msgstr "geändert: %s" -#: wt-status.c:316 +#: wt-status.c:315 #, c-format msgid "renamed: %s -> %s" msgstr "umbenannt: %s -> %s" -#: wt-status.c:319 +#: wt-status.c:318 #, c-format msgid "typechange: %s" msgstr "Typänderung: %s" -#: wt-status.c:322 +#: wt-status.c:321 #, c-format msgid "unknown: %s" msgstr "unbekannt: %s" -#: wt-status.c:325 +#: wt-status.c:324 #, c-format msgid "unmerged: %s" msgstr "nicht zusammengeführt: %s" -#: wt-status.c:328 +#: wt-status.c:327 #, c-format msgid "bug: unhandled diff status %c" msgstr "Fehler: unbehandelter Differenz-Status %c" -#: wt-status.c:786 +#: wt-status.c:785 msgid "You have unmerged paths." msgstr "Du hast nicht zusammengeführte Pfade." -#: wt-status.c:789 wt-status.c:913 +#: wt-status.c:788 wt-status.c:912 msgid " (fix conflicts and run \"git commit\")" msgstr " (behebe die Konflikte und führe \"git commit\" aus)" -#: wt-status.c:792 +#: wt-status.c:791 msgid "All conflicts fixed but you are still merging." -msgstr "Alle Konflikte sind behoben, aber du bist immer noch beim " -"Zusammenführen." +msgstr "" +"Alle Konflikte sind behoben, aber du bist immer noch beim Zusammenführen." -#: wt-status.c:795 +#: wt-status.c:794 msgid " (use \"git commit\" to conclude merge)" msgstr " (benutze \"git commit\" um die Zusammenführung abzuschließen)" -#: wt-status.c:805 +#: wt-status.c:804 msgid "You are in the middle of an am session." msgstr "Eine \"am\"-Sitzung ist im Gange." -#: wt-status.c:808 +#: wt-status.c:807 msgid "The current patch is empty." msgstr "Der aktuelle Patch ist leer." -#: wt-status.c:812 +#: wt-status.c:811 msgid " (fix conflicts and then run \"git am --resolved\")" msgstr " (behebe die Konflikte und führe dann \"git am --resolved\" aus)" -#: wt-status.c:814 +#: wt-status.c:813 msgid " (use \"git am --skip\" to skip this patch)" msgstr " (benutze \"git am --skip\" um diesen Patch auszulassen)" -#: wt-status.c:816 +#: wt-status.c:815 msgid " (use \"git am --abort\" to restore the original branch)" -msgstr " (benutze \"git am --abort\" um den ursprünglichen Zweig " -"wiederherzustellen)" +msgstr "" +" (benutze \"git am --abort\" um den ursprünglichen Zweig wiederherzustellen)" -#: wt-status.c:874 wt-status.c:884 +#: wt-status.c:873 wt-status.c:883 msgid "You are currently rebasing." msgstr "Du bist gerade beim Neuaufbau." -#: wt-status.c:877 +#: wt-status.c:876 msgid " (fix conflicts and then run \"git rebase --continue\")" msgstr " (behebe die Konflikte und führe dann \"git rebase --continue\" aus)" -#: wt-status.c:879 +#: wt-status.c:878 msgid " (use \"git rebase --skip\" to skip this patch)" msgstr " (benutze \"git rebase --skip\" um diesen Patch auszulassen)" -#: wt-status.c:881 +#: wt-status.c:880 msgid " (use \"git rebase --abort\" to check out the original branch)" -msgstr " (benutze \"git rebase --abort\" um den ursprünglichen Zweig " -"auszuchecken)" +msgstr "" +" (benutze \"git rebase --abort\" um den ursprünglichen Zweig auszuchecken)" -#: wt-status.c:887 +#: wt-status.c:886 msgid " (all conflicts fixed: run \"git rebase --continue\")" msgstr " (alle Konflikte behoben: führe \"git rebase --continue\" aus)" -#: wt-status.c:889 +#: wt-status.c:888 msgid "You are currently splitting a commit during a rebase." msgstr "Du teilst gerade eine Version während eines Neuaufbaus auf." -#: wt-status.c:892 +#: wt-status.c:891 msgid " (Once your working directory is clean, run \"git rebase --continue\")" -msgstr " (Sobald dein Arbeitsverzeichnis sauber ist, führe " -"\"git rebase --continue\" aus)" +msgstr "" +" (Sobald dein Arbeitsverzeichnis sauber ist, führe \"git rebase --continue" +"\" aus)" -#: wt-status.c:894 +#: wt-status.c:893 msgid "You are currently editing a commit during a rebase." msgstr "Du editierst gerade eine Version während eines Neuaufbaus." -#: wt-status.c:897 +#: wt-status.c:896 msgid " (use \"git commit --amend\" to amend the current commit)" -msgstr " (benutze \"git commit --amend\" um die aktuelle Version " -"nachzubessern)" +msgstr "" +" (benutze \"git commit --amend\" um die aktuelle Version nachzubessern)" -#: wt-status.c:899 +#: wt-status.c:898 msgid "" " (use \"git rebase --continue\" once you are satisfied with your changes)" -msgstr " (benutze \"git rebase --continue\" sobald deine Änderungen " -"abgeschlossen sind)" +msgstr "" +" (benutze \"git rebase --continue\" sobald deine Änderungen abgeschlossen " +"sind)" -#: wt-status.c:909 +#: wt-status.c:908 msgid "You are currently cherry-picking." msgstr "Du führst gerade \"cherry-pick\" aus." -#: wt-status.c:916 +#: wt-status.c:915 msgid " (all conflicts fixed: run \"git commit\")" msgstr " (alle Konflikte behoben: führe \"git commit\" aus)" -#: wt-status.c:925 +#: wt-status.c:924 msgid "You are currently bisecting." msgstr "Du bist gerade beim Halbieren." -#: wt-status.c:928 +#: wt-status.c:927 msgid " (use \"git bisect reset\" to get back to the original branch)" -msgstr " (benutze \"git bisect reset\" um zum ursprünglichen Zweig " -"zurückzukehren)" +msgstr "" +" (benutze \"git bisect reset\" um zum ursprünglichen Zweig zurückzukehren)" -#: wt-status.c:979 +#: wt-status.c:978 msgid "On branch " msgstr "Auf Zweig " -#: wt-status.c:986 +#: wt-status.c:985 msgid "Not currently on any branch." msgstr "Im Moment auf keinem Zweig." -#: wt-status.c:998 +#: wt-status.c:997 msgid "Initial commit" msgstr "Initiale Version" -#: wt-status.c:1012 +#: wt-status.c:1011 msgid "Untracked" msgstr "Unbeobachtete" -#: wt-status.c:1014 +#: wt-status.c:1013 msgid "Ignored" msgstr "Ignorierte" -#: wt-status.c:1016 +#: wt-status.c:1015 #, c-format msgid "Untracked files not listed%s" msgstr "Unbeobachtete Dateien nicht aufgelistet%s" -#: wt-status.c:1018 +#: wt-status.c:1017 msgid " (use -u option to show untracked files)" msgstr " (benutze die Option -u um unbeobachteten Dateien anzuzeigen)" -#: wt-status.c:1024 +#: wt-status.c:1023 msgid "No changes" msgstr "Keine Änderungen" -#: wt-status.c:1028 +#: wt-status.c:1027 #, c-format msgid "no changes added to commit%s\n" msgstr "keine Änderungen zum Eintragen hinzugefügt%s\n" -#: wt-status.c:1030 +#: wt-status.c:1029 msgid " (use \"git add\" and/or \"git commit -a\")" msgstr " (benutze \"git add\" und/oder \"git commit -a\")" -#: wt-status.c:1032 +#: wt-status.c:1031 #, c-format msgid "nothing added to commit but untracked files present%s\n" msgstr "" "nichts zum Eintragen hinzugefügt, aber es gibt unbeobachtete Dateien%s\n" -#: wt-status.c:1034 +#: wt-status.c:1033 msgid " (use \"git add\" to track)" msgstr " (benutze \"git add\" zum Beobachten)" -#: wt-status.c:1036 wt-status.c:1039 wt-status.c:1042 +#: wt-status.c:1035 wt-status.c:1038 wt-status.c:1041 #, c-format msgid "nothing to commit%s\n" msgstr "nichts zum Eintragen%s\n" -#: wt-status.c:1037 +#: wt-status.c:1036 msgid " (create/copy files and use \"git add\" to track)" msgstr " (Erstelle/Kopiere Dateien und benutze \"git add\" zum Beobachten)" -#: wt-status.c:1040 +#: wt-status.c:1039 msgid " (use -u to show untracked files)" msgstr " (benutze die Option -u um unbeobachtete Dateien anzuzeigen)" -#: wt-status.c:1043 +#: wt-status.c:1042 msgid " (working directory clean)" msgstr " (Arbeitsverzeichnis sauber)" -#: wt-status.c:1151 +#: wt-status.c:1150 msgid "HEAD (no branch)" msgstr "HEAD (kein Zweig)" -#: wt-status.c:1157 +#: wt-status.c:1156 msgid "Initial commit on " msgstr "Initiale Version auf " -#: wt-status.c:1172 +#: wt-status.c:1171 msgid "behind " msgstr "hinterher " -#: wt-status.c:1175 wt-status.c:1178 +#: wt-status.c:1174 wt-status.c:1177 msgid "ahead " msgstr "voraus " -#: wt-status.c:1180 +#: wt-status.c:1179 msgid ", behind " msgstr ", hinterher " @@ -1030,7 +1298,7 @@ msgstr ", hinterher " msgid "unexpected diff status %c" msgstr "unerwarteter Differenz-Status %c" -#: builtin/add.c:67 builtin/commit.c:226 +#: builtin/add.c:67 builtin/commit.c:229 msgid "updating files failed" msgstr "Aktualisierung der Dateien fehlgeschlagen" @@ -1124,79 +1392,79 @@ msgstr "Nichts spezifiziert, nichts hinzugefügt.\n" msgid "Maybe you wanted to say 'git add .'?\n" msgstr "Wolltest du vielleicht 'git add .' sagen?\n" -#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:286 builtin/mv.c:82 +#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:289 builtin/mv.c:82 #: builtin/rm.c:162 msgid "index file corrupt" msgstr "Bereitstellungsdatei beschädigt" -#: builtin/add.c:480 builtin/apply.c:4108 builtin/mv.c:229 builtin/rm.c:260 +#: builtin/add.c:480 builtin/apply.c:4433 builtin/mv.c:229 builtin/rm.c:260 msgid "Unable to write new index file" msgstr "Konnte neue Bereitstellungsdatei nicht schreiben." -#: builtin/apply.c:53 +#: builtin/apply.c:57 msgid "git apply [options] [<patch>...]" msgstr "git apply [Optionen] [<Patch>...]" -#: builtin/apply.c:106 +#: builtin/apply.c:110 #, c-format msgid "unrecognized whitespace option '%s'" msgstr "nicht erkannte Option für Leerzeichen: '%s'" -#: builtin/apply.c:121 +#: builtin/apply.c:125 #, c-format msgid "unrecognized whitespace ignore option '%s'" msgstr "nicht erkannte Option zum Ignorieren von Leerzeichen: '%s'" -#: builtin/apply.c:815 +#: builtin/apply.c:824 #, c-format msgid "Cannot prepare timestamp regexp %s" msgstr "Kann regulären Ausdruck für Zeitstempel %s nicht verarbeiten" -#: builtin/apply.c:824 +#: builtin/apply.c:833 #, c-format msgid "regexec returned %d for input: %s" msgstr "Ausführung des regulären Ausdrucks gab %d zurück. Eingabe: %s" -#: builtin/apply.c:905 +#: builtin/apply.c:914 #, c-format msgid "unable to find filename in patch at line %d" msgstr "Konnte keinen Dateinamen in Zeile %d des Patches finden." -#: builtin/apply.c:937 +#: builtin/apply.c:946 #, c-format msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d" msgstr "" "git apply: ungültiges 'git-diff' - erwartete /dev/null, erhielt %s in Zeile " "%d" -#: builtin/apply.c:941 +#: builtin/apply.c:950 #, c-format msgid "git apply: bad git-diff - inconsistent new filename on line %d" msgstr "" "git apply: ungültiges 'git-diff' - Inkonsistenter neuer Dateiname in Zeile %d" -#: builtin/apply.c:942 +#: builtin/apply.c:951 #, c-format msgid "git apply: bad git-diff - inconsistent old filename on line %d" msgstr "" "git apply: ungültiges 'git-diff' - Inkonsistenter alter Dateiname in Zeile %d" -#: builtin/apply.c:949 +#: builtin/apply.c:958 #, c-format msgid "git apply: bad git-diff - expected /dev/null on line %d" msgstr "git apply: ungültiges 'git-diff' - erwartete /dev/null in Zeile %d" -#: builtin/apply.c:1394 +#: builtin/apply.c:1403 #, c-format msgid "recount: unexpected line: %.*s" msgstr "recount: unerwartete Zeile: %.*s" -#: builtin/apply.c:1451 +#: builtin/apply.c:1460 #, c-format msgid "patch fragment without header at line %d: %.*s" msgstr "Patch-Fragment ohne Kopfbereich bei Zeile %d: %.*s" -#: builtin/apply.c:1468 +#: builtin/apply.c:1477 #, c-format msgid "" "git diff header lacks filename information when removing %d leading pathname " @@ -1211,70 +1479,70 @@ msgstr[1] "" "Dem Kopfbereich von \"git diff\" fehlen Informationen zum Dateinamen, wenn " "%d vorangestellte Teile des Pfades entfernt werden (Zeile %d)" -#: builtin/apply.c:1628 +#: builtin/apply.c:1637 msgid "new file depends on old contents" msgstr "neue Datei hängt von alten Inhalten ab" -#: builtin/apply.c:1630 +#: builtin/apply.c:1639 msgid "deleted file still has contents" msgstr "entfernte Datei hat noch Inhalte" -#: builtin/apply.c:1656 +#: builtin/apply.c:1665 #, c-format msgid "corrupt patch at line %d" msgstr "fehlerhafter Patch bei Zeile %d" -#: builtin/apply.c:1692 +#: builtin/apply.c:1701 #, c-format msgid "new file %s depends on old contents" msgstr "neue Datei %s hängt von alten Inhalten ab" -#: builtin/apply.c:1694 +#: builtin/apply.c:1703 #, c-format msgid "deleted file %s still has contents" msgstr "entfernte Datei %s hat noch Inhalte" -#: builtin/apply.c:1697 +#: builtin/apply.c:1706 #, c-format msgid "** warning: file %s becomes empty but is not deleted" msgstr "** Warnung: Datei %s wird leer, aber nicht entfernt." -#: builtin/apply.c:1843 +#: builtin/apply.c:1852 #, c-format msgid "corrupt binary patch at line %d: %.*s" msgstr "fehlerhafter Binär-Patch bei Zeile %d: %.*s" #. there has to be one hunk (forward hunk) -#: builtin/apply.c:1872 +#: builtin/apply.c:1881 #, c-format msgid "unrecognized binary patch at line %d" msgstr "nicht erkannter Binär-Patch bei Zeile %d" -#: builtin/apply.c:1958 +#: builtin/apply.c:1967 #, c-format msgid "patch with only garbage at line %d" msgstr "Patch mit nutzlosen Informationen bei Zeile %d" -#: builtin/apply.c:2048 +#: builtin/apply.c:2057 #, c-format msgid "unable to read symlink %s" msgstr "konnte symbolische Verknüpfung %s nicht lesen" -#: builtin/apply.c:2052 +#: builtin/apply.c:2061 #, c-format msgid "unable to open or read %s" msgstr "konnte %s nicht öffnen oder lesen" -#: builtin/apply.c:2123 +#: builtin/apply.c:2132 msgid "oops" msgstr "Ups" -#: builtin/apply.c:2645 +#: builtin/apply.c:2654 #, c-format msgid "invalid start of line: '%c'" msgstr "Ungültiger Zeilenanfang: '%c'" -#: builtin/apply.c:2763 +#: builtin/apply.c:2772 #, c-format msgid "Hunk #%d succeeded at %d (offset %d line)." msgid_plural "Hunk #%d succeeded at %d (offset %d lines)." @@ -1282,12 +1550,12 @@ msgstr[0] "Patch-Bereich #%d erfolgreich angewendet bei %d (%d Zeile versetzt)" msgstr[1] "" "Patch-Bereich #%d erfolgreich angewendet bei %d (%d Zeilen versetzt)" -#: builtin/apply.c:2775 +#: builtin/apply.c:2784 #, c-format msgid "Context reduced to (%ld/%ld) to apply fragment at %d" msgstr "Kontext reduziert zu (%ld/%ld) um Patch-Bereich bei %d anzuwenden" -#: builtin/apply.c:2781 +#: builtin/apply.c:2790 #, c-format msgid "" "while searching for:\n" @@ -1296,329 +1564,339 @@ msgstr "" "bei der Suche nach:\n" "%.*s" -#: builtin/apply.c:2800 +#: builtin/apply.c:2809 #, c-format msgid "missing binary patch data for '%s'" msgstr "keine Daten in Binär-Patch für '%s'" -#: builtin/apply.c:2903 +#: builtin/apply.c:2912 #, c-format msgid "binary patch does not apply to '%s'" msgstr "Konnte Binär-Patch nicht auf '%s' anwenden" -#: builtin/apply.c:2909 +#: builtin/apply.c:2918 #, c-format msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)" msgstr "" "Binär-Patch für '%s' erzeugt falsches Ergebnis (erwartete %s, bekam %s)" -#: builtin/apply.c:2930 +#: builtin/apply.c:2939 #, c-format msgid "patch failed: %s:%ld" msgstr "Anwendung des Patches fehlgeschlagen: %s:%ld" -#: builtin/apply.c:3045 +#: builtin/apply.c:3061 #, c-format -msgid "patch %s has been renamed/deleted" -msgstr "Patch %s wurde umbenannt/gelöscht" +msgid "cannot checkout %s" +msgstr "kann %s nicht auschecken" -#: builtin/apply.c:3052 builtin/apply.c:3069 +#: builtin/apply.c:3106 builtin/apply.c:3115 builtin/apply.c:3159 #, c-format msgid "read of %s failed" msgstr "Konnte %s nicht lesen" -#: builtin/apply.c:3084 -msgid "removal patch leaves file contents" -msgstr "Lösch-Patch hinterlässt Dateiinhalte" - -#: builtin/apply.c:3105 +#: builtin/apply.c:3139 builtin/apply.c:3361 #, c-format -msgid "%s: already exists in working directory" -msgstr "%s existiert bereits im Arbeitsverzeichnis" +msgid "path %s has been renamed/deleted" +msgstr "Pfad %s wurde umbenannt/gelöscht" -#: builtin/apply.c:3143 +#: builtin/apply.c:3220 builtin/apply.c:3375 #, c-format -msgid "%s: has been deleted/renamed" -msgstr "%s wurde gelöscht/umbenannt" +msgid "%s: does not exist in index" +msgstr "%s ist nicht bereitgestellt" -#: builtin/apply.c:3148 builtin/apply.c:3179 +#: builtin/apply.c:3224 builtin/apply.c:3367 builtin/apply.c:3389 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: builtin/apply.c:3159 -#, c-format -msgid "%s: does not exist in index" -msgstr "%s ist nicht bereitgestellt" - -#: builtin/apply.c:3173 +#: builtin/apply.c:3229 builtin/apply.c:3383 #, c-format msgid "%s: does not match index" msgstr "%s entspricht nicht der Bereitstellung" -#: builtin/apply.c:3190 +#: builtin/apply.c:3331 +msgid "removal patch leaves file contents" +msgstr "Lösch-Patch hinterlässt Dateiinhalte" + +#: builtin/apply.c:3400 #, c-format msgid "%s: wrong type" msgstr "%s: falscher Typ" -#: builtin/apply.c:3192 +#: builtin/apply.c:3402 #, c-format msgid "%s has type %o, expected %o" msgstr "%s ist vom Typ %o, erwartete %o" -#: builtin/apply.c:3247 +#: builtin/apply.c:3503 #, c-format msgid "%s: already exists in index" msgstr "%s ist bereits bereitgestellt" -#: builtin/apply.c:3267 +#: builtin/apply.c:3506 +#, c-format +msgid "%s: already exists in working directory" +msgstr "%s existiert bereits im Arbeitsverzeichnis" + +#: builtin/apply.c:3526 #, c-format msgid "new mode (%o) of %s does not match old mode (%o)" msgstr "neuer Modus (%o) von %s entspricht nicht dem alten Modus (%o)" -#: builtin/apply.c:3272 +#: builtin/apply.c:3531 #, c-format msgid "new mode (%o) of %s does not match old mode (%o) of %s" msgstr "neuer Modus (%o) von %s entspricht nicht dem alten Modus (%o) von %s" -#: builtin/apply.c:3280 +#: builtin/apply.c:3539 #, c-format msgid "%s: patch does not apply" msgstr "%s: Patch konnte nicht angewendet werden" -#: builtin/apply.c:3293 +#: builtin/apply.c:3552 #, c-format msgid "Checking patch %s..." msgstr "Prüfe Patch %s..." -#: builtin/apply.c:3348 builtin/checkout.c:212 builtin/reset.c:158 +#: builtin/apply.c:3607 builtin/checkout.c:213 builtin/reset.c:158 #, c-format msgid "make_cache_entry failed for path '%s'" msgstr "make_cache_entry für Pfad '%s' fehlgeschlagen" -#: builtin/apply.c:3491 +#: builtin/apply.c:3750 #, c-format msgid "unable to remove %s from index" msgstr "konnte %s nicht aus der Bereitstellung entfernen" -#: builtin/apply.c:3518 +#: builtin/apply.c:3778 #, c-format msgid "corrupt patch for subproject %s" msgstr "fehlerhafter Patch für Unterprojekt %s" -#: builtin/apply.c:3522 +#: builtin/apply.c:3782 #, c-format msgid "unable to stat newly created file '%s'" msgstr "konnte neu erstellte Datei '%s' nicht lesen" -#: builtin/apply.c:3527 +#: builtin/apply.c:3787 #, c-format msgid "unable to create backing store for newly created file %s" msgstr "kann internen Speicher für eben erstellte Datei %s nicht erzeugen" -#: builtin/apply.c:3530 +#: builtin/apply.c:3790 builtin/apply.c:3898 #, c-format msgid "unable to add cache entry for %s" msgstr "kann für %s keinen Eintrag in den Zwischenspeicher hinzufügen" -#: builtin/apply.c:3563 +#: builtin/apply.c:3823 #, c-format msgid "closing file '%s'" msgstr "schließe Datei '%s'" -#: builtin/apply.c:3612 +#: builtin/apply.c:3872 #, c-format msgid "unable to write file '%s' mode %o" msgstr "konnte Datei '%s' mit Modus %o nicht schreiben" -#: builtin/apply.c:3668 +#: builtin/apply.c:3959 #, c-format msgid "Applied patch %s cleanly." msgstr "Patch %s sauber angewendet" -#: builtin/apply.c:3676 +#: builtin/apply.c:3967 msgid "internal error" msgstr "interner Fehler" #. Say this even without --verbose -#: builtin/apply.c:3679 +#: builtin/apply.c:3970 #, c-format msgid "Applying patch %%s with %d reject..." msgid_plural "Applying patch %%s with %d rejects..." msgstr[0] "Wende Patch %%s mit %d Zurückweisung an..." msgstr[1] "Wende Patch %%s mit %d Zurückweisungen an..." -#: builtin/apply.c:3689 +#: builtin/apply.c:3980 #, c-format msgid "truncating .rej filename to %.*s.rej" msgstr "Verkürze Name von .rej Datei zu %.*s.rej" -#: builtin/apply.c:3710 +#: builtin/apply.c:4001 #, c-format msgid "Hunk #%d applied cleanly." msgstr "Patch-Bereich #%d sauber angewendet." -#: builtin/apply.c:3713 +#: builtin/apply.c:4004 #, c-format msgid "Rejected hunk #%d." msgstr "Patch-Bereich #%d zurückgewiesen." -#: builtin/apply.c:3844 +#: builtin/apply.c:4154 msgid "unrecognized input" msgstr "nicht erkannte Eingabe" -#: builtin/apply.c:3855 +#: builtin/apply.c:4165 msgid "unable to read index file" msgstr "Konnte Bereitstellungsdatei nicht lesen" -#: builtin/apply.c:3970 builtin/apply.c:3973 +#: builtin/apply.c:4284 builtin/apply.c:4287 msgid "path" msgstr "Pfad" -#: builtin/apply.c:3971 +#: builtin/apply.c:4285 msgid "don't apply changes matching the given path" msgstr "wendet keine Änderungen im angegebenen Pfad an" -#: builtin/apply.c:3974 +#: builtin/apply.c:4288 msgid "apply changes matching the given path" msgstr "wendet Änderungen nur im angegebenen Pfad an" -#: builtin/apply.c:3976 +#: builtin/apply.c:4290 msgid "num" msgstr "Anzahl" -#: builtin/apply.c:3977 +#: builtin/apply.c:4291 msgid "remove <num> leading slashes from traditional diff paths" msgstr "" "entfernt <Anzahl> vorrangestellte Schrägstriche von herkömmlichen " "Differenzpfaden" -#: builtin/apply.c:3980 +#: builtin/apply.c:4294 msgid "ignore additions made by the patch" msgstr "ignoriert hinzugefügte Zeilen des Patches" -#: builtin/apply.c:3982 +#: builtin/apply.c:4296 msgid "instead of applying the patch, output diffstat for the input" msgstr "" "anstatt der Anwendung des Patches, wird der \"diffstat\" für die Eingabe " "ausgegeben" -#: builtin/apply.c:3986 +#: builtin/apply.c:4300 msgid "shows number of added and deleted lines in decimal notation" msgstr "" "zeigt die Anzahl von hinzugefügten/entfernten Zeilen in Dezimalnotation" -#: builtin/apply.c:3988 +#: builtin/apply.c:4302 msgid "instead of applying the patch, output a summary for the input" msgstr "" "anstatt der Anwendung des Patches, wird eine Zusammenfassung für die Eingabe " "ausgegeben" -#: builtin/apply.c:3990 +#: builtin/apply.c:4304 msgid "instead of applying the patch, see if the patch is applicable" msgstr "" "anstatt der Anwendung des Patches, zeige ob Patch angewendet werden kann" -#: builtin/apply.c:3992 +#: builtin/apply.c:4306 msgid "make sure the patch is applicable to the current index" msgstr "" "stellt sicher, dass der Patch in der aktuellen Bereitstellung angewendet " "werden kann" -#: builtin/apply.c:3994 +#: builtin/apply.c:4308 msgid "apply a patch without touching the working tree" msgstr "wendet einen Patch an, ohne Änderungen im Arbeitszweig vorzunehmen" -#: builtin/apply.c:3996 +#: builtin/apply.c:4310 msgid "also apply the patch (use with --stat/--summary/--check)" msgstr "wendet den Patch an (Benutzung mit --stat/--summary/--check)" -#: builtin/apply.c:3998 +#: builtin/apply.c:4312 +msgid "attempt three-way merge if a patch does not apply" +msgstr "" +"versucht 3-Wege-Zusammenführung, wenn der Patch nicht angewendet werden " +"konnte" + +#: builtin/apply.c:4314 msgid "build a temporary index based on embedded index information" msgstr "" "erstellt eine temporäre Bereitstellung basierend auf den integrierten " "Bereitstellungsinformationen" -#: builtin/apply.c:4000 +#: builtin/apply.c:4316 msgid "paths are separated with NUL character" msgstr "Pfade sind getrennt durch NUL Zeichen" -#: builtin/apply.c:4003 +#: builtin/apply.c:4319 msgid "ensure at least <n> lines of context match" msgstr "" "stellt sicher, dass mindestens <Anzahl> Zeilen des Kontextes übereinstimmen" -#: builtin/apply.c:4004 +#: builtin/apply.c:4320 msgid "action" msgstr "Aktion" -#: builtin/apply.c:4005 +#: builtin/apply.c:4321 msgid "detect new or modified lines that have whitespace errors" msgstr "ermittelt neue oder geänderte Zeilen die Fehler in Leerzeichen haben" -#: builtin/apply.c:4008 builtin/apply.c:4011 +#: builtin/apply.c:4324 builtin/apply.c:4327 msgid "ignore changes in whitespace when finding context" msgstr "ignoriert Änderungen in Leerzeichen bei der Suche des Kontextes" -#: builtin/apply.c:4014 +#: builtin/apply.c:4330 msgid "apply the patch in reverse" msgstr "wendet den Patch in umgekehrter Reihenfolge an" -#: builtin/apply.c:4016 +#: builtin/apply.c:4332 msgid "don't expect at least one line of context" msgstr "erwartet keinen Kontext" -#: builtin/apply.c:4018 +#: builtin/apply.c:4334 msgid "leave the rejected hunks in corresponding *.rej files" msgstr "" "hinterlässt zurückgewiesene Patch-Bereiche in den entsprechenden *.rej " "Dateien" -#: builtin/apply.c:4020 +#: builtin/apply.c:4336 msgid "allow overlapping hunks" msgstr "erlaubt sich überlappende Patch-Bereiche" -#: builtin/apply.c:4021 +#: builtin/apply.c:4337 msgid "be verbose" msgstr "erweiterte Ausgaben" -#: builtin/apply.c:4023 +#: builtin/apply.c:4339 msgid "tolerate incorrectly detected missing new-line at the end of file" msgstr "toleriert fehlerhaft erkannten fehlenden Zeilenumbruch am Dateiende" -#: builtin/apply.c:4026 +#: builtin/apply.c:4342 msgid "do not trust the line counts in the hunk headers" msgstr "vertraut nicht den Zeilennummern im Kopf des Patch-Bereiches" -#: builtin/apply.c:4028 +#: builtin/apply.c:4344 msgid "root" msgstr "Wurzelverzeichnis" -#: builtin/apply.c:4029 +#: builtin/apply.c:4345 msgid "prepend <root> to all filenames" msgstr "stellt <Wurzelverzeichnis> vor alle Dateinamen" -#: builtin/apply.c:4050 +#: builtin/apply.c:4367 +msgid "--3way outside a repository" +msgstr "--3way außerhalb eines Projektarchivs" + +#: builtin/apply.c:4375 msgid "--index outside a repository" msgstr "--index außerhalb eines Projektarchivs" -#: builtin/apply.c:4053 +#: builtin/apply.c:4378 msgid "--cached outside a repository" msgstr "--cached außerhalb eines Projektarchivs" -#: builtin/apply.c:4069 +#: builtin/apply.c:4394 #, c-format msgid "can't open patch '%s'" msgstr "kann Patch '%s' nicht öffnen" -#: builtin/apply.c:4083 +#: builtin/apply.c:4408 #, c-format msgid "squelched %d whitespace error" msgid_plural "squelched %d whitespace errors" msgstr[0] "unterdrückte %d Fehler in Leerzeichen" msgstr[1] "unterdrückte %d Fehler in Leerzeichen" -#: builtin/apply.c:4089 builtin/apply.c:4099 +#: builtin/apply.c:4414 builtin/apply.c:4424 #, c-format msgid "%d line adds whitespace errors." msgid_plural "%d lines add whitespace errors." @@ -1828,7 +2106,7 @@ msgstr "Konnte Beschreibungsvorlage für Zweig nicht schreiben: %s" msgid "Failed to resolve HEAD as a valid ref." msgstr "Konnte Zweigspitze (HEAD) nicht als gültige Referenz auflösen." -#: builtin/branch.c:788 builtin/clone.c:558 +#: builtin/branch.c:788 builtin/clone.c:561 msgid "HEAD not found below refs/heads!" msgstr "Zweigspitze (HEAD) wurde nicht unter \"refs/heads\" gefunden!" @@ -1855,99 +2133,99 @@ msgstr "Um ein Paket zu erstellen wird ein Projektarchiv benötigt." msgid "Need a repository to unbundle." msgstr "Zum Entpacken wird ein Projektarchiv benötigt." -#: builtin/checkout.c:113 builtin/checkout.c:146 +#: builtin/checkout.c:114 builtin/checkout.c:147 #, c-format msgid "path '%s' does not have our version" msgstr "Pfad '%s' hat nicht unsere Version." -#: builtin/checkout.c:115 builtin/checkout.c:148 +#: builtin/checkout.c:116 builtin/checkout.c:149 #, c-format msgid "path '%s' does not have their version" msgstr "Pfad '%s' hat nicht deren Version." -#: builtin/checkout.c:131 +#: builtin/checkout.c:132 #, c-format msgid "path '%s' does not have all necessary versions" msgstr "Pfad '%s' hat nicht alle notwendigen Versionen." -#: builtin/checkout.c:175 +#: builtin/checkout.c:176 #, c-format msgid "path '%s' does not have necessary versions" msgstr "Pfad '%s' hat nicht die notwendigen Versionen." -#: builtin/checkout.c:192 +#: builtin/checkout.c:193 #, c-format msgid "path '%s': cannot merge" msgstr "Pfad '%s': kann nicht zusammenführen" -#: builtin/checkout.c:209 +#: builtin/checkout.c:210 #, c-format msgid "Unable to add merge result for '%s'" msgstr "Konnte Ergebnis der Zusammenführung von '%s' nicht hinzufügen." -#: builtin/checkout.c:234 builtin/checkout.c:392 +#: builtin/checkout.c:235 builtin/checkout.c:393 msgid "corrupt index file" msgstr "beschädigte Bereitstellungsdatei" -#: builtin/checkout.c:264 builtin/checkout.c:271 +#: builtin/checkout.c:265 builtin/checkout.c:272 #, c-format msgid "path '%s' is unmerged" msgstr "Pfad '%s' ist nicht zusammengeführt." -#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583 +#: builtin/checkout.c:303 builtin/checkout.c:499 builtin/clone.c:586 #: builtin/merge.c:812 msgid "unable to write new index file" msgstr "Konnte neue Bereitstellungsdatei nicht schreiben." -#: builtin/checkout.c:319 builtin/diff.c:302 builtin/merge.c:408 +#: builtin/checkout.c:320 builtin/diff.c:302 builtin/merge.c:408 msgid "diff_setup_done failed" msgstr "diff_setup_done fehlgeschlagen" -#: builtin/checkout.c:414 +#: builtin/checkout.c:415 msgid "you need to resolve your current index first" msgstr "Du musst zuerst deine aktuelle Bereitstellung auflösen." -#: builtin/checkout.c:533 +#: builtin/checkout.c:534 #, c-format msgid "Can not do reflog for '%s'\n" msgstr "Konnte \"reflog\" für '%s' nicht durchführen\n" -#: builtin/checkout.c:566 +#: builtin/checkout.c:567 msgid "HEAD is now at" msgstr "Zweigspitze (HEAD) ist jetzt bei" -#: builtin/checkout.c:573 +#: builtin/checkout.c:574 #, c-format msgid "Reset branch '%s'\n" msgstr "Setze Zweig '%s' zurück\n" -#: builtin/checkout.c:576 +#: builtin/checkout.c:577 #, c-format msgid "Already on '%s'\n" msgstr "Bereits auf '%s'\n" -#: builtin/checkout.c:580 +#: builtin/checkout.c:581 #, c-format msgid "Switched to and reset branch '%s'\n" msgstr "Gewechselt zu zurückgesetztem Zweig '%s'\n" -#: builtin/checkout.c:582 +#: builtin/checkout.c:583 #, c-format msgid "Switched to a new branch '%s'\n" msgstr "Gewechselt zu einem neuen Zweig '%s'\n" -#: builtin/checkout.c:584 +#: builtin/checkout.c:585 #, c-format msgid "Switched to branch '%s'\n" msgstr "Gewechselt zu Zweig '%s'\n" -#: builtin/checkout.c:640 +#: builtin/checkout.c:641 #, c-format msgid " ... and %d more.\n" msgstr " ... und %d weitere.\n" #. The singular version -#: builtin/checkout.c:646 +#: builtin/checkout.c:647 #, c-format msgid "" "Warning: you are leaving %d commit behind, not connected to\n" @@ -1970,7 +2248,7 @@ msgstr[1] "" "\n" "%s\n" -#: builtin/checkout.c:664 +#: builtin/checkout.c:665 #, c-format msgid "" "If you want to keep them by creating a new branch, this may be a good time\n" @@ -1985,71 +2263,71 @@ msgstr "" " git branch neuer_zweig_name %s\n" "\n" -#: builtin/checkout.c:694 +#: builtin/checkout.c:695 msgid "internal error in revision walk" msgstr "interner Fehler im Revisionsgang" -#: builtin/checkout.c:698 +#: builtin/checkout.c:699 msgid "Previous HEAD position was" msgstr "Vorherige Position der Zweigspitze (HEAD) war" -#: builtin/checkout.c:724 +#: builtin/checkout.c:725 builtin/checkout.c:920 msgid "You are on a branch yet to be born" msgstr "du bist auf einem Zweig, der noch geboren wird" #. case (1) -#: builtin/checkout.c:855 +#: builtin/checkout.c:856 #, c-format msgid "invalid reference: %s" msgstr "Ungültige Referenz: %s" #. case (1): want a tree -#: builtin/checkout.c:894 +#: builtin/checkout.c:895 #, c-format msgid "reference is not a tree: %s" msgstr "Referenz ist kein Baum: %s" -#: builtin/checkout.c:974 +#: builtin/checkout.c:977 msgid "-B cannot be used with -b" msgstr "-B kann nicht mit -b benutzt werden" -#: builtin/checkout.c:983 +#: builtin/checkout.c:986 msgid "--patch is incompatible with all other options" msgstr "--patch ist inkompatibel mit allen anderen Optionen" -#: builtin/checkout.c:986 +#: builtin/checkout.c:989 msgid "--detach cannot be used with -b/-B/--orphan" msgstr "--detach kann nicht mit -b/-B/--orphan benutzt werden" -#: builtin/checkout.c:988 +#: builtin/checkout.c:991 msgid "--detach cannot be used with -t" msgstr "--detach kann nicht mit -t benutzt werden" -#: builtin/checkout.c:994 +#: builtin/checkout.c:997 msgid "--track needs a branch name" msgstr "--track benötigt einen Zweignamen" -#: builtin/checkout.c:1001 +#: builtin/checkout.c:1004 msgid "Missing branch name; try -b" msgstr "Vermisse Zweignamen; versuche -b" -#: builtin/checkout.c:1007 +#: builtin/checkout.c:1010 msgid "--orphan and -b|-B are mutually exclusive" msgstr "--orphan und -b|-B sind gegenseitig exklusiv" -#: builtin/checkout.c:1009 +#: builtin/checkout.c:1012 msgid "--orphan cannot be used with -t" msgstr "--orphan kann nicht mit -t benutzt werden" -#: builtin/checkout.c:1019 +#: builtin/checkout.c:1022 msgid "git checkout: -f and -m are incompatible" msgstr "git checkout: -f und -m sind inkompatibel" -#: builtin/checkout.c:1053 +#: builtin/checkout.c:1056 msgid "invalid path specification" msgstr "ungültige Pfadspezifikation" -#: builtin/checkout.c:1061 +#: builtin/checkout.c:1064 #, c-format msgid "" "git checkout: updating paths is incompatible with switching branches.\n" @@ -2060,17 +2338,17 @@ msgstr "" "Hast du beabsichtigt '%s' auszuchecken, welcher nicht als Version aufgelöst " "werden kann?" -#: builtin/checkout.c:1063 +#: builtin/checkout.c:1066 msgid "git checkout: updating paths is incompatible with switching branches." msgstr "" "git checkout: Die Aktualisierung von Pfaden ist inkompatibel mit dem Wechsel " "von Zweigen." -#: builtin/checkout.c:1068 +#: builtin/checkout.c:1071 msgid "git checkout: --detach does not take a path argument" msgstr "git checkout: --detach nimmt kein Pfad-Argument" -#: builtin/checkout.c:1071 +#: builtin/checkout.c:1074 msgid "" "git checkout: --ours/--theirs, --force and --merge are incompatible when\n" "checking out of the index." @@ -2078,11 +2356,11 @@ msgstr "" "git checkout: --ours/--theirs, --force and --merge sind inkompatibel wenn\n" "du aus der Bereitstellung auscheckst." -#: builtin/checkout.c:1090 +#: builtin/checkout.c:1093 msgid "Cannot switch branch to a non-commit." msgstr "Kann Zweig nur zu einer Version wechseln." -#: builtin/checkout.c:1093 +#: builtin/checkout.c:1096 msgid "--ours/--theirs is incompatible with switching branches." msgstr "--ours/--theirs ist inkompatibel mit den Wechseln von Zweigen." @@ -2135,11 +2413,6 @@ msgstr "Entferne nicht %s\n" msgid "reference repository '%s' is not a local directory." msgstr "Referenziertes Projektarchiv '%s' ist kein lokales Verzeichnis." -#: builtin/clone.c:302 -#, c-format -msgid "failed to open '%s'" -msgstr "Fehler beim Öffnen von '%s'" - #: builtin/clone.c:306 #, c-format msgid "failed to create directory '%s'" @@ -2180,80 +2453,80 @@ msgstr "Konnte Datei nicht nach '%s' kopieren" msgid "done.\n" msgstr "Fertig.\n" -#: builtin/clone.c:440 +#: builtin/clone.c:443 #, c-format msgid "Could not find remote branch %s to clone." msgstr "Konnte zu klonenden externer Zweig %s nicht finden." -#: builtin/clone.c:549 +#: builtin/clone.c:552 msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n" msgstr "" "Externe Zweigspitze (HEAD) bezieht sich auf eine nicht existierende Referenz " "und kann nicht ausgecheckt werden.\n" -#: builtin/clone.c:639 +#: builtin/clone.c:642 msgid "Too many arguments." msgstr "Zu viele Argumente." -#: builtin/clone.c:643 +#: builtin/clone.c:646 msgid "You must specify a repository to clone." msgstr "Du musst ein Projektarchiv zum Klonen angeben." -#: builtin/clone.c:654 +#: builtin/clone.c:657 #, c-format msgid "--bare and --origin %s options are incompatible." msgstr "--bare und --origin %s Optionen sind inkompatibel." -#: builtin/clone.c:668 +#: builtin/clone.c:671 #, c-format msgid "repository '%s' does not exist" msgstr "Projektarchiv '%s' existiert nicht." -#: builtin/clone.c:673 +#: builtin/clone.c:676 msgid "--depth is ignored in local clones; use file:// instead." msgstr "--depth wird in lokalen Klonen ignoriert; benutze stattdessen file://." -#: builtin/clone.c:683 +#: builtin/clone.c:686 #, c-format msgid "destination path '%s' already exists and is not an empty directory." msgstr "Zielpfad '%s' existiert bereits und ist kein leeres Verzeichnis." -#: builtin/clone.c:693 +#: builtin/clone.c:696 #, c-format msgid "working tree '%s' already exists." msgstr "Arbeitsbaum '%s' existiert bereits." -#: builtin/clone.c:706 builtin/clone.c:720 +#: builtin/clone.c:709 builtin/clone.c:723 #, c-format msgid "could not create leading directories of '%s'" msgstr "Konnte führende Verzeichnisse von '%s' nicht erstellen." -#: builtin/clone.c:709 +#: builtin/clone.c:712 #, c-format msgid "could not create work tree dir '%s'." msgstr "Konnte Arbeitsverzeichnis '%s' nicht erstellen." -#: builtin/clone.c:728 +#: builtin/clone.c:731 #, c-format msgid "Cloning into bare repository '%s'...\n" msgstr "Klone in bloßes Projektarchiv '%s'...\n" -#: builtin/clone.c:730 +#: builtin/clone.c:733 #, c-format msgid "Cloning into '%s'...\n" msgstr "Klone nach '%s'...\n" -#: builtin/clone.c:786 +#: builtin/clone.c:789 #, c-format msgid "Don't know how to clone %s" msgstr "Weiß nicht wie %s zu klonen ist." -#: builtin/clone.c:835 +#: builtin/clone.c:838 #, c-format msgid "Remote branch %s not found in upstream %s" msgstr "externer Zweig %s nicht im anderen Projektarchiv %s gefunden" -#: builtin/clone.c:842 +#: builtin/clone.c:845 msgid "You appear to have cloned an empty repository." msgstr "Du scheinst ein leeres Projektarchiv geklont zu haben." @@ -2314,97 +2587,97 @@ msgstr "" "\n" "Andernfalls benutze bitte 'git reset'\n" -#: builtin/commit.c:253 +#: builtin/commit.c:256 msgid "failed to unpack HEAD tree object" msgstr "Fehler beim Entpacken des Baum-Objektes der Zweigspitze (HEAD)." -#: builtin/commit.c:295 +#: builtin/commit.c:298 msgid "unable to create temporary index" msgstr "Konnte temporäre Bereitstellung nicht erstellen." -#: builtin/commit.c:301 +#: builtin/commit.c:304 msgid "interactive add failed" msgstr "interaktives Hinzufügen fehlgeschlagen" -#: builtin/commit.c:334 builtin/commit.c:355 builtin/commit.c:405 +#: builtin/commit.c:337 builtin/commit.c:358 builtin/commit.c:408 msgid "unable to write new_index file" msgstr "Konnte new_index Datei nicht schreiben" -#: builtin/commit.c:386 +#: builtin/commit.c:389 msgid "cannot do a partial commit during a merge." msgstr "" "Kann keine partielle Eintragung durchführen, während eine Zusammenführung im " "Gange ist." -#: builtin/commit.c:388 +#: builtin/commit.c:391 msgid "cannot do a partial commit during a cherry-pick." msgstr "" "Kann keine partielle Eintragung durchführen, während \"cherry-pick\" im " "Gange ist." -#: builtin/commit.c:398 +#: builtin/commit.c:401 msgid "cannot read the index" msgstr "Kann Bereitstellung nicht lesen" -#: builtin/commit.c:418 +#: builtin/commit.c:421 msgid "unable to write temporary index file" msgstr "Konnte temporäre Bereitstellungsdatei nicht schreiben." -#: builtin/commit.c:493 builtin/commit.c:499 +#: builtin/commit.c:496 builtin/commit.c:502 #, c-format msgid "invalid commit: %s" msgstr "Ungültige Version: %s" -#: builtin/commit.c:522 +#: builtin/commit.c:525 msgid "malformed --author parameter" msgstr "Fehlerhafter --author Parameter" -#: builtin/commit.c:582 +#: builtin/commit.c:585 #, c-format msgid "Malformed ident string: '%s'" msgstr "Fehlerhafte Identifikations-String: '%s'" -#: builtin/commit.c:620 builtin/commit.c:653 builtin/commit.c:967 +#: builtin/commit.c:623 builtin/commit.c:656 builtin/commit.c:970 #, c-format msgid "could not lookup commit %s" msgstr "Konnte Version %s nicht nachschlagen" -#: builtin/commit.c:632 builtin/shortlog.c:296 +#: builtin/commit.c:635 builtin/shortlog.c:296 #, c-format msgid "(reading log message from standard input)\n" msgstr "(lese Log-Nachricht von Standard-Eingabe)\n" -#: builtin/commit.c:634 +#: builtin/commit.c:637 msgid "could not read log from standard input" msgstr "Konnte Log nicht von Standard-Eingabe lesen." -#: builtin/commit.c:638 +#: builtin/commit.c:641 #, c-format msgid "could not read log file '%s'" msgstr "Konnte Log-Datei '%s' nicht lesen" -#: builtin/commit.c:644 +#: builtin/commit.c:647 msgid "commit has empty message" msgstr "Version hat eine leere Beschreibung" -#: builtin/commit.c:660 +#: builtin/commit.c:663 msgid "could not read MERGE_MSG" msgstr "Konnte MERGE_MSG nicht lesen" -#: builtin/commit.c:664 +#: builtin/commit.c:667 msgid "could not read SQUASH_MSG" msgstr "Konnte SQUASH_MSG nicht lesen" -#: builtin/commit.c:668 +#: builtin/commit.c:671 #, c-format msgid "could not read '%s'" msgstr "Konnte '%s' nicht lesen" -#: builtin/commit.c:720 +#: builtin/commit.c:723 msgid "could not write commit template" msgstr "Konnte Versionsvorlage nicht schreiben" -#: builtin/commit.c:731 +#: builtin/commit.c:734 #, c-format msgid "" "\n" @@ -2419,7 +2692,7 @@ msgstr "" "\t%s\n" "und versuche es erneut.\n" -#: builtin/commit.c:736 +#: builtin/commit.c:739 #, c-format msgid "" "\n" @@ -2434,7 +2707,7 @@ msgstr "" "\t%s\n" "und versuche es erneut.\n" -#: builtin/commit.c:748 +#: builtin/commit.c:751 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be ignored, and an empty message aborts the commit.\n" @@ -2443,7 +2716,7 @@ msgstr "" "die mit '#' beginnen, werden ignoriert, und eine leere Versionsbeschreibung\n" "bricht die Eintragung ab.\n" -#: builtin/commit.c:753 +#: builtin/commit.c:756 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be kept; you may remove them yourself if you want to.\n" @@ -2454,171 +2727,171 @@ msgstr "" "entfernen.\n" "Eine leere Versionsbeschreibung bricht die Eintragung ab.\n" -#: builtin/commit.c:766 +#: builtin/commit.c:769 #, c-format msgid "%sAuthor: %s" msgstr "%sAutor: %s" -#: builtin/commit.c:773 +#: builtin/commit.c:776 #, c-format msgid "%sCommitter: %s" msgstr "%sEintragender: %s" -#: builtin/commit.c:793 +#: builtin/commit.c:796 msgid "Cannot read index" msgstr "Kann Bereitstellung nicht lesen" -#: builtin/commit.c:830 +#: builtin/commit.c:833 msgid "Error building trees" msgstr "Fehler beim Erzeugen der Zweige" -#: builtin/commit.c:845 builtin/tag.c:361 +#: builtin/commit.c:848 builtin/tag.c:361 #, c-format msgid "Please supply the message using either -m or -F option.\n" msgstr "Bitte liefere eine Beschreibung entweder mit der Option -m oder -F.\n" -#: builtin/commit.c:942 +#: builtin/commit.c:945 #, c-format msgid "No existing author found with '%s'" msgstr "Kein existierender Autor mit '%s' gefunden." -#: builtin/commit.c:957 builtin/commit.c:1157 +#: builtin/commit.c:960 builtin/commit.c:1160 #, c-format msgid "Invalid untracked files mode '%s'" msgstr "Ungültiger Modus '%s' für unbeobachtete Dateien" -#: builtin/commit.c:997 +#: builtin/commit.c:1000 msgid "Using both --reset-author and --author does not make sense" msgstr "Verwendung von --reset-author und --author macht keinen Sinn." -#: builtin/commit.c:1008 +#: builtin/commit.c:1011 msgid "You have nothing to amend." msgstr "Du hast nichts zum nachbessern." -#: builtin/commit.c:1011 +#: builtin/commit.c:1014 msgid "You are in the middle of a merge -- cannot amend." msgstr "Eine Zusammenführung ist im Gange -- kann nicht nachbessern." -#: builtin/commit.c:1013 +#: builtin/commit.c:1016 msgid "You are in the middle of a cherry-pick -- cannot amend." msgstr "\"cherry-pick\" ist im Gange -- kann nicht nachbessern." -#: builtin/commit.c:1016 +#: builtin/commit.c:1019 msgid "Options --squash and --fixup cannot be used together" msgstr "" "Die Optionen --squash und --fixup können nicht gemeinsam benutzt werden." -#: builtin/commit.c:1026 +#: builtin/commit.c:1029 msgid "Only one of -c/-C/-F/--fixup can be used." msgstr "Nur eines von -c/-C/-F/--fixup kann benutzt werden." -#: builtin/commit.c:1028 +#: builtin/commit.c:1031 msgid "Option -m cannot be combined with -c/-C/-F/--fixup." msgstr "Option -m kann nicht mit -c/-C/-F/--fixup kombiniert werden" -#: builtin/commit.c:1036 +#: builtin/commit.c:1039 msgid "--reset-author can be used only with -C, -c or --amend." msgstr "--reset--author kann nur mit -C, -c oder --amend benutzt werden" -#: builtin/commit.c:1053 +#: builtin/commit.c:1056 msgid "Only one of --include/--only/--all/--interactive/--patch can be used." msgstr "" "Nur eines von --include/--only/--all/--interactive/--patch kann benutzt " "werden." -#: builtin/commit.c:1055 +#: builtin/commit.c:1058 msgid "No paths with --include/--only does not make sense." msgstr "--include/--only machen ohne Pfade keinen Sinn." -#: builtin/commit.c:1057 +#: builtin/commit.c:1060 msgid "Clever... amending the last one with dirty index." msgstr "" "Klug... die letzte Version mit einer unsauberen Bereitstellung nachbessern." -#: builtin/commit.c:1059 +#: builtin/commit.c:1062 msgid "Explicit paths specified without -i nor -o; assuming --only paths..." msgstr "" "Explizite Pfade ohne -i oder -o angegeben; unter der Annahme von --only " "Pfaden..." -#: builtin/commit.c:1069 builtin/tag.c:577 +#: builtin/commit.c:1072 builtin/tag.c:577 #, c-format msgid "Invalid cleanup mode %s" msgstr "Ungültiger \"cleanup\" Modus %s" -#: builtin/commit.c:1074 +#: builtin/commit.c:1077 msgid "Paths with -a does not make sense." msgstr "Pfade mit -a machen keinen Sinn." -#: builtin/commit.c:1257 +#: builtin/commit.c:1260 msgid "couldn't look up newly created commit" msgstr "Konnte neu erstellte Version nicht nachschlagen." -#: builtin/commit.c:1259 +#: builtin/commit.c:1262 msgid "could not parse newly created commit" msgstr "Konnte neulich erstellte Version nicht analysieren." -#: builtin/commit.c:1300 +#: builtin/commit.c:1303 msgid "detached HEAD" msgstr "losgelöste Zweigspitze (HEAD)" -#: builtin/commit.c:1302 +#: builtin/commit.c:1305 msgid " (root-commit)" msgstr " (Basis-Version)" -#: builtin/commit.c:1446 +#: builtin/commit.c:1449 msgid "could not parse HEAD commit" msgstr "Konnte Version der Zweigspitze (HEAD) nicht analysieren." -#: builtin/commit.c:1484 builtin/merge.c:509 +#: builtin/commit.c:1487 builtin/merge.c:509 #, c-format msgid "could not open '%s' for reading" msgstr "Konnte '%s' nicht zum Lesen öffnen." -#: builtin/commit.c:1491 +#: builtin/commit.c:1494 #, c-format msgid "Corrupt MERGE_HEAD file (%s)" msgstr "Beschädigte MERGE_HEAD-Datei (%s)" -#: builtin/commit.c:1498 +#: builtin/commit.c:1501 msgid "could not read MERGE_MODE" msgstr "Konnte MERGE_MODE nicht lesen" -#: builtin/commit.c:1517 +#: builtin/commit.c:1520 #, c-format msgid "could not read commit message: %s" msgstr "Konnte Versionsbeschreibung nicht lesen: %s" -#: builtin/commit.c:1531 +#: builtin/commit.c:1534 #, c-format msgid "Aborting commit; you did not edit the message.\n" msgstr "Eintragung abgebrochen; du hast die Beschreibung nicht editiert.\n" -#: builtin/commit.c:1536 +#: builtin/commit.c:1539 #, c-format msgid "Aborting commit due to empty commit message.\n" msgstr "Eintragung aufgrund leerer Versionsbeschreibung abgebrochen.\n" -#: builtin/commit.c:1551 builtin/merge.c:936 builtin/merge.c:961 +#: builtin/commit.c:1554 builtin/merge.c:936 builtin/merge.c:961 msgid "failed to write commit object" msgstr "Fehler beim Schreiben des Versionsobjektes." -#: builtin/commit.c:1572 +#: builtin/commit.c:1575 msgid "cannot lock HEAD ref" msgstr "Kann Referenz der Zweigspitze (HEAD) nicht sperren." -#: builtin/commit.c:1576 +#: builtin/commit.c:1579 msgid "cannot update HEAD ref" msgstr "Kann Referenz der Zweigspitze (HEAD) nicht aktualisieren." -#: builtin/commit.c:1587 +#: builtin/commit.c:1590 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 "" "Das Projektarchiv wurde aktualisiert, aber die \"new_index\"-Datei\n" -"konnte nicht geschrieben werden. Prüfe, dass dein Speicher nicht\n" +"konnte nicht geschrieben werden. Prüfe, dass deine Festplatte nicht\n" "voll und Dein Kontingent nicht aufgebraucht ist und führe\n" "anschließend \"git reset HEAD\" zu Wiederherstellung aus." @@ -2994,30 +3267,30 @@ msgstr "" msgid "both --cached and trees are given." msgstr "sowohl --cached als auch Zweige gegeben" -#: builtin/help.c:63 +#: builtin/help.c:65 #, c-format msgid "unrecognized help format '%s'" msgstr "nicht erkanntes Hilfeformat: %s" -#: builtin/help.c:91 +#: builtin/help.c:93 msgid "Failed to start emacsclient." msgstr "Konnte emacsclient nicht starten." -#: builtin/help.c:104 +#: builtin/help.c:106 msgid "Failed to parse emacsclient version." msgstr "Konnte Version des emacsclient nicht parsen." -#: builtin/help.c:112 +#: builtin/help.c:114 #, c-format msgid "emacsclient version '%d' too old (< 22)." msgstr "Version des emacsclient '%d' ist zu alt (< 22)." -#: builtin/help.c:130 builtin/help.c:158 builtin/help.c:167 builtin/help.c:175 +#: builtin/help.c:132 builtin/help.c:160 builtin/help.c:169 builtin/help.c:177 #, c-format msgid "failed to exec '%s': %s" msgstr "Fehler beim Ausführen von '%s': %s" -#: builtin/help.c:215 +#: builtin/help.c:217 #, c-format msgid "" "'%s': path for unsupported man viewer.\n" @@ -3026,7 +3299,7 @@ msgstr "" "'%s': Pfad für nicht unterstützten Handbuchbetrachter.\n" "Du könntest stattdessen 'man.<Werkzeug>.cmd' benutzen." -#: builtin/help.c:227 +#: builtin/help.c:229 #, c-format msgid "" "'%s': cmd for supported man viewer.\n" @@ -3035,34 +3308,29 @@ msgstr "" "'%s': Kommando für unterstützten Handbuchbetrachter.\n" "Du könntest stattdessen 'man.<Werkzeug>.path' benutzen." -#: builtin/help.c:291 +#: builtin/help.c:299 msgid "The most commonly used git commands are:" msgstr "Die allgemein verwendeten Git-Kommandos sind:" -#: builtin/help.c:359 +#: builtin/help.c:367 #, c-format msgid "'%s': unknown man viewer." msgstr "'%s': unbekannter Handbuch-Betrachter." -#: builtin/help.c:376 +#: builtin/help.c:384 msgid "no man viewer handled the request" msgstr "kein Handbuch-Betrachter konnte mit dieser Anfrage umgehen" -#: builtin/help.c:384 +#: builtin/help.c:392 msgid "no info viewer handled the request" msgstr "kein Informations-Betrachter konnte mit dieser Anfrage umgehen" -#: builtin/help.c:395 -#, c-format -msgid "'%s': not a documentation directory." -msgstr "'%s' ist kein Dokumentationsverzeichnis" - -#: builtin/help.c:436 builtin/help.c:443 +#: builtin/help.c:447 builtin/help.c:454 #, c-format msgid "usage: %s%s" msgstr "Verwendung: %s%s" -#: builtin/help.c:459 +#: builtin/help.c:470 #, c-format msgid "`git %s' is aliased to `%s'" msgstr "für `git %s' wurde der Alias `%s' angelegt" @@ -3137,176 +3405,176 @@ msgstr "" msgid "unknown object type %d" msgstr "Unbekannter Objekt-Typ %d" -#: builtin/index-pack.c:531 +#: builtin/index-pack.c:530 msgid "cannot pread pack file" msgstr "Kann Paketdatei %s nicht lesen" -#: builtin/index-pack.c:533 +#: builtin/index-pack.c:532 #, c-format msgid "premature end of pack file, %lu byte missing" msgid_plural "premature end of pack file, %lu bytes missing" msgstr[0] "frühzeitiges Ende der Paketdatei, vermisse %lu Byte" msgstr[1] "frühzeitiges Ende der Paketdatei, vermisse %lu Bytes" -#: builtin/index-pack.c:555 +#: builtin/index-pack.c:558 msgid "serious inflate inconsistency" msgstr "ernsthafte Inkonsistenz nach Dekomprimierung" -#: builtin/index-pack.c:646 builtin/index-pack.c:652 builtin/index-pack.c:675 -#: builtin/index-pack.c:709 builtin/index-pack.c:718 +#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678 +#: builtin/index-pack.c:712 builtin/index-pack.c:721 #, c-format msgid "SHA1 COLLISION FOUND WITH %s !" msgstr "SHA1 KOLLISION MIT %s GEFUNDEN !" -#: builtin/index-pack.c:649 builtin/pack-objects.c:170 +#: builtin/index-pack.c:652 builtin/pack-objects.c:170 #: builtin/pack-objects.c:262 #, c-format msgid "unable to read %s" msgstr "kann %s nicht lesen" -#: builtin/index-pack.c:715 +#: builtin/index-pack.c:718 #, c-format msgid "cannot read existing object %s" msgstr "Kann existierendes Objekt %s nicht lesen." -#: builtin/index-pack.c:729 +#: builtin/index-pack.c:732 #, c-format msgid "invalid blob object %s" msgstr "ungültiges Blob-Objekt %s" -#: builtin/index-pack.c:744 +#: builtin/index-pack.c:747 #, c-format msgid "invalid %s" msgstr "Ungültiger Objekt-Typ %s" -#: builtin/index-pack.c:746 +#: builtin/index-pack.c:749 msgid "Error in object" msgstr "Fehler in Objekt" -#: builtin/index-pack.c:748 +#: builtin/index-pack.c:751 #, c-format msgid "Not all child objects of %s are reachable" msgstr "Nicht alle Kind-Objekte von %s sind erreichbar" -#: builtin/index-pack.c:818 builtin/index-pack.c:844 +#: builtin/index-pack.c:821 builtin/index-pack.c:847 msgid "failed to apply delta" msgstr "Konnte Dateiunterschied nicht anwenden" -#: builtin/index-pack.c:983 +#: builtin/index-pack.c:986 msgid "Receiving objects" msgstr "Empfange Objekte" -#: builtin/index-pack.c:983 +#: builtin/index-pack.c:986 msgid "Indexing objects" msgstr "Indiziere Objekte" -#: builtin/index-pack.c:1009 +#: builtin/index-pack.c:1012 msgid "pack is corrupted (SHA1 mismatch)" msgstr "Paket ist beschädigt (SHA1 unterschiedlich)" -#: builtin/index-pack.c:1014 +#: builtin/index-pack.c:1017 msgid "cannot fstat packfile" msgstr "kann Paketdatei nicht lesen" -#: builtin/index-pack.c:1017 +#: builtin/index-pack.c:1020 msgid "pack has junk at the end" msgstr "Paketende enthält nicht verwendbaren Inhalt" -#: builtin/index-pack.c:1028 +#: builtin/index-pack.c:1031 msgid "confusion beyond insanity in parse_pack_objects()" msgstr "Fehler beim Ausführen von \"parse_pack_objects()\"" -#: builtin/index-pack.c:1051 +#: builtin/index-pack.c:1054 msgid "Resolving deltas" msgstr "Löse Unterschiede auf" -#: builtin/index-pack.c:1102 +#: builtin/index-pack.c:1105 msgid "confusion beyond insanity" msgstr "Fehler beim Auflösen der Unterschiede" -#: builtin/index-pack.c:1121 +#: builtin/index-pack.c:1124 #, c-format msgid "pack has %d unresolved delta" msgid_plural "pack has %d unresolved deltas" msgstr[0] "Paket hat %d unaufgelöste Unterschied" msgstr[1] "Paket hat %d unaufgelöste Unterschiede" -#: builtin/index-pack.c:1146 +#: builtin/index-pack.c:1149 #, c-format msgid "unable to deflate appended object (%d)" msgstr "Konnte angehängtes Objekt (%d) nicht komprimieren" -#: builtin/index-pack.c:1225 +#: builtin/index-pack.c:1228 #, c-format msgid "local object %s is corrupt" msgstr "lokales Objekt %s ist beschädigt" -#: builtin/index-pack.c:1249 +#: builtin/index-pack.c:1252 msgid "error while closing pack file" msgstr "Fehler beim Schließen der Paketdatei" -#: builtin/index-pack.c:1262 +#: builtin/index-pack.c:1265 #, c-format msgid "cannot write keep file '%s'" msgstr "Kann Paketbeschreibungsdatei '%s' nicht schreiben" -#: builtin/index-pack.c:1270 +#: builtin/index-pack.c:1273 #, c-format msgid "cannot close written keep file '%s'" msgstr "Kann eben erstellte Paketbeschreibungsdatei '%s' nicht schließen" -#: builtin/index-pack.c:1283 +#: builtin/index-pack.c:1286 msgid "cannot store pack file" msgstr "Kann Paketdatei nicht speichern" -#: builtin/index-pack.c:1294 +#: builtin/index-pack.c:1297 msgid "cannot store index file" msgstr "Kann Indexdatei nicht speichern" -#: builtin/index-pack.c:1395 +#: builtin/index-pack.c:1398 #, c-format msgid "Cannot open existing pack file '%s'" msgstr "Kann existierende Paketdatei '%s' nicht öffnen" -#: builtin/index-pack.c:1397 +#: builtin/index-pack.c:1400 #, c-format msgid "Cannot open existing pack idx file for '%s'" msgstr "Kann existierende Indexdatei für Paket '%s' nicht öffnen" -#: builtin/index-pack.c:1444 +#: builtin/index-pack.c:1447 #, c-format msgid "non delta: %d object" msgid_plural "non delta: %d objects" msgstr[0] "kein Unterschied: %d Objekt" msgstr[1] "kein Unterschied: %d Objekte" -#: builtin/index-pack.c:1451 +#: builtin/index-pack.c:1454 #, c-format msgid "chain length = %d: %lu object" msgid_plural "chain length = %d: %lu objects" msgstr[0] "Länge der Objekt-Liste = %d: %lu Objekt" msgstr[1] "Länge der Objekt-Liste = %d: %lu Objekte" -#: builtin/index-pack.c:1478 +#: builtin/index-pack.c:1481 msgid "Cannot come back to cwd" msgstr "Kann nicht zurück zu Arbeitsverzeichnis wechseln" -#: builtin/index-pack.c:1522 builtin/index-pack.c:1525 -#: builtin/index-pack.c:1537 builtin/index-pack.c:1541 +#: builtin/index-pack.c:1525 builtin/index-pack.c:1528 +#: builtin/index-pack.c:1540 builtin/index-pack.c:1544 #, c-format msgid "bad %s" msgstr "%s ist ungültig" -#: builtin/index-pack.c:1555 +#: builtin/index-pack.c:1558 msgid "--fix-thin cannot be used without --stdin" msgstr "--fix-thin kann nicht ohne --stdin benutzt werden" -#: builtin/index-pack.c:1559 builtin/index-pack.c:1569 +#: builtin/index-pack.c:1562 builtin/index-pack.c:1572 #, c-format msgid "packfile name '%s' does not end with '.pack'" msgstr "Name der Paketdatei '%s' endet nicht mit '.pack'" -#: builtin/index-pack.c:1578 +#: builtin/index-pack.c:1581 msgid "--verify with no packfile name given" msgstr "--verify ohne Name der Paketdatei angegeben" @@ -3380,22 +3648,22 @@ msgstr "kopiere keine Vorlagen mit einer falschen Formatversion %d von '%s'" msgid "insane git directory %s" msgstr "ungültiges Git-Verzeichnis %s" -#: builtin/init-db.c:322 builtin/init-db.c:325 +#: builtin/init-db.c:323 builtin/init-db.c:326 #, c-format msgid "%s already exists" msgstr "%s existiert bereits" -#: builtin/init-db.c:354 +#: builtin/init-db.c:355 #, c-format msgid "unable to handle file type %d" msgstr "kann nicht mit Dateityp %d umgehen" -#: builtin/init-db.c:357 +#: builtin/init-db.c:358 #, c-format msgid "unable to move %s to %s" msgstr "Konnte %s nicht nach %s verschieben" -#: builtin/init-db.c:362 +#: builtin/init-db.c:363 #, c-format msgid "Could not create git link %s" msgstr "Konnte git-Verknüfung %s nicht erstellen" @@ -3405,38 +3673,38 @@ msgstr "Konnte git-Verknüfung %s nicht erstellen" #. * existing" or "Initialized empty", the second " shared" or #. * "", and the last '%s%s' is the verbatim directory name. #. -#: builtin/init-db.c:419 +#: builtin/init-db.c:420 #, c-format msgid "%s%s Git repository in %s%s\n" msgstr "%s%s Git-Projektarchiv in %s%s\n" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Reinitialized existing" msgstr "Reinitialisierte existierendes" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Initialized empty" msgstr "Initialisierte leeres" -#: builtin/init-db.c:421 +#: builtin/init-db.c:422 msgid " shared" msgstr " gemeinsames" -#: builtin/init-db.c:440 +#: builtin/init-db.c:441 msgid "cannot tell cwd" msgstr "kann aktuelles Arbeitsverzeichnis nicht ermitteln" -#: builtin/init-db.c:521 builtin/init-db.c:528 +#: builtin/init-db.c:522 builtin/init-db.c:529 #, c-format msgid "cannot mkdir %s" msgstr "kann Verzeichnis %s nicht erstellen" -#: builtin/init-db.c:532 +#: builtin/init-db.c:533 #, c-format msgid "cannot chdir to %s" msgstr "kann nicht in Verzeichnis %s wechseln" -#: builtin/init-db.c:554 +#: builtin/init-db.c:555 #, c-format msgid "" "%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-" @@ -3445,11 +3713,11 @@ msgstr "" "%s (oder --work-tree=<Verzeichnis>) nicht erlaubt ohne Spezifizierung von %s " "(oder --git-dir=<Verzeichnis>)" -#: builtin/init-db.c:578 +#: builtin/init-db.c:579 msgid "Cannot access current working directory" msgstr "Kann nicht auf aktuelles Arbeitsverzeichnis zugreifen." -#: builtin/init-db.c:585 +#: builtin/init-db.c:586 #, c-format msgid "Cannot access work tree '%s'" msgstr "Kann nicht auf Arbeitsbaum '%s' zugreifen." @@ -3459,89 +3727,89 @@ msgstr "Kann nicht auf Arbeitsbaum '%s' zugreifen." msgid "Final output: %d %s\n" msgstr "letzte Ausgabe: %d %s\n" -#: builtin/log.c:402 builtin/log.c:490 +#: builtin/log.c:403 builtin/log.c:494 #, c-format msgid "Could not read object %s" msgstr "Kann Objekt %s nicht lesen." -#: builtin/log.c:514 +#: builtin/log.c:518 #, c-format msgid "Unknown type: %d" msgstr "Unbekannter Typ: %d" -#: builtin/log.c:603 +#: builtin/log.c:608 msgid "format.headers without value" msgstr "format.headers ohne Wert" -#: builtin/log.c:677 +#: builtin/log.c:682 msgid "name of output directory is too long" msgstr "Name des Ausgabeverzeichnisses ist zu lang." -#: builtin/log.c:688 +#: builtin/log.c:693 #, c-format msgid "Cannot open patch file %s" msgstr "Kann Patch-Datei %s nicht öffnen" -#: builtin/log.c:702 +#: builtin/log.c:707 msgid "Need exactly one range." msgstr "Brauche genau einen Versionsbereich." -#: builtin/log.c:710 +#: builtin/log.c:715 msgid "Not a range." msgstr "Kein Versionsbereich." -#: builtin/log.c:787 +#: builtin/log.c:792 msgid "Cover letter needs email format" msgstr "Anschreiben benötigt E-Mail-Format" -#: builtin/log.c:860 +#: builtin/log.c:865 #, c-format msgid "insane in-reply-to: %s" msgstr "ungültiges in-reply-to: %s" -#: builtin/log.c:933 +#: builtin/log.c:938 msgid "Two output directories?" msgstr "Zwei Ausgabeverzeichnisse?" -#: builtin/log.c:1154 +#: builtin/log.c:1160 #, c-format msgid "bogus committer info %s" msgstr "unechte Einreicher-Informationen %s" -#: builtin/log.c:1199 +#: builtin/log.c:1205 msgid "-n and -k are mutually exclusive." msgstr "-n und -k schliessen sich gegenseitig aus" -#: builtin/log.c:1201 +#: builtin/log.c:1207 msgid "--subject-prefix and -k are mutually exclusive." msgstr "--subject-prefix und -k schliessen sich gegenseitig aus" -#: builtin/log.c:1209 +#: builtin/log.c:1215 msgid "--name-only does not make sense" msgstr "--name-only macht keinen Sinn" -#: builtin/log.c:1211 +#: builtin/log.c:1217 msgid "--name-status does not make sense" msgstr "--name-status macht keinen Sinn" -#: builtin/log.c:1213 +#: builtin/log.c:1219 msgid "--check does not make sense" msgstr "--check macht keinen Sinn" -#: builtin/log.c:1236 +#: builtin/log.c:1242 msgid "standard output, or directory, which one?" msgstr "Standard-Ausgabe oder Verzeichnis, welches von beidem?" -#: builtin/log.c:1238 +#: builtin/log.c:1244 #, c-format msgid "Could not create directory '%s'" msgstr "Konnte Verzeichnis '%s' nicht erstellen." -#: builtin/log.c:1391 +#: builtin/log.c:1397 msgid "Failed to create output files" msgstr "Fehler beim Erstellen der Ausgabedateien." -#: builtin/log.c:1495 +#: builtin/log.c:1501 #, c-format msgid "" "Could not find a tracked remote branch, please specify <upstream> manually.\n" @@ -3549,7 +3817,7 @@ msgstr "" "Konnte gefolgten, externen Zweig nicht finden, bitte gebe <upstream> manuell " "an.\n" -#: builtin/log.c:1511 builtin/log.c:1513 builtin/log.c:1525 +#: builtin/log.c:1517 builtin/log.c:1519 builtin/log.c:1531 #, c-format msgid "Unknown commit %s" msgstr "Unbekannte Version %s" @@ -3632,10 +3900,6 @@ msgstr "\"git write-tree\" schlug beim Schreiben eines Baumes fehl" msgid "failed to read the cache" msgstr "Lesen des Zwischenspeichers fehlgeschlagen" -#: builtin/merge.c:697 -msgid "Unable to write index." -msgstr "Konnte Bereitstellung nicht schreiben." - #: builtin/merge.c:710 msgid "Not handling anything other than two heads merge." msgstr "Es wird nur die Zusammenführung von zwei Zweigen behandelt." @@ -4694,31 +4958,31 @@ msgstr "" "Kann keine '%s' Zurücksetzung durchführen, während eine Zusammenführung im " "Gange ist." -#: builtin/reset.c:297 +#: builtin/reset.c:303 #, c-format msgid "Could not parse object '%s'." msgstr "Konnte Objekt '%s' nicht parsen." -#: builtin/reset.c:302 +#: builtin/reset.c:308 msgid "--patch is incompatible with --{hard,mixed,soft}" msgstr "--patch ist inkompatibel mit --{hard,mixed,soft}" -#: builtin/reset.c:311 +#: builtin/reset.c:317 msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead." msgstr "" "--mixed mit Pfaden ist veraltet; benutze stattdessen 'git reset -- <Pfade>'." -#: builtin/reset.c:313 +#: builtin/reset.c:319 #, c-format msgid "Cannot do %s reset with paths." msgstr "Eine '%s' Zurücksetzung mit Pfaden ist nicht möglich." -#: builtin/reset.c:325 +#: builtin/reset.c:331 #, c-format msgid "%s reset is not allowed in a bare repository" msgstr "'%s' Zurücksetzung ist in einem bloßen Projektarchiv nicht erlaubt" -#: builtin/reset.c:341 +#: builtin/reset.c:347 #, c-format msgid "Could not reset index file to revision '%s'." msgstr "Konnte Bereitstellungsdatei nicht zu Version '%s' zurücksetzen." @@ -5069,11 +5333,11 @@ msgstr "" #: git-am.sh:105 #, sh-format msgid "" -"When you have resolved this problem run \"$cmdline --resolved\".\n" -"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n" -"To restore the original branch and stop patching run \"$cmdline --abort\"." +"When you have resolved this problem, run \"$cmdline --resolved\".\n" +"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n" +"To restore the original branch and stop patching, run \"$cmdline --abort\"." msgstr "" -"Wenn du das Problem aufgelöst hast, führe \"$cmdline --resolved\" aus.\n" +"Wenn du das Problem gelöst hast, führe \"$cmdline --resolved\" aus.\n" "Falls du diesen Patch auslassen möchtest, führe stattdessen \"$cmdline --skip" "\" aus.\n" "Um den ursprünglichen Zweig wiederherzustellen und die Anwendung der " @@ -5090,6 +5354,12 @@ msgstr "" "Dem Projektarchiv fehlen notwendige Blobs um auf eine 3-Wege-Zusammenführung " "zurückzufallen." +#: git-am.sh:139 +msgid "Using index info to reconstruct a base tree..." +msgstr "" +"Verwende Informationen aus der Bereitstellung um einen Basisbaum " +"nachzustellen" + #: git-am.sh:154 msgid "" "Did you hand edit your patch?\n" @@ -5102,45 +5372,53 @@ msgstr "" msgid "Falling back to patching base and 3-way merge..." msgstr "Falle zurück zum Patchen der Basis und der 3-Wege-Zusammenführung..." -#: git-am.sh:275 +#: git-am.sh:179 +msgid "Failed to merge in the changes." +msgstr "Zusammenführung der Änderungen fehlgeschlagen" + +#: git-am.sh:274 msgid "Only one StGIT patch series can be applied at once" msgstr "Es kann nur eine StGIT Patch-Serie auf einmal angewendet werden." -#: git-am.sh:362 +#: git-am.sh:361 #, sh-format msgid "Patch format $patch_format is not supported." msgstr "Patch-Format $patch_format wird nicht unterstützt." -#: git-am.sh:364 +#: git-am.sh:363 msgid "Patch format detection failed." msgstr "Patch-Formaterkennung fehlgeschlagen." -#: git-am.sh:418 -msgid "-d option is no longer supported. Do not use." -msgstr "-d Option wird nicht länger unterstützt. Nicht benutzen." +#: git-am.sh:389 +msgid "" +"The -b/--binary option has been a no-op for long time, and\n" +"it will be removed. Please do not use it anymore." +msgstr "" +"Die -b/--binary Option hat seit Langem keinen Effekt und wird\n" +"entfernt. Bitte nicht mehr verwenden." -#: git-am.sh:481 +#: git-am.sh:477 #, sh-format msgid "previous rebase directory $dotest still exists but mbox given." msgstr "" "Vorheriges Verzeichnis des Neuaufbaus $dotest existiert noch, aber mbox " "gegeben." -#: git-am.sh:486 +#: git-am.sh:482 msgid "Please make up your mind. --skip or --abort?" msgstr "Bitte werde dir klar. --skip oder --abort?" -#: git-am.sh:513 +#: git-am.sh:509 msgid "Resolve operation not in progress, we are not resuming." msgstr "Es ist keine Auflösung im Gange, es wird nicht fortgesetzt." -#: git-am.sh:579 +#: git-am.sh:575 #, sh-format msgid "Dirty index: cannot apply patches (dirty: $files)" msgstr "" "Unsaubere Bereitstellung: kann Patches nicht anwenden (unsauber: $files)" -#: git-am.sh:671 +#: git-am.sh:679 #, sh-format msgid "" "Patch is empty. Was it split wrong?\n" @@ -5154,33 +5432,33 @@ msgstr "" "Patches\n" "abzubrechen, führe \"$cmdline --abort\" aus." -#: git-am.sh:708 +#: git-am.sh:706 msgid "Patch does not have a valid e-mail address." msgstr "Patch enthält keine gültige eMail-Adresse." -#: git-am.sh:755 +#: git-am.sh:753 msgid "cannot be interactive without stdin connected to a terminal." msgstr "" "Kann nicht interaktiv sein, ohne dass die Standard-Eingabe mit einem " "Terminal verbunden ist." -#: git-am.sh:759 +#: git-am.sh:757 msgid "Commit Body is:" msgstr "Beschreibung der Eintragung ist:" #. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a] #. in your translation. The program will only accept English #. input at this point. -#: git-am.sh:766 +#: git-am.sh:764 msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " msgstr "Anwenden? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " -#: git-am.sh:802 +#: git-am.sh:800 #, sh-format msgid "Applying: $FIRSTLINE" msgstr "Wende an: $FIRSTLINE" -#: git-am.sh:823 +#: git-am.sh:821 msgid "" "No changes - did you forget to use 'git add'?\n" "If there is nothing left to stage, chances are that something else\n" @@ -5191,7 +5469,7 @@ msgstr "" "diese bereits anderweitig eingefügt worden sein; du könntest diesen Patch\n" "auslassen." -#: git-am.sh:831 +#: git-am.sh:829 msgid "" "You still have unmerged paths in your index\n" "did you forget to use 'git add'?" @@ -5199,16 +5477,16 @@ msgstr "" "Du hast immer noch nicht zusammengeführte Pfade in der Bereitstellung.\n" "Hast du vergessen 'git add' zu benutzen?" -#: git-am.sh:847 +#: git-am.sh:845 msgid "No changes -- Patch already applied." msgstr "Keine Änderungen -- Patches bereits angewendet." -#: git-am.sh:857 +#: git-am.sh:855 #, sh-format msgid "Patch failed at $msgnum $FIRSTLINE" msgstr "Anwendung des Patches fehlgeschlagen bei $msgnum $FIRSTLINE" -#: git-am.sh:873 +#: git-am.sh:876 msgid "applying to an empty history" msgstr "wende zu leerer Historie an" @@ -5413,6 +5691,131 @@ msgstr "Kann nicht mehrere Zweige in einen ungeborenen Zweig zusammenführen" msgid "Cannot rebase onto multiple branches" msgstr "kann nicht auf mehrere Zweige neu aufbauen" +#: git-rebase.sh:52 +msgid "" +"When you have resolved this problem, run \"git rebase --continue\".\n" +"If you prefer to skip this patch, run \"git rebase --skip\" instead.\n" +"To check out the original branch and stop rebasing, run \"git rebase --abort" +"\"." +msgstr "" +"Wenn du das Problem aufgelöst hast, führe \"git rebase --continue\" aus.\n" +"Falls du diesen Patch auslassen möchtest, führe stattdessen \"git rebase --" +"skip\" aus.\n" +"Um den ursprünglichen Zweig wiederherzustellen und den Neuaufbau " +"abzubrechen,\n" +"führe \"git rebase --abort\" aus." + +#: git-rebase.sh:159 +msgid "The pre-rebase hook refused to rebase." +msgstr "Der \"pre-rebase hook\" hat den Neuaufbau zurückgewiesen." + +#: git-rebase.sh:164 +msgid "It looks like git-am is in progress. Cannot rebase." +msgstr "\"git-am\" scheint im Gange zu sein. Kann nicht neu aufbauen." + +#: git-rebase.sh:295 +msgid "The --exec option must be used with the --interactive option" +msgstr "Die --exec Option muss mit der --interactive Option benutzt werden" + +#: git-rebase.sh:300 +msgid "No rebase in progress?" +msgstr "Kein Neuaufbau im Gange?" + +#: git-rebase.sh:313 +msgid "Cannot read HEAD" +msgstr "Kann Zweigspitze (HEAD) nicht lesen" + +#: git-rebase.sh:316 +msgid "" +"You must edit all merge conflicts and then\n" +"mark them as resolved using git add" +msgstr "" +"Du musst alle Zusammenführungskonflikte editieren und diese dann\n" +"mittels \"git add\" als aufgelöst markieren" + +#: git-rebase.sh:334 +#, sh-format +msgid "Could not move back to $head_name" +msgstr "Konnte nicht zu $head_name zurückgehen" + +#: git-rebase.sh:350 +#, sh-format +msgid "" +"It seems that there is already a $state_dir_base directory, and\n" +"I wonder if you are in the middle of another rebase. If that is the\n" +"case, please try\n" +"\t$cmd_live_rebase\n" +"If that is not the case, please\n" +"\t$cmd_clear_stale_rebase\n" +"and run me again. I am stopping in case you still have something\n" +"valuable there." +msgstr "" +"Es scheint so, als gäbe es das Verzeichnis $state_dir_base bereits, und\n" +"es wäre verwunderlich, wenn ein Neuaufbau bereits im Gange ist. Wenn das\n" +"der Fall ist, probiere bitte\n" +"\t$cmd_live_rebase\n" +"Wenn das nicht der Fall ist, probiere bitte\n" +"\t$cmd_clear_stale_rebase\n" +"und führe dieses Kommando nochmal aus. Es wird angehalten, falls bereits\n" +"etwas Nützliches vorhanden ist." + +#: git-rebase.sh:395 +#, sh-format +msgid "invalid upstream $upstream_name" +msgstr "ungültiger Übernahmezweig $upstream_name" + +#: git-rebase.sh:419 +#, sh-format +msgid "$onto_name: there are more than one merge bases" +msgstr "$onto_name: es gibt mehr als eine Zusammenführungsbasis" + +#: git-rebase.sh:422 git-rebase.sh:426 +#, sh-format +msgid "$onto_name: there is no merge base" +msgstr "$onto_name: es gibt keine Zusammenführungsbasis" + +#: git-rebase.sh:431 +#, sh-format +msgid "Does not point to a valid commit: $onto_name" +msgstr "$onto_name zeigt auf keine gültige Version" + +#: git-rebase.sh:454 +#, sh-format +msgid "fatal: no such branch: $branch_name" +msgstr "fatal: Zweig $branch_name nicht gefunden" + +#: git-rebase.sh:474 +msgid "Please commit or stash them." +msgstr "Bitte trage die Änderungen ein oder benutze \"stash\"." + +#: git-rebase.sh:492 +#, sh-format +msgid "Current branch $branch_name is up to date." +msgstr "Aktueller Zweig $branch_name ist auf dem neusten Stand." + +#: git-rebase.sh:495 +#, sh-format +msgid "Current branch $branch_name is up to date, rebase forced." +msgstr "" +"Aktueller Zweig $branch_name ist auf dem neusten Stand, Neuaufbau erzwungen." + +#: git-rebase.sh:506 +#, sh-format +msgid "Changes from $mb to $onto:" +msgstr "Änderungen von $mb zu $onto:" + +#. Detach HEAD and reset the tree +#: git-rebase.sh:515 +msgid "First, rewinding head to replay your work on top of it..." +msgstr "" +"Zunächst wird die Zweigspitze zurückgespult, um deine Änderungen\n" +"darauf neu anzuwenden..." + +#: git-rebase.sh:523 +#, sh-format +msgid "Fast-forwarded $branch_name to $onto_name." +msgstr "$branch_name zu $onto_name vorgespult." + #: git-stash.sh:51 msgid "git stash clear with parameters is unimplemented" msgstr "git stash clear mit Parametern ist nicht implementiert" @@ -5555,28 +5958,28 @@ msgid "No submodule mapping found in .gitmodules for path '$sm_path'" msgstr "" "Keine Unterprojekt-Zuordnung in .gitmodules für Pfad '$sm_path' gefunden" -#: git-submodule.sh:186 +#: git-submodule.sh:189 #, sh-format msgid "Clone of '$url' into submodule path '$sm_path' failed" msgstr "Klonen von '$url' in Unterprojekt-Pfad '$sm_path' fehlgeschlagen" -#: git-submodule.sh:196 +#: git-submodule.sh:201 #, sh-format msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa" msgstr "" "Git-Verzeichnis '$a' ist Teil des Unterprojekt-Pfades '$b', oder umgekehrt" -#: git-submodule.sh:285 +#: git-submodule.sh:290 #, sh-format msgid "repo URL: '$repo' must be absolute or begin with ./|../" msgstr "repo URL: '$repo' muss absolut sein oder mit ./|../ beginnen" -#: git-submodule.sh:302 +#: git-submodule.sh:307 #, sh-format msgid "'$sm_path' already exists in the index" msgstr "'$sm_path' existiert bereits in der Bereitstellung" -#: git-submodule.sh:306 +#: git-submodule.sh:311 #, sh-format msgid "" "The following path is ignored by one of your .gitignore files:\n" @@ -5587,65 +5990,65 @@ msgstr "" "$sm_path\n" "Benutze -f wenn du diesen wirklich hinzufügen möchtest." -#: git-submodule.sh:317 +#: git-submodule.sh:322 #, sh-format msgid "Adding existing repo at '$sm_path' to the index" msgstr "" "Füge existierendes Projektarchiv in '$sm_path' der Bereitstellung hinzu." -#: git-submodule.sh:319 +#: git-submodule.sh:324 #, sh-format msgid "'$sm_path' already exists and is not a valid git repo" msgstr "'$sm_path' existiert bereits und ist kein gültiges Git-Projektarchiv" -#: git-submodule.sh:333 +#: git-submodule.sh:338 #, sh-format msgid "Unable to checkout submodule '$sm_path'" msgstr "Unfähig Unterprojekt '$sm_path' auszuchecken" -#: git-submodule.sh:338 +#: git-submodule.sh:343 #, sh-format msgid "Failed to add submodule '$sm_path'" msgstr "Hinzufügen von Unterprojekt '$sm_path' fehlgeschlagen" -#: git-submodule.sh:343 +#: git-submodule.sh:348 #, sh-format msgid "Failed to register submodule '$sm_path'" msgstr "Registierung von Unterprojekt '$sm_path' fehlgeschlagen" -#: git-submodule.sh:385 +#: git-submodule.sh:390 #, sh-format msgid "Entering '$prefix$sm_path'" msgstr "Betrete '$prefix$sm_path'" -#: git-submodule.sh:399 +#: git-submodule.sh:404 #, sh-format msgid "Stopping at '$sm_path'; script returned non-zero status." msgstr "Stoppe bei '$sm_path'; Skript gab nicht-Null Status zurück." -#: git-submodule.sh:442 +#: git-submodule.sh:447 #, sh-format msgid "No url found for submodule path '$sm_path' in .gitmodules" msgstr "Keine URL für Unterprojekt-Pfad '$sm_path' in .gitmodules gefunden" -#: git-submodule.sh:451 +#: git-submodule.sh:456 #, sh-format msgid "Failed to register url for submodule path '$sm_path'" msgstr "Registrierung der URL für Unterprojekt-Pfad '$sm_path' fehlgeschlagen" -#: git-submodule.sh:453 +#: git-submodule.sh:458 #, sh-format msgid "Submodule '$name' ($url) registered for path '$sm_path'" msgstr "Unterprojekt '$name' ($url) ist für Pfad '$sm_path' registriert" -#: git-submodule.sh:461 +#: git-submodule.sh:466 #, sh-format msgid "Failed to register update mode for submodule path '$sm_path'" msgstr "" "Registrierung des Aktualisierungsmodus für Unterprojekt-Pfad '$sm_path' " "fehlgeschlagen" -#: git-submodule.sh:560 +#: git-submodule.sh:565 #, sh-format msgid "" "Submodule path '$sm_path' not initialized\n" @@ -5654,99 +6057,104 @@ msgstr "" "Unterprojekt-Pfad '$sm_path' ist nicht initialisiert\n" "Vielleicht möchtest du 'update --init' benutzen?" -#: git-submodule.sh:573 +#: git-submodule.sh:578 #, sh-format msgid "Unable to find current revision in submodule path '$sm_path'" msgstr "Konnte aktuelle Version in Unterprojekt-Pfad '$sm_path' nicht finden" -#: git-submodule.sh:592 +#: git-submodule.sh:597 #, sh-format msgid "Unable to fetch in submodule path '$sm_path'" msgstr "Konnte in Unterprojekt-Pfad '$sm_path' nicht anfordern" -#: git-submodule.sh:606 +#: git-submodule.sh:611 #, sh-format msgid "Unable to rebase '$sha1' in submodule path '$sm_path'" msgstr "Neuaufbau von '$sha1' in Unterprojekt-Pfad '$sm_path' nicht möglich" -#: git-submodule.sh:607 +#: git-submodule.sh:612 #, sh-format msgid "Submodule path '$sm_path': rebased into '$sha1'" msgstr "Unterprojekt-Pfad '$sm_path': neu aufgebaut in '$sha1'" -#: git-submodule.sh:612 +#: git-submodule.sh:617 #, sh-format msgid "Unable to merge '$sha1' in submodule path '$sm_path'" msgstr "" "Zusammenführung von '$sha1' in Unterprojekt-Pfad '$sm_path' fehlgeschlagen" -#: git-submodule.sh:613 +#: git-submodule.sh:618 #, sh-format msgid "Submodule path '$sm_path': merged in '$sha1'" msgstr "Unterprojekt-Pfad '$sm_path': zusammengeführt in '$sha1'" -#: git-submodule.sh:618 +#: git-submodule.sh:623 #, sh-format msgid "Unable to checkout '$sha1' in submodule path '$sm_path'" msgstr "Konnte '$sha1' in Unterprojekt-Pfad '$sm_path' nicht auschecken." -#: git-submodule.sh:619 +#: git-submodule.sh:624 #, sh-format msgid "Submodule path '$sm_path': checked out '$sha1'" msgstr "Unterprojekt-Pfad: '$sm_path': '$sha1' ausgecheckt" -#: git-submodule.sh:641 git-submodule.sh:964 +#: git-submodule.sh:646 git-submodule.sh:969 #, sh-format msgid "Failed to recurse into submodule path '$sm_path'" msgstr "Fehler bei Rekursion in Unterprojekt-Pfad '$sm_path'" -#: git-submodule.sh:749 -msgid "--cached cannot be used with --files" -msgstr "--cached kann nicht mit --files benutzt werden" +#: git-submodule.sh:754 +msgid "The --cached option cannot be used with the --files option" +msgstr "Die --cached Option kann nicht mit der --files Option benutzt werden" #. unexpected type -#: git-submodule.sh:789 +#: git-submodule.sh:794 #, sh-format msgid "unexpected mode $mod_dst" msgstr "unerwarteter Modus $mod_dst" -#: git-submodule.sh:807 +#: git-submodule.sh:812 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_src" msgstr " Warnung: $name beinhaltet nicht Version $sha1_src" -#: git-submodule.sh:810 +#: git-submodule.sh:815 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_dst" msgstr " Warnung: $name beinhaltet nicht Version $sha1_dst" -#: git-submodule.sh:813 +#: git-submodule.sh:818 #, sh-format msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst" msgstr "" " Warnung: $name beinhaltet nicht die Versionen $sha1_src und $sha1_dst" -#: git-submodule.sh:838 +#: git-submodule.sh:843 msgid "blob" msgstr "Blob" -#: git-submodule.sh:839 -msgid "submodule" -msgstr "Unterprojekt" - -#: git-submodule.sh:876 +#: git-submodule.sh:881 msgid "# Submodules changed but not updated:" msgstr "# Unterprojekte geändert, aber nicht aktualisiert:" -#: git-submodule.sh:878 +#: git-submodule.sh:883 msgid "# Submodule changes to be committed:" msgstr "# Änderungen in Unterprojekt zum Eintragen:" -#: git-submodule.sh:1022 +#: git-submodule.sh:1027 #, sh-format msgid "Synchronizing submodule url for '$name'" msgstr "Synchronisiere Unterprojekt-URL für '$name'" +#~ msgid "-d option is no longer supported. Do not use." +#~ msgstr "-d Option wird nicht länger unterstützt. Nicht benutzen." + +#~ msgid "%s: has been deleted/renamed" +#~ msgstr "%s wurde gelöscht/umbenannt" + +#~ msgid "'%s': not a documentation directory." +#~ msgstr "'%s' ist kein Dokumentationsverzeichnis" + #~ msgid "--" #~ msgstr "--" diff --git a/po/git.pot b/po/git.pot index 3d9ae759ea..5c586d6007 100644 --- a/po/git.pot +++ b/po/git.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2012-07-03 10:23+0800\n" +"POT-Creation-Date: 2012-08-06 23:47+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -45,7 +45,7 @@ msgstr "" msgid "unrecognized header: %s%s (%d)" msgstr "" -#: bundle.c:89 builtin/commit.c:696 +#: bundle.c:89 builtin/commit.c:699 #, c-format msgid "could not open '%s'" msgstr "" @@ -55,7 +55,7 @@ msgid "Repository lacks these prerequisite commits:" msgstr "" #: bundle.c:164 sequencer.c:550 sequencer.c:982 builtin/log.c:290 -#: builtin/log.c:721 builtin/log.c:1310 builtin/log.c:1529 builtin/merge.c:347 +#: builtin/log.c:726 builtin/log.c:1316 builtin/log.c:1535 builtin/merge.c:347 #: builtin/shortlog.c:181 msgid "revision walk setup failed" msgstr "" @@ -82,7 +82,7 @@ msgstr[1] "" msgid "rev-list died" msgstr "" -#: bundle.c:300 builtin/log.c:1206 builtin/shortlog.c:284 +#: bundle.c:300 builtin/log.c:1212 builtin/shortlog.c:284 #, c-format msgid "unrecognized argument: %s" msgstr "" @@ -226,7 +226,7 @@ msgid "" msgstr "" #: diff.c:1400 -msgid " 0 files changed\n" +msgid " 0 files changed" msgstr "" #: diff.c:1404 @@ -250,7 +250,7 @@ msgid_plural ", %d deletions(-)" msgstr[0] "" msgstr[1] "" -#: diff.c:3478 +#: diff.c:3461 #, c-format msgid "" "Failed to parse --dirstat/-X option parameter:\n" @@ -284,44 +284,44 @@ msgstr "" msgid "'%s': short read %s" msgstr "" -#: help.c:208 +#: help.c:212 #, c-format msgid "available git commands in '%s'" msgstr "" -#: help.c:215 +#: help.c:219 msgid "git commands available from elsewhere on your $PATH" msgstr "" -#: help.c:271 +#: help.c:275 #, c-format msgid "" "'%s' appears to be a git command, but we were not\n" "able to execute it. Maybe git-%s is broken?" msgstr "" -#: help.c:328 +#: help.c:332 msgid "Uh oh. Your system reports no Git commands at all." msgstr "" -#: help.c:350 +#: help.c:354 #, c-format msgid "" "WARNING: You called a Git command named '%s', which does not exist.\n" "Continuing under the assumption that you meant '%s'" msgstr "" -#: help.c:355 +#: help.c:359 #, c-format msgid "in %0.1f seconds automatically..." msgstr "" -#: help.c:362 +#: help.c:366 #, c-format msgid "git: '%s' is not a git command. See 'git --help'." msgstr "" -#: help.c:366 +#: help.c:370 msgid "" "\n" "Did you mean this?" @@ -331,35 +331,289 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: parse-options.c:493 +#: merge-recursive.c:190 +#, c-format +msgid "(bad commit)\n" +msgstr "" + +#: merge-recursive.c:206 +#, c-format +msgid "addinfo_cache failed for path '%s'" +msgstr "" + +#: merge-recursive.c:268 +msgid "error building trees" +msgstr "" + +#: merge-recursive.c:497 +msgid "diff setup failed" +msgstr "" + +#: merge-recursive.c:627 +msgid "merge-recursive: disk full?" +msgstr "" + +#: merge-recursive.c:690 +#, c-format +msgid "failed to create path '%s'%s" +msgstr "" + +#: merge-recursive.c:701 +#, c-format +msgid "Removing %s to make room for subdirectory\n" +msgstr "" + +#. something else exists +#. .. but not some other error (who really cares what?) +#: merge-recursive.c:715 merge-recursive.c:736 +msgid ": perhaps a D/F conflict?" +msgstr "" + +#: merge-recursive.c:726 +#, c-format +msgid "refusing to lose untracked file at '%s'" +msgstr "" + +#: merge-recursive.c:766 +#, c-format +msgid "cannot read object %s '%s'" +msgstr "" + +#: merge-recursive.c:768 +#, c-format +msgid "blob expected for %s '%s'" +msgstr "" + +#: merge-recursive.c:791 builtin/clone.c:302 +#, c-format +msgid "failed to open '%s'" +msgstr "" + +#: merge-recursive.c:799 +#, c-format +msgid "failed to symlink '%s'" +msgstr "" + +#: merge-recursive.c:802 +#, c-format +msgid "do not know what to do with %06o %s '%s'" +msgstr "" + +#: merge-recursive.c:939 +msgid "Failed to execute internal merge" +msgstr "" + +#: merge-recursive.c:943 +#, c-format +msgid "Unable to add %s to database" +msgstr "" + +#: merge-recursive.c:959 +msgid "unsupported object type in the tree" +msgstr "" + +#: merge-recursive.c:1038 merge-recursive.c:1052 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree." +msgstr "" + +#: merge-recursive.c:1044 merge-recursive.c:1057 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree at %s." +msgstr "" + +#: merge-recursive.c:1098 +msgid "rename" +msgstr "" + +#: merge-recursive.c:1098 +msgid "renamed" +msgstr "" + +#: merge-recursive.c:1154 +#, c-format +msgid "%s is a directory in %s adding as %s instead" +msgstr "" + +#: merge-recursive.c:1176 +#, c-format +msgid "" +"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s" +"\"->\"%s\" in \"%s\"%s" +msgstr "" + +#: merge-recursive.c:1181 +msgid " (left unresolved)" +msgstr "" + +#: merge-recursive.c:1235 +#, c-format +msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s" +msgstr "" + +#: merge-recursive.c:1265 +#, c-format +msgid "Renaming %s to %s and %s to %s instead" +msgstr "" + +#: merge-recursive.c:1464 +#, c-format +msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s" +msgstr "" + +#: merge-recursive.c:1474 +#, c-format +msgid "Adding merged %s" +msgstr "" + +#: merge-recursive.c:1479 merge-recursive.c:1677 +#, c-format +msgid "Adding as %s instead" +msgstr "" + +#: merge-recursive.c:1530 +#, c-format +msgid "cannot read object %s" +msgstr "" + +#: merge-recursive.c:1533 +#, c-format +msgid "object %s is not a blob" +msgstr "" + +#: merge-recursive.c:1581 +msgid "modify" +msgstr "" + +#: merge-recursive.c:1581 +msgid "modified" +msgstr "" + +#: merge-recursive.c:1591 +msgid "content" +msgstr "" + +#: merge-recursive.c:1598 +msgid "add/add" +msgstr "" + +#: merge-recursive.c:1632 +#, c-format +msgid "Skipped %s (merged same as existing)" +msgstr "" + +#: merge-recursive.c:1646 +#, c-format +msgid "Auto-merging %s" +msgstr "" + +#: merge-recursive.c:1650 git-submodule.sh:844 +msgid "submodule" +msgstr "" + +#: merge-recursive.c:1651 +#, c-format +msgid "CONFLICT (%s): Merge conflict in %s" +msgstr "" + +#: merge-recursive.c:1741 +#, c-format +msgid "Removing %s" +msgstr "" + +#: merge-recursive.c:1766 +msgid "file/directory" +msgstr "" + +#: merge-recursive.c:1772 +msgid "directory/file" +msgstr "" + +#: merge-recursive.c:1777 +#, c-format +msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s" +msgstr "" + +#: merge-recursive.c:1787 +#, c-format +msgid "Adding %s" +msgstr "" + +#: merge-recursive.c:1804 +msgid "Fatal merge failure, shouldn't happen." +msgstr "" + +#: merge-recursive.c:1823 +msgid "Already up-to-date!" +msgstr "" + +#: merge-recursive.c:1832 +#, c-format +msgid "merging of trees %s and %s failed" +msgstr "" + +#: merge-recursive.c:1862 +#, c-format +msgid "Unprocessed path??? %s" +msgstr "" + +#: merge-recursive.c:1907 +msgid "Merging:" +msgstr "" + +#: merge-recursive.c:1920 +#, c-format +msgid "found %u common ancestor:" +msgid_plural "found %u common ancestors:" +msgstr[0] "" +msgstr[1] "" + +#: merge-recursive.c:1957 +msgid "merge returned no commit" +msgstr "" + +#: merge-recursive.c:2014 +#, c-format +msgid "Could not parse object '%s'" +msgstr "" + +#: merge-recursive.c:2026 builtin/merge.c:697 +msgid "Unable to write index." +msgstr "" + +#: parse-options.c:494 msgid "..." msgstr "" -#: parse-options.c:511 +#: parse-options.c:512 #, c-format msgid "usage: %s" msgstr "" #. TRANSLATORS: the colon here should align with the #. one in "usage: %s" translation -#: parse-options.c:515 +#: parse-options.c:516 #, c-format msgid " or: %s" msgstr "" -#: parse-options.c:518 +#: parse-options.c:519 #, c-format msgid " %s" msgstr "" -#: remote.c:1629 +#: remote.c:1632 #, 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] "" msgstr[1] "" -#: remote.c:1635 +#: remote.c:1638 #, c-format msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n" msgid_plural "" @@ -367,7 +621,7 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: remote.c:1643 +#: remote.c:1646 #, c-format msgid "" "Your branch and '%s' have diverged,\n" @@ -582,7 +836,7 @@ msgstr "" msgid "cannot abort from a branch yet to be born" msgstr "" -#: sequencer.c:805 builtin/apply.c:3697 +#: sequencer.c:805 builtin/apply.c:3988 #, c-format msgid "cannot open %s: %s" msgstr "" @@ -614,21 +868,21 @@ msgstr "" msgid "Can't cherry-pick into empty head" msgstr "" -#: sha1_name.c:864 +#: sha1_name.c:1044 msgid "HEAD does not point to a branch" msgstr "" -#: sha1_name.c:867 +#: sha1_name.c:1047 #, c-format msgid "No such branch: '%s'" msgstr "" -#: sha1_name.c:869 +#: sha1_name.c:1049 #, c-format msgid "No upstream configured for branch '%s'" msgstr "" -#: sha1_name.c:872 +#: sha1_name.c:1052 #, c-format msgid "Upstream branch '%s' not stored as a remote-tracking branch" msgstr "" @@ -642,333 +896,333 @@ msgstr "" msgid "no such user" msgstr "" -#: wt-status.c:141 +#: wt-status.c:140 msgid "Unmerged paths:" msgstr "" -#: wt-status.c:168 wt-status.c:195 +#: wt-status.c:167 wt-status.c:194 #, c-format msgid " (use \"git reset %s <file>...\" to unstage)" msgstr "" -#: wt-status.c:170 wt-status.c:197 +#: wt-status.c:169 wt-status.c:196 msgid " (use \"git rm --cached <file>...\" to unstage)" msgstr "" -#: wt-status.c:174 +#: wt-status.c:173 msgid " (use \"git add <file>...\" to mark resolution)" msgstr "" -#: wt-status.c:176 wt-status.c:180 +#: wt-status.c:175 wt-status.c:179 msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)" msgstr "" -#: wt-status.c:178 +#: wt-status.c:177 msgid " (use \"git rm <file>...\" to mark resolution)" msgstr "" -#: wt-status.c:189 +#: wt-status.c:188 msgid "Changes to be committed:" msgstr "" -#: wt-status.c:207 +#: wt-status.c:206 msgid "Changes not staged for commit:" msgstr "" -#: wt-status.c:211 +#: wt-status.c:210 msgid " (use \"git add <file>...\" to update what will be committed)" msgstr "" -#: wt-status.c:213 +#: wt-status.c:212 msgid " (use \"git add/rm <file>...\" to update what will be committed)" msgstr "" -#: wt-status.c:214 +#: wt-status.c:213 msgid "" " (use \"git checkout -- <file>...\" to discard changes in working directory)" msgstr "" -#: wt-status.c:216 +#: wt-status.c:215 msgid " (commit or discard the untracked or modified content in submodules)" msgstr "" -#: wt-status.c:225 +#: wt-status.c:224 #, c-format msgid "%s files:" msgstr "" -#: wt-status.c:228 +#: wt-status.c:227 #, c-format msgid " (use \"git %s <file>...\" to include in what will be committed)" msgstr "" -#: wt-status.c:245 +#: wt-status.c:244 msgid "bug" msgstr "" -#: wt-status.c:250 +#: wt-status.c:249 msgid "both deleted:" msgstr "" -#: wt-status.c:251 +#: wt-status.c:250 msgid "added by us:" msgstr "" -#: wt-status.c:252 +#: wt-status.c:251 msgid "deleted by them:" msgstr "" -#: wt-status.c:253 +#: wt-status.c:252 msgid "added by them:" msgstr "" -#: wt-status.c:254 +#: wt-status.c:253 msgid "deleted by us:" msgstr "" -#: wt-status.c:255 +#: wt-status.c:254 msgid "both added:" msgstr "" -#: wt-status.c:256 +#: wt-status.c:255 msgid "both modified:" msgstr "" -#: wt-status.c:286 +#: wt-status.c:285 msgid "new commits, " msgstr "" -#: wt-status.c:288 +#: wt-status.c:287 msgid "modified content, " msgstr "" -#: wt-status.c:290 +#: wt-status.c:289 msgid "untracked content, " msgstr "" -#: wt-status.c:304 +#: wt-status.c:303 #, c-format msgid "new file: %s" msgstr "" -#: wt-status.c:307 +#: wt-status.c:306 #, c-format msgid "copied: %s -> %s" msgstr "" -#: wt-status.c:310 +#: wt-status.c:309 #, c-format msgid "deleted: %s" msgstr "" -#: wt-status.c:313 +#: wt-status.c:312 #, c-format msgid "modified: %s" msgstr "" -#: wt-status.c:316 +#: wt-status.c:315 #, c-format msgid "renamed: %s -> %s" msgstr "" -#: wt-status.c:319 +#: wt-status.c:318 #, c-format msgid "typechange: %s" msgstr "" -#: wt-status.c:322 +#: wt-status.c:321 #, c-format msgid "unknown: %s" msgstr "" -#: wt-status.c:325 +#: wt-status.c:324 #, c-format msgid "unmerged: %s" msgstr "" -#: wt-status.c:328 +#: wt-status.c:327 #, c-format msgid "bug: unhandled diff status %c" msgstr "" -#: wt-status.c:786 +#: wt-status.c:785 msgid "You have unmerged paths." msgstr "" -#: wt-status.c:789 wt-status.c:913 +#: wt-status.c:788 wt-status.c:912 msgid " (fix conflicts and run \"git commit\")" msgstr "" -#: wt-status.c:792 +#: wt-status.c:791 msgid "All conflicts fixed but you are still merging." msgstr "" -#: wt-status.c:795 +#: wt-status.c:794 msgid " (use \"git commit\" to conclude merge)" msgstr "" -#: wt-status.c:805 +#: wt-status.c:804 msgid "You are in the middle of an am session." msgstr "" -#: wt-status.c:808 +#: wt-status.c:807 msgid "The current patch is empty." msgstr "" -#: wt-status.c:812 +#: wt-status.c:811 msgid " (fix conflicts and then run \"git am --resolved\")" msgstr "" -#: wt-status.c:814 +#: wt-status.c:813 msgid " (use \"git am --skip\" to skip this patch)" msgstr "" -#: wt-status.c:816 +#: wt-status.c:815 msgid " (use \"git am --abort\" to restore the original branch)" msgstr "" -#: wt-status.c:874 wt-status.c:884 +#: wt-status.c:873 wt-status.c:883 msgid "You are currently rebasing." msgstr "" -#: wt-status.c:877 +#: wt-status.c:876 msgid " (fix conflicts and then run \"git rebase --continue\")" msgstr "" -#: wt-status.c:879 +#: wt-status.c:878 msgid " (use \"git rebase --skip\" to skip this patch)" msgstr "" -#: wt-status.c:881 +#: wt-status.c:880 msgid " (use \"git rebase --abort\" to check out the original branch)" msgstr "" -#: wt-status.c:887 +#: wt-status.c:886 msgid " (all conflicts fixed: run \"git rebase --continue\")" msgstr "" -#: wt-status.c:889 +#: wt-status.c:888 msgid "You are currently splitting a commit during a rebase." msgstr "" -#: wt-status.c:892 +#: wt-status.c:891 msgid " (Once your working directory is clean, run \"git rebase --continue\")" msgstr "" -#: wt-status.c:894 +#: wt-status.c:893 msgid "You are currently editing a commit during a rebase." msgstr "" -#: wt-status.c:897 +#: wt-status.c:896 msgid " (use \"git commit --amend\" to amend the current commit)" msgstr "" -#: wt-status.c:899 +#: wt-status.c:898 msgid "" " (use \"git rebase --continue\" once you are satisfied with your changes)" msgstr "" -#: wt-status.c:909 +#: wt-status.c:908 msgid "You are currently cherry-picking." msgstr "" -#: wt-status.c:916 +#: wt-status.c:915 msgid " (all conflicts fixed: run \"git commit\")" msgstr "" -#: wt-status.c:925 +#: wt-status.c:924 msgid "You are currently bisecting." msgstr "" -#: wt-status.c:928 +#: wt-status.c:927 msgid " (use \"git bisect reset\" to get back to the original branch)" msgstr "" -#: wt-status.c:979 +#: wt-status.c:978 msgid "On branch " msgstr "" -#: wt-status.c:986 +#: wt-status.c:985 msgid "Not currently on any branch." msgstr "" -#: wt-status.c:998 +#: wt-status.c:997 msgid "Initial commit" msgstr "" -#: wt-status.c:1012 +#: wt-status.c:1011 msgid "Untracked" msgstr "" -#: wt-status.c:1014 +#: wt-status.c:1013 msgid "Ignored" msgstr "" -#: wt-status.c:1016 +#: wt-status.c:1015 #, c-format msgid "Untracked files not listed%s" msgstr "" -#: wt-status.c:1018 +#: wt-status.c:1017 msgid " (use -u option to show untracked files)" msgstr "" -#: wt-status.c:1024 +#: wt-status.c:1023 msgid "No changes" msgstr "" -#: wt-status.c:1028 +#: wt-status.c:1027 #, c-format msgid "no changes added to commit%s\n" msgstr "" -#: wt-status.c:1030 +#: wt-status.c:1029 msgid " (use \"git add\" and/or \"git commit -a\")" msgstr "" -#: wt-status.c:1032 +#: wt-status.c:1031 #, c-format msgid "nothing added to commit but untracked files present%s\n" msgstr "" -#: wt-status.c:1034 +#: wt-status.c:1033 msgid " (use \"git add\" to track)" msgstr "" -#: wt-status.c:1036 wt-status.c:1039 wt-status.c:1042 +#: wt-status.c:1035 wt-status.c:1038 wt-status.c:1041 #, c-format msgid "nothing to commit%s\n" msgstr "" -#: wt-status.c:1037 +#: wt-status.c:1036 msgid " (create/copy files and use \"git add\" to track)" msgstr "" -#: wt-status.c:1040 +#: wt-status.c:1039 msgid " (use -u to show untracked files)" msgstr "" -#: wt-status.c:1043 +#: wt-status.c:1042 msgid " (working directory clean)" msgstr "" -#: wt-status.c:1151 +#: wt-status.c:1150 msgid "HEAD (no branch)" msgstr "" -#: wt-status.c:1157 +#: wt-status.c:1156 msgid "Initial commit on " msgstr "" -#: wt-status.c:1172 +#: wt-status.c:1171 msgid "behind " msgstr "" -#: wt-status.c:1175 wt-status.c:1178 +#: wt-status.c:1174 wt-status.c:1177 msgid "ahead " msgstr "" -#: wt-status.c:1180 +#: wt-status.c:1179 msgid ", behind " msgstr "" @@ -977,7 +1231,7 @@ msgstr "" msgid "unexpected diff status %c" msgstr "" -#: builtin/add.c:67 builtin/commit.c:226 +#: builtin/add.c:67 builtin/commit.c:229 msgid "updating files failed" msgstr "" @@ -1067,75 +1321,75 @@ msgstr "" msgid "Maybe you wanted to say 'git add .'?\n" msgstr "" -#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:286 builtin/mv.c:82 +#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:289 builtin/mv.c:82 #: builtin/rm.c:162 msgid "index file corrupt" msgstr "" -#: builtin/add.c:480 builtin/apply.c:4108 builtin/mv.c:229 builtin/rm.c:260 +#: builtin/add.c:480 builtin/apply.c:4433 builtin/mv.c:229 builtin/rm.c:260 msgid "Unable to write new index file" msgstr "" -#: builtin/apply.c:53 +#: builtin/apply.c:57 msgid "git apply [options] [<patch>...]" msgstr "" -#: builtin/apply.c:106 +#: builtin/apply.c:110 #, c-format msgid "unrecognized whitespace option '%s'" msgstr "" -#: builtin/apply.c:121 +#: builtin/apply.c:125 #, c-format msgid "unrecognized whitespace ignore option '%s'" msgstr "" -#: builtin/apply.c:815 +#: builtin/apply.c:824 #, c-format msgid "Cannot prepare timestamp regexp %s" msgstr "" -#: builtin/apply.c:824 +#: builtin/apply.c:833 #, c-format msgid "regexec returned %d for input: %s" msgstr "" -#: builtin/apply.c:905 +#: builtin/apply.c:914 #, c-format msgid "unable to find filename in patch at line %d" msgstr "" -#: builtin/apply.c:937 +#: builtin/apply.c:946 #, c-format msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d" msgstr "" -#: builtin/apply.c:941 +#: builtin/apply.c:950 #, c-format msgid "git apply: bad git-diff - inconsistent new filename on line %d" msgstr "" -#: builtin/apply.c:942 +#: builtin/apply.c:951 #, c-format msgid "git apply: bad git-diff - inconsistent old filename on line %d" msgstr "" -#: builtin/apply.c:949 +#: builtin/apply.c:958 #, c-format msgid "git apply: bad git-diff - expected /dev/null on line %d" msgstr "" -#: builtin/apply.c:1394 +#: builtin/apply.c:1403 #, c-format msgid "recount: unexpected line: %.*s" msgstr "" -#: builtin/apply.c:1451 +#: builtin/apply.c:1460 #, c-format msgid "patch fragment without header at line %d: %.*s" msgstr "" -#: builtin/apply.c:1468 +#: builtin/apply.c:1477 #, c-format msgid "" "git diff header lacks filename information when removing %d leading pathname " @@ -1146,395 +1400,403 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: builtin/apply.c:1628 +#: builtin/apply.c:1637 msgid "new file depends on old contents" msgstr "" -#: builtin/apply.c:1630 +#: builtin/apply.c:1639 msgid "deleted file still has contents" msgstr "" -#: builtin/apply.c:1656 +#: builtin/apply.c:1665 #, c-format msgid "corrupt patch at line %d" msgstr "" -#: builtin/apply.c:1692 +#: builtin/apply.c:1701 #, c-format msgid "new file %s depends on old contents" msgstr "" -#: builtin/apply.c:1694 +#: builtin/apply.c:1703 #, c-format msgid "deleted file %s still has contents" msgstr "" -#: builtin/apply.c:1697 +#: builtin/apply.c:1706 #, c-format msgid "** warning: file %s becomes empty but is not deleted" msgstr "" -#: builtin/apply.c:1843 +#: builtin/apply.c:1852 #, c-format msgid "corrupt binary patch at line %d: %.*s" msgstr "" #. there has to be one hunk (forward hunk) -#: builtin/apply.c:1872 +#: builtin/apply.c:1881 #, c-format msgid "unrecognized binary patch at line %d" msgstr "" -#: builtin/apply.c:1958 +#: builtin/apply.c:1967 #, c-format msgid "patch with only garbage at line %d" msgstr "" -#: builtin/apply.c:2048 +#: builtin/apply.c:2057 #, c-format msgid "unable to read symlink %s" msgstr "" -#: builtin/apply.c:2052 +#: builtin/apply.c:2061 #, c-format msgid "unable to open or read %s" msgstr "" -#: builtin/apply.c:2123 +#: builtin/apply.c:2132 msgid "oops" msgstr "" -#: builtin/apply.c:2645 +#: builtin/apply.c:2654 #, c-format msgid "invalid start of line: '%c'" msgstr "" -#: builtin/apply.c:2763 +#: builtin/apply.c:2772 #, c-format msgid "Hunk #%d succeeded at %d (offset %d line)." msgid_plural "Hunk #%d succeeded at %d (offset %d lines)." msgstr[0] "" msgstr[1] "" -#: builtin/apply.c:2775 +#: builtin/apply.c:2784 #, c-format msgid "Context reduced to (%ld/%ld) to apply fragment at %d" msgstr "" -#: builtin/apply.c:2781 +#: builtin/apply.c:2790 #, c-format msgid "" "while searching for:\n" "%.*s" msgstr "" -#: builtin/apply.c:2800 +#: builtin/apply.c:2809 #, c-format msgid "missing binary patch data for '%s'" msgstr "" -#: builtin/apply.c:2903 +#: builtin/apply.c:2912 #, c-format msgid "binary patch does not apply to '%s'" msgstr "" -#: builtin/apply.c:2909 +#: builtin/apply.c:2918 #, c-format msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)" msgstr "" -#: builtin/apply.c:2930 +#: builtin/apply.c:2939 #, c-format msgid "patch failed: %s:%ld" msgstr "" -#: builtin/apply.c:3045 +#: builtin/apply.c:3061 #, c-format -msgid "patch %s has been renamed/deleted" +msgid "cannot checkout %s" msgstr "" -#: builtin/apply.c:3052 builtin/apply.c:3069 +#: builtin/apply.c:3106 builtin/apply.c:3115 builtin/apply.c:3159 #, c-format msgid "read of %s failed" msgstr "" -#: builtin/apply.c:3084 -msgid "removal patch leaves file contents" -msgstr "" - -#: builtin/apply.c:3105 +#: builtin/apply.c:3139 builtin/apply.c:3361 #, c-format -msgid "%s: already exists in working directory" +msgid "path %s has been renamed/deleted" msgstr "" -#: builtin/apply.c:3143 +#: builtin/apply.c:3220 builtin/apply.c:3375 #, c-format -msgid "%s: has been deleted/renamed" +msgid "%s: does not exist in index" msgstr "" -#: builtin/apply.c:3148 builtin/apply.c:3179 +#: builtin/apply.c:3224 builtin/apply.c:3367 builtin/apply.c:3389 #, c-format msgid "%s: %s" msgstr "" -#: builtin/apply.c:3159 +#: builtin/apply.c:3229 builtin/apply.c:3383 #, c-format -msgid "%s: does not exist in index" +msgid "%s: does not match index" msgstr "" -#: builtin/apply.c:3173 -#, c-format -msgid "%s: does not match index" +#: builtin/apply.c:3331 +msgid "removal patch leaves file contents" msgstr "" -#: builtin/apply.c:3190 +#: builtin/apply.c:3400 #, c-format msgid "%s: wrong type" msgstr "" -#: builtin/apply.c:3192 +#: builtin/apply.c:3402 #, c-format msgid "%s has type %o, expected %o" msgstr "" -#: builtin/apply.c:3247 +#: builtin/apply.c:3503 #, c-format msgid "%s: already exists in index" msgstr "" -#: builtin/apply.c:3267 +#: builtin/apply.c:3506 +#, c-format +msgid "%s: already exists in working directory" +msgstr "" + +#: builtin/apply.c:3526 #, c-format msgid "new mode (%o) of %s does not match old mode (%o)" msgstr "" -#: builtin/apply.c:3272 +#: builtin/apply.c:3531 #, c-format msgid "new mode (%o) of %s does not match old mode (%o) of %s" msgstr "" -#: builtin/apply.c:3280 +#: builtin/apply.c:3539 #, c-format msgid "%s: patch does not apply" msgstr "" -#: builtin/apply.c:3293 +#: builtin/apply.c:3552 #, c-format msgid "Checking patch %s..." msgstr "" -#: builtin/apply.c:3348 builtin/checkout.c:212 builtin/reset.c:158 +#: builtin/apply.c:3607 builtin/checkout.c:213 builtin/reset.c:158 #, c-format msgid "make_cache_entry failed for path '%s'" msgstr "" -#: builtin/apply.c:3491 +#: builtin/apply.c:3750 #, c-format msgid "unable to remove %s from index" msgstr "" -#: builtin/apply.c:3518 +#: builtin/apply.c:3778 #, c-format msgid "corrupt patch for subproject %s" msgstr "" -#: builtin/apply.c:3522 +#: builtin/apply.c:3782 #, c-format msgid "unable to stat newly created file '%s'" msgstr "" -#: builtin/apply.c:3527 +#: builtin/apply.c:3787 #, c-format msgid "unable to create backing store for newly created file %s" msgstr "" -#: builtin/apply.c:3530 +#: builtin/apply.c:3790 builtin/apply.c:3898 #, c-format msgid "unable to add cache entry for %s" msgstr "" -#: builtin/apply.c:3563 +#: builtin/apply.c:3823 #, c-format msgid "closing file '%s'" msgstr "" -#: builtin/apply.c:3612 +#: builtin/apply.c:3872 #, c-format msgid "unable to write file '%s' mode %o" msgstr "" -#: builtin/apply.c:3668 +#: builtin/apply.c:3959 #, c-format msgid "Applied patch %s cleanly." msgstr "" -#: builtin/apply.c:3676 +#: builtin/apply.c:3967 msgid "internal error" msgstr "" #. Say this even without --verbose -#: builtin/apply.c:3679 +#: builtin/apply.c:3970 #, c-format msgid "Applying patch %%s with %d reject..." msgid_plural "Applying patch %%s with %d rejects..." msgstr[0] "" msgstr[1] "" -#: builtin/apply.c:3689 +#: builtin/apply.c:3980 #, c-format msgid "truncating .rej filename to %.*s.rej" msgstr "" -#: builtin/apply.c:3710 +#: builtin/apply.c:4001 #, c-format msgid "Hunk #%d applied cleanly." msgstr "" -#: builtin/apply.c:3713 +#: builtin/apply.c:4004 #, c-format msgid "Rejected hunk #%d." msgstr "" -#: builtin/apply.c:3844 +#: builtin/apply.c:4154 msgid "unrecognized input" msgstr "" -#: builtin/apply.c:3855 +#: builtin/apply.c:4165 msgid "unable to read index file" msgstr "" -#: builtin/apply.c:3970 builtin/apply.c:3973 +#: builtin/apply.c:4284 builtin/apply.c:4287 msgid "path" msgstr "" -#: builtin/apply.c:3971 +#: builtin/apply.c:4285 msgid "don't apply changes matching the given path" msgstr "" -#: builtin/apply.c:3974 +#: builtin/apply.c:4288 msgid "apply changes matching the given path" msgstr "" -#: builtin/apply.c:3976 +#: builtin/apply.c:4290 msgid "num" msgstr "" -#: builtin/apply.c:3977 +#: builtin/apply.c:4291 msgid "remove <num> leading slashes from traditional diff paths" msgstr "" -#: builtin/apply.c:3980 +#: builtin/apply.c:4294 msgid "ignore additions made by the patch" msgstr "" -#: builtin/apply.c:3982 +#: builtin/apply.c:4296 msgid "instead of applying the patch, output diffstat for the input" msgstr "" -#: builtin/apply.c:3986 +#: builtin/apply.c:4300 msgid "shows number of added and deleted lines in decimal notation" msgstr "" -#: builtin/apply.c:3988 +#: builtin/apply.c:4302 msgid "instead of applying the patch, output a summary for the input" msgstr "" -#: builtin/apply.c:3990 +#: builtin/apply.c:4304 msgid "instead of applying the patch, see if the patch is applicable" msgstr "" -#: builtin/apply.c:3992 +#: builtin/apply.c:4306 msgid "make sure the patch is applicable to the current index" msgstr "" -#: builtin/apply.c:3994 +#: builtin/apply.c:4308 msgid "apply a patch without touching the working tree" msgstr "" -#: builtin/apply.c:3996 +#: builtin/apply.c:4310 msgid "also apply the patch (use with --stat/--summary/--check)" msgstr "" -#: builtin/apply.c:3998 +#: builtin/apply.c:4312 +msgid "attempt three-way merge if a patch does not apply" +msgstr "" + +#: builtin/apply.c:4314 msgid "build a temporary index based on embedded index information" msgstr "" -#: builtin/apply.c:4000 +#: builtin/apply.c:4316 msgid "paths are separated with NUL character" msgstr "" -#: builtin/apply.c:4003 +#: builtin/apply.c:4319 msgid "ensure at least <n> lines of context match" msgstr "" -#: builtin/apply.c:4004 +#: builtin/apply.c:4320 msgid "action" msgstr "" -#: builtin/apply.c:4005 +#: builtin/apply.c:4321 msgid "detect new or modified lines that have whitespace errors" msgstr "" -#: builtin/apply.c:4008 builtin/apply.c:4011 +#: builtin/apply.c:4324 builtin/apply.c:4327 msgid "ignore changes in whitespace when finding context" msgstr "" -#: builtin/apply.c:4014 +#: builtin/apply.c:4330 msgid "apply the patch in reverse" msgstr "" -#: builtin/apply.c:4016 +#: builtin/apply.c:4332 msgid "don't expect at least one line of context" msgstr "" -#: builtin/apply.c:4018 +#: builtin/apply.c:4334 msgid "leave the rejected hunks in corresponding *.rej files" msgstr "" -#: builtin/apply.c:4020 +#: builtin/apply.c:4336 msgid "allow overlapping hunks" msgstr "" -#: builtin/apply.c:4021 +#: builtin/apply.c:4337 msgid "be verbose" msgstr "" -#: builtin/apply.c:4023 +#: builtin/apply.c:4339 msgid "tolerate incorrectly detected missing new-line at the end of file" msgstr "" -#: builtin/apply.c:4026 +#: builtin/apply.c:4342 msgid "do not trust the line counts in the hunk headers" msgstr "" -#: builtin/apply.c:4028 +#: builtin/apply.c:4344 msgid "root" msgstr "" -#: builtin/apply.c:4029 +#: builtin/apply.c:4345 msgid "prepend <root> to all filenames" msgstr "" -#: builtin/apply.c:4050 +#: builtin/apply.c:4367 +msgid "--3way outside a repository" +msgstr "" + +#: builtin/apply.c:4375 msgid "--index outside a repository" msgstr "" -#: builtin/apply.c:4053 +#: builtin/apply.c:4378 msgid "--cached outside a repository" msgstr "" -#: builtin/apply.c:4069 +#: builtin/apply.c:4394 #, c-format msgid "can't open patch '%s'" msgstr "" -#: builtin/apply.c:4083 +#: builtin/apply.c:4408 #, c-format msgid "squelched %d whitespace error" msgid_plural "squelched %d whitespace errors" msgstr[0] "" msgstr[1] "" -#: builtin/apply.c:4089 builtin/apply.c:4099 +#: builtin/apply.c:4414 builtin/apply.c:4424 #, c-format msgid "%d line adds whitespace errors." msgid_plural "%d lines add whitespace errors." @@ -1733,7 +1995,7 @@ msgstr "" msgid "Failed to resolve HEAD as a valid ref." msgstr "" -#: builtin/branch.c:788 builtin/clone.c:558 +#: builtin/branch.c:788 builtin/clone.c:561 msgid "HEAD not found below refs/heads!" msgstr "" @@ -1758,99 +2020,99 @@ msgstr "" msgid "Need a repository to unbundle." msgstr "" -#: builtin/checkout.c:113 builtin/checkout.c:146 +#: builtin/checkout.c:114 builtin/checkout.c:147 #, c-format msgid "path '%s' does not have our version" msgstr "" -#: builtin/checkout.c:115 builtin/checkout.c:148 +#: builtin/checkout.c:116 builtin/checkout.c:149 #, c-format msgid "path '%s' does not have their version" msgstr "" -#: builtin/checkout.c:131 +#: builtin/checkout.c:132 #, c-format msgid "path '%s' does not have all necessary versions" msgstr "" -#: builtin/checkout.c:175 +#: builtin/checkout.c:176 #, c-format msgid "path '%s' does not have necessary versions" msgstr "" -#: builtin/checkout.c:192 +#: builtin/checkout.c:193 #, c-format msgid "path '%s': cannot merge" msgstr "" -#: builtin/checkout.c:209 +#: builtin/checkout.c:210 #, c-format msgid "Unable to add merge result for '%s'" msgstr "" -#: builtin/checkout.c:234 builtin/checkout.c:392 +#: builtin/checkout.c:235 builtin/checkout.c:393 msgid "corrupt index file" msgstr "" -#: builtin/checkout.c:264 builtin/checkout.c:271 +#: builtin/checkout.c:265 builtin/checkout.c:272 #, c-format msgid "path '%s' is unmerged" msgstr "" -#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583 +#: builtin/checkout.c:303 builtin/checkout.c:499 builtin/clone.c:586 #: builtin/merge.c:812 msgid "unable to write new index file" msgstr "" -#: builtin/checkout.c:319 builtin/diff.c:302 builtin/merge.c:408 +#: builtin/checkout.c:320 builtin/diff.c:302 builtin/merge.c:408 msgid "diff_setup_done failed" msgstr "" -#: builtin/checkout.c:414 +#: builtin/checkout.c:415 msgid "you need to resolve your current index first" msgstr "" -#: builtin/checkout.c:533 +#: builtin/checkout.c:534 #, c-format msgid "Can not do reflog for '%s'\n" msgstr "" -#: builtin/checkout.c:566 +#: builtin/checkout.c:567 msgid "HEAD is now at" msgstr "" -#: builtin/checkout.c:573 +#: builtin/checkout.c:574 #, c-format msgid "Reset branch '%s'\n" msgstr "" -#: builtin/checkout.c:576 +#: builtin/checkout.c:577 #, c-format msgid "Already on '%s'\n" msgstr "" -#: builtin/checkout.c:580 +#: builtin/checkout.c:581 #, c-format msgid "Switched to and reset branch '%s'\n" msgstr "" -#: builtin/checkout.c:582 +#: builtin/checkout.c:583 #, c-format msgid "Switched to a new branch '%s'\n" msgstr "" -#: builtin/checkout.c:584 +#: builtin/checkout.c:585 #, c-format msgid "Switched to branch '%s'\n" msgstr "" -#: builtin/checkout.c:640 +#: builtin/checkout.c:641 #, c-format msgid " ... and %d more.\n" msgstr "" #. The singular version -#: builtin/checkout.c:646 +#: builtin/checkout.c:647 #, c-format msgid "" "Warning: you are leaving %d commit behind, not connected to\n" @@ -1865,7 +2127,7 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: builtin/checkout.c:664 +#: builtin/checkout.c:665 #, c-format msgid "" "If you want to keep them by creating a new branch, this may be a good time\n" @@ -1875,96 +2137,96 @@ msgid "" "\n" msgstr "" -#: builtin/checkout.c:694 +#: builtin/checkout.c:695 msgid "internal error in revision walk" msgstr "" -#: builtin/checkout.c:698 +#: builtin/checkout.c:699 msgid "Previous HEAD position was" msgstr "" -#: builtin/checkout.c:724 +#: builtin/checkout.c:725 builtin/checkout.c:920 msgid "You are on a branch yet to be born" msgstr "" #. case (1) -#: builtin/checkout.c:855 +#: builtin/checkout.c:856 #, c-format msgid "invalid reference: %s" msgstr "" #. case (1): want a tree -#: builtin/checkout.c:894 +#: builtin/checkout.c:895 #, c-format msgid "reference is not a tree: %s" msgstr "" -#: builtin/checkout.c:974 +#: builtin/checkout.c:977 msgid "-B cannot be used with -b" msgstr "" -#: builtin/checkout.c:983 +#: builtin/checkout.c:986 msgid "--patch is incompatible with all other options" msgstr "" -#: builtin/checkout.c:986 +#: builtin/checkout.c:989 msgid "--detach cannot be used with -b/-B/--orphan" msgstr "" -#: builtin/checkout.c:988 +#: builtin/checkout.c:991 msgid "--detach cannot be used with -t" msgstr "" -#: builtin/checkout.c:994 +#: builtin/checkout.c:997 msgid "--track needs a branch name" msgstr "" -#: builtin/checkout.c:1001 +#: builtin/checkout.c:1004 msgid "Missing branch name; try -b" msgstr "" -#: builtin/checkout.c:1007 +#: builtin/checkout.c:1010 msgid "--orphan and -b|-B are mutually exclusive" msgstr "" -#: builtin/checkout.c:1009 +#: builtin/checkout.c:1012 msgid "--orphan cannot be used with -t" msgstr "" -#: builtin/checkout.c:1019 +#: builtin/checkout.c:1022 msgid "git checkout: -f and -m are incompatible" msgstr "" -#: builtin/checkout.c:1053 +#: builtin/checkout.c:1056 msgid "invalid path specification" msgstr "" -#: builtin/checkout.c:1061 +#: builtin/checkout.c:1064 #, c-format msgid "" "git checkout: updating paths is incompatible with switching branches.\n" "Did you intend to checkout '%s' which can not be resolved as commit?" msgstr "" -#: builtin/checkout.c:1063 +#: builtin/checkout.c:1066 msgid "git checkout: updating paths is incompatible with switching branches." msgstr "" -#: builtin/checkout.c:1068 +#: builtin/checkout.c:1071 msgid "git checkout: --detach does not take a path argument" msgstr "" -#: builtin/checkout.c:1071 +#: builtin/checkout.c:1074 msgid "" "git checkout: --ours/--theirs, --force and --merge are incompatible when\n" "checking out of the index." msgstr "" -#: builtin/checkout.c:1090 +#: builtin/checkout.c:1093 msgid "Cannot switch branch to a non-commit." msgstr "" -#: builtin/checkout.c:1093 +#: builtin/checkout.c:1096 msgid "--ours/--theirs is incompatible with switching branches." msgstr "" @@ -2013,11 +2275,6 @@ msgstr "" msgid "reference repository '%s' is not a local directory." msgstr "" -#: builtin/clone.c:302 -#, c-format -msgid "failed to open '%s'" -msgstr "" - #: builtin/clone.c:306 #, c-format msgid "failed to create directory '%s'" @@ -2058,78 +2315,78 @@ msgstr "" msgid "done.\n" msgstr "" -#: builtin/clone.c:440 +#: builtin/clone.c:443 #, c-format msgid "Could not find remote branch %s to clone." msgstr "" -#: builtin/clone.c:549 +#: builtin/clone.c:552 msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n" msgstr "" -#: builtin/clone.c:639 +#: builtin/clone.c:642 msgid "Too many arguments." msgstr "" -#: builtin/clone.c:643 +#: builtin/clone.c:646 msgid "You must specify a repository to clone." msgstr "" -#: builtin/clone.c:654 +#: builtin/clone.c:657 #, c-format msgid "--bare and --origin %s options are incompatible." msgstr "" -#: builtin/clone.c:668 +#: builtin/clone.c:671 #, c-format msgid "repository '%s' does not exist" msgstr "" -#: builtin/clone.c:673 +#: builtin/clone.c:676 msgid "--depth is ignored in local clones; use file:// instead." msgstr "" -#: builtin/clone.c:683 +#: builtin/clone.c:686 #, c-format msgid "destination path '%s' already exists and is not an empty directory." msgstr "" -#: builtin/clone.c:693 +#: builtin/clone.c:696 #, c-format msgid "working tree '%s' already exists." msgstr "" -#: builtin/clone.c:706 builtin/clone.c:720 +#: builtin/clone.c:709 builtin/clone.c:723 #, c-format msgid "could not create leading directories of '%s'" msgstr "" -#: builtin/clone.c:709 +#: builtin/clone.c:712 #, c-format msgid "could not create work tree dir '%s'." msgstr "" -#: builtin/clone.c:728 +#: builtin/clone.c:731 #, c-format msgid "Cloning into bare repository '%s'...\n" msgstr "" -#: builtin/clone.c:730 +#: builtin/clone.c:733 #, c-format msgid "Cloning into '%s'...\n" msgstr "" -#: builtin/clone.c:786 +#: builtin/clone.c:789 #, c-format msgid "Don't know how to clone %s" msgstr "" -#: builtin/clone.c:835 +#: builtin/clone.c:838 #, c-format msgid "Remote branch %s not found in upstream %s" msgstr "" -#: builtin/clone.c:842 +#: builtin/clone.c:845 msgid "You appear to have cloned an empty repository." msgstr "" @@ -2168,93 +2425,93 @@ msgid "" "Otherwise, please use 'git reset'\n" msgstr "" -#: builtin/commit.c:253 +#: builtin/commit.c:256 msgid "failed to unpack HEAD tree object" msgstr "" -#: builtin/commit.c:295 +#: builtin/commit.c:298 msgid "unable to create temporary index" msgstr "" -#: builtin/commit.c:301 +#: builtin/commit.c:304 msgid "interactive add failed" msgstr "" -#: builtin/commit.c:334 builtin/commit.c:355 builtin/commit.c:405 +#: builtin/commit.c:337 builtin/commit.c:358 builtin/commit.c:408 msgid "unable to write new_index file" msgstr "" -#: builtin/commit.c:386 +#: builtin/commit.c:389 msgid "cannot do a partial commit during a merge." msgstr "" -#: builtin/commit.c:388 +#: builtin/commit.c:391 msgid "cannot do a partial commit during a cherry-pick." msgstr "" -#: builtin/commit.c:398 +#: builtin/commit.c:401 msgid "cannot read the index" msgstr "" -#: builtin/commit.c:418 +#: builtin/commit.c:421 msgid "unable to write temporary index file" msgstr "" -#: builtin/commit.c:493 builtin/commit.c:499 +#: builtin/commit.c:496 builtin/commit.c:502 #, c-format msgid "invalid commit: %s" msgstr "" -#: builtin/commit.c:522 +#: builtin/commit.c:525 msgid "malformed --author parameter" msgstr "" -#: builtin/commit.c:582 +#: builtin/commit.c:585 #, c-format msgid "Malformed ident string: '%s'" msgstr "" -#: builtin/commit.c:620 builtin/commit.c:653 builtin/commit.c:967 +#: builtin/commit.c:623 builtin/commit.c:656 builtin/commit.c:970 #, c-format msgid "could not lookup commit %s" msgstr "" -#: builtin/commit.c:632 builtin/shortlog.c:296 +#: builtin/commit.c:635 builtin/shortlog.c:296 #, c-format msgid "(reading log message from standard input)\n" msgstr "" -#: builtin/commit.c:634 +#: builtin/commit.c:637 msgid "could not read log from standard input" msgstr "" -#: builtin/commit.c:638 +#: builtin/commit.c:641 #, c-format msgid "could not read log file '%s'" msgstr "" -#: builtin/commit.c:644 +#: builtin/commit.c:647 msgid "commit has empty message" msgstr "" -#: builtin/commit.c:660 +#: builtin/commit.c:663 msgid "could not read MERGE_MSG" msgstr "" -#: builtin/commit.c:664 +#: builtin/commit.c:667 msgid "could not read SQUASH_MSG" msgstr "" -#: builtin/commit.c:668 +#: builtin/commit.c:671 #, c-format msgid "could not read '%s'" msgstr "" -#: builtin/commit.c:720 +#: builtin/commit.c:723 msgid "could not write commit template" msgstr "" -#: builtin/commit.c:731 +#: builtin/commit.c:734 #, c-format msgid "" "\n" @@ -2264,7 +2521,7 @@ msgid "" "and try again.\n" msgstr "" -#: builtin/commit.c:736 +#: builtin/commit.c:739 #, c-format msgid "" "\n" @@ -2274,171 +2531,171 @@ msgid "" "and try again.\n" msgstr "" -#: builtin/commit.c:748 +#: builtin/commit.c:751 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be ignored, and an empty message aborts the commit.\n" msgstr "" -#: builtin/commit.c:753 +#: builtin/commit.c:756 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be kept; you may remove them yourself if you want to.\n" "An empty message aborts the commit.\n" msgstr "" -#: builtin/commit.c:766 +#: builtin/commit.c:769 #, c-format msgid "%sAuthor: %s" msgstr "" -#: builtin/commit.c:773 +#: builtin/commit.c:776 #, c-format msgid "%sCommitter: %s" msgstr "" -#: builtin/commit.c:793 +#: builtin/commit.c:796 msgid "Cannot read index" msgstr "" -#: builtin/commit.c:830 +#: builtin/commit.c:833 msgid "Error building trees" msgstr "" -#: builtin/commit.c:845 builtin/tag.c:361 +#: builtin/commit.c:848 builtin/tag.c:361 #, c-format msgid "Please supply the message using either -m or -F option.\n" msgstr "" -#: builtin/commit.c:942 +#: builtin/commit.c:945 #, c-format msgid "No existing author found with '%s'" msgstr "" -#: builtin/commit.c:957 builtin/commit.c:1157 +#: builtin/commit.c:960 builtin/commit.c:1160 #, c-format msgid "Invalid untracked files mode '%s'" msgstr "" -#: builtin/commit.c:997 +#: builtin/commit.c:1000 msgid "Using both --reset-author and --author does not make sense" msgstr "" -#: builtin/commit.c:1008 +#: builtin/commit.c:1011 msgid "You have nothing to amend." msgstr "" -#: builtin/commit.c:1011 +#: builtin/commit.c:1014 msgid "You are in the middle of a merge -- cannot amend." msgstr "" -#: builtin/commit.c:1013 +#: builtin/commit.c:1016 msgid "You are in the middle of a cherry-pick -- cannot amend." msgstr "" -#: builtin/commit.c:1016 +#: builtin/commit.c:1019 msgid "Options --squash and --fixup cannot be used together" msgstr "" -#: builtin/commit.c:1026 +#: builtin/commit.c:1029 msgid "Only one of -c/-C/-F/--fixup can be used." msgstr "" -#: builtin/commit.c:1028 +#: builtin/commit.c:1031 msgid "Option -m cannot be combined with -c/-C/-F/--fixup." msgstr "" -#: builtin/commit.c:1036 +#: builtin/commit.c:1039 msgid "--reset-author can be used only with -C, -c or --amend." msgstr "" -#: builtin/commit.c:1053 +#: builtin/commit.c:1056 msgid "Only one of --include/--only/--all/--interactive/--patch can be used." msgstr "" -#: builtin/commit.c:1055 +#: builtin/commit.c:1058 msgid "No paths with --include/--only does not make sense." msgstr "" -#: builtin/commit.c:1057 +#: builtin/commit.c:1060 msgid "Clever... amending the last one with dirty index." msgstr "" -#: builtin/commit.c:1059 +#: builtin/commit.c:1062 msgid "Explicit paths specified without -i nor -o; assuming --only paths..." msgstr "" -#: builtin/commit.c:1069 builtin/tag.c:577 +#: builtin/commit.c:1072 builtin/tag.c:577 #, c-format msgid "Invalid cleanup mode %s" msgstr "" -#: builtin/commit.c:1074 +#: builtin/commit.c:1077 msgid "Paths with -a does not make sense." msgstr "" -#: builtin/commit.c:1257 +#: builtin/commit.c:1260 msgid "couldn't look up newly created commit" msgstr "" -#: builtin/commit.c:1259 +#: builtin/commit.c:1262 msgid "could not parse newly created commit" msgstr "" -#: builtin/commit.c:1300 +#: builtin/commit.c:1303 msgid "detached HEAD" msgstr "" -#: builtin/commit.c:1302 +#: builtin/commit.c:1305 msgid " (root-commit)" msgstr "" -#: builtin/commit.c:1446 +#: builtin/commit.c:1449 msgid "could not parse HEAD commit" msgstr "" -#: builtin/commit.c:1484 builtin/merge.c:509 +#: builtin/commit.c:1487 builtin/merge.c:509 #, c-format msgid "could not open '%s' for reading" msgstr "" -#: builtin/commit.c:1491 +#: builtin/commit.c:1494 #, c-format msgid "Corrupt MERGE_HEAD file (%s)" msgstr "" -#: builtin/commit.c:1498 +#: builtin/commit.c:1501 msgid "could not read MERGE_MODE" msgstr "" -#: builtin/commit.c:1517 +#: builtin/commit.c:1520 #, c-format msgid "could not read commit message: %s" msgstr "" -#: builtin/commit.c:1531 +#: builtin/commit.c:1534 #, c-format msgid "Aborting commit; you did not edit the message.\n" msgstr "" -#: builtin/commit.c:1536 +#: builtin/commit.c:1539 #, c-format msgid "Aborting commit due to empty commit message.\n" msgstr "" -#: builtin/commit.c:1551 builtin/merge.c:936 builtin/merge.c:961 +#: builtin/commit.c:1554 builtin/merge.c:936 builtin/merge.c:961 msgid "failed to write commit object" msgstr "" -#: builtin/commit.c:1572 +#: builtin/commit.c:1575 msgid "cannot lock HEAD ref" msgstr "" -#: builtin/commit.c:1576 +#: builtin/commit.c:1579 msgid "cannot update HEAD ref" msgstr "" -#: builtin/commit.c:1587 +#: builtin/commit.c:1590 msgid "" "Repository has been updated, but unable to write\n" "new_index file. Check that disk is not full or quota is\n" @@ -2794,71 +3051,66 @@ msgstr "" msgid "both --cached and trees are given." msgstr "" -#: builtin/help.c:63 +#: builtin/help.c:65 #, c-format msgid "unrecognized help format '%s'" msgstr "" -#: builtin/help.c:91 +#: builtin/help.c:93 msgid "Failed to start emacsclient." msgstr "" -#: builtin/help.c:104 +#: builtin/help.c:106 msgid "Failed to parse emacsclient version." msgstr "" -#: builtin/help.c:112 +#: builtin/help.c:114 #, c-format msgid "emacsclient version '%d' too old (< 22)." msgstr "" -#: builtin/help.c:130 builtin/help.c:158 builtin/help.c:167 builtin/help.c:175 +#: builtin/help.c:132 builtin/help.c:160 builtin/help.c:169 builtin/help.c:177 #, c-format msgid "failed to exec '%s': %s" msgstr "" -#: builtin/help.c:215 +#: builtin/help.c:217 #, c-format msgid "" "'%s': path for unsupported man viewer.\n" "Please consider using 'man.<tool>.cmd' instead." msgstr "" -#: builtin/help.c:227 +#: builtin/help.c:229 #, c-format msgid "" "'%s': cmd for supported man viewer.\n" "Please consider using 'man.<tool>.path' instead." msgstr "" -#: builtin/help.c:291 +#: builtin/help.c:299 msgid "The most commonly used git commands are:" msgstr "" -#: builtin/help.c:359 +#: builtin/help.c:367 #, c-format msgid "'%s': unknown man viewer." msgstr "" -#: builtin/help.c:376 +#: builtin/help.c:384 msgid "no man viewer handled the request" msgstr "" -#: builtin/help.c:384 +#: builtin/help.c:392 msgid "no info viewer handled the request" msgstr "" -#: builtin/help.c:395 -#, c-format -msgid "'%s': not a documentation directory." -msgstr "" - -#: builtin/help.c:436 builtin/help.c:443 +#: builtin/help.c:447 builtin/help.c:454 #, c-format msgid "usage: %s%s" msgstr "" -#: builtin/help.c:459 +#: builtin/help.c:470 #, c-format msgid "`git %s' is aliased to `%s'" msgstr "" @@ -2932,176 +3184,176 @@ msgstr "" msgid "unknown object type %d" msgstr "" -#: builtin/index-pack.c:531 +#: builtin/index-pack.c:530 msgid "cannot pread pack file" msgstr "" -#: builtin/index-pack.c:533 +#: builtin/index-pack.c:532 #, 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] "" -#: builtin/index-pack.c:555 +#: builtin/index-pack.c:558 msgid "serious inflate inconsistency" msgstr "" -#: builtin/index-pack.c:646 builtin/index-pack.c:652 builtin/index-pack.c:675 -#: builtin/index-pack.c:709 builtin/index-pack.c:718 +#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678 +#: builtin/index-pack.c:712 builtin/index-pack.c:721 #, c-format msgid "SHA1 COLLISION FOUND WITH %s !" msgstr "" -#: builtin/index-pack.c:649 builtin/pack-objects.c:170 +#: builtin/index-pack.c:652 builtin/pack-objects.c:170 #: builtin/pack-objects.c:262 #, c-format msgid "unable to read %s" msgstr "" -#: builtin/index-pack.c:715 +#: builtin/index-pack.c:718 #, c-format msgid "cannot read existing object %s" msgstr "" -#: builtin/index-pack.c:729 +#: builtin/index-pack.c:732 #, c-format msgid "invalid blob object %s" msgstr "" -#: builtin/index-pack.c:744 +#: builtin/index-pack.c:747 #, c-format msgid "invalid %s" msgstr "" -#: builtin/index-pack.c:746 +#: builtin/index-pack.c:749 msgid "Error in object" msgstr "" -#: builtin/index-pack.c:748 +#: builtin/index-pack.c:751 #, c-format msgid "Not all child objects of %s are reachable" msgstr "" -#: builtin/index-pack.c:818 builtin/index-pack.c:844 +#: builtin/index-pack.c:821 builtin/index-pack.c:847 msgid "failed to apply delta" msgstr "" -#: builtin/index-pack.c:983 +#: builtin/index-pack.c:986 msgid "Receiving objects" msgstr "" -#: builtin/index-pack.c:983 +#: builtin/index-pack.c:986 msgid "Indexing objects" msgstr "" -#: builtin/index-pack.c:1009 +#: builtin/index-pack.c:1012 msgid "pack is corrupted (SHA1 mismatch)" msgstr "" -#: builtin/index-pack.c:1014 +#: builtin/index-pack.c:1017 msgid "cannot fstat packfile" msgstr "" -#: builtin/index-pack.c:1017 +#: builtin/index-pack.c:1020 msgid "pack has junk at the end" msgstr "" -#: builtin/index-pack.c:1028 +#: builtin/index-pack.c:1031 msgid "confusion beyond insanity in parse_pack_objects()" msgstr "" -#: builtin/index-pack.c:1051 +#: builtin/index-pack.c:1054 msgid "Resolving deltas" msgstr "" -#: builtin/index-pack.c:1102 +#: builtin/index-pack.c:1105 msgid "confusion beyond insanity" msgstr "" -#: builtin/index-pack.c:1121 +#: builtin/index-pack.c:1124 #, c-format msgid "pack has %d unresolved delta" msgid_plural "pack has %d unresolved deltas" msgstr[0] "" msgstr[1] "" -#: builtin/index-pack.c:1146 +#: builtin/index-pack.c:1149 #, c-format msgid "unable to deflate appended object (%d)" msgstr "" -#: builtin/index-pack.c:1225 +#: builtin/index-pack.c:1228 #, c-format msgid "local object %s is corrupt" msgstr "" -#: builtin/index-pack.c:1249 +#: builtin/index-pack.c:1252 msgid "error while closing pack file" msgstr "" -#: builtin/index-pack.c:1262 +#: builtin/index-pack.c:1265 #, c-format msgid "cannot write keep file '%s'" msgstr "" -#: builtin/index-pack.c:1270 +#: builtin/index-pack.c:1273 #, c-format msgid "cannot close written keep file '%s'" msgstr "" -#: builtin/index-pack.c:1283 +#: builtin/index-pack.c:1286 msgid "cannot store pack file" msgstr "" -#: builtin/index-pack.c:1294 +#: builtin/index-pack.c:1297 msgid "cannot store index file" msgstr "" -#: builtin/index-pack.c:1395 +#: builtin/index-pack.c:1398 #, c-format msgid "Cannot open existing pack file '%s'" msgstr "" -#: builtin/index-pack.c:1397 +#: builtin/index-pack.c:1400 #, c-format msgid "Cannot open existing pack idx file for '%s'" msgstr "" -#: builtin/index-pack.c:1444 +#: builtin/index-pack.c:1447 #, c-format msgid "non delta: %d object" msgid_plural "non delta: %d objects" msgstr[0] "" msgstr[1] "" -#: builtin/index-pack.c:1451 +#: builtin/index-pack.c:1454 #, c-format msgid "chain length = %d: %lu object" msgid_plural "chain length = %d: %lu objects" msgstr[0] "" msgstr[1] "" -#: builtin/index-pack.c:1478 +#: builtin/index-pack.c:1481 msgid "Cannot come back to cwd" msgstr "" -#: builtin/index-pack.c:1522 builtin/index-pack.c:1525 -#: builtin/index-pack.c:1537 builtin/index-pack.c:1541 +#: builtin/index-pack.c:1525 builtin/index-pack.c:1528 +#: builtin/index-pack.c:1540 builtin/index-pack.c:1544 #, c-format msgid "bad %s" msgstr "" -#: builtin/index-pack.c:1555 +#: builtin/index-pack.c:1558 msgid "--fix-thin cannot be used without --stdin" msgstr "" -#: builtin/index-pack.c:1559 builtin/index-pack.c:1569 +#: builtin/index-pack.c:1562 builtin/index-pack.c:1572 #, c-format msgid "packfile name '%s' does not end with '.pack'" msgstr "" -#: builtin/index-pack.c:1578 +#: builtin/index-pack.c:1581 msgid "--verify with no packfile name given" msgstr "" @@ -3175,22 +3427,22 @@ msgstr "" msgid "insane git directory %s" msgstr "" -#: builtin/init-db.c:322 builtin/init-db.c:325 +#: builtin/init-db.c:323 builtin/init-db.c:326 #, c-format msgid "%s already exists" msgstr "" -#: builtin/init-db.c:354 +#: builtin/init-db.c:355 #, c-format msgid "unable to handle file type %d" msgstr "" -#: builtin/init-db.c:357 +#: builtin/init-db.c:358 #, c-format msgid "unable to move %s to %s" msgstr "" -#: builtin/init-db.c:362 +#: builtin/init-db.c:363 #, c-format msgid "Could not create git link %s" msgstr "" @@ -3200,49 +3452,49 @@ msgstr "" #. * existing" or "Initialized empty", the second " shared" or #. * "", and the last '%s%s' is the verbatim directory name. #. -#: builtin/init-db.c:419 +#: builtin/init-db.c:420 #, c-format msgid "%s%s Git repository in %s%s\n" msgstr "" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Reinitialized existing" msgstr "" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Initialized empty" msgstr "" -#: builtin/init-db.c:421 +#: builtin/init-db.c:422 msgid " shared" msgstr "" -#: builtin/init-db.c:440 +#: builtin/init-db.c:441 msgid "cannot tell cwd" msgstr "" -#: builtin/init-db.c:521 builtin/init-db.c:528 +#: builtin/init-db.c:522 builtin/init-db.c:529 #, c-format msgid "cannot mkdir %s" msgstr "" -#: builtin/init-db.c:532 +#: builtin/init-db.c:533 #, c-format msgid "cannot chdir to %s" msgstr "" -#: builtin/init-db.c:554 +#: builtin/init-db.c:555 #, c-format msgid "" "%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-" "dir=<directory>)" msgstr "" -#: builtin/init-db.c:578 +#: builtin/init-db.c:579 msgid "Cannot access current working directory" msgstr "" -#: builtin/init-db.c:585 +#: builtin/init-db.c:586 #, c-format msgid "Cannot access work tree '%s'" msgstr "" @@ -3252,95 +3504,95 @@ msgstr "" msgid "Final output: %d %s\n" msgstr "" -#: builtin/log.c:402 builtin/log.c:490 +#: builtin/log.c:403 builtin/log.c:494 #, c-format msgid "Could not read object %s" msgstr "" -#: builtin/log.c:514 +#: builtin/log.c:518 #, c-format msgid "Unknown type: %d" msgstr "" -#: builtin/log.c:603 +#: builtin/log.c:608 msgid "format.headers without value" msgstr "" -#: builtin/log.c:677 +#: builtin/log.c:682 msgid "name of output directory is too long" msgstr "" -#: builtin/log.c:688 +#: builtin/log.c:693 #, c-format msgid "Cannot open patch file %s" msgstr "" -#: builtin/log.c:702 +#: builtin/log.c:707 msgid "Need exactly one range." msgstr "" -#: builtin/log.c:710 +#: builtin/log.c:715 msgid "Not a range." msgstr "" -#: builtin/log.c:787 +#: builtin/log.c:792 msgid "Cover letter needs email format" msgstr "" -#: builtin/log.c:860 +#: builtin/log.c:865 #, c-format msgid "insane in-reply-to: %s" msgstr "" -#: builtin/log.c:933 +#: builtin/log.c:938 msgid "Two output directories?" msgstr "" -#: builtin/log.c:1154 +#: builtin/log.c:1160 #, c-format msgid "bogus committer info %s" msgstr "" -#: builtin/log.c:1199 +#: builtin/log.c:1205 msgid "-n and -k are mutually exclusive." msgstr "" -#: builtin/log.c:1201 +#: builtin/log.c:1207 msgid "--subject-prefix and -k are mutually exclusive." msgstr "" -#: builtin/log.c:1209 +#: builtin/log.c:1215 msgid "--name-only does not make sense" msgstr "" -#: builtin/log.c:1211 +#: builtin/log.c:1217 msgid "--name-status does not make sense" msgstr "" -#: builtin/log.c:1213 +#: builtin/log.c:1219 msgid "--check does not make sense" msgstr "" -#: builtin/log.c:1236 +#: builtin/log.c:1242 msgid "standard output, or directory, which one?" msgstr "" -#: builtin/log.c:1238 +#: builtin/log.c:1244 #, c-format msgid "Could not create directory '%s'" msgstr "" -#: builtin/log.c:1391 +#: builtin/log.c:1397 msgid "Failed to create output files" msgstr "" -#: builtin/log.c:1495 +#: builtin/log.c:1501 #, c-format msgid "" "Could not find a tracked remote branch, please specify <upstream> manually.\n" msgstr "" -#: builtin/log.c:1511 builtin/log.c:1513 builtin/log.c:1525 +#: builtin/log.c:1517 builtin/log.c:1519 builtin/log.c:1531 #, c-format msgid "Unknown commit %s" msgstr "" @@ -3421,10 +3673,6 @@ msgstr "" msgid "failed to read the cache" msgstr "" -#: builtin/merge.c:697 -msgid "Unable to write index." -msgstr "" - #: builtin/merge.c:710 msgid "Not handling anything other than two heads merge." msgstr "" @@ -4379,30 +4627,30 @@ msgstr "" msgid "Cannot do a %s reset in the middle of a merge." msgstr "" -#: builtin/reset.c:297 +#: builtin/reset.c:303 #, c-format msgid "Could not parse object '%s'." msgstr "" -#: builtin/reset.c:302 +#: builtin/reset.c:308 msgid "--patch is incompatible with --{hard,mixed,soft}" msgstr "" -#: builtin/reset.c:311 +#: builtin/reset.c:317 msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead." msgstr "" -#: builtin/reset.c:313 +#: builtin/reset.c:319 #, c-format msgid "Cannot do %s reset with paths." msgstr "" -#: builtin/reset.c:325 +#: builtin/reset.c:331 #, c-format msgid "%s reset is not allowed in a bare repository" msgstr "" -#: builtin/reset.c:341 +#: builtin/reset.c:347 #, c-format msgid "Could not reset index file to revision '%s'." msgstr "" @@ -4720,9 +4968,9 @@ msgstr "" #: git-am.sh:105 #, sh-format msgid "" -"When you have resolved this problem run \"$cmdline --resolved\".\n" -"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n" -"To restore the original branch and stop patching run \"$cmdline --abort\"." +"When you have resolved this problem, run \"$cmdline --resolved\".\n" +"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n" +"To restore the original branch and stop patching, run \"$cmdline --abort\"." msgstr "" #: git-am.sh:121 @@ -4733,6 +4981,10 @@ msgstr "" msgid "Repository lacks necessary blobs to fall back on 3-way merge." msgstr "" +#: git-am.sh:139 +msgid "Using index info to reconstruct a base tree..." +msgstr "" + #: git-am.sh:154 msgid "" "Did you hand edit your patch?\n" @@ -4743,42 +4995,48 @@ msgstr "" msgid "Falling back to patching base and 3-way merge..." msgstr "" -#: git-am.sh:275 +#: git-am.sh:179 +msgid "Failed to merge in the changes." +msgstr "" + +#: git-am.sh:274 msgid "Only one StGIT patch series can be applied at once" msgstr "" -#: git-am.sh:362 +#: git-am.sh:361 #, sh-format msgid "Patch format $patch_format is not supported." msgstr "" -#: git-am.sh:364 +#: git-am.sh:363 msgid "Patch format detection failed." msgstr "" -#: git-am.sh:418 -msgid "-d option is no longer supported. Do not use." +#: git-am.sh:389 +msgid "" +"The -b/--binary option has been a no-op for long time, and\n" +"it will be removed. Please do not use it anymore." msgstr "" -#: git-am.sh:481 +#: git-am.sh:477 #, sh-format msgid "previous rebase directory $dotest still exists but mbox given." msgstr "" -#: git-am.sh:486 +#: git-am.sh:482 msgid "Please make up your mind. --skip or --abort?" msgstr "" -#: git-am.sh:513 +#: git-am.sh:509 msgid "Resolve operation not in progress, we are not resuming." msgstr "" -#: git-am.sh:579 +#: git-am.sh:575 #, sh-format msgid "Dirty index: cannot apply patches (dirty: $files)" msgstr "" -#: git-am.sh:671 +#: git-am.sh:679 #, sh-format msgid "" "Patch is empty. Was it split wrong?\n" @@ -4786,53 +5044,53 @@ msgid "" "To restore the original branch and stop patching run \"$cmdline --abort\"." msgstr "" -#: git-am.sh:708 +#: git-am.sh:706 msgid "Patch does not have a valid e-mail address." msgstr "" -#: git-am.sh:755 +#: git-am.sh:753 msgid "cannot be interactive without stdin connected to a terminal." msgstr "" -#: git-am.sh:759 +#: git-am.sh:757 msgid "Commit Body is:" msgstr "" #. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a] #. in your translation. The program will only accept English #. input at this point. -#: git-am.sh:766 +#: git-am.sh:764 msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " msgstr "" -#: git-am.sh:802 +#: git-am.sh:800 #, sh-format msgid "Applying: $FIRSTLINE" msgstr "" -#: git-am.sh:823 +#: git-am.sh:821 msgid "" "No changes - did you forget to use 'git add'?\n" "If there is nothing left to stage, chances are that something else\n" "already introduced the same changes; you might want to skip this patch." msgstr "" -#: git-am.sh:831 +#: git-am.sh:829 msgid "" "You still have unmerged paths in your index\n" "did you forget to use 'git add'?" msgstr "" -#: git-am.sh:847 +#: git-am.sh:845 msgid "No changes -- Patch already applied." msgstr "" -#: git-am.sh:857 +#: git-am.sh:855 #, sh-format msgid "Patch failed at $msgnum $FIRSTLINE" msgstr "" -#: git-am.sh:873 +#: git-am.sh:876 msgid "applying to an empty history" msgstr "" @@ -5015,6 +5273,112 @@ msgstr "" msgid "Cannot rebase onto multiple branches" msgstr "" +#: git-rebase.sh:52 +msgid "" +"When you have resolved this problem, run \"git rebase --continue\".\n" +"If you prefer to skip this patch, run \"git rebase --skip\" instead.\n" +"To check out the original branch and stop rebasing, run \"git rebase --abort" +"\"." +msgstr "" + +#: git-rebase.sh:159 +msgid "The pre-rebase hook refused to rebase." +msgstr "" + +#: git-rebase.sh:164 +msgid "It looks like git-am is in progress. Cannot rebase." +msgstr "" + +#: git-rebase.sh:295 +msgid "The --exec option must be used with the --interactive option" +msgstr "" + +#: git-rebase.sh:300 +msgid "No rebase in progress?" +msgstr "" + +#: git-rebase.sh:313 +msgid "Cannot read HEAD" +msgstr "" + +#: git-rebase.sh:316 +msgid "" +"You must edit all merge conflicts and then\n" +"mark them as resolved using git add" +msgstr "" + +#: git-rebase.sh:334 +#, sh-format +msgid "Could not move back to $head_name" +msgstr "" + +#: git-rebase.sh:350 +#, sh-format +msgid "" +"It seems that there is already a $state_dir_base directory, and\n" +"I wonder if you are in the middle of another rebase. If that is the\n" +"case, please try\n" +"\t$cmd_live_rebase\n" +"If that is not the case, please\n" +"\t$cmd_clear_stale_rebase\n" +"and run me again. I am stopping in case you still have something\n" +"valuable there." +msgstr "" + +#: git-rebase.sh:395 +#, sh-format +msgid "invalid upstream $upstream_name" +msgstr "" + +#: git-rebase.sh:419 +#, sh-format +msgid "$onto_name: there are more than one merge bases" +msgstr "" + +#: git-rebase.sh:422 git-rebase.sh:426 +#, sh-format +msgid "$onto_name: there is no merge base" +msgstr "" + +#: git-rebase.sh:431 +#, sh-format +msgid "Does not point to a valid commit: $onto_name" +msgstr "" + +#: git-rebase.sh:454 +#, sh-format +msgid "fatal: no such branch: $branch_name" +msgstr "" + +#: git-rebase.sh:474 +msgid "Please commit or stash them." +msgstr "" + +#: git-rebase.sh:492 +#, sh-format +msgid "Current branch $branch_name is up to date." +msgstr "" + +#: git-rebase.sh:495 +#, sh-format +msgid "Current branch $branch_name is up to date, rebase forced." +msgstr "" + +#: git-rebase.sh:506 +#, sh-format +msgid "Changes from $mb to $onto:" +msgstr "" + +#. Detach HEAD and reset the tree +#: git-rebase.sh:515 +msgid "First, rewinding head to replay your work on top of it..." +msgstr "" + +#: git-rebase.sh:523 +#, sh-format +msgid "Fast-forwarded $branch_name to $onto_name." +msgstr "" + #: git-stash.sh:51 msgid "git stash clear with parameters is unimplemented" msgstr "" @@ -5152,27 +5516,27 @@ msgstr "" msgid "No submodule mapping found in .gitmodules for path '$sm_path'" msgstr "" -#: git-submodule.sh:186 +#: git-submodule.sh:189 #, sh-format msgid "Clone of '$url' into submodule path '$sm_path' failed" msgstr "" -#: git-submodule.sh:196 +#: git-submodule.sh:201 #, sh-format msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa" msgstr "" -#: git-submodule.sh:285 +#: git-submodule.sh:290 #, sh-format msgid "repo URL: '$repo' must be absolute or begin with ./|../" msgstr "" -#: git-submodule.sh:302 +#: git-submodule.sh:307 #, sh-format msgid "'$sm_path' already exists in the index" msgstr "" -#: git-submodule.sh:306 +#: git-submodule.sh:311 #, sh-format msgid "" "The following path is ignored by one of your .gitignore files:\n" @@ -5180,155 +5544,151 @@ msgid "" "Use -f if you really want to add it." msgstr "" -#: git-submodule.sh:317 +#: git-submodule.sh:322 #, sh-format msgid "Adding existing repo at '$sm_path' to the index" msgstr "" -#: git-submodule.sh:319 +#: git-submodule.sh:324 #, sh-format msgid "'$sm_path' already exists and is not a valid git repo" msgstr "" -#: git-submodule.sh:333 +#: git-submodule.sh:338 #, sh-format msgid "Unable to checkout submodule '$sm_path'" msgstr "" -#: git-submodule.sh:338 +#: git-submodule.sh:343 #, sh-format msgid "Failed to add submodule '$sm_path'" msgstr "" -#: git-submodule.sh:343 +#: git-submodule.sh:348 #, sh-format msgid "Failed to register submodule '$sm_path'" msgstr "" -#: git-submodule.sh:385 +#: git-submodule.sh:390 #, sh-format msgid "Entering '$prefix$sm_path'" msgstr "" -#: git-submodule.sh:399 +#: git-submodule.sh:404 #, sh-format msgid "Stopping at '$sm_path'; script returned non-zero status." msgstr "" -#: git-submodule.sh:442 +#: git-submodule.sh:447 #, sh-format msgid "No url found for submodule path '$sm_path' in .gitmodules" msgstr "" -#: git-submodule.sh:451 +#: git-submodule.sh:456 #, sh-format msgid "Failed to register url for submodule path '$sm_path'" msgstr "" -#: git-submodule.sh:453 +#: git-submodule.sh:458 #, sh-format msgid "Submodule '$name' ($url) registered for path '$sm_path'" msgstr "" -#: git-submodule.sh:461 +#: git-submodule.sh:466 #, sh-format msgid "Failed to register update mode for submodule path '$sm_path'" msgstr "" -#: git-submodule.sh:560 +#: git-submodule.sh:565 #, sh-format msgid "" "Submodule path '$sm_path' not initialized\n" "Maybe you want to use 'update --init'?" msgstr "" -#: git-submodule.sh:573 +#: git-submodule.sh:578 #, sh-format msgid "Unable to find current revision in submodule path '$sm_path'" msgstr "" -#: git-submodule.sh:592 +#: git-submodule.sh:597 #, sh-format msgid "Unable to fetch in submodule path '$sm_path'" msgstr "" -#: git-submodule.sh:606 +#: git-submodule.sh:611 #, sh-format msgid "Unable to rebase '$sha1' in submodule path '$sm_path'" msgstr "" -#: git-submodule.sh:607 +#: git-submodule.sh:612 #, sh-format msgid "Submodule path '$sm_path': rebased into '$sha1'" msgstr "" -#: git-submodule.sh:612 +#: git-submodule.sh:617 #, sh-format msgid "Unable to merge '$sha1' in submodule path '$sm_path'" msgstr "" -#: git-submodule.sh:613 +#: git-submodule.sh:618 #, sh-format msgid "Submodule path '$sm_path': merged in '$sha1'" msgstr "" -#: git-submodule.sh:618 +#: git-submodule.sh:623 #, sh-format msgid "Unable to checkout '$sha1' in submodule path '$sm_path'" msgstr "" -#: git-submodule.sh:619 +#: git-submodule.sh:624 #, sh-format msgid "Submodule path '$sm_path': checked out '$sha1'" msgstr "" -#: git-submodule.sh:641 git-submodule.sh:964 +#: git-submodule.sh:646 git-submodule.sh:969 #, sh-format msgid "Failed to recurse into submodule path '$sm_path'" msgstr "" -#: git-submodule.sh:749 -msgid "--cached cannot be used with --files" +#: git-submodule.sh:754 +msgid "The --cached option cannot be used with the --files option" msgstr "" #. unexpected type -#: git-submodule.sh:789 +#: git-submodule.sh:794 #, sh-format msgid "unexpected mode $mod_dst" msgstr "" -#: git-submodule.sh:807 +#: git-submodule.sh:812 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_src" msgstr "" -#: git-submodule.sh:810 +#: git-submodule.sh:815 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_dst" msgstr "" -#: git-submodule.sh:813 +#: git-submodule.sh:818 #, sh-format msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst" msgstr "" -#: git-submodule.sh:838 +#: git-submodule.sh:843 msgid "blob" msgstr "" -#: git-submodule.sh:839 -msgid "submodule" -msgstr "" - -#: git-submodule.sh:876 +#: git-submodule.sh:881 msgid "# Submodules changed but not updated:" msgstr "" -#: git-submodule.sh:878 +#: git-submodule.sh:883 msgid "# Submodule changes to be committed:" msgstr "" -#: git-submodule.sh:1022 +#: git-submodule.sh:1027 #, sh-format msgid "Synchronizing submodule url for '$name'" msgstr "" @@ -5,10 +5,10 @@ # msgid "" msgstr "" -"Project-Id-Version: git 1.7.10\n" +"Project-Id-Version: git 1.7.12\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2012-07-03 10:23+0800\n" -"PO-Revision-Date: 2012-07-04 19:33+0100\n" +"POT-Creation-Date: 2012-08-06 23:47+0800\n" +"PO-Revision-Date: 2012-08-14 09:58+0100\n" "Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n" "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n" "Language: sv\n" @@ -48,7 +48,7 @@ msgstr "'%s' ser inte ut som en v2-bundle-fil" msgid "unrecognized header: %s%s (%d)" msgstr "okänt huvud: %s%s (%d)" -#: bundle.c:89 builtin/commit.c:696 +#: bundle.c:89 builtin/commit.c:699 #, c-format msgid "could not open '%s'" msgstr "kunde inte öppna \"%s\"" @@ -58,7 +58,7 @@ msgid "Repository lacks these prerequisite commits:" msgstr "Arkivet saknar dessa nödvändiga incheckningar:" #: bundle.c:164 sequencer.c:550 sequencer.c:982 builtin/log.c:290 -#: builtin/log.c:721 builtin/log.c:1310 builtin/log.c:1529 builtin/merge.c:347 +#: builtin/log.c:726 builtin/log.c:1316 builtin/log.c:1535 builtin/merge.c:347 #: builtin/shortlog.c:181 msgid "revision walk setup failed" msgstr "misslyckades skapa revisionstraversering" @@ -85,7 +85,7 @@ msgstr[1] "Paketet (bundlen) kräver dessa %d referenser" msgid "rev-list died" msgstr "rev-list dog" -#: bundle.c:300 builtin/log.c:1206 builtin/shortlog.c:284 +#: bundle.c:300 builtin/log.c:1212 builtin/shortlog.c:284 #, c-format msgid "unrecognized argument: %s" msgstr "okänt argument: %s" @@ -231,8 +231,8 @@ msgstr "" "%s" #: diff.c:1400 -msgid " 0 files changed\n" -msgstr " 0 filer ändrade\n" +msgid " 0 files changed" +msgstr " 0 filer ändrade" #: diff.c:1404 #, c-format @@ -255,7 +255,7 @@ msgid_plural ", %d deletions(-)" msgstr[0] ", %d borttagning(-)" msgstr[1] ", %d borttagningar(-)" -#: diff.c:3478 +#: diff.c:3461 #, c-format msgid "" "Failed to parse --dirstat/-X option parameter:\n" @@ -291,16 +291,16 @@ msgstr "\"%s\": %s" msgid "'%s': short read %s" msgstr "\"%s\": kort läsning %s" -#: help.c:208 +#: help.c:212 #, c-format msgid "available git commands in '%s'" msgstr "git-kommandon tillgängliga i \"%s\"" -#: help.c:215 +#: help.c:219 msgid "git commands available from elsewhere on your $PATH" msgstr "git-kommandon från andra platser i din $PATH" -#: help.c:271 +#: help.c:275 #, c-format msgid "" "'%s' appears to be a git command, but we were not\n" @@ -309,11 +309,11 @@ msgstr "" "\"%s\" verkar vara ett git-kommando, men vi kan inte\n" "köra det. Kanske git-%s är trasigt?" -#: help.c:328 +#: help.c:332 msgid "Uh oh. Your system reports no Git commands at all." msgstr "Oj då. Ditt system rapporterar inga Git-kommandon alls." -#: help.c:350 +#: help.c:354 #, c-format msgid "" "WARNING: You called a Git command named '%s', which does not exist.\n" @@ -322,17 +322,17 @@ msgstr "" "VARNING: Du anropade ett Git-kommando vid namn \"%s\", som inte finns.\n" "Fortsätter under förutsättningen att du menade \"%s\"" -#: help.c:355 +#: help.c:359 #, c-format msgid "in %0.1f seconds automatically..." msgstr "automatiskt om %0.1f sekunder..." -#: help.c:362 +#: help.c:366 #, c-format msgid "git: '%s' is not a git command. See 'git --help'." msgstr "git: \"%s\" är inte ett git-kommando. Se \"git --help\"." -#: help.c:366 +#: help.c:370 msgid "" "\n" "Did you mean this?" @@ -346,35 +346,297 @@ msgstr[1] "" "\n" "Menade du ett av dessa?" -#: parse-options.c:493 +#: merge-recursive.c:190 +#, c-format +msgid "(bad commit)\n" +msgstr "(felaktig incheckning)\n" + +#: merge-recursive.c:206 +#, c-format +msgid "addinfo_cache failed for path '%s'" +msgstr "addinfo_cache misslyckades för sökvägen \"%s\"" + +#: merge-recursive.c:268 +msgid "error building trees" +msgstr "fel vid byggande av träd" + +#: merge-recursive.c:497 +msgid "diff setup failed" +msgstr "misslyckades sätta upp för diff" + +#: merge-recursive.c:627 +msgid "merge-recursive: disk full?" +msgstr "merge-recursive: disk full?" + +#: merge-recursive.c:690 +#, c-format +msgid "failed to create path '%s'%s" +msgstr "misslyckades skapa sökvägen \"%s\"%s" + +#: merge-recursive.c:701 +#, c-format +msgid "Removing %s to make room for subdirectory\n" +msgstr "Tar bort %s för att göra plats för underkatalog\n" + +#. something else exists +#. .. but not some other error (who really cares what?) +#: merge-recursive.c:715 merge-recursive.c:736 +msgid ": perhaps a D/F conflict?" +msgstr ": kanske en K/F-konflikt?" + +#: merge-recursive.c:726 +#, c-format +msgid "refusing to lose untracked file at '%s'" +msgstr "vägrar förlora ospårad fil vid \"%s\"" + +#: merge-recursive.c:766 +#, c-format +msgid "cannot read object %s '%s'" +msgstr "kan inte läsa objektet %s: \"%s\"" + +#: merge-recursive.c:768 +#, c-format +msgid "blob expected for %s '%s'" +msgstr "blob förväntades för %s \"%s\"" + +#: merge-recursive.c:791 builtin/clone.c:302 +#, c-format +msgid "failed to open '%s'" +msgstr "misslyckades öppna \"%s\"" + +#: merge-recursive.c:799 +#, c-format +msgid "failed to symlink '%s'" +msgstr "misslyckades ta skapa symboliska länken \"%s\"" + +#: merge-recursive.c:802 +#, c-format +msgid "do not know what to do with %06o %s '%s'" +msgstr "vet inte hur %06o %s \"%s\" skall hanteras" + +#: merge-recursive.c:939 +msgid "Failed to execute internal merge" +msgstr "Misslyckades exekvera intern sammanslagning" + +#: merge-recursive.c:943 +#, c-format +msgid "Unable to add %s to database" +msgstr "Kunde inte lägga till %s till databasen" + +#: merge-recursive.c:959 +msgid "unsupported object type in the tree" +msgstr "objekttyp som ej stöds upptäcktes i trädet" + +#: merge-recursive.c:1038 merge-recursive.c:1052 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree." +msgstr "" +"KONFLIKT (%s/radera): %s raderad i %s och %s i %s. Versionen %s av %s lämnad " +"i trädet." + +#: merge-recursive.c:1044 merge-recursive.c:1057 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree at %s." +msgstr "" +"KONFLIKT (%s/radera): %s raderad i %s och %s i %s. Versionen %s av %s lämnad " +"i trädet vid %s." + +#: merge-recursive.c:1098 +msgid "rename" +msgstr "namnbyte" + +#: merge-recursive.c:1098 +msgid "renamed" +msgstr "namnbytt" + +#: merge-recursive.c:1154 +#, c-format +msgid "%s is a directory in %s adding as %s instead" +msgstr "%s är en katalog i %s lägger till som %s istället" + +#: merge-recursive.c:1176 +#, c-format +msgid "" +"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s" +"\"->\"%s\" in \"%s\"%s" +msgstr "" +"KONFLIKT (namnbyte/namnbyte): Namnbyte \"%s\"->\"%s\" på grenen \"%s\" " +"namnbyte \"%s\"->\"%s\" i \"%s\"%s" + +#: merge-recursive.c:1181 +msgid " (left unresolved)" +msgstr " (lämnad olöst)" + +#: merge-recursive.c:1235 +#, c-format +msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s" +msgstr "" +"KONFLIKT (namnbyte/namnbyte): Namnbyte %s->%s i %s. Namnbyte %s->%s i %s" + +#: merge-recursive.c:1265 +#, c-format +msgid "Renaming %s to %s and %s to %s instead" +msgstr "Byter namn på %s till %s och %s till %s istället" + +#: merge-recursive.c:1464 +#, c-format +msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s" +msgstr "KONFLIKT (namnbyte/tillägg): Namnbyte %s->%s i %s. %s tillagd i %s" + +#: merge-recursive.c:1474 +#, c-format +msgid "Adding merged %s" +msgstr "Lägger till sammanslagen %s" + +#: merge-recursive.c:1479 merge-recursive.c:1677 +#, c-format +msgid "Adding as %s instead" +msgstr "Lägger till som %s iställer" + +#: merge-recursive.c:1530 +#, c-format +msgid "cannot read object %s" +msgstr "kan inte läsa objektet %s" + +#: merge-recursive.c:1533 +#, c-format +msgid "object %s is not a blob" +msgstr "objektet %s är inte en blob" + +#: merge-recursive.c:1581 +msgid "modify" +msgstr "ändra" + +#: merge-recursive.c:1581 +msgid "modified" +msgstr "ändrad" + +#: merge-recursive.c:1591 +msgid "content" +msgstr "innehåll" + +#: merge-recursive.c:1598 +msgid "add/add" +msgstr "tillägg/tillägg" + +#: merge-recursive.c:1632 +#, c-format +msgid "Skipped %s (merged same as existing)" +msgstr "Hoppade över %s (sammanslagen samma som befintlig)" + +#: merge-recursive.c:1646 +#, c-format +msgid "Auto-merging %s" +msgstr "Slår ihop %s automatiskt" + +#: merge-recursive.c:1650 git-submodule.sh:844 +msgid "submodule" +msgstr "undermodul" + +#: merge-recursive.c:1651 +#, c-format +msgid "CONFLICT (%s): Merge conflict in %s" +msgstr "KONFLIKT (%s): Sammanslagningskonflikt i %s" + +#: merge-recursive.c:1741 +#, c-format +msgid "Removing %s" +msgstr "Tar bort %s" + +#: merge-recursive.c:1766 +msgid "file/directory" +msgstr "fil/katalog" + +#: merge-recursive.c:1772 +msgid "directory/file" +msgstr "katalog/fil" + +#: merge-recursive.c:1777 +#, c-format +msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s" +msgstr "" +"KONFLIKT (%s): Det finns en katalog med namnet %s i %s. Lägger till %s som %s" + +#: merge-recursive.c:1787 +#, c-format +msgid "Adding %s" +msgstr "Lägger till %s" + +#: merge-recursive.c:1804 +msgid "Fatal merge failure, shouldn't happen." +msgstr "Ödesdigert sammanslagningsfel, borde inte inträffa." + +#: merge-recursive.c:1823 +msgid "Already up-to-date!" +msgstr "Redan à jour!" + +#: merge-recursive.c:1832 +#, c-format +msgid "merging of trees %s and %s failed" +msgstr "sammanslagning av träden %s och %s misslyckades" + +#: merge-recursive.c:1862 +#, c-format +msgid "Unprocessed path??? %s" +msgstr "Obehandlad sökväg??? %s" + +#: merge-recursive.c:1907 +msgid "Merging:" +msgstr "Slår ihop:" + +#: merge-recursive.c:1920 +#, c-format +msgid "found %u common ancestor:" +msgid_plural "found %u common ancestors:" +msgstr[0] "hittade %u gemensam förfader:" +msgstr[1] "hittade %u gemensamma förfäder:" + +#: merge-recursive.c:1957 +msgid "merge returned no commit" +msgstr "sammanslagningen returnerade ingen incheckning" + +#: merge-recursive.c:2014 +#, c-format +msgid "Could not parse object '%s'" +msgstr "Kunde inte tolka objektet \"%s\"" + +#: merge-recursive.c:2026 builtin/merge.c:697 +msgid "Unable to write index." +msgstr "Kunde inte skriva indexet." + +#: parse-options.c:494 msgid "..." msgstr "..." -#: parse-options.c:511 +#: parse-options.c:512 #, c-format msgid "usage: %s" msgstr "användning: %s" #. TRANSLATORS: the colon here should align with the #. one in "usage: %s" translation -#: parse-options.c:515 +#: parse-options.c:516 #, c-format msgid " or: %s" msgstr " eller: %s" -#: parse-options.c:518 +#: parse-options.c:519 #, c-format msgid " %s" msgstr " %s" -#: remote.c:1629 +#: remote.c:1632 #, 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] "Din gren ligger före \"%s\" med %d incheckning.\n" msgstr[1] "Din gren ligger före \"%s\" med %d incheckningar.\n" -#: remote.c:1635 +#: remote.c:1638 #, c-format msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n" msgid_plural "" @@ -384,7 +646,7 @@ msgstr[0] "" msgstr[1] "" "Din gren ligger efter \"%s\" med %d incheckningar, och kan snabbspolas.\n" -#: remote.c:1643 +#: remote.c:1646 #, c-format msgid "" "Your branch and '%s' have diverged,\n" @@ -608,7 +870,7 @@ msgstr "kan inte bestämma HEAD" msgid "cannot abort from a branch yet to be born" msgstr "kan inte avbryta från en gren som ännu inte är född" -#: sequencer.c:805 builtin/apply.c:3697 +#: sequencer.c:805 builtin/apply.c:3988 #, c-format msgid "cannot open %s: %s" msgstr "kan inte öppna %s: %s" @@ -640,21 +902,21 @@ msgstr "Kan inte ångra som första incheckning" msgid "Can't cherry-pick into empty head" msgstr "Kan inte göra \"cherry-pick\" i ett tomt huvud" -#: sha1_name.c:864 +#: sha1_name.c:1044 msgid "HEAD does not point to a branch" msgstr "HEAD pekar inte på en gren" -#: sha1_name.c:867 +#: sha1_name.c:1047 #, c-format msgid "No such branch: '%s'" msgstr "Okänd gren: \"%s\"" -#: sha1_name.c:869 +#: sha1_name.c:1049 #, c-format msgid "No upstream configured for branch '%s'" msgstr "Ingen standarduppström angiven för grenen \"%s\"" -#: sha1_name.c:872 +#: sha1_name.c:1052 #, c-format msgid "Upstream branch '%s' not stored as a remote-tracking branch" msgstr "Uppströmsgrenen \"%s\" är inte lagrad som en fjärrspårande gren" @@ -668,343 +930,343 @@ msgstr "kan inte slå upp aktuell användare i passwd-filen: %s" msgid "no such user" msgstr "okänd användare" -#: wt-status.c:141 +#: wt-status.c:140 msgid "Unmerged paths:" msgstr "Ej sammanslagna sökvägar:" -#: wt-status.c:168 wt-status.c:195 +#: wt-status.c:167 wt-status.c:194 #, c-format msgid " (use \"git reset %s <file>...\" to unstage)" msgstr " (använd \"git reset %s <fil>...\" för att ta bort från kö)" -#: wt-status.c:170 wt-status.c:197 +#: wt-status.c:169 wt-status.c:196 msgid " (use \"git rm --cached <file>...\" to unstage)" msgstr " (använd \"git rm --cached <fil>...\" för att ta bort från kö)" -#: wt-status.c:174 +#: wt-status.c:173 msgid " (use \"git add <file>...\" to mark resolution)" msgstr " (använd \"git add <fil>...\" för att ange lösning)" -#: wt-status.c:176 wt-status.c:180 +#: wt-status.c:175 wt-status.c:179 msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)" msgstr " (använd \"git add/rm <fil>...\" som lämpligt för att ange lösning)" -#: wt-status.c:178 +#: wt-status.c:177 msgid " (use \"git rm <file>...\" to mark resolution)" msgstr " (använd \"git rm <fil>...\" för att ange lösning)" -#: wt-status.c:189 +#: wt-status.c:188 msgid "Changes to be committed:" msgstr "Ändringar att checka in:" -#: wt-status.c:207 +#: wt-status.c:206 msgid "Changes not staged for commit:" msgstr "Ändringar ej i incheckningskön:" -#: wt-status.c:211 +#: wt-status.c:210 msgid " (use \"git add <file>...\" to update what will be committed)" msgstr "" " (använd \"git add <fil>...\" för att uppdatera vad som skall checkas in)" -#: wt-status.c:213 +#: wt-status.c:212 msgid " (use \"git add/rm <file>...\" to update what will be committed)" msgstr "" " (använd \"git add/rm <fil>...\" för att uppdatera vad som skall checkas in)" -#: wt-status.c:214 +#: wt-status.c:213 msgid "" " (use \"git checkout -- <file>...\" to discard changes in working directory)" msgstr "" " (använd \"git checkout -- <fil>...\" för att förkasta ändringar i " "arbetskatalogen)" -#: wt-status.c:216 +#: wt-status.c:215 msgid " (commit or discard the untracked or modified content in submodules)" msgstr "" " (checka in eller förkasta ospårat eller ändrat innehåll i undermoduler)" # %s är ett verb ("Untracked"/"Ignored"); lägg till ett -e. -#: wt-status.c:225 +#: wt-status.c:224 #, c-format msgid "%s files:" msgstr "%se filer:" -#: wt-status.c:228 +#: wt-status.c:227 #, c-format msgid " (use \"git %s <file>...\" to include in what will be committed)" msgstr "" -" (använd \"git %s <fil>...\" för att ta med i vad som skall checkas in)" +" (använd \"git %s <fil>...\" för att ta med i det som skall checkas in)" -#: wt-status.c:245 +#: wt-status.c:244 msgid "bug" msgstr "programfel" -#: wt-status.c:250 +#: wt-status.c:249 msgid "both deleted:" msgstr "borttaget av bägge:" -#: wt-status.c:251 +#: wt-status.c:250 msgid "added by us:" msgstr "tillagt av oss:" -#: wt-status.c:252 +#: wt-status.c:251 msgid "deleted by them:" msgstr "borttaget av dem:" -#: wt-status.c:253 +#: wt-status.c:252 msgid "added by them:" msgstr "tillagt av dem:" -#: wt-status.c:254 +#: wt-status.c:253 msgid "deleted by us:" msgstr "borttaget av oss:" -#: wt-status.c:255 +#: wt-status.c:254 msgid "both added:" msgstr "tillagt av bägge:" -#: wt-status.c:256 +#: wt-status.c:255 msgid "both modified:" msgstr "ändrat av bägge:" -#: wt-status.c:286 +#: wt-status.c:285 msgid "new commits, " msgstr "nya incheckningar, " -#: wt-status.c:288 +#: wt-status.c:287 msgid "modified content, " msgstr "ändrat innehåll, " -#: wt-status.c:290 +#: wt-status.c:289 msgid "untracked content, " msgstr "ospårat innehåll, " -#: wt-status.c:304 +#: wt-status.c:303 #, c-format msgid "new file: %s" msgstr "ny fil: %s" -#: wt-status.c:307 +#: wt-status.c:306 #, c-format msgid "copied: %s -> %s" msgstr "kopierad: %s -> %s" -#: wt-status.c:310 +#: wt-status.c:309 #, c-format msgid "deleted: %s" msgstr "borttagen: %s" -#: wt-status.c:313 +#: wt-status.c:312 #, c-format msgid "modified: %s" msgstr "ändrad: %s" -#: wt-status.c:316 +#: wt-status.c:315 #, c-format msgid "renamed: %s -> %s" msgstr "namnbyte: %s -> %s" -#: wt-status.c:319 +#: wt-status.c:318 #, c-format msgid "typechange: %s" msgstr "typbyte: %s" -#: wt-status.c:322 +#: wt-status.c:321 #, c-format msgid "unknown: %s" msgstr "okänd: %s" -#: wt-status.c:325 +#: wt-status.c:324 #, c-format msgid "unmerged: %s" msgstr "osammansl.: %s" -#: wt-status.c:328 +#: wt-status.c:327 #, c-format msgid "bug: unhandled diff status %c" msgstr "programfel: diff-status %c ej hanterad" -#: wt-status.c:786 +#: wt-status.c:785 msgid "You have unmerged paths." msgstr "Du har ej sammanslagna sökvägar." -#: wt-status.c:789 wt-status.c:913 +#: wt-status.c:788 wt-status.c:912 msgid " (fix conflicts and run \"git commit\")" msgstr " (rätta konflikter och kör \"git commit\")" -#: wt-status.c:792 +#: wt-status.c:791 msgid "All conflicts fixed but you are still merging." msgstr "Alla konflikter har rättats men du är fortfarande i en sammanslagning." -#: wt-status.c:795 +#: wt-status.c:794 msgid " (use \"git commit\" to conclude merge)" msgstr " (använd \"git commit\" för att slutföra sammanslagningen)" -#: wt-status.c:805 +#: wt-status.c:804 msgid "You are in the middle of an am session." msgstr "Du är i mitten av en körning av \"git am\"." -#: wt-status.c:808 +#: wt-status.c:807 msgid "The current patch is empty." msgstr "Aktuell patch är tom." -#: wt-status.c:812 +#: wt-status.c:811 msgid " (fix conflicts and then run \"git am --resolved\")" msgstr " (rätta konflikter och kör sedan \"git am --resolved\")" -#: wt-status.c:814 +#: wt-status.c:813 msgid " (use \"git am --skip\" to skip this patch)" msgstr " (använd \"git am --skip\" för att hoppa över patchen)" -#: wt-status.c:816 +#: wt-status.c:815 msgid " (use \"git am --abort\" to restore the original branch)" msgstr " (använd \"git am --abort\" för att återställa ursprungsgrenen)" -#: wt-status.c:874 wt-status.c:884 +#: wt-status.c:873 wt-status.c:883 msgid "You are currently rebasing." msgstr "Du håller på med en ombasering." -#: wt-status.c:877 +#: wt-status.c:876 msgid " (fix conflicts and then run \"git rebase --continue\")" msgstr " (rätta konflikter och kör sedan \"git rebase --continue\")" -#: wt-status.c:879 +#: wt-status.c:878 msgid " (use \"git rebase --skip\" to skip this patch)" msgstr " (använd \"git rebase --skip\" för att hoppa över patchen)" -#: wt-status.c:881 +#: wt-status.c:880 msgid " (use \"git rebase --abort\" to check out the original branch)" msgstr " (använd \"git rebase --abort\" för att checka ut ursprungsgrenen)" -#: wt-status.c:887 +#: wt-status.c:886 msgid " (all conflicts fixed: run \"git rebase --continue\")" msgstr " (alla konflikter rättade: kör \"git rebase --continue\")" -#: wt-status.c:889 +#: wt-status.c:888 msgid "You are currently splitting a commit during a rebase." msgstr "Du håller på att dela upp en incheckning i en ombasering." -#: wt-status.c:892 +#: wt-status.c:891 msgid " (Once your working directory is clean, run \"git rebase --continue\")" msgstr " (Så fort din arbetskatalog är ren, kör \"git rebase --continue\")" -#: wt-status.c:894 +#: wt-status.c:893 msgid "You are currently editing a commit during a rebase." msgstr "Du håller på att redigera en incheckning under en ombasering." -#: wt-status.c:897 +#: wt-status.c:896 msgid " (use \"git commit --amend\" to amend the current commit)" msgstr "" " (använd \"git commit --amend\" för att lägga till på aktuell incheckning)" -#: wt-status.c:899 +#: wt-status.c:898 msgid "" " (use \"git rebase --continue\" once you are satisfied with your changes)" msgstr " (använd \"git rebase --continue\" när du är nöjd med dina ändringar)" -#: wt-status.c:909 +#: wt-status.c:908 msgid "You are currently cherry-picking." msgstr "Du håller på med en \"cherry-pick\"." -#: wt-status.c:916 +#: wt-status.c:915 msgid " (all conflicts fixed: run \"git commit\")" msgstr " (alla konflikter har rättats: kör \"git commit\")" -#: wt-status.c:925 +#: wt-status.c:924 msgid "You are currently bisecting." msgstr "Du håller på med en \"bisect\"." -#: wt-status.c:928 +#: wt-status.c:927 msgid " (use \"git bisect reset\" to get back to the original branch)" msgstr "" " (använd \"git bisect reset\" för att komma tillbaka till ursprungsgrenen)" -#: wt-status.c:979 +#: wt-status.c:978 msgid "On branch " msgstr "På grenen " -#: wt-status.c:986 +#: wt-status.c:985 msgid "Not currently on any branch." msgstr "Inte på någon gren för närvarande." -#: wt-status.c:998 +#: wt-status.c:997 msgid "Initial commit" msgstr "Första incheckning" -#: wt-status.c:1012 +#: wt-status.c:1011 msgid "Untracked" msgstr "Ospårad" -#: wt-status.c:1014 +#: wt-status.c:1013 msgid "Ignored" msgstr "Ignorerad" # %s är nästa sträng eller tom. -#: wt-status.c:1016 +#: wt-status.c:1015 #, c-format msgid "Untracked files not listed%s" msgstr "Ospårade filer visas ej%s" -#: wt-status.c:1018 +#: wt-status.c:1017 msgid " (use -u option to show untracked files)" msgstr " (använd flaggan -u för att visa ospårade filer)" -#: wt-status.c:1024 +#: wt-status.c:1023 msgid "No changes" msgstr "Inga ändringar" -#: wt-status.c:1028 +#: wt-status.c:1027 #, c-format msgid "no changes added to commit%s\n" msgstr "inga ändringar att checka in%s\n" -#: wt-status.c:1030 +#: wt-status.c:1029 msgid " (use \"git add\" and/or \"git commit -a\")" msgstr " (använd \"git add\" och/eller \"git commit -a\")" -#: wt-status.c:1032 +#: wt-status.c:1031 #, c-format msgid "nothing added to commit but untracked files present%s\n" msgstr "inget köat för incheckning, men ospårade filer finns%s\n" -#: wt-status.c:1034 +#: wt-status.c:1033 msgid " (use \"git add\" to track)" -msgstr " (använd \"git add\" för att spåra)" +msgstr " (spåra med \"git add\")" -#: wt-status.c:1036 wt-status.c:1039 wt-status.c:1042 +#: wt-status.c:1035 wt-status.c:1038 wt-status.c:1041 #, c-format msgid "nothing to commit%s\n" msgstr "inget att checka in%s\n" -#: wt-status.c:1037 +#: wt-status.c:1036 msgid " (create/copy files and use \"git add\" to track)" -msgstr " (skapa/kopiera filer och använd \"git add\" för att spåra)" +msgstr " (skapa/kopiera filer och spåra med \"git add\")" -#: wt-status.c:1040 +#: wt-status.c:1039 msgid " (use -u to show untracked files)" msgstr " (använd -u för att visa ospårade filer)" -#: wt-status.c:1043 +#: wt-status.c:1042 msgid " (working directory clean)" msgstr " (arbetskatalogen ren)" -#: wt-status.c:1151 +#: wt-status.c:1150 msgid "HEAD (no branch)" msgstr "HEAD (ingen gren)" -#: wt-status.c:1157 +#: wt-status.c:1156 msgid "Initial commit on " msgstr "Första incheckning på " -#: wt-status.c:1172 +#: wt-status.c:1171 msgid "behind " msgstr "efter " -#: wt-status.c:1175 wt-status.c:1178 +#: wt-status.c:1174 wt-status.c:1177 msgid "ahead " msgstr "före " -#: wt-status.c:1180 +#: wt-status.c:1179 msgid ", behind " msgstr ", efter " @@ -1013,7 +1275,7 @@ msgstr ", efter " msgid "unexpected diff status %c" msgstr "diff-status %c förväntades inte" -#: builtin/add.c:67 builtin/commit.c:226 +#: builtin/add.c:67 builtin/commit.c:229 msgid "updating files failed" msgstr "misslyckades uppdatera filer" @@ -1103,75 +1365,75 @@ msgstr "Inget angivet, inget tillagt.\n" msgid "Maybe you wanted to say 'git add .'?\n" msgstr "Kanske menade du att skriva \"git add .\"?\n" -#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:286 builtin/mv.c:82 +#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:289 builtin/mv.c:82 #: builtin/rm.c:162 msgid "index file corrupt" msgstr "indexfilen trasig" -#: builtin/add.c:480 builtin/apply.c:4108 builtin/mv.c:229 builtin/rm.c:260 +#: builtin/add.c:480 builtin/apply.c:4433 builtin/mv.c:229 builtin/rm.c:260 msgid "Unable to write new index file" msgstr "Kunde inte skriva ny indexfil" -#: builtin/apply.c:53 +#: builtin/apply.c:57 msgid "git apply [options] [<patch>...]" msgstr "git apply [flaggor] [<patch>...]" -#: builtin/apply.c:106 +#: builtin/apply.c:110 #, c-format msgid "unrecognized whitespace option '%s'" msgstr "okänt alternativ för whitespace: \"%s\"" -#: builtin/apply.c:121 +#: builtin/apply.c:125 #, c-format msgid "unrecognized whitespace ignore option '%s'" msgstr "okänt alternativ för ignore-whitespace: \"%s\"" -#: builtin/apply.c:815 +#: builtin/apply.c:824 #, c-format msgid "Cannot prepare timestamp regexp %s" msgstr "Kan inte förbereda reguljärt uttryck för tidsstämpeln %s" -#: builtin/apply.c:824 +#: builtin/apply.c:833 #, c-format msgid "regexec returned %d for input: %s" msgstr "regexec returnerade %d för indata: %s" -#: builtin/apply.c:905 +#: builtin/apply.c:914 #, c-format msgid "unable to find filename in patch at line %d" msgstr "kan inte hitta filnamn i patchen på rad %d" -#: builtin/apply.c:937 +#: builtin/apply.c:946 #, c-format msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d" msgstr "git apply: dålig git-diff - förväntade /dev/null, fick %s på rad %d" -#: builtin/apply.c:941 +#: builtin/apply.c:950 #, c-format msgid "git apply: bad git-diff - inconsistent new filename on line %d" msgstr "git apply: dålig git-diff - motsägande nytt filnamn på rad %d" -#: builtin/apply.c:942 +#: builtin/apply.c:951 #, c-format msgid "git apply: bad git-diff - inconsistent old filename on line %d" msgstr "git apply: dålig git-diff - motsägande gammalt filnamn på rad %d" -#: builtin/apply.c:949 +#: builtin/apply.c:958 #, c-format msgid "git apply: bad git-diff - expected /dev/null on line %d" msgstr "git apply: dålig git-diff - förväntade /dev/null på rad %d" -#: builtin/apply.c:1394 +#: builtin/apply.c:1403 #, c-format msgid "recount: unexpected line: %.*s" msgstr "recount: förväntade rad: %.*s" -#: builtin/apply.c:1451 +#: builtin/apply.c:1460 #, c-format msgid "patch fragment without header at line %d: %.*s" msgstr "patch-fragment utan huvud på rad %d: %.*s" -#: builtin/apply.c:1468 +#: builtin/apply.c:1477 #, c-format msgid "" "git diff header lacks filename information when removing %d leading pathname " @@ -1187,82 +1449,82 @@ msgstr[1] "" "sökvägskomponenter\n" "tas bort (rad %d)" -#: builtin/apply.c:1628 +#: builtin/apply.c:1637 msgid "new file depends on old contents" msgstr "ny fil beror på gammalt innehåll" -#: builtin/apply.c:1630 +#: builtin/apply.c:1639 msgid "deleted file still has contents" msgstr "borttagen fil har fortfarande innehåll" -#: builtin/apply.c:1656 +#: builtin/apply.c:1665 #, c-format msgid "corrupt patch at line %d" msgstr "trasig patch på rad %d" -#: builtin/apply.c:1692 +#: builtin/apply.c:1701 #, c-format msgid "new file %s depends on old contents" msgstr "nya filen %s beror på gammalt innehåll" -#: builtin/apply.c:1694 +#: builtin/apply.c:1703 #, c-format msgid "deleted file %s still has contents" msgstr "borttagna filen %s har fortfarande innehåll" -#: builtin/apply.c:1697 +#: builtin/apply.c:1706 #, c-format msgid "** warning: file %s becomes empty but is not deleted" msgstr "** varning: filen %s blir tom men har inte tagits bort" -#: builtin/apply.c:1843 +#: builtin/apply.c:1852 #, c-format msgid "corrupt binary patch at line %d: %.*s" msgstr "trasig binärpatch på rad %d: %.*s" #. there has to be one hunk (forward hunk) -#: builtin/apply.c:1872 +#: builtin/apply.c:1881 #, c-format msgid "unrecognized binary patch at line %d" msgstr "binärpatchen på rad %d känns inte igen" -#: builtin/apply.c:1958 +#: builtin/apply.c:1967 #, c-format msgid "patch with only garbage at line %d" msgstr "patch med bara skräp på rad %d" -#: builtin/apply.c:2048 +#: builtin/apply.c:2057 #, c-format msgid "unable to read symlink %s" msgstr "kunde inte läsa symboliska länken %s" -#: builtin/apply.c:2052 +#: builtin/apply.c:2061 #, c-format msgid "unable to open or read %s" msgstr "kunde inte öppna eller läsa %s" -#: builtin/apply.c:2123 +#: builtin/apply.c:2132 msgid "oops" msgstr "hoppsan" -#: builtin/apply.c:2645 +#: builtin/apply.c:2654 #, c-format msgid "invalid start of line: '%c'" msgstr "felaktig inledning på rad: \"%c\"" -#: builtin/apply.c:2763 +#: builtin/apply.c:2772 #, c-format msgid "Hunk #%d succeeded at %d (offset %d line)." msgid_plural "Hunk #%d succeeded at %d (offset %d lines)." msgstr[0] "Stycke %d lyckades på %d (offset %d rad)." msgstr[1] "Stycke %d lyckades på %d (offset %d rader)." -#: builtin/apply.c:2775 +#: builtin/apply.c:2784 #, c-format msgid "Context reduced to (%ld/%ld) to apply fragment at %d" msgstr "Sammanhang reducerat till (%ld/%ld) för att tillämpa fragment vid %d" -#: builtin/apply.c:2781 +#: builtin/apply.c:2790 #, c-format msgid "" "while searching for:\n" @@ -1271,313 +1533,321 @@ msgstr "" "vid sökning efter:\n" "%.*s" -#: builtin/apply.c:2800 +#: builtin/apply.c:2809 #, c-format msgid "missing binary patch data for '%s'" msgstr "saknar binära patchdata för \"%s\"" -#: builtin/apply.c:2903 +#: builtin/apply.c:2912 #, c-format msgid "binary patch does not apply to '%s'" msgstr "binärpatchen kan inte tillämpas på \"%s\"" -#: builtin/apply.c:2909 +#: builtin/apply.c:2918 #, c-format msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)" msgstr "binärpatchen på \"%s\" ger felaktigt resultat (förväntade %s, fick %s)" -#: builtin/apply.c:2930 +#: builtin/apply.c:2939 #, c-format msgid "patch failed: %s:%ld" msgstr "patch misslyckades: %s:%ld" -#: builtin/apply.c:3045 +#: builtin/apply.c:3061 #, c-format -msgid "patch %s has been renamed/deleted" -msgstr "patchen %s har ändrat namn/tagits bort" +msgid "cannot checkout %s" +msgstr "kan inte checka ut %s" -#: builtin/apply.c:3052 builtin/apply.c:3069 +#: builtin/apply.c:3106 builtin/apply.c:3115 builtin/apply.c:3159 #, c-format msgid "read of %s failed" msgstr "misslyckades läsa %s" -#: builtin/apply.c:3084 -msgid "removal patch leaves file contents" -msgstr "patch för borttagning lämnar kvar filinnehåll" - -#: builtin/apply.c:3105 +#: builtin/apply.c:3139 builtin/apply.c:3361 #, c-format -msgid "%s: already exists in working directory" -msgstr "%s: finns redan i arbetskatalogen" +msgid "path %s has been renamed/deleted" +msgstr "sökvägen %s har ändrat namn/tagits bort" -#: builtin/apply.c:3143 +#: builtin/apply.c:3220 builtin/apply.c:3375 #, c-format -msgid "%s: has been deleted/renamed" -msgstr "%s: har tagits bort/ändrat namn" +msgid "%s: does not exist in index" +msgstr "%s: finns inte i indexet" -#: builtin/apply.c:3148 builtin/apply.c:3179 +#: builtin/apply.c:3224 builtin/apply.c:3367 builtin/apply.c:3389 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: builtin/apply.c:3159 -#, c-format -msgid "%s: does not exist in index" -msgstr "%s: finns inte i indexet" - -#: builtin/apply.c:3173 +#: builtin/apply.c:3229 builtin/apply.c:3383 #, c-format msgid "%s: does not match index" msgstr "%s: motsvarar inte indexet" -#: builtin/apply.c:3190 +#: builtin/apply.c:3331 +msgid "removal patch leaves file contents" +msgstr "patch för borttagning lämnar kvar filinnehåll" + +#: builtin/apply.c:3400 #, c-format msgid "%s: wrong type" msgstr "%s: fel typ" -#: builtin/apply.c:3192 +#: builtin/apply.c:3402 #, c-format msgid "%s has type %o, expected %o" msgstr "%s har typen %o, förväntade %o" -#: builtin/apply.c:3247 +#: builtin/apply.c:3503 #, c-format msgid "%s: already exists in index" msgstr "%s: finns redan i indexet" -#: builtin/apply.c:3267 +#: builtin/apply.c:3506 +#, c-format +msgid "%s: already exists in working directory" +msgstr "%s: finns redan i arbetskatalogen" + +#: builtin/apply.c:3526 #, c-format msgid "new mode (%o) of %s does not match old mode (%o)" msgstr "nytt läge (%o) för %s motsvarar inte gammalt läge (%o)" -#: builtin/apply.c:3272 +#: builtin/apply.c:3531 #, c-format msgid "new mode (%o) of %s does not match old mode (%o) of %s" msgstr "nytt läge (%o) för %s motsvarar inte gammalt läge (%o) för %s" -#: builtin/apply.c:3280 +#: builtin/apply.c:3539 #, c-format msgid "%s: patch does not apply" msgstr "%s: patchen kan inte tillämpas" -#: builtin/apply.c:3293 +#: builtin/apply.c:3552 #, c-format msgid "Checking patch %s..." msgstr "Kontrollerar patchen %s..." -#: builtin/apply.c:3348 builtin/checkout.c:212 builtin/reset.c:158 +#: builtin/apply.c:3607 builtin/checkout.c:213 builtin/reset.c:158 #, c-format msgid "make_cache_entry failed for path '%s'" msgstr "make_cache_entry misslyckades för sökvägen \"%s\"" -#: builtin/apply.c:3491 +#: builtin/apply.c:3750 #, c-format msgid "unable to remove %s from index" msgstr "kan inte ta bort %s från indexet" -#: builtin/apply.c:3518 +#: builtin/apply.c:3778 #, c-format msgid "corrupt patch for subproject %s" msgstr "trasig patch för underprojektet %s" -#: builtin/apply.c:3522 +#: builtin/apply.c:3782 #, c-format msgid "unable to stat newly created file '%s'" msgstr "kan inte ta status på nyligen skapade filen \"%s\"" -#: builtin/apply.c:3527 +#: builtin/apply.c:3787 #, c-format msgid "unable to create backing store for newly created file %s" msgstr "kan inte skapa säkerhetsminne för nyligen skapade filen %s" -#: builtin/apply.c:3530 +#: builtin/apply.c:3790 builtin/apply.c:3898 #, c-format msgid "unable to add cache entry for %s" msgstr "kan inte lägga till cachepost för %s" -#: builtin/apply.c:3563 +#: builtin/apply.c:3823 #, c-format msgid "closing file '%s'" msgstr "stänger filen \"%s\"" -#: builtin/apply.c:3612 +#: builtin/apply.c:3872 #, c-format msgid "unable to write file '%s' mode %o" msgstr "kan inte skriva filen \"%s\" läge %o" -#: builtin/apply.c:3668 +#: builtin/apply.c:3959 #, c-format msgid "Applied patch %s cleanly." msgstr "Tillämpade patchen %s rent." -#: builtin/apply.c:3676 +#: builtin/apply.c:3967 msgid "internal error" msgstr "internt fel" #. Say this even without --verbose -#: builtin/apply.c:3679 +#: builtin/apply.c:3970 #, c-format msgid "Applying patch %%s with %d reject..." msgid_plural "Applying patch %%s with %d rejects..." msgstr[0] "Tillämpade patchen %%s med %d refuserad..." msgstr[1] "Tillämpade patchen %%s med %d refuserade..." -#: builtin/apply.c:3689 +#: builtin/apply.c:3980 #, c-format msgid "truncating .rej filename to %.*s.rej" msgstr "trunkerar .rej-filnamnet till %.*s.rej" -#: builtin/apply.c:3710 +#: builtin/apply.c:4001 #, c-format msgid "Hunk #%d applied cleanly." msgstr "Stycke %d tillämpades rent." -#: builtin/apply.c:3713 +#: builtin/apply.c:4004 #, c-format msgid "Rejected hunk #%d." msgstr "Refuserar stycke %d." -#: builtin/apply.c:3844 +#: builtin/apply.c:4154 msgid "unrecognized input" msgstr "indata känns inte igen" -#: builtin/apply.c:3855 +#: builtin/apply.c:4165 msgid "unable to read index file" msgstr "kan inte läsa indexfilen" -#: builtin/apply.c:3970 builtin/apply.c:3973 +#: builtin/apply.c:4284 builtin/apply.c:4287 msgid "path" msgstr "sökväg" -#: builtin/apply.c:3971 +#: builtin/apply.c:4285 msgid "don't apply changes matching the given path" msgstr "tillämpa inte ändringar som motsvarar given sökväg" -#: builtin/apply.c:3974 +#: builtin/apply.c:4288 msgid "apply changes matching the given path" msgstr "tillämpa ändringar som motsvarar given sökväg" -#: builtin/apply.c:3976 +#: builtin/apply.c:4290 msgid "num" msgstr "antal" -#: builtin/apply.c:3977 +#: builtin/apply.c:4291 msgid "remove <num> leading slashes from traditional diff paths" msgstr "ta bort <antal> inledande snedstreck från traditionella diff-sökvägar" -#: builtin/apply.c:3980 +#: builtin/apply.c:4294 msgid "ignore additions made by the patch" msgstr "ignorera tillägg gjorda av patchen" -#: builtin/apply.c:3982 +#: builtin/apply.c:4296 msgid "instead of applying the patch, output diffstat for the input" msgstr "istället för att tillämpa patchen, skriv ut diffstat för indata" -#: builtin/apply.c:3986 +#: builtin/apply.c:4300 msgid "shows number of added and deleted lines in decimal notation" msgstr "visar antal tillagda och borttagna rader decimalt" -#: builtin/apply.c:3988 +#: builtin/apply.c:4302 msgid "instead of applying the patch, output a summary for the input" msgstr "istället för att tillämpa patchen, skriv ut en summering av indata" -#: builtin/apply.c:3990 +#: builtin/apply.c:4304 msgid "instead of applying the patch, see if the patch is applicable" msgstr "istället för att tillämpa patchen, se om patchen kan tillämpas" -#: builtin/apply.c:3992 +#: builtin/apply.c:4306 msgid "make sure the patch is applicable to the current index" msgstr "se till att patchen kan tillämpas på aktuellt index" -#: builtin/apply.c:3994 +#: builtin/apply.c:4308 msgid "apply a patch without touching the working tree" msgstr "tillämpa en patch utan att röra arbetskatalogen" -#: builtin/apply.c:3996 +#: builtin/apply.c:4310 msgid "also apply the patch (use with --stat/--summary/--check)" msgstr "tillämpa också patchen (använd med --stat/--summary/--check)" -#: builtin/apply.c:3998 +#: builtin/apply.c:4312 +msgid "attempt three-way merge if a patch does not apply" +msgstr "försök en trevägssammanslagning om patchen inte kan tillämpas" + +#: builtin/apply.c:4314 msgid "build a temporary index based on embedded index information" msgstr "bygg ett temporärt index baserat på inbyggd indexinformation" -#: builtin/apply.c:4000 +#: builtin/apply.c:4316 msgid "paths are separated with NUL character" msgstr "sökvägar avdelas med NUL-tecken" -#: builtin/apply.c:4003 +#: builtin/apply.c:4319 msgid "ensure at least <n> lines of context match" msgstr "se till att åtminstone <n> rader sammanhang är lika" -#: builtin/apply.c:4004 +#: builtin/apply.c:4320 msgid "action" msgstr "åtgärd" -#: builtin/apply.c:4005 +#: builtin/apply.c:4321 msgid "detect new or modified lines that have whitespace errors" msgstr "detektera nya eller ändrade rader som har fel i blanktecken" -#: builtin/apply.c:4008 builtin/apply.c:4011 +#: builtin/apply.c:4324 builtin/apply.c:4327 msgid "ignore changes in whitespace when finding context" msgstr "ignorera ändringar i blanktecken för sammanhang" -#: builtin/apply.c:4014 +#: builtin/apply.c:4330 msgid "apply the patch in reverse" msgstr "tillämpa patchen baklänges" -#: builtin/apply.c:4016 +#: builtin/apply.c:4332 msgid "don't expect at least one line of context" msgstr "förvänta inte minst en rad sammanhang" -#: builtin/apply.c:4018 +#: builtin/apply.c:4334 msgid "leave the rejected hunks in corresponding *.rej files" msgstr "lämna refuserade stycken i motsvarande *.rej-filer" -#: builtin/apply.c:4020 +#: builtin/apply.c:4336 msgid "allow overlapping hunks" msgstr "tillåt överlappande stycken" -#: builtin/apply.c:4021 +#: builtin/apply.c:4337 msgid "be verbose" msgstr "var pratsam" -#: builtin/apply.c:4023 +#: builtin/apply.c:4339 msgid "tolerate incorrectly detected missing new-line at the end of file" msgstr "tolerera felaktigt detekterade saknade nyradstecken vid filslut" -#: builtin/apply.c:4026 +#: builtin/apply.c:4342 msgid "do not trust the line counts in the hunk headers" msgstr "lite inte på antalet linjer i styckehuvuden" -#: builtin/apply.c:4028 +#: builtin/apply.c:4344 msgid "root" msgstr "rot" -#: builtin/apply.c:4029 +#: builtin/apply.c:4345 msgid "prepend <root> to all filenames" msgstr "lägg till <rot> i alla filnamn" -#: builtin/apply.c:4050 +#: builtin/apply.c:4367 +msgid "--3way outside a repository" +msgstr "--3way utanför arkiv" + +#: builtin/apply.c:4375 msgid "--index outside a repository" msgstr "--index utanför arkiv" -#: builtin/apply.c:4053 +#: builtin/apply.c:4378 msgid "--cached outside a repository" msgstr "--cached utanför arkiv" -#: builtin/apply.c:4069 +#: builtin/apply.c:4394 #, c-format msgid "can't open patch '%s'" msgstr "kan inte öppna patchen \"%s\"" -#: builtin/apply.c:4083 +#: builtin/apply.c:4408 #, c-format msgid "squelched %d whitespace error" msgid_plural "squelched %d whitespace errors" msgstr[0] "undertryckte %d fel i blanksteg" msgstr[1] "undertryckte %d fel i blanksteg" -#: builtin/apply.c:4089 builtin/apply.c:4099 +#: builtin/apply.c:4414 builtin/apply.c:4424 #, c-format msgid "%d line adds whitespace errors." msgid_plural "%d lines add whitespace errors." @@ -1783,7 +2053,7 @@ msgstr "kunde inte skriva grenbeskrivningsmall: %s" msgid "Failed to resolve HEAD as a valid ref." msgstr "Misslyckades slå upp HEAD som giltig referens" -#: builtin/branch.c:788 builtin/clone.c:558 +#: builtin/branch.c:788 builtin/clone.c:561 msgid "HEAD not found below refs/heads!" msgstr "HEAD hittades inte under refs/heads!" @@ -1810,99 +2080,99 @@ msgstr "Behöver ett arkiv för att skapa ett paket (bundle)." msgid "Need a repository to unbundle." msgstr "Behöver ett arkiv för att packa upp ett paket (bundle)." -#: builtin/checkout.c:113 builtin/checkout.c:146 +#: builtin/checkout.c:114 builtin/checkout.c:147 #, c-format msgid "path '%s' does not have our version" msgstr "sökvägen \"%s\" har inte vår version" -#: builtin/checkout.c:115 builtin/checkout.c:148 +#: builtin/checkout.c:116 builtin/checkout.c:149 #, c-format msgid "path '%s' does not have their version" msgstr "sökvägen \"%s\" har inte deras version" -#: builtin/checkout.c:131 +#: builtin/checkout.c:132 #, c-format msgid "path '%s' does not have all necessary versions" msgstr "sökvägen \"%s\" innehåller inte alla nödvändiga versioner" -#: builtin/checkout.c:175 +#: builtin/checkout.c:176 #, c-format msgid "path '%s' does not have necessary versions" msgstr "sökvägen \"%s\" innehåller inte nödvändiga versioner" -#: builtin/checkout.c:192 +#: builtin/checkout.c:193 #, c-format msgid "path '%s': cannot merge" msgstr "sökväg \"%s\": kan inte slå ihop" -#: builtin/checkout.c:209 +#: builtin/checkout.c:210 #, c-format msgid "Unable to add merge result for '%s'" msgstr "Kunde inte lägga till sammanslagningsresultat för \"%s\"" -#: builtin/checkout.c:234 builtin/checkout.c:392 +#: builtin/checkout.c:235 builtin/checkout.c:393 msgid "corrupt index file" msgstr "indexfilen är trasig" -#: builtin/checkout.c:264 builtin/checkout.c:271 +#: builtin/checkout.c:265 builtin/checkout.c:272 #, c-format msgid "path '%s' is unmerged" msgstr "sökvägen \"%s\" har inte slagits ihop" -#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583 +#: builtin/checkout.c:303 builtin/checkout.c:499 builtin/clone.c:586 #: builtin/merge.c:812 msgid "unable to write new index file" msgstr "kunde inte skriva ny indexfil" -#: builtin/checkout.c:319 builtin/diff.c:302 builtin/merge.c:408 +#: builtin/checkout.c:320 builtin/diff.c:302 builtin/merge.c:408 msgid "diff_setup_done failed" msgstr "diff_setup_done misslyckades" -#: builtin/checkout.c:414 +#: builtin/checkout.c:415 msgid "you need to resolve your current index first" msgstr "du måste lösa ditt befintliga index först" -#: builtin/checkout.c:533 +#: builtin/checkout.c:534 #, c-format msgid "Can not do reflog for '%s'\n" msgstr "Kan inte skapa referenslog för \"%s\"\n" -#: builtin/checkout.c:566 +#: builtin/checkout.c:567 msgid "HEAD is now at" msgstr "HEAD är nu på" -#: builtin/checkout.c:573 +#: builtin/checkout.c:574 #, c-format msgid "Reset branch '%s'\n" msgstr "Återställ gren \"%s\"\n" -#: builtin/checkout.c:576 +#: builtin/checkout.c:577 #, c-format msgid "Already on '%s'\n" msgstr "Redan på \"%s\"\n" -#: builtin/checkout.c:580 +#: builtin/checkout.c:581 #, c-format msgid "Switched to and reset branch '%s'\n" msgstr "Växlade till och nollställde grenen \"%s\"\n" -#: builtin/checkout.c:582 +#: builtin/checkout.c:583 #, c-format msgid "Switched to a new branch '%s'\n" msgstr "Växlade till en ny gren \"%s\"\n" -#: builtin/checkout.c:584 +#: builtin/checkout.c:585 #, c-format msgid "Switched to branch '%s'\n" msgstr "Växlade till grenen \"%s\"\n" -#: builtin/checkout.c:640 +#: builtin/checkout.c:641 #, c-format msgid " ... and %d more.\n" msgstr " ... och %d till.\n" #. The singular version -#: builtin/checkout.c:646 +#: builtin/checkout.c:647 #, c-format msgid "" "Warning: you are leaving %d commit behind, not connected to\n" @@ -1925,7 +2195,7 @@ msgstr[1] "" "\n" "%s\n" -#: builtin/checkout.c:664 +#: builtin/checkout.c:665 #, c-format msgid "" "If you want to keep them by creating a new branch, this may be a good time\n" @@ -1940,71 +2210,71 @@ msgstr "" " git branch nytt_grennamn %s\n" "\n" -#: builtin/checkout.c:694 +#: builtin/checkout.c:695 msgid "internal error in revision walk" msgstr "internt fel vid genomgång av revisioner (revision walk)" -#: builtin/checkout.c:698 +#: builtin/checkout.c:699 msgid "Previous HEAD position was" msgstr "Tidigare position för HEAD var" -#: builtin/checkout.c:724 +#: builtin/checkout.c:725 builtin/checkout.c:920 msgid "You are on a branch yet to be born" msgstr "Du är på en gren som ännu inte är född" #. case (1) -#: builtin/checkout.c:855 +#: builtin/checkout.c:856 #, c-format msgid "invalid reference: %s" msgstr "felaktig referens: %s" #. case (1): want a tree -#: builtin/checkout.c:894 +#: builtin/checkout.c:895 #, c-format msgid "reference is not a tree: %s" msgstr "referensen är inte ett träd: %s" -#: builtin/checkout.c:974 +#: builtin/checkout.c:977 msgid "-B cannot be used with -b" msgstr "-B kan inte användas med -b" -#: builtin/checkout.c:983 +#: builtin/checkout.c:986 msgid "--patch is incompatible with all other options" msgstr "--patch är inkompatibel med alla andra flaggor" -#: builtin/checkout.c:986 +#: builtin/checkout.c:989 msgid "--detach cannot be used with -b/-B/--orphan" msgstr "--detcah kan inte användas med -b/-B/--orphan" -#: builtin/checkout.c:988 +#: builtin/checkout.c:991 msgid "--detach cannot be used with -t" msgstr "--detach kan inte användas med -t" -#: builtin/checkout.c:994 +#: builtin/checkout.c:997 msgid "--track needs a branch name" msgstr "--track behöver ett namn på en gren" -#: builtin/checkout.c:1001 +#: builtin/checkout.c:1004 msgid "Missing branch name; try -b" msgstr "Grennamn saknas; försök med -b" -#: builtin/checkout.c:1007 +#: builtin/checkout.c:1010 msgid "--orphan and -b|-B are mutually exclusive" msgstr "--orphan och -b|-B kan inte användas samtidigt" -#: builtin/checkout.c:1009 +#: builtin/checkout.c:1012 msgid "--orphan cannot be used with -t" msgstr "--orphan kan inte användas med -t" -#: builtin/checkout.c:1019 +#: builtin/checkout.c:1022 msgid "git checkout: -f and -m are incompatible" msgstr "git checkout: -f och -m är inkompatibla" -#: builtin/checkout.c:1053 +#: builtin/checkout.c:1056 msgid "invalid path specification" msgstr "felaktig sökvägsangivelse" -#: builtin/checkout.c:1061 +#: builtin/checkout.c:1064 #, c-format msgid "" "git checkout: updating paths is incompatible with switching branches.\n" @@ -2013,15 +2283,15 @@ msgstr "" "git checkout: uppdatera sökvägar är inkompatibelt med att växla gren.\n" "Ville du checka ut \"%s\" som inte kan lösas som en sammanslaning?" -#: builtin/checkout.c:1063 +#: builtin/checkout.c:1066 msgid "git checkout: updating paths is incompatible with switching branches." msgstr "git checkout: uppdatera sökvägar är inkompatibelt med att växla gren." -#: builtin/checkout.c:1068 +#: builtin/checkout.c:1071 msgid "git checkout: --detach does not take a path argument" msgstr "git checkout: --detach tar inte en sökväg som argument" -#: builtin/checkout.c:1071 +#: builtin/checkout.c:1074 msgid "" "git checkout: --ours/--theirs, --force and --merge are incompatible when\n" "checking out of the index." @@ -2029,11 +2299,11 @@ msgstr "" "git checkout: --ours/--theirs, --force och --merge är inkompatibla när\n" "du checkar ut från indexet." -#: builtin/checkout.c:1090 +#: builtin/checkout.c:1093 msgid "Cannot switch branch to a non-commit." msgstr "Kan inte växla gren på en icke-incheckning." -#: builtin/checkout.c:1093 +#: builtin/checkout.c:1096 msgid "--ours/--theirs is incompatible with switching branches." msgstr "--ours/--theirs är inkompatibla med att byta gren." @@ -2086,11 +2356,6 @@ msgstr "Tar inte bort %s\n" msgid "reference repository '%s' is not a local directory." msgstr "referensarkivet \"%s\" är inte en lokal katalog." -#: builtin/clone.c:302 -#, c-format -msgid "failed to open '%s'" -msgstr "misslyckades öppna \"%s\"" - #: builtin/clone.c:306 #, c-format msgid "failed to create directory '%s'" @@ -2131,79 +2396,79 @@ msgstr "misslyckades kopiera filen till \"%s\"" msgid "done.\n" msgstr "klart.\n" -#: builtin/clone.c:440 +#: builtin/clone.c:443 #, c-format msgid "Could not find remote branch %s to clone." msgstr "Kunde inte hitta fjärrgrenen %s för att klona." -#: builtin/clone.c:549 +#: builtin/clone.c:552 msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n" msgstr "" "HEAD hos fjärren pekar på en obefintlig referens, kan inte checka ut.\n" -#: builtin/clone.c:639 +#: builtin/clone.c:642 msgid "Too many arguments." msgstr "För många argument." -#: builtin/clone.c:643 +#: builtin/clone.c:646 msgid "You must specify a repository to clone." msgstr "Du måste ange ett arkiv att klona." -#: builtin/clone.c:654 +#: builtin/clone.c:657 #, c-format msgid "--bare and --origin %s options are incompatible." msgstr "flaggorna --bare och --origin %s är inkompatibla." -#: builtin/clone.c:668 +#: builtin/clone.c:671 #, c-format msgid "repository '%s' does not exist" msgstr "arkivet \"%s\" finns inte" -#: builtin/clone.c:673 +#: builtin/clone.c:676 msgid "--depth is ignored in local clones; use file:// instead." msgstr "--depth ignoreras i lokala kloningar; använd file:// istället" -#: builtin/clone.c:683 +#: builtin/clone.c:686 #, c-format msgid "destination path '%s' already exists and is not an empty directory." msgstr "destinationssökvägen \"%s\" finns redan och är inte en tom katalog." -#: builtin/clone.c:693 +#: builtin/clone.c:696 #, c-format msgid "working tree '%s' already exists." msgstr "arbetsträdet \"%s\" finns redan." -#: builtin/clone.c:706 builtin/clone.c:720 +#: builtin/clone.c:709 builtin/clone.c:723 #, c-format msgid "could not create leading directories of '%s'" msgstr "kunde inte skapa inledande kataloger för \"%s\"" -#: builtin/clone.c:709 +#: builtin/clone.c:712 #, c-format msgid "could not create work tree dir '%s'." msgstr "kunde inte skapa arbetskatalogen \"%s\"" -#: builtin/clone.c:728 +#: builtin/clone.c:731 #, c-format msgid "Cloning into bare repository '%s'...\n" msgstr "Klonar till ett naket arkiv \"%s\"...\n" -#: builtin/clone.c:730 +#: builtin/clone.c:733 #, c-format msgid "Cloning into '%s'...\n" msgstr "Klonar till \"%s\"...\n" -#: builtin/clone.c:786 +#: builtin/clone.c:789 #, c-format msgid "Don't know how to clone %s" msgstr "Vet inte hur man klonar %s" -#: builtin/clone.c:835 +#: builtin/clone.c:838 #, c-format msgid "Remote branch %s not found in upstream %s" msgstr "Fjärrgrenen %s hittades inte i uppströmsarkivet %s" -#: builtin/clone.c:842 +#: builtin/clone.c:845 msgid "You appear to have cloned an empty repository." msgstr "Du verkar ha klonat ett tomt arkiv." @@ -2262,93 +2527,93 @@ msgstr "" "\n" "Annars använder du \"git reset\"\n" -#: builtin/commit.c:253 +#: builtin/commit.c:256 msgid "failed to unpack HEAD tree object" msgstr "misslyckades packa upp HEAD:s trädobjekt" -#: builtin/commit.c:295 +#: builtin/commit.c:298 msgid "unable to create temporary index" msgstr "kunde inte skapa temporär indexfil" -#: builtin/commit.c:301 +#: builtin/commit.c:304 msgid "interactive add failed" msgstr "interaktiv tilläggning misslyckades" -#: builtin/commit.c:334 builtin/commit.c:355 builtin/commit.c:405 +#: builtin/commit.c:337 builtin/commit.c:358 builtin/commit.c:408 msgid "unable to write new_index file" msgstr "kunde inte skriva filen new_index" -#: builtin/commit.c:386 +#: builtin/commit.c:389 msgid "cannot do a partial commit during a merge." msgstr "kan inte utföra en delvis incheckning under en sammanslagning." -#: builtin/commit.c:388 +#: builtin/commit.c:391 msgid "cannot do a partial commit during a cherry-pick." msgstr "kan inte utföra en delvis incheckning under en cherry-pick." -#: builtin/commit.c:398 +#: builtin/commit.c:401 msgid "cannot read the index" msgstr "kan inte läsa indexet" -#: builtin/commit.c:418 +#: builtin/commit.c:421 msgid "unable to write temporary index file" msgstr "kunde inte skriva temporär indexfil" -#: builtin/commit.c:493 builtin/commit.c:499 +#: builtin/commit.c:496 builtin/commit.c:502 #, c-format msgid "invalid commit: %s" msgstr "felaktig incheckning: %s" -#: builtin/commit.c:522 +#: builtin/commit.c:525 msgid "malformed --author parameter" msgstr "felformad \"--author\"-flagga" -#: builtin/commit.c:582 +#: builtin/commit.c:585 #, c-format msgid "Malformed ident string: '%s'" msgstr "Felaktig indragningssträng: \"%s\"" -#: builtin/commit.c:620 builtin/commit.c:653 builtin/commit.c:967 +#: builtin/commit.c:623 builtin/commit.c:656 builtin/commit.c:970 #, c-format msgid "could not lookup commit %s" msgstr "kunde inte slå upp incheckningen %s" -#: builtin/commit.c:632 builtin/shortlog.c:296 +#: builtin/commit.c:635 builtin/shortlog.c:296 #, c-format msgid "(reading log message from standard input)\n" msgstr "(läser loggmeddelande från standard in)\n" -#: builtin/commit.c:634 +#: builtin/commit.c:637 msgid "could not read log from standard input" msgstr "kunde inte läsa logg från standard in" -#: builtin/commit.c:638 +#: builtin/commit.c:641 #, c-format msgid "could not read log file '%s'" msgstr "kunde inte läsa loggfilen \"%s\"" -#: builtin/commit.c:644 +#: builtin/commit.c:647 msgid "commit has empty message" msgstr "incheckningen har ett tomt meddelande" -#: builtin/commit.c:660 +#: builtin/commit.c:663 msgid "could not read MERGE_MSG" msgstr "kunde inte läsa MERGE_MSG" -#: builtin/commit.c:664 +#: builtin/commit.c:667 msgid "could not read SQUASH_MSG" msgstr "kunde inte läsa SQUASH_MSG" -#: builtin/commit.c:668 +#: builtin/commit.c:671 #, c-format msgid "could not read '%s'" msgstr "kunde inte läsa \"%s\"" -#: builtin/commit.c:720 +#: builtin/commit.c:723 msgid "could not write commit template" msgstr "kunde inte skriva incheckningsmall" -#: builtin/commit.c:731 +#: builtin/commit.c:734 #, c-format msgid "" "\n" @@ -2363,7 +2628,7 @@ msgstr "" "\t%s\n" "och försöker igen.\n" -#: builtin/commit.c:736 +#: builtin/commit.c:739 #, c-format msgid "" "\n" @@ -2378,7 +2643,7 @@ msgstr "" "\t%s\n" "och försöker igen.\n" -#: builtin/commit.c:748 +#: builtin/commit.c:751 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be ignored, and an empty message aborts the commit.\n" @@ -2386,7 +2651,7 @@ msgstr "" "Ange incheckningsmeddelandet för dina ändringar. Rader som inleds\n" "med \"#\" kommer ignoreras, och ett tomt meddelande avbryter incheckningen.\n" -#: builtin/commit.c:753 +#: builtin/commit.c:756 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be kept; you may remove them yourself if you want to.\n" @@ -2396,159 +2661,159 @@ msgstr "" "med \"#\" kommer behållas; du kan själv ta bort dem om du vill.\n" "Ett tomt meddelande avbryter incheckningen.\n" -#: builtin/commit.c:766 +#: builtin/commit.c:769 #, c-format msgid "%sAuthor: %s" msgstr "%sFörfattare: %s" -#: builtin/commit.c:773 +#: builtin/commit.c:776 #, c-format msgid "%sCommitter: %s" msgstr "%sIncheckare: %s" -#: builtin/commit.c:793 +#: builtin/commit.c:796 msgid "Cannot read index" msgstr "Kan inte läsa indexet" -#: builtin/commit.c:830 +#: builtin/commit.c:833 msgid "Error building trees" msgstr "Fel vid byggande av träd" -#: builtin/commit.c:845 builtin/tag.c:361 +#: builtin/commit.c:848 builtin/tag.c:361 #, c-format msgid "Please supply the message using either -m or -F option.\n" msgstr "Ange meddelandet en av flaggorna -m eller -F.\n" -#: builtin/commit.c:942 +#: builtin/commit.c:945 #, c-format msgid "No existing author found with '%s'" msgstr "Hittade ingen befintlig författare med \"%s\"" -#: builtin/commit.c:957 builtin/commit.c:1157 +#: builtin/commit.c:960 builtin/commit.c:1160 #, c-format msgid "Invalid untracked files mode '%s'" msgstr "Ogiltigt läge för ospårade filer: \"%s\"" -#: builtin/commit.c:997 +#: builtin/commit.c:1000 msgid "Using both --reset-author and --author does not make sense" msgstr "Kan inte använda både --reset-author och --author" -#: builtin/commit.c:1008 +#: builtin/commit.c:1011 msgid "You have nothing to amend." msgstr "Du har inget att utöka." -#: builtin/commit.c:1011 +#: builtin/commit.c:1014 msgid "You are in the middle of a merge -- cannot amend." msgstr "Du är i mitten av en sammanslagning -- kan inte utöka." -#: builtin/commit.c:1013 +#: builtin/commit.c:1016 msgid "You are in the middle of a cherry-pick -- cannot amend." msgstr "Du är i mitten av en cherry-pick -- kan inte utöka." -#: builtin/commit.c:1016 +#: builtin/commit.c:1019 msgid "Options --squash and --fixup cannot be used together" msgstr "Flaggorna --squash och --fixup kan inte användas samtidigt" -#: builtin/commit.c:1026 +#: builtin/commit.c:1029 msgid "Only one of -c/-C/-F/--fixup can be used." msgstr "Endast en av -c/-C/-F/--fixup kan användas." -#: builtin/commit.c:1028 +#: builtin/commit.c:1031 msgid "Option -m cannot be combined with -c/-C/-F/--fixup." msgstr "Flaggan -m kan inte kombineras med -c/-C/-F/--fixup." -#: builtin/commit.c:1036 +#: builtin/commit.c:1039 msgid "--reset-author can be used only with -C, -c or --amend." msgstr "--reset-author kan endast användas med -C, -c eller --amend." -#: builtin/commit.c:1053 +#: builtin/commit.c:1056 msgid "Only one of --include/--only/--all/--interactive/--patch can be used." msgstr "" "Endast en av --include/--only/--all/--interactive/--patch kan användas." -#: builtin/commit.c:1055 +#: builtin/commit.c:1058 msgid "No paths with --include/--only does not make sense." msgstr "Du måste ange sökvägar tillsammans med --include/--only." -#: builtin/commit.c:1057 +#: builtin/commit.c:1060 msgid "Clever... amending the last one with dirty index." msgstr "Smart... utöka den senaste med smutsigt index." -#: builtin/commit.c:1059 +#: builtin/commit.c:1062 msgid "Explicit paths specified without -i nor -o; assuming --only paths..." msgstr "Explicita sökvägar angavs utan -i eller -o; antar --only sökvägar..." -#: builtin/commit.c:1069 builtin/tag.c:577 +#: builtin/commit.c:1072 builtin/tag.c:577 #, c-format msgid "Invalid cleanup mode %s" msgstr "Felaktigt städningsläge %s" -#: builtin/commit.c:1074 +#: builtin/commit.c:1077 msgid "Paths with -a does not make sense." msgstr "Kan inte ange sökvägar med -a." -#: builtin/commit.c:1257 +#: builtin/commit.c:1260 msgid "couldn't look up newly created commit" msgstr "kunde inte slå upp en precis skapad incheckning" -#: builtin/commit.c:1259 +#: builtin/commit.c:1262 msgid "could not parse newly created commit" msgstr "kunde inte tolka en precis skapad incheckning" -#: builtin/commit.c:1300 +#: builtin/commit.c:1303 msgid "detached HEAD" msgstr "frånkopplad HEAD" -#: builtin/commit.c:1302 +#: builtin/commit.c:1305 msgid " (root-commit)" msgstr " (rotincheckning)" -#: builtin/commit.c:1446 +#: builtin/commit.c:1449 msgid "could not parse HEAD commit" msgstr "kunde inte tolka HEAD:s incheckning" -#: builtin/commit.c:1484 builtin/merge.c:509 +#: builtin/commit.c:1487 builtin/merge.c:509 #, c-format msgid "could not open '%s' for reading" msgstr "kunde inte öppna \"%s\" för läsning" -#: builtin/commit.c:1491 +#: builtin/commit.c:1494 #, c-format msgid "Corrupt MERGE_HEAD file (%s)" msgstr "Trasig MERGE_HEAD-fil (%s)" -#: builtin/commit.c:1498 +#: builtin/commit.c:1501 msgid "could not read MERGE_MODE" msgstr "kunde inte läsa MERGE_MODE" -#: builtin/commit.c:1517 +#: builtin/commit.c:1520 #, c-format msgid "could not read commit message: %s" msgstr "kunde inte läsa incheckningsmeddelande: %s" -#: builtin/commit.c:1531 +#: builtin/commit.c:1534 #, c-format msgid "Aborting commit; you did not edit the message.\n" msgstr "Avbryter incheckning; meddelandet inte redigerat.\n" -#: builtin/commit.c:1536 +#: builtin/commit.c:1539 #, c-format msgid "Aborting commit due to empty commit message.\n" msgstr "Avbryter på grund av tomt incheckningsmeddelande.\n" -#: builtin/commit.c:1551 builtin/merge.c:936 builtin/merge.c:961 +#: builtin/commit.c:1554 builtin/merge.c:936 builtin/merge.c:961 msgid "failed to write commit object" msgstr "kunde inte skriva incheckningsobjekt" -#: builtin/commit.c:1572 +#: builtin/commit.c:1575 msgid "cannot lock HEAD ref" msgstr "kunde inte låsa HEAD-referens" -#: builtin/commit.c:1576 +#: builtin/commit.c:1579 msgid "cannot update HEAD ref" msgstr "kunde inte uppdatera HEAD-referens" -#: builtin/commit.c:1587 +#: builtin/commit.c:1590 msgid "" "Repository has been updated, but unable to write\n" "new_index file. Check that disk is not full or quota is\n" @@ -2922,30 +3187,30 @@ msgstr "--[no-]exclude-standard kan inte användas för spårat innehåll." msgid "both --cached and trees are given." msgstr "både --cached och träd angavs." -#: builtin/help.c:63 +#: builtin/help.c:65 #, c-format msgid "unrecognized help format '%s'" msgstr "okänt hjälpformat: %s" -#: builtin/help.c:91 +#: builtin/help.c:93 msgid "Failed to start emacsclient." msgstr "Misslyckades starta emacsclient." -#: builtin/help.c:104 +#: builtin/help.c:106 msgid "Failed to parse emacsclient version." msgstr "Kunde inte tolka emacsclient-version." -#: builtin/help.c:112 +#: builtin/help.c:114 #, c-format msgid "emacsclient version '%d' too old (< 22)." msgstr "emacsclient version \"%d\" för gammal (< 22)." -#: builtin/help.c:130 builtin/help.c:158 builtin/help.c:167 builtin/help.c:175 +#: builtin/help.c:132 builtin/help.c:160 builtin/help.c:169 builtin/help.c:177 #, c-format msgid "failed to exec '%s': %s" msgstr "exec misslyckades för \"%s\": %s" -#: builtin/help.c:215 +#: builtin/help.c:217 #, c-format msgid "" "'%s': path for unsupported man viewer.\n" @@ -2954,7 +3219,7 @@ msgstr "" "\"%s\": sökväg för man-visare som ej stöds.\n" "Använd \"man.<verktyg>.cmd\" istället." -#: builtin/help.c:227 +#: builtin/help.c:229 #, c-format msgid "" "'%s': cmd for supported man viewer.\n" @@ -2963,34 +3228,29 @@ msgstr "" "\"%s\": kommando för man-visare som stöds.\n" "Använd \"man.<verktyg>.path\" istället." -#: builtin/help.c:291 +#: builtin/help.c:299 msgid "The most commonly used git commands are:" msgstr "De mest använda git-kommandona är:" -#: builtin/help.c:359 +#: builtin/help.c:367 #, c-format msgid "'%s': unknown man viewer." msgstr "\"%s\": okänd man-visare." -#: builtin/help.c:376 +#: builtin/help.c:384 msgid "no man viewer handled the request" msgstr "ingen man-visare hanterade förfrågan" -#: builtin/help.c:384 +#: builtin/help.c:392 msgid "no info viewer handled the request" msgstr "ingen info-visare hanterade förfrågan" -#: builtin/help.c:395 -#, c-format -msgid "'%s': not a documentation directory." -msgstr "\"%s\": inte en dokumentationskatalog." - -#: builtin/help.c:436 builtin/help.c:443 +#: builtin/help.c:447 builtin/help.c:454 #, c-format msgid "usage: %s%s" msgstr "användning: %s%s" -#: builtin/help.c:459 +#: builtin/help.c:470 #, c-format msgid "`git %s' is aliased to `%s'" msgstr "\"git %s\" är ett alias för \"%s\"" @@ -3064,176 +3324,176 @@ msgstr "deltabasindex utanför gränsen" msgid "unknown object type %d" msgstr "okänd objekttyp %d" -#: builtin/index-pack.c:531 +#: builtin/index-pack.c:530 msgid "cannot pread pack file" msgstr "kan inte utföra \"pread\" på paketfil" -#: builtin/index-pack.c:533 +#: builtin/index-pack.c:532 #, c-format msgid "premature end of pack file, %lu byte missing" msgid_plural "premature end of pack file, %lu bytes missing" msgstr[0] "för tidigt slut på paketfilen, %lu byte saknas" msgstr[1] "för tidigt slut på paketfilen, %lu byte saknas" -#: builtin/index-pack.c:555 +#: builtin/index-pack.c:558 msgid "serious inflate inconsistency" msgstr "allvarlig inflate-inkonsekvens" -#: builtin/index-pack.c:646 builtin/index-pack.c:652 builtin/index-pack.c:675 -#: builtin/index-pack.c:709 builtin/index-pack.c:718 +#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678 +#: builtin/index-pack.c:712 builtin/index-pack.c:721 #, c-format msgid "SHA1 COLLISION FOUND WITH %s !" msgstr "SHA1-KOLLISION UPPTÄCKT VID %s !" -#: builtin/index-pack.c:649 builtin/pack-objects.c:170 +#: builtin/index-pack.c:652 builtin/pack-objects.c:170 #: builtin/pack-objects.c:262 #, c-format msgid "unable to read %s" msgstr "kunde inte läsa %s" -#: builtin/index-pack.c:715 +#: builtin/index-pack.c:718 #, c-format msgid "cannot read existing object %s" msgstr "kan inte läsa befintligt objekt %s" -#: builtin/index-pack.c:729 +#: builtin/index-pack.c:732 #, c-format msgid "invalid blob object %s" msgstr "ogiltigt blob-objekt %s" -#: builtin/index-pack.c:744 +#: builtin/index-pack.c:747 #, c-format msgid "invalid %s" msgstr "ogiltigt %s" -#: builtin/index-pack.c:746 +#: builtin/index-pack.c:749 msgid "Error in object" msgstr "Fel i objekt" -#: builtin/index-pack.c:748 +#: builtin/index-pack.c:751 #, c-format msgid "Not all child objects of %s are reachable" msgstr "Inte alla barnobjekt för %s kan nås" -#: builtin/index-pack.c:818 builtin/index-pack.c:844 +#: builtin/index-pack.c:821 builtin/index-pack.c:847 msgid "failed to apply delta" msgstr "misslyckades tillämpa delta" -#: builtin/index-pack.c:983 +#: builtin/index-pack.c:986 msgid "Receiving objects" -msgstr "Tar bort objeckt" +msgstr "Tar bort objekt" -#: builtin/index-pack.c:983 +#: builtin/index-pack.c:986 msgid "Indexing objects" msgstr "Skapar index för objekt" -#: builtin/index-pack.c:1009 +#: builtin/index-pack.c:1012 msgid "pack is corrupted (SHA1 mismatch)" msgstr "paketet är trasigt (SHA1 stämmer inte)" -#: builtin/index-pack.c:1014 +#: builtin/index-pack.c:1017 msgid "cannot fstat packfile" msgstr "kan inte utföra \"fstat\" på paketfil" -#: builtin/index-pack.c:1017 +#: builtin/index-pack.c:1020 msgid "pack has junk at the end" msgstr "paket har skräp i slutet" -#: builtin/index-pack.c:1028 +#: builtin/index-pack.c:1031 msgid "confusion beyond insanity in parse_pack_objects()" msgstr "förvirrad bortom vanvett i parse_pack_objects()" -#: builtin/index-pack.c:1051 +#: builtin/index-pack.c:1054 msgid "Resolving deltas" msgstr "Analyserar delta" -#: builtin/index-pack.c:1102 +#: builtin/index-pack.c:1105 msgid "confusion beyond insanity" msgstr "förvirrad bortom vanvett" -#: builtin/index-pack.c:1121 +#: builtin/index-pack.c:1124 #, c-format msgid "pack has %d unresolved delta" msgid_plural "pack has %d unresolved deltas" msgstr[0] "paketet har %d oanalyserat delta" msgstr[1] "paketet har %d oanalyserade delta" -#: builtin/index-pack.c:1146 +#: builtin/index-pack.c:1149 #, c-format msgid "unable to deflate appended object (%d)" msgstr "kunde inte utföra \"deflate\" på tillagt objekt (%d)" -#: builtin/index-pack.c:1225 +#: builtin/index-pack.c:1228 #, c-format msgid "local object %s is corrupt" msgstr "lokalt objekt %s är trasigt" -#: builtin/index-pack.c:1249 +#: builtin/index-pack.c:1252 msgid "error while closing pack file" msgstr "fel vid stängning av paketfil" -#: builtin/index-pack.c:1262 +#: builtin/index-pack.c:1265 #, c-format msgid "cannot write keep file '%s'" msgstr "kan inte ta skriva \"keep\"-fil \"%s\"" -#: builtin/index-pack.c:1270 +#: builtin/index-pack.c:1273 #, c-format msgid "cannot close written keep file '%s'" msgstr "akn inte stänga skriven \"keep\"-fil \"%s\"" -#: builtin/index-pack.c:1283 +#: builtin/index-pack.c:1286 msgid "cannot store pack file" msgstr "kan inte spara paketfil" -#: builtin/index-pack.c:1294 +#: builtin/index-pack.c:1297 msgid "cannot store index file" msgstr "kan inte spara indexfil" -#: builtin/index-pack.c:1395 +#: builtin/index-pack.c:1398 #, c-format msgid "Cannot open existing pack file '%s'" msgstr "Kan inte öppna befintlig paketfil \"%s\"" -#: builtin/index-pack.c:1397 +#: builtin/index-pack.c:1400 #, c-format msgid "Cannot open existing pack idx file for '%s'" msgstr "Kan inte öppna befintligt paket-idx-fil för \"%s\"" -#: builtin/index-pack.c:1444 +#: builtin/index-pack.c:1447 #, c-format msgid "non delta: %d object" msgid_plural "non delta: %d objects" msgstr[0] "icke-delta: %d objekt" msgstr[1] "icke-delta: %d objekt" -#: builtin/index-pack.c:1451 +#: builtin/index-pack.c:1454 #, c-format msgid "chain length = %d: %lu object" msgid_plural "chain length = %d: %lu objects" msgstr[0] "kedjelängd = %d: %lu objekt" msgstr[1] "kedjelängd = %d: %lu objekt" -#: builtin/index-pack.c:1478 +#: builtin/index-pack.c:1481 msgid "Cannot come back to cwd" msgstr "Kan inte gå tillbaka till arbetskatalogen (cwd)" -#: builtin/index-pack.c:1522 builtin/index-pack.c:1525 -#: builtin/index-pack.c:1537 builtin/index-pack.c:1541 +#: builtin/index-pack.c:1525 builtin/index-pack.c:1528 +#: builtin/index-pack.c:1540 builtin/index-pack.c:1544 #, c-format msgid "bad %s" msgstr "felaktig %s" -#: builtin/index-pack.c:1555 +#: builtin/index-pack.c:1558 msgid "--fix-thin cannot be used without --stdin" msgstr "--fix-thin kan inte användas med --stdin" -#: builtin/index-pack.c:1559 builtin/index-pack.c:1569 +#: builtin/index-pack.c:1562 builtin/index-pack.c:1572 #, c-format msgid "packfile name '%s' does not end with '.pack'" msgstr "paketfilnamnet \"%s\" slutar inte med \".pack\"" -#: builtin/index-pack.c:1578 +#: builtin/index-pack.c:1581 msgid "--verify with no packfile name given" msgstr "--verify angavs utan paketfilnamn" @@ -3307,22 +3567,22 @@ msgstr "kopierade inte mallar från felaktig formatversion %d från \"%s\"" msgid "insane git directory %s" msgstr "tokig git-katalog %s" -#: builtin/init-db.c:322 builtin/init-db.c:325 +#: builtin/init-db.c:323 builtin/init-db.c:326 #, c-format msgid "%s already exists" msgstr "%s finns redan" -#: builtin/init-db.c:354 +#: builtin/init-db.c:355 #, c-format msgid "unable to handle file type %d" msgstr "kan inte hantera filtyp %d" -#: builtin/init-db.c:357 +#: builtin/init-db.c:358 #, c-format msgid "unable to move %s to %s" msgstr "kan inte flytta %s till %s" -#: builtin/init-db.c:362 +#: builtin/init-db.c:363 #, c-format msgid "Could not create git link %s" msgstr "Kunde inte skapa gitlänk %s" @@ -3332,38 +3592,38 @@ msgstr "Kunde inte skapa gitlänk %s" #. * existing" or "Initialized empty", the second " shared" or #. * "", and the last '%s%s' is the verbatim directory name. #. -#: builtin/init-db.c:419 +#: builtin/init-db.c:420 #, c-format msgid "%s%s Git repository in %s%s\n" msgstr "%s%s Git-arkiv i %s%s\n" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Reinitialized existing" msgstr "Ominitierade befintligt" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Initialized empty" msgstr "Initierade tomt" -#: builtin/init-db.c:421 +#: builtin/init-db.c:422 msgid " shared" msgstr " delat" -#: builtin/init-db.c:440 +#: builtin/init-db.c:441 msgid "cannot tell cwd" msgstr "kan inte läsa aktuell katalog (cwd)" -#: builtin/init-db.c:521 builtin/init-db.c:528 +#: builtin/init-db.c:522 builtin/init-db.c:529 #, c-format msgid "cannot mkdir %s" msgstr "kan inte skapa katalogen (mkdir) %s" -#: builtin/init-db.c:532 +#: builtin/init-db.c:533 #, c-format msgid "cannot chdir to %s" msgstr "kan inte byta katalog (chdir) till %s" -#: builtin/init-db.c:554 +#: builtin/init-db.c:555 #, c-format msgid "" "%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-" @@ -3372,11 +3632,11 @@ msgstr "" "%s (eller --work-tree=<katalog>) inte tillåtet utan att ange %s (eller --git-" "dir=<katalog>)" -#: builtin/init-db.c:578 +#: builtin/init-db.c:579 msgid "Cannot access current working directory" msgstr "Kan inte komma åt aktuell arbetskatalog" -#: builtin/init-db.c:585 +#: builtin/init-db.c:586 #, c-format msgid "Cannot access work tree '%s'" msgstr "Kan inte komma åt arbetskatalogen \"%s\"" @@ -3386,95 +3646,95 @@ msgstr "Kan inte komma åt arbetskatalogen \"%s\"" msgid "Final output: %d %s\n" msgstr "Slututdata: %d %s\n" -#: builtin/log.c:402 builtin/log.c:490 +#: builtin/log.c:403 builtin/log.c:494 #, c-format msgid "Could not read object %s" msgstr "Kunde inte läsa objektet %s" -#: builtin/log.c:514 +#: builtin/log.c:518 #, c-format msgid "Unknown type: %d" msgstr "Okänd typ: %d" -#: builtin/log.c:603 +#: builtin/log.c:608 msgid "format.headers without value" msgstr "format.headers utan värde" -#: builtin/log.c:677 +#: builtin/log.c:682 msgid "name of output directory is too long" msgstr "namnet på utdatakatalogen är för långt" -#: builtin/log.c:688 +#: builtin/log.c:693 #, c-format msgid "Cannot open patch file %s" msgstr "Kan inte öppna patchfilen %s" -#: builtin/log.c:702 +#: builtin/log.c:707 msgid "Need exactly one range." msgstr "Behöver precis ett intervall." -#: builtin/log.c:710 +#: builtin/log.c:715 msgid "Not a range." msgstr "Inte ett intervall." -#: builtin/log.c:787 +#: builtin/log.c:792 msgid "Cover letter needs email format" msgstr "Omslagsbrevet behöver e-postformat" -#: builtin/log.c:860 +#: builtin/log.c:865 #, c-format msgid "insane in-reply-to: %s" msgstr "tokigt in-reply-to: %s" -#: builtin/log.c:933 +#: builtin/log.c:938 msgid "Two output directories?" msgstr "Två utdatakataloger?" -#: builtin/log.c:1154 +#: builtin/log.c:1160 #, c-format msgid "bogus committer info %s" msgstr "felaktig incheckarinformation %s" -#: builtin/log.c:1199 +#: builtin/log.c:1205 msgid "-n and -k are mutually exclusive." msgstr "-n och -k kan inte användas samtidigt." -#: builtin/log.c:1201 +#: builtin/log.c:1207 msgid "--subject-prefix and -k are mutually exclusive." msgstr "--subject-prefix och -k kan inte användas samtidigt." -#: builtin/log.c:1209 +#: builtin/log.c:1215 msgid "--name-only does not make sense" msgstr "kan inte använda --name-only" -#: builtin/log.c:1211 +#: builtin/log.c:1217 msgid "--name-status does not make sense" msgstr "kan inte använda --name-status" -#: builtin/log.c:1213 +#: builtin/log.c:1219 msgid "--check does not make sense" msgstr "kan inte använda --check" -#: builtin/log.c:1236 +#: builtin/log.c:1242 msgid "standard output, or directory, which one?" msgstr "standard ut, eller katalog, vilken skall det vara?" -#: builtin/log.c:1238 +#: builtin/log.c:1244 #, c-format msgid "Could not create directory '%s'" msgstr "Kunde inte skapa katalogen \"%s\"" -#: builtin/log.c:1391 +#: builtin/log.c:1397 msgid "Failed to create output files" msgstr "Misslyckades skapa utdatafiler" -#: builtin/log.c:1495 +#: builtin/log.c:1501 #, c-format msgid "" "Could not find a tracked remote branch, please specify <upstream> manually.\n" msgstr "Kunde inte hitta en spårad fjärrgren, ange <uppström> manuellt.\n" -#: builtin/log.c:1511 builtin/log.c:1513 builtin/log.c:1525 +#: builtin/log.c:1517 builtin/log.c:1519 builtin/log.c:1531 #, c-format msgid "Unknown commit %s" msgstr "Okänd incheckning %s" @@ -3555,10 +3815,6 @@ msgstr "git write-tree misslyckades skriva ett träd" msgid "failed to read the cache" msgstr "misslyckads läsa cachen" -#: builtin/merge.c:697 -msgid "Unable to write index." -msgstr "Kunde inte skriva indexet." - #: builtin/merge.c:710 msgid "Not handling anything other than two heads merge." msgstr "Hanterar inte något annat än en sammanslagning av två huvuden." @@ -4590,31 +4846,31 @@ msgstr "Oköade ändringar efter återställning:" msgid "Cannot do a %s reset in the middle of a merge." msgstr "Kan inte utföra en %s återställning mitt i en sammanslagning." -#: builtin/reset.c:297 +#: builtin/reset.c:303 #, c-format msgid "Could not parse object '%s'." msgstr "Kan inte tolka objektet \"%s\"" -#: builtin/reset.c:302 +#: builtin/reset.c:308 msgid "--patch is incompatible with --{hard,mixed,soft}" msgstr "--patch är inkompatibel med --{hard,mixed,soft}" -#: builtin/reset.c:311 +#: builtin/reset.c:317 msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead." msgstr "" "--mixed rekommenderas inte med sökvägar; använd \"git reset -- <sökvägar>\"." -#: builtin/reset.c:313 +#: builtin/reset.c:319 #, c-format msgid "Cannot do %s reset with paths." msgstr "Kan inte göra %s återställning med sökvägar." -#: builtin/reset.c:325 +#: builtin/reset.c:331 #, c-format msgid "%s reset is not allowed in a bare repository" msgstr "%s återställning tillåts inte i ett naket arkiv" -#: builtin/reset.c:341 +#: builtin/reset.c:347 #, c-format msgid "Could not reset index file to revision '%s'." msgstr "Kunde inte återställa indexfilen till versionen \"%s\"." @@ -4936,7 +5192,7 @@ msgstr "Visa status för arbetskatalogen" #: common-cmds.h:28 msgid "Create, list, delete or verify a tag object signed with GPG" -msgstr "Skapa, visa, ta bort eller verifiera ett taggobjekt signerat med GPG" +msgstr "Skapa, visa, ta bort eller verifiera GPG-signerat taggobjekt" #: git-am.sh:50 msgid "You need to set your committer info first" @@ -4953,9 +5209,9 @@ msgstr "" #: git-am.sh:105 #, sh-format msgid "" -"When you have resolved this problem run \"$cmdline --resolved\".\n" -"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n" -"To restore the original branch and stop patching run \"$cmdline --abort\"." +"When you have resolved this problem, run \"$cmdline --resolved\".\n" +"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n" +"To restore the original branch and stop patching, run \"$cmdline --abort\"." msgstr "" "När du har löst problemet kör du \"$cmdline --resolved\".\n" "Om du vill hoppa över patchen kör du istället \"$cmdline --skip\".\n" @@ -4971,6 +5227,10 @@ msgstr "" "Arkivet saknar objekt som behövs för att falla tillbaka på 3-" "vägssammanslagning." +#: git-am.sh:139 +msgid "Using index info to reconstruct a base tree..." +msgstr "Använder indexinfo för att åteskapa ett basträd..." + #: git-am.sh:154 msgid "" "Did you hand edit your patch?\n" @@ -4984,42 +5244,50 @@ msgid "Falling back to patching base and 3-way merge..." msgstr "" "Faller tillbaka på att pacha grundversionen och trevägssammanslagning..." -#: git-am.sh:275 +#: git-am.sh:179 +msgid "Failed to merge in the changes." +msgstr "Misslyckads slå ihop ändringarna." + +#: git-am.sh:274 msgid "Only one StGIT patch series can be applied at once" msgstr "Endast en StGIT-patchserie kan tillämpas åt gången" -#: git-am.sh:362 +#: git-am.sh:361 #, sh-format msgid "Patch format $patch_format is not supported." msgstr "Patchformatet $patch_format stöds inte." -#: git-am.sh:364 +#: git-am.sh:363 msgid "Patch format detection failed." msgstr "Misslyckades detektera patchformat." -#: git-am.sh:418 -msgid "-d option is no longer supported. Do not use." -msgstr "Flaggan -d stöds inte lägre. Använd inte." +#: git-am.sh:389 +msgid "" +"The -b/--binary option has been a no-op for long time, and\n" +"it will be removed. Please do not use it anymore." +msgstr "" +"Flaggan -b/--binary har varit utan funktion länge, och\n" +"kommer tas bort. Vi ber dig att inte använda den längre." -#: git-am.sh:481 +#: git-am.sh:477 #, sh-format msgid "previous rebase directory $dotest still exists but mbox given." msgstr "tidigare rebase-katalog $dotest finns fortfarande, men mbox angavs." -#: git-am.sh:486 +#: git-am.sh:482 msgid "Please make up your mind. --skip or --abort?" msgstr "Bestäm dig. --skip eller --abort?" -#: git-am.sh:513 +#: git-am.sh:509 msgid "Resolve operation not in progress, we are not resuming." msgstr "Lösningsoperation pågår inte, vi återupptar inte." -#: git-am.sh:579 +#: git-am.sh:575 #, sh-format msgid "Dirty index: cannot apply patches (dirty: $files)" msgstr "Smutsigt index: kan inte tillämpa patchar (smutsiga: $files)" -#: git-am.sh:671 +#: git-am.sh:679 #, sh-format msgid "" "Patch is empty. Was it split wrong?\n" @@ -5030,32 +5298,32 @@ msgstr "" "Om du vill hoppa över patchen kör du istället \"$cmdline --skip\".\n" "För att återställa originalgrenen och avbryta kör du \"$cmdline --abort\"." -#: git-am.sh:708 +#: git-am.sh:706 msgid "Patch does not have a valid e-mail address." msgstr "Patchen har inte någon giltig e-postadress." -#: git-am.sh:755 +#: git-am.sh:753 msgid "cannot be interactive without stdin connected to a terminal." msgstr "" "kan inte vara interaktiv om standard in inte är ansluten till en terminal." -#: git-am.sh:759 +#: git-am.sh:757 msgid "Commit Body is:" msgstr "Incheckningskroppen är:" #. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a] #. in your translation. The program will only accept English #. input at this point. -#: git-am.sh:766 +#: git-am.sh:764 msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " msgstr "Tillämpa? Y=ja/N=nej/E=redigera/V=visa patch/A=godta alla " -#: git-am.sh:802 +#: git-am.sh:800 #, sh-format msgid "Applying: $FIRSTLINE" msgstr "Tillämpar: $FIRSTLINE" -#: git-am.sh:823 +#: git-am.sh:821 msgid "" "No changes - did you forget to use 'git add'?\n" "If there is nothing left to stage, chances are that something else\n" @@ -5065,7 +5333,7 @@ msgstr "" "Om det inte är något kvar att köa kan det hända att något annat redan\n" "introducerat samma ändringar; kanske du bör hoppa över patchen." -#: git-am.sh:831 +#: git-am.sh:829 msgid "" "You still have unmerged paths in your index\n" "did you forget to use 'git add'?" @@ -5073,16 +5341,16 @@ msgstr "" "Du har fortfarande sökvägar som inte slagits samman i ditt index\n" "glömde du använda \"git add\"?" -#: git-am.sh:847 +#: git-am.sh:845 msgid "No changes -- Patch already applied." msgstr "Inga ändringar -- Patchen har redan tillämpats." -#: git-am.sh:857 +#: git-am.sh:855 #, sh-format msgid "Patch failed at $msgnum $FIRSTLINE" msgstr "Patchen misslyckades vid $msgnum $FIRSTLINE" -#: git-am.sh:873 +#: git-am.sh:876 msgid "applying to an empty history" msgstr "tillämpar på en tom historik" @@ -5285,6 +5553,126 @@ msgstr "Kan inte slå ihop flera grenar i ett tomt huvud." msgid "Cannot rebase onto multiple branches" msgstr "Kan inte utföra en \"rebase\" ovanpå flera grenar" +#: git-rebase.sh:52 +msgid "" +"When you have resolved this problem, run \"git rebase --continue\".\n" +"If you prefer to skip this patch, run \"git rebase --skip\" instead.\n" +"To check out the original branch and stop rebasing, run \"git rebase --abort" +"\"." +msgstr "" +"När du har löst problemet kör du \"git rebase --continue\".\n" +"Om du vill hoppa över patchen kör du istället \"git rebase --skip\".\n" +"För att återställa originalgrenen och avbryta kör du \"git rebase --abort\"." + +#: git-rebase.sh:159 +msgid "The pre-rebase hook refused to rebase." +msgstr "Kroken pre-rebase vägrade ombaseringen." + +#: git-rebase.sh:164 +msgid "It looks like git-am is in progress. Cannot rebase." +msgstr "Det verkar som en git-am körs. Kan inte ombasera." + +#: git-rebase.sh:295 +msgid "The --exec option must be used with the --interactive option" +msgstr "Flaggan --exec måste användas tillsammans med flaggan --interactive" + +#: git-rebase.sh:300 +msgid "No rebase in progress?" +msgstr "Ingen ombasering pågår?" + +#: git-rebase.sh:313 +msgid "Cannot read HEAD" +msgstr "Kan inte läsa HEAD" + +#: git-rebase.sh:316 +msgid "" +"You must edit all merge conflicts and then\n" +"mark them as resolved using git add" +msgstr "" +"Du måste redigera alla sammanslagningskonflikter och\n" +"därefter markera dem som lösta med git add" + +#: git-rebase.sh:334 +#, sh-format +msgid "Could not move back to $head_name" +msgstr "Kunde inte flytta tillbaka till $head_name" + +#: git-rebase.sh:350 +#, sh-format +msgid "" +"It seems that there is already a $state_dir_base directory, and\n" +"I wonder if you are in the middle of another rebase. If that is the\n" +"case, please try\n" +"\t$cmd_live_rebase\n" +"If that is not the case, please\n" +"\t$cmd_clear_stale_rebase\n" +"and run me again. I am stopping in case you still have something\n" +"valuable there." +msgstr "" +"Det verkar som katalogen $state_dir_base redan existerar, och\n" +"jag undrar om du redan är mitt i en annan ombasering. Om så är\n" +"fallet, försök\n" +"\t$cmd_live_rebase\n" +"Om så inte är fallet, kör\n" +"\t$cmd_clear_stale_rebase\n" +"och kör programmet igen. Jag avslutar ifall du fortfarande har\n" +"något av värde där." + +#: git-rebase.sh:395 +#, sh-format +msgid "invalid upstream $upstream_name" +msgstr "ogiltig uppström $upstream_name" + +#: git-rebase.sh:419 +#, sh-format +msgid "$onto_name: there are more than one merge bases" +msgstr "$onto_name: mer än en sammanslagningsbas finns" + +#: git-rebase.sh:422 git-rebase.sh:426 +#, sh-format +msgid "$onto_name: there is no merge base" +msgstr "$onto_name: ingen sammanslagningsbas finns" + +#: git-rebase.sh:431 +#, sh-format +msgid "Does not point to a valid commit: $onto_name" +msgstr "Peka på en giltig incheckning: $onto_name" + +#: git-rebase.sh:454 +#, sh-format +msgid "fatal: no such branch: $branch_name" +msgstr "ödesdigert: ingen sådan gren: $branch_name" + +#: git-rebase.sh:474 +msgid "Please commit or stash them." +msgstr "Checka in eller använd \"stash\" på dem." + +#: git-rebase.sh:492 +#, sh-format +msgid "Current branch $branch_name is up to date." +msgstr "Aktuell gren $branch_name är à jour." + +#: git-rebase.sh:495 +#, sh-format +msgid "Current branch $branch_name is up to date, rebase forced." +msgstr "Aktuell gren $branch_name är à jour, ombasering framtvingad." + +#: git-rebase.sh:506 +#, sh-format +msgid "Changes from $mb to $onto:" +msgstr "Ändringar från $mb till $onto:" + +#. Detach HEAD and reset the tree +#: git-rebase.sh:515 +msgid "First, rewinding head to replay your work on top of it..." +msgstr "" +"Först, spolar tillbaka huvudet för att spela av ditt arbete ovanpå det..." + +#: git-rebase.sh:523 +#, sh-format +msgid "Fast-forwarded $branch_name to $onto_name." +msgstr "Snabbspolade $branch_name till $onto_name." + #: git-stash.sh:51 msgid "git stash clear with parameters is unimplemented" msgstr "\"git stash clear\" med parametrar har inte implementerats" @@ -5425,27 +5813,27 @@ msgid "No submodule mapping found in .gitmodules for path '$sm_path'" msgstr "" "Hittade ingen undermodulmappning i .gitmodules för sökvägen \"$sm_path\"" -#: git-submodule.sh:186 +#: git-submodule.sh:189 #, sh-format msgid "Clone of '$url' into submodule path '$sm_path' failed" msgstr "Misslyckades klona \"$url\" till undermodulsökvägen \"$sm_path\"" -#: git-submodule.sh:196 +#: git-submodule.sh:201 #, sh-format msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa" msgstr "Gitkatalog \"$a\" ingår i underkatalogsökvägen \"$b\" eller omvänt" -#: git-submodule.sh:285 +#: git-submodule.sh:290 #, sh-format msgid "repo URL: '$repo' must be absolute or begin with ./|../" msgstr "arkiv-URL: \"$repo\" måste vara absolut eller börja med ./|../" -#: git-submodule.sh:302 +#: git-submodule.sh:307 #, sh-format msgid "'$sm_path' already exists in the index" msgstr "\"$sm_path\" finns redan i indexet" -#: git-submodule.sh:306 +#: git-submodule.sh:311 #, sh-format msgid "" "The following path is ignored by one of your .gitignore files:\n" @@ -5456,64 +5844,64 @@ msgstr "" "$sm_path\n" "Använd -f om du verkligen vill lägga till den" -#: git-submodule.sh:317 +#: git-submodule.sh:322 #, sh-format msgid "Adding existing repo at '$sm_path' to the index" msgstr "Lägger till befintligt arkiv i \"$sm_path\" i indexet" -#: git-submodule.sh:319 +#: git-submodule.sh:324 #, sh-format msgid "'$sm_path' already exists and is not a valid git repo" msgstr "\"$sm_path\" finns redan och är inte ett giltigt git-arkiv" -#: git-submodule.sh:333 +#: git-submodule.sh:338 #, sh-format msgid "Unable to checkout submodule '$sm_path'" msgstr "Kan inte checka ut undermodulen \"$sm_path\"" -#: git-submodule.sh:338 +#: git-submodule.sh:343 #, sh-format msgid "Failed to add submodule '$sm_path'" msgstr "Misslyckades lägga till undermodulen \"$sm_path\"" -#: git-submodule.sh:343 +#: git-submodule.sh:348 #, sh-format msgid "Failed to register submodule '$sm_path'" msgstr "Misslyckades registrera undermodulen \"$sm_path\"" -#: git-submodule.sh:385 +#: git-submodule.sh:390 #, sh-format msgid "Entering '$prefix$sm_path'" msgstr "Går in i \"$prefix$sm_path\"" -#: git-submodule.sh:399 +#: git-submodule.sh:404 #, sh-format msgid "Stopping at '$sm_path'; script returned non-zero status." msgstr "" "Stoppar på \"$sm_path\"; skriptet returnerade en status skild från noll." -#: git-submodule.sh:442 +#: git-submodule.sh:447 #, sh-format msgid "No url found for submodule path '$sm_path' in .gitmodules" msgstr "Hittade ingen url för undermodulsökvägen \"$sm_path\" i .gitmodules" -#: git-submodule.sh:451 +#: git-submodule.sh:456 #, sh-format msgid "Failed to register url for submodule path '$sm_path'" msgstr "Misslyckades registrera url för underkatalogsökväg \"$sm_path\"" -#: git-submodule.sh:453 +#: git-submodule.sh:458 #, sh-format msgid "Submodule '$name' ($url) registered for path '$sm_path'" msgstr "Undermodulen \"$name\" ($url) registrerad för sökvägen \"$sm_path\"" -#: git-submodule.sh:461 +#: git-submodule.sh:466 #, sh-format msgid "Failed to register update mode for submodule path '$sm_path'" msgstr "" "Misslyckades registrera uppdateringsläge för undermodulsökväg \"$sm_path\"" -#: git-submodule.sh:560 +#: git-submodule.sh:565 #, sh-format msgid "" "Submodule path '$sm_path' not initialized\n" @@ -5522,97 +5910,102 @@ msgstr "" "Undermodulen \"$sm_path\" har inte initierats\n" "Kanske du vill köra \"update --init\"?" -#: git-submodule.sh:573 +#: git-submodule.sh:578 #, sh-format msgid "Unable to find current revision in submodule path '$sm_path'" msgstr "Kan inte hitta aktuell revision i undermodulsökväg \"$sm_path\"" -#: git-submodule.sh:592 +#: git-submodule.sh:597 #, sh-format msgid "Unable to fetch in submodule path '$sm_path'" msgstr "Kan inte hämta i undermodulsökväg \"$sm_path\"" -#: git-submodule.sh:606 +#: git-submodule.sh:611 #, sh-format msgid "Unable to rebase '$sha1' in submodule path '$sm_path'" msgstr "Kan inte ombasera \"$sha1\" i undermodulsökväg \"$sm_path\"" -#: git-submodule.sh:607 +#: git-submodule.sh:612 #, sh-format msgid "Submodule path '$sm_path': rebased into '$sha1'" msgstr "Undermodulsökvägen \"$sm_path\": ombaserade in i \"$sha1\"" -#: git-submodule.sh:612 +#: git-submodule.sh:617 #, sh-format msgid "Unable to merge '$sha1' in submodule path '$sm_path'" msgstr "Kan inte slå ihop \"$sha1\" i undermodulsökvägen \"$sm_path\"" -#: git-submodule.sh:613 +#: git-submodule.sh:618 #, sh-format msgid "Submodule path '$sm_path': merged in '$sha1'" msgstr "Undermodulsökvägen \"$sm_path\": sammanslagen i \"$sha1\"" -#: git-submodule.sh:618 +#: git-submodule.sh:623 #, sh-format msgid "Unable to checkout '$sha1' in submodule path '$sm_path'" msgstr "Kan inte checka ut \"$sha1\" i undermodulsökvägen \"$sm_path\"" -#: git-submodule.sh:619 +#: git-submodule.sh:624 #, sh-format msgid "Submodule path '$sm_path': checked out '$sha1'" msgstr "Undermodulsökvägen \"$sm_path\": checkade ut \"$sha1\"" -#: git-submodule.sh:641 git-submodule.sh:964 +#: git-submodule.sh:646 git-submodule.sh:969 #, sh-format msgid "Failed to recurse into submodule path '$sm_path'" msgstr "Misslyckades rekursera in i undermodulsökvägen \"$sm_path\"" -#: git-submodule.sh:749 -msgid "--cached cannot be used with --files" -msgstr "--cached kan inte användas med --files" +#: git-submodule.sh:754 +msgid "The --cached option cannot be used with the --files option" +msgstr "Flaggan --cached kan inte användas med flaggan --files" #. unexpected type -#: git-submodule.sh:789 +#: git-submodule.sh:794 #, sh-format msgid "unexpected mode $mod_dst" msgstr "oväntat läge $mod_dst" -#: git-submodule.sh:807 +#: git-submodule.sh:812 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_src" msgstr " Varning: $name innehåller inte incheckning $sha1_src" -#: git-submodule.sh:810 +#: git-submodule.sh:815 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_dst" msgstr " Varning: $name innehåller inte incheckning $sha1_dst" -#: git-submodule.sh:813 +#: git-submodule.sh:818 #, sh-format msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst" msgstr " Varning: $name innehåller inte incheckningar $sha1_src och $sha1_dst" -#: git-submodule.sh:838 +#: git-submodule.sh:843 msgid "blob" msgstr "blob" -#: git-submodule.sh:839 -msgid "submodule" -msgstr "undermodul" - -#: git-submodule.sh:876 +#: git-submodule.sh:881 msgid "# Submodules changed but not updated:" msgstr "# Undermoduler ändrade men inte uppdaterade:" -#: git-submodule.sh:878 +#: git-submodule.sh:883 msgid "# Submodule changes to be committed:" msgstr "# Undermodulers ändringar att checka in:" -#: git-submodule.sh:1022 +#: git-submodule.sh:1027 #, sh-format msgid "Synchronizing submodule url for '$name'" msgstr "Synkroniserar undermodul-url för \"$name\"" +#~ msgid "%s: has been deleted/renamed" +#~ msgstr "%s: har tagits bort/ändrat namn" + +#~ msgid "'%s': not a documentation directory." +#~ msgstr "\"%s\": inte en dokumentationskatalog." + +#~ msgid "-d option is no longer supported. Do not use." +#~ msgstr "Flaggan -d stöds inte lägre. Använd inte." + #~ msgid "cherry-pick" #~ msgstr "cherry-pick" @@ -5,10 +5,10 @@ # msgid "" msgstr "" -"Project-Id-Version: git-1.7.11.1-107-g72601\n" +"Project-Id-Version: git-1.7.12-rc1-18-ge0453\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2012-07-03 10:23+0800\n" -"PO-Revision-Date: 2012-07-03 14:21+0700\n" +"POT-Creation-Date: 2012-08-06 23:47+0800\n" +"PO-Revision-Date: 2012-08-07 07:11+0700\n" "Last-Translator: Trần Ngọc Quân <vnwildman@gmail.com>\n" "Language-Team: Vietnamese <translation-team-vi@lists.sourceforge.net>\n" "MIME-Version: 1.0\n" @@ -53,7 +53,7 @@ msgid "unrecognized header: %s%s (%d)" msgstr "phần đầu (header) không được thừa nhận: %s%s (%d)" #: bundle.c:89 -#: builtin/commit.c:696 +#: builtin/commit.c:699 #, c-format msgid "could not open '%s'" msgstr "không thể mở '%s'" @@ -66,9 +66,9 @@ msgstr "Khó chứa thiếu những lần chuyển giao (commit) cần trước #: sequencer.c:550 #: sequencer.c:982 #: builtin/log.c:290 -#: builtin/log.c:721 -#: builtin/log.c:1310 -#: builtin/log.c:1529 +#: builtin/log.c:726 +#: builtin/log.c:1316 +#: builtin/log.c:1535 #: builtin/merge.c:347 #: builtin/shortlog.c:181 msgid "revision walk setup failed" @@ -97,7 +97,7 @@ msgid "rev-list died" msgstr "rev-list bị chết" #: bundle.c:300 -#: builtin/log.c:1206 +#: builtin/log.c:1212 #: builtin/shortlog.c:284 #, c-format msgid "unrecognized argument: %s" @@ -246,8 +246,8 @@ msgstr "" "%s" #: diff.c:1400 -msgid " 0 files changed\n" -msgstr " 0 tập tin nào bị thay đổi\n" +msgid " 0 files changed" +msgstr " 0 có tập tin nào bị sửa đổi" #: diff.c:1404 #, c-format @@ -270,7 +270,7 @@ msgid_plural ", %d deletions(-)" msgstr[0] ", %d bị xóa(-)" msgstr[1] ", %d bị xóa(-)" -#: diff.c:3478 +#: diff.c:3461 #, c-format msgid "" "Failed to parse --dirstat/-X option parameter:\n" @@ -306,16 +306,16 @@ msgstr "'%s': %s" msgid "'%s': short read %s" msgstr "'%s': đọc ngắn %s" -#: help.c:208 +#: help.c:212 #, c-format msgid "available git commands in '%s'" msgstr "các lệnh git sẵn sàng để dùng trong '%s'" -#: help.c:215 +#: help.c:219 msgid "git commands available from elsewhere on your $PATH" msgstr "các lệnh git sẵn sàng để dùng từ một nơi khác trong $PATH của bạn" -#: help.c:271 +#: help.c:275 #, c-format msgid "" "'%s' appears to be a git command, but we were not\n" @@ -324,11 +324,11 @@ msgstr "" "'%s' trông như là một lệnh git, nhưng chúng tôi không\n" "thể thực thi nó. Có lẽ là lệnh git-%s đã bị hỏng?" -#: help.c:328 +#: help.c:332 msgid "Uh oh. Your system reports no Git commands at all." msgstr "Ối chà. Hệ thống của bạn báo rằng chẳng có lệnh Git nào cả." -#: help.c:350 +#: help.c:354 #, c-format msgid "" "WARNING: You called a Git command named '%s', which does not exist.\n" @@ -337,17 +337,17 @@ msgstr "" "CẢNH BÁO: Bạn đã gọi lệnh Git có tên '%s', mà nó lại không sẵn có.\n" "Giả định rằng ý bạn là '%s'" -#: help.c:355 +#: help.c:359 #, c-format msgid "in %0.1f seconds automatically..." msgstr "trong %0.1f giây một cách tự động..." -#: help.c:362 +#: help.c:366 #, c-format msgid "git: '%s' is not a git command. See 'git --help'." msgstr "git: '%s' không phải là một lệnh của git. Xem thêm 'git --help'." -#: help.c:366 +#: help.c:370 msgid "" "\n" "Did you mean this?" @@ -361,42 +361,297 @@ msgstr[1] "" "\n" "Có phải ý bạn là một trong số những cái này không?" -#: parse-options.c:493 +#: merge-recursive.c:190 +#, c-format +msgid "(bad commit)\n" +msgstr "(commit sai)\n" + +#: merge-recursive.c:206 +#, c-format +msgid "addinfo_cache failed for path '%s'" +msgstr "addinfo_cache gặp lỗi đối với đường dẫn '%s'" + +#: merge-recursive.c:268 +msgid "error building trees" +msgstr "gặp lỗi khi xây dựng cây" + +#: merge-recursive.c:497 +msgid "diff setup failed" +msgstr "cài đặt diff gặp lỗi" + +#: merge-recursive.c:627 +msgid "merge-recursive: disk full?" +msgstr "merge-recursive: đĩa bị đầy?" + +#: merge-recursive.c:690 +#, c-format +msgid "failed to create path '%s'%s" +msgstr "gặp lỗi khi tạo đường dẫn '%s'%s" + +#: merge-recursive.c:701 +#, c-format +msgid "Removing %s to make room for subdirectory\n" +msgstr "Gỡ bỏ %s để tạo chỗ (room) cho thư mục con\n" + +#. something else exists +#. .. but not some other error (who really cares what?) +#: merge-recursive.c:715 +#: merge-recursive.c:736 +msgid ": perhaps a D/F conflict?" +msgstr ": có lẽ là một xung đột D/F?" + +#: merge-recursive.c:726 +#, c-format +msgid "refusing to lose untracked file at '%s'" +msgstr "từ chối đóng tập tin không được theo vết tại '%s'" + +#: merge-recursive.c:766 +#, c-format +msgid "cannot read object %s '%s'" +msgstr "không thể đọc đối tượng %s '%s'" + +#: merge-recursive.c:768 +#, c-format +msgid "blob expected for %s '%s'" +msgstr "đối tượng blob được mong đợi cho %s '%s'" + +#: merge-recursive.c:791 +#: builtin/clone.c:302 +#, c-format +msgid "failed to open '%s'" +msgstr "gặp lỗi khi mở '%s'" + +#: merge-recursive.c:799 +#, c-format +msgid "failed to symlink '%s'" +msgstr "gặp lỗi khi tạo liên kết tượng trưng symlink '%s'" + +#: merge-recursive.c:802 +#, c-format +msgid "do not know what to do with %06o %s '%s'" +msgstr "không hiểu phải làm gì với %06o %s '%s'" + +#: merge-recursive.c:939 +msgid "Failed to execute internal merge" +msgstr "Gặp lỗi khi thực hiện trộn nội bộ" + +#: merge-recursive.c:943 +#, c-format +msgid "Unable to add %s to database" +msgstr "Không thể thêm %s vào cơ sở dữ liệu" + +#: merge-recursive.c:959 +msgid "unsupported object type in the tree" +msgstr "kiểu đối tượng không được hỗ trợ trong cây (tree)" + +#: merge-recursive.c:1038 +#: merge-recursive.c:1052 +#, c-format +msgid "CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left in tree." +msgstr "XUNG ĐỘT (%s/xóa): %s bị xóa trong %s và %s trong %s. Phiên bản %s của %s còn lại trong cây (tree)." + +#: merge-recursive.c:1044 +#: merge-recursive.c:1057 +#, c-format +msgid "CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left in tree at %s." +msgstr "XUNG ĐỘT (%s/xóa): %s bị xóa trong %s và %s trong %s. Phiên bản %s của %s còn lại trong cây (tree) tại %s." + +#: merge-recursive.c:1098 +msgid "rename" +msgstr "đổi tên" + +#: merge-recursive.c:1098 +msgid "renamed" +msgstr "đã đổi tên" + +#: merge-recursive.c:1154 +#, c-format +msgid "%s is a directory in %s adding as %s instead" +msgstr "%s là một thư mục trong %s thay vào đó thêm vào như là %s" + +#: merge-recursive.c:1176 +#, c-format +msgid "CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s\"->\"%s\" in \"%s\"%s" +msgstr "XUNG ĐỘT (đổi tên/đổi tên): Đổi tên \"%s\"->\"%s\" trong nhánh \"%s\" đổi tên \"%s\"->\"%s\" trong \"%s\"%s" + +#: merge-recursive.c:1181 +msgid " (left unresolved)" +msgstr " (cần giải quyết)" + +#: merge-recursive.c:1235 +#, c-format +msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s" +msgstr "XUNG ĐỘT (đổi tên/đổi tên): Đổi tên %s->%s trong %s. Đổi tên %s->%s trong %s" + +#: merge-recursive.c:1265 +#, c-format +msgid "Renaming %s to %s and %s to %s instead" +msgstr "Đang đổi tên %s thành %s thay vì %s thành %s" + +#: merge-recursive.c:1464 +#, c-format +msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s" +msgstr "XUNG ĐỘT (đổi tên/thêm): Đổi tên %s->%s trong %s. %s được thêm vào trong %s" + +#: merge-recursive.c:1474 +#, c-format +msgid "Adding merged %s" +msgstr "Thêm hòa trộn %s" + +#: merge-recursive.c:1479 +#: merge-recursive.c:1677 +#, c-format +msgid "Adding as %s instead" +msgstr "Thay vào đó thêm vào %s" + +#: merge-recursive.c:1530 +#, c-format +msgid "cannot read object %s" +msgstr "không thể đọc đối tượng %s" + +#: merge-recursive.c:1533 +#, c-format +msgid "object %s is not a blob" +msgstr "đối tượng %s không phải là một blob" + +#: merge-recursive.c:1581 +msgid "modify" +msgstr "sửa đổi" + +#: merge-recursive.c:1581 +msgid "modified" +msgstr "đã sửa" + +#: merge-recursive.c:1591 +msgid "content" +msgstr "nội dung" + +#: merge-recursive.c:1598 +msgid "add/add" +msgstr "thêm/thêm" + +#: merge-recursive.c:1632 +#, c-format +msgid "Skipped %s (merged same as existing)" +msgstr "Đã bỏ qua %s (đã sẵn có lần hòa trộn này)" + +#: merge-recursive.c:1646 +#, c-format +msgid "Auto-merging %s" +msgstr "Tự-động-hòa-trộn %s" + +#: merge-recursive.c:1650 +#: git-submodule.sh:844 +msgid "submodule" +msgstr "mô-đun con" + +#: merge-recursive.c:1651 +#, c-format +msgid "CONFLICT (%s): Merge conflict in %s" +msgstr "XUNG ĐỘT (%s): Xung đột hòa trộn trong %s" + +#: merge-recursive.c:1741 +#, c-format +msgid "Removing %s" +msgstr "Đang xóa %s" + +#: merge-recursive.c:1766 +msgid "file/directory" +msgstr "tập-tin/thư-mục" + +#: merge-recursive.c:1772 +msgid "directory/file" +msgstr "thư-mục/tập tin" + +#: merge-recursive.c:1777 +#, c-format +msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s" +msgstr "XUNG ĐỘT (%s): Ở đây không có thư mục nào có tên %s trong %s. Thêm %s như là %s" + +#: merge-recursive.c:1787 +#, c-format +msgid "Adding %s" +msgstr "Đang thêm \"%s\"" + +#: merge-recursive.c:1804 +msgid "Fatal merge failure, shouldn't happen." +msgstr "Việc hòa trộn hỏng nghiêm trọng, không nên để xảy ra." + +#: merge-recursive.c:1823 +msgid "Already up-to-date!" +msgstr "Đã cập nhật rồi!" + +#: merge-recursive.c:1832 +#, c-format +msgid "merging of trees %s and %s failed" +msgstr "hòa trộn cây (tree) %s và %s gặp lỗi" + +#: merge-recursive.c:1862 +#, c-format +msgid "Unprocessed path??? %s" +msgstr "Đường dẫn chưa được xử lý??? %s" + +#: merge-recursive.c:1907 +msgid "Merging:" +msgstr "Đang trộn:" + +#: merge-recursive.c:1920 +#, c-format +msgid "found %u common ancestor:" +msgid_plural "found %u common ancestors:" +msgstr[0] "tìm thấy %u tổ tiên chung:" +msgstr[1] "tìm thấy %u tổ tiên chung:" + +#: merge-recursive.c:1957 +msgid "merge returned no commit" +msgstr "hòa trộn không trả về lần chuyển giao (commit) nào" + +#: merge-recursive.c:2014 +#, c-format +msgid "Could not parse object '%s'" +msgstr "Không thể phân tích đối tượng '%s'" + +#: merge-recursive.c:2026 +#: builtin/merge.c:697 +msgid "Unable to write index." +msgstr "Không thể ghi bảng mục lục" + +#: parse-options.c:494 msgid "..." msgstr "..." -#: parse-options.c:511 +#: parse-options.c:512 #, c-format msgid "usage: %s" msgstr "cách sử dụng: %s" #. TRANSLATORS: the colon here should align with the #. one in "usage: %s" translation -#: parse-options.c:515 +#: parse-options.c:516 #, c-format msgid " or: %s" msgstr " hoặc: %s" -#: parse-options.c:518 +#: parse-options.c:519 #, c-format msgid " %s" msgstr " %s" -#: remote.c:1629 +#: remote.c:1632 #, 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] "Nhánh của bạn là đầu của '%s' bởi %d lần chuyển giao (commit).\n" msgstr[1] "Nhánh của bạn là đầu của '%s' bởi %d lần chuyển giao (commit).\n" -#: remote.c:1635 +#: remote.c:1638 #, c-format msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n" msgid_plural "Your branch is behind '%s' by %d commits, and can be fast-forwarded.\n" msgstr[0] "Nhánh của bạn thì ở đằng sau '%s' bởi %d lần chuyển giao (commit), và có thể được fast-forward.\n" msgstr[1] "Nhánh của bạn thì ở đằng sau '%s' bởi %d lần chuyển giao (commit), và có thể được fast-forward.\n" -#: remote.c:1643 +#: remote.c:1646 #, c-format msgid "" "Your branch and '%s' have diverged,\n" @@ -632,7 +887,7 @@ msgid "cannot abort from a branch yet to be born" msgstr "không thể hủy bỏ từ một nhánh mà nó còn chưa được tạo ra" #: sequencer.c:805 -#: builtin/apply.c:3697 +#: builtin/apply.c:3988 #, c-format msgid "cannot open %s: %s" msgstr "không thể mở %s: %s" @@ -664,21 +919,21 @@ msgstr "Không thể revert một lần chuyển giao (commit) khởi tạo" msgid "Can't cherry-pick into empty head" msgstr "Không thể cherry-pick vào một đầu (head) trống rỗng" -#: sha1_name.c:864 +#: sha1_name.c:1044 msgid "HEAD does not point to a branch" msgstr "HEAD không chỉ đến một nhánh nào cả" -#: sha1_name.c:867 +#: sha1_name.c:1047 #, c-format msgid "No such branch: '%s'" msgstr "Không có nhánh nào như thế: '%s'" -#: sha1_name.c:869 +#: sha1_name.c:1049 #, c-format msgid "No upstream configured for branch '%s'" msgstr "Không có dòng ngược (upstream) được cấu hình cho nhánh '%s'" -#: sha1_name.c:872 +#: sha1_name.c:1052 #, c-format msgid "Upstream branch '%s' not stored as a remote-tracking branch" msgstr "Nhánh dòng ngược (upstream) '%s' không được lưu lại như là một nhánh 'remote-tracking'" @@ -692,339 +947,339 @@ msgstr "không tìm thấy người dùng hiện tại trong tập tin passwd: % msgid "no such user" msgstr "không có người dùng như vậy" -#: wt-status.c:141 +#: wt-status.c:140 msgid "Unmerged paths:" msgstr "Những đường dẫn chưa được hòa trộn:" -#: wt-status.c:168 -#: wt-status.c:195 +#: wt-status.c:167 +#: wt-status.c:194 #, c-format msgid " (use \"git reset %s <file>...\" to unstage)" msgstr " (sử dụng \"git reset %s <tập-tin>...\" để bỏ một stage (trạng thái))" -#: wt-status.c:170 -#: wt-status.c:197 +#: wt-status.c:169 +#: wt-status.c:196 msgid " (use \"git rm --cached <file>...\" to unstage)" msgstr " (sử dụng \"git rm --cached <tập-tin>...\" để bỏ trạng thái (stage))" -#: wt-status.c:174 +#: wt-status.c:173 msgid " (use \"git add <file>...\" to mark resolution)" msgstr " (sử dụng \"git add <tập-tin>...\" để đánh dấu là cần giải quyết)" -#: wt-status.c:176 -#: wt-status.c:180 +#: wt-status.c:175 +#: wt-status.c:179 msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)" msgstr " (sử dụng \"git add/rm <tập-tin>...\" như là một cách thích hợp để đánh dấu là cần được giải quyết)" -#: wt-status.c:178 +#: wt-status.c:177 msgid " (use \"git rm <file>...\" to mark resolution)" msgstr " (sử dụng \"git rm <tập-tin>...\" để đánh dấu là cần giải quyết)" -#: wt-status.c:189 +#: wt-status.c:188 msgid "Changes to be committed:" msgstr "Những thay đổi sẽ được chuyển giao:" -#: wt-status.c:207 +#: wt-status.c:206 msgid "Changes not staged for commit:" msgstr "Các thay đổi không được đặt trạng thái (stage) cho lần chuyển giao (commit):" -#: wt-status.c:211 +#: wt-status.c:210 msgid " (use \"git add <file>...\" to update what will be committed)" msgstr " (sử dụng \"git add <tập-tin>...\" để cập nhật những gì cần chuyển giao (commit))" -#: wt-status.c:213 +#: wt-status.c:212 msgid " (use \"git add/rm <file>...\" to update what will be committed)" msgstr " (sử dụng \"git add/rm <tập_tin>...\" để cập nhật những gì sẽ được chuyển giao)" -#: wt-status.c:214 +#: wt-status.c:213 msgid " (use \"git checkout -- <file>...\" to discard changes in working directory)" msgstr " (sử dụng \"git checkout -- <tập_tin>...\" để loại bỏ những thay đổi trong thư mục làm việc)" -#: wt-status.c:216 +#: wt-status.c:215 msgid " (commit or discard the untracked or modified content in submodules)" msgstr " (chuyển giao (commit) hoặc là loại bỏ các nội dung không-bị-theo-vết hay đã bị chỉnh sửa trong mô-đun-con)" -#: wt-status.c:225 +#: wt-status.c:224 #, c-format msgid "%s files:" msgstr "%s tệp tin:" -#: wt-status.c:228 +#: wt-status.c:227 #, c-format msgid " (use \"git %s <file>...\" to include in what will be committed)" msgstr " (sử dụng \"git %s <tập-tin>...\" để bao gồm thêm vào những gì cần chuyển giao (commit))" -#: wt-status.c:245 +#: wt-status.c:244 msgid "bug" msgstr "lỗi" -#: wt-status.c:250 +#: wt-status.c:249 msgid "both deleted:" msgstr "bị xóa bởi cả hai:" -#: wt-status.c:251 +#: wt-status.c:250 msgid "added by us:" msgstr "được thêm vào bởi chúng tôi:" -#: wt-status.c:252 +#: wt-status.c:251 msgid "deleted by them:" msgstr "bị xóa đi bởi họ:" -#: wt-status.c:253 +#: wt-status.c:252 msgid "added by them:" msgstr "được thêm vào bởi họ:" -#: wt-status.c:254 +#: wt-status.c:253 msgid "deleted by us:" msgstr "bị xóa bởi chúng tôi:" -#: wt-status.c:255 +#: wt-status.c:254 msgid "both added:" msgstr "được thêm vào bởi cả hai:" -#: wt-status.c:256 +#: wt-status.c:255 msgid "both modified:" msgstr "bị sửa bởi cả hai:" -#: wt-status.c:286 +#: wt-status.c:285 msgid "new commits, " msgstr " lần chuyển giao (commit) mới, " -#: wt-status.c:288 +#: wt-status.c:287 msgid "modified content, " msgstr "nội dung được sửa đổi," -#: wt-status.c:290 +#: wt-status.c:289 msgid "untracked content, " msgstr "nội dung chưa được theo dõi" -#: wt-status.c:304 +#: wt-status.c:303 #, c-format msgid "new file: %s" msgstr "tập tin mới: %s" -#: wt-status.c:307 +#: wt-status.c:306 #, c-format msgid "copied: %s -> %s" msgstr "đã sao chép: %s -> %s" -#: wt-status.c:310 +#: wt-status.c:309 #, c-format msgid "deleted: %s" msgstr "bị xóa: %s" -#: wt-status.c:313 +#: wt-status.c:312 #, c-format msgid "modified: %s" msgstr "bị sửa đổi: %s" -#: wt-status.c:316 +#: wt-status.c:315 #, c-format msgid "renamed: %s -> %s" msgstr "đã đổi tên: %s -> %s" -#: wt-status.c:319 +#: wt-status.c:318 #, c-format msgid "typechange: %s" msgstr "đổi-kiểu: %s" -#: wt-status.c:322 +#: wt-status.c:321 #, c-format msgid "unknown: %s" msgstr "không rõ: %s" -#: wt-status.c:325 +#: wt-status.c:324 #, c-format msgid "unmerged: %s" msgstr "chưa hòa trộn: %s" -#: wt-status.c:328 +#: wt-status.c:327 #, c-format msgid "bug: unhandled diff status %c" msgstr "lỗi: không lấy được trạng thái lệnh diff %c" -#: wt-status.c:786 +#: wt-status.c:785 msgid "You have unmerged paths." msgstr "Bạn có những đường dẫn chưa được hòa trộn." -#: wt-status.c:789 -#: wt-status.c:913 +#: wt-status.c:788 +#: wt-status.c:912 msgid " (fix conflicts and run \"git commit\")" msgstr " (sửa các xung đột sau đó chạy \"git commit\")" -#: wt-status.c:792 +#: wt-status.c:791 msgid "All conflicts fixed but you are still merging." msgstr "Tất cả các xung đột đã được giải quyết nhưng bạn vẫn đang hòa trộn." -#: wt-status.c:795 +#: wt-status.c:794 msgid " (use \"git commit\" to conclude merge)" msgstr " (sử dụng \"git commit\" để hoàn tất việc hòa trộn)" -#: wt-status.c:805 +#: wt-status.c:804 msgid "You are in the middle of an am session." msgstr "Bạn đang ở giữa của một phiên 'am'." -#: wt-status.c:808 +#: wt-status.c:807 msgid "The current patch is empty." msgstr "Miếng vá hiện tại bị trống rỗng." -#: wt-status.c:812 +#: wt-status.c:811 msgid " (fix conflicts and then run \"git am --resolved\")" msgstr " (sửa các xung đột và sau đó chạy lệnh \"git am --resolved\")" -#: wt-status.c:814 +#: wt-status.c:813 msgid " (use \"git am --skip\" to skip this patch)" msgstr " (sử dụng \"git am --skip\" để bỏ qua lần vá này)" -#: wt-status.c:816 +#: wt-status.c:815 msgid " (use \"git am --abort\" to restore the original branch)" msgstr " (sử dụng \"git am --abort\" để phục hồi lại nhánh nguyên thủy)" -#: wt-status.c:874 -#: wt-status.c:884 +#: wt-status.c:873 +#: wt-status.c:883 msgid "You are currently rebasing." msgstr "Bạn hiện nay đang thực hiện việc rebase (tái cấu trúc)." -#: wt-status.c:877 +#: wt-status.c:876 msgid " (fix conflicts and then run \"git rebase --continue\")" msgstr " (sửa các xung đột và sau đó chạy lệnh \"git rebase --continue\")" -#: wt-status.c:879 +#: wt-status.c:878 msgid " (use \"git rebase --skip\" to skip this patch)" msgstr " (sử dụng \"git rebase --skip\" để bỏ qua lần vá này)" -#: wt-status.c:881 +#: wt-status.c:880 msgid " (use \"git rebase --abort\" to check out the original branch)" msgstr " (sử dụng \"git rebase --abort\" để check-out nhánh nguyên thủy)" -#: wt-status.c:887 +#: wt-status.c:886 msgid " (all conflicts fixed: run \"git rebase --continue\")" msgstr " (khi tất cả các xung đột đã sửa xong: chạy lệnh \"git rebase --continue\")" -#: wt-status.c:889 +#: wt-status.c:888 msgid "You are currently splitting a commit during a rebase." msgstr "Bạn hiện tại đang cắt đôi một lần chuyển giao trong khi đang thực hiện việc rebase." -#: wt-status.c:892 +#: wt-status.c:891 msgid " (Once your working directory is clean, run \"git rebase --continue\")" msgstr " (Một khi thư mục làm việc của bạn đã gọn gàng, chạy \"git rebase --continue\")" -#: wt-status.c:894 +#: wt-status.c:893 msgid "You are currently editing a commit during a rebase." msgstr "Bạn hiện đang sửa một lần chuyển giao trong khi bạn thực hiện rebase." -#: wt-status.c:897 +#: wt-status.c:896 msgid " (use \"git commit --amend\" to amend the current commit)" msgstr " (sử dụng \"git commit --amend\" để tu bổ lần chuyển giao (commit) hiện tại)" -#: wt-status.c:899 +#: wt-status.c:898 msgid " (use \"git rebase --continue\" once you are satisfied with your changes)" msgstr " (sử dụng \"git rebase --continue\" một khi bạn cảm thấy hài lòng về những thay đổi của mình)" -#: wt-status.c:909 +#: wt-status.c:908 msgid "You are currently cherry-picking." msgstr "Bạn hiện nay đang thực hiện việc cherry-pick." -#: wt-status.c:916 +#: wt-status.c:915 msgid " (all conflicts fixed: run \"git commit\")" msgstr " (khi tất cả các xung đột đã sửa xong: chạy lệnh \"git commit\")" -#: wt-status.c:925 +#: wt-status.c:924 msgid "You are currently bisecting." msgstr "Bạn hiện tại đang thực hiện việc bisect (chia đôi)." -#: wt-status.c:928 +#: wt-status.c:927 msgid " (use \"git bisect reset\" to get back to the original branch)" msgstr " (sử dụng \"git bisect reset\" để quay trở lại nhánh nguyên thủy)" -#: wt-status.c:979 +#: wt-status.c:978 msgid "On branch " msgstr "Trên nhánh" -#: wt-status.c:986 +#: wt-status.c:985 msgid "Not currently on any branch." msgstr "Hiện tại chẳng ở nhánh nào cả." -#: wt-status.c:998 +#: wt-status.c:997 msgid "Initial commit" msgstr "Lần chuyển giao (commit) khởi đầu" -#: wt-status.c:1012 +#: wt-status.c:1011 msgid "Untracked" msgstr "Không được theo vết" -#: wt-status.c:1014 +#: wt-status.c:1013 msgid "Ignored" msgstr "Bị bỏ qua" -#: wt-status.c:1016 +#: wt-status.c:1015 #, c-format msgid "Untracked files not listed%s" msgstr "Những tập tin không bị theo vết không được liệt kê ra %s" -#: wt-status.c:1018 +#: wt-status.c:1017 msgid " (use -u option to show untracked files)" msgstr " (sử dụng tùy chọn -u để hiển thị các tập tin chưa được theo dõi)" -#: wt-status.c:1024 +#: wt-status.c:1023 msgid "No changes" msgstr "Không có thay đổi nào" -#: wt-status.c:1028 +#: wt-status.c:1027 #, c-format msgid "no changes added to commit%s\n" msgstr "không có thay đổi nào được thêm vào lần chuyển giao (commit)%s\n" -#: wt-status.c:1030 +#: wt-status.c:1029 msgid " (use \"git add\" and/or \"git commit -a\")" msgstr " (sử dụng \"git add\" và/hoặc \"git commit -a\")" -#: wt-status.c:1032 +#: wt-status.c:1031 #, c-format msgid "nothing added to commit but untracked files present%s\n" msgstr "không có gì được thêm vào lần chuyển giao (commit) nhưng có những tập tin không được theo dấu vết hiện diện%s\n" -#: wt-status.c:1034 +#: wt-status.c:1033 msgid " (use \"git add\" to track)" msgstr " (sử dụng \"git add\" để theo dõi dấu vết)" -#: wt-status.c:1036 -#: wt-status.c:1039 -#: wt-status.c:1042 +#: wt-status.c:1035 +#: wt-status.c:1038 +#: wt-status.c:1041 #, c-format msgid "nothing to commit%s\n" msgstr "không có gì để chuyển giao (commit) %s\n" -#: wt-status.c:1037 +#: wt-status.c:1036 msgid " (create/copy files and use \"git add\" to track)" msgstr " (tạo/sao-chép các tập tin và sử dụng \"git add\" để theo dõi dấu vết)" -#: wt-status.c:1040 +#: wt-status.c:1039 msgid " (use -u to show untracked files)" msgstr " (sử dụng tùy chọn -u để hiển thị các tập tin chưa được theo dõi)" -#: wt-status.c:1043 +#: wt-status.c:1042 msgid " (working directory clean)" msgstr " (thư mục làm việc sạch sẽ)" -#: wt-status.c:1151 +#: wt-status.c:1150 msgid "HEAD (no branch)" msgstr "HEAD (chưa có nhánh nào)" -#: wt-status.c:1157 +#: wt-status.c:1156 msgid "Initial commit on " msgstr "Lần chuyển giao (commit) khởi tạo trên" -#: wt-status.c:1172 +#: wt-status.c:1171 msgid "behind " msgstr "đằng sau" -#: wt-status.c:1175 -#: wt-status.c:1178 +#: wt-status.c:1174 +#: wt-status.c:1177 msgid "ahead " msgstr "phía trước" -#: wt-status.c:1180 +#: wt-status.c:1179 msgid ", behind " msgstr ", đằng sau" @@ -1034,7 +1289,7 @@ msgid "unexpected diff status %c" msgstr "trạng thái lệnh diff không như mong đợi %c" #: builtin/add.c:67 -#: builtin/commit.c:226 +#: builtin/commit.c:229 msgid "updating files failed" msgstr "Cập nhật tập tin gặp lỗi" @@ -1128,161 +1383,161 @@ msgstr "Có lẽ bạn muốn nói là 'git add .' phải không?\n" #: builtin/add.c:420 #: builtin/clean.c:95 -#: builtin/commit.c:286 +#: builtin/commit.c:289 #: builtin/mv.c:82 #: builtin/rm.c:162 msgid "index file corrupt" msgstr "tập tin ghi bảng mục lục bị hỏng" #: builtin/add.c:480 -#: builtin/apply.c:4108 +#: builtin/apply.c:4433 #: builtin/mv.c:229 #: builtin/rm.c:260 msgid "Unable to write new index file" msgstr "Không thể ghi tập tin lưu bảng mục lục mới" -#: builtin/apply.c:53 +#: builtin/apply.c:57 msgid "git apply [options] [<patch>...]" msgstr "git apply [các-tùy-chọn] [<miếng-vá>...]" -#: builtin/apply.c:106 +#: builtin/apply.c:110 #, c-format msgid "unrecognized whitespace option '%s'" msgstr "không nhận ra tùy chọn về khoảng trắng '%s'" -#: builtin/apply.c:121 +#: builtin/apply.c:125 #, c-format msgid "unrecognized whitespace ignore option '%s'" msgstr "không nhận ra tùy chọn bỏ qua khoảng trắng '%s'" -#: builtin/apply.c:815 +#: builtin/apply.c:824 #, c-format msgid "Cannot prepare timestamp regexp %s" msgstr "Không thể chuẩn bị biểu thức chính qui dấu vết thời gian (timestamp regexp) %s" -#: builtin/apply.c:824 +#: builtin/apply.c:833 #, c-format msgid "regexec returned %d for input: %s" msgstr "thi hành biểu thức chính quy trả về %d cho kết xuất: %s" -#: builtin/apply.c:905 +#: builtin/apply.c:914 #, c-format msgid "unable to find filename in patch at line %d" msgstr "không thể tìm thấy tên tập tin trong miếng vá tại dòng %d" -#: builtin/apply.c:937 +#: builtin/apply.c:946 #, c-format msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d" msgstr "git apply: git-diff sai - mong đợi /dev/null, đã nhận %s trên dòng %d" -#: builtin/apply.c:941 +#: builtin/apply.c:950 #, c-format msgid "git apply: bad git-diff - inconsistent new filename on line %d" msgstr "git apply: git-diff sai - tên tập tin mới mâu thuấn trên dòng %d" -#: builtin/apply.c:942 +#: builtin/apply.c:951 #, c-format msgid "git apply: bad git-diff - inconsistent old filename on line %d" msgstr "git apply: git-diff sai - tên tập tin cũ mâu thuấn trên dòng %d" -#: builtin/apply.c:949 +#: builtin/apply.c:958 #, c-format msgid "git apply: bad git-diff - expected /dev/null on line %d" msgstr "git apply: git-diff sai - mong đợi /dev/null trên dòng %d" -#: builtin/apply.c:1394 +#: builtin/apply.c:1403 #, c-format msgid "recount: unexpected line: %.*s" msgstr "chi tiết: dòng không được mong đợi: %.*s" -#: builtin/apply.c:1451 +#: builtin/apply.c:1460 #, c-format msgid "patch fragment without header at line %d: %.*s" msgstr "miếng vá phân mảnh mà không có phần đầu tại dòng %d: %.*s" -#: builtin/apply.c:1468 +#: builtin/apply.c:1477 #, c-format msgid "git diff header lacks filename information when removing %d leading pathname component (line %d)" msgid_plural "git diff header lacks filename information when removing %d leading pathname components (line %d)" msgstr[0] "phần đầu diff cho git thiếu thông tin tên tập tin khi gỡ bỏ đi %d trong thành phần dẫn đầu tên của đường dẫn (dòng %d)" msgstr[1] "phần đầu diff cho git thiếu thông tin tên tập tin khi gỡ bỏ đi %d trong thành phần dẫn đầu tên của đường dẫn (dòng %d)" -#: builtin/apply.c:1628 +#: builtin/apply.c:1637 msgid "new file depends on old contents" msgstr "tập tin mới phụ thuộc vào nội dung cũ" -#: builtin/apply.c:1630 +#: builtin/apply.c:1639 msgid "deleted file still has contents" msgstr "tập tin đã xóa vẫn còn nội dung" -#: builtin/apply.c:1656 +#: builtin/apply.c:1665 #, c-format msgid "corrupt patch at line %d" msgstr "miếng vá hỏng tại dòng %d" -#: builtin/apply.c:1692 +#: builtin/apply.c:1701 #, c-format msgid "new file %s depends on old contents" msgstr "tập tin mới %s phụ thuộc vào nội dung cũ" -#: builtin/apply.c:1694 +#: builtin/apply.c:1703 #, c-format msgid "deleted file %s still has contents" msgstr "tập tin đã xóa %s vẫn còn nội dung" -#: builtin/apply.c:1697 +#: builtin/apply.c:1706 #, c-format msgid "** warning: file %s becomes empty but is not deleted" msgstr "** cảnh báo: tập tin %s trở nên trống rỗng nhưng không bị xóa" -#: builtin/apply.c:1843 +#: builtin/apply.c:1852 #, c-format msgid "corrupt binary patch at line %d: %.*s" msgstr "miếng vá định dạng nhị phân sai hỏng tại dòng %d: %.*s" #. there has to be one hunk (forward hunk) -#: builtin/apply.c:1872 +#: builtin/apply.c:1881 #, c-format msgid "unrecognized binary patch at line %d" msgstr "miếng vá định dạng nhị phân không được nhận ra tại dòng %d" -#: builtin/apply.c:1958 +#: builtin/apply.c:1967 #, c-format msgid "patch with only garbage at line %d" msgstr "vá chỉ với 'garbage' tại dòng %d" -#: builtin/apply.c:2048 +#: builtin/apply.c:2057 #, c-format msgid "unable to read symlink %s" msgstr "không thể đọc liên kết tượng trưng %s" -#: builtin/apply.c:2052 +#: builtin/apply.c:2061 #, c-format msgid "unable to open or read %s" msgstr "không thể mở để đọc hay ghi %s" -#: builtin/apply.c:2123 +#: builtin/apply.c:2132 msgid "oops" msgstr "ôi?" -#: builtin/apply.c:2645 +#: builtin/apply.c:2654 #, c-format msgid "invalid start of line: '%c'" msgstr "sai khởi đầu dòng: '%c'" -#: builtin/apply.c:2763 +#: builtin/apply.c:2772 #, c-format msgid "Hunk #%d succeeded at %d (offset %d line)." msgid_plural "Hunk #%d succeeded at %d (offset %d lines)." msgstr[0] "Khối dữ liệu #%d thành công tại %d (offset %d dòng)." msgstr[1] "Khối dữ liệu #%d thành công tại %d (offset %d dòng)." -#: builtin/apply.c:2775 +#: builtin/apply.c:2784 #, c-format msgid "Context reduced to (%ld/%ld) to apply fragment at %d" msgstr "Nội dung được giảm xuống (%ld/%ld) để áp dụng mảnh dữ liệu tại %d" -#: builtin/apply.c:2781 +#: builtin/apply.c:2790 #, c-format msgid "" "while searching for:\n" @@ -1291,320 +1546,334 @@ msgstr "" "Trong khi đang tìm kiếm cho:\n" "%.*s" -#: builtin/apply.c:2800 +#: builtin/apply.c:2809 #, c-format msgid "missing binary patch data for '%s'" msgstr "thiếu dữ liệu của miếng vá định dạng nhị phân cho '%s'" -#: builtin/apply.c:2903 +#: builtin/apply.c:2912 #, c-format msgid "binary patch does not apply to '%s'" msgstr "miếng vá định dạng nhị phân không được áp dụng cho '%s'" -#: builtin/apply.c:2909 +#: builtin/apply.c:2918 #, c-format msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)" msgstr "vá nhị phân cho '%s' tạo ra kết quả không chính xác (đang chờ %s, đã nhận %s)" -#: builtin/apply.c:2930 +#: builtin/apply.c:2939 #, c-format msgid "patch failed: %s:%ld" msgstr "vá gặp lỗi: %s:%ld" -#: builtin/apply.c:3045 +#: builtin/apply.c:3061 #, c-format -msgid "patch %s has been renamed/deleted" -msgstr "miếng vá %s đã bị xóa/đổi tên" +msgid "cannot checkout %s" +msgstr "không thể \"checkout\" %s" -#: builtin/apply.c:3052 -#: builtin/apply.c:3069 +#: builtin/apply.c:3106 +#: builtin/apply.c:3115 +#: builtin/apply.c:3159 #, c-format msgid "read of %s failed" msgstr "đọc %s gặp lỗi" -#: builtin/apply.c:3084 -msgid "removal patch leaves file contents" -msgstr "loại bỏ miếng vá để lại nội dung tập tin" - -#: builtin/apply.c:3105 +#: builtin/apply.c:3139 +#: builtin/apply.c:3361 #, c-format -msgid "%s: already exists in working directory" -msgstr "%s: đã sẵn có trong thư mục đang làm việc" +msgid "path %s has been renamed/deleted" +msgstr "đường dẫn %s đã bị xóa/đổi tên" -#: builtin/apply.c:3143 +#: builtin/apply.c:3220 +#: builtin/apply.c:3375 #, c-format -msgid "%s: has been deleted/renamed" -msgstr "%s: đã được xóa/thay-tên" +msgid "%s: does not exist in index" +msgstr "%s: không tồn tại trong bảng mục lục" -#: builtin/apply.c:3148 -#: builtin/apply.c:3179 +#: builtin/apply.c:3224 +#: builtin/apply.c:3367 +#: builtin/apply.c:3389 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: builtin/apply.c:3159 -#, c-format -msgid "%s: does not exist in index" -msgstr "%s: không tồn tại trong bảng mục lục" - -#: builtin/apply.c:3173 +#: builtin/apply.c:3229 +#: builtin/apply.c:3383 #, c-format msgid "%s: does not match index" msgstr "%s: không khớp trong mục lục" -#: builtin/apply.c:3190 +#: builtin/apply.c:3331 +msgid "removal patch leaves file contents" +msgstr "loại bỏ miếng vá để lại nội dung tập tin" + +#: builtin/apply.c:3400 #, c-format msgid "%s: wrong type" msgstr "%s: sai kiểu" -#: builtin/apply.c:3192 +#: builtin/apply.c:3402 #, c-format msgid "%s has type %o, expected %o" msgstr "%s có kiểu %o, mong chờ %o" -#: builtin/apply.c:3247 +#: builtin/apply.c:3503 #, c-format msgid "%s: already exists in index" msgstr "%s: đã có từ trước trong bảng mục lục" -#: builtin/apply.c:3267 +#: builtin/apply.c:3506 +#, c-format +msgid "%s: already exists in working directory" +msgstr "%s: đã sẵn có trong thư mục đang làm việc" + +#: builtin/apply.c:3526 #, c-format msgid "new mode (%o) of %s does not match old mode (%o)" msgstr "chế độ mới (%o) của %s không khớp với chế độ cũ (%o)" -#: builtin/apply.c:3272 +#: builtin/apply.c:3531 #, c-format msgid "new mode (%o) of %s does not match old mode (%o) of %s" msgstr "chế độ mới (%o) của %s không khớp với chế độ cũ (%o) của %s" -#: builtin/apply.c:3280 +#: builtin/apply.c:3539 #, c-format msgid "%s: patch does not apply" msgstr "%s: miếng vá không được áp dụng" -#: builtin/apply.c:3293 +#: builtin/apply.c:3552 #, c-format msgid "Checking patch %s..." msgstr "Đang kiểm tra miếng vá %s..." -#: builtin/apply.c:3348 -#: builtin/checkout.c:212 +#: builtin/apply.c:3607 +#: builtin/checkout.c:213 #: builtin/reset.c:158 #, c-format msgid "make_cache_entry failed for path '%s'" msgstr "make_cache_entry gặp lỗi đối với đường dẫn '%s'" -#: builtin/apply.c:3491 +#: builtin/apply.c:3750 #, c-format msgid "unable to remove %s from index" msgstr "không thể gỡ bỏ %s từ mục lục" -#: builtin/apply.c:3518 +#: builtin/apply.c:3778 #, c-format msgid "corrupt patch for subproject %s" msgstr "miếng vá sai hỏng cho dự án con (subproject) %s" -#: builtin/apply.c:3522 +#: builtin/apply.c:3782 #, c-format msgid "unable to stat newly created file '%s'" msgstr "không thể lấy trạng thái về tập tin %s mới hơn đã được tạo" -#: builtin/apply.c:3527 +#: builtin/apply.c:3787 #, c-format msgid "unable to create backing store for newly created file %s" msgstr "không thể tạo 'backing store' cho tập tin được tạo mới hơn %s" -#: builtin/apply.c:3530 +#: builtin/apply.c:3790 +#: builtin/apply.c:3898 #, c-format msgid "unable to add cache entry for %s" msgstr "không thể thêm mục nhớ tạm cho %s" -#: builtin/apply.c:3563 +#: builtin/apply.c:3823 #, c-format msgid "closing file '%s'" msgstr "đang đóng tập tin '%s'" -#: builtin/apply.c:3612 +#: builtin/apply.c:3872 #, c-format msgid "unable to write file '%s' mode %o" msgstr "không thể ghi vào tập tin '%s' chế độ (mode) %o" -#: builtin/apply.c:3668 +#: builtin/apply.c:3959 #, c-format msgid "Applied patch %s cleanly." msgstr "Đã áp dụng miếng và %s một cách sạch sẽ." -#: builtin/apply.c:3676 +#: builtin/apply.c:3967 msgid "internal error" msgstr "lỗi nội bộ" #. Say this even without --verbose -#: builtin/apply.c:3679 +#: builtin/apply.c:3970 #, c-format msgid "Applying patch %%s with %d reject..." msgid_plural "Applying patch %%s with %d rejects..." msgstr[0] "Đang áp dụng miếng vá %%s với %d lần từ chối..." msgstr[1] "Đang áp dụng miếng vá %%s với %d lần từ chối..." -#: builtin/apply.c:3689 +#: builtin/apply.c:3980 #, c-format msgid "truncating .rej filename to %.*s.rej" msgstr "đang cắt cụt tên tập tin .rej thành %.*s.rej" -#: builtin/apply.c:3710 +#: builtin/apply.c:4001 #, c-format msgid "Hunk #%d applied cleanly." msgstr "Khối nhớ #%d được áp dụng gọn gàng." -#: builtin/apply.c:3713 +#: builtin/apply.c:4004 #, c-format msgid "Rejected hunk #%d." msgstr "hunk #%d bị từ chối." -#: builtin/apply.c:3844 +#: builtin/apply.c:4154 msgid "unrecognized input" msgstr "không thừa nhận đầu vào" -#: builtin/apply.c:3855 +#: builtin/apply.c:4165 msgid "unable to read index file" msgstr "không thể đọc tập tin lưu bảng mục lục" -#: builtin/apply.c:3970 -#: builtin/apply.c:3973 +#: builtin/apply.c:4284 +#: builtin/apply.c:4287 msgid "path" msgstr "đường-dẫn" -#: builtin/apply.c:3971 +#: builtin/apply.c:4285 msgid "don't apply changes matching the given path" msgstr "không áp dụng các thay đổi khớp với đường dẫn đã cho" -#: builtin/apply.c:3974 +#: builtin/apply.c:4288 msgid "apply changes matching the given path" msgstr "áp dụng các thay đổi khớp với đường dẫn đã cho" -#: builtin/apply.c:3976 +#: builtin/apply.c:4290 msgid "num" msgstr "số" -#: builtin/apply.c:3977 +#: builtin/apply.c:4291 msgid "remove <num> leading slashes from traditional diff paths" msgstr "gỡ bỏ <số> phần dẫn đầu (slashe) từ đường dẫn diff cổ điển" -#: builtin/apply.c:3980 +#: builtin/apply.c:4294 msgid "ignore additions made by the patch" msgstr "lờ đi phần phụ thêm tạo ra bởi miếng vá" -#: builtin/apply.c:3982 +#: builtin/apply.c:4296 msgid "instead of applying the patch, output diffstat for the input" msgstr "thay vì áp dụng một miếng vá, kết xuất kết quả từ lệnh diffstat cho đầu ra" -#: builtin/apply.c:3986 +#: builtin/apply.c:4300 msgid "shows number of added and deleted lines in decimal notation" msgstr "hiển thị số lượng các dòng được thêm vào và xóa đi theo ký hiệu thập phân" -#: builtin/apply.c:3988 +#: builtin/apply.c:4302 msgid "instead of applying the patch, output a summary for the input" msgstr "thay vì áp dụng một miếng vá, kết xuất kết quả cho đầu vào" -#: builtin/apply.c:3990 +#: builtin/apply.c:4304 msgid "instead of applying the patch, see if the patch is applicable" msgstr "thay vì áp dụng miếng vá, hãy xem xem miếng vá có thích hợp không" -#: builtin/apply.c:3992 +#: builtin/apply.c:4306 msgid "make sure the patch is applicable to the current index" msgstr "hãy chắc chắn là miếng vá thích hợp với bảng mục lục hiện hành" -#: builtin/apply.c:3994 +#: builtin/apply.c:4308 msgid "apply a patch without touching the working tree" msgstr "áp dụng một miếng vá mà không động chạm đến cây làm việc" -#: builtin/apply.c:3996 +#: builtin/apply.c:4310 msgid "also apply the patch (use with --stat/--summary/--check)" msgstr "đồng thời áp dụng miếng vá (sử dụng với tùy chọn --stat/--summary/--check)" -#: builtin/apply.c:3998 +#: builtin/apply.c:4312 +msgid "attempt three-way merge if a patch does not apply" +msgstr "thử hòa trộn kiểu three-way nếu việc vá không thể thực hiện được" + +#: builtin/apply.c:4314 msgid "build a temporary index based on embedded index information" msgstr "xây dựng bảng mục lục tạm thời trên cơ sở thông tin bảng mục lục được nhúng" -#: builtin/apply.c:4000 +#: builtin/apply.c:4316 msgid "paths are separated with NUL character" msgstr "các đường dẫn bị ngăn cách bởi ký tự NULL" -#: builtin/apply.c:4003 +#: builtin/apply.c:4319 msgid "ensure at least <n> lines of context match" msgstr "đảm bảo rằng có ít nhất <n> dòng nội dung khớp" -#: builtin/apply.c:4004 +#: builtin/apply.c:4320 msgid "action" msgstr "hành động" -#: builtin/apply.c:4005 +#: builtin/apply.c:4321 msgid "detect new or modified lines that have whitespace errors" msgstr "tìm thấy một dòng mới hoặc bị sửa đổi mà nó có lỗi do khoảng trắng" -#: builtin/apply.c:4008 -#: builtin/apply.c:4011 +#: builtin/apply.c:4324 +#: builtin/apply.c:4327 msgid "ignore changes in whitespace when finding context" msgstr "lờ đi sự thay đổi do khoảng trắng khi quét nội dung" -#: builtin/apply.c:4014 +#: builtin/apply.c:4330 msgid "apply the patch in reverse" msgstr "áp dụng miếng vá theo chiều ngược" -#: builtin/apply.c:4016 +#: builtin/apply.c:4332 msgid "don't expect at least one line of context" msgstr "đừng hy vọng có ít nhất một dòng nội dung" -#: builtin/apply.c:4018 +#: builtin/apply.c:4334 msgid "leave the rejected hunks in corresponding *.rej files" msgstr "để lại khối dữ liệu bị từ chối trong các tập tin *.rej tương ứng" -#: builtin/apply.c:4020 +#: builtin/apply.c:4336 msgid "allow overlapping hunks" msgstr "cho phép chồng khối nhớ" -#: builtin/apply.c:4021 +#: builtin/apply.c:4337 msgid "be verbose" msgstr "chi tiết" -#: builtin/apply.c:4023 +#: builtin/apply.c:4339 msgid "tolerate incorrectly detected missing new-line at the end of file" msgstr "dung sai không chính xác đã tìm thấy thiếu dòng mới tại cuối tập tin" -#: builtin/apply.c:4026 +#: builtin/apply.c:4342 msgid "do not trust the line counts in the hunk headers" msgstr "không tin số lượng dòng trong phần đầu khối dữ liệu" -#: builtin/apply.c:4028 +#: builtin/apply.c:4344 msgid "root" msgstr "root" -#: builtin/apply.c:4029 +#: builtin/apply.c:4345 msgid "prepend <root> to all filenames" msgstr "treo thêm <root> vào tất cả các tên tập tin" -#: builtin/apply.c:4050 +#: builtin/apply.c:4367 +msgid "--3way outside a repository" +msgstr "--3way ở ngoài một kho chứa" + +#: builtin/apply.c:4375 msgid "--index outside a repository" msgstr "--index ở ngoài một kho chứa" -#: builtin/apply.c:4053 +#: builtin/apply.c:4378 msgid "--cached outside a repository" msgstr "--cached ở ngoài một kho chứa" -#: builtin/apply.c:4069 +#: builtin/apply.c:4394 #, c-format msgid "can't open patch '%s'" msgstr "không thể mở miếng vá '%s'" -#: builtin/apply.c:4083 +#: builtin/apply.c:4408 #, c-format msgid "squelched %d whitespace error" msgid_plural "squelched %d whitespace errors" msgstr[0] "đã chấm dứt %d lỗi khoảng trắng" msgstr[1] "đã chấm dứt %d lỗi khoảng trắng" -#: builtin/apply.c:4089 -#: builtin/apply.c:4099 +#: builtin/apply.c:4414 +#: builtin/apply.c:4424 #, c-format msgid "%d line adds whitespace errors." msgid_plural "%d lines add whitespace errors." @@ -1810,7 +2079,7 @@ msgid "Failed to resolve HEAD as a valid ref." msgstr "Gặp lỗi khi giải quyết HEAD như là một tham chiếu (ref) hợp lệ." #: builtin/branch.c:788 -#: builtin/clone.c:558 +#: builtin/clone.c:561 msgid "HEAD not found below refs/heads!" msgstr "HEAD không tìm thấy ở dưới refs/heads!" @@ -1835,107 +2104,107 @@ msgstr "Cần một kho chứa để mà tạo một bundle." msgid "Need a repository to unbundle." msgstr "Cần một kho chứa để mà bung một bundle." -#: builtin/checkout.c:113 -#: builtin/checkout.c:146 +#: builtin/checkout.c:114 +#: builtin/checkout.c:147 #, c-format msgid "path '%s' does not have our version" msgstr "đường dẫn '%s' không có các phiên bản của chúng ta" -#: builtin/checkout.c:115 -#: builtin/checkout.c:148 +#: builtin/checkout.c:116 +#: builtin/checkout.c:149 #, c-format msgid "path '%s' does not have their version" msgstr "đường dẫn '%s' không có các phiên bản của chúng" -#: builtin/checkout.c:131 +#: builtin/checkout.c:132 #, c-format msgid "path '%s' does not have all necessary versions" msgstr "đường dẫn '%s' không có tất cả các phiên bản cần thiết" -#: builtin/checkout.c:175 +#: builtin/checkout.c:176 #, c-format msgid "path '%s' does not have necessary versions" msgstr "đường dẫn '%s' không có các phiên bản cần thiết" -#: builtin/checkout.c:192 +#: builtin/checkout.c:193 #, c-format msgid "path '%s': cannot merge" msgstr "đường dẫn '%s': không thể hòa trộn" -#: builtin/checkout.c:209 +#: builtin/checkout.c:210 #, c-format msgid "Unable to add merge result for '%s'" msgstr "Không thể thêm kết quả hòa trộn cho '%s'" -#: builtin/checkout.c:234 -#: builtin/checkout.c:392 +#: builtin/checkout.c:235 +#: builtin/checkout.c:393 msgid "corrupt index file" msgstr "tập tin ghi bảng mục lục bị hỏng" -#: builtin/checkout.c:264 -#: builtin/checkout.c:271 +#: builtin/checkout.c:265 +#: builtin/checkout.c:272 #, c-format msgid "path '%s' is unmerged" msgstr "đường dẫn '%s' không được hòa trộn" -#: builtin/checkout.c:302 -#: builtin/checkout.c:498 -#: builtin/clone.c:583 +#: builtin/checkout.c:303 +#: builtin/checkout.c:499 +#: builtin/clone.c:586 #: builtin/merge.c:812 msgid "unable to write new index file" msgstr "không thể ghi tập tin lưu bảng mục lục mới" -#: builtin/checkout.c:319 +#: builtin/checkout.c:320 #: builtin/diff.c:302 #: builtin/merge.c:408 msgid "diff_setup_done failed" msgstr "diff_setup_done gặp lỗi" -#: builtin/checkout.c:414 +#: builtin/checkout.c:415 msgid "you need to resolve your current index first" msgstr "bạn cần phải giải quyết bảng mục lục hiện tại của bạn trước đã!" -#: builtin/checkout.c:533 +#: builtin/checkout.c:534 #, c-format msgid "Can not do reflog for '%s'\n" msgstr "Không thể thực hiện reflog cho '%s'\n" -#: builtin/checkout.c:566 +#: builtin/checkout.c:567 msgid "HEAD is now at" msgstr "HEAD hiện giờ tại" -#: builtin/checkout.c:573 +#: builtin/checkout.c:574 #, c-format msgid "Reset branch '%s'\n" msgstr "Đặt lại nhánh '%s'\n" -#: builtin/checkout.c:576 +#: builtin/checkout.c:577 #, c-format msgid "Already on '%s'\n" msgstr "Đã sẵn sàng trên '%s'\n" -#: builtin/checkout.c:580 +#: builtin/checkout.c:581 #, c-format msgid "Switched to and reset branch '%s'\n" msgstr "Đã chuyển tới và reset nhánh '%s'\n" -#: builtin/checkout.c:582 +#: builtin/checkout.c:583 #, c-format msgid "Switched to a new branch '%s'\n" msgstr "Đã chuyển đến nhánh mới '%s'\n" -#: builtin/checkout.c:584 +#: builtin/checkout.c:585 #, c-format msgid "Switched to branch '%s'\n" msgstr "Đã chuyển đến nhánh '%s'\n" -#: builtin/checkout.c:640 +#: builtin/checkout.c:641 #, c-format msgid " ... and %d more.\n" msgstr " ... và nhiều hơn %d.\n" #. The singular version -#: builtin/checkout.c:646 +#: builtin/checkout.c:647 #, c-format msgid "" "Warning: you are leaving %d commit behind, not connected to\n" @@ -1958,7 +2227,7 @@ msgstr[1] "" "\n" "%s\n" -#: builtin/checkout.c:664 +#: builtin/checkout.c:665 #, c-format msgid "" "If you want to keep them by creating a new branch, this may be a good time\n" @@ -1973,71 +2242,72 @@ msgstr "" " git branch tên_nhánh_mới %s\n" "\n" -#: builtin/checkout.c:694 +#: builtin/checkout.c:695 msgid "internal error in revision walk" msgstr "lỗi nội bộ trong khi di chuyển qua các điểm xét lại" -#: builtin/checkout.c:698 +#: builtin/checkout.c:699 msgid "Previous HEAD position was" msgstr "Vị trí kế trước của HEAD là" -#: builtin/checkout.c:724 +#: builtin/checkout.c:725 +#: builtin/checkout.c:920 msgid "You are on a branch yet to be born" msgstr "Bạn tại nhánh mà nó chưa hề được sinh ra" #. case (1) -#: builtin/checkout.c:855 +#: builtin/checkout.c:856 #, c-format msgid "invalid reference: %s" msgstr "tham chiếu sai: %s" #. case (1): want a tree -#: builtin/checkout.c:894 +#: builtin/checkout.c:895 #, c-format msgid "reference is not a tree: %s" msgstr "tham chiếu không phải là cây:%s" -#: builtin/checkout.c:974 +#: builtin/checkout.c:977 msgid "-B cannot be used with -b" msgstr "-B không thể được sử dụng với -b" -#: builtin/checkout.c:983 +#: builtin/checkout.c:986 msgid "--patch is incompatible with all other options" msgstr "--patch xung khắc với tất cả các tùy chọn khác" -#: builtin/checkout.c:986 +#: builtin/checkout.c:989 msgid "--detach cannot be used with -b/-B/--orphan" msgstr "--detach không thể được sử dụng với -b/-B/--orphan" -#: builtin/checkout.c:988 +#: builtin/checkout.c:991 msgid "--detach cannot be used with -t" msgstr "--detach không thể được sử dụng với tùy chọn -t" -#: builtin/checkout.c:994 +#: builtin/checkout.c:997 msgid "--track needs a branch name" msgstr "--track cần tên một nhánh" -#: builtin/checkout.c:1001 +#: builtin/checkout.c:1004 msgid "Missing branch name; try -b" msgstr "Thiếu tên nhánh; hãy thử -b" -#: builtin/checkout.c:1007 +#: builtin/checkout.c:1010 msgid "--orphan and -b|-B are mutually exclusive" msgstr "Tùy chọn --orphan và -b|-B loại từ lẫn nhau" -#: builtin/checkout.c:1009 +#: builtin/checkout.c:1012 msgid "--orphan cannot be used with -t" msgstr "--orphan không thể được sử dụng với tùy chọn -t" -#: builtin/checkout.c:1019 +#: builtin/checkout.c:1022 msgid "git checkout: -f and -m are incompatible" msgstr "git checkout: -f và -m xung khắc nhau" -#: builtin/checkout.c:1053 +#: builtin/checkout.c:1056 msgid "invalid path specification" msgstr "đường dẫn đã cho không hợp lệ" -#: builtin/checkout.c:1061 +#: builtin/checkout.c:1064 #, c-format msgid "" "git checkout: updating paths is incompatible with switching branches.\n" @@ -2046,27 +2316,27 @@ msgstr "" "git checkout: việc cập nhật các đường dẫn là xung khắc với việc chuyển đổi các nhánh..\n" "Bạn đã có ý định checkout '%s' cái mà không thể được phân giải như là lần chuyển giao (commit)?" -#: builtin/checkout.c:1063 +#: builtin/checkout.c:1066 msgid "git checkout: updating paths is incompatible with switching branches." msgstr "git checkout: việc cập nhật các đường dẫn là xung khắc với việc chuyển đổi các nhánh." -#: builtin/checkout.c:1068 +#: builtin/checkout.c:1071 msgid "git checkout: --detach does not take a path argument" -msgstr "git checkout: --detach không nhận một đối số đường dẫn" +msgstr "git checkout: --detach không nhận một đối số là đường dẫn" -#: builtin/checkout.c:1071 +#: builtin/checkout.c:1074 msgid "" "git checkout: --ours/--theirs, --force and --merge are incompatible when\n" "checking out of the index." msgstr "" "git checkout: --ours/--theirs, --force và --merge là xung khắc với nhau khi\n" -"checkout." +"checkout bảng mục lục (index)." -#: builtin/checkout.c:1090 +#: builtin/checkout.c:1093 msgid "Cannot switch branch to a non-commit." msgstr "Không thể chuyển đến một non-commit." -#: builtin/checkout.c:1093 +#: builtin/checkout.c:1096 msgid "--ours/--theirs is incompatible with switching branches." msgstr "--ours/--theirs là xung khắc nhau khi chuyển đổi các nhánh." @@ -2115,11 +2385,6 @@ msgstr "Không xóa %s\n" msgid "reference repository '%s' is not a local directory." msgstr "kho tham chiếu '%s' không phải là một thư mục nội bộ." -#: builtin/clone.c:302 -#, c-format -msgid "failed to open '%s'" -msgstr "gặp lỗi khi mở '%s'" - #: builtin/clone.c:306 #, c-format msgid "failed to create directory '%s'" @@ -2161,79 +2426,79 @@ msgstr "sao chép tệp tin tới '%s' gặp lỗi" msgid "done.\n" msgstr "hoàn tất.\n" -#: builtin/clone.c:440 +#: builtin/clone.c:443 #, c-format msgid "Could not find remote branch %s to clone." msgstr "Không tìm thấy nhánh máy chủ %s để nhân bản (clone)." -#: builtin/clone.c:549 +#: builtin/clone.c:552 msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n" msgstr "refers HEAD máy chủ chỉ đến ref không tồn tại, không thể checkout.\n" -#: builtin/clone.c:639 +#: builtin/clone.c:642 msgid "Too many arguments." msgstr "Có quá nhiều đối số." -#: builtin/clone.c:643 +#: builtin/clone.c:646 msgid "You must specify a repository to clone." msgstr "Bạn phải chỉ định một kho để mà nhân bản (clone)." -#: builtin/clone.c:654 +#: builtin/clone.c:657 #, c-format msgid "--bare and --origin %s options are incompatible." msgstr "tùy chọn --bare và --origin %s xung khắc nhau." -#: builtin/clone.c:668 +#: builtin/clone.c:671 #, c-format msgid "repository '%s' does not exist" msgstr "kho chứa '%s' chưa tồn tại" -#: builtin/clone.c:673 +#: builtin/clone.c:676 msgid "--depth is ignored in local clones; use file:// instead." msgstr "--depth bị lờ đi khi nhân bản nội bộ; hãy sử dụng file:// để thay thế." -#: builtin/clone.c:683 +#: builtin/clone.c:686 #, c-format msgid "destination path '%s' already exists and is not an empty directory." msgstr "đường dẫn đích '%s' đã có từ trước và không phải là một thư mục rỗng." -#: builtin/clone.c:693 +#: builtin/clone.c:696 #, c-format msgid "working tree '%s' already exists." msgstr "cây làm việc '%s' đã sẵn tồn tại rồi." -#: builtin/clone.c:706 -#: builtin/clone.c:720 +#: builtin/clone.c:709 +#: builtin/clone.c:723 #, c-format msgid "could not create leading directories of '%s'" msgstr "không thể tạo các thư mục dẫn đầu của '%s'" -#: builtin/clone.c:709 +#: builtin/clone.c:712 #, c-format msgid "could not create work tree dir '%s'." msgstr "không thể tạo cây thư mục làm việc dir '%s'." -#: builtin/clone.c:728 +#: builtin/clone.c:731 #, c-format msgid "Cloning into bare repository '%s'...\n" msgstr "Đang nhân bản thành kho chứa bare '%s'...\n" -#: builtin/clone.c:730 +#: builtin/clone.c:733 #, c-format msgid "Cloning into '%s'...\n" msgstr "Đang nhân bản thành '%s'...\n" -#: builtin/clone.c:786 +#: builtin/clone.c:789 #, c-format msgid "Don't know how to clone %s" msgstr "Không biết làm cách nào để nhân bản (clone) %s" -#: builtin/clone.c:835 +#: builtin/clone.c:838 #, c-format msgid "Remote branch %s not found in upstream %s" msgstr "Nhánh máy chủ %s không tìm thấy trong dòng ngược (upstream) %s" -#: builtin/clone.c:842 +#: builtin/clone.c:845 msgid "You appear to have cloned an empty repository." msgstr "Bạn hình như là đã nhân bản một kho trống rỗng." @@ -2292,99 +2557,99 @@ msgstr "" "\n" "Nếu không, hãy thử sử dụng 'git reset'\n" -#: builtin/commit.c:253 +#: builtin/commit.c:256 msgid "failed to unpack HEAD tree object" msgstr "gặp lỗi khi tháo dỡ HEAD đối tượng cây" -#: builtin/commit.c:295 +#: builtin/commit.c:298 msgid "unable to create temporary index" msgstr "không thể tạo bảng mục lục tạm thời" -#: builtin/commit.c:301 +#: builtin/commit.c:304 msgid "interactive add failed" msgstr "việc thêm tương tác gặp lỗi" -#: builtin/commit.c:334 -#: builtin/commit.c:355 -#: builtin/commit.c:405 +#: builtin/commit.c:337 +#: builtin/commit.c:358 +#: builtin/commit.c:408 msgid "unable to write new_index file" msgstr "không thể ghi tập tin lưu bảng mục lục mới (new_index)" -#: builtin/commit.c:386 +#: builtin/commit.c:389 msgid "cannot do a partial commit during a merge." msgstr "không thể thực hiện việc chuyển giao (commit) cục bộ trong khi đang được hòa trộn." -#: builtin/commit.c:388 +#: builtin/commit.c:391 msgid "cannot do a partial commit during a cherry-pick." msgstr "không thể thực hiện việc chuyển giao (commit) bộ phận trong khi đang cherry-pick." -#: builtin/commit.c:398 +#: builtin/commit.c:401 msgid "cannot read the index" msgstr "không đọc được bảng mục lục" -#: builtin/commit.c:418 +#: builtin/commit.c:421 msgid "unable to write temporary index file" msgstr "không thể ghi tập tin lưu bảng mục lục tạm thời" -#: builtin/commit.c:493 -#: builtin/commit.c:499 +#: builtin/commit.c:496 +#: builtin/commit.c:502 #, c-format msgid "invalid commit: %s" msgstr "lần chuyển giao (commit) không hợp lệ: %s" -#: builtin/commit.c:522 +#: builtin/commit.c:525 msgid "malformed --author parameter" msgstr "đối số --author bị dị hình" -#: builtin/commit.c:582 +#: builtin/commit.c:585 #, c-format msgid "Malformed ident string: '%s'" msgstr "Chuỗi thụt lề đầu dòng dị hình: '%s'" -#: builtin/commit.c:620 -#: builtin/commit.c:653 -#: builtin/commit.c:967 +#: builtin/commit.c:623 +#: builtin/commit.c:656 +#: builtin/commit.c:970 #, c-format msgid "could not lookup commit %s" msgstr "không thể tìm kiếm commit (lần chuyển giao) %s" -#: builtin/commit.c:632 +#: builtin/commit.c:635 #: builtin/shortlog.c:296 #, c-format msgid "(reading log message from standard input)\n" msgstr "(đang đọc thông điệp nhật ký từ đầu vào tiêu chuẩn)\n" -#: builtin/commit.c:634 +#: builtin/commit.c:637 msgid "could not read log from standard input" msgstr "không thể đọc nhật ký từ đầu vào tiêu chuẩn" -#: builtin/commit.c:638 +#: builtin/commit.c:641 #, c-format msgid "could not read log file '%s'" msgstr "không đọc được tệp nhật ký '%s'" -#: builtin/commit.c:644 +#: builtin/commit.c:647 msgid "commit has empty message" msgstr "lần chuyển giao (commit) có ghi chú trống rỗng" -#: builtin/commit.c:660 +#: builtin/commit.c:663 msgid "could not read MERGE_MSG" msgstr "không thể đọc MERGE_MSG" -#: builtin/commit.c:664 +#: builtin/commit.c:667 msgid "could not read SQUASH_MSG" msgstr "không thể đọc SQUASH_MSG" -#: builtin/commit.c:668 +#: builtin/commit.c:671 #, c-format msgid "could not read '%s'" msgstr "Không thể đọc '%s'." -#: builtin/commit.c:720 +#: builtin/commit.c:723 msgid "could not write commit template" msgstr "không thể ghi mẫu commit" -#: builtin/commit.c:731 +#: builtin/commit.c:734 #, c-format msgid "" "\n" @@ -2399,7 +2664,7 @@ msgstr "" "\t%s\n" "và thử lại.\n" -#: builtin/commit.c:736 +#: builtin/commit.c:739 #, c-format msgid "" "\n" @@ -2414,7 +2679,7 @@ msgstr "" "\t%s\n" "và thử lại.\n" -#: builtin/commit.c:748 +#: builtin/commit.c:751 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be ignored, and an empty message aborts the commit.\n" @@ -2422,7 +2687,7 @@ msgstr "" "Hãy nhập vào các thông tin để giải thích các thay đổi của bạn. Những dòng được\n" "bắt đầu bằng '#' sẽ được bỏ qua, phần chú thích này nếu rỗng sẽ làm hủy bỏ lần chuyển giao (commit).\n" -#: builtin/commit.c:753 +#: builtin/commit.c:756 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be kept; you may remove them yourself if you want to.\n" @@ -2432,164 +2697,164 @@ msgstr "" "bắt đầu bằng '#' sẽ được bỏ qua; bạn có thể xóa chúng đi nếu muốn.\n" "Phần chú thích này nếu rỗng sẽ làm hủy bỏ lần chuyển giao (commit).\n" -#: builtin/commit.c:766 +#: builtin/commit.c:769 #, c-format msgid "%sAuthor: %s" msgstr "%sTác giả: %s" -#: builtin/commit.c:773 +#: builtin/commit.c:776 #, c-format msgid "%sCommitter: %s" msgstr "%sNgười chuyển giao (commit): %s" -#: builtin/commit.c:793 +#: builtin/commit.c:796 msgid "Cannot read index" msgstr "không đọc được bảng mục lục" -#: builtin/commit.c:830 +#: builtin/commit.c:833 msgid "Error building trees" msgstr "Gặp lỗi khi xây dựng cây" -#: builtin/commit.c:845 +#: builtin/commit.c:848 #: builtin/tag.c:361 #, c-format msgid "Please supply the message using either -m or -F option.\n" msgstr "Xin hãy áp dụng thông điệp sử dụng hoặc là tùy chọn -m hoặc là -F.\n" -#: builtin/commit.c:942 +#: builtin/commit.c:945 #, c-format msgid "No existing author found with '%s'" msgstr "Không tìm thấy tác giả đã sẵn có với '%s'" -#: builtin/commit.c:957 -#: builtin/commit.c:1157 +#: builtin/commit.c:960 +#: builtin/commit.c:1160 #, c-format msgid "Invalid untracked files mode '%s'" msgstr "Chế độ cho các tập tin không bị theo vết không hợp lệ '%s'" -#: builtin/commit.c:997 +#: builtin/commit.c:1000 msgid "Using both --reset-author and --author does not make sense" msgstr "Sử dụng cả hai tùy chọn --reset-author và --author không hợp lý" -#: builtin/commit.c:1008 +#: builtin/commit.c:1011 msgid "You have nothing to amend." msgstr "Không có gì để amend (tu bổ) cả." -#: builtin/commit.c:1011 +#: builtin/commit.c:1014 msgid "You are in the middle of a merge -- cannot amend." msgstr "Bạn đang ở giữa của quá trình hòa trộn -- không thể thực hiện amend (tu bổ)." -#: builtin/commit.c:1013 +#: builtin/commit.c:1016 msgid "You are in the middle of a cherry-pick -- cannot amend." msgstr "Bạn đang ở giữa của quá trình cherry-pick -- không thể thực hiện amend (tu bổ)." -#: builtin/commit.c:1016 +#: builtin/commit.c:1019 msgid "Options --squash and --fixup cannot be used together" msgstr "Các tùy chọn --squash và --fixup không thể sử dụng cùng với nhau" -#: builtin/commit.c:1026 +#: builtin/commit.c:1029 msgid "Only one of -c/-C/-F/--fixup can be used." msgstr "Chỉ một tùy chọn trong số -c/-C/-F/--fixup được sử dụng" -#: builtin/commit.c:1028 +#: builtin/commit.c:1031 msgid "Option -m cannot be combined with -c/-C/-F/--fixup." msgstr "Tùy chọn -m không thể được tổ hợp cùng với -c/-C/-F/--fixup." -#: builtin/commit.c:1036 +#: builtin/commit.c:1039 msgid "--reset-author can be used only with -C, -c or --amend." msgstr "--reset-author chỉ có thể được sử dụng với tùy chọn -C, -c hay --amend." -#: builtin/commit.c:1053 +#: builtin/commit.c:1056 msgid "Only one of --include/--only/--all/--interactive/--patch can be used." msgstr "Chỉ một trong các tùy chọn --include/--only/--all/--interactive/--patch được sử dụng." -#: builtin/commit.c:1055 +#: builtin/commit.c:1058 msgid "No paths with --include/--only does not make sense." msgstr "Không đường dẫn với các tùy chọn --include/--only không hợp lý." -#: builtin/commit.c:1057 +#: builtin/commit.c:1060 msgid "Clever... amending the last one with dirty index." msgstr "Giỏi... đang tu bổ cái cuối với bảng mục lục phi nghĩa." -#: builtin/commit.c:1059 +#: builtin/commit.c:1062 msgid "Explicit paths specified without -i nor -o; assuming --only paths..." msgstr "Những đường dẫn rõ ràng được chỉ ra không có tùy chọn -i cũng không -o; đang giả định --only những-đường-dẫn..." -#: builtin/commit.c:1069 +#: builtin/commit.c:1072 #: builtin/tag.c:577 #, c-format msgid "Invalid cleanup mode %s" msgstr "Chế độ dọn dẹp không hợp lệ %s" -#: builtin/commit.c:1074 +#: builtin/commit.c:1077 msgid "Paths with -a does not make sense." msgstr "Các đường dẫn với tùy chọn -a không hợp lý." -#: builtin/commit.c:1257 +#: builtin/commit.c:1260 msgid "couldn't look up newly created commit" msgstr "không thể tìm thấy lần chuyển giao (commit) mới hơn đã được tạo" -#: builtin/commit.c:1259 +#: builtin/commit.c:1262 msgid "could not parse newly created commit" msgstr "không thể phân tích cú pháp của đối tượng chuyển giao mới hơn đã được tạo" -#: builtin/commit.c:1300 +#: builtin/commit.c:1303 msgid "detached HEAD" msgstr "đã rời khỏi HEAD" -#: builtin/commit.c:1302 +#: builtin/commit.c:1305 msgid " (root-commit)" msgstr " (root-commit)" -#: builtin/commit.c:1446 +#: builtin/commit.c:1449 msgid "could not parse HEAD commit" msgstr "không thể phân tích commit (lần chuyển giao) HEAD" -#: builtin/commit.c:1484 +#: builtin/commit.c:1487 #: builtin/merge.c:509 #, c-format msgid "could not open '%s' for reading" msgstr "không thể mở %s' để đọc" -#: builtin/commit.c:1491 +#: builtin/commit.c:1494 #, c-format msgid "Corrupt MERGE_HEAD file (%s)" msgstr "Tập tin MERGE_HEAD sai hỏng (%s)" -#: builtin/commit.c:1498 +#: builtin/commit.c:1501 msgid "could not read MERGE_MODE" msgstr "không thể đọc MERGE_MODE" -#: builtin/commit.c:1517 +#: builtin/commit.c:1520 #, c-format msgid "could not read commit message: %s" msgstr "không thể đọc thông điệp (message) commit (lần chuyển giao): %s" -#: builtin/commit.c:1531 +#: builtin/commit.c:1534 #, c-format msgid "Aborting commit; you did not edit the message.\n" msgstr "Đang bỏ qua việc chuyển giao (commit); bạn đã không biên soạn thông điệp (message).\n" -#: builtin/commit.c:1536 +#: builtin/commit.c:1539 #, c-format msgid "Aborting commit due to empty commit message.\n" msgstr "Đang bỏ qua lần chuyển giao (commit) bởi vì thông điệp của nó trống rỗng.\n" -#: builtin/commit.c:1551 +#: builtin/commit.c:1554 #: builtin/merge.c:936 #: builtin/merge.c:961 msgid "failed to write commit object" msgstr "gặp lỗi khi ghi đối tượng chuyển giao (commit)" -#: builtin/commit.c:1572 +#: builtin/commit.c:1575 msgid "cannot lock HEAD ref" msgstr "không thể khóa HEAD ref (tham chiếu)" -#: builtin/commit.c:1576 +#: builtin/commit.c:1579 msgid "cannot update HEAD ref" msgstr "không thể cập nhật HEAD ref (tham chiếu)" -#: builtin/commit.c:1587 +#: builtin/commit.c:1590 msgid "" "Repository has been updated, but unable to write\n" "new_index file. Check that disk is not full or quota is\n" @@ -2966,33 +3231,33 @@ msgstr "--[no-]exclude-standard không thể sử dụng cho nội dung lưu d msgid "both --cached and trees are given." msgstr "cả hai --cached và các cây phải được chỉ ra." -#: builtin/help.c:63 +#: builtin/help.c:65 #, c-format msgid "unrecognized help format '%s'" msgstr "không nhận ra định dạng trợ giúp '%s'" -#: builtin/help.c:91 +#: builtin/help.c:93 msgid "Failed to start emacsclient." msgstr "Lỗi khởi chạy emacsclient." -#: builtin/help.c:104 +#: builtin/help.c:106 msgid "Failed to parse emacsclient version." msgstr "Gặp lỗi khi phân tích phiên bản emacsclient." -#: builtin/help.c:112 +#: builtin/help.c:114 #, c-format msgid "emacsclient version '%d' too old (< 22)." msgstr "phiên bản của emacsclient '%d' quá cũ (< 22)." -#: builtin/help.c:130 -#: builtin/help.c:158 -#: builtin/help.c:167 -#: builtin/help.c:175 +#: builtin/help.c:132 +#: builtin/help.c:160 +#: builtin/help.c:169 +#: builtin/help.c:177 #, c-format msgid "failed to exec '%s': %s" msgstr "gặp lỗi khi thực thi '%s': %s" -#: builtin/help.c:215 +#: builtin/help.c:217 #, c-format msgid "" "'%s': path for unsupported man viewer.\n" @@ -3001,7 +3266,7 @@ msgstr "" "'%s': đường dẫn không hỗ trợ bộ trình chiếu man.\n" "Hãy cân nhắc đến việc sử dụng 'man.<tool>.cmd' để thay thế." -#: builtin/help.c:227 +#: builtin/help.c:229 #, c-format msgid "" "'%s': cmd for supported man viewer.\n" @@ -3010,35 +3275,30 @@ msgstr "" "'%s': cmd (lệnh) hỗ trợ bộ trình chiếu man.\n" "Hãy cân nhắc đến việc sử dụng 'man.<tool>.path' để thay thế." -#: builtin/help.c:291 +#: builtin/help.c:299 msgid "The most commonly used git commands are:" msgstr "Những lệnh git hay được sử dụng nhất là:" -#: builtin/help.c:359 +#: builtin/help.c:367 #, c-format msgid "'%s': unknown man viewer." msgstr "'%s': không rõ chương trình xem man." -#: builtin/help.c:376 +#: builtin/help.c:384 msgid "no man viewer handled the request" msgstr "không có trình xem trợ giúp dạng manpage tiếp hợp với yêu cầu" -#: builtin/help.c:384 +#: builtin/help.c:392 msgid "no info viewer handled the request" msgstr "không có trình xem trợ giúp dạng info tiếp hợp với yêu cầu" -#: builtin/help.c:395 -#, c-format -msgid "'%s': not a documentation directory." -msgstr "'%s': không phải là một thư mục tài liệu." - -#: builtin/help.c:436 -#: builtin/help.c:443 +#: builtin/help.c:447 +#: builtin/help.c:454 #, c-format msgid "usage: %s%s" msgstr "cách sử dụng: %s%s" -#: builtin/help.c:459 +#: builtin/help.c:470 #, c-format msgid "`git %s' is aliased to `%s'" msgstr "`git %s' được đặt bí danh thành `%s'" @@ -3112,184 +3372,184 @@ msgstr "khoảng bù cơ sở cho delta nằm ngoài phạm vi" msgid "unknown object type %d" msgstr "không hiểu kiểu đối tượng %d" -#: builtin/index-pack.c:531 +#: builtin/index-pack.c:530 msgid "cannot pread pack file" msgstr "không thể chạy hàm pread cho tập tin pack" -#: builtin/index-pack.c:533 +#: builtin/index-pack.c:532 #, c-format msgid "premature end of pack file, %lu byte missing" msgid_plural "premature end of pack file, %lu bytes missing" msgstr[0] "tập tin pack bị kết thúc sớm, %lu byte bị thiếu" msgstr[1] "tập tin pack bị kết thúc sớm, %lu byte bị thiếu" -#: builtin/index-pack.c:555 +#: builtin/index-pack.c:558 msgid "serious inflate inconsistency" msgstr "sự mâu thuẫn xả nén nghiêm trọng" -#: builtin/index-pack.c:646 -#: builtin/index-pack.c:652 -#: builtin/index-pack.c:675 -#: builtin/index-pack.c:709 -#: builtin/index-pack.c:718 +#: builtin/index-pack.c:649 +#: builtin/index-pack.c:655 +#: builtin/index-pack.c:678 +#: builtin/index-pack.c:712 +#: builtin/index-pack.c:721 #, c-format msgid "SHA1 COLLISION FOUND WITH %s !" msgstr "SỰ VA CHẠM SHA1 ĐÃ XẢY RA VỚI %s!" -#: builtin/index-pack.c:649 +#: builtin/index-pack.c:652 #: builtin/pack-objects.c:170 #: builtin/pack-objects.c:262 #, c-format msgid "unable to read %s" msgstr "không thể đọc %s" -#: builtin/index-pack.c:715 +#: builtin/index-pack.c:718 #, c-format msgid "cannot read existing object %s" msgstr "không thể đọc đối tượng đã tồn tại %s" -#: builtin/index-pack.c:729 +#: builtin/index-pack.c:732 #, c-format msgid "invalid blob object %s" msgstr "đối tượng blob không hợp lệ %s" -#: builtin/index-pack.c:744 +#: builtin/index-pack.c:747 #, c-format msgid "invalid %s" msgstr "%s không hợp lệ" -#: builtin/index-pack.c:746 +#: builtin/index-pack.c:749 msgid "Error in object" msgstr "Lỗi trong đối tượng" -#: builtin/index-pack.c:748 +#: builtin/index-pack.c:751 #, c-format msgid "Not all child objects of %s are reachable" msgstr "Không phải tất cả các đối tượng con của %s là có thể với tới được" -#: builtin/index-pack.c:818 -#: builtin/index-pack.c:844 +#: builtin/index-pack.c:821 +#: builtin/index-pack.c:847 msgid "failed to apply delta" msgstr "gặp lỗi khi áp dụng delta" -#: builtin/index-pack.c:983 +#: builtin/index-pack.c:986 msgid "Receiving objects" msgstr "Đang nhận về các đối tượng" -#: builtin/index-pack.c:983 +#: builtin/index-pack.c:986 msgid "Indexing objects" msgstr "Các đối tượng bảng mục lục" -#: builtin/index-pack.c:1009 +#: builtin/index-pack.c:1012 msgid "pack is corrupted (SHA1 mismatch)" msgstr "pack bị sai hỏng (SHA1 không khớp)" -#: builtin/index-pack.c:1014 +#: builtin/index-pack.c:1017 msgid "cannot fstat packfile" msgstr "không thể fstat packfile" -#: builtin/index-pack.c:1017 +#: builtin/index-pack.c:1020 msgid "pack has junk at the end" msgstr "pack có phần thừa ở cuối" -#: builtin/index-pack.c:1028 +#: builtin/index-pack.c:1031 msgid "confusion beyond insanity in parse_pack_objects()" msgstr "lộn xộn hơn cả điên rồ khi chạy hàm parse_pack_objects()" -#: builtin/index-pack.c:1051 +#: builtin/index-pack.c:1054 msgid "Resolving deltas" msgstr "Đang phân giải các delta" -#: builtin/index-pack.c:1102 +#: builtin/index-pack.c:1105 msgid "confusion beyond insanity" msgstr "lộn xộn hơn cả điên rồ" -#: builtin/index-pack.c:1121 +#: builtin/index-pack.c:1124 #, c-format msgid "pack has %d unresolved delta" msgid_plural "pack has %d unresolved deltas" msgstr[0] "pack có %d delta chưa được giải quyết" msgstr[1] "pack có %d delta chưa được giải quyết" -#: builtin/index-pack.c:1146 +#: builtin/index-pack.c:1149 #, c-format msgid "unable to deflate appended object (%d)" msgstr "không thể xả đối tượng nối thêm (%d)" -#: builtin/index-pack.c:1225 +#: builtin/index-pack.c:1228 #, c-format msgid "local object %s is corrupt" msgstr "đối tượng nội bộ %s bị hỏng" -#: builtin/index-pack.c:1249 +#: builtin/index-pack.c:1252 msgid "error while closing pack file" msgstr "gặp lỗi trong khi đóng tập tin pack" -#: builtin/index-pack.c:1262 +#: builtin/index-pack.c:1265 #, c-format msgid "cannot write keep file '%s'" msgstr "không thể ghi tập tin giữ lại '%s'" -#: builtin/index-pack.c:1270 +#: builtin/index-pack.c:1273 #, c-format msgid "cannot close written keep file '%s'" msgstr "không thể đóng tập tin giữ lại đã được ghi '%s'" -#: builtin/index-pack.c:1283 +#: builtin/index-pack.c:1286 msgid "cannot store pack file" msgstr "không thể lưu tập tin pack" -#: builtin/index-pack.c:1294 +#: builtin/index-pack.c:1297 msgid "cannot store index file" msgstr "không thể lưu trữ tập tin ghi mục lục" -#: builtin/index-pack.c:1395 +#: builtin/index-pack.c:1398 #, c-format msgid "Cannot open existing pack file '%s'" msgstr "Không thể mở tập tin pack đã sẵn có '%s' " -#: builtin/index-pack.c:1397 +#: builtin/index-pack.c:1400 #, c-format msgid "Cannot open existing pack idx file for '%s'" msgstr "Không thể mở tập tin 'pack idx' cho '%s'" -#: builtin/index-pack.c:1444 +#: builtin/index-pack.c:1447 #, c-format msgid "non delta: %d object" msgid_plural "non delta: %d objects" msgstr[0] "không delta: %d đối tượng" msgstr[1] "không delta: %d đối tượng" -#: builtin/index-pack.c:1451 +#: builtin/index-pack.c:1454 #, c-format msgid "chain length = %d: %lu object" msgid_plural "chain length = %d: %lu objects" msgstr[0] "chiều dài xích = %d: %lu đối tượng" msgstr[1] "chiều dài xích = %d: %lu đối tượng" -#: builtin/index-pack.c:1478 +#: builtin/index-pack.c:1481 msgid "Cannot come back to cwd" msgstr "Không thể quay lại cwd" -#: builtin/index-pack.c:1522 #: builtin/index-pack.c:1525 -#: builtin/index-pack.c:1537 -#: builtin/index-pack.c:1541 +#: builtin/index-pack.c:1528 +#: builtin/index-pack.c:1540 +#: builtin/index-pack.c:1544 #, c-format msgid "bad %s" msgstr "%s sai" -#: builtin/index-pack.c:1555 +#: builtin/index-pack.c:1558 msgid "--fix-thin cannot be used without --stdin" msgstr "--fix-thin không thể được dùng mà không có --stdin" -#: builtin/index-pack.c:1559 -#: builtin/index-pack.c:1569 +#: builtin/index-pack.c:1562 +#: builtin/index-pack.c:1572 #, c-format msgid "packfile name '%s' does not end with '.pack'" msgstr "tên tập tin packfile '%s' không được kết thúc bằng đuôi '.pack'" -#: builtin/index-pack.c:1578 +#: builtin/index-pack.c:1581 msgid "--verify with no packfile name given" msgstr "dùng tùy chọn --verify mà không đưa ra tên packfile" @@ -3363,23 +3623,23 @@ msgstr "không sao chép các mẫu của phiên bản sai định dạng %d t msgid "insane git directory %s" msgstr "thư mục git điên rồ %s" -#: builtin/init-db.c:322 -#: builtin/init-db.c:325 +#: builtin/init-db.c:323 +#: builtin/init-db.c:326 #, c-format msgid "%s already exists" msgstr "%s đã tồn tại rồi" -#: builtin/init-db.c:354 +#: builtin/init-db.c:355 #, c-format msgid "unable to handle file type %d" msgstr "không thể handle tệp tin kiểu %d" -#: builtin/init-db.c:357 +#: builtin/init-db.c:358 #, c-format msgid "unable to move %s to %s" msgstr "không di chuyển được %s vào %s" -#: builtin/init-db.c:362 +#: builtin/init-db.c:363 #, c-format msgid "Could not create git link %s" msgstr "Không thể tạo liên kết git '%s'" @@ -3389,48 +3649,48 @@ msgstr "Không thể tạo liên kết git '%s'" #. * existing" or "Initialized empty", the second " shared" or #. * "", and the last '%s%s' is the verbatim directory name. #. -#: builtin/init-db.c:419 +#: builtin/init-db.c:420 #, c-format msgid "%s%s Git repository in %s%s\n" msgstr "%s%s kho Git trong %s%s\n" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Reinitialized existing" msgstr "Khởi tạo lại đã sẵn có rồi" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Initialized empty" msgstr "Khởi tạo trống rỗng" -#: builtin/init-db.c:421 +#: builtin/init-db.c:422 msgid " shared" msgstr " đã chia sẻ" -#: builtin/init-db.c:440 +#: builtin/init-db.c:441 msgid "cannot tell cwd" msgstr "không nói chuyện được với lệnh cwd" -#: builtin/init-db.c:521 -#: builtin/init-db.c:528 +#: builtin/init-db.c:522 +#: builtin/init-db.c:529 #, c-format msgid "cannot mkdir %s" msgstr "không thể mkdir (tạo thư mục): %s" -#: builtin/init-db.c:532 +#: builtin/init-db.c:533 #, c-format msgid "cannot chdir to %s" msgstr "không thể chdir (chuyển đổi thư mục) sang %s" -#: builtin/init-db.c:554 +#: builtin/init-db.c:555 #, c-format msgid "%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-dir=<directory>)" msgstr "%s (hoặc --work-tree=<thư-mục>) không cho phép không chỉ định %s (hoặc --git-dir=<thư-mục>)" -#: builtin/init-db.c:578 +#: builtin/init-db.c:579 msgid "Cannot access current working directory" msgstr "Không thể truy cập thư mục làm việc hiện hành" -#: builtin/init-db.c:585 +#: builtin/init-db.c:586 #, c-format msgid "Cannot access work tree '%s'" msgstr "không thể truy cập cây (tree) làm việc '%s'" @@ -3440,97 +3700,97 @@ msgstr "không thể truy cập cây (tree) làm việc '%s'" msgid "Final output: %d %s\n" msgstr "Kết xuất cuối cùng: %d %s\n" -#: builtin/log.c:402 -#: builtin/log.c:490 +#: builtin/log.c:403 +#: builtin/log.c:494 #, c-format msgid "Could not read object %s" msgstr "Không thể đọc đối tượng %s" -#: builtin/log.c:514 +#: builtin/log.c:518 #, c-format msgid "Unknown type: %d" msgstr "Không nhận ra kiểu: %d" -#: builtin/log.c:603 +#: builtin/log.c:608 msgid "format.headers without value" msgstr "format.headers không có giá trị cụ thể" -#: builtin/log.c:677 +#: builtin/log.c:682 msgid "name of output directory is too long" msgstr "tên của thư mục kết xuất quá dài" -#: builtin/log.c:688 +#: builtin/log.c:693 #, c-format msgid "Cannot open patch file %s" msgstr "Không thể mở tập tin miếng vá: %s" -#: builtin/log.c:702 +#: builtin/log.c:707 msgid "Need exactly one range." msgstr "Cần chính xác một vùng." -#: builtin/log.c:710 +#: builtin/log.c:715 msgid "Not a range." msgstr "Không phải là một vùng." -#: builtin/log.c:787 +#: builtin/log.c:792 msgid "Cover letter needs email format" msgstr "'Cover letter' cần cho định dạng thư" -#: builtin/log.c:860 +#: builtin/log.c:865 #, c-format msgid "insane in-reply-to: %s" msgstr "in-reply-to điên rồ: %s" -#: builtin/log.c:933 +#: builtin/log.c:938 msgid "Two output directories?" msgstr "Hai thư mục kết xuất?" -#: builtin/log.c:1154 +#: builtin/log.c:1160 #, c-format msgid "bogus committer info %s" msgstr "thông tin người chuyển giao không có thực %s" -#: builtin/log.c:1199 +#: builtin/log.c:1205 msgid "-n and -k are mutually exclusive." msgstr "-n và -k loại từ lẫn nhau." -#: builtin/log.c:1201 +#: builtin/log.c:1207 msgid "--subject-prefix and -k are mutually exclusive." msgstr "--subject-prefix và -k xung khắc nhau." -#: builtin/log.c:1209 +#: builtin/log.c:1215 msgid "--name-only does not make sense" msgstr "--name-only không hợp lý" -#: builtin/log.c:1211 +#: builtin/log.c:1217 msgid "--name-status does not make sense" msgstr "--name-status không hợp lý" -#: builtin/log.c:1213 +#: builtin/log.c:1219 msgid "--check does not make sense" msgstr "--check không hợp lý" -#: builtin/log.c:1236 +#: builtin/log.c:1242 msgid "standard output, or directory, which one?" msgstr "đầu ra chuẩn, hay thư mục, chọn cái nào?" -#: builtin/log.c:1238 +#: builtin/log.c:1244 #, c-format msgid "Could not create directory '%s'" msgstr "Không thể tạo thư mục '%s'" -#: builtin/log.c:1391 +#: builtin/log.c:1397 msgid "Failed to create output files" msgstr "Gặp lỗi khi tạo các tập tin kết xuất" -#: builtin/log.c:1495 +#: builtin/log.c:1501 #, c-format msgid "Could not find a tracked remote branch, please specify <upstream> manually.\n" msgstr "Không tìm thấy nhánh mạng bị theo vết, hãy chỉ định <dòng-ngược> một cách thủ công.\n" -#: builtin/log.c:1511 -#: builtin/log.c:1513 -#: builtin/log.c:1525 +#: builtin/log.c:1517 +#: builtin/log.c:1519 +#: builtin/log.c:1531 #, c-format msgid "Unknown commit %s" msgstr "Không hiểu lần chuyển giao (commit) %s" @@ -3612,10 +3872,6 @@ msgstr "lệnh git write-tree gặp lỗi khi ghi một cây" msgid "failed to read the cache" msgstr "gặp lỗi khi đọc bộ nhớ tạm" -#: builtin/merge.c:697 -msgid "Unable to write index." -msgstr "Không thể ghi bảng mục lục" - #: builtin/merge.c:710 msgid "Not handling anything other than two heads merge." msgstr "Không cầm nắm gì ngoài hai head hòa trộn" @@ -4666,30 +4922,30 @@ msgstr "Những thay đổi bị bỏ trạng thái (stage) sau khi reset:" msgid "Cannot do a %s reset in the middle of a merge." msgstr "Không thể thực hiện một %s reset ở giữa của quá trình hòa trộn." -#: builtin/reset.c:297 +#: builtin/reset.c:303 #, c-format msgid "Could not parse object '%s'." msgstr "không thể phân tích đối tượng '%s'." -#: builtin/reset.c:302 +#: builtin/reset.c:308 msgid "--patch is incompatible with --{hard,mixed,soft}" msgstr "--patch xung khắc với --{hard,mixed,soft}" -#: builtin/reset.c:311 +#: builtin/reset.c:317 msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead." msgstr "--mixed với các đường dẫn không còn dùng nữa; hãy thay thế bằng lệnh 'git reset -- <đường_dẫn>'." -#: builtin/reset.c:313 +#: builtin/reset.c:319 #, c-format msgid "Cannot do %s reset with paths." msgstr "Không thể thực hiện lệnh %s reset với các đường dẫn." -#: builtin/reset.c:325 +#: builtin/reset.c:331 #, c-format msgid "%s reset is not allowed in a bare repository" msgstr "%s reset không được phép trên kho bare (trên máy chủ)" -#: builtin/reset.c:341 +#: builtin/reset.c:347 #, c-format msgid "Could not reset index file to revision '%s'." msgstr "Không thể đặt lại (reset) bảng mục lục thành điểm xét lại '%s'." @@ -4941,7 +5197,7 @@ msgstr "Liệt kê, tạo hay là xóa các nhánh" #: common-cmds.h:11 msgid "Checkout a branch or paths to the working tree" -msgstr "Checkout một nhánh hay các đường dẫn tời cây làm việc" +msgstr "Checkout một nhánh hay các đường dẫn tới cây làm việc" #: common-cmds.h:12 msgid "Clone a repository into a new directory" @@ -5026,9 +5282,9 @@ msgstr "" #: git-am.sh:105 #, sh-format msgid "" -"When you have resolved this problem run \"$cmdline --resolved\".\n" -"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n" -"To restore the original branch and stop patching run \"$cmdline --abort\"." +"When you have resolved this problem, run \"$cmdline --resolved\".\n" +"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n" +"To restore the original branch and stop patching, run \"$cmdline --abort\"." msgstr "" "Khi bạn cần giải quyết vấn đề này hãy chạy lệnh \"$cmdline --resolved\".\n" "Nếu bạn có ý định bỏ qua miếng vá, thay vào đó bạn chạy \"$cmdline --skip\".\n" @@ -5042,6 +5298,10 @@ msgstr "Đang trở lại để hòa trộn kiểu 'three-way'." msgid "Repository lacks necessary blobs to fall back on 3-way merge." msgstr "Kho thiếu đối tượng blob cần thiết để trở về trên '3-way merge'." +#: git-am.sh:139 +msgid "Using index info to reconstruct a base tree..." +msgstr "Sử dụng thông tin trong bảng mục lục để cấu trúc lại một cây (tree) cơ sở..." + #: git-am.sh:154 msgid "" "Did you hand edit your patch?\n" @@ -5054,42 +5314,50 @@ msgstr "" msgid "Falling back to patching base and 3-way merge..." msgstr "Đang trở lại để vá cơ sở và '3-way merge'..." -#: git-am.sh:275 +#: git-am.sh:179 +msgid "Failed to merge in the changes." +msgstr "Gặp lỗi khi trộn vào các thay đổi." + +#: git-am.sh:274 msgid "Only one StGIT patch series can be applied at once" msgstr "Chỉ có một sê-ri miếng vá StGIT được áp dụng một lúc" -#: git-am.sh:362 +#: git-am.sh:361 #, sh-format msgid "Patch format $patch_format is not supported." msgstr "Định dạng miếng vá $patch_format không được hỗ trợ." -#: git-am.sh:364 +#: git-am.sh:363 msgid "Patch format detection failed." msgstr "Dò tìm định dạng miếng vá gặp lỗi." -#: git-am.sh:418 -msgid "-d option is no longer supported. Do not use." -msgstr "Tùy chọn -d không còn được hỗ trợ nữa. Xin đừng sử dụng." +#: git-am.sh:389 +msgid "" +"The -b/--binary option has been a no-op for long time, and\n" +"it will be removed. Please do not use it anymore." +msgstr "" +"Tùy chọn -b/--binary đã không dùng từ lâu rồi, và\n" +"nó sẽ được bỏ đi. Xin đừng sử dụng nó thêm nữa." -#: git-am.sh:481 +#: git-am.sh:477 #, sh-format msgid "previous rebase directory $dotest still exists but mbox given." msgstr "thư mục rebase trước $dotest vẫn chưa sẵn sàng nhưng mbox được đưa ra." -#: git-am.sh:486 +#: git-am.sh:482 msgid "Please make up your mind. --skip or --abort?" msgstr "Xin hãy rõ ràng. --skip hay --abort?" -#: git-am.sh:513 +#: git-am.sh:509 msgid "Resolve operation not in progress, we are not resuming." msgstr "Thao tác phân giải không đang được tiến hành, chúng ta không phục hồi lại." -#: git-am.sh:579 +#: git-am.sh:575 #, sh-format msgid "Dirty index: cannot apply patches (dirty: $files)" msgstr "Bảng mục lục sai: không thể áp dụng các miếng vá (sai: $files)" -#: git-am.sh:671 +#: git-am.sh:679 #, sh-format msgid "" "Patch is empty. Was it split wrong?\n" @@ -5100,31 +5368,31 @@ msgstr "" "Nếu bạn thích bỏ qua miếng vá này, hãy chạy lệnh sau để thay thế \"$cmdline --skip\".\n" "Để phục hồi lại nhánh nguyên thủy và dừng vá lại hãy chạy lệnh \"$cmdline --abort\"." -#: git-am.sh:708 +#: git-am.sh:706 msgid "Patch does not have a valid e-mail address." msgstr "Miếng vá không có địa chỉ e-mail hợp lệ." -#: git-am.sh:755 +#: git-am.sh:753 msgid "cannot be interactive without stdin connected to a terminal." msgstr "không thể được tương tác mà không có stdin kết nối với một thiết bị cuối" -#: git-am.sh:759 +#: git-am.sh:757 msgid "Commit Body is:" msgstr "Thân của lần chuyển giao (commit) là:" #. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a] #. in your translation. The program will only accept English #. input at this point. -#: git-am.sh:766 +#: git-am.sh:764 msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " msgstr "Áp dụng? đồng ý [y]/không [n]/chỉnh sửa [e]/hiển thị miếng [v]á/đồng ý tất cả [a]" -#: git-am.sh:802 +#: git-am.sh:800 #, sh-format msgid "Applying: $FIRSTLINE" msgstr "Đang áp dụng (miếng vá): $FIRSTLINE" -#: git-am.sh:823 +#: git-am.sh:821 msgid "" "No changes - did you forget to use 'git add'?\n" "If there is nothing left to stage, chances are that something else\n" @@ -5134,7 +5402,7 @@ msgstr "" "Nếu ở đây không có gì còn lại stage, tình cờ là có một số thứ khác\n" "đã sẵn được đưa vào với cùng nội dung thay đổi; bạn có lẽ muốn bỏ qua miếng vá này." -#: git-am.sh:831 +#: git-am.sh:829 msgid "" "You still have unmerged paths in your index\n" "did you forget to use 'git add'?" @@ -5142,16 +5410,16 @@ msgstr "" "Bạn vẫn có những đường dẫn chưa được hòa trộn trong bảng mục lục của mình\n" "bạn đã quên sử dụng lệnh 'git add' à?" -#: git-am.sh:847 +#: git-am.sh:845 msgid "No changes -- Patch already applied." msgstr "Không thay đổi gì cả -- Miếng vá đã được áp dụng rồi." -#: git-am.sh:857 +#: git-am.sh:855 #, sh-format msgid "Patch failed at $msgnum $FIRSTLINE" msgstr "Vá gặp lỗi tại $msgnum $FIRSTLINE" -#: git-am.sh:873 +#: git-am.sh:876 msgid "applying to an empty history" msgstr "áp dụng vào một lịch sử trống rỗng" @@ -5351,6 +5619,127 @@ msgstr "Không thể hòa trộn nhiều nhánh và trong một head trống r msgid "Cannot rebase onto multiple branches" msgstr "Không thể thực hiện lệnh rebase (cơ cấu lại) trên nhiều nhánh" +#: git-rebase.sh:52 +msgid "" +"When you have resolved this problem, run \"git rebase --continue\".\n" +"If you prefer to skip this patch, run \"git rebase --skip\" instead.\n" +"To check out the original branch and stop rebasing, run \"git rebase --abort\"." +msgstr "" +"Khi bạn cần giải quyết vấn đề này hãy chạy lệnh \"git rebase --continue\".\n" +"Nếu bạn có ý định bỏ qua miếng vá, thay vào đó bạn chạy \"git rebase --skip\".\n" +"Để phục hồi lại thành nhánh nguyên thủy và dừng việc vá lại thì chạy \"git rebase --abort\"." + +#: git-rebase.sh:159 +msgid "The pre-rebase hook refused to rebase." +msgstr "hook (chương trình móc vào git) pre-rebase từ chối rebase." + +#: git-rebase.sh:164 +msgid "It looks like git-am is in progress. Cannot rebase." +msgstr "Hình như đang trong quá trình thực hiện lệnh git-am. Không thể chạy lệnh rebase." + +#: git-rebase.sh:295 +msgid "The --exec option must be used with the --interactive option" +msgstr "Tùy chọn --exec phải được sử dụng cùng với tùy chọn --interactive" + +#: git-rebase.sh:300 +msgid "No rebase in progress?" +msgstr "Không phải đang rebase?" + +#: git-rebase.sh:313 +msgid "Cannot read HEAD" +msgstr "Không thể đọc HEAD" + +#: git-rebase.sh:316 +msgid "" +"You must edit all merge conflicts and then\n" +"mark them as resolved using git add" +msgstr "" +"Bạn phải sửa tất cả các lần hòa trộn xung đột và sau\n" +"đó đánh dấu chúng là cần xử lý sử dụng lệnh git add" + +#: git-rebase.sh:334 +#, sh-format +msgid "Could not move back to $head_name" +msgstr "Không thể quay trở lại $head_name" + +#: git-rebase.sh:350 +#, sh-format +msgid "" +"It seems that there is already a $state_dir_base directory, and\n" +"I wonder if you are in the middle of another rebase. If that is the\n" +"case, please try\n" +"\t$cmd_live_rebase\n" +"If that is not the case, please\n" +"\t$cmd_clear_stale_rebase\n" +"and run me again. I am stopping in case you still have something\n" +"valuable there." +msgstr "" +"Hình như là ở đây sẵn có một thư mục $state_dir_base directory, và\n" +"Tôi tự hỏi có phải bạn đang ở giữa một lệnh rebase khác. Nếu đúng là\n" +"như vậy, xin hãy thử\n" +"\t$cmd_live_rebase\n" +"Nếu không phải thế, hãy thử\n" +"\t$cmd_clear_stale_rebase\n" +"và chạy TÔI lần nữa. TÔI dừng lại trong trường hợp bạn vẫn\n" +"có một số thứ quý giá ở đây.\n" +"\n" +"TÔI: là lệnh bạn vừa gọi!" + +#: git-rebase.sh:395 +#, sh-format +msgid "invalid upstream $upstream_name" +msgstr "dòng ngược không hợp lệ $upstream_name" + +#: git-rebase.sh:419 +#, sh-format +msgid "$onto_name: there are more than one merge bases" +msgstr "$onto_name: ở đây có nhiều hơn một " + +#: git-rebase.sh:422 +#: git-rebase.sh:426 +#, sh-format +msgid "$onto_name: there is no merge base" +msgstr "$onto_name: ở đây không có gì để hòa trộn" + +#: git-rebase.sh:431 +#, sh-format +msgid "Does not point to a valid commit: $onto_name" +msgstr "Không chỉ đến một lần chuyển giao (commit) không hợp lệ: $onto_name" + +#: git-rebase.sh:454 +#, sh-format +msgid "fatal: no such branch: $branch_name" +msgstr "nghiêm trọng: không có nhánh như thế: $branch_name" + +#: git-rebase.sh:474 +msgid "Please commit or stash them." +msgstr "Xin hãy commit hoặc stash chúng." + +#: git-rebase.sh:492 +#, sh-format +msgid "Current branch $branch_name is up to date." +msgstr "Nhánh hiện tại $branch_name đã được cập nhật rồi." + +#: git-rebase.sh:495 +#, sh-format +msgid "Current branch $branch_name is up to date, rebase forced." +msgstr "Nhánh hiện tại $branch_name đã được cập nhật rồi, lệnh rebase ép buộc." + +#: git-rebase.sh:506 +#, sh-format +msgid "Changes from $mb to $onto:" +msgstr "Thay đổi từ $mb thành $onto:" + +#. Detach HEAD and reset the tree +#: git-rebase.sh:515 +msgid "First, rewinding head to replay your work on top of it..." +msgstr "Trước tiên, di chuyển head để xem lại các công việc trên đỉnh của nó..." + +#: git-rebase.sh:523 +#, sh-format +msgid "Fast-forwarded $branch_name to $onto_name." +msgstr "Fast-forward $branch_name thành $onto_name." + #: git-stash.sh:51 msgid "git stash clear with parameters is unimplemented" msgstr "git stash clear với các tham số là chưa được thực hiện (không nhận đối số)" @@ -5491,27 +5880,27 @@ msgstr "không thể tháo bỏ một thành phần ra khỏi url '$remoteurl'" msgid "No submodule mapping found in .gitmodules for path '$sm_path'" msgstr "Không tìm thấy ánh xạ (mapping) mô-đun-con trong .gitmodules cho đường dẫn '$sm_path'" -#: git-submodule.sh:186 +#: git-submodule.sh:189 #, sh-format msgid "Clone of '$url' into submodule path '$sm_path' failed" msgstr "Nhân bản '$url' vào đường dẫn mô-đun-con '$sm_path' gặp lỗi" -#: git-submodule.sh:196 +#: git-submodule.sh:201 #, sh-format msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa" msgstr "Gitdir '$a' là bộ phận của đường dẫn mô-đun-con '$b' hoặc \"vice versa\"" -#: git-submodule.sh:285 +#: git-submodule.sh:290 #, sh-format msgid "repo URL: '$repo' must be absolute or begin with ./|../" msgstr "repo URL: '$repo' phải là đường dẫn tuyệt đối hoặc là bắt đầu bằng ./|../" -#: git-submodule.sh:302 +#: git-submodule.sh:307 #, sh-format msgid "'$sm_path' already exists in the index" msgstr "'$sm_path' thực sự đã tồn tại ở bảng mục lục rồi" -#: git-submodule.sh:306 +#: git-submodule.sh:311 #, sh-format msgid "" "The following path is ignored by one of your .gitignore files:\n" @@ -5522,62 +5911,62 @@ msgstr "" "$sm_path\n" "Sử dụng -f nếu bạn thực sự muốn thêm nó vào." -#: git-submodule.sh:317 +#: git-submodule.sh:322 #, sh-format msgid "Adding existing repo at '$sm_path' to the index" msgstr "Đang thêm repo có sẵn tại '$sm_path' vào bảng mục lục" -#: git-submodule.sh:319 +#: git-submodule.sh:324 #, sh-format msgid "'$sm_path' already exists and is not a valid git repo" msgstr "'$sm_path' đã tồn tại từ trước và không phải là một kho git hợp lệ" -#: git-submodule.sh:333 +#: git-submodule.sh:338 #, sh-format msgid "Unable to checkout submodule '$sm_path'" msgstr "Không thể checkout mô-đun con '$sm_path'" -#: git-submodule.sh:338 +#: git-submodule.sh:343 #, sh-format msgid "Failed to add submodule '$sm_path'" msgstr "Gặp lỗi khi thêm mô-đun con '$sm_path'" -#: git-submodule.sh:343 +#: git-submodule.sh:348 #, sh-format msgid "Failed to register submodule '$sm_path'" msgstr "Gặp lỗi khi đăng ký với hệ thống mô-đun con '$sm_path'" -#: git-submodule.sh:385 +#: git-submodule.sh:390 #, sh-format msgid "Entering '$prefix$sm_path'" msgstr "Đang nhập '$prefix$sm_path'" -#: git-submodule.sh:399 +#: git-submodule.sh:404 #, sh-format msgid "Stopping at '$sm_path'; script returned non-zero status." msgstr "Dừng lại tại '$sm_path'; script trả về trạng thái khác không." -#: git-submodule.sh:442 +#: git-submodule.sh:447 #, sh-format msgid "No url found for submodule path '$sm_path' in .gitmodules" msgstr "Không tìm thấy url cho đường dẫn mô-đun-con '$sm_path' trong .gitmodules" -#: git-submodule.sh:451 +#: git-submodule.sh:456 #, sh-format msgid "Failed to register url for submodule path '$sm_path'" msgstr "Gặp lỗi khi đăng ký url cho đường dẫn mô-đun-con '$sm_path'" -#: git-submodule.sh:453 +#: git-submodule.sh:458 #, sh-format msgid "Submodule '$name' ($url) registered for path '$sm_path'" msgstr "Mô-đun-con '$name' ($url) được đăng ký cho đường dẫn '$sm_path'" -#: git-submodule.sh:461 +#: git-submodule.sh:466 #, sh-format msgid "Failed to register update mode for submodule path '$sm_path'" msgstr "Gặp lỗi khi đăng ký chế độ cập nhật cho đường dẫn mô-đun-con '$sm_path'" -#: git-submodule.sh:560 +#: git-submodule.sh:565 #, sh-format msgid "" "Submodule path '$sm_path' not initialized\n" @@ -5586,98 +5975,103 @@ msgstr "" "Đường dẫn mô-đun-con '$sm_path' chưa được khởi tạo\n" "Có lẽ bạn muốn sử dụng lệnh 'update --init'?" -#: git-submodule.sh:573 +#: git-submodule.sh:578 #, sh-format msgid "Unable to find current revision in submodule path '$sm_path'" msgstr "Không tìm thấy điểm xét lại hiện hành trong đường dẫn mô-đun-con '$sm_path'" -#: git-submodule.sh:592 +#: git-submodule.sh:597 #, sh-format msgid "Unable to fetch in submodule path '$sm_path'" msgstr "Không thể lấy về (fetch) trong đường dẫn mô-đun-con '$sm_path'" -#: git-submodule.sh:606 +#: git-submodule.sh:611 #, sh-format msgid "Unable to rebase '$sha1' in submodule path '$sm_path'" msgstr "Không thể rebase '$sha1' trong đường dẫn mô-đun-con '$sm_path'" -#: git-submodule.sh:607 +#: git-submodule.sh:612 #, sh-format msgid "Submodule path '$sm_path': rebased into '$sha1'" msgstr "Đường dẫn mô-đun-con '$sm_path': được rebase vào trong '$sha1'" -#: git-submodule.sh:612 +#: git-submodule.sh:617 #, sh-format msgid "Unable to merge '$sha1' in submodule path '$sm_path'" msgstr "Không thể hòa trộn (merge) '$sha1' trong đường dẫn mô-đun-con '$sm_path'" -#: git-submodule.sh:613 +#: git-submodule.sh:618 #, sh-format msgid "Submodule path '$sm_path': merged in '$sha1'" msgstr "Đường dẫn mô-đun-con '$sm_path': được hòa trộn vào '$sha1'" -#: git-submodule.sh:618 +#: git-submodule.sh:623 #, sh-format msgid "Unable to checkout '$sha1' in submodule path '$sm_path'" msgstr "Không thể checkout '$sha1' trong đường dẫn mô-đun-con '$sm_path'" -#: git-submodule.sh:619 +#: git-submodule.sh:624 #, sh-format msgid "Submodule path '$sm_path': checked out '$sha1'" msgstr "Đường dẫn mô-đun-con '$sm_path': được checkout '$sha1'" -#: git-submodule.sh:641 -#: git-submodule.sh:964 +#: git-submodule.sh:646 +#: git-submodule.sh:969 #, sh-format msgid "Failed to recurse into submodule path '$sm_path'" msgstr "Gặp lỗi khi đệ quy vào trong đường dẫn mô-đun-con '$sm_path'" -#: git-submodule.sh:749 -msgid "--cached cannot be used with --files" -msgstr "--cached không thể được sử dụng cùng với --files" +#: git-submodule.sh:754 +msgid "The --cached option cannot be used with the --files option" +msgstr "Tùy chọn --cached không thể dùng cùng với tùy chọn --files" #. unexpected type -#: git-submodule.sh:789 +#: git-submodule.sh:794 #, sh-format msgid "unexpected mode $mod_dst" msgstr "chế độ không như mong chờ $mod_dst" -#: git-submodule.sh:807 +#: git-submodule.sh:812 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_src" msgstr " Cảnh báo: $name không chứa lần chuyển giao (commit) $sha1_src" -#: git-submodule.sh:810 +#: git-submodule.sh:815 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_dst" msgstr " Cảnh báo: $name không chứa lần chuyển giao (commit) $sha1_dst" -#: git-submodule.sh:813 +#: git-submodule.sh:818 #, sh-format msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst" msgstr " Cảnh báo: $name không chứa những lần chuyển giao (commit) $sha1_src và $sha1_dst" -#: git-submodule.sh:838 +#: git-submodule.sh:843 msgid "blob" msgstr "blob" -#: git-submodule.sh:839 -msgid "submodule" -msgstr "mô-đun con" - -#: git-submodule.sh:876 +#: git-submodule.sh:881 msgid "# Submodules changed but not updated:" msgstr "# Những mô-đun-con đã bị thay đổi nhưng chưa được cập nhật:" -#: git-submodule.sh:878 +#: git-submodule.sh:883 msgid "# Submodule changes to be committed:" msgstr "# Những thay đổi mô-đun-con được chuyển giao (commit):" -#: git-submodule.sh:1022 +#: git-submodule.sh:1027 #, sh-format msgid "Synchronizing submodule url for '$name'" msgstr "Đang đồng bộ hóa url mô-đun-con cho '$name'" +#~ msgid "-d option is no longer supported. Do not use." +#~ msgstr "Tùy chọn -d không còn được hỗ trợ nữa. Xin đừng sử dụng." + +#~ msgid "%s: has been deleted/renamed" +#~ msgstr "%s: đã được xóa/thay-tên" + +#~ msgid "'%s': not a documentation directory." +#~ msgstr "'%s': không phải là một thư mục tài liệu." + #~ msgid "--" #~ msgstr "--" diff --git a/po/zh_CN.po b/po/zh_CN.po index b3e1a54c8e..bc04236e47 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -12,8 +12,8 @@ msgid "" msgstr "" "Project-Id-Version: Git\n" "Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" -"POT-Creation-Date: 2012-07-03 10:23+0800\n" -"PO-Revision-Date: 2012-07-04 22:38+0800\n" +"POT-Creation-Date: 2012-08-06 23:47+0800\n" +"PO-Revision-Date: 2012-08-07 01:07+0800\n" "Last-Translator: Jiang Xin <worldhello.net@gmail.com>\n" "Language-Team: GitHub <https://github.com/gotgit/git/>\n" "Language: zh_CN\n" @@ -52,7 +52,7 @@ msgstr "'%s' 不像是一个 v2 版本的包文件" msgid "unrecognized header: %s%s (%d)" msgstr "未能识别的包头:%s%s (%d)" -#: bundle.c:89 builtin/commit.c:696 +#: bundle.c:89 builtin/commit.c:699 #, c-format msgid "could not open '%s'" msgstr "不能打开 '%s'" @@ -62,7 +62,7 @@ msgid "Repository lacks these prerequisite commits:" msgstr "版本库缺少这些必备的提交:" #: bundle.c:164 sequencer.c:550 sequencer.c:982 builtin/log.c:290 -#: builtin/log.c:721 builtin/log.c:1310 builtin/log.c:1529 builtin/merge.c:347 +#: builtin/log.c:726 builtin/log.c:1316 builtin/log.c:1535 builtin/merge.c:347 #: builtin/shortlog.c:181 msgid "revision walk setup failed" msgstr "版本遍历设置失败" @@ -89,7 +89,7 @@ msgstr[1] "这个包需要 %d 个这些引用" msgid "rev-list died" msgstr "rev-list 终止" -#: bundle.c:300 builtin/log.c:1206 builtin/shortlog.c:284 +#: bundle.c:300 builtin/log.c:1212 builtin/shortlog.c:284 #, c-format msgid "unrecognized argument: %s" msgstr "未能识别的参数:%s" @@ -237,8 +237,8 @@ msgstr "" "%s" #: diff.c:1400 -msgid " 0 files changed\n" -msgstr " 0 个文件被修改\n" +msgid " 0 files changed" +msgstr " 0 个文件被修改" #: diff.c:1404 #, c-format @@ -261,7 +261,7 @@ msgid_plural ", %d deletions(-)" msgstr[0] ",删除 %d 行(-)" msgstr[1] ",删除 %d 行(-)" -#: diff.c:3478 +#: diff.c:3461 #, c-format msgid "" "Failed to parse --dirstat/-X option parameter:\n" @@ -297,16 +297,16 @@ msgstr "'%s':%s" msgid "'%s': short read %s" msgstr "'%s':读取不完整 %s" -#: help.c:208 +#: help.c:212 #, c-format msgid "available git commands in '%s'" msgstr "在 '%s' 下可用的 git 命令" -#: help.c:215 +#: help.c:219 msgid "git commands available from elsewhere on your $PATH" msgstr "在 $PATH 路径中的其他地方可用的 git 命令" -#: help.c:271 +#: help.c:275 #, c-format msgid "" "'%s' appears to be a git command, but we were not\n" @@ -315,11 +315,11 @@ msgstr "" "'%s' 像是一个 git 命令,但却无法运行。\n" "可能是 git-%s 受损?" -#: help.c:328 +#: help.c:332 msgid "Uh oh. Your system reports no Git commands at all." msgstr "唉呀,您的系统中未发现 Git 命令。" -#: help.c:350 +#: help.c:354 #, c-format msgid "" "WARNING: You called a Git command named '%s', which does not exist.\n" @@ -328,17 +328,17 @@ msgstr "" "警告:您运行一个不存在的 Git 命令 '%s'。继续执行假定您要要运行的\n" "是 '%s'" -#: help.c:355 +#: help.c:359 #, c-format msgid "in %0.1f seconds automatically..." msgstr "在 %0.1f 秒钟后自动运行..." -#: help.c:362 +#: help.c:366 #, c-format msgid "git: '%s' is not a git command. See 'git --help'." msgstr "git:'%s' 不是一个 git 命令。参见 'git --help'。" -#: help.c:366 +#: help.c:370 msgid "" "\n" "Did you mean this?" @@ -352,36 +352,298 @@ msgstr[1] "" "\n" "您指的是这些其中一个么?" -#: parse-options.c:493 +#: merge-recursive.c:190 +#, c-format +msgid "(bad commit)\n" +msgstr "(坏提交)\n" + +#: merge-recursive.c:206 +#, c-format +msgid "addinfo_cache failed for path '%s'" +msgstr "为路径 '%s' addinfo_cache 失败" + +#: merge-recursive.c:268 +msgid "error building trees" +msgstr "无法创建树" + +#: merge-recursive.c:497 +msgid "diff setup failed" +msgstr "diff 设置失败" + +#: merge-recursive.c:627 +msgid "merge-recursive: disk full?" +msgstr "merge-recursive:磁盘已满?" + +#: merge-recursive.c:690 +#, c-format +msgid "failed to create path '%s'%s" +msgstr "无法创建路径 '%s'%s" + +#: merge-recursive.c:701 +#, c-format +msgid "Removing %s to make room for subdirectory\n" +msgstr "删除 %s 以便为子目录留出空间\n" + +#. something else exists +#. .. but not some other error (who really cares what?) +#: merge-recursive.c:715 merge-recursive.c:736 +msgid ": perhaps a D/F conflict?" +msgstr ":可能是一个目录/文件冲突?" + +#: merge-recursive.c:726 +#, c-format +msgid "refusing to lose untracked file at '%s'" +msgstr "拒绝丢弃 '%s' 中的未跟踪文件" + +#: merge-recursive.c:766 +#, c-format +msgid "cannot read object %s '%s'" +msgstr "不能读取对象 %s '%s'" + +#: merge-recursive.c:768 +#, c-format +msgid "blob expected for %s '%s'" +msgstr "%s '%s' 应为二进制对象(blob)" + +#: merge-recursive.c:791 builtin/clone.c:302 +#, c-format +msgid "failed to open '%s'" +msgstr "无法打开 '%s'" + +#: merge-recursive.c:799 +#, c-format +msgid "failed to symlink '%s'" +msgstr "无法创建符号链接 '%s'" + +#: merge-recursive.c:802 +#, c-format +msgid "do not know what to do with %06o %s '%s'" +msgstr "不知道如何处理 %06o %s '%s'" + +#: merge-recursive.c:939 +msgid "Failed to execute internal merge" +msgstr "无法执行内部合并" + +#: merge-recursive.c:943 +#, c-format +msgid "Unable to add %s to database" +msgstr "不能添加 %s 至对象库" + +#: merge-recursive.c:959 +msgid "unsupported object type in the tree" +msgstr "在树中有不支持的对象类型" + +#: merge-recursive.c:1038 merge-recursive.c:1052 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree." +msgstr "" +"冲突(%1$s/删除):%2$s 在 %3$s 中被删除,在 %5$s 中被 %4$s。%7$s 在 %6$s 中" +"的版本被保留。" + +#: merge-recursive.c:1044 merge-recursive.c:1057 +#, c-format +msgid "" +"CONFLICT (%s/delete): %s deleted in %s and %s in %s. Version %s of %s left " +"in tree at %s." +msgstr "" +"冲突(%1$s/删除):%2$s 在 %3$s 中被删除,在 %5$s 中被 %4$s。%7$s 在 %6$s 中" +"的版本保留于 %8$s 中。" + +#: merge-recursive.c:1098 +msgid "rename" +msgstr "重命名" + +#: merge-recursive.c:1098 +msgid "renamed" +msgstr "重命名" + +#: merge-recursive.c:1154 +#, c-format +msgid "%s is a directory in %s adding as %s instead" +msgstr "%s 是 %s 中的一个目录而以 %s 为名被添加" + +#: merge-recursive.c:1176 +#, c-format +msgid "" +"CONFLICT (rename/rename): Rename \"%s\"->\"%s\" in branch \"%s\" rename \"%s" +"\"->\"%s\" in \"%s\"%s" +msgstr "" +"冲突(重命名/重命名):在分支 \"%3$s\" 中重命名 \"%1$s\"->\"%2$s\",在分支 " +"\"%6$s\" 中重命名 \"%4$s\"->\"%5$s\"%7$s" + +#: merge-recursive.c:1181 +msgid " (left unresolved)" +msgstr "(留下未解决)" + +#: merge-recursive.c:1235 +#, c-format +msgid "CONFLICT (rename/rename): Rename %s->%s in %s. Rename %s->%s in %s" +msgstr "" +"冲突(重命名/重命名):在 %3$s 中重命名 %1$s->%2$s,在 %6$s 中重命名 %4$s->" +"%5$s" + +#: merge-recursive.c:1265 +#, c-format +msgid "Renaming %s to %s and %s to %s instead" +msgstr "而是重命名 %s 至 %s 以及 %s 至 %s" + +#: merge-recursive.c:1464 +#, c-format +msgid "CONFLICT (rename/add): Rename %s->%s in %s. %s added in %s" +msgstr "冲突(重命名/添加):在 %3$s 中重命名 %1$s->%2$s。在 %5$s 中添加 %4$s" + +#: merge-recursive.c:1474 +#, c-format +msgid "Adding merged %s" +msgstr "添加合并后的 %s" + +#: merge-recursive.c:1479 merge-recursive.c:1677 +#, c-format +msgid "Adding as %s instead" +msgstr "而是以 %s 为名添加" + +#: merge-recursive.c:1530 +#, c-format +msgid "cannot read object %s" +msgstr "不能读取对象 %s" + +#: merge-recursive.c:1533 +#, c-format +msgid "object %s is not a blob" +msgstr "对象 %s 不是一个二进制对象(blob)" + +#: merge-recursive.c:1581 +msgid "modify" +msgstr "修改" + +#: merge-recursive.c:1581 +msgid "modified" +msgstr "修改" + +#: merge-recursive.c:1591 +msgid "content" +msgstr "内容" + +#: merge-recursive.c:1598 +msgid "add/add" +msgstr "添加/添加" + +#: merge-recursive.c:1632 +#, c-format +msgid "Skipped %s (merged same as existing)" +msgstr "略过 %s(已经做过相同合并)" + +#: merge-recursive.c:1646 +#, c-format +msgid "Auto-merging %s" +msgstr "自动合并 %s" + +#: merge-recursive.c:1650 git-submodule.sh:844 +msgid "submodule" +msgstr "子模组" + +#: merge-recursive.c:1651 +#, c-format +msgid "CONFLICT (%s): Merge conflict in %s" +msgstr "冲突(%s):合并冲突于 %s" + +#: merge-recursive.c:1741 +#, c-format +msgid "Removing %s" +msgstr "删除 %s" + +#: merge-recursive.c:1766 +msgid "file/directory" +msgstr "文件/目录" + +#: merge-recursive.c:1772 +msgid "directory/file" +msgstr "目录/文件" + +#: merge-recursive.c:1777 +#, c-format +msgid "CONFLICT (%s): There is a directory with name %s in %s. Adding %s as %s" +msgstr "冲突(%1$s):在 %3$s 中有一个名为 %2$s 的目录。以 %5$s 为名添加 %4$s" + +#: merge-recursive.c:1787 +#, c-format +msgid "Adding %s" +msgstr "添加 %s" + +#: merge-recursive.c:1804 +msgid "Fatal merge failure, shouldn't happen." +msgstr "严重的合并错误,不应发生。" + +#: merge-recursive.c:1823 +msgid "Already up-to-date!" +msgstr "已经是最新的!" + +#: merge-recursive.c:1832 +#, c-format +msgid "merging of trees %s and %s failed" +msgstr "无法合并树 %s 和 %s" + +#: merge-recursive.c:1862 +#, c-format +msgid "Unprocessed path??? %s" +msgstr "未处理的路径??? %s" + +#: merge-recursive.c:1907 +msgid "Merging:" +msgstr "合并:" + +#: merge-recursive.c:1920 +#, c-format +msgid "found %u common ancestor:" +msgid_plural "found %u common ancestors:" +msgstr[0] "发现 %u 个共同祖先:" +msgstr[1] "发现 %u 个共同祖先:" + +#: merge-recursive.c:1957 +msgid "merge returned no commit" +msgstr "合并未返回提交" + +#: merge-recursive.c:2014 +#, c-format +msgid "Could not parse object '%s'" +msgstr "不能解析对象 '%s'" + +#: merge-recursive.c:2026 builtin/merge.c:697 +msgid "Unable to write index." +msgstr "不能写入索引。" + +#: parse-options.c:494 msgid "..." msgstr "..." -#: parse-options.c:511 +#: parse-options.c:512 #, c-format msgid "usage: %s" msgstr "用法:%s" #. TRANSLATORS: the colon here should align with the #. one in "usage: %s" translation -#: parse-options.c:515 +#: parse-options.c:516 #, c-format msgid " or: %s" msgstr " 或:%s" # 译者:为保证在输出中对齐,注意调整句中空格! -#: parse-options.c:518 +#: parse-options.c:519 #, c-format msgid " %s" msgstr " %s" -#: remote.c:1629 +#: remote.c:1632 #, 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] "您的分支领先 '%s' 共 %d 个提交。\n" msgstr[1] "您的分支领先 '%s' 共 %d 个提交。\n" -#: remote.c:1635 +#: remote.c:1638 #, c-format msgid "Your branch is behind '%s' by %d commit, and can be fast-forwarded.\n" msgid_plural "" @@ -389,7 +651,7 @@ msgid_plural "" msgstr[0] "您的分支落后 '%s' 共 %d 个提交,并且可以快进。\n" msgstr[1] "您的分支落后 '%s' 共 %d 个提交,并且可以快进。\n" -#: remote.c:1643 +#: remote.c:1646 #, c-format msgid "" "Your branch and '%s' have diverged,\n" @@ -612,7 +874,7 @@ msgstr "不能解析 HEAD" msgid "cannot abort from a branch yet to be born" msgstr "不能从尚未建立的分支终止" -#: sequencer.c:805 builtin/apply.c:3697 +#: sequencer.c:805 builtin/apply.c:3988 #, c-format msgid "cannot open %s: %s" msgstr "不能打开 %s:%s" @@ -644,21 +906,21 @@ msgstr "不能作为初始提交还原" msgid "Can't cherry-pick into empty head" msgstr "不能拣选到空分支" -#: sha1_name.c:864 +#: sha1_name.c:1044 msgid "HEAD does not point to a branch" msgstr "HEAD 没有指向一个分支" -#: sha1_name.c:867 +#: sha1_name.c:1047 #, c-format msgid "No such branch: '%s'" msgstr "没有此分支:'%s'" -#: sha1_name.c:869 +#: sha1_name.c:1049 #, c-format msgid "No upstream configured for branch '%s'" msgstr "尚未给分支 '%s' 设置上游" -#: sha1_name.c:872 +#: sha1_name.c:1052 #, c-format msgid "Upstream branch '%s' not stored as a remote-tracking branch" msgstr "上游分支 '%s' 没有存储为一个远程跟踪分支" @@ -672,379 +934,378 @@ msgstr "无法在 passwd 文件中查询到当前用户:%s" msgid "no such user" msgstr "无此用户" -#: wt-status.c:141 +#: wt-status.c:140 msgid "Unmerged paths:" msgstr "未合并的路径:" # 译者:注意保持前导空格 -#: wt-status.c:168 wt-status.c:195 +#: wt-status.c:167 wt-status.c:194 #, c-format msgid " (use \"git reset %s <file>...\" to unstage)" msgstr " (使用 \"git reset %s <file>...\" 撤出暂存区)" # 译者:注意保持前导空格 -#: wt-status.c:170 wt-status.c:197 +#: wt-status.c:169 wt-status.c:196 msgid " (use \"git rm --cached <file>...\" to unstage)" msgstr " (使用 \"git rm --cached <file>...\" 撤出暂存区)" # 译者:注意保持前导空格 -#: wt-status.c:174 +#: wt-status.c:173 msgid " (use \"git add <file>...\" to mark resolution)" msgstr " (使用 \"git add <file>...\" 标记解决方案)" # 译者:注意保持前导空格 -#: wt-status.c:176 wt-status.c:180 +#: wt-status.c:175 wt-status.c:179 msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)" msgstr " (酌情使用 \"git add/rm <file>...\" 标记解决方案)" # 译者:注意保持前导空格 -#: wt-status.c:178 +#: wt-status.c:177 msgid " (use \"git rm <file>...\" to mark resolution)" msgstr " (使用 \"git rm <file>...\" 标记解决方案)" -#: wt-status.c:189 +#: wt-status.c:188 msgid "Changes to be committed:" msgstr "要提交的变更:" -#: wt-status.c:207 +#: wt-status.c:206 msgid "Changes not staged for commit:" msgstr "尚未暂存以备提交的变更:" # 译者:注意保持前导空格 -#: wt-status.c:211 +#: wt-status.c:210 msgid " (use \"git add <file>...\" to update what will be committed)" msgstr " (使用 \"git add <file>...\" 更新要提交的内容)" # 译者:注意保持前导空格 -#: wt-status.c:213 +#: wt-status.c:212 msgid " (use \"git add/rm <file>...\" to update what will be committed)" msgstr " (使用 \"git add/rm <file>...\" 更新要提交的内容)" # 译者:注意保持前导空格 -#: wt-status.c:214 +#: wt-status.c:213 msgid "" " (use \"git checkout -- <file>...\" to discard changes in working directory)" msgstr " (使用 \"git checkout -- <file>...\" 丢弃工作区的改动)" # 译者:注意保持前导空格 -#: wt-status.c:216 +#: wt-status.c:215 msgid " (commit or discard the untracked or modified content in submodules)" msgstr " (提交或丢弃子模组中未跟踪或修改的内容)" -#: wt-status.c:225 +#: wt-status.c:224 #, c-format msgid "%s files:" msgstr "%s文件:" # 译者:注意保持前导空格 -#: wt-status.c:228 +#: wt-status.c:227 #, c-format msgid " (use \"git %s <file>...\" to include in what will be committed)" msgstr " (使用 \"git %s <file>...\" 以包含要提交的内容)" -#: wt-status.c:245 +#: wt-status.c:244 msgid "bug" msgstr "bug" -#: wt-status.c:250 +#: wt-status.c:249 msgid "both deleted:" msgstr "双方删除:" -#: wt-status.c:251 +#: wt-status.c:250 msgid "added by us:" msgstr "由我们添加:" -#: wt-status.c:252 +#: wt-status.c:251 msgid "deleted by them:" msgstr "由他们删除:" -#: wt-status.c:253 +#: wt-status.c:252 msgid "added by them:" msgstr "由他们添加:" -#: wt-status.c:254 +#: wt-status.c:253 msgid "deleted by us:" msgstr "由我们删除:" -#: wt-status.c:255 +#: wt-status.c:254 msgid "both added:" msgstr "双方添加:" -#: wt-status.c:256 +#: wt-status.c:255 msgid "both modified:" msgstr "双方修改:" # 译者:末尾两个字节可能被删减,如果翻译为中文标点会出现半个汉字 -#: wt-status.c:286 +#: wt-status.c:285 msgid "new commits, " msgstr "新提交, " # 译者:末尾两个字节可能被删减,如果翻译为中文标点会出现半个汉字 -#: wt-status.c:288 +#: wt-status.c:287 msgid "modified content, " msgstr "修改的内容, " # 译者:末尾两个字节可能被删减,如果翻译为中文标点会出现半个汉字 -#: wt-status.c:290 +#: wt-status.c:289 msgid "untracked content, " msgstr "未跟踪的内容, " # 译者:为保证在输出中对齐,注意调整句中空格! -#: wt-status.c:304 +#: wt-status.c:303 #, c-format msgid "new file: %s" msgstr "新文件: %s" # 译者:为保证在输出中对齐,注意调整句中空格! -#: wt-status.c:307 +#: wt-status.c:306 #, c-format msgid "copied: %s -> %s" msgstr "拷贝: %s -> %s" # 译者:为保证在输出中对齐,注意调整句中空格! -#: wt-status.c:310 +#: wt-status.c:309 #, c-format msgid "deleted: %s" msgstr "删除: %s" # 译者:为保证在输出中对齐,注意调整句中空格! -#: wt-status.c:313 +#: wt-status.c:312 #, c-format msgid "modified: %s" msgstr "修改: %s" # 译者:为保证在输出中对齐,注意调整句中空格! -#: wt-status.c:316 +#: wt-status.c:315 #, c-format msgid "renamed: %s -> %s" msgstr "重命名: %s -> %s" # 译者:为保证在输出中对齐,注意调整句中空格! -#: wt-status.c:319 +#: wt-status.c:318 #, c-format msgid "typechange: %s" msgstr "类型变更: %s" # 译者:为保证在输出中对齐,注意调整句中空格! -#: wt-status.c:322 +#: wt-status.c:321 #, c-format msgid "unknown: %s" msgstr "未知: %s" # 译者:为保证在输出中对齐,注意调整句中空格! -#: wt-status.c:325 +#: wt-status.c:324 #, c-format msgid "unmerged: %s" msgstr "未合并: %s" -#: wt-status.c:328 +#: wt-status.c:327 #, c-format msgid "bug: unhandled diff status %c" msgstr "bug:未处理的差异状态 %c" -#: wt-status.c:786 +#: wt-status.c:785 msgid "You have unmerged paths." msgstr "您有路径尚未合并。" # 译者:注意保持前导空格 -#: wt-status.c:789 wt-status.c:913 +#: wt-status.c:788 wt-status.c:912 msgid " (fix conflicts and run \"git commit\")" msgstr " (解决冲突并运行 \"git commit\")" -#: wt-status.c:792 +#: wt-status.c:791 msgid "All conflicts fixed but you are still merging." msgstr "所有冲突已解决但您仍处于合并中。" # 译者:注意保持前导空格 -#: wt-status.c:795 +#: wt-status.c:794 msgid " (use \"git commit\" to conclude merge)" msgstr " (使用 \"git commit\" 结束合并)" -#: wt-status.c:805 +#: wt-status.c:804 msgid "You are in the middle of an am session." msgstr "您正处于一个 am 过程中。" -#: wt-status.c:808 +#: wt-status.c:807 msgid "The current patch is empty." msgstr "当前的补丁为空。" # 译者:注意保持前导空格 -#: wt-status.c:812 +#: wt-status.c:811 msgid " (fix conflicts and then run \"git am --resolved\")" msgstr " (解决冲突,然后运行 \"git am --resolved\")" # 译者:注意保持前导空格 -#: wt-status.c:814 +#: wt-status.c:813 msgid " (use \"git am --skip\" to skip this patch)" msgstr " (使用 \"git am --skip\" 跳过此补丁)" # 译者:注意保持前导空格 -#: wt-status.c:816 +#: wt-status.c:815 msgid " (use \"git am --abort\" to restore the original branch)" msgstr " (使用 \"git am --abort\" 恢复原有分支)" -#: wt-status.c:874 wt-status.c:884 +#: wt-status.c:873 wt-status.c:883 msgid "You are currently rebasing." msgstr "您正在变基。" # 译者:注意保持前导空格 -#: wt-status.c:877 +#: wt-status.c:876 msgid " (fix conflicts and then run \"git rebase --continue\")" msgstr " (解决冲突,然后运行 \"git rebase --continue\")" # 译者:注意保持前导空格 -#: wt-status.c:879 +#: wt-status.c:878 msgid " (use \"git rebase --skip\" to skip this patch)" msgstr " (使用 \"git rebase --skip\" 跳过此补丁)" # 译者:注意保持前导空格 -#: wt-status.c:881 +#: wt-status.c:880 msgid " (use \"git rebase --abort\" to check out the original branch)" msgstr " (使用 \"git rebase --abort\" 以检出原有分支)" # 译者:注意保持前导空格 -#: wt-status.c:887 +#: wt-status.c:886 msgid " (all conflicts fixed: run \"git rebase --continue\")" msgstr " (所有冲突已解决:运行 \"git rebase --continue\")" -#: wt-status.c:889 +#: wt-status.c:888 msgid "You are currently splitting a commit during a rebase." msgstr "您正在变基过程中拆分一个提交。" # 译者:注意保持前导空格 -#: wt-status.c:892 +#: wt-status.c:891 msgid " (Once your working directory is clean, run \"git rebase --continue\")" msgstr " (一旦您工作目录提交干净后,运行 \"git rebase --continue\")" -#: wt-status.c:894 +#: wt-status.c:893 msgid "You are currently editing a commit during a rebase." msgstr "您正在变基过程中编辑一个提交。" # 译者:注意保持前导空格 -#: wt-status.c:897 +#: wt-status.c:896 msgid " (use \"git commit --amend\" to amend the current commit)" msgstr " (使用 \"git commit --amend\" 修补当前提交)" # 译者:注意保持前导空格 -#: wt-status.c:899 +#: wt-status.c:898 msgid "" " (use \"git rebase --continue\" once you are satisfied with your changes)" -msgstr "" -" (执行 \"git rebase --continue\" 一旦您满意您的修改)" +msgstr " (执行 \"git rebase --continue\" 一旦您满意您的修改)" -#: wt-status.c:909 +#: wt-status.c:908 msgid "You are currently cherry-picking." msgstr "您正在做拣选操作。" # 译者:注意保持前导空格 -#: wt-status.c:916 +#: wt-status.c:915 msgid " (all conflicts fixed: run \"git commit\")" msgstr " (解决所有冲突后,执行 \"git commit\")" -#: wt-status.c:925 +#: wt-status.c:924 msgid "You are currently bisecting." msgstr "您正在做二分查找。" # 译者:注意保持前导空格 -#: wt-status.c:928 +#: wt-status.c:927 msgid " (use \"git bisect reset\" to get back to the original branch)" msgstr " (使用 \"git bisect reset\" 以回到原有分支)" -#: wt-status.c:979 +#: wt-status.c:978 msgid "On branch " msgstr "位于分支 " -#: wt-status.c:986 +#: wt-status.c:985 msgid "Not currently on any branch." msgstr "当前不在任何分支上。" -#: wt-status.c:998 +#: wt-status.c:997 msgid "Initial commit" msgstr "初始提交" -#: wt-status.c:1012 +#: wt-status.c:1011 msgid "Untracked" msgstr "未跟踪的" -#: wt-status.c:1014 +#: wt-status.c:1013 msgid "Ignored" msgstr "忽略的" -#: wt-status.c:1016 +#: wt-status.c:1015 #, c-format msgid "Untracked files not listed%s" msgstr "未跟踪的文件没有列出%s" # 译者:中文字符串拼接,可删除前导空格 -#: wt-status.c:1018 +#: wt-status.c:1017 msgid " (use -u option to show untracked files)" msgstr "(使用 -u 参数显示未跟踪的文件)" -#: wt-status.c:1024 +#: wt-status.c:1023 msgid "No changes" msgstr "没有修改" -#: wt-status.c:1028 +#: wt-status.c:1027 #, c-format msgid "no changes added to commit%s\n" msgstr "修改尚未加入提交%s\n" # 译者:中文字符串拼接,可删除前导空格 -#: wt-status.c:1030 +#: wt-status.c:1029 msgid " (use \"git add\" and/or \"git commit -a\")" msgstr "(使用 \"git add\" 和/或 \"git commit -a\")" -#: wt-status.c:1032 +#: wt-status.c:1031 #, c-format msgid "nothing added to commit but untracked files present%s\n" msgstr "空提交但存在未跟踪文件%s\n" # 译者:中文字符串拼接,可删除前导空格 -#: wt-status.c:1034 +#: wt-status.c:1033 msgid " (use \"git add\" to track)" msgstr "(使用 \"git add\" 建立跟踪)" -#: wt-status.c:1036 wt-status.c:1039 wt-status.c:1042 +#: wt-status.c:1035 wt-status.c:1038 wt-status.c:1041 #, c-format msgid "nothing to commit%s\n" msgstr "无须提交%s\n" # 译者:中文字符串拼接,可删除前导空格 -#: wt-status.c:1037 +#: wt-status.c:1036 msgid " (create/copy files and use \"git add\" to track)" msgstr "(新建/拷贝的文件使用 \"git add\" 建立跟踪)" # 译者:中文字符串拼接,可删除前导空格 -#: wt-status.c:1040 +#: wt-status.c:1039 msgid " (use -u to show untracked files)" msgstr "(使用 -u 显示未跟踪文件)" # 译者:中文字符串拼接,可删除前导空格 -#: wt-status.c:1043 +#: wt-status.c:1042 msgid " (working directory clean)" msgstr "(干净的工作区)" -#: wt-status.c:1151 +#: wt-status.c:1150 msgid "HEAD (no branch)" msgstr "HEAD(非分支)" # 译者:注意保持句尾空格 -#: wt-status.c:1157 +#: wt-status.c:1156 msgid "Initial commit on " msgstr "初始提交于 " # 译者:注意保持句尾空格 -#: wt-status.c:1172 +#: wt-status.c:1171 msgid "behind " msgstr "落后 " # 译者:注意保持句尾空格 -#: wt-status.c:1175 wt-status.c:1178 +#: wt-status.c:1174 wt-status.c:1177 msgid "ahead " msgstr "领先 " # 译者:注意保持句尾空格 -#: wt-status.c:1180 +#: wt-status.c:1179 msgid ", behind " msgstr ",落后 " @@ -1053,7 +1314,7 @@ msgstr ",落后 " msgid "unexpected diff status %c" msgstr "意外的差异状态 %c" -#: builtin/add.c:67 builtin/commit.c:226 +#: builtin/add.c:67 builtin/commit.c:229 msgid "updating files failed" msgstr "更新文件失败" @@ -1131,7 +1392,7 @@ msgstr "-A 和 -u 选项互斥" #: builtin/add.c:393 msgid "Option --ignore-missing can only be used together with --dry-run" -msgstr "选项 --ignore-missing 只能和 --dry-run 共用" +msgstr "选项 --ignore-missing 只能和 --dry-run 同时使用" #: builtin/add.c:413 #, c-format @@ -1143,75 +1404,75 @@ msgstr "没有指定文件,也没有文件被添加。\n" msgid "Maybe you wanted to say 'git add .'?\n" msgstr "也许您想要执行 'git add .'?\n" -#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:286 builtin/mv.c:82 +#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:289 builtin/mv.c:82 #: builtin/rm.c:162 msgid "index file corrupt" msgstr "索引文件损坏" -#: builtin/add.c:480 builtin/apply.c:4108 builtin/mv.c:229 builtin/rm.c:260 +#: builtin/add.c:480 builtin/apply.c:4433 builtin/mv.c:229 builtin/rm.c:260 msgid "Unable to write new index file" msgstr "无法写入新索引文件" -#: builtin/apply.c:53 +#: builtin/apply.c:57 msgid "git apply [options] [<patch>...]" msgstr "git apply [选项] [<补丁>...]" -#: builtin/apply.c:106 +#: builtin/apply.c:110 #, c-format msgid "unrecognized whitespace option '%s'" msgstr "未能识别的空白字符选项 '%s'" -#: builtin/apply.c:121 +#: builtin/apply.c:125 #, c-format msgid "unrecognized whitespace ignore option '%s'" msgstr "未能识别的空白字符忽略选项 '%s'" -#: builtin/apply.c:815 +#: builtin/apply.c:824 #, c-format msgid "Cannot prepare timestamp regexp %s" msgstr "无法准备时间戳正则表达式 %s" -#: builtin/apply.c:824 +#: builtin/apply.c:833 #, c-format msgid "regexec returned %d for input: %s" msgstr "regexec 返回 %d,输入为:%s" -#: builtin/apply.c:905 +#: builtin/apply.c:914 #, c-format msgid "unable to find filename in patch at line %d" msgstr "不能在补丁的第 %d 行找到文件名" -#: builtin/apply.c:937 +#: builtin/apply.c:946 #, c-format msgid "git apply: bad git-diff - expected /dev/null, got %s on line %d" msgstr "git apply:错误的 git-diff - 期望 /dev/null,但在第 %2$d 行得到 %1$s" -#: builtin/apply.c:941 +#: builtin/apply.c:950 #, c-format msgid "git apply: bad git-diff - inconsistent new filename on line %d" msgstr "git apply:错误的 git-diff - 第 %d 行上新文件名不一致" -#: builtin/apply.c:942 +#: builtin/apply.c:951 #, c-format msgid "git apply: bad git-diff - inconsistent old filename on line %d" msgstr "git apply:错误的 git-diff - 第 %d 行上旧文件名不一致" -#: builtin/apply.c:949 +#: builtin/apply.c:958 #, c-format msgid "git apply: bad git-diff - expected /dev/null on line %d" msgstr "git apply:错误的 git-diff - 期望 /dev/null 于第 %d 行" -#: builtin/apply.c:1394 +#: builtin/apply.c:1403 #, c-format msgid "recount: unexpected line: %.*s" msgstr "recount:意外的行:%.*s" -#: builtin/apply.c:1451 +#: builtin/apply.c:1460 #, c-format msgid "patch fragment without header at line %d: %.*s" msgstr "第 %d 行的补丁片段没有头信息:%.*s" -#: builtin/apply.c:1468 +#: builtin/apply.c:1477 #, c-format msgid "" "git diff header lacks filename information when removing %d leading pathname " @@ -1222,82 +1483,82 @@ msgid_plural "" msgstr[0] "当移除 %d 个前导路径后 git diff 头缺乏文件名信息(第 %d 行)" msgstr[1] "当移除 %d 个前导路径后 git diff 头缺乏文件名信息(第 %d 行)" -#: builtin/apply.c:1628 +#: builtin/apply.c:1637 msgid "new file depends on old contents" msgstr "新文件依赖旧内容" -#: builtin/apply.c:1630 +#: builtin/apply.c:1639 msgid "deleted file still has contents" msgstr "删除的文件仍有内容" -#: builtin/apply.c:1656 +#: builtin/apply.c:1665 #, c-format msgid "corrupt patch at line %d" msgstr "补丁损坏位于第 %d 行" -#: builtin/apply.c:1692 +#: builtin/apply.c:1701 #, c-format msgid "new file %s depends on old contents" msgstr "新文件 %s 依赖旧内容" -#: builtin/apply.c:1694 +#: builtin/apply.c:1703 #, c-format msgid "deleted file %s still has contents" msgstr "删除的文件 %s 仍有内容" -#: builtin/apply.c:1697 +#: builtin/apply.c:1706 #, c-format msgid "** warning: file %s becomes empty but is not deleted" msgstr "** 警告:文件 %s 成为空文件但并未删除" -#: builtin/apply.c:1843 +#: builtin/apply.c:1852 #, c-format msgid "corrupt binary patch at line %d: %.*s" msgstr "二进制补丁在第 %d 行损坏:%.*s" #. there has to be one hunk (forward hunk) -#: builtin/apply.c:1872 +#: builtin/apply.c:1881 #, c-format msgid "unrecognized binary patch at line %d" msgstr "未能识别的二进制补丁位于第 %d 行" -#: builtin/apply.c:1958 +#: builtin/apply.c:1967 #, c-format msgid "patch with only garbage at line %d" msgstr "补丁文件的第 %d 行只有垃圾数据" -#: builtin/apply.c:2048 +#: builtin/apply.c:2057 #, c-format msgid "unable to read symlink %s" msgstr "无法读取符号链接 %s" -#: builtin/apply.c:2052 +#: builtin/apply.c:2061 #, c-format msgid "unable to open or read %s" msgstr "不能打开或读取 %s" -#: builtin/apply.c:2123 +#: builtin/apply.c:2132 msgid "oops" msgstr "哎哟" -#: builtin/apply.c:2645 +#: builtin/apply.c:2654 #, c-format msgid "invalid start of line: '%c'" msgstr "无效的行首字符:'%c'" -#: builtin/apply.c:2763 +#: builtin/apply.c:2772 #, 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:2775 +#: builtin/apply.c:2784 #, c-format msgid "Context reduced to (%ld/%ld) to apply fragment at %d" msgstr "上下文减少到(%ld/%ld)以在第 %d 行应用补丁片段" -#: builtin/apply.c:2781 +#: builtin/apply.c:2790 #, c-format msgid "" "while searching for:\n" @@ -1306,313 +1567,321 @@ msgstr "" "当查询:\n" "%.*s" -#: builtin/apply.c:2800 +#: builtin/apply.c:2809 #, c-format msgid "missing binary patch data for '%s'" msgstr "缺失 '%s' 的二进制补丁数据" -#: builtin/apply.c:2903 +#: builtin/apply.c:2912 #, c-format msgid "binary patch does not apply to '%s'" msgstr "二进制补丁未应用到 '%s'" -#: builtin/apply.c:2909 +#: builtin/apply.c:2918 #, c-format msgid "binary patch to '%s' creates incorrect result (expecting %s, got %s)" msgstr "到 '%s' 的二进制补丁产生了不正确的结果(预期 %s,得到 %s)" -#: builtin/apply.c:2930 +#: builtin/apply.c:2939 #, c-format msgid "patch failed: %s:%ld" msgstr "打补丁失败:%s:%ld" -#: builtin/apply.c:3045 +#: builtin/apply.c:3061 #, c-format -msgid "patch %s has been renamed/deleted" -msgstr "补丁 %s 已经被重命名/删除" +msgid "cannot checkout %s" +msgstr "不能检出 %s" -#: builtin/apply.c:3052 builtin/apply.c:3069 +#: builtin/apply.c:3106 builtin/apply.c:3115 builtin/apply.c:3159 #, c-format msgid "read of %s failed" msgstr "读取 %s 失败" -#: builtin/apply.c:3084 -msgid "removal patch leaves file contents" -msgstr "移除补丁仍留下了文件内容" - -#: builtin/apply.c:3105 +#: builtin/apply.c:3139 builtin/apply.c:3361 #, c-format -msgid "%s: already exists in working directory" -msgstr "%s:已经存在于工作区中" +msgid "path %s has been renamed/deleted" +msgstr "路径 %s 已经被重命名/删除" -#: builtin/apply.c:3143 +#: builtin/apply.c:3220 builtin/apply.c:3375 #, c-format -msgid "%s: has been deleted/renamed" -msgstr "%s:已经被删除/重命名" +msgid "%s: does not exist in index" +msgstr "%s:不存在于索引中" -#: builtin/apply.c:3148 builtin/apply.c:3179 +#: builtin/apply.c:3224 builtin/apply.c:3367 builtin/apply.c:3389 #, c-format msgid "%s: %s" msgstr "%s:%s" -#: builtin/apply.c:3159 -#, c-format -msgid "%s: does not exist in index" -msgstr "%s:不存在于索引中" - -#: builtin/apply.c:3173 +#: builtin/apply.c:3229 builtin/apply.c:3383 #, c-format msgid "%s: does not match index" msgstr "%s:和索引不匹配" -#: builtin/apply.c:3190 +#: builtin/apply.c:3331 +msgid "removal patch leaves file contents" +msgstr "移除补丁仍留下了文件内容" + +#: builtin/apply.c:3400 #, c-format msgid "%s: wrong type" msgstr "%s:错误类型" -#: builtin/apply.c:3192 +#: builtin/apply.c:3402 #, c-format msgid "%s has type %o, expected %o" msgstr "%s 的类型是 %o,预期是 %o" -#: builtin/apply.c:3247 +#: builtin/apply.c:3503 #, c-format msgid "%s: already exists in index" msgstr "%s:已经存在于索引中" -#: builtin/apply.c:3267 +#: builtin/apply.c:3506 +#, c-format +msgid "%s: already exists in working directory" +msgstr "%s:已经存在于工作区中" + +#: builtin/apply.c:3526 #, c-format msgid "new mode (%o) of %s does not match old mode (%o)" msgstr "%2$s 的新模式(%1$o)和旧模式(%3$o)不匹配" -#: builtin/apply.c:3272 +#: builtin/apply.c:3531 #, c-format msgid "new mode (%o) of %s does not match old mode (%o) of %s" msgstr "%2$s 的新模式(%1$o)和 %4$s 的旧模式(%3$o)不匹配" -#: builtin/apply.c:3280 +#: builtin/apply.c:3539 #, c-format msgid "%s: patch does not apply" msgstr "%s:补丁未应用" -#: builtin/apply.c:3293 +#: builtin/apply.c:3552 #, c-format msgid "Checking patch %s..." msgstr "检查补丁 %s..." -#: builtin/apply.c:3348 builtin/checkout.c:212 builtin/reset.c:158 +#: builtin/apply.c:3607 builtin/checkout.c:213 builtin/reset.c:158 #, c-format msgid "make_cache_entry failed for path '%s'" msgstr "对路径 '%s' 的 make_cache_entry 操作失败" -#: builtin/apply.c:3491 +#: builtin/apply.c:3750 #, c-format msgid "unable to remove %s from index" msgstr "不能从索引中移除 %s" -#: builtin/apply.c:3518 +#: builtin/apply.c:3778 #, c-format msgid "corrupt patch for subproject %s" msgstr "子项目 %s 损坏的补丁" -#: builtin/apply.c:3522 +#: builtin/apply.c:3782 #, c-format msgid "unable to stat newly created file '%s'" msgstr "不能枚举新建文件 '%s' 的状态" -#: builtin/apply.c:3527 +#: builtin/apply.c:3787 #, c-format msgid "unable to create backing store for newly created file %s" msgstr "不能为新建文件 %s 创建后端存储" -#: builtin/apply.c:3530 +#: builtin/apply.c:3790 builtin/apply.c:3898 #, c-format msgid "unable to add cache entry for %s" msgstr "无法为 %s 添加缓存条目" -#: builtin/apply.c:3563 +#: builtin/apply.c:3823 #, c-format msgid "closing file '%s'" msgstr "关闭文件 '%s'" -#: builtin/apply.c:3612 +#: builtin/apply.c:3872 #, c-format msgid "unable to write file '%s' mode %o" msgstr "不能写文件 '%s' 权限 %o" -#: builtin/apply.c:3668 +#: builtin/apply.c:3959 #, c-format msgid "Applied patch %s cleanly." msgstr "成功应用补丁 %s。" -#: builtin/apply.c:3676 +#: builtin/apply.c:3967 msgid "internal error" msgstr "内部错误" #. Say this even without --verbose -#: builtin/apply.c:3679 +#: builtin/apply.c:3970 #, c-format msgid "Applying patch %%s with %d reject..." msgid_plural "Applying patch %%s with %d rejects..." msgstr[0] "应用补丁 %%s 时 %d 个被拒绝..." msgstr[1] "应用补丁 %%s 时 %d 个被拒绝..." -#: builtin/apply.c:3689 +#: builtin/apply.c:3980 #, c-format msgid "truncating .rej filename to %.*s.rej" msgstr "截短 .rej 文件名为 %.*s.rej" -#: builtin/apply.c:3710 +#: builtin/apply.c:4001 #, c-format msgid "Hunk #%d applied cleanly." msgstr "第 #%d 个片段成功应用。" -#: builtin/apply.c:3713 +#: builtin/apply.c:4004 #, c-format msgid "Rejected hunk #%d." msgstr "拒绝第 #%d 个片段。" -#: builtin/apply.c:3844 +#: builtin/apply.c:4154 msgid "unrecognized input" msgstr "未能识别的输入" -#: builtin/apply.c:3855 +#: builtin/apply.c:4165 msgid "unable to read index file" msgstr "无法读取索引文件" -#: builtin/apply.c:3970 builtin/apply.c:3973 +#: builtin/apply.c:4284 builtin/apply.c:4287 msgid "path" msgstr "路径" -#: builtin/apply.c:3971 +#: builtin/apply.c:4285 msgid "don't apply changes matching the given path" msgstr "不要应用与给出路径向匹配的变更" -#: builtin/apply.c:3974 +#: builtin/apply.c:4288 msgid "apply changes matching the given path" msgstr "应用与给出路径向匹配的变更" -#: builtin/apply.c:3976 +#: builtin/apply.c:4290 msgid "num" msgstr "数字" -#: builtin/apply.c:3977 +#: builtin/apply.c:4291 msgid "remove <num> leading slashes from traditional diff paths" msgstr "从传统的 diff 路径中移除 <数字> 个前导路径" -#: builtin/apply.c:3980 +#: builtin/apply.c:4294 msgid "ignore additions made by the patch" msgstr "忽略补丁中的添加的文件" -#: builtin/apply.c:3982 +#: builtin/apply.c:4296 msgid "instead of applying the patch, output diffstat for the input" msgstr "不应用补丁,而是显示输入的差异统计(diffstat)" -#: builtin/apply.c:3986 +#: builtin/apply.c:4300 msgid "shows number of added and deleted lines in decimal notation" msgstr "以数字方式显示添加或删除行的数量" -#: builtin/apply.c:3988 +#: builtin/apply.c:4302 msgid "instead of applying the patch, output a summary for the input" msgstr "不应用补丁,而是显示输入的概要" -#: builtin/apply.c:3990 +#: builtin/apply.c:4304 msgid "instead of applying the patch, see if the patch is applicable" msgstr "不应用补丁,而是查看补丁是否可应用" -#: builtin/apply.c:3992 +#: builtin/apply.c:4306 msgid "make sure the patch is applicable to the current index" msgstr "确认补丁可以应用到当前索引" -#: builtin/apply.c:3994 +#: builtin/apply.c:4308 msgid "apply a patch without touching the working tree" msgstr "应用补丁而不修改工作区" -#: builtin/apply.c:3996 +#: builtin/apply.c:4310 msgid "also apply the patch (use with --stat/--summary/--check)" -msgstr "同时应用此补丁(和 --stat/--summary/--check 共用)" +msgstr "还应用此补丁(使用 --stat/--summary/--check 参数)" + +#: builtin/apply.c:4312 +msgid "attempt three-way merge if a patch does not apply" +msgstr "如果一个补丁不能应用则尝试三路合并" -#: builtin/apply.c:3998 +#: builtin/apply.c:4314 msgid "build a temporary index based on embedded index information" msgstr "创建一个临时索引基于嵌入的索引信息" -#: builtin/apply.c:4000 +#: builtin/apply.c:4316 msgid "paths are separated with NUL character" msgstr "路径以 NUL 字符分隔" -#: builtin/apply.c:4003 +#: builtin/apply.c:4319 msgid "ensure at least <n> lines of context match" msgstr "确保至少匹配 <n> 行上下文" -#: builtin/apply.c:4004 +#: builtin/apply.c:4320 msgid "action" msgstr "动作" -#: builtin/apply.c:4005 +#: builtin/apply.c:4321 msgid "detect new or modified lines that have whitespace errors" msgstr "检查新增和修改的行中间的空白字符滥用" -#: builtin/apply.c:4008 builtin/apply.c:4011 +#: builtin/apply.c:4324 builtin/apply.c:4327 msgid "ignore changes in whitespace when finding context" msgstr "查找上下文时忽略空白字符的变更" -#: builtin/apply.c:4014 +#: builtin/apply.c:4330 msgid "apply the patch in reverse" msgstr "反向应用补丁" -#: builtin/apply.c:4016 +#: builtin/apply.c:4332 msgid "don't expect at least one line of context" msgstr "无需至少一行上下文" -#: builtin/apply.c:4018 +#: builtin/apply.c:4334 msgid "leave the rejected hunks in corresponding *.rej files" msgstr "将拒绝的补丁片段保存在对应的 *.rej 文件中" -#: builtin/apply.c:4020 +#: builtin/apply.c:4336 msgid "allow overlapping hunks" msgstr "允许重叠的补丁片段" -#: builtin/apply.c:4021 +#: builtin/apply.c:4337 msgid "be verbose" msgstr "冗长输出" -#: builtin/apply.c:4023 +#: builtin/apply.c:4339 msgid "tolerate incorrectly detected missing new-line at the end of file" msgstr "宽容不正确的文件末尾换行符" -#: builtin/apply.c:4026 +#: builtin/apply.c:4342 msgid "do not trust the line counts in the hunk headers" msgstr "不信任补丁片段的头信息中的行号" -#: builtin/apply.c:4028 +#: builtin/apply.c:4344 msgid "root" msgstr "根目录" -#: builtin/apply.c:4029 +#: builtin/apply.c:4345 msgid "prepend <root> to all filenames" msgstr "为所有文件名前添加 <根目录>" -#: builtin/apply.c:4050 +#: builtin/apply.c:4367 +msgid "--3way outside a repository" +msgstr "--3way 在一个版本库之外" + +#: builtin/apply.c:4375 msgid "--index outside a repository" msgstr "--index 在一个版本库之外" -#: builtin/apply.c:4053 +#: builtin/apply.c:4378 msgid "--cached outside a repository" msgstr "--cached 在一个版本库之外" -#: builtin/apply.c:4069 +#: builtin/apply.c:4394 #, c-format msgid "can't open patch '%s'" msgstr "不能打开补丁 '%s'" -#: builtin/apply.c:4083 +#: builtin/apply.c:4408 #, c-format msgid "squelched %d whitespace error" msgid_plural "squelched %d whitespace errors" msgstr[0] "抑制下仍有 %d 个空白字符误用" msgstr[1] "抑制下仍有 %d 个空白字符误用" -#: builtin/apply.c:4089 builtin/apply.c:4099 +#: builtin/apply.c:4414 builtin/apply.c:4424 #, c-format msgid "%d line adds whitespace errors." msgid_plural "%d lines add whitespace errors." @@ -1676,7 +1945,7 @@ msgstr "" #: builtin/branch.c:180 msgid "cannot use -a with -d" -msgstr "不能将 -a 和 -d 共用" +msgstr "不能将 -a 和 -d 同时使用" #: builtin/branch.c:186 msgid "Couldn't look up commit object for HEAD" @@ -1819,7 +2088,7 @@ msgstr "不能写分支描述模版:%s" msgid "Failed to resolve HEAD as a valid ref." msgstr "无法将 HEAD 解析为有效引用。" -#: builtin/branch.c:788 builtin/clone.c:558 +#: builtin/branch.c:788 builtin/clone.c:561 msgid "HEAD not found below refs/heads!" msgstr "HEAD 没有位于 /refs/heads 之下!" @@ -1844,100 +2113,100 @@ msgstr "需要一个版本库来创建包。" msgid "Need a repository to unbundle." msgstr "需要一个版本库来解包。" -#: builtin/checkout.c:113 builtin/checkout.c:146 +#: builtin/checkout.c:114 builtin/checkout.c:147 #, c-format msgid "path '%s' does not have our version" msgstr "路径 '%s' 没有我们的版本" -#: builtin/checkout.c:115 builtin/checkout.c:148 +#: builtin/checkout.c:116 builtin/checkout.c:149 #, c-format msgid "path '%s' does not have their version" msgstr "路径 '%s' 没有他们的版本" -#: builtin/checkout.c:131 +#: builtin/checkout.c:132 #, c-format msgid "path '%s' does not have all necessary versions" msgstr "路径 '%s' 没有全部必须的版本" -#: builtin/checkout.c:175 +#: builtin/checkout.c:176 #, c-format msgid "path '%s' does not have necessary versions" msgstr "路径 '%s' 没有必须的版本" -#: builtin/checkout.c:192 +#: builtin/checkout.c:193 #, c-format msgid "path '%s': cannot merge" msgstr "path '%s':无法合并" -#: builtin/checkout.c:209 +#: builtin/checkout.c:210 #, c-format msgid "Unable to add merge result for '%s'" msgstr "无法为 '%s' 添加合并结果" -#: builtin/checkout.c:234 builtin/checkout.c:392 +#: builtin/checkout.c:235 builtin/checkout.c:393 msgid "corrupt index file" msgstr "损坏的索引文件" -#: builtin/checkout.c:264 builtin/checkout.c:271 +#: builtin/checkout.c:265 builtin/checkout.c:272 #, c-format msgid "path '%s' is unmerged" msgstr "路径 '%s' 未合并" -#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583 +#: builtin/checkout.c:303 builtin/checkout.c:499 builtin/clone.c:586 #: builtin/merge.c:812 msgid "unable to write new index file" msgstr "无法写新的索引文件" -#: builtin/checkout.c:319 builtin/diff.c:302 builtin/merge.c:408 +#: builtin/checkout.c:320 builtin/diff.c:302 builtin/merge.c:408 msgid "diff_setup_done failed" msgstr "diff_setup_done 失败" -#: builtin/checkout.c:414 +#: builtin/checkout.c:415 msgid "you need to resolve your current index first" msgstr "您需要先解决当前索引的冲突" -#: builtin/checkout.c:533 +#: builtin/checkout.c:534 #, c-format msgid "Can not do reflog for '%s'\n" msgstr "不能对 '%s' 执行 reflog 操作\n" -#: builtin/checkout.c:566 +#: builtin/checkout.c:567 msgid "HEAD is now at" msgstr "HEAD 目前位于" -#: builtin/checkout.c:573 +#: builtin/checkout.c:574 #, c-format msgid "Reset branch '%s'\n" msgstr "重置分支 '%s'\n" -#: builtin/checkout.c:576 +#: builtin/checkout.c:577 #, c-format msgid "Already on '%s'\n" msgstr "已经位于 '%s'\n" -#: builtin/checkout.c:580 +#: builtin/checkout.c:581 #, c-format msgid "Switched to and reset branch '%s'\n" msgstr "切换并重置分支 '%s'\n" -#: builtin/checkout.c:582 +#: builtin/checkout.c:583 #, c-format msgid "Switched to a new branch '%s'\n" msgstr "切换到一个新分支 '%s'\n" -#: builtin/checkout.c:584 +#: builtin/checkout.c:585 #, c-format msgid "Switched to branch '%s'\n" msgstr "切换到分支 '%s'\n" # 译者:注意保持前导空格 -#: builtin/checkout.c:640 +#: builtin/checkout.c:641 #, c-format msgid " ... and %d more.\n" msgstr " ... 及其它 %d 个。\n" #. The singular version -#: builtin/checkout.c:646 +#: builtin/checkout.c:647 #, c-format msgid "" "Warning: you are leaving %d commit behind, not connected to\n" @@ -1958,7 +2227,7 @@ msgstr[1] "" "\n" "%s\n" -#: builtin/checkout.c:664 +#: builtin/checkout.c:665 #, c-format msgid "" "If you want to keep them by creating a new branch, this may be a good time\n" @@ -1973,71 +2242,71 @@ msgstr "" " git branch new_branch_name %s\n" "\n" -#: builtin/checkout.c:694 +#: builtin/checkout.c:695 msgid "internal error in revision walk" msgstr "在版本遍历时遇到内部错误" -#: builtin/checkout.c:698 +#: builtin/checkout.c:699 msgid "Previous HEAD position was" msgstr "之前的 HEAD 位置是" -#: builtin/checkout.c:724 +#: builtin/checkout.c:725 builtin/checkout.c:920 msgid "You are on a branch yet to be born" msgstr "您位于一个尚未初始化的分支" #. case (1) -#: builtin/checkout.c:855 +#: builtin/checkout.c:856 #, c-format msgid "invalid reference: %s" msgstr "无效引用:%s" #. case (1): want a tree -#: builtin/checkout.c:894 +#: builtin/checkout.c:895 #, c-format msgid "reference is not a tree: %s" msgstr "引用不是一个树:%s" -#: builtin/checkout.c:974 +#: builtin/checkout.c:977 msgid "-B cannot be used with -b" -msgstr "-B 不能和 -b 共用" +msgstr "-B 不能和 -b 同时使用" -#: builtin/checkout.c:983 +#: builtin/checkout.c:986 msgid "--patch is incompatible with all other options" msgstr "--patch 选项和其他选项不兼容" -#: builtin/checkout.c:986 +#: builtin/checkout.c:989 msgid "--detach cannot be used with -b/-B/--orphan" -msgstr "--detach 不能和 -b/-B/--orphan 共用" +msgstr "--detach 不能和 -b/-B/--orphan 同时使用" -#: builtin/checkout.c:988 +#: builtin/checkout.c:991 msgid "--detach cannot be used with -t" -msgstr "--detach 不能和 -t 共用" +msgstr "--detach 不能和 -t 同时使用" -#: builtin/checkout.c:994 +#: builtin/checkout.c:997 msgid "--track needs a branch name" msgstr "--track 需要一个分支名" -#: builtin/checkout.c:1001 +#: builtin/checkout.c:1004 msgid "Missing branch name; try -b" msgstr "缺少分支名;尝试 -b" -#: builtin/checkout.c:1007 +#: builtin/checkout.c:1010 msgid "--orphan and -b|-B are mutually exclusive" msgstr "--orphan 和 -b|-B 互斥" -#: builtin/checkout.c:1009 +#: builtin/checkout.c:1012 msgid "--orphan cannot be used with -t" -msgstr "--orphan 不能和 -t 共用" +msgstr "--orphan 不能和 -t 同时使用" -#: builtin/checkout.c:1019 +#: builtin/checkout.c:1022 msgid "git checkout: -f and -m are incompatible" msgstr "git checkout:-f 和 -m 不兼容" -#: builtin/checkout.c:1053 +#: builtin/checkout.c:1056 msgid "invalid path specification" msgstr "无效的路径规格" -#: builtin/checkout.c:1061 +#: builtin/checkout.c:1064 #, c-format msgid "" "git checkout: updating paths is incompatible with switching branches.\n" @@ -2046,32 +2315,32 @@ msgstr "" "git checkout:更新路径和切换分支不兼容。\n" "您是想要检出 '%s' 但未能将其解析为提交么?" -#: builtin/checkout.c:1063 +#: builtin/checkout.c:1066 msgid "git checkout: updating paths is incompatible with switching branches." msgstr "git checkout:更新路径和切换分支不兼容。" -#: builtin/checkout.c:1068 +#: builtin/checkout.c:1071 msgid "git checkout: --detach does not take a path argument" msgstr "git checkout:--detach 不跟路径参数" -#: builtin/checkout.c:1071 +#: builtin/checkout.c:1074 msgid "" "git checkout: --ours/--theirs, --force and --merge are incompatible when\n" "checking out of the index." msgstr "" "git checkout:在从索引检出时,--ours/--theirs、--force 和 --merge 不兼容。" -#: builtin/checkout.c:1090 +#: builtin/checkout.c:1093 msgid "Cannot switch branch to a non-commit." msgstr "无法切换分支到一个非提交。" -#: builtin/checkout.c:1093 +#: builtin/checkout.c:1096 msgid "--ours/--theirs is incompatible with switching branches." msgstr "--ours/--theirs 和切换分支不兼容。" #: builtin/clean.c:78 msgid "-x and -X cannot be used together" -msgstr "-x 和 -X 不能共用" +msgstr "-x 和 -X 不能同时使用" #: builtin/clean.c:82 msgid "" @@ -2116,11 +2385,6 @@ msgstr "未删除 %s\n" msgid "reference repository '%s' is not a local directory." msgstr "引用版本库 '%s' 不是一个本地目录。" -#: builtin/clone.c:302 -#, c-format -msgid "failed to open '%s'" -msgstr "无法打开 '%s'" - #: builtin/clone.c:306 #, c-format msgid "failed to create directory '%s'" @@ -2161,78 +2425,78 @@ msgstr "无法拷贝文件至 '%s'" msgid "done.\n" msgstr "完成。\n" -#: builtin/clone.c:440 +#: builtin/clone.c:443 #, c-format msgid "Could not find remote branch %s to clone." msgstr "不能发现要克隆的远程分支 %s。" -#: builtin/clone.c:549 +#: builtin/clone.c:552 msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n" msgstr "远程 HEAD 指向一个不存在的引用,无法检出。\n" -#: builtin/clone.c:639 +#: builtin/clone.c:642 msgid "Too many arguments." msgstr "太多参数。" -#: builtin/clone.c:643 +#: builtin/clone.c:646 msgid "You must specify a repository to clone." msgstr "您必须指定一个版本库来克隆。" -#: builtin/clone.c:654 +#: builtin/clone.c:657 #, c-format msgid "--bare and --origin %s options are incompatible." msgstr "--bare 和 --origin %s 选项不兼容。" -#: builtin/clone.c:668 +#: builtin/clone.c:671 #, c-format msgid "repository '%s' does not exist" msgstr "版本库 '%s' 不存在" -#: builtin/clone.c:673 +#: builtin/clone.c:676 msgid "--depth is ignored in local clones; use file:// instead." msgstr "--depth 在本地克隆被忽略,改为 file:// 协议试试。" -#: builtin/clone.c:683 +#: builtin/clone.c:686 #, c-format msgid "destination path '%s' already exists and is not an empty directory." msgstr "目标路径 '%s' 已经存在,并且不是一个空目录。" -#: builtin/clone.c:693 +#: builtin/clone.c:696 #, c-format msgid "working tree '%s' already exists." msgstr "工作区 '%s' 已经存在。" -#: builtin/clone.c:706 builtin/clone.c:720 +#: builtin/clone.c:709 builtin/clone.c:723 #, c-format msgid "could not create leading directories of '%s'" msgstr "不能为 '%s' 创建先导目录" -#: builtin/clone.c:709 +#: builtin/clone.c:712 #, c-format msgid "could not create work tree dir '%s'." msgstr "不能为 '%s' 创建工作区目录。" -#: builtin/clone.c:728 +#: builtin/clone.c:731 #, c-format msgid "Cloning into bare repository '%s'...\n" msgstr "克隆到裸版本库 '%s'...\n" -#: builtin/clone.c:730 +#: builtin/clone.c:733 #, c-format msgid "Cloning into '%s'...\n" msgstr "正克隆到 '%s'...\n" -#: builtin/clone.c:786 +#: builtin/clone.c:789 #, c-format msgid "Don't know how to clone %s" msgstr "不知道如何克隆 %s" -#: builtin/clone.c:835 +#: builtin/clone.c:838 #, c-format msgid "Remote branch %s not found in upstream %s" msgstr "远程分支 %s 在上游 %s 未发现" -#: builtin/clone.c:842 +#: builtin/clone.c:845 msgid "You appear to have cloned an empty repository." msgstr "您似乎克隆了一个空版本库。" @@ -2288,93 +2552,93 @@ msgstr "" "\n" "否则,请使用命令 'git reset'\n" -#: builtin/commit.c:253 +#: builtin/commit.c:256 msgid "failed to unpack HEAD tree object" msgstr "无法解包 HEAD 树对象" -#: builtin/commit.c:295 +#: builtin/commit.c:298 msgid "unable to create temporary index" msgstr "不能创建临时索引" -#: builtin/commit.c:301 +#: builtin/commit.c:304 msgid "interactive add failed" msgstr "交互式添加失败" -#: builtin/commit.c:334 builtin/commit.c:355 builtin/commit.c:405 +#: builtin/commit.c:337 builtin/commit.c:358 builtin/commit.c:408 msgid "unable to write new_index file" msgstr "无法写 new_index 文件" -#: builtin/commit.c:386 +#: builtin/commit.c:389 msgid "cannot do a partial commit during a merge." msgstr "在合并过程中不能做部分提交。" -#: builtin/commit.c:388 +#: builtin/commit.c:391 msgid "cannot do a partial commit during a cherry-pick." msgstr "在拣选过程中不能做部分提交。" -#: builtin/commit.c:398 +#: builtin/commit.c:401 msgid "cannot read the index" msgstr "无法读取索引" -#: builtin/commit.c:418 +#: builtin/commit.c:421 msgid "unable to write temporary index file" msgstr "无法写临时索引文件" -#: builtin/commit.c:493 builtin/commit.c:499 +#: builtin/commit.c:496 builtin/commit.c:502 #, c-format msgid "invalid commit: %s" msgstr "无效的提交:%s" -#: builtin/commit.c:522 +#: builtin/commit.c:525 msgid "malformed --author parameter" msgstr "非法的 --author 参数" -#: builtin/commit.c:582 +#: builtin/commit.c:585 #, c-format msgid "Malformed ident string: '%s'" msgstr "非法的身份字符串:'%s'" -#: builtin/commit.c:620 builtin/commit.c:653 builtin/commit.c:967 +#: builtin/commit.c:623 builtin/commit.c:656 builtin/commit.c:970 #, c-format msgid "could not lookup commit %s" msgstr "不能查询提交 %s" -#: builtin/commit.c:632 builtin/shortlog.c:296 +#: builtin/commit.c:635 builtin/shortlog.c:296 #, c-format msgid "(reading log message from standard input)\n" msgstr "(正从标准输入中读取日志信息)\n" -#: builtin/commit.c:634 +#: builtin/commit.c:637 msgid "could not read log from standard input" msgstr "不能从标准输入中读取日志信息" -#: builtin/commit.c:638 +#: builtin/commit.c:641 #, c-format msgid "could not read log file '%s'" msgstr "不能读取日志文件 '%s'" -#: builtin/commit.c:644 +#: builtin/commit.c:647 msgid "commit has empty message" msgstr "提交说明为空" -#: builtin/commit.c:660 +#: builtin/commit.c:663 msgid "could not read MERGE_MSG" msgstr "不能读取 MERGE_MSG" -#: builtin/commit.c:664 +#: builtin/commit.c:667 msgid "could not read SQUASH_MSG" msgstr "不能读取 SQUASH_MSG" -#: builtin/commit.c:668 +#: builtin/commit.c:671 #, c-format msgid "could not read '%s'" msgstr "不能读取 '%s'" -#: builtin/commit.c:720 +#: builtin/commit.c:723 msgid "could not write commit template" msgstr "不能写提交模版" -#: builtin/commit.c:731 +#: builtin/commit.c:734 #, c-format msgid "" "\n" @@ -2384,11 +2648,11 @@ msgid "" "and try again.\n" msgstr "" "\n" -"看起来您正在做一个合并提交。如果不对,请删除文件\n" +"似乎您正在做一个合并提交。如果不对,请删除文件\n" "\t%s\n" "然后重试。\n" -#: builtin/commit.c:736 +#: builtin/commit.c:739 #, c-format msgid "" "\n" @@ -2398,11 +2662,11 @@ msgid "" "and try again.\n" msgstr "" "\n" -"看起来您正在做一个拣选提交。如果不对,请删除文件\n" +"似乎您正在做一个拣选提交。如果不对,请删除文件\n" "\t%s\n" "然后重试。\n" -#: builtin/commit.c:748 +#: builtin/commit.c:751 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be ignored, and an empty message aborts the commit.\n" @@ -2410,7 +2674,7 @@ msgstr "" "请为您的变更输入提交说明。以 '#' 开始的行将被忽略,而一个空的提交\n" "说明将会终止提交。\n" -#: builtin/commit.c:753 +#: builtin/commit.c:756 msgid "" "Please enter the commit message for your changes. Lines starting\n" "with '#' will be kept; you may remove them yourself if you want to.\n" @@ -2420,160 +2684,160 @@ msgstr "" "如果您想这样做的话。而一个空的提交说明将会终止提交。\n" # 译者:为保证在输出中对齐,注意调整句中空格! -#: builtin/commit.c:766 +#: builtin/commit.c:769 #, c-format msgid "%sAuthor: %s" msgstr "%s作者: %s" # 译者:为保证在输出中对齐,注意调整句中空格! -#: builtin/commit.c:773 +#: builtin/commit.c:776 #, c-format msgid "%sCommitter: %s" msgstr "%s提交者: %s" -#: builtin/commit.c:793 +#: builtin/commit.c:796 msgid "Cannot read index" msgstr "无法读取索引" -#: builtin/commit.c:830 +#: builtin/commit.c:833 msgid "Error building trees" msgstr "无法创建树对象" -#: builtin/commit.c:845 builtin/tag.c:361 +#: builtin/commit.c:848 builtin/tag.c:361 #, c-format msgid "Please supply the message using either -m or -F option.\n" msgstr "请使用 -m 或者 -F 选项提供提交说明。\n" -#: builtin/commit.c:942 +#: builtin/commit.c:945 #, c-format msgid "No existing author found with '%s'" msgstr "没有找到匹配 '%s' 的作者" -#: builtin/commit.c:957 builtin/commit.c:1157 +#: builtin/commit.c:960 builtin/commit.c:1160 #, c-format msgid "Invalid untracked files mode '%s'" msgstr "无效的未追踪文件参数 '%s'" -#: builtin/commit.c:997 +#: builtin/commit.c:1000 msgid "Using both --reset-author and --author does not make sense" msgstr "同时使用 --reset-author 和 --author 没有意义" -#: builtin/commit.c:1008 +#: builtin/commit.c:1011 msgid "You have nothing to amend." msgstr "您没有可修补的提交。" -#: builtin/commit.c:1011 +#: builtin/commit.c:1014 msgid "You are in the middle of a merge -- cannot amend." msgstr "您正处于一个合并过程中 -- 无法修补提交。" -#: builtin/commit.c:1013 +#: builtin/commit.c:1016 msgid "You are in the middle of a cherry-pick -- cannot amend." msgstr "您正处于一个拣选过程中 -- 无法修补提交。" -#: builtin/commit.c:1016 +#: builtin/commit.c:1019 msgid "Options --squash and --fixup cannot be used together" -msgstr "选项 --squash 和 --fixup 不能共用" +msgstr "选项 --squash 和 --fixup 不能同时使用" -#: builtin/commit.c:1026 +#: builtin/commit.c:1029 msgid "Only one of -c/-C/-F/--fixup can be used." msgstr "只能用一个 -c/-C/-F/--fixup 选项。" -#: builtin/commit.c:1028 +#: builtin/commit.c:1031 msgid "Option -m cannot be combined with -c/-C/-F/--fixup." -msgstr "选项 -m 不能和 -c/-C/-F/--fixup 共用。" +msgstr "选项 -m 不能和 -c/-C/-F/--fixup 同时使用。" -#: builtin/commit.c:1036 +#: builtin/commit.c:1039 msgid "--reset-author can be used only with -C, -c or --amend." -msgstr "--reset-author 只能和 -C、-c 或 --amend 共用。" +msgstr "--reset-author 只能和 -C、-c 或 --amend 同时使用。" -#: builtin/commit.c:1053 +#: builtin/commit.c:1056 msgid "Only one of --include/--only/--all/--interactive/--patch can be used." msgstr "只能用一个 --include/--only/--all/--interactive/--patch 选项。" -#: builtin/commit.c:1055 +#: builtin/commit.c:1058 msgid "No paths with --include/--only does not make sense." msgstr "参数 --include/--only 不跟路径没有意义。" -#: builtin/commit.c:1057 +#: builtin/commit.c:1060 msgid "Clever... amending the last one with dirty index." msgstr "聪明... 在索引不干净下修补最后的提交。" -#: builtin/commit.c:1059 +#: builtin/commit.c:1062 msgid "Explicit paths specified without -i nor -o; assuming --only paths..." msgstr "指定了明确的路径而没有使用 -i 或 -o 选项;认为是 --only paths..." -#: builtin/commit.c:1069 builtin/tag.c:577 +#: builtin/commit.c:1072 builtin/tag.c:577 #, c-format msgid "Invalid cleanup mode %s" msgstr "无效的清理模式 %s" -#: builtin/commit.c:1074 +#: builtin/commit.c:1077 msgid "Paths with -a does not make sense." -msgstr "路径和 -a 选项共用没有意义。" +msgstr "路径和 -a 选项同时使用没有意义。" -#: builtin/commit.c:1257 +#: builtin/commit.c:1260 msgid "couldn't look up newly created commit" msgstr "无法找到新创建的提交" -#: builtin/commit.c:1259 +#: builtin/commit.c:1262 msgid "could not parse newly created commit" msgstr "不能解析新创建的提交" -#: builtin/commit.c:1300 +#: builtin/commit.c:1303 msgid "detached HEAD" msgstr "分离头指针" # 译者:中文字符串拼接,可删除前导空格 -#: builtin/commit.c:1302 +#: builtin/commit.c:1305 msgid " (root-commit)" msgstr "(根提交)" -#: builtin/commit.c:1446 +#: builtin/commit.c:1449 msgid "could not parse HEAD commit" msgstr "不能解析 HEAD 提交" -#: builtin/commit.c:1484 builtin/merge.c:509 +#: builtin/commit.c:1487 builtin/merge.c:509 #, c-format msgid "could not open '%s' for reading" msgstr "不能为读入打开 '%s'" -#: builtin/commit.c:1491 +#: builtin/commit.c:1494 #, c-format msgid "Corrupt MERGE_HEAD file (%s)" msgstr "损坏的 MERGE_HEAD 文件(%s)" -#: builtin/commit.c:1498 +#: builtin/commit.c:1501 msgid "could not read MERGE_MODE" msgstr "不能读取 MERGE_MODE" -#: builtin/commit.c:1517 +#: builtin/commit.c:1520 #, c-format msgid "could not read commit message: %s" msgstr "不能读取提交说明:%s" -#: builtin/commit.c:1531 +#: builtin/commit.c:1534 #, c-format msgid "Aborting commit; you did not edit the message.\n" msgstr "终止提交;您未更改来自模版的提交说明。\n" -#: builtin/commit.c:1536 +#: builtin/commit.c:1539 #, c-format msgid "Aborting commit due to empty commit message.\n" msgstr "终止提交因为提交说明为空。\n" -#: builtin/commit.c:1551 builtin/merge.c:936 builtin/merge.c:961 +#: builtin/commit.c:1554 builtin/merge.c:936 builtin/merge.c:961 msgid "failed to write commit object" msgstr "无法写提交对象" -#: builtin/commit.c:1572 +#: builtin/commit.c:1575 msgid "cannot lock HEAD ref" msgstr "无法锁定 HEAD 引用" -#: builtin/commit.c:1576 +#: builtin/commit.c:1579 msgid "cannot update HEAD ref" msgstr "无法更新 HEAD 引用" -#: builtin/commit.c:1587 +#: builtin/commit.c:1590 msgid "" "Repository has been updated, but unable to write\n" "new_index file. Check that disk is not full or quota is\n" @@ -2664,7 +2928,7 @@ msgstr "没有发现名称,无法描述任何东西。" #: builtin/describe.c:482 msgid "--dirty is incompatible with committishes" -msgstr "--dirty 不能与提交共用" +msgstr "--dirty 不能与提交同时使用" #: builtin/diff.c:77 #, c-format @@ -2693,7 +2957,7 @@ msgstr "提供了超过 %d 个树对象:'%s'" #: builtin/diff.c:356 #, c-format msgid "more than two blobs given: '%s'" -msgstr "提供了超过两个 blob 对象:'%s'" +msgstr "提供了超过两个二进制对象(blob):'%s'" #: builtin/diff.c:364 #, c-format @@ -2930,11 +3194,11 @@ msgstr "--open-files-in-pager 仅用于工作区" #: builtin/grep.c:963 msgid "--cached or --untracked cannot be used with --no-index." -msgstr "--cached 或 --untracked 不能与 --no-index 共用。" +msgstr "--cached 或 --untracked 不能与 --no-index 同时使用。" #: builtin/grep.c:968 msgid "--no-index or --untracked cannot be used with revs." -msgstr "--no-index 或 --untracked 不能和版本共用。" +msgstr "--no-index 或 --untracked 不能和版本同时使用。" #: builtin/grep.c:971 msgid "--[no-]exclude-standard cannot be used for tracked contents." @@ -2944,30 +3208,30 @@ msgstr "--[no-]exclude-standard 不能用于已跟踪内容。" msgid "both --cached and trees are given." msgstr "同时给出了 --cached 和树对象。" -#: builtin/help.c:63 +#: builtin/help.c:65 #, c-format msgid "unrecognized help format '%s'" msgstr "未能识别的帮助格式 '%s'" -#: builtin/help.c:91 +#: builtin/help.c:93 msgid "Failed to start emacsclient." msgstr "无法启动 emacsclient。" -#: builtin/help.c:104 +#: builtin/help.c:106 msgid "Failed to parse emacsclient version." msgstr "无法解析 emacsclient 版本。" -#: builtin/help.c:112 +#: builtin/help.c:114 #, c-format msgid "emacsclient version '%d' too old (< 22)." msgstr "emacsclient 版本 '%d' 太老 (< 22)。" -#: builtin/help.c:130 builtin/help.c:158 builtin/help.c:167 builtin/help.c:175 +#: builtin/help.c:132 builtin/help.c:160 builtin/help.c:169 builtin/help.c:177 #, c-format msgid "failed to exec '%s': %s" msgstr "无法执行 '%s':%s" -#: builtin/help.c:215 +#: builtin/help.c:217 #, c-format msgid "" "'%s': path for unsupported man viewer.\n" @@ -2976,7 +3240,7 @@ msgstr "" "'%s':不支持的 man 手册查看器的路径。\n" "请使用 'man.<tool>.cmd'。" -#: builtin/help.c:227 +#: builtin/help.c:229 #, c-format msgid "" "'%s': cmd for supported man viewer.\n" @@ -2985,34 +3249,29 @@ msgstr "" "'%s': 支持的 man 手册查看器命令。\n" "请使用 'man.<tool>.path'。" -#: builtin/help.c:291 +#: builtin/help.c:299 msgid "The most commonly used git commands are:" msgstr "最常用的 git 命令有:" -#: builtin/help.c:359 +#: builtin/help.c:367 #, c-format msgid "'%s': unknown man viewer." msgstr "'%s':未知的 man 查看器。" -#: builtin/help.c:376 +#: builtin/help.c:384 msgid "no man viewer handled the request" msgstr "没有 man 查看器处理此请求" -#: builtin/help.c:384 +#: builtin/help.c:392 msgid "no info viewer handled the request" msgstr "没有 info 查看器处理此请求" -#: builtin/help.c:395 -#, c-format -msgid "'%s': not a documentation directory." -msgstr "'%s':不是一个文档目录。" - -#: builtin/help.c:436 builtin/help.c:443 +#: builtin/help.c:447 builtin/help.c:454 #, c-format msgid "usage: %s%s" msgstr "用法:%s%s" -#: builtin/help.c:459 +#: builtin/help.c:470 #, c-format msgid "`git %s' is aliased to `%s'" msgstr "`git %s' 是 `%s' 的别名" @@ -3086,176 +3345,176 @@ msgstr "delta 基准偏移越界" msgid "unknown object type %d" msgstr "未知对象类型 %d" -#: builtin/index-pack.c:531 +#: builtin/index-pack.c:530 msgid "cannot pread pack file" msgstr "无法读取包文件" -#: builtin/index-pack.c:533 +#: builtin/index-pack.c:532 #, c-format msgid "premature end of pack file, %lu byte missing" msgid_plural "premature end of pack file, %lu bytes missing" msgstr[0] "包文件过早结束,缺少 %lu 字节" msgstr[1] "包文件过早结束,缺少 %lu 字节" -#: builtin/index-pack.c:555 +#: builtin/index-pack.c:558 msgid "serious inflate inconsistency" msgstr "解压缩严重的不一致" -#: builtin/index-pack.c:646 builtin/index-pack.c:652 builtin/index-pack.c:675 -#: builtin/index-pack.c:709 builtin/index-pack.c:718 +#: builtin/index-pack.c:649 builtin/index-pack.c:655 builtin/index-pack.c:678 +#: builtin/index-pack.c:712 builtin/index-pack.c:721 #, c-format msgid "SHA1 COLLISION FOUND WITH %s !" msgstr "发现 %s 出现 SHA1 冲突!" -#: builtin/index-pack.c:649 builtin/pack-objects.c:170 +#: builtin/index-pack.c:652 builtin/pack-objects.c:170 #: builtin/pack-objects.c:262 #, c-format msgid "unable to read %s" msgstr "不能读 %s" -#: builtin/index-pack.c:715 +#: builtin/index-pack.c:718 #, c-format msgid "cannot read existing object %s" msgstr "不能读取现存对象 %s" -#: builtin/index-pack.c:729 +#: builtin/index-pack.c:732 #, c-format msgid "invalid blob object %s" -msgstr "无效的 blob 对象 %s" +msgstr "无效的二进制对象(blob)%s" -#: builtin/index-pack.c:744 +#: builtin/index-pack.c:747 #, c-format msgid "invalid %s" msgstr "无效的 %s" -#: builtin/index-pack.c:746 +#: builtin/index-pack.c:749 msgid "Error in object" msgstr "对象中出错" -#: builtin/index-pack.c:748 +#: builtin/index-pack.c:751 #, c-format msgid "Not all child objects of %s are reachable" msgstr "%s 的所有子对象并非都可达" -#: builtin/index-pack.c:818 builtin/index-pack.c:844 +#: builtin/index-pack.c:821 builtin/index-pack.c:847 msgid "failed to apply delta" msgstr "无法应用 delta" -#: builtin/index-pack.c:983 +#: builtin/index-pack.c:986 msgid "Receiving objects" msgstr "接收对象中" -#: builtin/index-pack.c:983 +#: builtin/index-pack.c:986 msgid "Indexing objects" msgstr "索引对象中" -#: builtin/index-pack.c:1009 +#: builtin/index-pack.c:1012 msgid "pack is corrupted (SHA1 mismatch)" msgstr "包冲突(SHA1 不匹配)" -#: builtin/index-pack.c:1014 +#: builtin/index-pack.c:1017 msgid "cannot fstat packfile" msgstr "不能枚举包文件状态" -#: builtin/index-pack.c:1017 +#: builtin/index-pack.c:1020 msgid "pack has junk at the end" msgstr "包的结尾有垃圾数据" -#: builtin/index-pack.c:1028 +#: builtin/index-pack.c:1031 msgid "confusion beyond insanity in parse_pack_objects()" msgstr "parse_pack_objects() 中遇到不可理喻的问题" -#: builtin/index-pack.c:1051 +#: builtin/index-pack.c:1054 msgid "Resolving deltas" msgstr "处理 delta 中" -#: builtin/index-pack.c:1102 +#: builtin/index-pack.c:1105 msgid "confusion beyond insanity" msgstr "不可理喻" -#: builtin/index-pack.c:1121 +#: builtin/index-pack.c:1124 #, c-format msgid "pack has %d unresolved delta" msgid_plural "pack has %d unresolved deltas" msgstr[0] "包有 %d 个未解决的 delta" msgstr[1] "包有 %d 个未解决的 delta" -#: builtin/index-pack.c:1146 +#: builtin/index-pack.c:1149 #, c-format msgid "unable to deflate appended object (%d)" msgstr "不能缩小附加对象(%d)" -#: builtin/index-pack.c:1225 +#: builtin/index-pack.c:1228 #, c-format msgid "local object %s is corrupt" msgstr "本地对象 %s 已损坏" -#: builtin/index-pack.c:1249 +#: builtin/index-pack.c:1252 msgid "error while closing pack file" msgstr "关闭包文件时出错" -#: builtin/index-pack.c:1262 +#: builtin/index-pack.c:1265 #, c-format msgid "cannot write keep file '%s'" msgstr "无法写保留文件 '%s'" -#: builtin/index-pack.c:1270 +#: builtin/index-pack.c:1273 #, c-format msgid "cannot close written keep file '%s'" msgstr "无法关闭保留文件 '%s'" -#: builtin/index-pack.c:1283 +#: builtin/index-pack.c:1286 msgid "cannot store pack file" msgstr "无法存储包文件" -#: builtin/index-pack.c:1294 +#: builtin/index-pack.c:1297 msgid "cannot store index file" msgstr "无法存储索引文件" -#: builtin/index-pack.c:1395 +#: builtin/index-pack.c:1398 #, c-format msgid "Cannot open existing pack file '%s'" msgstr "无法打开现存包文件 '%s'" -#: builtin/index-pack.c:1397 +#: builtin/index-pack.c:1400 #, c-format msgid "Cannot open existing pack idx file for '%s'" msgstr "无法为 %s 打开包索引文件" -#: builtin/index-pack.c:1444 +#: builtin/index-pack.c:1447 #, c-format msgid "non delta: %d object" msgid_plural "non delta: %d objects" msgstr[0] "非 delta:%d 个对象" msgstr[1] "非 delta:%d 个对象" -#: builtin/index-pack.c:1451 +#: builtin/index-pack.c:1454 #, c-format msgid "chain length = %d: %lu object" msgid_plural "chain length = %d: %lu objects" msgstr[0] "链长 = %d: %lu 对象" msgstr[1] "链长 = %d: %lu 对象" -#: builtin/index-pack.c:1478 +#: builtin/index-pack.c:1481 msgid "Cannot come back to cwd" msgstr "无法返回当前工作目录" -#: builtin/index-pack.c:1522 builtin/index-pack.c:1525 -#: builtin/index-pack.c:1537 builtin/index-pack.c:1541 +#: builtin/index-pack.c:1525 builtin/index-pack.c:1528 +#: builtin/index-pack.c:1540 builtin/index-pack.c:1544 #, c-format msgid "bad %s" msgstr "错误选项 %s" -#: builtin/index-pack.c:1555 +#: builtin/index-pack.c:1558 msgid "--fix-thin cannot be used without --stdin" -msgstr "--fix-thin 不能和 --stdin 共用" +msgstr "--fix-thin 不能和 --stdin 同时使用" -#: builtin/index-pack.c:1559 builtin/index-pack.c:1569 +#: builtin/index-pack.c:1562 builtin/index-pack.c:1572 #, c-format msgid "packfile name '%s' does not end with '.pack'" msgstr "包名 '%s' 没有以 '.pack' 结尾" -#: builtin/index-pack.c:1578 +#: builtin/index-pack.c:1581 msgid "--verify with no packfile name given" msgstr "--verify 没有提供包名参数" @@ -3329,22 +3588,22 @@ msgstr "没有从 '%2$s' 复制带有错误版本 %1$d 的模版" msgid "insane git directory %s" msgstr "不正常的 git 目录 %s" -#: builtin/init-db.c:322 builtin/init-db.c:325 +#: builtin/init-db.c:323 builtin/init-db.c:326 #, c-format msgid "%s already exists" msgstr "%s 已经存在" -#: builtin/init-db.c:354 +#: builtin/init-db.c:355 #, c-format msgid "unable to handle file type %d" msgstr "不能处理 %d 类型的文件" -#: builtin/init-db.c:357 +#: builtin/init-db.c:358 #, c-format msgid "unable to move %s to %s" msgstr "不能移动 %s 至 %s" -#: builtin/init-db.c:362 +#: builtin/init-db.c:363 #, c-format msgid "Could not create git link %s" msgstr "不能创建 git link %s" @@ -3354,39 +3613,39 @@ msgstr "不能创建 git link %s" #. * existing" or "Initialized empty", the second " shared" or #. * "", and the last '%s%s' is the verbatim directory name. #. -#: builtin/init-db.c:419 +#: builtin/init-db.c:420 #, c-format msgid "%s%s Git repository in %s%s\n" msgstr "%s%s Git 版本库于 %s%s\n" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Reinitialized existing" msgstr "重新初始化现存的" -#: builtin/init-db.c:420 +#: builtin/init-db.c:421 msgid "Initialized empty" msgstr "初始化空的" # 译者:中文字符串拼接,可删除前导空格 -#: builtin/init-db.c:421 +#: builtin/init-db.c:422 msgid " shared" msgstr "共享" -#: builtin/init-db.c:440 +#: builtin/init-db.c:441 msgid "cannot tell cwd" msgstr "无法获知当前路径" -#: builtin/init-db.c:521 builtin/init-db.c:528 +#: builtin/init-db.c:522 builtin/init-db.c:529 #, c-format msgid "cannot mkdir %s" msgstr "不能创建目录 %s" -#: builtin/init-db.c:532 +#: builtin/init-db.c:533 #, c-format msgid "cannot chdir to %s" msgstr "不能切换目录到 %s" -#: builtin/init-db.c:554 +#: builtin/init-db.c:555 #, c-format msgid "" "%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-" @@ -3395,11 +3654,11 @@ msgstr "" "不允许 %s(或 --work-tree=<directory>)而没有指定 %s(或 --git-" "dir=<directory>)" -#: builtin/init-db.c:578 +#: builtin/init-db.c:579 msgid "Cannot access current working directory" msgstr "不能访问当前工作目录" -#: builtin/init-db.c:585 +#: builtin/init-db.c:586 #, c-format msgid "Cannot access work tree '%s'" msgstr "不能访问工作区 '%s'" @@ -3409,95 +3668,95 @@ msgstr "不能访问工作区 '%s'" msgid "Final output: %d %s\n" msgstr "最终输出:%d %s\n" -#: builtin/log.c:402 builtin/log.c:490 +#: builtin/log.c:403 builtin/log.c:494 #, c-format msgid "Could not read object %s" msgstr "不能读取对象 %s" -#: builtin/log.c:514 +#: builtin/log.c:518 #, c-format msgid "Unknown type: %d" msgstr "未知类型:%d" -#: builtin/log.c:603 +#: builtin/log.c:608 msgid "format.headers without value" msgstr "format.headers 没有值" -#: builtin/log.c:677 +#: builtin/log.c:682 msgid "name of output directory is too long" msgstr "输出目录名太长" -#: builtin/log.c:688 +#: builtin/log.c:693 #, c-format msgid "Cannot open patch file %s" msgstr "无法打开补丁文件 %s" -#: builtin/log.c:702 +#: builtin/log.c:707 msgid "Need exactly one range." msgstr "只需要一个范围。" -#: builtin/log.c:710 +#: builtin/log.c:715 msgid "Not a range." msgstr "不是一个范围。" -#: builtin/log.c:787 +#: builtin/log.c:792 msgid "Cover letter needs email format" msgstr "信封需要邮件地址格式" -#: builtin/log.c:860 +#: builtin/log.c:865 #, c-format msgid "insane in-reply-to: %s" msgstr "不正常的 in-reply-to:%s" -#: builtin/log.c:933 +#: builtin/log.c:938 msgid "Two output directories?" msgstr "两个输出目录?" -#: builtin/log.c:1154 +#: builtin/log.c:1160 #, c-format msgid "bogus committer info %s" msgstr "虚假的提交者信息 %s" -#: builtin/log.c:1199 +#: builtin/log.c:1205 msgid "-n and -k are mutually exclusive." msgstr "-n 和 -k 互斥。" -#: builtin/log.c:1201 +#: builtin/log.c:1207 msgid "--subject-prefix and -k are mutually exclusive." msgstr "--subject-prefix 和 -k 互斥。" -#: builtin/log.c:1209 +#: builtin/log.c:1215 msgid "--name-only does not make sense" msgstr "--name-only 无意义" -#: builtin/log.c:1211 +#: builtin/log.c:1217 msgid "--name-status does not make sense" msgstr "--name-status 无意义" -#: builtin/log.c:1213 +#: builtin/log.c:1219 msgid "--check does not make sense" msgstr "--check 无意义" -#: builtin/log.c:1236 +#: builtin/log.c:1242 msgid "standard output, or directory, which one?" msgstr "标准输出或目录,哪一个?" -#: builtin/log.c:1238 +#: builtin/log.c:1244 #, c-format msgid "Could not create directory '%s'" msgstr "不能创建目录 '%s'" -#: builtin/log.c:1391 +#: builtin/log.c:1397 msgid "Failed to create output files" msgstr "无法创建输出文件" -#: builtin/log.c:1495 +#: builtin/log.c:1501 #, c-format msgid "" "Could not find a tracked remote branch, please specify <upstream> manually.\n" msgstr "不能找到跟踪的远程分支,请手工指定 <upstream>。\n" -#: builtin/log.c:1511 builtin/log.c:1513 builtin/log.c:1525 +#: builtin/log.c:1517 builtin/log.c:1519 builtin/log.c:1531 #, c-format msgid "Unknown commit %s" msgstr "未知提交 %s" @@ -3579,10 +3838,6 @@ msgstr "git write-tree 无法写入一树对象" msgid "failed to read the cache" msgstr "无法读取缓存" -#: builtin/merge.c:697 -msgid "Unable to write index." -msgstr "不能写索引。" - #: builtin/merge.c:710 msgid "Not handling anything other than two heads merge." msgstr "不能处理两个头合并之外的任何操作。" @@ -3691,11 +3946,11 @@ msgstr "您尚未结束您的拣选(存在 CHERRY_PICK_HEAD)。" #: builtin/merge.c:1249 msgid "You cannot combine --squash with --no-ff." -msgstr "您不能将 --squash 与 --no-ff 共用。" +msgstr "您不能将 --squash 与 --no-ff 同时使用。" #: builtin/merge.c:1254 msgid "You cannot combine --no-ff with --ff-only." -msgstr "您不能将 --no-ff 与 --ff-only 共用。" +msgstr "您不能将 --no-ff 与 --ff-only 同时使用。" #: builtin/merge.c:1261 msgid "No commit specified and merge.defaultToUpstream not set." @@ -4165,7 +4420,7 @@ msgstr "--all 和 --tags 不兼容" #: builtin/push.c:286 msgid "--all can't be combined with refspecs" -msgstr "--all 不能和引用表达式共用" +msgstr "--all 不能和引用表达式同时使用" #: builtin/push.c:291 msgid "--mirror and --tags are incompatible" @@ -4173,7 +4428,7 @@ msgstr "--mirror 和 --tags 不兼容" #: builtin/push.c:292 msgid "--mirror can't be combined with refspecs" -msgstr "--mirror 不能和引用表达式共用" +msgstr "--mirror 不能和引用表达式同时使用" #: builtin/push.c:297 msgid "--all and --mirror are incompatible" @@ -4211,7 +4466,7 @@ msgstr "指定一个 master 分支并使用 --mirror 选项没有意义" #: builtin/remote.c:187 msgid "specifying branches to track makes sense only with fetch mirrors" -msgstr "指定要跟踪的分支只在与获取镜像共用才有意义" +msgstr "指定要跟踪的分支只在与获取镜像同时使用才有意义" #: builtin/remote.c:195 builtin/remote.c:646 #, c-format @@ -4594,32 +4849,32 @@ msgstr "重置后撤出暂存区的变更:" msgid "Cannot do a %s reset in the middle of a merge." msgstr "在合并过程中不能做%s重置操作。" -#: builtin/reset.c:297 +#: builtin/reset.c:303 #, c-format msgid "Could not parse object '%s'." msgstr "不能解析对象 '%s'。" -#: builtin/reset.c:302 +#: builtin/reset.c:308 msgid "--patch is incompatible with --{hard,mixed,soft}" msgstr "--patch 与 --{hard,mixed,soft} 不兼容" -#: builtin/reset.c:311 +#: builtin/reset.c:317 msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead." -msgstr "--mixed 带路径已弃用,代之以 'git reset -- <paths>'。" +msgstr "--mixed 带路径已弃用,而是用 'git reset -- <paths>'。" # 译者:汉字之间无空格,故删除%s前后空格 -#: builtin/reset.c:313 +#: builtin/reset.c:319 #, c-format msgid "Cannot do %s reset with paths." msgstr "不能带路径进行%s重置。" # 译者:汉字之间无空格,故删除%s前后空格 -#: builtin/reset.c:325 +#: builtin/reset.c:331 #, c-format msgid "%s reset is not allowed in a bare repository" msgstr "不能对裸版本库进行%s重置" -#: builtin/reset.c:341 +#: builtin/reset.c:347 #, c-format msgid "Could not reset index file to revision '%s'." msgstr "不能重置索引文件至版本 '%s'。" @@ -4627,7 +4882,7 @@ msgstr "不能重置索引文件至版本 '%s'。" #: builtin/revert.c:70 builtin/revert.c:92 #, c-format msgid "%s: %s cannot be used with %s" -msgstr "%s:%s 不能和 %s 共用" +msgstr "%s:%s 不能和 %s 同时使用" #: builtin/revert.c:131 msgid "program error" @@ -4777,15 +5032,15 @@ msgstr "--column 和 -n 不兼容" #: builtin/tag.c:523 msgid "-n option is only allowed with -l." -msgstr "-n 选项只允许和 -l 共用。" +msgstr "-n 选项只允许和 -l 同时使用。" #: builtin/tag.c:525 msgid "--contains option is only allowed with -l." -msgstr "--contains 选项只允许和 -l 共用。" +msgstr "--contains 选项只允许和 -l 同时使用。" #: builtin/tag.c:527 msgid "--points-at option is only allowed with -l." -msgstr "--points-at 选项只允许和 -l 共用。" +msgstr "--points-at 选项只允许和 -l 同时使用。" #: builtin/tag.c:535 msgid "only one -F or -m option is allowed." @@ -4953,9 +5208,9 @@ msgstr "您好像在上一次 'am' 失败后移动了 HEAD。未回退至 ORIG_H #: git-am.sh:105 #, sh-format msgid "" -"When you have resolved this problem run \"$cmdline --resolved\".\n" -"If you would prefer to skip this patch, instead run \"$cmdline --skip\".\n" -"To restore the original branch and stop patching run \"$cmdline --abort\"." +"When you have resolved this problem, run \"$cmdline --resolved\".\n" +"If you prefer to skip this patch, run \"$cmdline --skip\" instead.\n" +"To restore the original branch and stop patching, run \"$cmdline --abort\"." msgstr "" "当您解决了此问题后,执行 \"$cmdline --resolved\"。\n" "如果您想跳过此补丁,则执行 \"$cmdline --skip\"。\n" @@ -4967,7 +5222,11 @@ msgstr "无法求助于三路合并。" #: git-am.sh:137 msgid "Repository lacks necessary blobs to fall back on 3-way merge." -msgstr "版本库缺乏必要的 blob 数据以进行三路合并。" +msgstr "版本库缺乏必要的二进制对象(blob)以进行三路合并。" + +#: git-am.sh:139 +msgid "Using index info to reconstruct a base tree..." +msgstr "更新索引信息以重建基树..." #: git-am.sh:154 msgid "" @@ -4975,48 +5234,56 @@ msgid "" "It does not apply to blobs recorded in its index." msgstr "" "您是否曾手动编辑过您的补丁?\n" -"无法应用补丁到索引中的数据上。" +"无法应用补丁到索引中的二进制对象(blob)上。" #: git-am.sh:163 msgid "Falling back to patching base and 3-way merge..." msgstr "转而在基础版本上打补丁及进行三路合并..." -#: git-am.sh:275 +#: git-am.sh:179 +msgid "Failed to merge in the changes." +msgstr "无法合并变更。" + +#: git-am.sh:274 msgid "Only one StGIT patch series can be applied at once" msgstr "一次只能有一个 StGIT 补丁队列被应用" -#: git-am.sh:362 +#: git-am.sh:361 #, sh-format msgid "Patch format $patch_format is not supported." msgstr "不支持 $patch_format 补丁格式。" -#: git-am.sh:364 +#: git-am.sh:363 msgid "Patch format detection failed." msgstr "补丁格式检测失败。" -#: git-am.sh:418 -msgid "-d option is no longer supported. Do not use." -msgstr "不再支持 -d 选项。不要使用。" +#: git-am.sh:389 +msgid "" +"The -b/--binary option has been a no-op for long time, and\n" +"it will be removed. Please do not use it anymore." +msgstr "" +"参数 -b/--binary 已经很长时间不做任何实质操作了,并且将被删除。\n" +"请不要再使用它了。" -#: git-am.sh:481 +#: git-am.sh:477 #, sh-format msgid "previous rebase directory $dotest still exists but mbox given." msgstr "之前的变基目录 $dotest 仍然存在但给出了mbox。" -#: git-am.sh:486 +#: git-am.sh:482 msgid "Please make up your mind. --skip or --abort?" msgstr "请下决心。--skip 或是 --abort ?" -#: git-am.sh:513 +#: git-am.sh:509 msgid "Resolve operation not in progress, we are not resuming." msgstr "解决操作未进行,我们不会继续。" -#: git-am.sh:579 +#: git-am.sh:575 #, sh-format msgid "Dirty index: cannot apply patches (dirty: $files)" msgstr "脏的索引:不能应用补丁(脏文件:$files)" -#: git-am.sh:671 +#: git-am.sh:679 #, sh-format msgid "" "Patch is empty. Was it split wrong?\n" @@ -5027,15 +5294,15 @@ msgstr "" "如果您想要跳过这个补丁,执行 \"$cmdline --skip\"。\n" "要恢复原分支并停止打补丁,执行 \"$cmdline --abort\"。" -#: git-am.sh:708 +#: git-am.sh:706 msgid "Patch does not have a valid e-mail address." msgstr "补丁中没有一个有效的邮件地址。" -#: git-am.sh:755 +#: git-am.sh:753 msgid "cannot be interactive without stdin connected to a terminal." msgstr "标准输入没有和终端关联,不能进行交互式操作。" -#: git-am.sh:759 +#: git-am.sh:757 msgid "Commit Body is:" msgstr "提交内容为:" @@ -5043,16 +5310,16 @@ msgstr "提交内容为:" #. TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a] #. in your translation. The program will only accept English #. input at this point. -#: git-am.sh:766 +#: git-am.sh:764 msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " msgstr "应用?[y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " -#: git-am.sh:802 +#: git-am.sh:800 #, sh-format msgid "Applying: $FIRSTLINE" msgstr "正应用:$FIRSTLINE" -#: git-am.sh:823 +#: git-am.sh:821 msgid "" "No changes - did you forget to use 'git add'?\n" "If there is nothing left to stage, chances are that something else\n" @@ -5062,22 +5329,22 @@ msgstr "" "如果没有什么要添加到暂存区的,则很可能是其它提交已经引入了相同的变更。\n" "您也许想要跳过这个补丁。" -#: git-am.sh:831 +#: git-am.sh:829 msgid "" "You still have unmerged paths in your index\n" "did you forget to use 'git add'?" msgstr "您的索引中仍有未合并的路径。您是否忘了执行 'git add'?" -#: git-am.sh:847 +#: git-am.sh:845 msgid "No changes -- Patch already applied." msgstr "没有变更 -- 补丁已经应用过。" -#: git-am.sh:857 +#: git-am.sh:855 #, sh-format msgid "Patch failed at $msgnum $FIRSTLINE" msgstr "补丁失败于 $msgnum $FIRSTLINE" -#: git-am.sh:873 +#: git-am.sh:876 msgid "applying to an empty history" msgstr "正应用到一个空历史上" @@ -5278,6 +5545,123 @@ msgstr "无法将多个分支合并到空分支" msgid "Cannot rebase onto multiple branches" msgstr "无法变基到多个分支" +#: git-rebase.sh:52 +msgid "" +"When you have resolved this problem, run \"git rebase --continue\".\n" +"If you prefer to skip this patch, run \"git rebase --skip\" instead.\n" +"To check out the original branch and stop rebasing, run \"git rebase --abort" +"\"." +msgstr "" +"当您解决了此问题后,执行 \"git rebase --continue\"。\n" +"如果您想跳过此补丁,则执行 \"git rebase --skip\"。\n" +"要恢复原分支并停止变基,执行 \"git rebase --abort\"。" + +#: git-rebase.sh:159 +msgid "The pre-rebase hook refused to rebase." +msgstr "钩子 pre-rebase 拒绝变基。" + +#: git-rebase.sh:164 +msgid "It looks like git-am is in progress. Cannot rebase." +msgstr "似乎正处于在 git-am 的执行过程中。无法变基。" + +#: git-rebase.sh:295 +msgid "The --exec option must be used with the --interactive option" +msgstr "选项 --exec 必须和选项 --interactive 同时使用" + +#: git-rebase.sh:300 +msgid "No rebase in progress?" +msgstr "没有正在进行的变基?" + +#: git-rebase.sh:313 +msgid "Cannot read HEAD" +msgstr "不能读取 HEAD" + +#: git-rebase.sh:316 +msgid "" +"You must edit all merge conflicts and then\n" +"mark them as resolved using git add" +msgstr "" +"您必须编辑所有的合并冲突,然后通过 git add\n" +"命令将它们标记为已解决" + +#: git-rebase.sh:334 +#, sh-format +msgid "Could not move back to $head_name" +msgstr "无法移回 $head_name" + +#: git-rebase.sh:350 +#, sh-format +msgid "" +"It seems that there is already a $state_dir_base directory, and\n" +"I wonder if you are in the middle of another rebase. If that is the\n" +"case, please try\n" +"\t$cmd_live_rebase\n" +"If that is not the case, please\n" +"\t$cmd_clear_stale_rebase\n" +"and run me again. I am stopping in case you still have something\n" +"valuable there." +msgstr "" +"好像已有一个 $state_dir_base 目录,我怀疑您正处于另外一个变基过程中。\n" +"如果是这样,请尝试执行\n" +"\t$cmd_live_rebase\n" +"如果不是这样,请执行\n" +"\t$cmd_clear_stale_rebase\n" +"然后再重新执行变基。为避免您丢失重要数据,我已经停止当前操作。" + +#: git-rebase.sh:395 +#, sh-format +msgid "invalid upstream $upstream_name" +msgstr "无效的上游 $upstream_name" + +#: git-rebase.sh:419 +#, sh-format +msgid "$onto_name: there are more than one merge bases" +msgstr "$onto_name: 有一个以上的合并基准" + +#: git-rebase.sh:422 git-rebase.sh:426 +#, sh-format +msgid "$onto_name: there is no merge base" +msgstr "$onto_name: 没有合并基准" + +#: git-rebase.sh:431 +#, sh-format +msgid "Does not point to a valid commit: $onto_name" +msgstr "没有指向一个有效的提交:$onto_name" + +#: git-rebase.sh:454 +#, sh-format +msgid "fatal: no such branch: $branch_name" +msgstr "严重错误:无此分支:$branch_name" + +#: git-rebase.sh:474 +msgid "Please commit or stash them." +msgstr "请提交或为它们保存进度。" + +#: git-rebase.sh:492 +#, sh-format +msgid "Current branch $branch_name is up to date." +msgstr "当前分支 $branch_name 是最新的。" + +#: git-rebase.sh:495 +#, sh-format +msgid "Current branch $branch_name is up to date, rebase forced." +msgstr "当前分支 $branch_name 是最新的,强制变基。" + +#: git-rebase.sh:506 +#, sh-format +msgid "Changes from $mb to $onto:" +msgstr "变更从 $mb 到 $onto:" + +#. Detach HEAD and reset the tree +#: git-rebase.sh:515 +msgid "First, rewinding head to replay your work on top of it..." +msgstr "首先,重置头指针以便在上面重放您的工作..." + +#: git-rebase.sh:523 +#, sh-format +msgid "Fast-forwarded $branch_name to $onto_name." +msgstr "快进 $branch_name 至 $onto_name。" + #: git-stash.sh:51 msgid "git stash clear with parameters is unimplemented" msgstr "git stash clear 不支持参数" @@ -5417,27 +5801,27 @@ msgstr "无法从 url '$remoteurl' 剥离一个组件" msgid "No submodule mapping found in .gitmodules for path '$sm_path'" msgstr "未在 .gitmodules 中发现路径 '$sm_path' 的子模组映射" -#: git-submodule.sh:186 +#: git-submodule.sh:189 #, sh-format msgid "Clone of '$url' into submodule path '$sm_path' failed" msgstr "无法克隆 '$url' 到子模组路径 '$sm_path'" -#: git-submodule.sh:196 +#: git-submodule.sh:201 #, sh-format msgid "Gitdir '$a' is part of the submodule path '$b' or vice versa" msgstr "Gitdir '$a' 在子模组路径 '$b' 之下或者相反" -#: git-submodule.sh:285 +#: git-submodule.sh:290 #, sh-format msgid "repo URL: '$repo' must be absolute or begin with ./|../" msgstr "版本库URL:'$repo' 必须是绝对路径或以 ./|../ 起始" -#: git-submodule.sh:302 +#: git-submodule.sh:307 #, sh-format msgid "'$sm_path' already exists in the index" msgstr "'$sm_path' 已经存在于索引中" -#: git-submodule.sh:306 +#: git-submodule.sh:311 #, sh-format msgid "" "The following path is ignored by one of your .gitignore files:\n" @@ -5448,62 +5832,62 @@ msgstr "" "$sm_path\n" "如果您确实想添加它,使用 -f 参数。" -#: git-submodule.sh:317 +#: git-submodule.sh:322 #, sh-format msgid "Adding existing repo at '$sm_path' to the index" msgstr "添加位于 '$sm_path' 的现存版本库到索引" -#: git-submodule.sh:319 +#: git-submodule.sh:324 #, sh-format msgid "'$sm_path' already exists and is not a valid git repo" msgstr "'$sm_path' 已存在且不是一个有效的 git 版本库" -#: git-submodule.sh:333 +#: git-submodule.sh:338 #, sh-format msgid "Unable to checkout submodule '$sm_path'" msgstr "不能检出子模组 '$sm_path'" -#: git-submodule.sh:338 +#: git-submodule.sh:343 #, sh-format msgid "Failed to add submodule '$sm_path'" msgstr "无法添加子模组 '$sm_path'" -#: git-submodule.sh:343 +#: git-submodule.sh:348 #, sh-format msgid "Failed to register submodule '$sm_path'" msgstr "无法注册子模组 '$sm_path'" -#: git-submodule.sh:385 +#: git-submodule.sh:390 #, sh-format msgid "Entering '$prefix$sm_path'" msgstr "正在进入 '$prefix$sm_path'" -#: git-submodule.sh:399 +#: git-submodule.sh:404 #, sh-format msgid "Stopping at '$sm_path'; script returned non-zero status." msgstr "停止于 '$sm_path',脚本返回非零值。" -#: git-submodule.sh:442 +#: git-submodule.sh:447 #, sh-format msgid "No url found for submodule path '$sm_path' in .gitmodules" msgstr "在 .gitmodules 中未找到子模组路径 '$sm_path' 的 url" -#: git-submodule.sh:451 +#: git-submodule.sh:456 #, sh-format msgid "Failed to register url for submodule path '$sm_path'" msgstr "无法为子模组路径 '$sm_path' 注册 url" -#: git-submodule.sh:453 +#: git-submodule.sh:458 #, sh-format msgid "Submodule '$name' ($url) registered for path '$sm_path'" msgstr "子模组 '$name' ($url) 已为路径 '$sm_path' 注册" -#: git-submodule.sh:461 +#: git-submodule.sh:466 #, sh-format msgid "Failed to register update mode for submodule path '$sm_path'" msgstr "无法为子模组路径 '$sm_path' 注册更新模式" -#: git-submodule.sh:560 +#: git-submodule.sh:565 #, sh-format msgid "" "Submodule path '$sm_path' not initialized\n" @@ -5512,96 +5896,92 @@ msgstr "" "子模组路径 '$sm_path' 没有初始化\n" "也许您想用 'update --init'?" -#: git-submodule.sh:573 +#: git-submodule.sh:578 #, sh-format msgid "Unable to find current revision in submodule path '$sm_path'" msgstr "无法在子模组路径 '$sm_path' 中找到当前版本" -#: git-submodule.sh:592 +#: git-submodule.sh:597 #, sh-format msgid "Unable to fetch in submodule path '$sm_path'" msgstr "无法在子模组路径 '$sm_path' 中获取" -#: git-submodule.sh:606 +#: git-submodule.sh:611 #, sh-format msgid "Unable to rebase '$sha1' in submodule path '$sm_path'" msgstr "无法在子模组路径 '$sm_path' 中变基 '$sha1'" -#: git-submodule.sh:607 +#: git-submodule.sh:612 #, sh-format msgid "Submodule path '$sm_path': rebased into '$sha1'" msgstr "子模组路径 '$sm_path':变基至 '$sha1'" -#: git-submodule.sh:612 +#: git-submodule.sh:617 #, sh-format msgid "Unable to merge '$sha1' in submodule path '$sm_path'" msgstr "无法合并 '$sha1' 到子模组路径 '$sm_path' 中" -#: git-submodule.sh:613 +#: git-submodule.sh:618 #, sh-format msgid "Submodule path '$sm_path': merged in '$sha1'" msgstr "子模组路径 '$sm_path':已合并入 '$sha1'" -#: git-submodule.sh:618 +#: git-submodule.sh:623 #, sh-format msgid "Unable to checkout '$sha1' in submodule path '$sm_path'" msgstr "无法在子模组路径 '$sm_path' 中检出 '$sha1'" -#: git-submodule.sh:619 +#: git-submodule.sh:624 #, sh-format msgid "Submodule path '$sm_path': checked out '$sha1'" msgstr "子模组路径 '$sm_path':检出 '$sha1'" -#: git-submodule.sh:641 git-submodule.sh:964 +#: git-submodule.sh:646 git-submodule.sh:969 #, sh-format msgid "Failed to recurse into submodule path '$sm_path'" msgstr "无法递归进子模组路径 '$sm_path'" -#: git-submodule.sh:749 -msgid "--cached cannot be used with --files" -msgstr "--cached 不能和 --files 共用" +#: git-submodule.sh:754 +msgid "The --cached option cannot be used with the --files option" +msgstr "选项 --cached 不能和选项 --files 同时使用" #. unexpected type -#: git-submodule.sh:789 +#: git-submodule.sh:794 #, sh-format msgid "unexpected mode $mod_dst" msgstr "意外的模式 $mod_dst" # 译者:注意保持前导空格 -#: git-submodule.sh:807 +#: git-submodule.sh:812 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_src" msgstr " 警告:$name 未包含提交 $sha1_src" # 译者:注意保持前导空格 -#: git-submodule.sh:810 +#: git-submodule.sh:815 #, sh-format msgid " Warn: $name doesn't contain commit $sha1_dst" msgstr " 警告:$name 未包含提交 $sha1_dst" # 译者:注意保持前导空格 -#: git-submodule.sh:813 +#: git-submodule.sh:818 #, sh-format msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst" msgstr " 警告:$name 未包含提交 $sha1_src 和 $sha1_dst" -#: git-submodule.sh:838 +#: git-submodule.sh:843 msgid "blob" -msgstr "blob" - -#: git-submodule.sh:839 -msgid "submodule" -msgstr "子模组" +msgstr "二进制对象" -#: git-submodule.sh:876 +#: git-submodule.sh:881 msgid "# Submodules changed but not updated:" msgstr "# 子模组已修改但尚未更新:" -#: git-submodule.sh:878 +#: git-submodule.sh:883 msgid "# Submodule changes to be committed:" msgstr "要提交的子模组变更:" -#: git-submodule.sh:1022 +#: git-submodule.sh:1027 #, sh-format msgid "Synchronizing submodule url for '$name'" msgstr "为 '$name' 同步子模组 url" diff --git a/read-cache.c b/read-cache.c index 2f8159fb16..79e3bbe024 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1414,11 +1414,9 @@ int read_index_from(struct index_state *istate, const char *path) size_t mmap_size; struct strbuf previous_name_buf = STRBUF_INIT, *previous_name; - errno = EBUSY; if (istate->initialized) return istate->cache_nr; - errno = ENOENT; istate->timestamp.sec = 0; istate->timestamp.nsec = 0; fd = open(path, O_RDONLY); @@ -1431,15 +1429,14 @@ int read_index_from(struct index_state *istate, const char *path) if (fstat(fd, &st)) die_errno("cannot stat the open index"); - errno = EINVAL; mmap_size = xsize_t(st.st_size); if (mmap_size < sizeof(struct cache_header) + 20) die("index file smaller than expected"); mmap = xmmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - close(fd); if (mmap == MAP_FAILED) die_errno("unable to map index file"); + close(fd); hdr = mmap; if (verify_hdr(hdr, mmap_size) < 0) @@ -1495,7 +1492,6 @@ int read_index_from(struct index_state *istate, const char *path) unmap: munmap(mmap, mmap_size); - errno = EINVAL; die("index file corrupt"); } @@ -1800,6 +1796,8 @@ int write_index(struct index_state *istate, int newfd) continue; if (!ce_uptodate(ce) && is_racy_timestamp(istate, ce)) ce_smudge_racily_clean_entry(ce); + if (is_null_sha1(ce->sha1)) + return error("cache entry has null sha1: %s", ce->name); if (ce_write_entry(&c, newfd, ce, previous_name) < 0) return -1; } diff --git a/revision.c b/revision.c index 9e8f47a25d..442a945233 100644 --- a/revision.c +++ b/revision.c @@ -345,6 +345,7 @@ static int tree_difference = REV_TREE_SAME; static void file_add_remove(struct diff_options *options, int addremove, unsigned mode, const unsigned char *sha1, + int sha1_valid, const char *fullpath, unsigned dirty_submodule) { int diff = addremove == '+' ? REV_TREE_NEW : REV_TREE_OLD; @@ -358,6 +359,7 @@ static void file_change(struct diff_options *options, unsigned old_mode, unsigned new_mode, const unsigned char *old_sha1, const unsigned char *new_sha1, + int old_sha1_valid, int new_sha1_valid, const char *fullpath, unsigned old_dirty_submodule, unsigned new_dirty_submodule) { @@ -1861,8 +1863,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s if (revs->combine_merges) revs->ignore_merges = 0; revs->diffopt.abbrev = revs->abbrev; - if (diff_setup_done(&revs->diffopt) < 0) - die("diff_setup_done failed"); + diff_setup_done(&revs->diffopt); compile_grep_patterns(&revs->grep_filter); @@ -79,7 +79,7 @@ static void NORETURN die_verify_filename(const char *prefix, { if (!diagnose_misspelt_rev) die("%s: no such path in the working tree.\n" - "Use '-- <path>...' to specify paths that do not exist locally.", + "Use 'git <command> -- <path>...' to specify paths that do not exist locally.", arg); /* * Saying "'(icase)foo' does not exist in the index" when the @@ -92,7 +92,8 @@ static void NORETURN die_verify_filename(const char *prefix, /* ... or fall back the most general message. */ die("ambiguous argument '%s': unknown revision or path not in the working tree.\n" - "Use '--' to separate paths from revisions", arg); + "Use '--' to separate paths from revisions, like this:\n" + "'git <command> [<revision>...] -- [<file>...]'", arg); } @@ -141,7 +142,8 @@ void verify_non_filename(const char *prefix, const char *arg) if (!check_filename(prefix, arg)) return; die("ambiguous argument '%s': both revision and filename\n" - "Use '--' to separate filenames from revisions", arg); + "Use '--' to separate paths from revisions, like this:\n" + "'git <command> [<revision>...] -- [<file>...]'", arg); } /* diff --git a/sha1_file.c b/sha1_file.c index 4ccaf7ac19..af5cfbde63 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -298,7 +298,7 @@ static int link_alt_odb_entry(const char * entry, int len, const char * relative return -1; } } - if (!memcmp(ent->base, objdir, pfxlen)) { + if (!strcmp(ent->base, objdir)) { free(ent); return -1; } diff --git a/submodule.c b/submodule.c index 959d349ea7..19dc6a6c0d 100644 --- a/submodule.c +++ b/submodule.c @@ -574,8 +574,7 @@ static void calculate_changed_submodule_paths(void) DIFF_OPT_SET(&diff_opts, RECURSIVE); diff_opts.output_format |= DIFF_FORMAT_CALLBACK; diff_opts.format_callback = submodule_collect_changed_cb; - if (diff_setup_done(&diff_opts) < 0) - die("diff_setup_done failed"); + diff_setup_done(&diff_opts); diff_tree_sha1(parent->item->object.sha1, commit->object.sha1, "", &diff_opts); diffcore_std(&diff_opts); diff_flush(&diff_opts); diff --git a/t/Git-SVN/00compile.t b/t/Git-SVN/00compile.t new file mode 100644 index 0000000000..c92fee453f --- /dev/null +++ b/t/Git-SVN/00compile.t @@ -0,0 +1,14 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Test::More tests => 7; + +require_ok 'Git::SVN'; +require_ok 'Git::SVN::Utils'; +require_ok 'Git::SVN::Ra'; +require_ok 'Git::SVN::Log'; +require_ok 'Git::SVN::Migration'; +require_ok 'Git::IndexInfo'; +require_ok 'Git::SVN::GlobSpec'; diff --git a/t/Git-SVN/Utils/add_path_to_url.t b/t/Git-SVN/Utils/add_path_to_url.t new file mode 100644 index 0000000000..bfbd87845f --- /dev/null +++ b/t/Git-SVN/Utils/add_path_to_url.t @@ -0,0 +1,27 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils qw( + add_path_to_url +); + +# A reference cannot be a hash key, so we use an array. +my @tests = ( + ["http://x.com", "bar"] => 'http://x.com/bar', + ["http://x.com", ""] => 'http://x.com', + ["http://x.com/foo/", undef] => 'http://x.com/foo/', + ["http://x.com/foo/", "/bar/baz/"] => 'http://x.com/foo/bar/baz/', + ["http://x.com", 'per%cent'] => 'http://x.com/per%25cent', +); + +while(@tests) { + my($have, $want) = splice @tests, 0, 2; + + my $args = join ", ", map { qq['$_'] } map { defined($_) ? $_ : 'undef' } @$have; + my $name = "add_path_to_url($args) eq $want"; + is add_path_to_url(@$have), $want, $name; +} diff --git a/t/Git-SVN/Utils/can_compress.t b/t/Git-SVN/Utils/can_compress.t new file mode 100644 index 0000000000..d7b49b8d54 --- /dev/null +++ b/t/Git-SVN/Utils/can_compress.t @@ -0,0 +1,11 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils qw(can_compress); + +# !! is the "convert this to boolean" operator. +is !!can_compress(), !!eval { require Compress::Zlib }; diff --git a/t/Git-SVN/Utils/canonicalize_url.t b/t/Git-SVN/Utils/canonicalize_url.t new file mode 100644 index 0000000000..05795ab636 --- /dev/null +++ b/t/Git-SVN/Utils/canonicalize_url.t @@ -0,0 +1,26 @@ +#!/usr/bin/env perl + +# Test our own home rolled URL canonicalizer. Test the private one +# directly because we can't predict what the SVN API is doing to do. + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils; +my $canonicalize_url = \&Git::SVN::Utils::_canonicalize_url_ourselves; + +my %tests = ( + "http://x.com" => "http://x.com", + "http://x.com/" => "http://x.com", + "http://x.com/foo/bar" => "http://x.com/foo/bar", + "http://x.com//foo//bar//" => "http://x.com/foo/bar", + "http://x.com/ /%/" => "http://x.com/%20%20/%25", +); + +for my $arg (keys %tests) { + my $want = $tests{$arg}; + + is $canonicalize_url->($arg), $want, "canonicalize_url('$arg') => $want"; +} diff --git a/t/Git-SVN/Utils/collapse_dotdot.t b/t/Git-SVN/Utils/collapse_dotdot.t new file mode 100644 index 0000000000..1da1cce156 --- /dev/null +++ b/t/Git-SVN/Utils/collapse_dotdot.t @@ -0,0 +1,23 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils; +my $collapse_dotdot = \&Git::SVN::Utils::_collapse_dotdot; + +my %tests = ( + "foo/bar/baz" => "foo/bar/baz", + ".." => "..", + "foo/.." => "", + "/foo/bar/../../baz" => "/baz", + "deeply/.././deeply/nested" => "./deeply/nested", +); + +for my $arg (keys %tests) { + my $want = $tests{$arg}; + + is $collapse_dotdot->($arg), $want, "_collapse_dotdot('$arg') => $want"; +} diff --git a/t/Git-SVN/Utils/fatal.t b/t/Git-SVN/Utils/fatal.t new file mode 100644 index 0000000000..49e1438295 --- /dev/null +++ b/t/Git-SVN/Utils/fatal.t @@ -0,0 +1,34 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +BEGIN { + # Override exit at BEGIN time before Git::SVN::Utils is loaded + # so it will see our local exit later. + *CORE::GLOBAL::exit = sub(;$) { + return @_ ? CORE::exit($_[0]) : CORE::exit(); + }; +} + +use Git::SVN::Utils qw(fatal); + +# fatal() +{ + # Capture the exit code and prevent exit. + my $exit_status; + no warnings 'redefine'; + local *CORE::GLOBAL::exit = sub { $exit_status = $_[0] || 0 }; + + # Trap fatal's message to STDERR + my $stderr; + close STDERR; + ok open STDERR, ">", \$stderr; + + fatal "Some", "Stuff", "Happened"; + + is $stderr, "Some Stuff Happened\n"; + is $exit_status, 1; +} diff --git a/t/Git-SVN/Utils/join_paths.t b/t/Git-SVN/Utils/join_paths.t new file mode 100644 index 0000000000..d4488e7162 --- /dev/null +++ b/t/Git-SVN/Utils/join_paths.t @@ -0,0 +1,32 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils qw( + join_paths +); + +# A reference cannot be a hash key, so we use an array. +my @tests = ( + [] => '', + ["/x.com", "bar"] => '/x.com/bar', + ["x.com", ""] => 'x.com', + ["/x.com/foo/", undef, "bar"] => '/x.com/foo/bar', + ["x.com/foo/", "/bar/baz/"] => 'x.com/foo/bar/baz/', + ["foo", "bar"] => 'foo/bar', + ["/foo/bar", "baz", "/biff"] => '/foo/bar/baz/biff', + ["", undef, "."] => '.', + [] => '', + +); + +while(@tests) { + my($have, $want) = splice @tests, 0, 2; + + my $args = join ", ", map { qq['$_'] } map { defined($_) ? $_ : 'undef' } @$have; + my $name = "join_paths($args) eq '$want'"; + is join_paths(@$have), $want, $name; +} @@ -625,6 +625,15 @@ use these, and "test_set_prereq" for how to define your own. Git was compiled with USE_LIBPCRE=YesPlease. Wrap any tests that use git-grep --perl-regexp or git-grep -P in these. + - CASE_INSENSITIVE_FS + + Test is run on a case insensitive file system. + + - UTF8_NFD_TO_NFC + + Test is run on a filesystem which converts decomposed utf-8 (nfd) + to precomposed utf-8 (nfc). + Tips for Writing Tests ---------------------- diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh index 5580c22812..a1361e530c 100644 --- a/t/perf/perf-lib.sh +++ b/t/perf/perf-lib.sh @@ -163,7 +163,7 @@ test_perf () { else echo "perf $test_count - $1:" fi - for i in $(seq 1 $GIT_PERF_REPEAT_COUNT); do + for i in $(test_seq 1 $GIT_PERF_REPEAT_COUNT); do say >&3 "running: $2" if test_run_perf_ "$2" then diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh index 51f3045ba4..febc45c9cc 100755 --- a/t/t0003-attributes.sh +++ b/t/t0003-attributes.sh @@ -123,16 +123,6 @@ test_expect_success 'attribute matching is case insensitive when core.ignorecase ' -test_expect_success 'check whether FS is case-insensitive' ' - mkdir junk && - echo good >junk/CamelCase && - echo bad >junk/camelcase && - if test "$(cat junk/CamelCase)" != good - then - test_set_prereq CASE_INSENSITIVE_FS - fi -' - test_expect_success CASE_INSENSITIVE_FS 'additional case insensitivity tests' ' test_must_fail attr_check a/B/D/g "a/b/d/*" "-c core.ignorecase=0" && test_must_fail attr_check A/B/D/NO "a/b/d/*" "-c core.ignorecase=0" && diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh index 1542cf6a13..78816d9d93 100755 --- a/t/t0050-filesystem.sh +++ b/t/t0050-filesystem.sh @@ -7,48 +7,26 @@ test_description='Various filesystem issues' auml=$(printf '\303\244') aumlcdiar=$(printf '\141\314\210') -case_insensitive= -unibad= -no_symlinks= -test_expect_success 'see what we expect' ' - - test_case=test_expect_success && - test_unicode=test_expect_success && - mkdir junk && - echo good >junk/CamelCase && - echo bad >junk/camelcase && - if test "$(cat junk/CamelCase)" != good - then - test_case=test_expect_failure && - case_insensitive=t - fi && - rm -fr junk && - mkdir junk && - >junk/"$auml" && - case "$(cd junk && echo *)" in - "$aumlcdiar") - test_unicode=test_expect_failure && - unibad=t - ;; - *) ;; - esac && - rm -fr junk && - { - ln -s x y 2> /dev/null && - test -h y 2> /dev/null || - no_symlinks=1 && - rm -f y - } -' - -test "$case_insensitive" && +if test_have_prereq CASE_INSENSITIVE_FS +then say "will test on a case insensitive filesystem" -test "$unibad" && + test_case=test_expect_failure +else + test_case=test_expect_success +fi + +if test_have_prereq UTF8_NFD_TO_NFC +then say "will test on a unicode corrupting filesystem" -test "$no_symlinks" && + test_unicode=test_expect_failure +else + test_unicode=test_expect_success +fi + +test_have_prereq SYMLINKS || say "will test on a filesystem lacking symbolic links" -if test "$case_insensitive" +if test_have_prereq CASE_INSENSITIVE_FS then test_expect_success "detection of case insensitive filesystem during repo init" ' @@ -62,18 +40,18 @@ test_expect_success "detection of case insensitive filesystem during repo init" ' fi -if test "$no_symlinks" +if test_have_prereq SYMLINKS then test_expect_success "detection of filesystem w/o symlink support during repo init" ' - v=$(git config --bool core.symlinks) && - test "$v" = false + test_must_fail git config --bool core.symlinks || + test "$(git config --bool core.symlinks)" = true ' else test_expect_success "detection of filesystem w/o symlink support during repo init" ' - test_must_fail git config --bool core.symlinks || - test "$(git config --bool core.symlinks)" = true + v=$(git config --bool core.symlinks) && + test "$v" = false ' fi diff --git a/t/t0201-gettext-fallbacks.sh b/t/t0201-gettext-fallbacks.sh index 52b1c27c2c..5d80a985fb 100755 --- a/t/t0201-gettext-fallbacks.sh +++ b/t/t0201-gettext-fallbacks.sh @@ -51,16 +51,16 @@ test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate v test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces' ' cmdline="git am" && export cmdline; - printf "When you have resolved this problem run git am --resolved." >expect && - eval_gettext "When you have resolved this problem run \$cmdline --resolved." >actual + printf "When you have resolved this problem, run git am --resolved." >expect && + eval_gettext "When you have resolved this problem, run \$cmdline --resolved." >actual test_i18ncmp expect actual ' test_expect_success 'eval_gettext: our eval_gettext() fallback can interpolate variables with spaces and quotes' ' cmdline="git am" && export cmdline; - printf "When you have resolved this problem run \"git am --resolved\"." >expect && - eval_gettext "When you have resolved this problem run \"\$cmdline --resolved\"." >actual + printf "When you have resolved this problem, run \"git am --resolved\"." >expect && + eval_gettext "When you have resolved this problem, run \"\$cmdline --resolved\"." >actual test_i18ncmp expect actual ' diff --git a/t/t1100-commit-tree-options.sh b/t/t1100-commit-tree-options.sh index a3b77239f4..f8457f9d14 100755 --- a/t/t1100-commit-tree-options.sh +++ b/t/t1100-commit-tree-options.sh @@ -47,6 +47,7 @@ test_expect_success \ test_expect_success 'flags and then non flags' ' + test_tick && echo comment text | git commit-tree $(cat treeid) >commitid && echo comment text | diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index 5b79c51b8c..bf7a2cd6fb 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -213,4 +213,30 @@ test_expect_success 'rev-list --verify-objects with bad sha1' ' grep -q "error: sha1 mismatch 63ffffffffffffffffffffffffffffffffffffff" out ' +_bz='\0' +_bz5="$_bz$_bz$_bz$_bz$_bz" +_bz20="$_bz5$_bz5$_bz5$_bz5" + +test_expect_success 'fsck notices blob entry pointing to null sha1' ' + (git init null-blob && + cd null-blob && + sha=$(printf "100644 file$_bz$_bz20" | + git hash-object -w --stdin -t tree) && + git fsck 2>out && + cat out && + grep "warning.*null sha1" out + ) +' + +test_expect_success 'fsck notices submodule entry pointing to null sha1' ' + (git init null-commit && + cd null-commit && + sha=$(printf "160000 submodule$_bz$_bz20" | + git hash-object -w --stdin -t tree) && + git fsck 2>out && + cat out && + grep "warning.*null sha1" out + ) +' + test_done diff --git a/t/t2107-update-index-basic.sh b/t/t2107-update-index-basic.sh index 809fafe208..0dbbb00d74 100755 --- a/t/t2107-update-index-basic.sh +++ b/t/t2107-update-index-basic.sh @@ -29,4 +29,23 @@ test_expect_success 'update-index -h with corrupt index' ' grep "[Uu]sage: git update-index" broken/usage ' +test_expect_success '--cacheinfo does not accept blob null sha1' ' + echo content >file && + git add file && + git rev-parse :file >expect && + test_must_fail git update-index --cacheinfo 100644 $_z40 file && + git rev-parse :file >actual && + test_cmp expect actual +' + +test_expect_success '--cacheinfo does not accept gitlink null sha1' ' + git init submodule && + (cd submodule && test_commit foo) && + git add submodule && + git rev-parse :submodule >expect && + test_must_fail git update-index --cacheinfo 160000 $_z40 submodule && + git rev-parse :submodule >actual && + test_cmp expect actual +' + test_done diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index 7788ae02ad..1de0ebda25 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -68,24 +68,24 @@ test_expect_success 'rebase against master' ' test_expect_success 'rebase against master twice' ' git rebase master >out && - grep "Current branch my-topic-branch is up to date" out + test_i18ngrep "Current branch my-topic-branch is up to date" out ' test_expect_success 'rebase against master twice with --force' ' git rebase --force-rebase master >out && - grep "Current branch my-topic-branch is up to date, rebase forced" out + test_i18ngrep "Current branch my-topic-branch is up to date, rebase forced" out ' test_expect_success 'rebase against master twice from another branch' ' git checkout my-topic-branch^ && git rebase master my-topic-branch >out && - grep "Current branch my-topic-branch is up to date" out + test_i18ngrep "Current branch my-topic-branch is up to date" out ' test_expect_success 'rebase fast-forward to master' ' git checkout my-topic-branch^ && git rebase my-topic-branch >out && - grep "Fast-forwarded HEAD to my-topic-branch" out + test_i18ngrep "Fast-forwarded HEAD to my-topic-branch" out ' test_expect_success 'the rebase operation should not have destroyed author information' ' diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 3f75d328de..7304b663c3 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -858,7 +858,7 @@ test_expect_success 'rebase -ix with --autosquash' ' test_expect_success 'rebase --exec without -i shows error message' ' git reset --hard execute && test_must_fail git rebase --exec "git show HEAD" HEAD~2 2>actual && - echo "--exec option must be used with --interactive option" >expected && + echo "The --exec option must be used with the --interactive option" >expected && test_i18ncmp expected actual ' diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh index 6898377910..e6a9a0d436 100755 --- a/t/t3406-rebase-message.sh +++ b/t/t3406-rebase-message.sh @@ -62,9 +62,16 @@ test_expect_success 'rebase -n overrides config rebase.stat config' ' ! grep "^ fileX | *1 +$" diffstat.txt ' +# Output to stderr: +# +# "Does not point to a valid commit: invalid-ref" +# +# NEEDSWORK: This "grep" is fine in real non-C locales, but +# GETTEXT_POISON poisons the refname along with the enclosing +# error message. test_expect_success 'rebase --onto outputs the invalid ref' ' test_must_fail git rebase --onto invalid-ref HEAD HEAD 2>err && - grep "invalid-ref" err + test_i18ngrep "invalid-ref" err ' test_done diff --git a/t/t3910-mac-os-precompose.sh b/t/t3910-mac-os-precompose.sh index 88b7a20c11..5fe57c5438 100755 --- a/t/t3910-mac-os-precompose.sh +++ b/t/t3910-mac-os-precompose.sh @@ -7,158 +7,147 @@ test_description='utf-8 decomposed (nfd) converted to precomposed (nfc)' . ./test-lib.sh +if ! test_have_prereq UTF8_NFD_TO_NFC +then + skip_all="filesystem does not corrupt utf-8" + test_done +fi + +# create utf-8 variables Adiarnfc=`printf '\303\204'` Adiarnfd=`printf 'A\314\210'` -# check if the feature is compiled in -mkdir junk && ->junk/"$Adiarnfc" && -case "$(cd junk && echo *)" in - "$Adiarnfd") - test_nfd=1 - ;; - *) ;; -esac -rm -rf junk +Odiarnfc=`printf '\303\226'` +Odiarnfd=`printf 'O\314\210'` +AEligatu=`printf '\303\206'` +Invalidu=`printf '\303\377'` -if test "$test_nfd" -then - # create more utf-8 variables - Odiarnfc=`printf '\303\226'` - Odiarnfd=`printf 'O\314\210'` - AEligatu=`printf '\303\206'` - Invalidu=`printf '\303\377'` +#Create a string with 255 bytes (decomposed) +Alongd=$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd #21 Byte +Alongd=$Alongd$Alongd$Alongd #63 Byte +Alongd=$Alongd$Alongd$Alongd$Alongd$Adiarnfd #255 Byte +#Create a string with 254 bytes (precomposed) +Alongc=$AEligatu$AEligatu$AEligatu$AEligatu$AEligatu #10 Byte +Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc #50 Byte +Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc #250 Byte +Alongc=$Alongc$AEligatu$AEligatu #254 Byte - #Create a string with 255 bytes (decomposed) - Alongd=$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd #21 Byte - Alongd=$Alongd$Alongd$Alongd #63 Byte - Alongd=$Alongd$Alongd$Alongd$Alongd$Adiarnfd #255 Byte - - #Create a string with 254 bytes (precomposed) - Alongc=$AEligatu$AEligatu$AEligatu$AEligatu$AEligatu #10 Byte - Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc #50 Byte - Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc #250 Byte - Alongc=$Alongc$AEligatu$AEligatu #254 Byte - - test_expect_success "detect if nfd needed" ' - precomposeunicode=`git config core.precomposeunicode` && - test "$precomposeunicode" = false && - git config core.precomposeunicode true - ' - test_expect_success "setup" ' - >x && - git add x && - git commit -m "1st commit" && - git rm x && - git commit -m "rm x" - ' - test_expect_success "setup case mac" ' - git checkout -b mac_os - ' - # This will test nfd2nfc in readdir() - test_expect_success "add file Adiarnfc" ' - echo f.Adiarnfc >f.$Adiarnfc && - git add f.$Adiarnfc && - git commit -m "add f.$Adiarnfc" - ' - # This will test nfd2nfc in git stage() - test_expect_success "stage file d.Adiarnfd/f.Adiarnfd" ' - mkdir d.$Adiarnfd && - echo d.$Adiarnfd/f.$Adiarnfd >d.$Adiarnfd/f.$Adiarnfd && - git stage d.$Adiarnfd/f.$Adiarnfd && - git commit -m "add d.$Adiarnfd/f.$Adiarnfd" - ' - test_expect_success "add link Adiarnfc" ' - ln -s d.$Adiarnfd/f.$Adiarnfd l.$Adiarnfc && - git add l.$Adiarnfc && - git commit -m "add l.Adiarnfc" - ' - # This will test git log - test_expect_success "git log f.Adiar" ' - git log f.$Adiarnfc > f.Adiarnfc.log && - git log f.$Adiarnfd > f.Adiarnfd.log && - test -s f.Adiarnfc.log && - test -s f.Adiarnfd.log && - test_cmp f.Adiarnfc.log f.Adiarnfd.log && - rm f.Adiarnfc.log f.Adiarnfd.log - ' - # This will test git ls-files - test_expect_success "git lsfiles f.Adiar" ' - git ls-files f.$Adiarnfc > f.Adiarnfc.log && - git ls-files f.$Adiarnfd > f.Adiarnfd.log && - test -s f.Adiarnfc.log && - test -s f.Adiarnfd.log && - test_cmp f.Adiarnfc.log f.Adiarnfd.log && - rm f.Adiarnfc.log f.Adiarnfd.log - ' - # This will test git mv - test_expect_success "git mv" ' - git mv f.$Adiarnfd f.$Odiarnfc && - git mv d.$Adiarnfd d.$Odiarnfc && - git mv l.$Adiarnfd l.$Odiarnfc && - git commit -m "mv Adiarnfd Odiarnfc" - ' - # Files can be checked out as nfc - # And the link has been corrected from nfd to nfc - test_expect_success "git checkout nfc" ' - rm f.$Odiarnfc && - git checkout f.$Odiarnfc - ' - # Make it possible to checkout files with their NFD names - test_expect_success "git checkout file nfd" ' - rm -f f.* && - git checkout f.$Odiarnfd - ' - # Make it possible to checkout links with their NFD names - test_expect_success "git checkout link nfd" ' - rm l.* && - git checkout l.$Odiarnfd - ' - test_expect_success "setup case mac2" ' - git checkout master && - git reset --hard && - git checkout -b mac_os_2 - ' - # This will test nfd2nfc in git commit - test_expect_success "commit file d2.Adiarnfd/f.Adiarnfd" ' - mkdir d2.$Adiarnfd && - echo d2.$Adiarnfd/f.$Adiarnfd >d2.$Adiarnfd/f.$Adiarnfd && - git add d2.$Adiarnfd/f.$Adiarnfd && - git commit -m "add d2.$Adiarnfd/f.$Adiarnfd" -- d2.$Adiarnfd/f.$Adiarnfd - ' - test_expect_success "setup for long decomposed filename" ' - git checkout master && - git reset --hard && - git checkout -b mac_os_long_nfd_fn - ' - test_expect_success "Add long decomposed filename" ' - echo longd >$Alongd && - git add * && - git commit -m "Long filename" - ' - test_expect_success "setup for long precomposed filename" ' - git checkout master && - git reset --hard && - git checkout -b mac_os_long_nfc_fn - ' - test_expect_success "Add long precomposed filename" ' - echo longc >$Alongc && - git add * && - git commit -m "Long filename" - ' - # Test if the global core.precomposeunicode stops autosensing - # Must be the last test case - test_expect_success "respect git config --global core.precomposeunicode" ' - git config --global core.precomposeunicode true && - rm -rf .git && - git init && - precomposeunicode=`git config core.precomposeunicode` && - test "$precomposeunicode" = "true" - ' -else - say "Skipping nfc/nfd tests" -fi +test_expect_success "detect if nfd needed" ' + precomposeunicode=`git config core.precomposeunicode` && + test "$precomposeunicode" = false && + git config core.precomposeunicode true +' +test_expect_success "setup" ' + >x && + git add x && + git commit -m "1st commit" && + git rm x && + git commit -m "rm x" +' +test_expect_success "setup case mac" ' + git checkout -b mac_os +' +# This will test nfd2nfc in readdir() +test_expect_success "add file Adiarnfc" ' + echo f.Adiarnfc >f.$Adiarnfc && + git add f.$Adiarnfc && + git commit -m "add f.$Adiarnfc" +' +# This will test nfd2nfc in git stage() +test_expect_success "stage file d.Adiarnfd/f.Adiarnfd" ' + mkdir d.$Adiarnfd && + echo d.$Adiarnfd/f.$Adiarnfd >d.$Adiarnfd/f.$Adiarnfd && + git stage d.$Adiarnfd/f.$Adiarnfd && + git commit -m "add d.$Adiarnfd/f.$Adiarnfd" +' +test_expect_success "add link Adiarnfc" ' + ln -s d.$Adiarnfd/f.$Adiarnfd l.$Adiarnfc && + git add l.$Adiarnfc && + git commit -m "add l.Adiarnfc" +' +# This will test git log +test_expect_success "git log f.Adiar" ' + git log f.$Adiarnfc > f.Adiarnfc.log && + git log f.$Adiarnfd > f.Adiarnfd.log && + test -s f.Adiarnfc.log && + test -s f.Adiarnfd.log && + test_cmp f.Adiarnfc.log f.Adiarnfd.log && + rm f.Adiarnfc.log f.Adiarnfd.log +' +# This will test git ls-files +test_expect_success "git lsfiles f.Adiar" ' + git ls-files f.$Adiarnfc > f.Adiarnfc.log && + git ls-files f.$Adiarnfd > f.Adiarnfd.log && + test -s f.Adiarnfc.log && + test -s f.Adiarnfd.log && + test_cmp f.Adiarnfc.log f.Adiarnfd.log && + rm f.Adiarnfc.log f.Adiarnfd.log +' +# This will test git mv +test_expect_success "git mv" ' + git mv f.$Adiarnfd f.$Odiarnfc && + git mv d.$Adiarnfd d.$Odiarnfc && + git mv l.$Adiarnfd l.$Odiarnfc && + git commit -m "mv Adiarnfd Odiarnfc" +' +# Files can be checked out as nfc +# And the link has been corrected from nfd to nfc +test_expect_success "git checkout nfc" ' + rm f.$Odiarnfc && + git checkout f.$Odiarnfc +' +# Make it possible to checkout files with their NFD names +test_expect_success "git checkout file nfd" ' + rm -f f.* && + git checkout f.$Odiarnfd +' +# Make it possible to checkout links with their NFD names +test_expect_success "git checkout link nfd" ' + rm l.* && + git checkout l.$Odiarnfd +' +test_expect_success "setup case mac2" ' + git checkout master && + git reset --hard && + git checkout -b mac_os_2 +' +# This will test nfd2nfc in git commit +test_expect_success "commit file d2.Adiarnfd/f.Adiarnfd" ' + mkdir d2.$Adiarnfd && + echo d2.$Adiarnfd/f.$Adiarnfd >d2.$Adiarnfd/f.$Adiarnfd && + git add d2.$Adiarnfd/f.$Adiarnfd && + git commit -m "add d2.$Adiarnfd/f.$Adiarnfd" -- d2.$Adiarnfd/f.$Adiarnfd +' +test_expect_success "setup for long decomposed filename" ' + git checkout master && + git reset --hard && + git checkout -b mac_os_long_nfd_fn +' +test_expect_success "Add long decomposed filename" ' + echo longd >$Alongd && + git add * && + git commit -m "Long filename" +' +test_expect_success "setup for long precomposed filename" ' + git checkout master && + git reset --hard && + git checkout -b mac_os_long_nfc_fn +' +test_expect_success "Add long precomposed filename" ' + echo longc >$Alongc && + git add * && + git commit -m "Long filename" +' +# Test if the global core.precomposeunicode stops autosensing +# Must be the last test case +test_expect_success "respect git config --global core.precomposeunicode" ' + git config --global core.precomposeunicode true && + rm -rf .git && + git init && + precomposeunicode=`git config core.precomposeunicode` && + test "$precomposeunicode" = "true" +' test_done diff --git a/t/t4022-diff-rewrite.sh b/t/t4022-diff-rewrite.sh index c00a94b9ba..2d030a4ec3 100755 --- a/t/t4022-diff-rewrite.sh +++ b/t/t4022-diff-rewrite.sh @@ -66,5 +66,35 @@ test_expect_success 'suppress deletion diff with -B -D' ' grep -v "Linus Torvalds" actual ' +test_expect_success 'prepare a file that ends with an incomplete line' ' + test_seq 1 99 >seq && + printf 100 >>seq && + git add seq && + git commit seq -m seq +' + +test_expect_success 'rewrite the middle 90% of sequence file and terminate with newline' ' + test_seq 1 5 >seq && + test_seq 9331 9420 >>seq && + test_seq 96 100 >>seq +' + +test_expect_success 'confirm that sequence file is considered a rewrite' ' + git diff -B seq >res && + grep "dissimilarity index" res +' + +test_expect_success 'no newline at eof is on its own line without -B' ' + git diff seq >res && + grep "^\\\\ " res && + ! grep "^..*\\\\ " res +' + +test_expect_success 'no newline at eof is on its own line with -B' ' + git diff -B seq >res && + grep "^\\\\ " res && + ! grep "^..*\\\\ " res +' + test_done diff --git a/t/t4054-diff-bogus-tree.sh b/t/t4054-diff-bogus-tree.sh new file mode 100755 index 0000000000..0843c87890 --- /dev/null +++ b/t/t4054-diff-bogus-tree.sh @@ -0,0 +1,83 @@ +#!/bin/sh + +test_description='test diff with a bogus tree containing the null sha1' +. ./test-lib.sh + +empty_tree=4b825dc642cb6eb9a060e54bf8d69288fbee4904 + +test_expect_success 'create bogus tree' ' + bogus_tree=$( + printf "100644 fooQQQQQQQQQQQQQQQQQQQQQ" | + q_to_nul | + git hash-object -w --stdin -t tree + ) +' + +test_expect_success 'create tree with matching file' ' + echo bar >foo && + git add foo && + good_tree=$(git write-tree) + blob=$(git rev-parse :foo) +' + +test_expect_success 'raw diff shows null sha1 (addition)' ' + echo ":000000 100644 $_z40 $_z40 A foo" >expect && + git diff-tree $empty_tree $bogus_tree >actual && + test_cmp expect actual +' + +test_expect_success 'raw diff shows null sha1 (removal)' ' + echo ":100644 000000 $_z40 $_z40 D foo" >expect && + git diff-tree $bogus_tree $empty_tree >actual && + test_cmp expect actual +' + +test_expect_success 'raw diff shows null sha1 (modification)' ' + echo ":100644 100644 $blob $_z40 M foo" >expect && + git diff-tree $good_tree $bogus_tree >actual && + test_cmp expect actual +' + +test_expect_success 'raw diff shows null sha1 (other direction)' ' + echo ":100644 100644 $_z40 $blob M foo" >expect && + git diff-tree $bogus_tree $good_tree >actual && + test_cmp expect actual +' + +test_expect_success 'raw diff shows null sha1 (reverse)' ' + echo ":100644 100644 $_z40 $blob M foo" >expect && + git diff-tree -R $good_tree $bogus_tree >actual && + test_cmp expect actual +' + +test_expect_success 'raw diff shows null sha1 (index)' ' + echo ":100644 100644 $_z40 $blob M foo" >expect && + git diff-index $bogus_tree >actual && + test_cmp expect actual +' + +test_expect_success 'patch fails due to bogus sha1 (addition)' ' + test_must_fail git diff-tree -p $empty_tree $bogus_tree +' + +test_expect_success 'patch fails due to bogus sha1 (removal)' ' + test_must_fail git diff-tree -p $bogus_tree $empty_tree +' + +test_expect_success 'patch fails due to bogus sha1 (modification)' ' + test_must_fail git diff-tree -p $good_tree $bogus_tree +' + +test_expect_success 'patch fails due to bogus sha1 (other direction)' ' + test_must_fail git diff-tree -p $bogus_tree $good_tree +' + +test_expect_success 'patch fails due to bogus sha1 (reverse)' ' + test_must_fail git diff-tree -R -p $good_tree $bogus_tree +' + +test_expect_success 'patch fails due to bogus sha1 (index)' ' + test_must_fail git diff-index -p $bogus_tree +' + +test_done diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh index 0eace37a03..250c720c14 100755 --- a/t/t5400-send-pack.sh +++ b/t/t5400-send-pack.sh @@ -145,6 +145,41 @@ test_expect_success 'push --all excludes remote-tracking hierarchy' ' ) ' +test_expect_success 'receive-pack runs auto-gc in remote repo' ' + rm -rf parent child && + git init parent && + ( + # Setup a repo with 2 packs + cd parent && + echo "Some text" >file.txt && + git add . && + git commit -m "Initial commit" && + git repack -adl && + echo "Some more text" >>file.txt && + git commit -a -m "Second commit" && + git repack + ) && + cp -a parent child && + ( + # Set the child to auto-pack if more than one pack exists + cd child && + git config gc.autopacklimit 1 && + git branch test_auto_gc && + # And create a file that follows the temporary object naming + # convention for the auto-gc to remove + : >.git/objects/tmp_test_object && + test-chmtime =-1209601 .git/objects/tmp_test_object + ) && + ( + cd parent && + echo "Even more text" >>file.txt && + git commit -a -m "Third commit" && + git send-pack ../child HEAD:refs/heads/test_auto_gc >output 2>&1 && + grep "Auto packing the repository for optimum performance." output + ) && + test ! -e child/.git/objects/tmp_test_object +' + rewound_push_setup() { rm -rf parent child && mkdir parent && diff --git a/t/t5541-http-push.sh b/t/t5541-http-push.sh index 312e484090..624633aced 100755 --- a/t/t5541-http-push.sh +++ b/t/t5541-http-push.sh @@ -64,7 +64,10 @@ test_expect_success 'no empty path components' ' test_expect_success 'clone remote repository' ' rm -rf test_repo_clone && - git clone $HTTPD_URL/smart/test_repo.git test_repo_clone + git clone $HTTPD_URL/smart/test_repo.git test_repo_clone && + ( + cd test_repo_clone && git config push.default matching + ) ' test_expect_success 'push to remote repository (standard)' ' diff --git a/t/t5551-http-fetch.sh b/t/t5551-http-fetch.sh index fadf2f258e..91eaf53d1d 100755 --- a/t/t5551-http-fetch.sh +++ b/t/t5551-http-fetch.sh @@ -114,7 +114,7 @@ test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE test_expect_success EXPENSIVE 'create 50,000 tags in the repo' ' ( cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" && - for i in `seq 50000` + for i in `test_seq 50000` do echo "commit refs/heads/too-many-refs" echo "mark :$i" diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh index 1104249182..c680f789a7 100755 --- a/t/t6022-merge-rename.sh +++ b/t/t6022-merge-rename.sh @@ -242,10 +242,10 @@ test_expect_success 'merge of identical changes in a renamed file' ' rm -f A M N && git reset --hard && git checkout change+rename && - GIT_MERGE_VERBOSITY=3 git merge change | grep "^Skipped B" && + GIT_MERGE_VERBOSITY=3 git merge change | test_i18ngrep "^Skipped B" && git reset --hard HEAD^ && git checkout change && - GIT_MERGE_VERBOSITY=3 git merge change+rename | grep "^Skipped B" + GIT_MERGE_VERBOSITY=3 git merge change+rename | test_i18ngrep "^Skipped B" ' test_expect_success 'setup for rename + d/f conflicts' ' @@ -303,9 +303,9 @@ test_expect_success 'Rename+D/F conflict; renamed file merges but dir in way' ' git checkout -q renamed-file-has-no-conflicts^0 && test_must_fail git merge --strategy=recursive dir-in-way >output && - grep "CONFLICT (modify/delete): dir/file-in-the-way" output && - grep "Auto-merging dir" output && - grep "Adding as dir~HEAD instead" output && + test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output && + test_i18ngrep "Auto-merging dir" output && + test_i18ngrep "Adding as dir~HEAD instead" output && test 3 -eq "$(git ls-files -u | wc -l)" && test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" && @@ -325,9 +325,9 @@ test_expect_success 'Same as previous, but merged other way' ' test_must_fail git merge --strategy=recursive renamed-file-has-no-conflicts >output 2>errors && ! grep "error: refusing to lose untracked file at" errors && - grep "CONFLICT (modify/delete): dir/file-in-the-way" output && - grep "Auto-merging dir" output && - grep "Adding as dir~renamed-file-has-no-conflicts instead" output && + test_i18ngrep "CONFLICT (modify/delete): dir/file-in-the-way" output && + test_i18ngrep "Auto-merging dir" output && + test_i18ngrep "Adding as dir~renamed-file-has-no-conflicts instead" output && test 3 -eq "$(git ls-files -u | wc -l)" && test 2 -eq "$(git ls-files -u dir/file-in-the-way | wc -l)" && diff --git a/t/t6042-merge-rename-corner-cases.sh b/t/t6042-merge-rename-corner-cases.sh index 466fa3804b..411550d2b6 100755 --- a/t/t6042-merge-rename-corner-cases.sh +++ b/t/t6042-merge-rename-corner-cases.sh @@ -380,7 +380,7 @@ test_expect_success 'handle rename/rename (2to1) conflict correctly' ' git checkout B^0 && test_must_fail git merge -s recursive C^0 >out && - grep "CONFLICT (rename/rename)" out && + test_i18ngrep "CONFLICT (rename/rename)" out && test 2 -eq $(git ls-files -s | wc -l) && test 2 -eq $(git ls-files -u | wc -l) && diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh index ce61d4c0fa..646298b212 100755 --- a/t/t7406-submodule-update.sh +++ b/t/t7406-submodule-update.sh @@ -367,7 +367,7 @@ test_expect_success 'submodule update continues after checkout error' ' git submodule init && git commit -am "new_submodule" && (cd submodule2 && - git rev-parse --max-count=1 HEAD > ../expect + git rev-parse --verify HEAD >../expect ) && (cd submodule && test_commit "update_submodule" file @@ -384,7 +384,7 @@ test_expect_success 'submodule update continues after checkout error' ' git checkout HEAD^ && test_must_fail git submodule update && (cd submodule2 && - git rev-parse --max-count=1 HEAD > ../actual + git rev-parse --verify HEAD >../actual ) && test_cmp expect actual ) @@ -413,7 +413,7 @@ test_expect_success 'submodule update continues after recursive checkout error' test_commit "update_submodule_again_again" file ) && (cd submodule2 && - git rev-parse --max-count=1 HEAD > ../expect && + git rev-parse --verify HEAD >../expect && test_commit "update_submodule2_again" file ) && git add submodule && @@ -428,7 +428,7 @@ test_expect_success 'submodule update continues after recursive checkout error' ) && test_must_fail git submodule update --recursive && (cd submodule2 && - git rev-parse --max-count=1 HEAD > ../actual + git rev-parse --verify HEAD >../actual ) && test_cmp expect actual ) @@ -460,12 +460,12 @@ test_expect_success 'submodule update exit immediately in case of merge conflict ) && git checkout HEAD^ && (cd submodule2 && - git rev-parse --max-count=1 HEAD > ../expect + git rev-parse --verify HEAD >../expect ) && git config submodule.submodule.update merge && test_must_fail git submodule update && (cd submodule2 && - git rev-parse --max-count=1 HEAD > ../actual + git rev-parse --verify HEAD >../actual ) && test_cmp expect actual ) @@ -495,12 +495,12 @@ test_expect_success 'submodule update exit immediately after recursive rebase er ) && git checkout HEAD^ && (cd submodule2 && - git rev-parse --max-count=1 HEAD > ../expect + git rev-parse --verify HEAD >../expect ) && git config submodule.submodule.update rebase && test_must_fail git submodule update && (cd submodule2 && - git rev-parse --max-count=1 HEAD > ../actual + git rev-parse --verify HEAD >../actual ) && test_cmp expect actual ) diff --git a/t/t7409-submodule-detached-worktree.sh b/t/t7409-submodule-detached-worktree.sh new file mode 100755 index 0000000000..2fec13dcd3 --- /dev/null +++ b/t/t7409-submodule-detached-worktree.sh @@ -0,0 +1,78 @@ +#!/bin/sh +# +# Copyright (c) 2012 Daniel Graña +# + +test_description='Test submodules on detached working tree + +This test verifies that "git submodule" initialization, update and addition works +on detahced working trees +' + +TEST_NO_CREATE_REPO=1 +. ./test-lib.sh + +test_expect_success 'submodule on detached working tree' ' + git init --bare remote && + test_create_repo bundle1 && + ( + cd bundle1 && + test_commit "shoot" && + git rev-parse --verify HEAD >../expect + ) && + mkdir home && + ( + cd home && + export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" && + git clone --bare ../remote .dotfiles && + git submodule add ../bundle1 .vim/bundle/sogood && + test_commit "sogood" && + ( + unset GIT_WORK_TREE GIT_DIR && + cd .vim/bundle/sogood && + git rev-parse --verify HEAD >actual && + test_cmp ../../../../expect actual + ) && + git push origin master + ) && + mkdir home2 && + ( + cd home2 && + git clone --bare ../remote .dotfiles && + export GIT_WORK_TREE="$(pwd)" GIT_DIR="$(pwd)/.dotfiles" && + git checkout master && + git submodule update --init && + ( + unset GIT_WORK_TREE GIT_DIR && + cd .vim/bundle/sogood && + git rev-parse --verify HEAD >actual && + test_cmp ../../../../expect actual + ) + ) +' + +test_expect_success 'submodule on detached working pointed by core.worktree' ' + mkdir home3 && + ( + cd home3 && + export GIT_DIR="$(pwd)/.dotfiles" && + git clone --bare ../remote "$GIT_DIR" && + git config core.bare false && + git config core.worktree .. && + git checkout master && + git submodule add ../bundle1 .vim/bundle/dupe && + test_commit "dupe" && + git push origin master + ) && + ( + cd home && + export GIT_DIR="$(pwd)/.dotfiles" && + git config core.bare false && + git config core.worktree .. && + git pull && + git submodule update --init && + test -f .vim/bundle/dupe/shoot.t + ) +' + +test_done diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh index 181456aa9a..deb187eb7b 100755 --- a/t/t7502-commit.sh +++ b/t/t7502-commit.sh @@ -235,44 +235,56 @@ test_expect_success 'cleanup commit messages (strip,-F,-e): output' ' test_i18ncmp expect actual ' -echo "# -# Author: $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> -#" >> expect - -test_expect_success 'author different from committer' ' +test_expect_success 'message shows author when it is not equal to committer' ' echo >>negative && - test_might_fail git commit -e -m "sample" && - head -n 7 .git/COMMIT_EDITMSG >actual && - test_i18ncmp expect actual + git commit -e -m "sample" -a && + test_i18ngrep \ + "^# Author: *A U Thor <author@example.com>\$" \ + .git/COMMIT_EDITMSG ' -mv expect expect.tmp -sed '$d' < expect.tmp > expect -rm -f expect.tmp -echo "# Committer: -#" >> expect +test_expect_success 'setup auto-ident prerequisite' ' + if (sane_unset GIT_COMMITTER_EMAIL && + sane_unset GIT_COMMITTER_NAME && + git var GIT_COMMITTER_IDENT); then + test_set_prereq AUTOIDENT + else + test_set_prereq NOAUTOIDENT + fi +' -test_expect_success 'committer is automatic' ' +test_expect_success AUTOIDENT 'message shows committer when it is automatic' ' echo >>negative && ( sane_unset GIT_COMMITTER_EMAIL && sane_unset GIT_COMMITTER_NAME && - # must fail because there is no change - test_must_fail git commit -e -m "sample" + git commit -e -m "sample" -a ) && - head -n 8 .git/COMMIT_EDITMSG | \ - sed "s/^# Committer: .*/# Committer:/" >actual - test_i18ncmp expect actual + # the ident is calculated from the system, so we cannot + # check the actual value, only that it is there + test_i18ngrep "^# Committer: " .git/COMMIT_EDITMSG ' -pwd=`pwd` -cat >> .git/FAKE_EDITOR << EOF -#! /bin/sh -echo editor started > "$pwd/.git/result" +write_script .git/FAKE_EDITOR <<EOF +echo editor started > "$(pwd)/.git/result" exit 0 EOF -chmod +x .git/FAKE_EDITOR + +test_expect_success NOAUTOIDENT 'do not fire editor when committer is bogus' ' + >.git/result + >expect && + + echo >>negative && + ( + sane_unset GIT_COMMITTER_EMAIL && + sane_unset GIT_COMMITTER_NAME && + GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" && + export GIT_EDITOR && + test_must_fail git commit -e -m sample -a + ) && + test_cmp expect .git/result +' test_expect_success 'do not fire editor in the presence of conflicts' ' @@ -293,16 +305,14 @@ test_expect_success 'do not fire editor in the presence of conflicts' ' test_must_fail git cherry-pick -n master && echo "editor not started" >.git/result && ( - GIT_EDITOR="$(pwd)/.git/FAKE_EDITOR" && + GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" && export GIT_EDITOR && test_must_fail git commit ) && test "$(cat .git/result)" = "editor not started" ' -pwd=`pwd` -cat >.git/FAKE_EDITOR <<EOF -#! $SHELL_PATH +write_script .git/FAKE_EDITOR <<EOF # kill -TERM command added below. EOF @@ -339,13 +349,12 @@ test_expect_success 'A single-liner subject with a token plus colon is not a foo ' -cat >.git/FAKE_EDITOR <<EOF -#!$SHELL_PATH -mv "\$1" "\$1.orig" +write_script .git/FAKE_EDITOR <<\EOF +mv "$1" "$1.orig" ( echo message - cat "\$1.orig" -) >"\$1" + cat "$1.orig" +) >"$1" EOF echo '## Custom template' >template diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index 24e9b1974d..35d357d4c8 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -250,6 +250,84 @@ do git -c grep.extendedRegexp=true grep "a+b*c" ab >actual && test_cmp expected actual ' + + test_expect_success "grep $L with grep.patterntype=basic" ' + echo "ab:a+bc" >expected && + git -c grep.patterntype=basic grep "a+b*c" ab >actual && + test_cmp expected actual + ' + + test_expect_success "grep $L with grep.patterntype=extended" ' + echo "ab:abc" >expected && + git -c grep.patterntype=extended grep "a+b*c" ab >actual && + test_cmp expected actual + ' + + test_expect_success "grep $L with grep.patterntype=fixed" ' + echo "ab:a+b*c" >expected && + git -c grep.patterntype=fixed grep "a+b*c" ab >actual && + test_cmp expected actual + ' + + test_expect_success LIBPCRE "grep $L with grep.patterntype=perl" ' + echo "ab:a+b*c" >expected && + git -c grep.patterntype=perl grep "a\x{2b}b\x{2a}c" ab >actual && + test_cmp expected actual + ' + + test_expect_success "grep $L with grep.patternType=default and grep.extendedRegexp=true" ' + echo "ab:abc" >expected && + git \ + -c grep.patternType=default \ + -c grep.extendedRegexp=true \ + grep "a+b*c" ab >actual && + test_cmp expected actual + ' + + test_expect_success "grep $L with grep.extendedRegexp=true and grep.patternType=default" ' + echo "ab:abc" >expected && + git \ + -c grep.extendedRegexp=true \ + -c grep.patternType=default \ + grep "a+b*c" ab >actual && + test_cmp expected actual + ' + + test_expect_success 'grep $L with grep.patternType=extended and grep.extendedRegexp=false' ' + echo "ab:abc" >expected && + git \ + -c grep.patternType=extended \ + -c grep.extendedRegexp=false \ + grep "a+b*c" ab >actual && + test_cmp expected actual + ' + + test_expect_success 'grep $L with grep.patternType=basic and grep.extendedRegexp=true' ' + echo "ab:a+bc" >expected && + git \ + -c grep.patternType=basic \ + -c grep.extendedRegexp=true \ + grep "a+b*c" ab >actual && + test_cmp expected actual + ' + + test_expect_success 'grep $L with grep.extendedRegexp=false and grep.patternType=extended' ' + echo "ab:abc" >expected && + git \ + -c grep.extendedRegexp=false \ + -c grep.patternType=extended \ + grep "a+b*c" ab >actual && + test_cmp expected actual + ' + + test_expect_success 'grep $L with grep.extendedRegexp=true and grep.patternType=basic' ' + echo "ab:a+bc" >expected && + git \ + -c grep.extendedRegexp=true \ + -c grep.patternType=basic \ + grep "a+b*c" ab >actual && + test_cmp expected actual + ' done cat >expected <<EOF @@ -399,17 +477,6 @@ test_expect_success 'grep -q, silently report matches' ' test_cmp empty actual ' -# Create 1024 file names that sort between "y" and "z" to make sure -# the two files are handled by different calls to an external grep. -# This depends on MAXARGS in builtin-grep.c being 1024 or less. -c32="0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v" -test_expect_success 'grep -C1, hunk mark between files' ' - for a in $c32; do for b in $c32; do : >y-$a$b; done; done && - git add y-?? && - git grep -C1 "^[yz]" >actual && - test_cmp expected actual -' - test_expect_success 'grep -C1 hunk mark between files' ' git grep -C1 "^[yz]" >actual && test_cmp expected actual @@ -772,44 +839,147 @@ test_expect_success 'grep -G invalidpattern properly dies ' ' test_must_fail git grep -G "a[" ' +test_expect_success 'grep invalidpattern properly dies with grep.patternType=basic' ' + test_must_fail git -c grep.patterntype=basic grep "a[" +' + test_expect_success 'grep -E invalidpattern properly dies ' ' test_must_fail git grep -E "a[" ' +test_expect_success 'grep invalidpattern properly dies with grep.patternType=extended' ' + test_must_fail git -c grep.patterntype=extended grep "a[" +' + test_expect_success LIBPCRE 'grep -P invalidpattern properly dies ' ' test_must_fail git grep -P "a[" ' +test_expect_success LIBPCRE 'grep invalidpattern properly dies with grep.patternType=perl' ' + test_must_fail git -c grep.patterntype=perl grep "a[" +' + test_expect_success 'grep -G -E -F pattern' ' echo "ab:a+b*c" >expected && git grep -G -E -F "a+b*c" ab >actual && test_cmp expected actual ' +test_expect_success 'grep pattern with grep.patternType=basic, =extended, =fixed' ' + echo "ab:a+b*c" >expected && + git \ + -c grep.patterntype=basic \ + -c grep.patterntype=extended \ + -c grep.patterntype=fixed \ + grep "a+b*c" ab >actual && + test_cmp expected actual +' + test_expect_success 'grep -E -F -G pattern' ' echo "ab:a+bc" >expected && git grep -E -F -G "a+b*c" ab >actual && test_cmp expected actual ' +test_expect_success 'grep pattern with grep.patternType=extended, =fixed, =basic' ' + echo "ab:a+bc" >expected && + git \ + -c grep.patterntype=extended \ + -c grep.patterntype=fixed \ + -c grep.patterntype=basic \ + grep "a+b*c" ab >actual && + test_cmp expected actual +' + test_expect_success 'grep -F -G -E pattern' ' echo "ab:abc" >expected && git grep -F -G -E "a+b*c" ab >actual && test_cmp expected actual ' +test_expect_success 'grep pattern with grep.patternType=fixed, =basic, =extended' ' + echo "ab:abc" >expected && + git \ + -c grep.patterntype=fixed \ + -c grep.patterntype=basic \ + -c grep.patterntype=extended \ + grep "a+b*c" ab >actual && + test_cmp expected actual +' + test_expect_success 'grep -G -F -P -E pattern' ' >empty && test_must_fail git grep -G -F -P -E "a\x{2b}b\x{2a}c" ab >actual && test_cmp empty actual ' +test_expect_success 'grep pattern with grep.patternType=fixed, =basic, =perl, =extended' ' + >empty && + test_must_fail git \ + -c grep.patterntype=fixed \ + -c grep.patterntype=basic \ + -c grep.patterntype=perl \ + -c grep.patterntype=extended \ + grep "a\x{2b}b\x{2a}c" ab >actual && + test_cmp empty actual +' + test_expect_success LIBPCRE 'grep -G -F -E -P pattern' ' echo "ab:a+b*c" >expected && git grep -G -F -E -P "a\x{2b}b\x{2a}c" ab >actual && test_cmp expected actual ' +test_expect_success LIBPCRE 'grep pattern with grep.patternType=fixed, =basic, =extended, =perl' ' + echo "ab:a+b*c" >expected && + git \ + -c grep.patterntype=fixed \ + -c grep.patterntype=basic \ + -c grep.patterntype=extended \ + -c grep.patterntype=perl \ + grep "a\x{2b}b\x{2a}c" ab >actual && + test_cmp expected actual +' + +test_expect_success LIBPCRE 'grep -P pattern with grep.patternType=fixed' ' + echo "ab:a+b*c" >expected && + git \ + -c grep.patterntype=fixed \ + grep -P "a\x{2b}b\x{2a}c" ab >actual && + test_cmp expected actual +' + +test_expect_success 'grep -F pattern with grep.patternType=basic' ' + echo "ab:a+b*c" >expected && + git \ + -c grep.patterntype=basic \ + grep -F "*c" ab >actual && + test_cmp expected actual +' + +test_expect_success 'grep -G pattern with grep.patternType=fixed' ' + { + echo "ab:a+b*c" + echo "ab:a+bc" + } >expected && + git \ + -c grep.patterntype=fixed \ + grep -G "a+b" ab >actual && + test_cmp expected actual +' + +test_expect_success 'grep -E pattern with grep.patternType=fixed' ' + { + echo "ab:a+b*c" + echo "ab:a+bc" + echo "ab:abc" + } >expected && + git \ + -c grep.patterntype=fixed \ + grep -E "a+" ab >actual && + test_cmp expected actual +' + test_config() { git config "$1" "$2" && test_when_finished "git config --unset $1" diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 8c12c65c72..035122808b 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -841,6 +841,19 @@ test_expect_success $PREREQ '--compose adds MIME for utf8 subject' ' grep "^Subject: =?UTF-8?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1 ' +test_expect_success $PREREQ 'utf8 author is correctly passed on' ' + clean_fake_sendmail && + test_commit weird_author && + test_when_finished "git reset --hard HEAD^" && + git commit --amend --author "Füñný Nâmé <odd_?=mail@example.com>" && + git format-patch --stdout -1 >funny_name.patch && + git send-email --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + funny_name.patch && + grep "^From: Füñný Nâmé <odd_?=mail@example.com>" msgtxt1 +' + test_expect_success $PREREQ 'detects ambiguous reference/file conflict' ' echo master > master && git add master && diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh index 289fc313fb..ee73013eed 100755 --- a/t/t9107-git-svn-migrate.sh +++ b/t/t9107-git-svn-migrate.sh @@ -27,15 +27,17 @@ test_expect_success 'setup old-looking metadata' ' head=`git rev-parse --verify refs/heads/git-svn-HEAD^0` test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'" +svnrepo_escaped=`echo $svnrepo | sed 's/ /%20/'` + test_expect_success 'initialize old-style (v0) git svn layout' ' mkdir -p "$GIT_DIR"/git-svn/info "$GIT_DIR"/svn/info && echo "$svnrepo" > "$GIT_DIR"/git-svn/info/url && echo "$svnrepo" > "$GIT_DIR"/svn/info/url && git svn migrate && - ! test -d "$GIT_DIR"/git svn && + ! test -d "$GIT_DIR"/git-svn && git rev-parse --verify refs/${remotes_git_svn}^0 && git rev-parse --verify refs/remotes/svn^0 && - test "$(git config --get svn-remote.svn.url)" = "$svnrepo" && + test "$(git config --get svn-remote.svn.url)" = "$svnrepo_escaped" && test `git config --get svn-remote.svn.fetch` = \ ":refs/${remotes_git_svn}" ' diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh index 63fc982c8c..193d3cabdd 100755 --- a/t/t9118-git-svn-funky-branch-names.sh +++ b/t/t9118-git-svn-funky-branch-names.sh @@ -32,6 +32,11 @@ test_expect_success 'setup svnrepo' ' start_httpd ' +# SVN 1.7 will truncate "not-a%40{0]" to just "not-a". +# Look at what SVN wound up naming the branch and use that. +# Be sure to escape the @ if it shows up. +non_reflog=`svn_cmd ls "$svnrepo/pr ject/branches" | grep not-a | sed 's/\///' | sed 's/@/%40/'` + test_expect_success 'test clone with funky branch names' ' git svn clone -s "$svnrepo/pr ject" project && ( @@ -42,7 +47,7 @@ test_expect_success 'test clone with funky branch names' ' git rev-parse "refs/remotes/%2Eleading_dot" && git rev-parse "refs/remotes/trailing_dot%2E" && git rev-parse "refs/remotes/trailing_dotlock%2Elock" && - git rev-parse "refs/remotes/not-a%40{0}reflog" + git rev-parse "refs/remotes/$non_reflog" ) ' diff --git a/t/t9163-git-svn-reset-clears-caches.sh b/t/t9163-git-svn-reset-clears-caches.sh new file mode 100755 index 0000000000..cd4c662ba2 --- /dev/null +++ b/t/t9163-git-svn-reset-clears-caches.sh @@ -0,0 +1,78 @@ +#!/bin/sh +# +# Copyright (c) 2012 Peter Baumann +# + +test_description='git svn reset clears memoized caches' +. ./lib-git-svn.sh + +svn_ver="$(svn --version --quiet)" +case $svn_ver in +0.* | 1.[0-4].*) + skip_all="skipping git-svn test - SVN too old ($svn_ver)" + test_done + ;; +esac + +# ... a - b - m <- trunk +# \ / +# ... c <- branch1 +# +# SVN Commits not interesting for this test are abbreviated with "..." +# +test_expect_success 'initialize source svn repo' ' + svn_cmd mkdir -m "create trunk" "$svnrepo"/trunk && + svn_cmd mkdir -m "create branches" "$svnrepo/branches" && + svn_cmd co "$svnrepo"/trunk "$SVN_TREE" && + ( + cd "$SVN_TREE" && + touch foo && + svn_cmd add foo && + svn_cmd commit -m "a" && + svn_cmd cp -m branch "$svnrepo"/trunk "$svnrepo"/branches/branch1 && + svn_cmd switch "$svnrepo"/branches/branch1 && + touch bar && + svn_cmd add bar && + svn_cmd commit -m b && + svn_cmd switch "$svnrepo"/trunk && + touch baz && + svn_cmd add baz && + svn_cmd commit -m c && + svn_cmd up && + svn_cmd merge "$svnrepo"/branches/branch1 && + svn_cmd commit -m "m" + ) && + rm -rf "$SVN_TREE" +' + +test_expect_success 'fetch to merge-base (a)' ' + git svn init -s "$svnrepo" && + git svn fetch --revision BASE:3 +' + +# git svn rebase looses the merge commit +# +# ... a - b - m <- trunk +# \ +# ... c +# +test_expect_success 'rebase looses SVN merge (m)' ' + git svn rebase && + git svn fetch && + test 1 = $(git cat-file -p master|grep parent|wc -l) +' + +# git svn fetch creates correct history with merge commit +# +# ... a - b - m <- trunk +# \ / +# ... c <- branch1 +# +test_expect_success 'reset and fetch gets the SVN merge (m) correctly' ' + git svn reset -r 3 && + git reset --hard trunk && + git svn fetch && + test 2 = $(git cat-file -p trunk|grep parent|wc -l) +' + +test_done diff --git a/t/t9164-git-svn-dcommit-concrrent.sh b/t/t9164-git-svn-dcommit-concrrent.sh new file mode 100755 index 0000000000..aac2ddadf2 --- /dev/null +++ b/t/t9164-git-svn-dcommit-concrrent.sh @@ -0,0 +1,216 @@ +#!/bin/sh +# +# Copyright (c) 2012 Robert Luberda +# + +test_description='concurrent git svn dcommit' +. ./lib-git-svn.sh + + + +test_expect_success 'setup svn repository' ' + svn_cmd checkout "$svnrepo" work.svn && + ( + cd work.svn && + echo >file && echo > auto_updated_file + svn_cmd add file auto_updated_file && + svn_cmd commit -m "initial commit" + ) && + svn_cmd checkout "$svnrepo" work-auto-commits.svn +' +N=0 +next_N() +{ + N=$(( $N + 1 )) +} + +# Setup SVN repository hooks to emulate SVN failures or concurrent commits +# The function adds +# either pre-commit hook, which causes SVN commit given in second argument +# to fail +# or post-commit hook, which creates a new commit (a new line added to +# auto_updated_file) after given SVN commit +# The first argument contains a type of the hook +# The second argument contains a number (not SVN revision) of commit +# the hook should be applied for (each time the hook is run, the given +# number is decreased by one until it gets 0, in which case the hook +# will execute its real action) +setup_hook() +{ + hook_type="$1" # "pre-commit" or "post-commit" + skip_revs="$2" + [ "$hook_type" = "pre-commit" ] || + [ "$hook_type" = "post-commit" ] || + { echo "ERROR: invalid argument ($hook_type)" \ + "passed to setup_hook" >&2 ; return 1; } + echo "cnt=$skip_revs" > "$hook_type-counter" + rm -f "$rawsvnrepo/hooks/"*-commit # drop previous hooks + hook="$rawsvnrepo/hooks/$hook_type" + cat > "$hook" <<- 'EOF1' + #!/bin/sh + set -e + cd "$1/.." # "$1" is repository location + exec >> svn-hook.log 2>&1 + hook="$(basename "$0")" + echo "*** Executing $hook $@" + set -x + . ./$hook-counter + cnt="$(($cnt - 1))" + echo "cnt=$cnt" > ./$hook-counter + [ "$cnt" = "0" ] || exit 0 +EOF1 + if [ "$hook_type" = "pre-commit" ]; then + echo "echo 'commit disallowed' >&2; exit 1" >> "$hook" + else + echo "PATH=\"$PATH\"; export PATH" >> $hook + echo "svnconf=\"$svnconf\"" >> $hook + cat >> "$hook" <<- 'EOF2' + cd work-auto-commits.svn + svn up --config-dir "$svnconf" + echo "$$" >> auto_updated_file + svn commit --config-dir "$svnconf" \ + -m "auto-committing concurrent change" + exit 0 +EOF2 + fi + chmod 755 "$hook" +} + +check_contents() +{ + gitdir="$1" + (cd ../work.svn && svn_cmd up) && + test_cmp file ../work.svn/file && + test_cmp auto_updated_file ../work.svn/auto_updated_file +} + +test_expect_success 'check if post-commit hook creates a concurrent commit' ' + setup_hook post-commit 1 && + ( + cd work.svn && + cp auto_updated_file au_file_saved && + echo 1 >> file && + svn_cmd commit -m "changing file" && + svn_cmd up && + test_must_fail test_cmp auto_updated_file au_file_saved + ) +' + +test_expect_success 'check if pre-commit hook fails' ' + setup_hook pre-commit 2 && + ( + cd work.svn && + echo 2 >> file && + svn_cmd commit -m "changing file once again" && + echo 3 >> file && + test_must_fail svn_cmd commit -m "this commit should fail" && + svn_cmd revert file + ) +' + +test_expect_success 'dcommit error handling' ' + setup_hook pre-commit 2 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + echo 1 >> file && git commit -am "commit change $N.1" && + echo 2 >> file && git commit -am "commit change $N.2" && + echo 3 >> file && git commit -am "commit change $N.3" && + # should fail to dcommit 2nd and 3rd change + # but still should leave the repository in reasonable state + test_must_fail git svn dcommit && + git update-index --refresh && + git show HEAD~2 | grep -q git-svn-id && + ! git show HEAD~1 | grep -q git-svn-id && + ! git show HEAD | grep -q git-svn-id + ) +' + +test_expect_success 'dcommit concurrent change in non-changed file' ' + setup_hook post-commit 2 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + echo 1 >> file && git commit -am "commit change $N.1" && + echo 2 >> file && git commit -am "commit change $N.2" && + echo 3 >> file && git commit -am "commit change $N.3" && + # should rebase and leave the repository in reasonable state + git svn dcommit && + git update-index --refresh && + check_contents && + git show HEAD~3 | grep -q git-svn-id && + git show HEAD~2 | grep -q git-svn-id && + git show HEAD~1 | grep -q auto-committing && + git show HEAD | grep -q git-svn-id + ) +' + +# An utility function used in the following test +delete_first_line() +{ + file="$1" && + sed 1d < "$file" > "${file}.tmp" && + rm "$file" && + mv "${file}.tmp" "$file" +} + +test_expect_success 'dcommit concurrent non-conflicting change' ' + setup_hook post-commit 2 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + cat file >> auto_updated_file && + git commit -am "commit change $N.1" && + delete_first_line auto_updated_file && + git commit -am "commit change $N.2" && + delete_first_line auto_updated_file && + git commit -am "commit change $N.3" && + # should rebase and leave the repository in reasonable state + git svn dcommit && + git update-index --refresh && + check_contents && + git show HEAD~3 | grep -q git-svn-id && + git show HEAD~2 | grep -q git-svn-id && + git show HEAD~1 | grep -q auto-committing && + git show HEAD | grep -q git-svn-id + ) +' + +test_expect_success 'dcommit --no-rebase concurrent non-conflicting change' ' + setup_hook post-commit 2 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + cat file >> auto_updated_file && + git commit -am "commit change $N.1" && + delete_first_line auto_updated_file && + git commit -am "commit change $N.2" && + delete_first_line auto_updated_file && + git commit -am "commit change $N.3" && + # should fail as rebase is needed + test_must_fail git svn dcommit --no-rebase && + # but should leave HEAD unchanged + git update-index --refresh && + ! git show HEAD~2 | grep -q git-svn-id && + ! git show HEAD~1 | grep -q git-svn-id && + ! git show HEAD | grep -q git-svn-id + ) +' + +test_expect_success 'dcommit fails on concurrent conflicting change' ' + setup_hook post-commit 1 && + next_N && git svn clone "$svnrepo" work$N.git && + ( + cd work$N.git && + echo a >> file && + git commit -am "commit change $N.1" && + echo b >> auto_updated_file && + git commit -am "commit change $N.2" && + echo c >> auto_updated_file && + git commit -am "commit change $N.3" && + test_must_fail git svn dcommit && # rebase should fail + test_must_fail git update-index --refresh + ) +' + +test_done diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index 80daaca780..9bc57d27e9 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -221,9 +221,35 @@ write_script () { # capital letters by convention). test_set_prereq () { - satisfied="$satisfied$1 " + satisfied_prereq="$satisfied_prereq$1 " +} +satisfied_prereq=" " +lazily_testable_prereq= lazily_tested_prereq= + +# Usage: test_lazy_prereq PREREQ 'script' +test_lazy_prereq () { + lazily_testable_prereq="$lazily_testable_prereq$1 " + eval test_prereq_lazily_$1=\$2 +} + +test_run_lazy_prereq_ () { + script=' +mkdir -p "$TRASH_DIRECTORY/prereq-test-dir" && +( + cd "$TRASH_DIRECTORY/prereq-test-dir" &&'"$2"' +)' + say >&3 "checking prerequisite: $1" + say >&3 "$script" + test_eval_ "$script" + eval_ret=$? + rm -rf "$TRASH_DIRECTORY/prereq-test-dir" + if test "$eval_ret" = 0; then + say >&3 "prerequisite $1 ok" + else + say >&3 "prerequisite $1 not satisfied" + fi + return $eval_ret } -satisfied=" " test_have_prereq () { # prerequisites can be concatenated with ',' @@ -238,8 +264,24 @@ test_have_prereq () { for prerequisite do + case " $lazily_tested_prereq " in + *" $prerequisite "*) + ;; + *) + case " $lazily_testable_prereq " in + *" $prerequisite "*) + eval "script=\$test_prereq_lazily_$prerequisite" && + if test_run_lazy_prereq_ "$prerequisite" "$script" + then + test_set_prereq $prerequisite + fi + lazily_tested_prereq="$lazily_tested_prereq$prerequisite " + esac + ;; + esac + total_prereq=$(($total_prereq + 1)) - case $satisfied in + case "$satisfied_prereq" in *" $prerequisite "*) ok_prereq=$(($ok_prereq + 1)) ;; @@ -530,6 +572,27 @@ test_cmp() { $GIT_TEST_CMP "$@" } +# Print a sequence of numbers or letters in increasing order. This is +# similar to GNU seq(1), but the latter might not be available +# everywhere (and does not do letters). It may be used like: +# +# for i in `test_seq 100`; do +# for j in `test_seq 10 20`; do +# for k in `test_seq a z`; do +# echo $i-$j-$k +# done +# done +# done + +test_seq () { + case $# in + 1) set 1 "$@" ;; + 2) ;; + *) error "bug in the test script: not 1 or 2 parameters to test_seq" ;; + esac + "$PERL_PATH" -le 'print for $ARGV[0]..$ARGV[1]' -- "$@" +} + # This function can be used to schedule some commands to be run # unconditionally at the end of the test to restore sanity: # diff --git a/t/test-lib.sh b/t/test-lib.sh index bb4f8865b2..78c428619e 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -659,9 +659,29 @@ test_i18ngrep () { fi } -# test whether the filesystem supports symbolic links -ln -s x y 2>/dev/null && test -h y 2>/dev/null && test_set_prereq SYMLINKS -rm -f y +test_lazy_prereq SYMLINKS ' + # test whether the filesystem supports symbolic links + ln -s x y && test -h y +' + +test_lazy_prereq CASE_INSENSITIVE_FS ' + echo good >CamelCase && + echo bad >camelcase && + test "$(cat CamelCase)" != good +' + +test_lazy_prereq UTF8_NFD_TO_NFC ' + # check whether FS converts nfd unicode to nfc + auml=$(printf "\303\244") + aumlcdiar=$(printf "\141\314\210") + >"$auml" && + case "$(echo *)" in + "$aumlcdiar") + true ;; + *) + false ;; + esac +' # When the tests are run as root, permission tests will report that # things are writable when they shouldn't be. diff --git a/transport-helper.c b/transport-helper.c index 61c928f6cd..cfe0988490 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -444,6 +444,21 @@ static int fetch_with_import(struct transport *transport, free(fastimport.argv); fastimport.argv = NULL; + /* + * The fast-import stream of a remote helper that advertises + * the "refspec" capability writes to the refs named after the + * right hand side of the first refspec matching each ref we + * were fetching. + * + * (If no "refspec" capability was specified, for historical + * reasons we default to *:*.) + * + * Store the result in to_fetch[i].old_sha1. Callers such + * as "git fetch" can use the value to write feedback to the + * terminal, populate FETCH_HEAD, and determine what new value + * should be written to peer_ref if the update is a + * fast-forward or this is a forced update. + */ for (i = 0; i < nr_heads; i++) { char *private; posn = to_fetch[i]; diff --git a/tree-diff.c b/tree-diff.c index 28ad6db9ff..ba01563a02 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -49,12 +49,12 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode1)) { if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) { opt->change(opt, mode1, mode2, - sha1, sha2, base->buf, 0, 0); + sha1, sha2, 1, 1, base->buf, 0, 0); } strbuf_addch(base, '/'); diff_tree_sha1(sha1, sha2, base->buf, opt); } else { - opt->change(opt, mode1, mode2, sha1, sha2, base->buf, 0, 0); + opt->change(opt, mode1, mode2, sha1, sha2, 1, 1, base->buf, 0, 0); } strbuf_setlen(base, old_baselen); return 0; @@ -100,7 +100,7 @@ static void show_entry(struct diff_options *opt, const char *prefix, die("corrupt tree sha %s", sha1_to_hex(sha1)); if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) - opt->add_remove(opt, *prefix, mode, sha1, base->buf, 0); + opt->add_remove(opt, *prefix, mode, sha1, 1, base->buf, 0); strbuf_addch(base, '/'); @@ -108,7 +108,7 @@ static void show_entry(struct diff_options *opt, const char *prefix, show_tree(opt, prefix, &inner, base); free(tree); } else - opt->add_remove(opt, prefix[0], mode, sha1, base->buf, 0); + opt->add_remove(opt, prefix[0], mode, sha1, 1, base->buf, 0); strbuf_setlen(base, old_baselen); } @@ -212,8 +212,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co diff_opts.rename_score = opt->rename_score; paths[0] = NULL; diff_tree_setup_paths(paths, &diff_opts); - if (diff_setup_done(&diff_opts) < 0) - die("unable to set up diff options to follow renames"); + diff_setup_done(&diff_opts); diff_tree(t1, t2, base, &diff_opts); diffcore_std(&diff_opts); diff_tree_release_paths(&diff_opts); |