diff options
265 files changed, 18218 insertions, 2627 deletions
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines index 483008699f..45577117c2 100644 --- a/Documentation/CodingGuidelines +++ b/Documentation/CodingGuidelines @@ -35,10 +35,22 @@ For shell scripts specifically (not exhaustive): - Case arms are indented at the same depth as case and esac lines. + - Redirection operators should be written with space before, but no + space after them. In other words, write 'echo test >"$file"' + instead of 'echo test> $file' or 'echo test > $file'. Note that + even though it is not required by POSIX to double-quote the + redirection target in a variable (as shown above), our code does so + because some versions of bash issue a warning without the quotes. + - We prefer $( ... ) for command substitution; unlike ``, it properly nests. It should have been the way Bourne spelled it from day one, but unfortunately isn't. + - If you want to find out if a command is available on the user's + $PATH, you should use 'type <command>', instead of 'which <command>'. + The output of 'which' is not machine parseable and its exit code + is not reliable across platforms. + - We use POSIX compliant parameter substitutions and avoid bashisms; namely: diff --git a/Documentation/RelNotes/1.7.10.txt b/Documentation/RelNotes/1.7.10.txt index e255901356..238234ed7c 100644 --- a/Documentation/RelNotes/1.7.10.txt +++ b/Documentation/RelNotes/1.7.10.txt @@ -1,57 +1,175 @@ Git v1.7.10 Release Notes ========================= +Compatibility Notes +------------------- + + * From this release on, the "git merge" command in an interactive + session will start an editor when it automatically resolves the + merge for the user to explain the resulting commit, just like the + "git commit" command does when it wasn't given a commit message. + + If you have a script that runs "git merge" and keeps its standard + input and output attached to the user's terminal, and if you do not + want the user to explain the resulting merge commits, you can + export GIT_MERGE_AUTOEDIT environment variable set to "no", like + this: + + #!/bin/sh + GIT_MERGE_AUTOEDIT=no + export GIT_MERGE_AUTOEDIT + + to disable this behaviour (if you want your users to explain their + merge commits, you do not have to do anything). Alternatively, you + can give the "--no-edit" option to individual invocations of the + "git merge" command if you know everybody who uses your script has + Git v1.7.8 or newer. + + * The "--binary/-b" options to "git am" have been a no-op for quite a + while and were deprecated in mid 2008 (v1.6.0). When you give these + options to "git am", it will now warn and ask you not to use them. + + Updates since v1.7.9 -------------------- UI, Workflows & Features - * Improved handling of views, labels and branches in git-p4 (in contrib). + * Teams for localizing the messages from the Porcelain layer of + commands are starting to form, thanks to Jiang Xin who volunteered + to be the localization coordinator. An initial set of translated + messages for simplified chinese is available. - * "vcs-svn"/"svn-fe" learned to read dumps with svn-deltas and - support incremental imports. + * The configuration mechanism learned an "include" facility; an + assignment to the include.path pseudo-variable causes the named + file to be included in-place when Git looks up configuration + variables. + + * A content filter (clean/smudge) used to be just a way to make the + recorded contents "more useful", and allowed to fail; a filter can + now optionally be marked as "required". + + * Options whose names begin with "--no-" (e.g. the "--no-verify" + option of the "git commit" command) can be negated by omitting + "no-" from its name, e.g. "git commit --verify". * "git am" learned to pass "-b" option to underlying "git mailinfo", so - that bracketed string other than "PATCH" at the beginning can be kept. + that a bracketed string other than "PATCH" at the beginning can be kept. * "git clone" learned "--single-branch" option to limit cloning to a - single branch (surprise!). + single branch (surprise!); tags that do not point into the history + of the branch are not fetched. * "git clone" learned to detach the HEAD in the resulting repository - when the source repository's HEAD does not point to a branch. + when the user specifies a tag with "--branch" (e.g., "--branch=v1.0"). + Clone also learned to print the usual "detached HEAD" advice in such + a case, similar to "git checkout v1.0". * When showing a patch while ignoring whitespace changes, the context lines are taken from the postimage, in order to make it easier to view the output. + * "git diff --stat" learned to adjust the width of the output on + wider terminals, and give more columns to pathnames as needed. + + * "diff-highlight" filter (in contrib/) was updated to produce more + aesthetically pleasing output. + + * "fsck" learned "--no-dangling" option to omit dangling object + information. + + * "git log -G" and "git log -S" learned to pay attention to the "-i" + option. With "-i", "log -G" ignores the case when finding patch + hunks that introduce or remove a string that matches the given + pattern. Similarly with "-i", "log -S" ignores the case when + finding the commit the given block of text appears or disappears + from the file. + * "git merge" in an interactive session learned to spawn the editor by default to let the user edit the auto-generated merge message, to encourage people to explain their merges better. Legacy scripts - can export MERGE_AUTOEDIT=no to retain the historical behaviour. + can export GIT_MERGE_AUTOEDIT=no to retain the historical behavior. + Both "git merge" and "git pull" can be given --no-edit from the + command line to accept the auto-generated merge message. + + * The advice message given when the user didn't give enough clue on + what to merge to "git pull" and "git merge" has been updated to + be more concise and easier to understand. + + * "git push" learned the "--prune" option, similar to "git fetch". + + * The whole directory that houses a top-level superproject managed by + "git submodule" can be moved to another place. + + * "git symbolic-ref" learned the "--short" option to abbreviate the + refname it shows unambiguously. + + * "git tag --list" can be given "--points-at <object>" to limit its + output to those that point at the given object. * "gitweb" allows intermediate entries in the directory hierarchy - that leads to a projects to be clicked, which in turn shows the + that leads to a project to be clicked, which in turn shows the list of projects inside that directory. + * "gitweb" learned to read various pieces of information for the + repositories lazily, instead of reading everything that could be + needed (including the ones that are not necessary for a specific + task). + + * Project search in "gitweb" shows the substring that matched in the + project name and description highlighted. + + * A new script "diffall" is added to contrib/; it drives an + external tool to perform a directory diff of two Git revisions + in one go, unlike "difftool" that compares one file at a time. + +Foreign Interface + + * Improved handling of views, labels and branches in "git-p4" (in contrib). + + * "git-p4" (in contrib) suffered from unnecessary merge conflicts when + p4 expanded the embedded $RCS$-like keywords; it can be now told to + unexpand them. + + * Some "git-svn" updates. + + * "vcs-svn"/"svn-fe" learned to read dumps with svn-deltas and + support incremental imports. + + * "git difftool/mergetool" learned to drive DeltaWalker. + Performance - * During "git upload-pack" in respose to "git fetch", unnecessary calls - to parse_object() have been eliminated, to help performance in - repositories with excessive number of refs. + * Unnecessary calls to parse_object() "git upload-pack" makes in + response to "git fetch", have been eliminated, to help performance + in repositories with excessive number of refs. -Internal Implementation +Internal Implementation (please report possible regressions) * Recursive call chains in "git index-pack" to deal with long delta chains have been flattened, to reduce the stack footprint. - * Use of add_extra_ref() API is slowly getting removed, to make it - possible to cleanly restructure the overall refs API. + * Use of add_extra_ref() API is now gone, to make it possible to + cleanly restructure the overall refs API. + + * The command line parser of "git pack-objects" now uses parse-options + API. * The test suite supports the new "test_pause" helper function. + * Parallel to the test suite, there is a beginning of performance + benchmarking framework. + * t/Makefile is adjusted to prevent newer versions of GNU make from running tests in seemingly random order. + * The code to check if a path points at a file beyond a symbolic link + has been restructured to be thread-safe. + + * When pruning directories that has become empty during "git prune" + and "git prune-packed", call closedir() that iterates over a + directory before rmdir() it. + Also contains minor documentation updates and code clean-ups. @@ -62,30 +180,34 @@ Unless otherwise noted, all the fixes since v1.7.9 in the maintenance releases are contained in this release (see release notes to them for details). - * "add -e" learned not to show a diff for an otherwise unmodified - submodule that only has uncommitted local changes in the patch - prepared by for the user to edit. - (merge 701825d js/add-e-submodule-fix later to maint). + * "git fast-import" accepted "ls" command with an empty path by + mistake. + (merge 178e1de jn/maint-fast-import-empty-ls later to maint). + + * The "remaining" subcommand to "git rerere" was not documented. + (merge 3e7a1df ph/rerere-doc later to maint). - * "rebase" and "commit --amend" failed to work on commits with ancient - timestamps near year 1970. - (merge 2c733fb jc/parse-date-raw later to maint). + * "git tag -s" honored "gpg.program" configuration variable since + 1.7.9, but "git tag -v" and "git verify-tag" didn't. + (merge a2c2506 az/verify-tag-use-gpg-config later to maint). - * "git merge --ff-only $tag" failed because it cannot record the - required mergetag without creating a merge, but this is so common - operation for branch that is used _only_ to follow the upstream, so - it is allowed to fast-forward without recording the mergetag. - (merge b5c9f1c jc/merge-ff-only-stronger-than-signed-merge later to maint). + * When "git config" diagnoses an error in a configuration file and + shows the line number for the offending line, it miscounted if the + error was at the end of line. + (merge 4b34059 ms/maint-config-error-at-eol-linecount later to maint). - * Typo in "git branch --edit-description my-tpoic" was not diagnosed. - (merge c2d17ba jc/branch-desc-typoavoidance later to maint). + * "configure" script learned to take "--sane-tool-path" from the + command line to record SANE_TOOL_PATH (used to avoid broken + platform tools in /usr/bin) in config.mak-autogen. This may be useful + for people on Solaris who have saner tools outside /usr/xpg[46]/bin. - * rpmbuild noticed an unpackaged but installed *.mo file and failed. - (merge 3a9f58c jn/rpm-spec later to maint). + * "gitweb" used to drop warnings in the log file when "heads" view is + accessed in a repository whose HEAD does not point at a valid + branch. --- exec >/var/tmp/1 -O=v1.7.9-208-gee8d52f +O=v1.7.10-rc1-18-g0987145 echo O=$(git describe) git log --first-parent --oneline ^maint $O.. echo diff --git a/Documentation/RelNotes/1.7.8.5.txt b/Documentation/RelNotes/1.7.8.5.txt new file mode 100644 index 0000000000..011fd2a428 --- /dev/null +++ b/Documentation/RelNotes/1.7.8.5.txt @@ -0,0 +1,19 @@ +Git v1.7.8.5 Release Notes +========================== + +Fixes since v1.7.8.4 +-------------------- + + * Dependency on our thread-utils.h header file was missing for + objects that depend on it in the Makefile. + + * "git am" when fed an empty file did not correctly finish reading it + when it attempts to guess the input format. + + * "git grep -P" (when PCRE is enabled in the build) did not match the + beginning and the end of the line correctly with ^ and $. + + * "git rebase -m" tried to run "git notes copy" needlessly when + nothing was rewritten. + +Also contains minor fixes and documentation updates. diff --git a/Documentation/RelNotes/1.7.9.1.txt b/Documentation/RelNotes/1.7.9.1.txt index a6c15e5d52..6957183dbb 100644 --- a/Documentation/RelNotes/1.7.9.1.txt +++ b/Documentation/RelNotes/1.7.9.1.txt @@ -4,9 +4,24 @@ Git v1.7.9.1 Release Notes Fixes since v1.7.9 ------------------ + * The makefile allowed environment variable X seep into it result in + command names suffixed with unnecessary strings. + + * The set of included header files in compat/inet-{ntop,pton} + wrappers was updated for Windows some time ago, but in a way that + broke Solaris build. + + * rpmbuild noticed an unpackaged but installed *.mo file and failed. + * Subprocesses spawned from various git programs were often left running to completion even when the top-level process was killed. + * "git add -e" learned not to show a diff for an otherwise unmodified + submodule that only has uncommitted local changes in the patch + prepared by for the user to edit. + + * Typo in "git branch --edit-description my-tpoic" was not diagnosed. + * Using "git grep -l/-L" together with options -W or --break may not make much sense as the output is to only count the number of hits and there is no place for file breaks, but the latter options made @@ -16,15 +31,25 @@ Fixes since v1.7.9 chain and veered into side branch from which the whole change to the specified paths came. - * "git push -q" was not sufficiently quiet. + * "git merge --no-edit $tag" failed to honor the --no-edit option. - * When "git push" fails to update any refs, the client side did not - report an error correctly to the end user. + * "git merge --ff-only $tag" failed because it cannot record the + required mergetag without creating a merge, but this is so common + operation for branch that is used _only_ to follow the upstream, so + it was changed to allow fast-forwarding without recording the mergetag. * "git mergetool" now gives an empty file as the common base version to the backend when dealing with the "both sides added, differently" case. + * "git push -q" was not sufficiently quiet. + + * When "git push" fails to update any refs, the client side did not + report an error correctly to the end user. + + * "rebase" and "commit --amend" failed to work on commits with ancient + timestamps near year 1970. + * When asking for a tag to be pulled, "request-pull" did not show the name of the tag prefixed with "tags/", which would have helped older clients. @@ -33,4 +58,6 @@ Fixes since v1.7.9 in .gitmodules when the submodule at $path was once added to the superproject and already initialized. + * Many small corner case bugs on "git tag -n" was corrected. + Also contains minor fixes and documentation updates. diff --git a/Documentation/RelNotes/1.7.9.2.txt b/Documentation/RelNotes/1.7.9.2.txt new file mode 100644 index 0000000000..e500da75dd --- /dev/null +++ b/Documentation/RelNotes/1.7.9.2.txt @@ -0,0 +1,69 @@ +Git v1.7.9.2 Release Notes +========================== + +Fixes since v1.7.9.1 +-------------------- + + * Bash completion script (in contrib/) did not like a pattern that + begins with a dash to be passed to __git_ps1 helper function. + + * Adaptation of the bash completion script (in contrib/) for zsh + incorrectly listed all subcommands when "git <TAB><TAB>" was given + to ask for list of porcelain subcommands. + + * The build procedure for profile-directed optimized binary was not + working very well. + + * Some systems need to explicitly link -lcharset to get locale_charset(). + + * t5541 ignored user-supplied port number used for HTTP server testing. + + * The error message emitted when we see an empty loose object was + not phrased correctly. + + * The code to ask for password did not fall back to the terminal + input when GIT_ASKPASS is set but does not work (e.g. lack of X + with GUI askpass helper). + + * We failed to give the true terminal width to any subcommand when + they are invoked with the pager, i.e. "git -p cmd". + + * map_user() was not rewriting its output correctly, which resulted + in the user visible symptom that "git blame -e" sometimes showed + excess '>' at the end of email addresses. + + * "git checkout -b" did not allow switching out of an unborn branch. + + * When you have both .../foo and .../foo.git, "git clone .../foo" did not + favor the former but the latter. + + * "git commit" refused to create a commit when entries added with + "add -N" remained in the index, without telling Git what their content + in the next commit should be. We should have created the commit without + these paths. + + * "git diff --stat" said "files", "insertions", and "deletions" even + when it is showing one "file", one "insertion" or one "deletion". + + * The output from "git diff --stat" for two paths that have the same + amount of changes showed graph bars of different length due to the + way we handled rounding errors. + + * "git grep" did not pay attention to -diff (hence -binary) attribute. + + * The transport programs (fetch, push, clone)ignored --no-progress + and showed progress when sending their output to a terminal. + + * Sometimes error status detected by a check in an earlier phase of + "git receive-pack" (the other end of "git push") was lost by later + checks, resulting in false indication of success. + + * "git rev-list --verify" sometimes skipped verification depending on + the phase of the moon, which dates back to 1.7.8.x series. + + * Search box in "gitweb" did not accept non-ASCII characters correctly. + + * Search interface of "gitweb" did not show multiple matches in the same file + correctly. + +Also contains minor fixes and documentation updates. diff --git a/Documentation/RelNotes/1.7.9.3.txt b/Documentation/RelNotes/1.7.9.3.txt new file mode 100644 index 0000000000..91c65012f9 --- /dev/null +++ b/Documentation/RelNotes/1.7.9.3.txt @@ -0,0 +1,51 @@ +Git v1.7.9.3 Release Notes +========================== + +Fixes since v1.7.9.2 +-------------------- + + * "git p4" (in contrib/) submit the changes to a wrong place when the + "--use-client-spec" option is set. + + * The config.mak.autogen generated by optional autoconf support tried + to link the binary with -lintl even when libintl.h is missing from + the system. + + * When the filter driver exits before reading the content before the + main git process writes the contents to be filtered to the pipe to + it, the latter could be killed with SIGPIPE instead of ignoring + such an event as an error. + + * "git add --refresh <pathspec>" used to warn about unmerged paths + outside the given pathspec. + + * The bulk check-in codepath in "git add" streamed contents that + needs smudge/clean filters without running them, instead of punting + and delegating to the codepath to run filters after slurping + everything to core. + + * "git branch --with $that" assumed incorrectly that the user will never + ask the question with nonsense value in $that. + + * "git bundle create" produced a corrupt bundle file upon seeing + commits with excessively long subject line. + + * When a remote helper exits before reading the blank line from the + main git process to signal the end of commands, the latter could be + killed with SIGPIPE. Instead we should ignore such event as a + non-error. + + * The commit log template given with "git merge --edit" did not have + a short instructive text like what "git commit" gives. + + * "git rev-list --verify-objects -q" omitted the extra verification + it needs to do over "git rev-list --objects -q" by mistake. + + * "gitweb" used to drop warnings in the log file when "heads" view is + accessed in a repository whose HEAD does not point at a valid + branch. + + * An invalid regular expression pattern given by an end user made + "gitweb" to return garbled response. + +Also contains minor fixes and documentation updates. diff --git a/Documentation/RelNotes/1.7.9.4.txt b/Documentation/RelNotes/1.7.9.4.txt new file mode 100644 index 0000000000..e5217a1889 --- /dev/null +++ b/Documentation/RelNotes/1.7.9.4.txt @@ -0,0 +1,24 @@ +Git v1.7.9.4 Release Notes +========================== + +Fixes since v1.7.9.3 +-------------------- + + * The code to synthesize the fake ancestor tree used by 3-way merge + fallback in "git am" was not prepared to read a patch created with + a non-standard -p<num> value. + + * "git bundle" did not record boundary commits correctly when there + are many of them. + + * "git diff-index" and its friends at the plumbing level showed the + "diff --git" header and nothing else for a path whose cached stat + info is dirty without actual difference when asked to produce a + patch. This was a longstanding bug that we could have fixed long + time ago. + + * "gitweb" did use quotemeta() to prepare search string when asked to + do a fixed-string project search, but did not use it by mistake and + used the user-supplied string instead. + +Also contains minor fixes and documentation updates. diff --git a/Documentation/config.txt b/Documentation/config.txt index abeb82b2c6..c081657be7 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -12,8 +12,9 @@ The configuration variables are used by both the git plumbing and the porcelains. The variables are divided into sections, wherein the fully qualified variable name of the variable itself is the last dot-separated segment and the section name is everything before the last -dot. The variable names are case-insensitive and only alphanumeric -characters are allowed. Some variables may appear multiple times. +dot. The variable names are case-insensitive, allow only alphanumeric +characters and `-`, and must start with an alphabetic character. Some +variables may appear multiple times. Syntax ~~~~~~ @@ -54,9 +55,10 @@ All the other lines (and the remainder of the line after the section header) are recognized as setting variables, in the form 'name = value'. If there is no equal sign on the line, the entire line is taken as 'name' and the variable is recognized as boolean "true". -The variable names are case-insensitive and only alphanumeric -characters and `-` are allowed. There can be more than one value -for a given variable; we say then that variable is multivalued. +The variable names are case-insensitive, allow only alphanumeric characters +and `-`, and must start with an alphabetic character. There can be more +than one value for a given variable; we say then that the variable is +multivalued. Leading and trailing whitespace in a variable value is discarded. Internal whitespace within a variable value is retained verbatim. @@ -84,6 +86,17 @@ customary UNIX fashion. Some variables may require a special value format. +Includes +~~~~~~~~ + +You can include one config file from another by setting the special +`include.path` variable to the name of the file to be included. The +included file is expanded immediately, as if its contents had been +found at the location of the include directive. If the value of the +`include.path` variable is a relative path, the path is considered to be +relative to the configuration file in which the include directive was +found. See below for examples. + Example ~~~~~~~ @@ -106,6 +119,10 @@ Example gitProxy="ssh" for "kernel.org" gitProxy=default-proxy ; for the rest + [include] + path = /path/to/foo.inc ; include by absolute path + path = foo ; expand "foo" relative to the current file + Variables ~~~~~~~~~ @@ -1258,9 +1275,10 @@ help.autocorrect:: This is the default. http.proxy:: - Override the HTTP proxy, normally configured using the 'http_proxy' - environment variable (see linkgit:curl[1]). This can be overridden - on a per-remote basis; see remote.<name>.proxy + Override the HTTP proxy, normally configured using the 'http_proxy', + 'https_proxy', and 'all_proxy' environment variables (see + `curl(1)`). This can be overridden on a per-remote basis; see + remote.<name>.proxy http.cookiefile:: File containing previously stored cookie lines which should be used diff --git a/Documentation/diff-config.txt b/Documentation/diff-config.txt index 1aed79e7dc..6aa1be0478 100644 --- a/Documentation/diff-config.txt +++ b/Documentation/diff-config.txt @@ -52,6 +52,10 @@ directories with less than 10% of the total amount of changed files, and accumulating child directory counts in the parent directories: `files,10,cumulative`. +diff.statGraphWidth:: + Limit the width of the graph part in --stat output. If set, applies + to all commands generating --stat outuput except format-patch. + diff.external:: If this config variable is set, diff generation is not performed using the internal diff machinery, but using the diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 9f7cba2be6..378f19f0e2 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -52,14 +52,23 @@ endif::git-format-patch[] --patience:: Generate a diff using the "patience diff" algorithm. +--histogram:: + Generate a diff using the "histogram diff" algorithm. + --stat[=<width>[,<name-width>[,<count>]]]:: - Generate a diffstat. You can override the default - output width for 80-column terminal by `--stat=<width>`. - The width of the filename part can be controlled by - giving another width to it separated by a comma. + Generate a diffstat. By default, as much space as necessary + will be used for the filename part, and the rest for the graph + part. Maximum width defaults to terminal width, or 80 columns + if not connected to a terminal, and can be overriden by + `<width>`. The width of the filename part can be limited by + giving another width `<name-width>` after a comma. The width + of the graph part can be limited by using + `--stat-graph-width=<width>` (affects all commands generating + a stat graph) or by setting `diff.statGraphWidth=<width>` + (does not affect `git format-patch`). By giving a third parameter `<count>`, you can limit the - output to the first `<count>` lines, followed by - `...` if there are more. + output to the first `<count>` lines, followed by `...` if + there are more. + These parameters can also be set individually with `--stat-width=<width>`, `--stat-name-width=<name-width>` and `--stat-count=<count>`. @@ -156,11 +165,12 @@ any of those replacements occurred. of the `--diff-filter` option on what the status letters mean. --submodule[=<format>]:: - Chose the output format for submodule differences. <format> can be one of - 'short' and 'log'. 'short' just shows pairs of commit names, this format - is used when this option is not given. 'log' is the default value for this - option and lists the commits in that commit range like the 'summary' - option of linkgit:git-submodule[1] does. + Specify how differences in submodules are shown. When `--submodule` + or `--submodule=log` is given, the 'log' format is used. This format lists + the commits in the range like linkgit:git-submodule[1] `summary` does. + Omitting the `--submodule` option or specifying `--submodule=short`, + uses the 'short' format. This format just shows the names of the commits + at the beginning and end of the range. --color[=<when>]:: Show colored diff. diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt index 0427e80a35..6410c3d345 100644 --- a/Documentation/git-branch.txt +++ b/Documentation/git-branch.txt @@ -24,8 +24,8 @@ be highlighted with an asterisk. Option `-r` causes the remote-tracking branches to be listed, and option `-a` shows both. This list mode is also activated by the `--list` option (see below). <pattern> restricts the output to matching branches, the pattern is a shell -wildcard (i.e., matched using fnmatch(3)) -Multiple patterns may be given; if any of them matches, the tag is shown. +wildcard (i.e., matched using fnmatch(3)). +Multiple patterns may be given; if any of them matches, the branch is shown. With `--contains`, shows only the branches that contain the named commit (in other words, the branches whose tip commits are descendants of the @@ -49,7 +49,7 @@ the remote-tracking branch. This behavior may be changed via the global overridden by using the `--track` and `--no-track` options, and changed later using `git branch --set-upstream`. -With a '-m' or '-M' option, <oldbranch> will be renamed to <newbranch>. +With a `-m` or `-M` option, <oldbranch> will be renamed to <newbranch>. If <oldbranch> had a corresponding reflog, it is renamed to match <newbranch>, and a reflog entry is created to remember the branch renaming. If <newbranch> exists, -M must be used to force the rename @@ -59,7 +59,7 @@ With a `-d` or `-D` option, `<branchname>` will be deleted. You may specify more than one branch for deletion. If the branch currently has a reflog then the reflog will also be deleted. -Use -r together with -d to delete remote-tracking branches. Note, that it +Use `-r` together with `-d` to delete remote-tracking branches. Note, that it only makes sense to delete remote-tracking branches if they no longer exist in the remote repository or if 'git fetch' was configured not to fetch them again. See also the 'prune' subcommand of linkgit:git-remote[1] for a @@ -154,17 +154,18 @@ start-point is either a local or remote-tracking branch. branch.autosetupmerge configuration variable is true. --set-upstream:: - If specified branch does not exist yet or if '--force' has been - given, acts exactly like '--track'. Otherwise sets up configuration - like '--track' would when creating the branch, except that where + If specified branch does not exist yet or if `--force` has been + given, acts exactly like `--track`. Otherwise sets up configuration + like `--track` would when creating the branch, except that where branch points to is not changed. --edit-description:: Open an editor and edit the text to explain what the branch is for, to be used by various other commands (e.g. `request-pull`). ---contains <commit>:: - Only list branches which contain the specified commit. +--contains [<commit>]:: + Only list branches which contain the specified commit (HEAD + if not specified). --merged [<commit>]:: Only list branches whose tips are reachable from the diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index e7ecf5d803..81b03982e3 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -85,8 +85,11 @@ OPTIONS is not exactly one. --get-regexp:: - Like --get-all, but interprets the name as a regular expression. - Also outputs the key names. + Like --get-all, but interprets the name as a regular expression and + writes out the key names. Regular expression matching is currently + case-sensitive and done against a canonicalized version of the key + in which section and variable names are lowercased, but subsection + names are not. --global:: For writing options: write to global ~/.gitconfig file rather than @@ -178,6 +181,11 @@ See also <<FILES>>. Opens an editor to modify the specified config file; either '--system', '--global', or repository (default). +--includes:: +--no-includes:: + Respect `include.*` directives in config files when looking up + values. Defaults to on. + [[FILES]] FILES ----- diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt index 19d473c070..fe38f667f9 100644 --- a/Documentation/git-difftool.txt +++ b/Documentation/git-difftool.txt @@ -32,8 +32,9 @@ OPTIONS --tool=<tool>:: Use the diff tool specified by <tool>. Valid diff tools are: - araxis, bc3, diffuse, emerge, ecmerge, gvimdiff, kdiff3, - kompare, meld, opendiff, p4merge, tkdiff, vimdiff and xxdiff. + araxis, bc3, deltawalker, diffuse, emerge, ecmerge, gvimdiff, + kdiff3, kompare, meld, opendiff, p4merge, tkdiff, vimdiff and + xxdiff. + If a diff tool is not specified, 'git difftool' will use the configuration variable `diff.tool`. If the diff --git a/Documentation/git-fmt-merge-msg.txt b/Documentation/git-fmt-merge-msg.txt index 32aff954a2..3a0f55ec8e 100644 --- a/Documentation/git-fmt-merge-msg.txt +++ b/Documentation/git-fmt-merge-msg.txt @@ -53,6 +53,11 @@ OPTIONS CONFIGURATION ------------- +merge.branchdesc:: + In addition to branch names, populate the log message with + the branch description text associated with them. Defaults + to false. + merge.log:: In addition to branch names, populate the log message with at most the specified number of one-line descriptions from the diff --git a/Documentation/git-fsck.txt b/Documentation/git-fsck.txt index 6c47395ad2..bbb25da2dd 100644 --- a/Documentation/git-fsck.txt +++ b/Documentation/git-fsck.txt @@ -11,7 +11,7 @@ SYNOPSIS [verse] 'git fsck' [--tags] [--root] [--unreachable] [--cache] [--no-reflogs] [--[no-]full] [--strict] [--verbose] [--lost-found] - [--[no-]progress] [<object>*] + [--[no-]dangling] [--[no-]progress] [<object>*] DESCRIPTION ----------- @@ -30,6 +30,11 @@ index file, all SHA1 references in .git/refs/*, and all reflogs (unless Print out objects that exist but that aren't reachable from any of the reference nodes. +--dangling:: +--no-dangling:: + Print objects that exist but that are never 'directly' used (default). + `--no-dangling` can be used to omit this information from the output. + --root:: Report root nodes. diff --git a/Documentation/git-p4.txt b/Documentation/git-p4.txt index 8b92cc0f8d..b7c7929716 100644 --- a/Documentation/git-p4.txt +++ b/Documentation/git-p4.txt @@ -303,9 +303,13 @@ CLIENT SPEC ----------- The p4 client specification is maintained with the 'p4 client' command and contains among other fields, a View that specifies how the depot -is mapped into the client repository. Git-p4 can consult the client -spec when given the '--use-client-spec' option or useClientSpec -variable. +is mapped into the client repository. The 'clone' and 'sync' commands +can consult the client spec when given the '--use-client-spec' option or +when the useClientSpec variable is true. After 'git p4 clone', the +useClientSpec variable is automatically set in the repository +configuration file. This allows future 'git p4 submit' commands to +work properly; the submit command looks only at the variable and does +not have a command-line option. The full syntax for a p4 view is documented in 'p4 help views'. Git-p4 knows only a subset of the view syntax. It understands multi-line @@ -483,6 +487,11 @@ git-p4.skipUserNameCheck:: user map, 'git p4' exits. This option can be used to force submission regardless. +git-p4.attemptRCSCleanup: + If enabled, 'git p4 submit' will attempt to cleanup RCS keywords + ($Header$, etc). These would otherwise cause merge conflicts and prevent + the submit going ahead. This option should be considered experimental at + present. IMPLEMENTATION DETAILS ---------------------- diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt index aede48877f..48760db337 100644 --- a/Documentation/git-push.txt +++ b/Documentation/git-push.txt @@ -10,7 +10,7 @@ SYNOPSIS -------- [verse] 'git push' [--all | --mirror | --tags] [-n | --dry-run] [--receive-pack=<git-receive-pack>] - [--repo=<repository>] [-f | --force] [-v | --verbose] [-u | --set-upstream] + [--repo=<repository>] [-f | --force] [--prune] [-v | --verbose] [-u | --set-upstream] [<repository> [<refspec>...]] DESCRIPTION @@ -71,6 +71,14 @@ nor in any Push line of the corresponding remotes file---see below). Instead of naming each ref to push, specifies that all refs under `refs/heads/` be pushed. +--prune:: + Remove remote branches that don't have a local counterpart. For example + a remote branch `tmp` will be removed if a local branch with the same + name doesn't exist any more. This also respects refspecs, e.g. + `git push --prune remote refs/heads/{asterisk}:refs/tmp/{asterisk}` would + make sure that remote `refs/tmp/foo` will be removed if `refs/heads/foo` + doesn't exist. + --mirror:: Instead of naming each ref to push, specifies that all refs under `refs/` (which includes but is not diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt index 5a8c5061f3..d376d19ef7 100644 --- a/Documentation/git-remote.txt +++ b/Documentation/git-remote.txt @@ -14,7 +14,7 @@ SYNOPSIS 'git remote rename' <old> <new> 'git remote rm' <name> 'git remote set-head' <name> (-a | -d | <branch>) -'git remote set-branches' <name> [--add] <branch>... +'git remote set-branches' [--add] <name> <branch>... 'git remote set-url' [--push] <name> <newurl> [<oldurl>] 'git remote set-url --add' [--push] <name> <newurl> 'git remote set-url --delete' [--push] <name> <url> diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt index 40af321153..4c1aff65e6 100644 --- a/Documentation/git-repack.txt +++ b/Documentation/git-repack.txt @@ -34,7 +34,7 @@ OPTIONS Especially useful when packing a repository that is used for private development. Use with '-d'. This will clean up the objects that `git prune` - leaves behind, but `git fsck --full` shows as + leaves behind, but `git fsck --full --dangling` shows as dangling. + Note that users fetching over dumb protocols will have to fetch the diff --git a/Documentation/git-rerere.txt b/Documentation/git-rerere.txt index a6253ba617..b43b7c8c0e 100644 --- a/Documentation/git-rerere.txt +++ b/Documentation/git-rerere.txt @@ -8,7 +8,7 @@ git-rerere - Reuse recorded resolution of conflicted merges SYNOPSIS -------- [verse] -'git rerere' ['clear'|'forget' <pathspec>|'diff'|'status'|'gc'] +'git rerere' ['clear'|'forget' <pathspec>|'diff'|'remaining'|'status'|'gc'] DESCRIPTION ----------- @@ -37,30 +37,35 @@ its working state. 'clear':: -This resets the metadata used by rerere if a merge resolution is to be +Reset the metadata used by rerere if a merge resolution is to be aborted. Calling 'git am [--skip|--abort]' or 'git rebase [--skip|--abort]' will automatically invoke this command. 'forget' <pathspec>:: -This resets the conflict resolutions which rerere has recorded for the current +Reset the conflict resolutions which rerere has recorded for the current conflict in <pathspec>. 'diff':: -This displays diffs for the current state of the resolution. It is +Display diffs for the current state of the resolution. It is useful for tracking what has changed while the user is resolving conflicts. Additional arguments are passed directly to the system 'diff' command installed in PATH. 'status':: -Like 'diff', but this only prints the filenames that will be tracked -for resolutions. +Print paths with conflicts whose merge resolution rerere will record. + +'remaining':: + +Print paths with conflicts that have not been autoresolved by rerere. +This includes paths whose resolutions cannot be tracked by rerere, +such as conflicting submodules. 'gc':: -This prunes records of conflicted merges that +Prune records of conflicted merges that occurred a long time ago. By default, unresolved conflicts older than 15 days and resolved conflicts older than 60 days are pruned. These defaults are controlled via the diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt index 327233c85b..324117072d 100644 --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@ -198,6 +198,10 @@ must be used for each option. if a username is not specified (with '--smtp-user' or 'sendemail.smtpuser'), then authentication is not attempted. +--smtp-debug=0|1:: + Enable (1) or disable (0) debug output. If enabled, SMTP + commands and replies will be printed. Useful to debug TLS + connection and authentication problems. Automating ~~~~~~~~~~ diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt index a45d4c4f29..981d3a8fc1 100644 --- a/Documentation/git-symbolic-ref.txt +++ b/Documentation/git-symbolic-ref.txt @@ -8,7 +8,8 @@ git-symbolic-ref - Read and modify symbolic refs SYNOPSIS -------- [verse] -'git symbolic-ref' [-q] [-m <reason>] <name> [<ref>] +'git symbolic-ref' [-m <reason>] <name> <ref> +'git symbolic-ref' [-q] [--short] <name> DESCRIPTION ----------- @@ -33,6 +34,10 @@ OPTIONS symbolic ref but a detached HEAD; instead exit with non-zero status silently. +--short:: + When showing the value of <name> as a symbolic ref, try to shorten the + value, e.g. from `refs/heads/master` to `master`. + -m:: Update the reflog for <name> with <reason>. This is valid only when creating or updating a symbolic ref. diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt index 53ff5f6cf7..8d32b9a814 100644 --- a/Documentation/git-tag.txt +++ b/Documentation/git-tag.txt @@ -12,7 +12,8 @@ SYNOPSIS 'git tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] <tagname> [<commit> | <object>] 'git tag' -d <tagname>... -'git tag' [-n[<num>]] -l [--contains <commit>] [<pattern>...] +'git tag' [-n[<num>]] -l [--contains <commit>] [--points-at <object>] + [<pattern>...] 'git tag' -v <tagname>... DESCRIPTION @@ -86,6 +87,9 @@ OPTIONS --contains <commit>:: Only list tags which contain the specified commit. +--points-at <object>:: + Only list tags of the given object. + -m <msg>:: --message=<msg>:: Use the given tag message (instead of prompting). diff --git a/Documentation/git.txt b/Documentation/git.txt index f7e201fae3..d5b7667c15 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -9,11 +9,11 @@ git - the stupid content tracker SYNOPSIS -------- [verse] -'git' [--version] [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path] +'git' [--version] [--help] [-c <name>=<value>] + [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path] [-p|--paginate|--no-pager] [--no-replace-objects] [--bare] [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>] - [-c <name>=<value>] - [--help] <command> [<args>] + <command> [<args>] DESCRIPTION ----------- @@ -44,9 +44,13 @@ 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.9/git.html[documentation for release 1.7.9] +* link:v1.7.9.4/git.html[documentation for release 1.7.9.4] * release notes for + link:RelNotes/1.7.9.4.txt[1.7.9.4], + link:RelNotes/1.7.9.3.txt[1.7.9.3], + link:RelNotes/1.7.9.2.txt[1.7.9.2], + link:RelNotes/1.7.9.1.txt[1.7.9.1], link:RelNotes/1.7.9.txt[1.7.9]. * link:v1.7.8.4/git.html[documentation for release 1.7.8.4] diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index a85b187e04..80120ea14f 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -294,16 +294,27 @@ output is used to update the worktree file. Similarly, the `clean` command is used to convert the contents of worktree file upon checkin. -A missing filter driver definition in the config is not an error -but makes the filter a no-op passthru. - -The content filtering is done to massage the content into a -shape that is more convenient for the platform, filesystem, and -the user to use. The key phrase here is "more convenient" and not -"turning something unusable into usable". In other words, the -intent is that if someone unsets the filter driver definition, -or does not have the appropriate filter program, the project -should still be usable. +One use of the content filtering is to massage the content into a shape +that is more convenient for the platform, filesystem, and the user to use. +For this mode of operation, the key phrase here is "more convenient" and +not "turning something unusable into usable". In other words, the intent +is that if someone unsets the filter driver definition, or does not have +the appropriate filter program, the project should still be usable. + +Another use of the content filtering is to store the content that cannot +be directly used in the repository (e.g. a UUID that refers to the true +content stored outside git, or an encrypted content) and turn it into a +usable form upon checkout (e.g. download the external content, or decrypt +the encrypted content). + +These two filters behave differently, and by default, a filter is taken as +the former, massaging the contents into more convenient shape. A missing +filter driver definition in the config, or a filter driver that exits with +a non-zero status, is not an error but makes the filter a no-op passthru. + +You can declare that a filter turns a content that by itself is unusable +into a usable content by setting the filter.<driver>.required configuration +variable to `true`. For example, in .gitattributes, you would assign the `filter` attribute for paths. @@ -335,6 +346,16 @@ input that is already correctly indented. In this case, the lack of a smudge filter means that the clean filter _must_ accept its own output without modifying it. +If a filter _must_ succeed in order to make the stored contents usable, +you can declare that the filter is `required`, in the configuration: + +------------------------ +[filter "crypt"] + clean = openssl enc ... + smudge = openssl enc -d ... + required +------------------------ + Sequence "%f" on the filter command line is replaced with the name of the file the filter is working on. A filter might use this in keyword substitution. For example: diff --git a/Documentation/gitcore-tutorial.txt b/Documentation/gitcore-tutorial.txt index c27d086f68..fb0d5692a4 100644 --- a/Documentation/gitcore-tutorial.txt +++ b/Documentation/gitcore-tutorial.txt @@ -1004,7 +1004,7 @@ Updating from ae3a2da... to a80b4aa.... Fast-forward (no commit created; -m option ignored) example | 1 + hello | 1 + - 2 files changed, 2 insertions(+), 0 deletions(-) + 2 files changed, 2 insertions(+) ---------------- Because your branch did not contain anything more than what had diff --git a/Documentation/gittutorial-2.txt b/Documentation/gittutorial-2.txt index f1e4422acc..e00a4d2170 100644 --- a/Documentation/gittutorial-2.txt +++ b/Documentation/gittutorial-2.txt @@ -34,12 +34,12 @@ $ echo 'hello world' > file.txt $ git add . $ git commit -a -m "initial commit" [master (root-commit) 54196cc] initial commit - 1 files changed, 1 insertions(+), 0 deletions(-) + 1 file changed, 1 insertion(+) create mode 100644 file.txt $ echo 'hello world!' >file.txt $ git commit -a -m "add emphasis" [master c4d59f3] add emphasis - 1 files changed, 1 insertions(+), 1 deletions(-) + 1 file changed, 1 insertion(+), 1 deletion(-) ------------------------------------------------ What are the 7 digits of hex that git responded to the commit with? diff --git a/Documentation/gitweb.txt b/Documentation/gitweb.txt index 605a085326..168e8bfed6 100644 --- a/Documentation/gitweb.txt +++ b/Documentation/gitweb.txt @@ -14,7 +14,7 @@ gitweb. DESCRIPTION ----------- -Gitweb provides a web interface to git repositories. It's features include: +Gitweb provides a web interface to git repositories. Its features include: * Viewing multiple Git repositories with common root. * Browsing every revision of the repository. @@ -60,7 +60,7 @@ to gitweb. The list of projects is generated by default by scanning the more exact; gitweb is not interested in a working area, and is best suited to showing "bare" repositories). -The name of repository in gitweb is path to it's `$GIT_DIR` (it's object +The name of the repository in gitweb is the path to its `$GIT_DIR` (its object database) relative to `$projectroot`. Therefore the repository $repo can be found at "$projectroot/$repo". diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt index f2f1d0f51c..0bcbe0ac3c 100644 --- a/Documentation/merge-options.txt +++ b/Documentation/merge-options.txt @@ -24,13 +24,18 @@ updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be set to `no` at the beginning of them. --ff:: + When the merge resolves as a fast-forward, only update the branch + pointer, without creating a merge commit. This is the default + behavior. + --no-ff:: - Do not generate a merge commit if the merge resolved as - a fast-forward, only update the branch pointer. This is - the default behavior of git-merge. -+ -With --no-ff Generate a merge commit even if the merge -resolved as a fast-forward. + Create a merge commit even when the merge resolves as a + fast-forward. + +--ff-only:: + Refuse to merge and exit with a non-zero status unless the + current `HEAD` is already up-to-date or the merge can be + resolved as a fast-forward. --log[=<n>]:: --no-log:: @@ -65,11 +70,6 @@ merge. With --no-squash perform the merge and commit the result. This option can be used to override --squash. ---ff-only:: - Refuse to merge and exit with a non-zero status unless the - current `HEAD` is already up-to-date or the merge can be - resolved as a fast-forward. - -s <strategy>:: --strategy=<strategy>:: Use the given merge strategy; can be supplied more than diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index 39e6207269..6a4b6355ba 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -117,27 +117,27 @@ parents) and `--max-parents=-1` (negative numbers denote no upper limit). Pretend as if all the refs in `refs/heads` are listed on the command line as '<commit>'. If '<pattern>' is given, limit branches to ones matching given shell glob. If pattern lacks '?', - '*', or '[', '/*' at the end is implied. + '{asterisk}', or '[', '/{asterisk}' at the end is implied. --tags[=<pattern>]:: Pretend as if all the refs in `refs/tags` are listed on the command line as '<commit>'. If '<pattern>' is given, limit - tags to ones matching given shell glob. If pattern lacks '?', '*', - or '[', '/*' at the end is implied. + tags to ones matching given shell glob. If pattern lacks '?', '{asterisk}', + or '[', '/{asterisk}' at the end is implied. --remotes[=<pattern>]:: Pretend as if all the refs in `refs/remotes` are listed on the command line as '<commit>'. If '<pattern>' is given, limit remote-tracking branches to ones matching given shell glob. - If pattern lacks '?', '*', or '[', '/*' at the end is implied. + If pattern lacks '?', '{asterisk}', or '[', '/{asterisk}' at the end is implied. --glob=<glob-pattern>:: Pretend as if all the refs matching shell glob '<glob-pattern>' are listed on the command line as '<commit>'. Leading 'refs/', - is automatically prepended if missing. If pattern lacks '?', '*', - or '[', '/*' at the end is implied. + is automatically prepended if missing. If pattern lacks '?', '{asterisk}', + or '[', '/{asterisk}' at the end is implied. --ignore-missing:: diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt index b290b617d4..1725661837 100644 --- a/Documentation/revisions.txt +++ b/Documentation/revisions.txt @@ -101,7 +101,7 @@ the '$GIT_DIR/refs' directory or from the '$GIT_DIR/packed-refs' file. '<rev>{tilde}<n>', e.g. 'master{tilde}3':: A suffix '{tilde}<n>' to a revision parameter means the commit - object that is the <n>th generation grand-parent of the named + object that is the <n>th generation ancestor of the named commit object, following only the first parents. I.e. '<rev>{tilde}3' is equivalent to '<rev>{caret}{caret}{caret}' which is equivalent to '<rev>{caret}1{caret}1{caret}1'. See below for an illustration of diff --git a/Documentation/technical/api-config.txt b/Documentation/technical/api-config.txt new file mode 100644 index 0000000000..edf8dfb99b --- /dev/null +++ b/Documentation/technical/api-config.txt @@ -0,0 +1,140 @@ +config API +========== + +The config API gives callers a way to access git configuration files +(and files which have the same syntax). See linkgit:git-config[1] for a +discussion of the config file syntax. + +General Usage +------------- + +Config files are parsed linearly, and each variable found is passed to a +caller-provided callback function. The callback function is responsible +for any actions to be taken on the config option, and is free to ignore +some options. It is not uncommon for the configuration to be parsed +several times during the run of a git program, with different callbacks +picking out different variables useful to themselves. + +A config callback function takes three parameters: + +- the name of the parsed variable. This is in canonical "flat" form: the + section, subsection, and variable segments will be separated by dots, + and the section and variable segments will be all lowercase. E.g., + `core.ignorecase`, `diff.SomeType.textconv`. + +- the value of the found variable, as a string. If the variable had no + value specified, the value will be NULL (typically this means it + should be interpreted as boolean true). + +- a void pointer passed in by the caller of the config API; this can + contain callback-specific data + +A config callback should return 0 for success, or -1 if the variable +could not be parsed properly. + +Basic Config Querying +--------------------- + +Most programs will simply want to look up variables in all config files +that git knows about, using the normal precedence rules. To do this, +call `git_config` with a callback function and void data pointer. + +`git_config` will read all config sources in order of increasing +priority. Thus a callback should typically overwrite previously-seen +entries with new ones (e.g., if both the user-wide `~/.gitconfig` and +repo-specific `.git/config` contain `color.ui`, the config machinery +will first feed the user-wide one to the callback, and then the +repo-specific one; by overwriting, the higher-priority repo-specific +value is left at the end). + +The `git_config_with_options` function lets the caller examine config +while adjusting some of the default behavior of `git_config`. It should +almost never be used by "regular" git code that is looking up +configuration variables. It is intended for advanced callers like +`git-config`, which are intentionally tweaking the normal config-lookup +process. It takes two extra parameters: + +`filename`:: +If this parameter is non-NULL, it specifies the name of a file to +parse for configuration, rather than looking in the usual files. Regular +`git_config` defaults to `NULL`. + +`respect_includes`:: +Specify whether include directives should be followed in parsed files. +Regular `git_config` defaults to `1`. + +There is a special version of `git_config` called `git_config_early`. +This version takes an additional parameter to specify the repository +config, instead of having it looked up via `git_path`. This is useful +early in a git program before the repository has been found. Unless +you're working with early setup code, you probably don't want to use +this. + +Reading Specific Files +---------------------- + +To read a specific file in git-config format, use +`git_config_from_file`. This takes the same callback and data parameters +as `git_config`. + +Value Parsing Helpers +--------------------- + +To aid in parsing string values, the config API provides callbacks with +a number of helper functions, including: + +`git_config_int`:: +Parse the string to an integer, including unit factors. Dies on error; +otherwise, returns the parsed result. + +`git_config_ulong`:: +Identical to `git_config_int`, but for unsigned longs. + +`git_config_bool`:: +Parse a string into a boolean value, respecting keywords like "true" and +"false". Integer values are converted into true/false values (when they +are non-zero or zero, respectively). Other values cause a die(). If +parsing is successful, the return value is the result. + +`git_config_bool_or_int`:: +Same as `git_config_bool`, except that integers are returned as-is, and +an `is_bool` flag is unset. + +`git_config_maybe_bool`:: +Same as `git_config_bool`, except that it returns -1 on error rather +than dying. + +`git_config_string`:: +Allocates and copies the value string into the `dest` parameter; if no +string is given, prints an error message and returns -1. + +`git_config_pathname`:: +Similar to `git_config_string`, but expands `~` or `~user` into the +user's home directory when found at the beginning of the path. + +Include Directives +------------------ + +By default, the config parser does not respect include directives. +However, a caller can use the special `git_config_include` wrapper +callback to support them. To do so, you simply wrap your "real" callback +function and data pointer in a `struct config_include_data`, and pass +the wrapper to the regular config-reading functions. For example: + +------------------------------------------- +int read_file_with_include(const char *file, config_fn_t fn, void *data) +{ + struct config_include_data inc = CONFIG_INCLUDE_INIT; + inc.fn = fn; + inc.data = data; + return git_config_from_file(git_config_include, file, &inc); +} +------------------------------------------- + +`git_config` respects includes automatically. The lower-level +`git_config_from_file` does not. + +Writing Config Files +-------------------- + +TODO diff --git a/Documentation/technical/api-parse-options.txt b/Documentation/technical/api-parse-options.txt index 4b92514f60..2527b7e8d7 100644 --- a/Documentation/technical/api-parse-options.txt +++ b/Documentation/technical/api-parse-options.txt @@ -39,7 +39,8 @@ The parse-options API allows: * Short options may be bundled, e.g. `-a -b` can be specified as `-ab`. * Boolean long options can be 'negated' (or 'unset') by prepending - `no-`, e.g. `\--no-abbrev` instead of `\--abbrev`. + `no-`, e.g. `\--no-abbrev` instead of `\--abbrev`. Conversely, + options that begin with `no-` can be 'negated' by removing it. * Options and non-option arguments can clearly be separated using the `\--` option, e.g. `-a -b \--option \-- \--this-is-a-file` indicates that diff --git a/Documentation/technical/api-strbuf.txt b/Documentation/technical/api-strbuf.txt index afe2759951..95a8bf3846 100644 --- a/Documentation/technical/api-strbuf.txt +++ b/Documentation/technical/api-strbuf.txt @@ -255,8 +255,24 @@ same behaviour as well. `strbuf_getline`:: - Read a line from a FILE* pointer. The second argument specifies the line + Read a line from a FILE *, overwriting the existing contents + of the strbuf. The second argument specifies the line terminator character, typically `'\n'`. + Reading stops after the terminator or at EOF. The terminator + is removed from the buffer before returning. Returns 0 unless + there was nothing left before EOF, in which case it returns `EOF`. + +`strbuf_getwholeline`:: + + Like `strbuf_getline`, but keeps the trailing terminator (if + any) in the buffer. + +`strbuf_getwholeline_fd`:: + + Like `strbuf_getwholeline`, but operates on a file descriptor. + It reads one character at a time, so it is very slow. Do not + use it unless you need the correct position in the file + descriptor. `stripspace`:: diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt index f13a846131..6c7fee7ef7 100644 --- a/Documentation/user-manual.txt +++ b/Documentation/user-manual.txt @@ -1582,7 +1582,7 @@ Checking the repository for corruption The linkgit:git-fsck[1] command runs a number of self-consistency checks on the repository, and reports on any problems. This may take some -time. The most common warning by far is about "dangling" objects: +time. ------------------------------------------------- $ git fsck @@ -1597,9 +1597,11 @@ dangling tree b24c2473f1fd3d91352a624795be026d64c8841f ... ------------------------------------------------- -Dangling objects are not a problem. At worst they may take up a little -extra disk space. They can sometimes provide a last-resort method for -recovering lost work--see <<dangling-objects>> for details. +You will see informational messages on dangling objects. They are objects +that still exist in the repository but are no longer referenced by any of +your branches, and can (and will) be removed after a while with "gc". +You can run `git fsck --no-dangling` to supress these messages, and still +view real errors. [[recovering-lost-changes]] Recovering lost changes @@ -3295,15 +3297,12 @@ it is with linkgit:git-fsck[1]; this may be time-consuming. Assume the output looks like this: ------------------------------------------------ -$ git fsck --full +$ git fsck --full --no-dangling broken link from tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8 to blob 4b9458b3786228369c63936db65827de3cc06200 missing blob 4b9458b3786228369c63936db65827de3cc06200 ------------------------------------------------ -(Typically there will be some "dangling object" messages too, but they -aren't interesting.) - Now you know that blob 4b9458b3 is missing, and that the tree 2d9263c6 points to it. If you could find just one copy of that missing blob object, possibly in some other repository, you could move it into diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index c25fd2a374..1c06cec047 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.7.9.GIT +DEF_VER=v1.7.10-rc1 LF=' ' @@ -28,16 +28,25 @@ set up install paths (via config.mak.autogen), so you can write instead If you're willing to trade off (much) longer build time for a later faster git you can also do a profile feedback build with - $ make profile-all - # make prefix=... install + $ make prefix=/usr PROFILE=BUILD all + # make prefix=/usr PROFILE=BUILD install This will run the complete test suite as training workload and then rebuild git with the generated profile feedback. This results in a git which is a few percent faster on CPU intensive workloads. This may be a good tradeoff for distribution packagers. -Note that the profile feedback build stage currently generates -a lot of additional compiler warnings. +Or if you just want to install a profile-optimized version of git into +your home directory, you could run: + + $ make PROFILE=BUILD install + +As a caveat: a profile-optimized build takes a *lot* longer since the +git tree must be built twice, and in order for the profiling +measurements to work properly, ccache must be disabled and the test +suite has to be run using only a single CPU. In addition, the profile +feedback build stage currently generates a lot of additional compiler +warnings. Issues of note: @@ -56,6 +56,10 @@ all:: # FreeBSD can use either, but MinGW and some others need to use # libcharset.h's locale_charset() instead. # +# Define CHARSET_LIB to you need to link with library other than -liconv to +# use locale_charset() function. On some platforms this needs to set to +# -lcharset +# # Define LIBC_CONTAINS_LIBINTL if your gettext implementation doesn't # need -lintl when linking. # @@ -342,7 +346,7 @@ pathsep = : export prefix bindir sharedir sysconfdir gitwebdir localedir -CC = gcc +CC = cc AR = ar RM = rm -f DIFF = diff @@ -616,6 +620,7 @@ LIB_H += streaming.h LIB_H += string-list.h LIB_H += submodule.h LIB_H += tag.h +LIB_H += thread-utils.h LIB_H += transport.h LIB_H += tree.h LIB_H += tree-walk.h @@ -1701,6 +1706,7 @@ endif ifdef HAVE_LIBCHARSET_H BASIC_CFLAGS += -DHAVE_LIBCHARSET_H + EXTLIBS += $(CHARSET_LIB) endif ifdef HAVE_DEV_TTY @@ -1777,6 +1783,26 @@ ifdef ASCIIDOC7 export ASCIIDOC7 endif +### profile feedback build +# + +# Can adjust this to be a global directory if you want to do extended +# data gathering +PROFILE_DIR := $(CURDIR) + +ifeq ("$(PROFILE)","GEN") + CFLAGS += -fprofile-generate=$(PROFILE_DIR) -DNO_NORETURN=1 + EXTLIBS += -lgcov + export CCACHE_DISABLE=t + V=1 +else +ifneq ("$(PROFILE)","") + CFLAGS += -fprofile-use=$(PROFILE_DIR) -fprofile-correction -DNO_NORETURN=1 + export CCACHE_DISABLE=t + V=1 +endif +endif + # Shell quote (do not use $(call) to accommodate ancient setups); SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER)) @@ -1833,7 +1859,17 @@ export DIFF TAR INSTALL DESTDIR SHELL_PATH SHELL = $(SHELL_PATH) -all:: shell_compatibility_test $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS +all:: shell_compatibility_test + +ifeq "$(PROFILE)" "BUILD" +ifeq ($(filter all,$(MAKECMDGOALS)),all) +all:: profile-clean + $(MAKE) PROFILE=GEN all + $(MAKE) PROFILE=GEN -j1 test +endif +endif + +all:: $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS ifneq (,$X) $(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test -d '$p' -o '$p' -ef '$p$X' || $(RM) '$p';) endif @@ -2326,6 +2362,10 @@ GIT-BUILD-OPTIONS: FORCE @echo USE_LIBPCRE=\''$(subst ','\'',$(subst ','\'',$(USE_LIBPCRE)))'\' >>$@ @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@ @echo NO_PYTHON=\''$(subst ','\'',$(subst ','\'',$(NO_PYTHON)))'\' >>$@ + @echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@ +ifdef GIT_TEST_OPTS + @echo GIT_TEST_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_OPTS)))'\' >>$@ +endif ifdef GIT_TEST_CMP @echo GIT_TEST_CMP=\''$(subst ','\'',$(subst ','\'',$(GIT_TEST_CMP)))'\' >>$@ endif @@ -2334,7 +2374,18 @@ ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT endif @echo NO_GETTEXT=\''$(subst ','\'',$(subst ','\'',$(NO_GETTEXT)))'\' >>$@ @echo GETTEXT_POISON=\''$(subst ','\'',$(subst ','\'',$(GETTEXT_POISON)))'\' >>$@ - @echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@ +ifdef GIT_PERF_REPEAT_COUNT + @echo GIT_PERF_REPEAT_COUNT=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_REPEAT_COUNT)))'\' >>$@ +endif +ifdef GIT_PERF_REPO + @echo GIT_PERF_REPO=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_REPO)))'\' >>$@ +endif +ifdef GIT_PERF_LARGE_REPO + @echo GIT_PERF_LARGE_REPO=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_LARGE_REPO)))'\' >>$@ +endif +ifdef GIT_PERF_MAKE_OPTS + @echo GIT_PERF_MAKE_OPTS=\''$(subst ','\'',$(subst ','\'',$(GIT_PERF_MAKE_OPTS)))'\' >>$@ +endif ### Detect Tck/Tk interpreter path changes ifndef NO_TCLTK @@ -2370,6 +2421,11 @@ export NO_SVN_TESTS test: all $(MAKE) -C t/ all +perf: all + $(MAKE) -C t/perf/ all + +.PHONY: test perf + test-ctype$X: ctype.o test-date$X: date.o ctype.o @@ -2579,9 +2635,12 @@ dist-doc: distclean: clean $(RM) configure - $(RM) po/git.pot -clean: +profile-clean: + $(RM) $(addsuffix *.gcda,$(addprefix $(PROFILE_DIR)/, $(object_dirs))) + $(RM) $(addsuffix *.gcno,$(addprefix $(PROFILE_DIR)/, $(object_dirs))) + +clean: profile-clean $(RM) *.o block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o vcs-svn/*.o \ builtin/*.o $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB) $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X @@ -2611,7 +2670,7 @@ ifndef NO_TCLTK endif $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-LDFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS -.PHONY: all install clean strip +.PHONY: all install profile-clean clean strip .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell .PHONY: FORCE cscope @@ -2721,18 +2780,3 @@ cover_db: coverage-report cover_db_html: cover_db cover -report html -outputdir cover_db_html cover_db -### profile feedback build -# -.PHONY: profile-all profile-clean - -PROFILE_GEN_CFLAGS := $(CFLAGS) -fprofile-generate -DNO_NORETURN=1 -PROFILE_USE_CFLAGS := $(CFLAGS) -fprofile-use -fprofile-correction -DNO_NORETURN=1 - -profile-clean: - $(RM) $(addsuffix *.gcda,$(object_dirs)) - $(RM) $(addsuffix *.gcno,$(object_dirs)) - -profile-all: profile-clean - $(MAKE) CFLAGS="$(PROFILE_GEN_CFLAGS)" all - $(MAKE) CFLAGS="$(PROFILE_GEN_CFLAGS)" -j1 test - $(MAKE) CFLAGS="$(PROFILE_USE_CFLAGS)" all @@ -42,10 +42,12 @@ including full documentation and Git related tools. The user discussion and development of Git take place on the Git mailing list -- everyone is welcome to post bug reports, feature -requests, comments and patches to git@vger.kernel.org. To subscribe -to the list, send an email with just "subscribe git" in the body to -majordomo@vger.kernel.org. The mailing list archives are available at -http://marc.theaimsgroup.com/?l=git and other archival sites. +requests, comments and patches to git@vger.kernel.org (read +Documentation/SubmittingPatches for instructions on patch submission). +To subscribe to the list, send an email with just "subscribe git" in +the body to majordomo@vger.kernel.org. The mailing list archives are +available at http://marc.theaimsgroup.com/?l=git and other archival +sites. The messages titled "A note from the maintainer", "What's in git.git (stable)" and "What's cooking in git.git (topics)" and @@ -15,13 +15,12 @@ extern void print_commit_list(struct commit_list *list, const char *format_cur, const char *format_last); -/* bisect_show_flags flags in struct rev_list_info */ #define BISECT_SHOW_ALL (1<<0) -#define BISECT_SHOW_TRIED (1<<1) +#define REV_LIST_QUIET (1<<1) struct rev_list_info { struct rev_info *revs; - int bisect_show_flags; + int flags; int show_timestamp; int hdr_termination; const char *header_prefix; diff --git a/builtin/apply.c b/builtin/apply.c index c24dc546d0..389898f133 100644 --- a/builtin/apply.c +++ b/builtin/apply.c @@ -14,6 +14,7 @@ #include "builtin.h" #include "string-list.h" #include "dir.h" +#include "diff.h" #include "parse-options.h" /* @@ -3241,7 +3242,7 @@ static void stat_patch_list(struct patch *patch) show_stats(patch); } - printf(" %d files changed, %d insertions(+), %d deletions(-)\n", files, adds, dels); + print_stat_summary(stdout, files, adds, dels); } static void numstat_patch_list(struct patch *patch) diff --git a/builtin/blame.c b/builtin/blame.c index 5a67c202f0..b35bd6249d 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -1829,18 +1829,6 @@ static int read_ancestry(const char *graft_file) } /* - * How many columns do we need to show line numbers in decimal? - */ -static int lineno_width(int lines) -{ - int i, width; - - for (width = 1, i = 10; i <= lines; width++) - i *= 10; - return width; -} - -/* * How many columns do we need to show line numbers, authors, * and filenames? */ @@ -1880,9 +1868,9 @@ static void find_alignment(struct scoreboard *sb, int *option) if (largest_score < ent_score(sb, e)) largest_score = ent_score(sb, e); } - max_orig_digits = lineno_width(longest_src_lines); - max_digits = lineno_width(longest_dst_lines); - max_score_digits = lineno_width(largest_score); + max_orig_digits = decimal_width(longest_src_lines); + max_digits = decimal_width(longest_dst_lines); + max_score_digits = decimal_width(largest_score); } /* @@ -2050,14 +2038,8 @@ static int git_blame_config(const char *var, const char *value, void *cb) return 0; } - switch (userdiff_config(var, value)) { - case 0: - break; - case -1: + if (userdiff_config(var, value) < 0) return -1; - default: - return 0; - } return git_default_config(var, value, cb); } diff --git a/builtin/branch.c b/builtin/branch.c index cb17bc3675..d8cccf725d 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -530,6 +530,10 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru if (merge_filter != NO_FILTER) { struct commit *filter; filter = lookup_commit_reference_gently(merge_filter_ref, 0); + if (!filter) + die("object '%s' does not point to a commit", + sha1_to_hex(merge_filter_ref)); + filter->object.flags |= UNINTERESTING; add_pending_object(&ref_list.revs, (struct object *) filter, ""); diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 07bd984084..8ed501f220 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -226,14 +226,8 @@ static const char * const cat_file_usage[] = { static int git_cat_file_config(const char *var, const char *value, void *cb) { - switch (userdiff_config(var, value)) { - case 0: - break; - case -1: + if (userdiff_config(var, value) < 0) return -1; - default: - return 0; - } return git_default_config(var, value, cb); } diff --git a/builtin/checkout.c b/builtin/checkout.c index 5bf96ba4d4..6b9061f26f 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -908,6 +908,17 @@ static int parse_branchname_arg(int argc, const char **argv, return argcount; } +static int switch_unborn_to_new_branch(struct checkout_opts *opts) +{ + int status; + struct strbuf branch_ref = STRBUF_INIT; + + strbuf_addf(&branch_ref, "refs/heads/%s", opts->new_branch); + status = create_symref("HEAD", branch_ref.buf, "checkout -b"); + strbuf_release(&branch_ref); + return status; +} + int cmd_checkout(int argc, const char **argv, const char *prefix) { struct checkout_opts opts; @@ -1079,5 +1090,13 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) if (opts.writeout_stage) die(_("--ours/--theirs is incompatible with switching branches.")); + if (!new.commit) { + unsigned char rev[20]; + int flag; + + if (!read_ref_full("HEAD", rev, 0, &flag) && + (flag & REF_ISSYMREF) && is_null_sha1(rev)) + return switch_unborn_to_new_branch(&opts); + } return switch_branches(&opts, &new); } diff --git a/builtin/clone.c b/builtin/clone.c index c62d4b5737..bbd5c96237 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -45,7 +45,7 @@ static char *option_branch = NULL; static const char *real_git_dir; static char *option_upload_pack = "git-upload-pack"; static int option_verbosity; -static int option_progress; +static int option_progress = -1; static struct string_list option_config; static struct string_list option_reference; @@ -60,8 +60,8 @@ static int opt_parse_reference(const struct option *opt, const char *arg, int un static struct option builtin_clone_options[] = { OPT__VERBOSITY(&option_verbosity), - OPT_BOOLEAN(0, "progress", &option_progress, - "force progress reporting"), + OPT_BOOL(0, "progress", &option_progress, + "force progress reporting"), OPT_BOOLEAN('n', "no-checkout", &option_no_checkout, "don't create a checkout"), OPT_BOOLEAN(0, "bare", &option_bare, "create a bare repository"), @@ -107,7 +107,7 @@ static const char *argv_submodule[] = { static char *get_repo_path(const char *repo, int *is_bundle) { - static char *suffix[] = { "/.git", ".git", "" }; + static char *suffix[] = { "/.git", "", ".git/.git", ".git" }; static char *bundle_suffix[] = { ".bundle", "" }; struct stat st; int i; @@ -117,7 +117,7 @@ static char *get_repo_path(const char *repo, int *is_bundle) path = mkpath("%s%s", repo, suffix[i]); if (stat(path, &st)) continue; - if (S_ISDIR(st.st_mode)) { + if (S_ISDIR(st.st_mode) && is_git_directory(path)) { *is_bundle = 0; return xstrdup(absolute_path(path)); } else if (S_ISREG(st.st_mode) && st.st_size > 8) { @@ -232,9 +232,6 @@ static int add_one_reference(struct string_list_item *item, void *cb_data) { char *ref_git; struct strbuf alternate = STRBUF_INIT; - struct remote *remote; - struct transport *transport; - const struct ref *extra; /* Beware: real_path() and mkpath() return static buffer */ ref_git = xstrdup(real_path(item->string)); @@ -249,14 +246,6 @@ static int add_one_reference(struct string_list_item *item, void *cb_data) strbuf_addf(&alternate, "%s/objects", ref_git); add_to_alternates_file(alternate.buf); strbuf_release(&alternate); - - remote = remote_get(ref_git); - transport = transport_get(remote, ref_git); - for (extra = transport_get_remote_refs(transport); extra; - extra = extra->next) - add_extra_ref(extra->name, extra->old_sha1, 0); - - transport_disconnect(transport); free(ref_git); return 0; } @@ -500,7 +489,6 @@ static void update_remote_refs(const struct ref *refs, const char *msg) { if (refs) { - clear_extra_refs(); write_remote_refs(mapped_refs); if (option_single_branch) write_followtags(refs, msg); @@ -813,28 +801,28 @@ int cmd_clone(int argc, const char **argv, const char *prefix) } refs = transport_get_remote_refs(transport); - mapped_refs = refs ? wanted_peer_refs(refs, refspec) : NULL; - /* - * transport_get_remote_refs() may return refs with null sha-1 - * in mapped_refs (see struct transport->get_refs_list - * comment). In that case we need fetch it early because - * remote_head code below relies on it. - * - * for normal clones, transport_get_remote_refs() should - * return reliable ref set, we can delay cloning until after - * remote HEAD check. - */ - for (ref = refs; ref; ref = ref->next) - if (is_null_sha1(ref->old_sha1)) { - complete_refs_before_fetch = 0; - break; - } + if (refs) { + mapped_refs = wanted_peer_refs(refs, refspec); + /* + * transport_get_remote_refs() may return refs with null sha-1 + * in mapped_refs (see struct transport->get_refs_list + * comment). In that case we need fetch it early because + * remote_head code below relies on it. + * + * for normal clones, transport_get_remote_refs() should + * return reliable ref set, we can delay cloning until after + * remote HEAD check. + */ + for (ref = refs; ref; ref = ref->next) + if (is_null_sha1(ref->old_sha1)) { + complete_refs_before_fetch = 0; + break; + } - if (!is_local && !complete_refs_before_fetch && refs) - transport_fetch_refs(transport, mapped_refs); + if (!is_local && !complete_refs_before_fetch) + transport_fetch_refs(transport, mapped_refs); - if (refs) { remote_head = find_ref_by_name(refs, "HEAD"); remote_head_points_at = guess_remote_head(remote_head, mapped_refs, 0); @@ -852,6 +840,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) } else { warning(_("You appear to have cloned an empty repository.")); + mapped_refs = NULL; our_head_points_at = NULL; remote_head_points_at = NULL; remote_head = NULL; diff --git a/builtin/commit.c b/builtin/commit.c index eae5a29aeb..3714582e19 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -400,7 +400,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, fd = hold_locked_index(&index_lock, 1); add_files_to_cache(also ? prefix : NULL, pathspec, 0); refresh_cache_or_die(refresh_flags); - update_main_cache_tree(1); + update_main_cache_tree(WRITE_TREE_SILENT); if (write_cache(fd, active_cache, active_nr) || close_lock_file(&index_lock)) die(_("unable to write new_index file")); @@ -421,7 +421,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, fd = hold_locked_index(&index_lock, 1); refresh_cache_or_die(refresh_flags); if (active_cache_changed) { - update_main_cache_tree(1); + update_main_cache_tree(WRITE_TREE_SILENT); if (write_cache(fd, active_cache, active_nr) || commit_locked_index(&index_lock)) die(_("unable to write new_index file")); diff --git a/builtin/config.c b/builtin/config.c index d35c06ae51..d41a9bfb14 100644 --- a/builtin/config.c +++ b/builtin/config.c @@ -25,6 +25,7 @@ static const char *given_config_file; static int actions, types; static const char *get_color_slot, *get_colorbool_slot; static int end_null; +static int respect_includes = -1; #define ACTION_GET (1<<0) #define ACTION_GET_ALL (1<<1) @@ -74,6 +75,7 @@ static struct option builtin_config_options[] = { OPT_BIT(0, "path", &types, "value is a path (file or directory name)", TYPE_PATH), OPT_GROUP("Other"), OPT_BOOLEAN('z', "null", &end_null, "terminate values with NUL byte"), + OPT_BOOL(0, "includes", &respect_includes, "respect include directives on lookup"), OPT_END(), }; @@ -161,8 +163,11 @@ static int get_value(const char *key_, const char *regex_) int ret = -1; char *global = NULL, *repo_config = NULL; const char *system_wide = NULL, *local; + struct config_include_data inc = CONFIG_INCLUDE_INIT; + config_fn_t fn; + void *data; - local = config_exclusive_filename; + local = given_config_file; if (!local) { const char *home = getenv("HOME"); local = repo_config = git_pathdup("config"); @@ -213,19 +218,28 @@ static int get_value(const char *key_, const char *regex_) } } + fn = show_config; + data = NULL; + if (respect_includes) { + inc.fn = fn; + inc.data = data; + fn = git_config_include; + data = &inc; + } + if (do_all && system_wide) - git_config_from_file(show_config, system_wide, NULL); + git_config_from_file(fn, system_wide, data); if (do_all && global) - git_config_from_file(show_config, global, NULL); + git_config_from_file(fn, global, data); if (do_all) - git_config_from_file(show_config, local, NULL); - git_config_from_parameters(show_config, NULL); + git_config_from_file(fn, local, data); + git_config_from_parameters(fn, data); if (!do_all && !seen) - git_config_from_file(show_config, local, NULL); + git_config_from_file(fn, local, data); if (!do_all && !seen && global) - git_config_from_file(show_config, global, NULL); + git_config_from_file(fn, global, data); if (!do_all && !seen && system_wide) - git_config_from_file(show_config, system_wide, NULL); + git_config_from_file(fn, system_wide, data); free(key); if (regexp) { @@ -301,7 +315,8 @@ static void get_color(const char *def_color) { get_color_found = 0; parsed_color[0] = '\0'; - git_config(git_get_color_config, NULL); + git_config_with_options(git_get_color_config, NULL, + given_config_file, respect_includes); if (!get_color_found && def_color) color_parse(def_color, "command line", parsed_color); @@ -328,7 +343,8 @@ static int get_colorbool(int print) { get_colorbool_found = -1; get_diff_color_found = -1; - git_config(git_get_colorbool_config, NULL); + git_config_with_options(git_get_colorbool_config, NULL, + given_config_file, respect_includes); if (get_colorbool_found < 0) { if (!strcmp(get_colorbool_slot, "color.diff")) @@ -351,7 +367,7 @@ int cmd_config(int argc, const char **argv, const char *prefix) int nongit = !startup_info->have_repository; char *value; - config_exclusive_filename = getenv(CONFIG_ENVIRONMENT); + given_config_file = getenv(CONFIG_ENVIRONMENT); argc = parse_options(argc, argv, prefix, builtin_config_options, builtin_config_usage, @@ -366,24 +382,28 @@ int cmd_config(int argc, const char **argv, const char *prefix) char *home = getenv("HOME"); if (home) { char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); - config_exclusive_filename = user_config; + given_config_file = user_config; } else { die("$HOME not set"); } } else if (use_system_config) - config_exclusive_filename = git_etc_gitconfig(); + given_config_file = git_etc_gitconfig(); else if (use_local_config) - config_exclusive_filename = git_pathdup("config"); + given_config_file = git_pathdup("config"); else if (given_config_file) { if (!is_absolute_path(given_config_file) && prefix) - config_exclusive_filename = prefix_filename(prefix, - strlen(prefix), - given_config_file); + given_config_file = + xstrdup(prefix_filename(prefix, + strlen(prefix), + given_config_file)); else - config_exclusive_filename = given_config_file; + given_config_file = given_config_file; } + if (respect_includes == -1) + respect_includes = !given_config_file; + if (end_null) { term = '\0'; delim = '\n'; @@ -420,28 +440,30 @@ int cmd_config(int argc, const char **argv, const char *prefix) if (actions == ACTION_LIST) { check_argc(argc, 0, 0); - if (git_config(show_all_config, NULL) < 0) { - if (config_exclusive_filename) + if (git_config_with_options(show_all_config, NULL, + given_config_file, + respect_includes) < 0) { + if (given_config_file) die_errno("unable to read config file '%s'", - config_exclusive_filename); + given_config_file); else die("error processing config file(s)"); } } else if (actions == ACTION_EDIT) { check_argc(argc, 0, 0); - if (!config_exclusive_filename && nongit) + if (!given_config_file && nongit) die("not in a git directory"); git_config(git_default_config, NULL); - launch_editor(config_exclusive_filename ? - config_exclusive_filename : git_path("config"), + launch_editor(given_config_file ? + given_config_file : git_path("config"), NULL, NULL); } else if (actions == ACTION_SET) { int ret; check_argc(argc, 2, 2); value = normalize_value(argv[0], argv[1]); - ret = git_config_set(argv[0], value); + ret = git_config_set_in_file(given_config_file, argv[0], value); if (ret == CONFIG_NOTHING_SET) error("cannot overwrite multiple values with a single value\n" " Use a regexp, --add or --replace-all to change %s.", argv[0]); @@ -450,17 +472,20 @@ int cmd_config(int argc, const char **argv, const char *prefix) else if (actions == ACTION_SET_ALL) { check_argc(argc, 2, 3); value = normalize_value(argv[0], argv[1]); - return git_config_set_multivar(argv[0], value, argv[2], 0); + return git_config_set_multivar_in_file(given_config_file, + argv[0], value, argv[2], 0); } else if (actions == ACTION_ADD) { check_argc(argc, 2, 2); value = normalize_value(argv[0], argv[1]); - return git_config_set_multivar(argv[0], value, "^$", 0); + return git_config_set_multivar_in_file(given_config_file, + argv[0], value, "^$", 0); } else if (actions == ACTION_REPLACE_ALL) { check_argc(argc, 2, 3); value = normalize_value(argv[0], argv[1]); - return git_config_set_multivar(argv[0], value, argv[2], 1); + return git_config_set_multivar_in_file(given_config_file, + argv[0], value, argv[2], 1); } else if (actions == ACTION_GET) { check_argc(argc, 1, 2); @@ -481,18 +506,22 @@ int cmd_config(int argc, const char **argv, const char *prefix) else if (actions == ACTION_UNSET) { check_argc(argc, 1, 2); if (argc == 2) - return git_config_set_multivar(argv[0], NULL, argv[1], 0); + return git_config_set_multivar_in_file(given_config_file, + argv[0], NULL, argv[1], 0); else - return git_config_set(argv[0], NULL); + return git_config_set_in_file(given_config_file, + argv[0], NULL); } else if (actions == ACTION_UNSET_ALL) { check_argc(argc, 1, 2); - return git_config_set_multivar(argv[0], NULL, argv[1], 1); + return git_config_set_multivar_in_file(given_config_file, + argv[0], NULL, argv[1], 1); } else if (actions == ACTION_RENAME_SECTION) { int ret; check_argc(argc, 2, 2); - ret = git_config_rename_section(argv[0], argv[1]); + ret = git_config_rename_section_in_file(given_config_file, + argv[0], argv[1]); if (ret < 0) return ret; if (ret == 0) @@ -501,7 +530,8 @@ int cmd_config(int argc, const char **argv, const char *prefix) else if (actions == ACTION_REMOVE_SECTION) { int ret; check_argc(argc, 1, 1); - ret = git_config_rename_section(argv[0], NULL); + ret = git_config_rename_section_in_file(given_config_file, + argv[0], NULL); if (ret < 0) return ret; if (ret == 0) diff --git a/builtin/diff.c b/builtin/diff.c index 387afa7568..424c815f9b 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -285,6 +285,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix) /* Otherwise, we are doing the usual "git" diff */ rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index; + /* Scale to real terminal size and respect statGraphWidth config */ + rev.diffopt.stat_width = -1; + rev.diffopt.stat_graph_width = -1; + /* Default to let external and textconv be used */ DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL); DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV); diff --git a/builtin/fast-export.c b/builtin/fast-export.c index 08fed989a4..19509ea754 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -647,9 +647,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix) "Output full tree for each commit"), OPT_BOOLEAN(0, "use-done-feature", &use_done_feature, "Use the done feature to terminate the stream"), - { OPTION_NEGBIT, 0, "data", &no_data, NULL, - "Skip output of blob data", - PARSE_OPT_NOARG | PARSE_OPT_NEGHELP, NULL, 1 }, + OPT_BOOL(0, "no-data", &no_data, "Skip output of blob data"), OPT_END() }; diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c index 6207ecd298..7124c4b49c 100644 --- a/builtin/fetch-pack.c +++ b/builtin/fetch-pack.c @@ -58,9 +58,9 @@ static void rev_list_push(struct commit *commit, int mark) } } -static int rev_list_insert_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data) +static int rev_list_insert_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { - struct object *o = deref_tag(parse_object(sha1), path, 0); + struct object *o = deref_tag(parse_object(sha1), refname, 0); if (o && o->type == OBJ_COMMIT) rev_list_push((struct commit *)o, SEEN); @@ -68,9 +68,9 @@ static int rev_list_insert_ref(const char *path, const unsigned char *sha1, int return 0; } -static int clear_marks(const char *path, const unsigned char *sha1, int flag, void *cb_data) +static int clear_marks(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { - struct object *o = deref_tag(parse_object(sha1), path, 0); + struct object *o = deref_tag(parse_object(sha1), refname, 0); if (o && o->type == OBJ_COMMIT) clear_commit_marks((struct commit *)o, @@ -256,11 +256,6 @@ static void insert_one_alternate_ref(const struct ref *ref, void *unused) rev_list_insert_ref(NULL, ref->old_sha1, 0, NULL); } -static void insert_alternate_refs(void) -{ - for_each_alternate_ref(insert_one_alternate_ref, NULL); -} - #define INITIAL_FLUSH 16 #define PIPESAFE_FLUSH 32 #define LARGE_FLUSH 1024 @@ -295,7 +290,7 @@ static int find_common(int fd[2], unsigned char *result_sha1, marked = 1; for_each_ref(rev_list_insert_ref, NULL); - insert_alternate_refs(); + for_each_alternate_ref(insert_one_alternate_ref, NULL); fetching = 0; for ( ; refs ; refs = refs->next) { @@ -493,7 +488,7 @@ done: static struct commit_list *complete; -static int mark_complete(const char *path, const unsigned char *sha1, int flag, void *cb_data) +static int mark_complete(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { struct object *o = parse_object(sha1); @@ -586,6 +581,11 @@ static void filter_refs(struct ref **refs, int nr_match, char **match) *refs = newlist; } +static void mark_alternate_complete(const struct ref *ref, void *unused) +{ + mark_complete(NULL, ref->old_sha1, 0, NULL); +} + static int everything_local(struct ref **refs, int nr_match, char **match) { struct ref *ref; @@ -614,6 +614,7 @@ static int everything_local(struct ref **refs, int nr_match, char **match) if (!args.depth) { for_each_ref(mark_complete, NULL); + for_each_alternate_ref(mark_alternate_complete, NULL); if (cutoff) mark_recent_complete_commits(cutoff); } @@ -736,7 +737,7 @@ static int get_pack(int xd[2], char **pack_lockfile) } else { *av++ = "unpack-objects"; - if (args.quiet) + if (args.quiet || args.no_progress) *av++ = "-q"; } if (*hdr_arg) diff --git a/builtin/fetch.c b/builtin/fetch.c index ab186332fa..65f5f9b72f 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -30,7 +30,7 @@ enum { }; static int all, append, dry_run, force, keep, multiple, prune, update_head_ok, verbosity; -static int progress, recurse_submodules = RECURSE_SUBMODULES_DEFAULT; +static int progress = -1, recurse_submodules = RECURSE_SUBMODULES_DEFAULT; static int tags = TAGS_DEFAULT; static const char *depth; static const char *upload_pack; @@ -78,7 +78,7 @@ static struct option builtin_fetch_options[] = { OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"), OPT_BOOLEAN('u', "update-head-ok", &update_head_ok, "allow updating of HEAD ref"), - OPT_BOOLEAN(0, "progress", &progress, "force progress reporting"), + OPT_BOOL(0, "progress", &progress, "force progress reporting"), OPT_STRING(0, "depth", &depth, "depth", "deepen history of shallow clone"), { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, "dir", diff --git a/builtin/fsck.c b/builtin/fsck.c index 8c479a791b..67eb553c7d 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -29,6 +29,7 @@ static int errors_found; static int write_lost_and_found; static int verbose; static int show_progress = -1; +static int show_dangling = 1; #define ERROR_OBJECT 01 #define ERROR_REACHABLE 02 #define ERROR_PACK 04 @@ -221,8 +222,9 @@ static void check_unreachable_object(struct object *obj) * start looking at, for example. */ if (!obj->used) { - printf("dangling %s %s\n", typename(obj->type), - sha1_to_hex(obj->sha1)); + if (show_dangling) + printf("dangling %s %s\n", typename(obj->type), + sha1_to_hex(obj->sha1)); if (write_lost_and_found) { char *filename = git_path("lost-found/%s/%s", obj->type == OBJ_COMMIT ? "commit" : "other", @@ -614,6 +616,7 @@ static char const * const fsck_usage[] = { static struct option fsck_opts[] = { OPT__VERBOSE(&verbose, "be verbose"), OPT_BOOLEAN(0, "unreachable", &show_unreachable, "show unreachable objects"), + OPT_BOOL(0, "dangling", &show_dangling, "show dangling objects"), OPT_BOOLEAN(0, "tags", &show_tags, "report tags"), OPT_BOOLEAN(0, "root", &show_root, "report root nodes"), OPT_BOOLEAN(0, "cache", &keep_cache_objects, "make index objects head nodes"), diff --git a/builtin/grep.c b/builtin/grep.c index 5c2ae94e55..643938d905 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -29,25 +29,12 @@ static int use_threads = 1; #define THREADS 8 static pthread_t threads[THREADS]; -static void *load_sha1(const unsigned char *sha1, unsigned long *size, - const char *name); -static void *load_file(const char *filename, size_t *sz); - -enum work_type {WORK_SHA1, WORK_FILE}; - /* We use one producer thread and THREADS consumer * threads. The producer adds struct work_items to 'todo' and the * consumers pick work items from the same array. */ struct work_item { - enum work_type type; - char *name; - - /* if type == WORK_SHA1, then 'identifier' is a SHA1, - * otherwise type == WORK_FILE, and 'identifier' is a NUL - * terminated filename. - */ - void *identifier; + struct grep_source source; char done; struct strbuf out; }; @@ -85,21 +72,6 @@ static inline void grep_unlock(void) pthread_mutex_unlock(&grep_mutex); } -/* Used to serialize calls to read_sha1_file. */ -static pthread_mutex_t read_sha1_mutex; - -static inline void read_sha1_lock(void) -{ - if (use_threads) - pthread_mutex_lock(&read_sha1_mutex); -} - -static inline void read_sha1_unlock(void) -{ - if (use_threads) - pthread_mutex_unlock(&read_sha1_mutex); -} - /* Signalled when a new work_item is added to todo. */ static pthread_cond_t cond_add; @@ -113,7 +85,8 @@ static pthread_cond_t cond_result; static int skip_first_line; -static void add_work(enum work_type type, char *name, void *id) +static void add_work(struct grep_opt *opt, enum grep_source_type type, + const char *name, const void *id) { grep_lock(); @@ -121,9 +94,9 @@ static void add_work(enum work_type type, char *name, void *id) pthread_cond_wait(&cond_write, &grep_mutex); } - todo[todo_end].type = type; - todo[todo_end].name = name; - todo[todo_end].identifier = id; + grep_source_init(&todo[todo_end].source, type, name, id); + if (opt->binary != GREP_BINARY_TEXT) + grep_source_load_driver(&todo[todo_end].source); todo[todo_end].done = 0; strbuf_reset(&todo[todo_end].out); todo_end = (todo_end + 1) % ARRAY_SIZE(todo); @@ -151,21 +124,6 @@ static struct work_item *get_work(void) return ret; } -static void grep_sha1_async(struct grep_opt *opt, char *name, - const unsigned char *sha1) -{ - unsigned char *s; - s = xmalloc(20); - memcpy(s, sha1, 20); - add_work(WORK_SHA1, name, s); -} - -static void grep_file_async(struct grep_opt *opt, char *name, - const char *filename) -{ - add_work(WORK_FILE, name, xstrdup(filename)); -} - static void work_done(struct work_item *w) { int old_done; @@ -192,8 +150,7 @@ static void work_done(struct work_item *w) write_or_die(1, p, len); } - free(w->name); - free(w->identifier); + grep_source_clear(&w->source); } if (old_done != todo_done) @@ -216,25 +173,8 @@ static void *run(void *arg) break; opt->output_priv = w; - if (w->type == WORK_SHA1) { - unsigned long sz; - void* data = load_sha1(w->identifier, &sz, w->name); - - if (data) { - hit |= grep_buffer(opt, w->name, data, sz); - free(data); - } - } else if (w->type == WORK_FILE) { - size_t sz; - void* data = load_file(w->identifier, &sz); - if (data) { - hit |= grep_buffer(opt, w->name, data, sz); - free(data); - } - } else { - assert(0); - } - + hit |= grep_source(opt, &w->source); + grep_source_clear_data(&w->source); work_done(w); } free_grep_patterns(arg); @@ -254,11 +194,12 @@ static void start_threads(struct grep_opt *opt) int i; pthread_mutex_init(&grep_mutex, NULL); - pthread_mutex_init(&read_sha1_mutex, NULL); + pthread_mutex_init(&grep_read_mutex, NULL); pthread_mutex_init(&grep_attr_mutex, NULL); pthread_cond_init(&cond_add, NULL); pthread_cond_init(&cond_write, NULL); pthread_cond_init(&cond_result, NULL); + grep_use_locks = 1; for (i = 0; i < ARRAY_SIZE(todo); i++) { strbuf_init(&todo[i].out, 0); @@ -302,17 +243,16 @@ static int wait_all(void) } pthread_mutex_destroy(&grep_mutex); - pthread_mutex_destroy(&read_sha1_mutex); + pthread_mutex_destroy(&grep_read_mutex); pthread_mutex_destroy(&grep_attr_mutex); pthread_cond_destroy(&cond_add); pthread_cond_destroy(&cond_write); pthread_cond_destroy(&cond_result); + grep_use_locks = 0; return hit; } #else /* !NO_PTHREADS */ -#define read_sha1_lock() -#define read_sha1_unlock() static int wait_all(void) { @@ -325,11 +265,8 @@ static int grep_config(const char *var, const char *value, void *cb) struct grep_opt *opt = cb; char *color = NULL; - switch (userdiff_config(var, value)) { - case 0: break; - case -1: return -1; - default: return 0; - } + if (userdiff_config(var, value) < 0) + return -1; if (!strcmp(var, "grep.extendedregexp")) { if (git_config_bool(var, value)) @@ -374,21 +311,9 @@ static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type { void *data; - read_sha1_lock(); + grep_read_lock(); data = read_sha1_file(sha1, type, size); - read_sha1_unlock(); - return data; -} - -static void *load_sha1(const unsigned char *sha1, unsigned long *size, - const char *name) -{ - enum object_type type; - void *data = lock_and_read_sha1_file(sha1, &type, size); - - if (!data) - error(_("'%s': unable to read %s"), name, sha1_to_hex(sha1)); - + grep_read_unlock(); return data; } @@ -396,7 +321,6 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char *filename, int tree_name_len) { struct strbuf pathbuf = STRBUF_INIT; - char *name; if (opt->relative && opt->prefix_length) { quote_path_relative(filename + tree_name_len, -1, &pathbuf, @@ -406,87 +330,51 @@ static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, strbuf_addstr(&pathbuf, filename); } - name = strbuf_detach(&pathbuf, NULL); - #ifndef NO_PTHREADS if (use_threads) { - grep_sha1_async(opt, name, sha1); + add_work(opt, GREP_SOURCE_SHA1, pathbuf.buf, sha1); + strbuf_release(&pathbuf); return 0; } else #endif { + struct grep_source gs; int hit; - unsigned long sz; - void *data = load_sha1(sha1, &sz, name); - if (!data) - hit = 0; - else - hit = grep_buffer(opt, name, data, sz); - free(data); - free(name); - return hit; - } -} + grep_source_init(&gs, GREP_SOURCE_SHA1, pathbuf.buf, sha1); + strbuf_release(&pathbuf); + hit = grep_source(opt, &gs); -static void *load_file(const char *filename, size_t *sz) -{ - struct stat st; - char *data; - int i; - - if (lstat(filename, &st) < 0) { - err_ret: - if (errno != ENOENT) - error(_("'%s': %s"), filename, strerror(errno)); - return NULL; - } - if (!S_ISREG(st.st_mode)) - return NULL; - *sz = xsize_t(st.st_size); - i = open(filename, O_RDONLY); - if (i < 0) - goto err_ret; - data = xmalloc(*sz + 1); - if (st.st_size != read_in_full(i, data, *sz)) { - error(_("'%s': short read %s"), filename, strerror(errno)); - close(i); - free(data); - return NULL; + grep_source_clear(&gs); + return hit; } - close(i); - data[*sz] = 0; - return data; } static int grep_file(struct grep_opt *opt, const char *filename) { struct strbuf buf = STRBUF_INIT; - char *name; if (opt->relative && opt->prefix_length) quote_path_relative(filename, -1, &buf, opt->prefix); else strbuf_addstr(&buf, filename); - name = strbuf_detach(&buf, NULL); #ifndef NO_PTHREADS if (use_threads) { - grep_file_async(opt, name, filename); + add_work(opt, GREP_SOURCE_FILE, buf.buf, filename); + strbuf_release(&buf); return 0; } else #endif { + struct grep_source gs; int hit; - size_t sz; - void *data = load_file(filename, &sz); - if (!data) - hit = 0; - else - hit = grep_buffer(opt, name, data, sz); - free(data); - free(name); + grep_source_init(&gs, GREP_SOURCE_FILE, buf.buf, filename); + strbuf_release(&buf); + hit = grep_source(opt, &gs); + + grep_source_clear(&gs); return hit; } } @@ -615,10 +503,10 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec, struct strbuf base; int hit, len; - read_sha1_lock(); + grep_read_lock(); data = read_object_with_reference(obj->sha1, tree_type, &size, NULL); - read_sha1_unlock(); + grep_read_unlock(); if (!data) die(_("unable to read tree (%s)"), sha1_to_hex(obj->sha1)); @@ -796,9 +684,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix) struct option options[] = { OPT_BOOLEAN(0, "cached", &cached, "search in index instead of in the work tree"), - { OPTION_BOOLEAN, 0, "index", &use_index, NULL, - "finds in contents not managed by git", - PARSE_OPT_NOARG | PARSE_OPT_NEGHELP }, + OPT_NEGBIT(0, "no-index", &use_index, + "finds in contents not managed by git", 1), OPT_BOOLEAN(0, "untracked", &untracked, "search in both tracked and untracked files"), OPT_SET_INT(0, "exclude-standard", &opt_exclude, @@ -1030,8 +917,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix) use_threads = 0; #endif - opt.use_threads = use_threads; - #ifndef NO_PTHREADS if (use_threads) { if (!(opt.name_only || opt.unmatch_name_only || opt.count) diff --git a/builtin/log.c b/builtin/log.c index 7d1f6f88a0..8a47012b0b 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -77,6 +77,8 @@ static void cmd_log_init_defaults(struct rev_info *rev) get_commit_format(fmt_pretty, rev); rev->verbose_header = 1; DIFF_OPT_SET(&rev->diffopt, RECURSIVE); + rev->diffopt.stat_width = -1; /* use full terminal width */ + rev->diffopt.stat_graph_width = -1; /* respect statGraphWidth config */ rev->abbrev_commit = default_abbrev_commit; rev->show_root_diff = default_show_root; rev->subject_prefix = fmt_patch_subject_prefix; @@ -447,6 +449,8 @@ int cmd_show(int argc, const char **argv, const char *prefix) rev.diff = 1; rev.always_show_header = 1; rev.no_walk = 1; + rev.diffopt.stat_width = -1; /* Scale to real terminal size */ + memset(&opt, 0, sizeof(opt)); opt.def = "HEAD"; opt.tweak = show_rev_tweak_rev; diff --git a/builtin/merge.c b/builtin/merge.c index ed0f959ac4..cb8f14910b 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -399,6 +399,8 @@ static void finish(struct commit *head_commit, if (new_head && show_diffstat) { struct diff_options opts; diff_setup(&opts); + opts.stat_width = -1; /* use full terminal width */ + opts.stat_graph_width = -1; /* respect statGraphWidth config */ opts.output_format |= DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT; opts.detect_rename = DIFF_DETECT_RENAME; @@ -1129,7 +1131,7 @@ static int default_edit_option(void) /* Use editor if stdin and stdout are the same and is a tty */ return (!fstat(0, &st_stdin) && !fstat(1, &st_stdout) && - isatty(0) && + isatty(0) && isatty(1) && st_stdin.st_dev == st_stdout.st_dev && st_stdin.st_ino == st_stdout.st_ino && st_stdin.st_mode == st_stdout.st_mode); diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 0f2e7b8f5c..7b07c092cc 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -18,16 +18,11 @@ #include "refs.h" #include "thread-utils.h" -static const char pack_usage[] = - "git pack-objects [ -q | --progress | --all-progress ]\n" - " [--all-progress-implied]\n" - " [--max-pack-size=<n>] [--local] [--incremental]\n" - " [--window=<n>] [--window-memory=<n>] [--depth=<n>]\n" - " [--no-reuse-delta] [--no-reuse-object] [--delta-base-offset]\n" - " [--threads=<n>] [--non-empty] [--revs [--unpacked | --all]]\n" - " [--reflog] [--stdout | base-name] [--include-tag]\n" - " [--keep-unreachable | --unpack-unreachable]\n" - " [< ref-list | < object-list]"; +static const char *pack_usage[] = { + "git pack-objects --stdout [options...] [< ref-list | < object-list]", + "git pack-objects [options...] base-name [< ref-list | < object-list]", + NULL +}; struct object_entry { struct pack_idx_entry idx; @@ -2305,204 +2300,159 @@ static void get_object_list(int ac, const char **av) loosen_unused_packed_objects(&revs); } +static int option_parse_index_version(const struct option *opt, + const char *arg, int unset) +{ + char *c; + const char *val = arg; + pack_idx_opts.version = strtoul(val, &c, 10); + if (pack_idx_opts.version > 2) + die(_("unsupported index version %s"), val); + if (*c == ',' && c[1]) + pack_idx_opts.off32_limit = strtoul(c+1, &c, 0); + if (*c || pack_idx_opts.off32_limit & 0x80000000) + die(_("bad index version '%s'"), val); + return 0; +} + +static int option_parse_ulong(const struct option *opt, + const char *arg, int unset) +{ + if (unset) + die(_("option %s does not accept negative form"), + opt->long_name); + + if (!git_parse_ulong(arg, opt->value)) + die(_("unable to parse value '%s' for option %s"), + arg, opt->long_name); + return 0; +} + +#define OPT_ULONG(s, l, v, h) \ + { OPTION_CALLBACK, (s), (l), (v), "n", (h), \ + PARSE_OPT_NONEG, option_parse_ulong } + int cmd_pack_objects(int argc, const char **argv, const char *prefix) { int use_internal_rev_list = 0; int thin = 0; int all_progress_implied = 0; - uint32_t i; - const char **rp_av; - int rp_ac_alloc = 64; - int rp_ac; + const char *rp_av[6]; + int rp_ac = 0; + int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0; + struct option pack_objects_options[] = { + OPT_SET_INT('q', "quiet", &progress, + "do not show progress meter", 0), + OPT_SET_INT(0, "progress", &progress, + "show progress meter", 1), + OPT_SET_INT(0, "all-progress", &progress, + "show progress meter during object writing phase", 2), + OPT_BOOL(0, "all-progress-implied", + &all_progress_implied, + "similar to --all-progress when progress meter is shown"), + { OPTION_CALLBACK, 0, "index-version", NULL, "version[,offset]", + "write the pack index file in the specified idx format version", + 0, option_parse_index_version }, + OPT_ULONG(0, "max-pack-size", &pack_size_limit, + "maximum size of each output pack file"), + OPT_BOOL(0, "local", &local, + "ignore borrowed objects from alternate object store"), + OPT_BOOL(0, "incremental", &incremental, + "ignore packed objects"), + OPT_INTEGER(0, "window", &window, + "limit pack window by objects"), + OPT_ULONG(0, "window-memory", &window_memory_limit, + "limit pack window by memory in addition to object limit"), + OPT_INTEGER(0, "depth", &depth, + "maximum length of delta chain allowed in the resulting pack"), + OPT_BOOL(0, "reuse-delta", &reuse_delta, + "reuse existing deltas"), + OPT_BOOL(0, "reuse-object", &reuse_object, + "reuse existing objects"), + OPT_BOOL(0, "delta-base-offset", &allow_ofs_delta, + "use OFS_DELTA objects"), + OPT_INTEGER(0, "threads", &delta_search_threads, + "use threads when searching for best delta matches"), + OPT_BOOL(0, "non-empty", &non_empty, + "do not create an empty pack output"), + OPT_BOOL(0, "revs", &use_internal_rev_list, + "read revision arguments from standard input"), + { OPTION_SET_INT, 0, "unpacked", &rev_list_unpacked, NULL, + "limit the objects to those that are not yet packed", + PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 }, + { OPTION_SET_INT, 0, "all", &rev_list_all, NULL, + "include objects reachable from any reference", + PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 }, + { OPTION_SET_INT, 0, "reflog", &rev_list_reflog, NULL, + "include objects referred by reflog entries", + PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 }, + OPT_BOOL(0, "stdout", &pack_to_stdout, + "output pack to stdout"), + OPT_BOOL(0, "include-tag", &include_tag, + "include tag objects that refer to objects to be packed"), + OPT_BOOL(0, "keep-unreachable", &keep_unreachable, + "keep unreachable objects"), + OPT_BOOL(0, "unpack-unreachable", &unpack_unreachable, + "unpack unreachable objects"), + OPT_BOOL(0, "thin", &thin, + "create thin packs"), + OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep, + "ignore packs that have companion .keep file"), + OPT_INTEGER(0, "compression", &pack_compression_level, + "pack compression level"), + OPT_SET_INT(0, "keep-true-parents", &grafts_replace_parents, + "do not hide commits by grafts", 0), + OPT_END(), + }; read_replace_refs = 0; - rp_av = xcalloc(rp_ac_alloc, sizeof(*rp_av)); - - rp_av[0] = "pack-objects"; - rp_av[1] = "--objects"; /* --thin will make it --objects-edge */ - rp_ac = 2; - reset_pack_idx_option(&pack_idx_opts); git_config(git_pack_config, NULL); if (!pack_compression_seen && core_compression_seen) pack_compression_level = core_compression_level; progress = isatty(2); - for (i = 1; i < argc; i++) { - const char *arg = argv[i]; - - if (*arg != '-') - break; + argc = parse_options(argc, argv, prefix, pack_objects_options, + pack_usage, 0); - if (!strcmp("--non-empty", arg)) { - non_empty = 1; - continue; - } - if (!strcmp("--local", arg)) { - local = 1; - continue; - } - if (!strcmp("--incremental", arg)) { - incremental = 1; - continue; - } - if (!strcmp("--honor-pack-keep", arg)) { - ignore_packed_keep = 1; - continue; - } - if (!prefixcmp(arg, "--compression=")) { - char *end; - int level = strtoul(arg+14, &end, 0); - if (!arg[14] || *end) - usage(pack_usage); - if (level == -1) - level = Z_DEFAULT_COMPRESSION; - else if (level < 0 || level > Z_BEST_COMPRESSION) - die("bad pack compression level %d", level); - pack_compression_level = level; - continue; - } - if (!prefixcmp(arg, "--max-pack-size=")) { - pack_size_limit_cfg = 0; - if (!git_parse_ulong(arg+16, &pack_size_limit)) - usage(pack_usage); - continue; - } - if (!prefixcmp(arg, "--window=")) { - char *end; - window = strtoul(arg+9, &end, 0); - if (!arg[9] || *end) - usage(pack_usage); - continue; - } - if (!prefixcmp(arg, "--window-memory=")) { - if (!git_parse_ulong(arg+16, &window_memory_limit)) - usage(pack_usage); - continue; - } - if (!prefixcmp(arg, "--threads=")) { - char *end; - delta_search_threads = strtoul(arg+10, &end, 0); - if (!arg[10] || *end || delta_search_threads < 0) - usage(pack_usage); -#ifdef NO_PTHREADS - if (delta_search_threads != 1) - warning("no threads support, " - "ignoring %s", arg); -#endif - continue; - } - if (!prefixcmp(arg, "--depth=")) { - char *end; - depth = strtoul(arg+8, &end, 0); - if (!arg[8] || *end) - usage(pack_usage); - continue; - } - if (!strcmp("--progress", arg)) { - progress = 1; - continue; - } - if (!strcmp("--all-progress", arg)) { - progress = 2; - continue; - } - if (!strcmp("--all-progress-implied", arg)) { - all_progress_implied = 1; - continue; - } - if (!strcmp("-q", arg)) { - progress = 0; - continue; - } - if (!strcmp("--no-reuse-delta", arg)) { - reuse_delta = 0; - continue; - } - if (!strcmp("--no-reuse-object", arg)) { - reuse_object = reuse_delta = 0; - continue; - } - if (!strcmp("--delta-base-offset", arg)) { - allow_ofs_delta = 1; - continue; - } - if (!strcmp("--stdout", arg)) { - pack_to_stdout = 1; - continue; - } - if (!strcmp("--revs", arg)) { - use_internal_rev_list = 1; - continue; - } - if (!strcmp("--keep-unreachable", arg)) { - keep_unreachable = 1; - continue; - } - if (!strcmp("--unpack-unreachable", arg)) { - unpack_unreachable = 1; - continue; - } - if (!strcmp("--include-tag", arg)) { - include_tag = 1; - continue; - } - if (!strcmp("--unpacked", arg) || - !strcmp("--reflog", arg) || - !strcmp("--all", arg)) { - use_internal_rev_list = 1; - if (rp_ac >= rp_ac_alloc - 1) { - rp_ac_alloc = alloc_nr(rp_ac_alloc); - rp_av = xrealloc(rp_av, - rp_ac_alloc * sizeof(*rp_av)); - } - rp_av[rp_ac++] = arg; - continue; - } - if (!strcmp("--thin", arg)) { - use_internal_rev_list = 1; - thin = 1; - rp_av[1] = "--objects-edge"; - continue; - } - if (!prefixcmp(arg, "--index-version=")) { - char *c; - pack_idx_opts.version = strtoul(arg + 16, &c, 10); - if (pack_idx_opts.version > 2) - die("bad %s", arg); - if (*c == ',') - pack_idx_opts.off32_limit = strtoul(c+1, &c, 0); - if (*c || pack_idx_opts.off32_limit & 0x80000000) - die("bad %s", arg); - continue; - } - if (!strcmp(arg, "--keep-true-parents")) { - grafts_replace_parents = 0; - continue; - } - usage(pack_usage); - } - - /* Traditionally "pack-objects [options] base extra" failed; - * we would however want to take refs parameter that would - * have been given to upstream rev-list ourselves, which means - * we somehow want to say what the base name is. So the - * syntax would be: - * - * pack-objects [options] base <refs...> - * - * in other words, we would treat the first non-option as the - * base_name and send everything else to the internal revision - * walker. - */ + if (argc) { + base_name = argv[0]; + argc--; + } + if (pack_to_stdout != !base_name || argc) + usage_with_options(pack_usage, pack_objects_options); - if (!pack_to_stdout) - base_name = argv[i++]; + rp_av[rp_ac++] = "pack-objects"; + if (thin) { + use_internal_rev_list = 1; + rp_av[rp_ac++] = "--objects-edge"; + } else + rp_av[rp_ac++] = "--objects"; - if (pack_to_stdout != !base_name) - usage(pack_usage); + if (rev_list_all) { + use_internal_rev_list = 1; + rp_av[rp_ac++] = "--all"; + } + if (rev_list_reflog) { + use_internal_rev_list = 1; + rp_av[rp_ac++] = "--reflog"; + } + if (rev_list_unpacked) { + use_internal_rev_list = 1; + rp_av[rp_ac++] = "--unpacked"; + } + if (!reuse_object) + reuse_delta = 0; + if (pack_compression_level == -1) + pack_compression_level = Z_DEFAULT_COMPRESSION; + else if (pack_compression_level < 0 || pack_compression_level > Z_BEST_COMPRESSION) + die("bad pack compression level %d", pack_compression_level); +#ifdef NO_PTHREADS + if (delta_search_threads != 1) + warning("no threads support, ignoring --threads"); +#endif if (!pack_to_stdout && !pack_size_limit) pack_size_limit = pack_size_limit_cfg; if (pack_to_stdout && pack_size_limit) diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c index f9463deec2..b58a2e1eb2 100644 --- a/builtin/prune-packed.c +++ b/builtin/prune-packed.c @@ -35,8 +35,6 @@ static void prune_dir(int i, DIR *dir, char *pathname, int len, int opts) unlink_or_warn(pathname); display_progress(progress, i + 1); } - pathname[len] = 0; - rmdir(pathname); } void prune_packed_objects(int opts) @@ -65,6 +63,8 @@ void prune_packed_objects(int opts) continue; prune_dir(i, d, pathname, len + 3, opts); closedir(d); + pathname[len + 2] = '\0'; + rmdir(pathname); } stop_progress(&progress); } diff --git a/builtin/prune.c b/builtin/prune.c index 58d7cb8324..b99b635e44 100644 --- a/builtin/prune.c +++ b/builtin/prune.c @@ -85,9 +85,9 @@ static int prune_dir(int i, char *path) } fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name); } + closedir(dir); if (!show_only) rmdir(path); - closedir(dir); return 0; } diff --git a/builtin/push.c b/builtin/push.c index 35cce532f2..d315475f16 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -19,7 +19,7 @@ static int thin; static int deleterefs; static const char *receivepack; static int verbosity; -static int progress; +static int progress = -1; static const char **refspec; static int refspec_nr; @@ -260,7 +260,9 @@ int cmd_push(int argc, const char **argv, const char *prefix) OPT_STRING( 0 , "exec", &receivepack, "receive-pack", "receive pack program"), OPT_BIT('u', "set-upstream", &flags, "set upstream for git pull/status", TRANSPORT_PUSH_SET_UPSTREAM), - OPT_BOOLEAN(0, "progress", &progress, "force progress reporting"), + OPT_BOOL(0, "progress", &progress, "force progress reporting"), + OPT_BIT(0, "prune", &flags, "prune locally removed refs", + TRANSPORT_PUSH_PRUNE), OPT_END() }; diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index fa7448be5a..0afb8b2896 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -642,8 +642,10 @@ static void check_aliased_updates(struct command *commands) } sort_string_list(&ref_list); - for (cmd = commands; cmd; cmd = cmd->next) - check_aliased_update(cmd, &ref_list); + for (cmd = commands; cmd; cmd = cmd->next) { + if (!cmd->error_string) + check_aliased_update(cmd, &ref_list); + } string_list_clear(&ref_list, 0); } @@ -707,8 +709,10 @@ static void execute_commands(struct command *commands, const char *unpacker_erro set_connectivity_errors(commands); if (run_receive_hook(commands, pre_receive_hook, 0)) { - for (cmd = commands; cmd; cmd = cmd->next) - cmd->error_string = "pre-receive hook declined"; + for (cmd = commands; cmd; cmd = cmd->next) { + if (!cmd->error_string) + cmd->error_string = "pre-receive hook declined"; + } return; } @@ -717,9 +721,15 @@ static void execute_commands(struct command *commands, const char *unpacker_erro free(head_name_to_free); head_name = head_name_to_free = resolve_refdup("HEAD", sha1, 0, NULL); - for (cmd = commands; cmd; cmd = cmd->next) - if (!cmd->skip_update) - cmd->error_string = update(cmd); + for (cmd = commands; cmd; cmd = cmd->next) { + if (cmd->error_string) + continue; + + if (cmd->skip_update) + continue; + + cmd->error_string = update(cmd); + } } static struct command *read_head_info(void) diff --git a/builtin/remote.c b/builtin/remote.c index f54a89adc7..fec92bc66e 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -16,7 +16,7 @@ static const char * const builtin_remote_usage[] = { "git remote [-v | --verbose] show [-n] <name>", "git remote prune [-n | --dry-run] <name>", "git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]", - "git remote set-branches <name> [--add] <branch>...", + "git remote set-branches [--add] <name> <branch>...", "git remote set-url <name> <newurl> [<oldurl>]", "git remote set-url --add <name> <newurl>", "git remote set-url --delete <name> <url>", diff --git a/builtin/rev-list.c b/builtin/rev-list.c index ab3be7ca82..4c4d404afc 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -52,6 +52,11 @@ static void show_commit(struct commit *commit, void *data) struct rev_list_info *info = data; struct rev_info *revs = info->revs; + if (info->flags & REV_LIST_QUIET) { + finish_commit(commit, data); + return; + } + graph_show_commit(revs->graph); if (revs->count) { @@ -172,19 +177,21 @@ static void finish_object(struct object *obj, const struct name_path *path, const char *name, void *cb_data) { + struct rev_list_info *info = cb_data; if (obj->type == OBJ_BLOB && !has_sha1_file(obj->sha1)) die("missing blob object '%s'", sha1_to_hex(obj->sha1)); + if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT) + parse_object(obj->sha1); } static void show_object(struct object *obj, const struct name_path *path, const char *component, void *cb_data) { - struct rev_info *info = cb_data; - + struct rev_list_info *info = cb_data; finish_object(obj, path, component, cb_data); - if (info->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT) - parse_object(obj->sha1); + if (info->flags & REV_LIST_QUIET) + return; show_object_with_name(stdout, obj, path, component); } @@ -242,13 +249,6 @@ void print_commit_list(struct commit_list *list, } } -static void show_tried_revs(struct commit_list *tried) -{ - printf("bisect_tried='"); - print_commit_list(tried, "%s|", "%s"); - printf("'\n"); -} - static void print_var_str(const char *var, const char *val) { printf("%s='%s'\n", var, val); @@ -261,12 +261,12 @@ static void print_var_int(const char *var, int val) static int show_bisect_vars(struct rev_list_info *info, int reaches, int all) { - int cnt, flags = info->bisect_show_flags; + int cnt, flags = info->flags; char hex[41] = ""; struct commit_list *tried; struct rev_info *revs = info->revs; - if (!revs->commits && !(flags & BISECT_SHOW_TRIED)) + if (!revs->commits) return 1; revs->commits = filter_skipped(revs->commits, &tried, @@ -294,9 +294,6 @@ static int show_bisect_vars(struct rev_list_info *info, int reaches, int all) printf("------\n"); } - if (flags & BISECT_SHOW_TRIED) - show_tried_revs(tried); - print_var_str("bisect_rev", hex); print_var_int("bisect_nr", cnt - 1); print_var_int("bisect_good", all - reaches - 1); @@ -315,7 +312,6 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) int bisect_list = 0; int bisect_show_vars = 0; int bisect_find_all = 0; - int quiet = 0; git_config(git_default_config, NULL); init_revisions(&revs, prefix); @@ -328,7 +324,8 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) if (revs.bisect) bisect_list = 1; - quiet = DIFF_OPT_TST(&revs.diffopt, QUICK); + if (DIFF_OPT_TST(&revs.diffopt, QUICK)) + info.flags |= REV_LIST_QUIET; for (i = 1 ; i < argc; i++) { const char *arg = argv[i]; @@ -347,7 +344,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) if (!strcmp(arg, "--bisect-all")) { bisect_list = 1; bisect_find_all = 1; - info.bisect_show_flags = BISECT_SHOW_ALL; + info.flags |= BISECT_SHOW_ALL; revs.show_decorations = 1; continue; } @@ -398,10 +395,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) return show_bisect_vars(&info, reaches, all); } - traverse_commit_list(&revs, - quiet ? finish_commit : show_commit, - quiet ? finish_object : show_object, - &info); + traverse_commit_list(&revs, show_commit, show_object, &info); if (revs.count) { if (revs.left_right && revs.cherry_mark) diff --git a/builtin/send-pack.c b/builtin/send-pack.c index 71f258ef6e..9df341c793 100644 --- a/builtin/send-pack.c +++ b/builtin/send-pack.c @@ -58,7 +58,7 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext argv[i++] = "--thin"; if (args->use_ofs_delta) argv[i++] = "--delta-base-offset"; - if (args->quiet) + if (args->quiet || !args->progress) argv[i++] = "-q"; if (args->progress) argv[i++] = "--progress"; @@ -250,6 +250,7 @@ int send_pack(struct send_pack_args *args, int allow_deleting_refs = 0; int status_report = 0; int use_sideband = 0; + int quiet_supported = 0; unsigned cmds_sent = 0; int ret; struct async demux; @@ -263,8 +264,8 @@ int send_pack(struct send_pack_args *args, args->use_ofs_delta = 1; if (server_supports("side-band-64k")) use_sideband = 1; - if (!server_supports("quiet")) - args->quiet = 0; + if (server_supports("quiet")) + quiet_supported = 1; if (!remote_refs) { fprintf(stderr, "No refs in common and none specified; doing nothing.\n" @@ -302,17 +303,18 @@ int send_pack(struct send_pack_args *args, } else { char *old_hex = sha1_to_hex(ref->old_sha1); char *new_hex = sha1_to_hex(ref->new_sha1); + int quiet = quiet_supported && (args->quiet || !args->progress); if (!cmds_sent && (status_report || use_sideband || args->quiet)) { packet_buf_write(&req_buf, "%s %s %s%c%s%s%s", - old_hex, new_hex, ref->name, 0, - status_report ? " report-status" : "", - use_sideband ? " side-band-64k" : "", - args->quiet ? " quiet" : ""); + old_hex, new_hex, ref->name, 0, + status_report ? " report-status" : "", + use_sideband ? " side-band-64k" : "", + quiet ? " quiet" : ""); } else packet_buf_write(&req_buf, "%s %s %s", - old_hex, new_hex, ref->name); + old_hex, new_hex, ref->name); ref->status = status_report ? REF_STATUS_EXPECTING_REPORT : REF_STATUS_OK; diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c index 2ef5962386..801d62ece5 100644 --- a/builtin/symbolic-ref.c +++ b/builtin/symbolic-ref.c @@ -8,13 +8,15 @@ static const char * const git_symbolic_ref_usage[] = { NULL }; +static int shorten; + static void check_symref(const char *HEAD, int quiet) { unsigned char sha1[20]; int flag; - const char *refs_heads_master = resolve_ref_unsafe(HEAD, sha1, 0, &flag); + const char *refname = resolve_ref_unsafe(HEAD, sha1, 0, &flag); - if (!refs_heads_master) + if (!refname) die("No such ref: %s", HEAD); else if (!(flag & REF_ISSYMREF)) { if (!quiet) @@ -22,7 +24,9 @@ static void check_symref(const char *HEAD, int quiet) else exit(1); } - puts(refs_heads_master); + if (shorten) + refname = shorten_unambiguous_ref(refname, 0); + puts(refname); } int cmd_symbolic_ref(int argc, const char **argv, const char *prefix) @@ -32,6 +36,7 @@ int cmd_symbolic_ref(int argc, const char **argv, const char *prefix) struct option options[] = { OPT__QUIET(&quiet, "suppress error message for non-symbolic (detached) refs"), + OPT_BOOL(0, "short", &shorten, "shorten ref output"), OPT_STRING('m', NULL, &msg, "reason", "reason of the update"), OPT_END(), }; diff --git a/builtin/tag.c b/builtin/tag.c index 03df16ac6e..fe7e5e5b3d 100644 --- a/builtin/tag.c +++ b/builtin/tag.c @@ -15,11 +15,13 @@ #include "diff.h" #include "revision.h" #include "gpg-interface.h" +#include "sha1-array.h" static const char * const git_tag_usage[] = { "git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]", "git tag -d <tagname>...", - "git tag -l [-n[<num>]] [<pattern>...]", + "git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] " + "\n\t\t[<pattern>...]", "git tag -v <tagname>...", NULL }; @@ -30,6 +32,8 @@ struct tag_filter { struct commit_list *with_commit; }; +static struct sha1_array points_at; + static int match_pattern(const char **patterns, const char *ref) { /* no pattern means match everything */ @@ -41,6 +45,24 @@ static int match_pattern(const char **patterns, const char *ref) return 0; } +static const unsigned char *match_points_at(const char *refname, + const unsigned char *sha1) +{ + const unsigned char *tagged_sha1 = NULL; + struct object *obj; + + if (sha1_array_lookup(&points_at, sha1) >= 0) + return sha1; + obj = parse_object(sha1); + if (!obj) + die(_("malformed object at '%s'"), refname); + if (obj->type == OBJ_TAG) + tagged_sha1 = ((struct tag *)obj)->tagged->sha1; + if (tagged_sha1 && sha1_array_lookup(&points_at, tagged_sha1) >= 0) + return tagged_sha1; + return NULL; +} + static int in_commit_list(const struct commit_list *want, struct commit *c) { for (; want; want = want->next) @@ -138,6 +160,9 @@ static int show_reference(const char *refname, const unsigned char *sha1, return 0; } + if (points_at.nr && !match_points_at(refname, sha1)) + return 0; + if (!filter->lines) { printf("%s\n", refname); return 0; @@ -383,6 +408,23 @@ static int strbuf_check_tag_ref(struct strbuf *sb, const char *name) return check_refname_format(sb->buf, 0); } +static int parse_opt_points_at(const struct option *opt __attribute__((unused)), + const char *arg, int unset) +{ + unsigned char sha1[20]; + + if (unset) { + sha1_array_clear(&points_at); + return 0; + } + if (!arg) + return error(_("switch 'points-at' requires an object")); + if (get_sha1(arg, sha1)) + return error(_("malformed object name '%s'"), arg); + sha1_array_append(&points_at, sha1); + return 0; +} + int cmd_tag(int argc, const char **argv, const char *prefix) { struct strbuf buf = STRBUF_INIT; @@ -425,6 +467,10 @@ int cmd_tag(int argc, const char **argv, const char *prefix) PARSE_OPT_LASTARG_DEFAULT, parse_opt_with_commit, (intptr_t)"HEAD", }, + { + OPTION_CALLBACK, 0, "points-at", NULL, "object", + "print only tags of the object", 0, parse_opt_points_at + }, OPT_END() }; @@ -456,6 +502,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix) die(_("-n option is only allowed with -l.")); if (with_commit) die(_("--contains option is only allowed with -l.")); + if (points_at.nr) + die(_("--points-at option is only allowed with -l.")); if (delete) return for_each_tag_name(argv, delete_tag); if (verify) diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c index 28c2174338..986789f706 100644 --- a/builtin/verify-tag.c +++ b/builtin/verify-tag.c @@ -58,6 +58,14 @@ static int verify_tag(const char *name, int verbose) return ret; } +static int git_verify_tag_config(const char *var, const char *value, void *cb) +{ + int status = git_gpg_config(var, value, cb); + if (status) + return status; + return git_default_config(var, value, cb); +} + int cmd_verify_tag(int argc, const char **argv, const char *prefix) { int i = 1, verbose = 0, had_error = 0; @@ -66,7 +74,7 @@ int cmd_verify_tag(int argc, const char **argv, const char *prefix) OPT_END() }; - git_config(git_default_config, NULL); + git_config(git_verify_tag_config, NULL); argc = parse_options(argc, argv, prefix, verify_tag_options, verify_tag_usage, PARSE_OPT_KEEP_ARGV0); @@ -23,23 +23,6 @@ static void add_to_ref_list(const unsigned char *sha1, const char *name, list->nr++; } -/* Eventually this should go to strbuf.[ch] */ -static int strbuf_readline_fd(struct strbuf *sb, int fd) -{ - strbuf_reset(sb); - - while (1) { - char ch; - ssize_t len = xread(fd, &ch, 1); - if (len <= 0) - return len; - strbuf_addch(sb, ch); - if (ch == '\n') - break; - } - return 0; -} - static int parse_bundle_header(int fd, struct bundle_header *header, const char *report_path) { @@ -47,7 +30,7 @@ static int parse_bundle_header(int fd, struct bundle_header *header, int status = 0; /* The bundle header begins with the signature */ - if (strbuf_readline_fd(&buf, fd) || + if (strbuf_getwholeline_fd(&buf, fd, '\n') || strcmp(buf.buf, bundle_signature)) { if (report_path) error("'%s' does not look like a v2 bundle file", @@ -57,7 +40,7 @@ static int parse_bundle_header(int fd, struct bundle_header *header, } /* The bundle header ends with an empty line */ - while (!strbuf_readline_fd(&buf, fd) && + while (!strbuf_getwholeline_fd(&buf, fd, '\n') && buf.len && buf.buf[0] != '\n') { unsigned char sha1[20]; int is_prereq = 0; @@ -251,7 +234,7 @@ int create_bundle(struct bundle_header *header, const char *path, const char **argv_boundary = xmalloc((argc + 4) * sizeof(const char *)); const char **argv_pack = xmalloc(6 * sizeof(const char *)); int i, ref_count = 0; - char buffer[1024]; + struct strbuf buf = STRBUF_INIT; struct rev_info revs; struct child_process rls; FILE *rls_fout; @@ -283,20 +266,21 @@ int create_bundle(struct bundle_header *header, const char *path, if (start_command(&rls)) return -1; rls_fout = xfdopen(rls.out, "r"); - while (fgets(buffer, sizeof(buffer), rls_fout)) { + while (strbuf_getwholeline(&buf, rls_fout, '\n') != EOF) { unsigned char sha1[20]; - if (buffer[0] == '-') { - write_or_die(bundle_fd, buffer, strlen(buffer)); - if (!get_sha1_hex(buffer + 1, sha1)) { + if (buf.len > 0 && buf.buf[0] == '-') { + write_or_die(bundle_fd, buf.buf, buf.len); + if (!get_sha1_hex(buf.buf + 1, sha1)) { struct object *object = parse_object(sha1); object->flags |= UNINTERESTING; - add_pending_object(&revs, object, buffer); + add_pending_object(&revs, object, xstrdup(buf.buf)); } - } else if (!get_sha1_hex(buffer, sha1)) { + } else if (!get_sha1_hex(buf.buf, sha1)) { struct object *object = parse_object(sha1); object->flags |= SHOWN; } } + strbuf_release(&buf); fclose(rls_fout); if (finish_command(&rls)) return error("rev-list died"); diff --git a/cache-tree.c b/cache-tree.c index bf03cb7fce..28ed6574a2 100644 --- a/cache-tree.c +++ b/cache-tree.c @@ -150,9 +150,10 @@ void cache_tree_invalidate_path(struct cache_tree *it, const char *path) } static int verify_cache(struct cache_entry **cache, - int entries, int silent) + int entries, int flags) { int i, funny; + int silent = flags & WRITE_TREE_SILENT; /* Verify that the tree is merged */ funny = 0; @@ -241,10 +242,11 @@ static int update_one(struct cache_tree *it, int entries, const char *base, int baselen, - int missing_ok, - int dryrun) + int flags) { struct strbuf buffer; + int missing_ok = flags & WRITE_TREE_MISSING_OK; + int dryrun = flags & WRITE_TREE_DRY_RUN; int i; if (0 <= it->entry_count && has_sha1_file(it->sha1)) @@ -288,8 +290,7 @@ static int update_one(struct cache_tree *it, cache + i, entries - i, path, baselen + sublen + 1, - missing_ok, - dryrun); + flags); if (subcnt < 0) return subcnt; i += subcnt - 1; @@ -371,15 +372,13 @@ static int update_one(struct cache_tree *it, int cache_tree_update(struct cache_tree *it, struct cache_entry **cache, int entries, - int missing_ok, - int dryrun, - int silent) + int flags) { int i; - i = verify_cache(cache, entries, silent); + i = verify_cache(cache, entries, flags); if (i) return i; - i = update_one(it, cache, entries, "", 0, missing_ok, dryrun); + i = update_one(it, cache, entries, "", 0, flags); if (i < 0) return i; return 0; @@ -572,11 +571,9 @@ int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix) was_valid = cache_tree_fully_valid(active_cache_tree); if (!was_valid) { - int missing_ok = flags & WRITE_TREE_MISSING_OK; - if (cache_tree_update(active_cache_tree, active_cache, active_nr, - missing_ok, 0, 0) < 0) + flags) < 0) return WRITE_TREE_UNMERGED_INDEX; if (0 <= newfd) { if (!write_cache(newfd, active_cache, active_nr) && @@ -672,10 +669,10 @@ int cache_tree_matches_traversal(struct cache_tree *root, return 0; } -int update_main_cache_tree (int silent) +int update_main_cache_tree(int flags) { if (!the_index.cache_tree) the_index.cache_tree = cache_tree(); return cache_tree_update(the_index.cache_tree, - the_index.cache, the_index.cache_nr, 0, 0, silent); + the_index.cache, the_index.cache_nr, flags); } diff --git a/cache-tree.h b/cache-tree.h index 0ec0b2a159..d8cb2e9e39 100644 --- a/cache-tree.h +++ b/cache-tree.h @@ -29,13 +29,15 @@ void cache_tree_write(struct strbuf *, struct cache_tree *root); struct cache_tree *cache_tree_read(const char *buffer, unsigned long size); int cache_tree_fully_valid(struct cache_tree *); -int cache_tree_update(struct cache_tree *, struct cache_entry **, int, int, int, int); +int cache_tree_update(struct cache_tree *, struct cache_entry **, int, int); int update_main_cache_tree(int); /* bitmasks to write_cache_as_tree flags */ #define WRITE_TREE_MISSING_OK 1 #define WRITE_TREE_IGNORE_CACHE_TREE 2 +#define WRITE_TREE_DRY_RUN 4 +#define WRITE_TREE_SILENT 8 /* error return codes */ #define WRITE_TREE_UNREADABLE_INDEX (-1) @@ -432,6 +432,7 @@ extern char *git_work_tree_cfg; extern int is_inside_work_tree(void); extern int have_git_dir(void); extern const char *get_git_dir(void); +extern int is_git_directory(const char *path); extern char *get_object_directory(void); extern char *get_index_file(void); extern char *get_graft_file(void); @@ -949,7 +950,9 @@ struct cache_def { extern int has_symlink_leading_path(const char *name, int len); extern int threaded_has_symlink_leading_path(struct cache_def *, const char *, int); extern int check_leading_path(const char *name, int len); +extern int threaded_check_leading_path(struct cache_def *cache, const char *name, int len); extern int has_dirs_only_path(const char *name, int len, int prefix_len); +extern int threaded_has_dirs_only_path(struct cache_def *cache, const char *name, int len, int prefix_len); extern void schedule_dir_for_removal(const char *name, int len); extern void remove_scheduled_dirs(void); @@ -1114,6 +1117,8 @@ extern int git_config_from_file(config_fn_t fn, const char *, void *); extern void git_config_push_parameter(const char *text); extern int git_config_from_parameters(config_fn_t fn, void *data); extern int git_config(config_fn_t fn, void *); +extern int git_config_with_options(config_fn_t fn, void *, + const char *filename, int respect_includes); extern int git_config_early(config_fn_t fn, void *, const char *repo_config); extern int git_parse_ulong(const char *, unsigned long *); extern int git_config_int(const char *, const char *); @@ -1129,6 +1134,7 @@ extern int git_config_parse_key(const char *, char **, int *); extern int git_config_set_multivar(const char *, const char *, const char *, int); extern int git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int); extern int git_config_rename_section(const char *, const char *); +extern int git_config_rename_section_in_file(const char *, const char *, const char *); extern const char *git_etc_gitconfig(void); extern int check_repository_format_version(const char *var, const char *value, void *cb); extern int git_env_bool(const char *, int); @@ -1139,7 +1145,13 @@ extern const char *get_commit_output_encoding(void); extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data); -extern const char *config_exclusive_filename; +struct config_include_data { + int depth; + config_fn_t fn; + void *data; +}; +#define CONFIG_INCLUDE_INIT { 0 } +extern int git_config_include(const char *name, const char *value, void *data); #define MAX_GITNAME (1000) extern char git_default_email[MAX_GITNAME]; @@ -1176,6 +1188,8 @@ extern void setup_pager(void); extern const char *pager_program; extern int pager_in_use(void); extern int pager_use_color; +extern int term_columns(void); +extern int decimal_width(int); extern const char *editor_program; extern const char *askpass_program; @@ -26,7 +26,68 @@ static config_file *cf; static int zlib_compression_seen; -const char *config_exclusive_filename = NULL; +#define MAX_INCLUDE_DEPTH 10 +static const char include_depth_advice[] = +"exceeded maximum include depth (%d) while including\n" +" %s\n" +"from\n" +" %s\n" +"Do you have circular includes?"; +static int handle_path_include(const char *path, struct config_include_data *inc) +{ + int ret = 0; + struct strbuf buf = STRBUF_INIT; + + /* + * Use an absolute path as-is, but interpret relative paths + * based on the including config file. + */ + if (!is_absolute_path(path)) { + char *slash; + + if (!cf || !cf->name) + return error("relative config includes must come from files"); + + slash = find_last_dir_sep(cf->name); + if (slash) + strbuf_add(&buf, cf->name, slash - cf->name + 1); + strbuf_addstr(&buf, path); + path = buf.buf; + } + + if (!access(path, R_OK)) { + if (++inc->depth > MAX_INCLUDE_DEPTH) + die(include_depth_advice, MAX_INCLUDE_DEPTH, path, + cf && cf->name ? cf->name : "the command line"); + ret = git_config_from_file(git_config_include, path, inc); + inc->depth--; + } + strbuf_release(&buf); + return ret; +} + +int git_config_include(const char *var, const char *value, void *data) +{ + struct config_include_data *inc = data; + const char *type; + int ret; + + /* + * Pass along all values, including "include" directives; this makes it + * possible to query information on the includes themselves. + */ + ret = inc->fn(var, value, inc->data); + if (ret < 0) + return ret; + + type = skip_prefix(var, "include."); + if (!type) + return ret; + + if (!strcmp(type, "path")) + ret = handle_path_include(value, inc); + return ret; +} static void lowercase(char *p) { @@ -135,8 +196,10 @@ static char *parse_value(void) for (;;) { int c = get_next_char(); if (c == '\n') { - if (quote) + if (quote) { + cf->linenr--; return NULL; + } return cf->value.buf; } if (comment) @@ -226,7 +289,7 @@ static int get_extended_base_var(char *name, int baselen, int c) { do { if (c == '\n') - return -1; + goto error_incomplete_line; c = get_next_char(); } while (isspace(c)); @@ -238,13 +301,13 @@ static int get_extended_base_var(char *name, int baselen, int c) for (;;) { int c = get_next_char(); if (c == '\n') - return -1; + goto error_incomplete_line; if (c == '"') break; if (c == '\\') { c = get_next_char(); if (c == '\n') - return -1; + goto error_incomplete_line; } name[baselen++] = c; if (baselen > MAXNAME / 2) @@ -255,6 +318,9 @@ static int get_extended_base_var(char *name, int baselen, int c) if (get_next_char() != ']') return -1; return baselen; +error_incomplete_line: + cf->linenr--; + return -1; } static int get_base_var(char *name) @@ -879,9 +945,6 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) int ret = 0, found = 0; const char *home = NULL; - /* Setting $GIT_CONFIG makes git read _only_ the given config file. */ - if (config_exclusive_filename) - return git_config_from_file(fn, config_exclusive_filename, data); if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) { ret += git_config_from_file(fn, git_etc_gitconfig(), data); @@ -917,10 +980,26 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) return ret == 0 ? found : ret; } -int git_config(config_fn_t fn, void *data) +int git_config_with_options(config_fn_t fn, void *data, + const char *filename, int respect_includes) { char *repo_config = NULL; int ret; + struct config_include_data inc = CONFIG_INCLUDE_INIT; + + if (respect_includes) { + inc.fn = fn; + inc.data = data; + fn = git_config_include; + data = &inc; + } + + /* + * If we have a specific filename, use it. Otherwise, follow the + * regular lookup sequence. + */ + if (filename) + return git_config_from_file(fn, filename, data); repo_config = git_pathdup("config"); ret = git_config_early(fn, data, repo_config); @@ -929,6 +1008,11 @@ int git_config(config_fn_t fn, void *data) return ret; } +int git_config(config_fn_t fn, void *data) +{ + return git_config_with_options(fn, data, NULL, 1); +} + /* * Find all the stuff for git_config_set() below. */ @@ -1233,6 +1317,7 @@ int git_config_set_multivar_in_file(const char *config_filename, int fd = -1, in_fd; int ret; struct lock_file *lock = NULL; + char *filename_buf = NULL; /* parse-key returns negative; flip the sign to feed exit(3) */ ret = 0 - git_config_parse_key(key, &store.key, &store.baselen); @@ -1241,6 +1326,8 @@ int git_config_set_multivar_in_file(const char *config_filename, store.multi_replace = multi_replace; + if (!config_filename) + config_filename = filename_buf = git_pathdup("config"); /* * The lock serves a purpose in addition to locking: the new @@ -1410,6 +1497,7 @@ int git_config_set_multivar_in_file(const char *config_filename, out_free: if (lock) rollback_lock_file(lock); + free(filename_buf); return ret; write_err_out: @@ -1421,19 +1509,8 @@ write_err_out: int git_config_set_multivar(const char *key, const char *value, const char *value_regex, int multi_replace) { - const char *config_filename; - char *buf = NULL; - int ret; - - if (config_exclusive_filename) - config_filename = config_exclusive_filename; - else - config_filename = buf = git_pathdup("config"); - - ret = git_config_set_multivar_in_file(config_filename, key, value, - value_regex, multi_replace); - free(buf); - return ret; + return git_config_set_multivar_in_file(NULL, key, value, value_regex, + multi_replace); } static int section_name_match (const char *buf, const char *name) @@ -1476,19 +1553,19 @@ static int section_name_match (const char *buf, const char *name) } /* if new_name == NULL, the section is removed instead */ -int git_config_rename_section(const char *old_name, const char *new_name) +int git_config_rename_section_in_file(const char *config_filename, + const char *old_name, const char *new_name) { int ret = 0, remove = 0; - char *config_filename; + char *filename_buf = NULL; struct lock_file *lock = xcalloc(sizeof(struct lock_file), 1); int out_fd; char buf[1024]; FILE *config_file; - if (config_exclusive_filename) - config_filename = xstrdup(config_exclusive_filename); - else - config_filename = git_pathdup("config"); + if (!config_filename) + config_filename = filename_buf = git_pathdup("config"); + out_fd = hold_lock_file_for_update(lock, config_filename, 0); if (out_fd < 0) { ret = error("could not lock config file %s", config_filename); @@ -1552,10 +1629,15 @@ unlock_and_out: if (commit_lock_file(lock) < 0) ret = error("could not commit config file %s", config_filename); out: - free(config_filename); + free(filename_buf); return ret; } +int git_config_rename_section(const char *old_name, const char *new_name) +{ + return git_config_rename_section_in_file(NULL, old_name, new_name); +} + /* * Call this to report error for your variable that should not * get a boolean value (i.e. "[my] var" means "true"). diff --git a/config.mak.in b/config.mak.in index 10698c8292..b2ba7104eb 100644 --- a/config.mak.in +++ b/config.mak.in @@ -74,3 +74,4 @@ SNPRINTF_RETURNS_BOGUS=@SNPRINTF_RETURNS_BOGUS@ NO_PTHREADS=@NO_PTHREADS@ PTHREAD_CFLAGS=@PTHREAD_CFLAGS@ PTHREAD_LIBS=@PTHREAD_LIBS@ +CHARSET_LIB=@CHARSET_LIB@ diff --git a/configure.ac b/configure.ac index 630dbdd19d..72f7958824 100644 --- a/configure.ac +++ b/configure.ac @@ -137,6 +137,23 @@ if test -n "$1"; then fi ]) +# Directories holding "saner" versions of common or POSIX binaries. +AC_ARG_WITH([sane-tool-path], + [AS_HELP_STRING( + [--with-sane-tool-path=DIR-1[[:DIR-2...:DIR-n]]], + [Directories to prepend to PATH in build system and generated scripts])], + [if test "$withval" = "no"; then + withval='' + else + AC_MSG_NOTICE([Setting SANE_TOOL_PATH to '$withval']) + fi + GIT_CONF_APPEND_LINE([SANE_TOOL_PATH=$withval])], + [# If the "--with-sane-tool-path" option was not given, don't touch + # SANE_TOOL_PATH here, but let defaults in Makefile take care of it. + # This should minimize spurious differences in the behaviour of the + # Git build system when configure is used w.r.t. when it is not. + :]) + ## Site configuration related to programs (before tests) ## --with-PACKAGE[=ARG] and --without-PACKAGE # @@ -640,7 +657,18 @@ AC_CHECK_LIB([c], [gettext], [LIBC_CONTAINS_LIBINTL=YesPlease], [LIBC_CONTAINS_LIBINTL=]) AC_SUBST(LIBC_CONTAINS_LIBINTL) -test -n "$LIBC_CONTAINS_LIBINTL" || LIBS="$LIBS -lintl" + +# +# Define NO_GETTEXT if you don't want Git output to be translated. +# A translated Git requires GNU libintl or another gettext implementation +AC_CHECK_HEADER([libintl.h], +[NO_GETTEXT=], +[NO_GETTEXT=YesPlease]) +AC_SUBST(NO_GETTEXT) + +if test -z "$NO_GETTEXT"; then + test -n "$LIBC_CONTAINS_LIBINTL" || LIBS="$LIBS -lintl" +fi ## Checks for header files. AC_MSG_NOTICE([CHECKS for header files]) @@ -824,18 +852,21 @@ AC_CHECK_HEADER([paths.h], [HAVE_PATHS_H=]) AC_SUBST(HAVE_PATHS_H) # -# Define NO_GETTEXT if you don't want Git output to be translated. -# A translated Git requires GNU libintl or another gettext implementation -AC_CHECK_HEADER([libintl.h], -[NO_GETTEXT=], -[NO_GETTEXT=YesPlease]) -AC_SUBST(NO_GETTEXT) -# # Define HAVE_LIBCHARSET_H if have libcharset.h AC_CHECK_HEADER([libcharset.h], [HAVE_LIBCHARSET_H=YesPlease], [HAVE_LIBCHARSET_H=]) AC_SUBST(HAVE_LIBCHARSET_H) +# Define CHARSET_LIB if libiconv does not export the locale_charset symbol +# and libcharset does +CHARSET_LIB= +AC_CHECK_LIB([iconv], [locale_charset], + [], + [AC_CHECK_LIB([charset], [locale_charset], + [CHARSET_LIB=-lcharset]) + ] +) +AC_SUBST(CHARSET_LIB) # # Define NO_STRCASESTR if you don't have strcasestr. GIT_CHECK_FUNC(strcasestr, diff --git a/connected.c b/connected.c index d7624230d4..1e89c1cd1d 100644 --- a/connected.c +++ b/connected.c @@ -6,18 +6,18 @@ /* * If we feed all the commits we want to verify to this command * - * $ git rev-list --verify-objects --stdin --not --all + * $ git rev-list --objects --stdin --not --all * * and if it does not error out, that means everything reachable from - * these commits locally exists and is connected to some of our - * existing refs. + * these commits locally exists and is connected to our existing refs. + * Note that this does _not_ validate the individual objects. * * Returns 0 if everything is connected, non-zero otherwise. */ int check_everything_connected(sha1_iterate_fn fn, int quiet, void *cb_data) { struct child_process rev_list; - const char *argv[] = {"rev-list", "--verify-objects", + const char *argv[] = {"rev-list", "--objects", "--stdin", "--not", "--all", NULL, NULL}; char commit[41]; unsigned char sha1[20]; diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 99fea1db28..31f714da92 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -60,18 +60,6 @@ # per-repository basis by setting the bash.showUpstream config # variable. # -# -# To submit patches: -# -# *) Read Documentation/SubmittingPatches -# *) Send all patches to the current maintainer: -# -# "Shawn O. Pearce" <spearce@spearce.org> -# -# *) Always CC the Git mailing list: -# -# git@vger.kernel.org -# if [[ -n ${ZSH_VERSION-} ]]; then autoload -U +X bashcompinit && bashcompinit @@ -150,7 +138,7 @@ __git_ps1_show_upstream () svn_upstream=${svn_upstream[ ${#svn_upstream[@]} - 2 ]} svn_upstream=${svn_upstream%@*} local n_stop="${#svn_remote[@]}" - for ((n=1; n <= n_stop; ++n)); do + for ((n=1; n <= n_stop; n++)); do svn_upstream=${svn_upstream#${svn_remote[$n]}} done @@ -179,10 +167,8 @@ __git_ps1_show_upstream () for commit in $commits do case "$commit" in - "<"*) let ++behind - ;; - *) let ++ahead - ;; + "<"*) ((behind++)) ;; + *) ((ahead++)) ;; esac done count="$behind $ahead" @@ -299,13 +285,13 @@ __git_ps1 () fi fi if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then - git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$" + git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$" fi if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then - if [ -n "$(git ls-files --others --exclude-standard)" ]; then - u="%" - fi + if [ -n "$(git ls-files --others --exclude-standard)" ]; then + u="%" + fi fi if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then @@ -314,7 +300,7 @@ __git_ps1 () fi local f="$w$i$s$u" - printf "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p" + printf -- "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p" fi } @@ -739,6 +725,9 @@ __git_complete_remote_or_refspec () { local cur_="$cur" cmd="${words[1]}" local i c=2 remote="" pfx="" lhs=1 no_complete_refspec=0 + if [ "$cmd" = "remote" ]; then + ((c++)) + fi while [ $c -lt $cword ]; do i="${words[c]}" case "$i" in @@ -756,7 +745,7 @@ __git_complete_remote_or_refspec () -*) ;; *) remote="$i"; break ;; esac - c=$((++c)) + ((c++)) done if [ -z "$remote" ]; then __gitcomp_nl "$(__git_remotes)" @@ -789,7 +778,7 @@ __git_complete_remote_or_refspec () __gitcomp_nl "$(__git_refs)" "$pfx" "$cur_" fi ;; - pull) + pull|remote) if [ $lhs = 1 ]; then __gitcomp_nl "$(__git_refs "$remote")" "$pfx" "$cur_" else @@ -996,7 +985,7 @@ __git_find_on_cmdline () return fi done - c=$((++c)) + ((c++)) done } @@ -1007,7 +996,7 @@ __git_has_doubledash () if [ "--" = "${words[c]}" ]; then return 0 fi - c=$((++c)) + ((c++)) done return 1 } @@ -1130,7 +1119,7 @@ _git_branch () -d|-m) only_local_ref="y" ;; -r) has_r="y" ;; esac - c=$((++c)) + ((c++)) done case "$cur" in @@ -1138,7 +1127,7 @@ _git_branch () __gitcomp " --color --no-color --verbose --abbrev= --no-abbrev --track --no-track --contains --merged --no-merged - --set-upstream --edit-description + --set-upstream --edit-description --list " ;; *) @@ -2104,6 +2093,7 @@ _git_config () core.whitespace core.worktree diff.autorefreshindex + diff.statGraphWidth diff.external diff.ignoreSubmodules diff.mnemonicprefix @@ -2290,7 +2280,7 @@ _git_config () _git_remote () { - local subcommands="add rename rm show prune update set-head" + local subcommands="add rename rm set-head set-branches set-url show prune update" local subcommand="$(__git_find_on_cmdline "$subcommands")" if [ -z "$subcommand" ]; then __gitcomp "$subcommands" @@ -2298,9 +2288,12 @@ _git_remote () fi case "$subcommand" in - rename|rm|show|prune) + rename|rm|set-url|show|prune) __gitcomp_nl "$(__git_remotes)" ;; + set-head|set-branches) + __git_complete_remote_or_refspec + ;; update) local i c='' IFS=$'\n' for i in $(git --git-dir="$(__gitdir)" config --get-regexp "remotes\..*" 2>/dev/null); do @@ -2513,7 +2506,7 @@ _git_svn () __gitcomp " --merge --strategy= --verbose --dry-run --fetch-all --no-rebase --commit-url - --revision $cmt_opts $fc_opts + --revision --interactive $cmt_opts $fc_opts " ;; set-tree,--*) @@ -2581,7 +2574,7 @@ _git_tag () f=1 ;; esac - c=$((++c)) + ((c++)) done case "$prev" in @@ -2634,7 +2627,7 @@ _git () --help) command="help"; break ;; *) command="$i"; break ;; esac - c=$((++c)) + ((c++)) done if [ -z "$command" ]; then diff --git a/contrib/diff-highlight/README b/contrib/diff-highlight/README index 1b7b6df8eb..502e03b305 100644 --- a/contrib/diff-highlight/README +++ b/contrib/diff-highlight/README @@ -14,13 +14,15 @@ Instead, this script post-processes the line-oriented diff, finds pairs of lines, and highlights the differing segments. It's currently very simple and stupid about doing these tasks. In particular: - 1. It will only highlight a pair of lines if they are the only two - lines in a hunk. It could instead try to match up "before" and - "after" lines for a given hunk into pairs of similar lines. - However, this may end up visually distracting, as the paired - lines would have other highlighted lines in between them. And in - practice, the lines which most need attention called to their - small, hard-to-see changes are touching only a single line. + 1. It will only highlight hunks in which the number of removed and + added lines is the same, and it will pair lines within the hunk by + position (so the first removed line is compared to the first added + line, and so forth). This is simple and tends to work well in + practice. More complex changes don't highlight well, so we tend to + exclude them due to the "same number of removed and added lines" + restriction. Or even if we do try to highlight them, they end up + not highlighting because of our "don't highlight if the whole line + would be highlighted" rule. 2. It will find the common prefix and suffix of two lines, and consider everything in the middle to be "different". It could @@ -55,3 +57,96 @@ following in your git configuration: show = diff-highlight | less diff = diff-highlight | less --------------------------------------------- + +Bugs +---- + +Because diff-highlight relies on heuristics to guess which parts of +changes are important, there are some cases where the highlighting is +more distracting than useful. Fortunately, these cases are rare in +practice, and when they do occur, the worst case is simply a little +extra highlighting. This section documents some cases known to be +sub-optimal, in case somebody feels like working on improving the +heuristics. + +1. Two changes on the same line get highlighted in a blob. For example, + highlighting: + +---------------------------------------------- +-foo(buf, size); ++foo(obj->buf, obj->size); +---------------------------------------------- + + yields (where the inside of "+{}" would be highlighted): + +---------------------------------------------- +-foo(buf, size); ++foo(+{obj->buf, obj->}size); +---------------------------------------------- + + whereas a more semantically meaningful output would be: + +---------------------------------------------- +-foo(buf, size); ++foo(+{obj->}buf, +{obj->}size); +---------------------------------------------- + + Note that doing this right would probably involve a set of + content-specific boundary patterns, similar to word-diff. Otherwise + you get junk like: + +----------------------------------------------------- +-this line has some -{i}nt-{ere}sti-{ng} text on it ++this line has some +{fa}nt+{a}sti+{c} text on it +----------------------------------------------------- + + which is less readable than the current output. + +2. The multi-line matching assumes that lines in the pre- and post-image + match by position. This is often the case, but can be fooled when a + line is removed from the top and a new one added at the bottom (or + vice versa). Unless the lines in the middle are also changed, diffs + will show this as two hunks, and it will not get highlighted at all + (which is good). But if the lines in the middle are changed, the + highlighting can be misleading. Here's a pathological case: + +----------------------------------------------------- +-one +-two +-three +-four ++two 2 ++three 3 ++four 4 ++five 5 +----------------------------------------------------- + + which gets highlighted as: + +----------------------------------------------------- +-one +-t-{wo} +-three +-f-{our} ++two 2 ++t+{hree 3} ++four 4 ++f+{ive 5} +----------------------------------------------------- + + because it matches "two" to "three 3", and so forth. It would be + nicer as: + +----------------------------------------------------- +-one +-two +-three +-four ++two +{2} ++three +{3} ++four +{4} ++five 5 +----------------------------------------------------- + + which would probably involve pre-matching the lines into pairs + according to some heuristic. diff --git a/contrib/diff-highlight/diff-highlight b/contrib/diff-highlight/diff-highlight index d8938982e4..c4404d49c9 100755 --- a/contrib/diff-highlight/diff-highlight +++ b/contrib/diff-highlight/diff-highlight @@ -1,28 +1,37 @@ #!/usr/bin/perl +use warnings FATAL => 'all'; +use strict; + # Highlight by reversing foreground and background. You could do # other things like bold or underline if you prefer. my $HIGHLIGHT = "\x1b[7m"; my $UNHIGHLIGHT = "\x1b[27m"; my $COLOR = qr/\x1b\[[0-9;]*m/; +my $BORING = qr/$COLOR|\s/; -my @window; +my @removed; +my @added; +my $in_hunk; while (<>) { - # We highlight only single-line changes, so we need - # a 4-line window to make a decision on whether - # to highlight. - push @window, $_; - next if @window < 4; - if ($window[0] =~ /^$COLOR*(\@| )/ && - $window[1] =~ /^$COLOR*-/ && - $window[2] =~ /^$COLOR*\+/ && - $window[3] !~ /^$COLOR*\+/) { - print shift @window; - show_pair(shift @window, shift @window); + if (!$in_hunk) { + print; + $in_hunk = /^$COLOR*\@/; + } + elsif (/^$COLOR*-/) { + push @removed, $_; + } + elsif (/^$COLOR*\+/) { + push @added, $_; } else { - print shift @window; + show_hunk(\@removed, \@added); + @removed = (); + @added = (); + + print; + $in_hunk = /^$COLOR*[\@ ]/; } # Most of the time there is enough output to keep things streaming, @@ -38,23 +47,40 @@ while (<>) { } } -# Special case a single-line hunk at the end of file. -if (@window == 3 && - $window[0] =~ /^$COLOR*(\@| )/ && - $window[1] =~ /^$COLOR*-/ && - $window[2] =~ /^$COLOR*\+/) { - print shift @window; - show_pair(shift @window, shift @window); -} - -# And then flush any remaining lines. -while (@window) { - print shift @window; -} +# Flush any queued hunk (this can happen when there is no trailing context in +# the final diff of the input). +show_hunk(\@removed, \@added); exit 0; -sub show_pair { +sub show_hunk { + my ($a, $b) = @_; + + # If one side is empty, then there is nothing to compare or highlight. + if (!@$a || !@$b) { + print @$a, @$b; + return; + } + + # If we have mismatched numbers of lines on each side, we could try to + # be clever and match up similar lines. But for now we are simple and + # stupid, and only handle multi-line hunks that remove and add the same + # number of lines. + if (@$a != @$b) { + print @$a, @$b; + return; + } + + my @queue; + for (my $i = 0; $i < @$a; $i++) { + my ($rm, $add) = highlight_pair($a->[$i], $b->[$i]); + print $rm; + push @queue, $add; + } + print @queue; +} + +sub highlight_pair { my @a = split_line(shift); my @b = split_line(shift); @@ -101,8 +127,14 @@ sub show_pair { } } - print highlight(\@a, $pa, $sa); - print highlight(\@b, $pb, $sb); + if (is_pair_interesting(\@a, $pa, $sa, \@b, $pb, $sb)) { + return highlight_line(\@a, $pa, $sa), + highlight_line(\@b, $pb, $sb); + } + else { + return join('', @a), + join('', @b); + } } sub split_line { @@ -111,7 +143,7 @@ sub split_line { split /($COLOR*)/; } -sub highlight { +sub highlight_line { my ($line, $prefix, $suffix) = @_; return join('', @@ -122,3 +154,20 @@ sub highlight { @{$line}[($suffix+1)..$#$line] ); } + +# Pairs are interesting to highlight only if we are going to end up +# highlighting a subset (i.e., not the whole line). Otherwise, the highlighting +# is just useless noise. We can detect this by finding either a matching prefix +# or suffix (disregarding boring bits like whitespace and colorization). +sub is_pair_interesting { + my ($a, $pa, $sa, $b, $pb, $sb) = @_; + my $prefix_a = join('', @$a[0..($pa-1)]); + my $prefix_b = join('', @$b[0..($pb-1)]); + my $suffix_a = join('', @$a[($sa+1)..$#$a]); + my $suffix_b = join('', @$b[($sb+1)..$#$b]); + + return $prefix_a !~ /^$COLOR*-$BORING*$/ || + $prefix_b !~ /^$COLOR*\+$BORING*$/ || + $suffix_a !~ /^$BORING*$/ || + $suffix_b !~ /^$BORING*$/; +} diff --git a/contrib/diffall/README b/contrib/diffall/README new file mode 100644 index 0000000000..507f17dcd6 --- /dev/null +++ b/contrib/diffall/README @@ -0,0 +1,31 @@ +The git-diffall script provides a directory based diff mechanism +for git. + +To determine what diff viewer is used, the script requires either +the 'diff.tool' or 'merge.tool' configuration option to be set. + +This script is compatible with most common forms used to specify a +range of revisions to diff: + + 1. git diffall: shows diff between working tree and staged changes + 2. git diffall --cached [<commit>]: shows diff between staged + changes and HEAD (or other named commit) + 3. git diffall <commit>: shows diff between working tree and named + commit + 4. git diffall <commit> <commit>: show diff between two named commits + 5. git diffall <commit>..<commit>: same as above + 6. git diffall <commit>...<commit>: show the changes on the branch + containing and up to the second, starting at a common ancestor + of both <commit> + +Note: all forms take an optional path limiter [-- <path>*] + +The '--extcmd=<command>' option allows the user to specify a custom +command for viewing diffs. When given, configured defaults are +ignored and the script runs $command $LOCAL $REMOTE. Additionally, +$BASE is set in the environment. + +This script is based on an example provided by Thomas Rast on the +Git list [1]: + +[1] http://thread.gmane.org/gmane.comp.version-control.git/124807 diff --git a/contrib/diffall/git-diffall b/contrib/diffall/git-diffall new file mode 100755 index 0000000000..84f2b654d7 --- /dev/null +++ b/contrib/diffall/git-diffall @@ -0,0 +1,257 @@ +#!/bin/sh +# Copyright 2010 - 2012, Tim Henigan <tim.henigan@gmail.com> +# +# Perform a directory diff between commits in the repository using +# the external diff or merge tool specified in the user's config. + +USAGE='[--cached] [--copy-back] [-x|--extcmd=<command>] <commit>{0,2} [-- <path>*] + + --cached Compare to the index rather than the working tree. + + --copy-back Copy files back to the working tree when the diff + tool exits (in case they were modified by the + user). This option is only valid if the diff + compared with the working tree. + + -x=<command> + --extcmd=<command> Specify a custom command for viewing diffs. + git-diffall ignores the configured defaults and + runs $command $LOCAL $REMOTE when this option is + specified. Additionally, $BASE is set in the + environment. +' + +SUBDIRECTORY_OK=1 +. "$(git --exec-path)/git-sh-setup" + +TOOL_MODE=diff +. "$(git --exec-path)/git-mergetool--lib" + +merge_tool="$(get_merge_tool)" +if test -z "$merge_tool" +then + echo "Error: Either the 'diff.tool' or 'merge.tool' option must be set." + usage +fi + +start_dir=$(pwd) + +# All the file paths returned by the diff command are relative to the root +# of the working copy. So if the script is called from a subdirectory, it +# must switch to the root of working copy before trying to use those paths. +cdup=$(git rev-parse --show-cdup) && +cd "$cdup" || { + echo >&2 "Cannot chdir to $cdup, the toplevel of the working tree" + exit 1 +} + +# set up temp dir +tmp=$(perl -e 'use File::Temp qw(tempdir); + $t=tempdir("/tmp/git-diffall.XXXXX") or exit(1); + print $t') || exit 1 +trap 'rm -rf "$tmp"' EXIT + +left= +right= +paths= +dashdash_seen= +compare_staged= +merge_base= +left_dir= +right_dir= +diff_tool= +copy_back= + +while test $# != 0 +do + case "$1" in + -h|--h|--he|--hel|--help) + usage + ;; + --cached) + compare_staged=1 + ;; + --copy-back) + copy_back=1 + ;; + -x|--e|--ex|--ext|--extc|--extcm|--extcmd) + if test $# = 1 + then + echo You must specify the tool for use with --extcmd + usage + else + diff_tool=$2 + shift + fi + ;; + --) + dashdash_seen=1 + ;; + -*) + echo Invalid option: "$1" + usage + ;; + *) + # could be commit, commit range or path limiter + case "$1" in + *...*) + left=${1%...*} + right=${1#*...} + merge_base=1 + ;; + *..*) + left=${1%..*} + right=${1#*..} + ;; + *) + if test -n "$dashdash_seen" + then + paths="$paths$1 " + elif test -z "$left" + then + left=$1 + elif test -z "$right" + then + right=$1 + else + paths="$paths$1 " + fi + ;; + esac + ;; + esac + shift +done + +# Determine the set of files which changed +if test -n "$left" && test -n "$right" +then + left_dir="cmt-$(git rev-parse --short $left)" + right_dir="cmt-$(git rev-parse --short $right)" + + if test -n "$compare_staged" + then + usage + elif test -n "$merge_base" + then + git diff --name-only "$left"..."$right" -- $paths >"$tmp/filelist" + else + git diff --name-only "$left" "$right" -- $paths >"$tmp/filelist" + fi +elif test -n "$left" +then + left_dir="cmt-$(git rev-parse --short $left)" + + if test -n "$compare_staged" + then + right_dir="staged" + git diff --name-only --cached "$left" -- $paths >"$tmp/filelist" + else + right_dir="working_tree" + git diff --name-only "$left" -- $paths >"$tmp/filelist" + fi +else + left_dir="HEAD" + + if test -n "$compare_staged" + then + right_dir="staged" + git diff --name-only --cached -- $paths >"$tmp/filelist" + else + right_dir="working_tree" + git diff --name-only -- $paths >"$tmp/filelist" + fi +fi + +# Exit immediately if there are no diffs +if test ! -s "$tmp/filelist" +then + exit 0 +fi + +if test -n "$copy_back" && test "$right_dir" != "working_tree" +then + echo "--copy-back is only valid when diff includes the working tree." + exit 1 +fi + +# Create the named tmp directories that will hold the files to be compared +mkdir -p "$tmp/$left_dir" "$tmp/$right_dir" + +# Populate the tmp/right_dir directory with the files to be compared +while read name +do + if test -n "$right" + then + ls_list=$(git ls-tree $right "$name") + if test -n "$ls_list" + then + mkdir -p "$tmp/$right_dir/$(dirname "$name")" + git show "$right":"$name" >"$tmp/$right_dir/$name" || true + fi + elif test -n "$compare_staged" + then + ls_list=$(git ls-files -- "$name") + if test -n "$ls_list" + then + mkdir -p "$tmp/$right_dir/$(dirname "$name")" + git show :"$name" >"$tmp/$right_dir/$name" + fi + else + if test -e "$name" + then + mkdir -p "$tmp/$right_dir/$(dirname "$name")" + cp "$name" "$tmp/$right_dir/$name" + fi + fi +done < "$tmp/filelist" + +# Populate the tmp/left_dir directory with the files to be compared +while read name +do + if test -n "$left" + then + ls_list=$(git ls-tree $left "$name") + if test -n "$ls_list" + then + mkdir -p "$tmp/$left_dir/$(dirname "$name")" + git show "$left":"$name" >"$tmp/$left_dir/$name" || true + fi + else + if test -n "$compare_staged" + then + ls_list=$(git ls-tree HEAD "$name") + if test -n "$ls_list" + then + mkdir -p "$tmp/$left_dir/$(dirname "$name")" + git show HEAD:"$name" >"$tmp/$left_dir/$name" + fi + else + mkdir -p "$tmp/$left_dir/$(dirname "$name")" + git show :"$name" >"$tmp/$left_dir/$name" + fi + fi +done < "$tmp/filelist" + +LOCAL="$tmp/$left_dir" +REMOTE="$tmp/$right_dir" + +if test -n "$diff_tool" +then + export BASE + eval $diff_tool '"$LOCAL"' '"$REMOTE"' +else + run_merge_tool "$merge_tool" false +fi + +# Copy files back to the working dir, if requested +if test -n "$copy_back" && test "$right_dir" = "working_tree" +then + cd "$start_dir" + git_top_dir=$(git rev-parse --show-toplevel) + find "$tmp/$right_dir" -type f | + while read file + do + cp "$file" "$git_top_dir/${file#$tmp/$right_dir/}" + done +fi diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index a78d9c5493..c5362c4c11 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -10,7 +10,7 @@ import optparse, sys, os, marshal, subprocess, shelve import tempfile, getopt, os.path, time, platform -import re +import re, shutil verbose = False @@ -38,7 +38,7 @@ def p4_build_cmd(cmd): host = gitConfig("git-p4.host") if len(host) > 0: - real_cmd += ["-h", host] + real_cmd += ["-H", host] client = gitConfig("git-p4.client") if len(client) > 0: @@ -186,6 +186,47 @@ def split_p4_type(p4type): mods = s[1] return (base, mods) +# +# return the raw p4 type of a file (text, text+ko, etc) +# +def p4_type(file): + results = p4CmdList(["fstat", "-T", "headType", file]) + return results[0]['headType'] + +# +# Given a type base and modifier, return a regexp matching +# the keywords that can be expanded in the file +# +def p4_keywords_regexp_for_type(base, type_mods): + if base in ("text", "unicode", "binary"): + kwords = None + if "ko" in type_mods: + kwords = 'Id|Header' + elif "k" in type_mods: + kwords = 'Id|Header|Author|Date|DateTime|Change|File|Revision' + else: + return None + pattern = r""" + \$ # Starts with a dollar, followed by... + (%s) # one of the keywords, followed by... + (:[^$]+)? # possibly an old expansion, followed by... + \$ # another dollar + """ % kwords + return pattern + else: + return None + +# +# Given a file, return a regexp matching the possible +# RCS keywords that will be expanded, or None for files +# with kw expansion turned off. +# +def p4_keywords_regexp_for_file(file): + if not os.path.exists(file): + return None + else: + (type_base, type_mods) = split_p4_type(p4_type(file)) + return p4_keywords_regexp_for_type(type_base, type_mods) def setP4ExecBit(file, mode): # Reopens an already open file and changes the execute bit to match @@ -555,6 +596,46 @@ def p4PathStartsWith(path, prefix): return path.lower().startswith(prefix.lower()) return path.startswith(prefix) +def getClientSpec(): + """Look at the p4 client spec, create a View() object that contains + all the mappings, and return it.""" + + specList = p4CmdList("client -o") + if len(specList) != 1: + die('Output from "client -o" is %d lines, expecting 1' % + len(specList)) + + # dictionary of all client parameters + entry = specList[0] + + # just the keys that start with "View" + view_keys = [ k for k in entry.keys() if k.startswith("View") ] + + # hold this new View + view = View() + + # append the lines, in order, to the view + for view_num in range(len(view_keys)): + k = "View%d" % view_num + if k not in view_keys: + die("Expected view key %s missing" % k) + view.append(entry[k]) + + return view + +def getClientRoot(): + """Grab the client directory.""" + + output = p4CmdList("client -o") + if len(output) != 1: + die('Output from "client -o" is %d lines, expecting 1' % len(output)) + + entry = output[0] + if "Root" not in entry: + die('Client has no "Root"') + + return entry["Root"] + class Command: def __init__(self): self.usage = "usage: %prog [options]" @@ -753,6 +834,29 @@ class P4Submit(Command, P4UserMap): return result + def patchRCSKeywords(self, file, pattern): + # Attempt to zap the RCS keywords in a p4 controlled file matching the given pattern + (handle, outFileName) = tempfile.mkstemp(dir='.') + try: + outFile = os.fdopen(handle, "w+") + inFile = open(file, "r") + regexp = re.compile(pattern, re.VERBOSE) + for line in inFile.readlines(): + line = regexp.sub(r'$\1$', line) + outFile.write(line) + inFile.close() + outFile.close() + # Forcibly overwrite the original file + os.unlink(file) + shutil.move(outFileName, file) + except: + # cleanup our temporary file + os.unlink(outFileName) + print "Failed to strip RCS keywords in %s" % file + raise + + print "Patched up RCS keywords in %s" % file + def p4UserForCommit(self,id): # Return the tuple (perforce user,git email) for a given git commit id self.getUserMapFromPerforceServer() @@ -918,6 +1022,7 @@ class P4Submit(Command, P4UserMap): filesToDelete = set() editedFiles = set() filesToChangeExecBit = {} + for line in diff: diff = parseDiffTreeEntry(line) modifier = diff['status'] @@ -964,9 +1069,45 @@ class P4Submit(Command, P4UserMap): patchcmd = diffcmd + " | git apply " tryPatchCmd = patchcmd + "--check -" applyPatchCmd = patchcmd + "--check --apply -" + patch_succeeded = True if os.system(tryPatchCmd) != 0: + fixed_rcs_keywords = False + patch_succeeded = False print "Unfortunately applying the change failed!" + + # Patch failed, maybe it's just RCS keyword woes. Look through + # the patch to see if that's possible. + if gitConfig("git-p4.attemptRCSCleanup","--bool") == "true": + file = None + pattern = None + kwfiles = {} + for file in editedFiles | filesToDelete: + # did this file's delta contain RCS keywords? + pattern = p4_keywords_regexp_for_file(file) + + if pattern: + # this file is a possibility...look for RCS keywords. + regexp = re.compile(pattern, re.VERBOSE) + for line in read_pipe_lines(["git", "diff", "%s^..%s" % (id, id), file]): + if regexp.search(line): + if verbose: + print "got keyword match on %s in %s in %s" % (pattern, line, file) + kwfiles[file] = pattern + break + + for file in kwfiles: + if verbose: + print "zapping %s with %s" % (line,pattern) + self.patchRCSKeywords(file, kwfiles[file]) + fixed_rcs_keywords = True + + if fixed_rcs_keywords: + print "Retrying the patch with RCS keywords cleaned up" + if os.system(tryPatchCmd) == 0: + patch_succeeded = True + + if not patch_succeeded: print "What do you want to do?" response = "x" while response != "s" and response != "a" and response != "w": @@ -1119,11 +1260,20 @@ class P4Submit(Command, P4UserMap): print "Internal error: cannot locate perforce depot path from existing branches" sys.exit(128) - self.clientPath = p4Where(self.depotPath) + self.useClientSpec = False + if gitConfig("git-p4.useclientspec", "--bool") == "true": + self.useClientSpec = True + if self.useClientSpec: + self.clientSpecDirs = getClientSpec() - if len(self.clientPath) == 0: - print "Error: Cannot locate perforce checkout of %s in client view" % self.depotPath - sys.exit(128) + if self.useClientSpec: + # all files are relative to the client spec + self.clientPath = getClientRoot() + else: + self.clientPath = p4Where(self.depotPath) + + if self.clientPath == "": + die("Error: Cannot locate perforce checkout of %s in client view" % self.depotPath) print "Perforce checkout for depot path %s located at %s" % (self.depotPath, self.clientPath) self.oldWorkingDirectory = os.getcwd() @@ -1429,6 +1579,7 @@ class P4Sync(Command, P4UserMap): self.p4BranchesInGit = [] self.cloneExclude = [] self.useClientSpec = False + self.useClientSpec_from_options = False self.clientSpecDirs = None self.tempBranches = [] self.tempBranchLocation = "git-p4-tmp" @@ -1585,15 +1736,12 @@ class P4Sync(Command, P4UserMap): # Note that we do not try to de-mangle keywords on utf16 files, # even though in theory somebody may want that. - if type_base in ("text", "unicode", "binary"): - if "ko" in type_mods: - text = ''.join(contents) - text = re.sub(r'\$(Id|Header):[^$]*\$', r'$\1$', text) - contents = [ text ] - elif "k" in type_mods: - text = ''.join(contents) - text = re.sub(r'\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$', r'$\1$', text) - contents = [ text ] + pattern = p4_keywords_regexp_for_type(type_base, type_mods) + if pattern: + regexp = re.compile(pattern, re.VERBOSE) + text = ''.join(contents) + text = regexp.sub(r'$\1$', text) + contents = [ text ] self.gitStream.write("M %s inline %s\n" % (git_mode, relPath)) @@ -2125,33 +2273,6 @@ class P4Sync(Command, P4UserMap): print self.gitError.read() - def getClientSpec(self): - specList = p4CmdList("client -o") - if len(specList) != 1: - die('Output from "client -o" is %d lines, expecting 1' % - len(specList)) - - # dictionary of all client parameters - entry = specList[0] - - # just the keys that start with "View" - view_keys = [ k for k in entry.keys() if k.startswith("View") ] - - # hold this new View - view = View() - - # append the lines, in order, to the view - for view_num in range(len(view_keys)): - k = "View%d" % view_num - if k not in view_keys: - die("Expected view key %s missing" % k) - view.append(entry[k]) - - self.clientSpecDirs = view - if self.verbose: - for i, m in enumerate(self.clientSpecDirs.mappings): - print "clientSpecDirs %d: %s" % (i, str(m)) - def run(self, args): self.depotPaths = [] self.changeRange = "" @@ -2184,11 +2305,15 @@ class P4Sync(Command, P4UserMap): if not gitBranchExists(self.refPrefix + "HEAD") and self.importIntoRemotes and gitBranchExists(self.branch): system("git symbolic-ref %sHEAD %s" % (self.refPrefix, self.branch)) - if not self.useClientSpec: + # accept either the command-line option, or the configuration variable + if self.useClientSpec: + # will use this after clone to set the variable + self.useClientSpec_from_options = True + else: if gitConfig("git-p4.useclientspec", "--bool") == "true": self.useClientSpec = True if self.useClientSpec: - self.getClientSpec() + self.clientSpecDirs = getClientSpec() # TODO: should always look at previous commits, # merge with previous imports, if possible. @@ -2509,6 +2634,10 @@ class P4Clone(P4Sync): else: print "Could not detect main branch. No checkout/master branch created." + # auto-set this variable if invoked with --use-client-spec + if self.useClientSpec_from_options: + system("git config --bool git-p4.useclientspec true") + return True class P4Branches(Command): diff --git a/contrib/hooks/post-receive-email b/contrib/hooks/post-receive-email index ba077c13f9..01af9df15e 100755 --- a/contrib/hooks/post-receive-email +++ b/contrib/hooks/post-receive-email @@ -85,7 +85,6 @@ prep_for_email() oldrev=$(git rev-parse $1) newrev=$(git rev-parse $2) refname="$3" - maxlines=$4 # --- Interpret # 0000->1234 (create) @@ -461,7 +460,7 @@ generate_delete_branch_email() { echo " was $oldrev" echo "" - echo $LOGEND + echo $LOGBEGIN git show -s --pretty=oneline $oldrev echo $LOGEND } @@ -561,7 +560,7 @@ generate_delete_atag_email() { echo " was $oldrev" echo "" - echo $LOGEND + echo $LOGBEGIN git show -s --pretty=oneline $oldrev echo $LOGEND } @@ -626,7 +625,7 @@ generate_delete_general_email() { echo " was $oldrev" echo "" - echo $LOGEND + echo $LOGBEGIN git show -s --pretty=oneline $oldrev echo $LOGEND } @@ -2,6 +2,7 @@ #include "attr.h" #include "run-command.h" #include "quote.h" +#include "sigchain.h" /* * convert.c - convert a file when checking it out and checking it in. @@ -195,9 +196,17 @@ static int crlf_to_git(const char *path, const char *src, size_t len, char *dst; if (crlf_action == CRLF_BINARY || - (crlf_action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE) || !len) + (crlf_action == CRLF_GUESS && auto_crlf == AUTO_CRLF_FALSE) || + (src && !len)) return 0; + /* + * If we are doing a dry-run and have no source buffer, there is + * nothing to analyze; we must assume we would convert. + */ + if (!buf && !src) + return 1; + gather_stats(src, len, &stats); if (crlf_action == CRLF_AUTO || crlf_action == CRLF_GUESS) { @@ -231,6 +240,13 @@ static int crlf_to_git(const char *path, const char *src, size_t len, if (!stats.cr) return 0; + /* + * At this point all of our source analysis is done, and we are sure we + * would convert. If we are in dry-run mode, we can give an answer. + */ + if (!buf) + return 1; + /* only grow if not in place */ if (strbuf_avail(buf) + buf->len < len) strbuf_grow(buf, len - buf->len); @@ -360,12 +376,16 @@ static int filter_buffer(int in, int out, void *data) if (start_command(&child_process)) return error("cannot fork to run external filter %s", params->cmd); + sigchain_push(SIGPIPE, SIG_IGN); + write_err = (write_in_full(child_process.in, params->src, params->size) < 0); if (close(child_process.in)) write_err = 1; if (write_err) error("cannot feed the input to external filter %s", params->cmd); + sigchain_pop(SIGPIPE); + status = finish_command(&child_process); if (status) error("external filter %s failed %d", params->cmd, status); @@ -391,6 +411,9 @@ static int apply_filter(const char *path, const char *src, size_t len, if (!cmd) return 0; + if (!dst) + return 1; + memset(&async, 0, sizeof(async)); async.proc = filter_buffer; async.data = ¶ms; @@ -429,6 +452,7 @@ static struct convert_driver { struct convert_driver *next; const char *smudge; const char *clean; + int required; } *user_convert, **user_convert_tail; static int read_convert_config(const char *var, const char *value, void *cb) @@ -472,6 +496,11 @@ static int read_convert_config(const char *var, const char *value, void *cb) if (!strcmp("clean", ep)) return git_config_string(&drv->clean, var, value); + if (!strcmp("required", ep)) { + drv->required = git_config_bool(var, value); + return 0; + } + return 0; } @@ -522,9 +551,12 @@ static int ident_to_git(const char *path, const char *src, size_t len, { char *dst, *dollar; - if (!ident || !count_ident(src, len)) + if (!ident || (src && !count_ident(src, len))) return 0; + if (!buf) + return 1; + /* only grow if not in place */ if (strbuf_avail(buf) + buf->len < len) strbuf_grow(buf, len - buf->len); @@ -747,20 +779,26 @@ int convert_to_git(const char *path, const char *src, size_t len, { int ret = 0; const char *filter = NULL; + int required = 0; struct conv_attrs ca; convert_attrs(&ca, path); - if (ca.drv) + if (ca.drv) { filter = ca.drv->clean; + required = ca.drv->required; + } ret |= apply_filter(path, src, len, dst, filter); - if (ret) { + if (!ret && required) + die("%s: clean filter '%s' failed", path, ca.drv->name); + + if (ret && dst) { src = dst->buf; len = dst->len; } ca.crlf_action = input_crlf_action(ca.crlf_action, ca.eol_attr); ret |= crlf_to_git(path, src, len, dst, ca.crlf_action, checksafe); - if (ret) { + if (ret && dst) { src = dst->buf; len = dst->len; } @@ -771,13 +809,16 @@ static int convert_to_working_tree_internal(const char *path, const char *src, size_t len, struct strbuf *dst, int normalizing) { - int ret = 0; + int ret = 0, ret_filter = 0; const char *filter = NULL; + int required = 0; struct conv_attrs ca; convert_attrs(&ca, path); - if (ca.drv) + if (ca.drv) { filter = ca.drv->smudge; + required = ca.drv->required; + } ret |= ident_to_worktree(path, src, len, dst, ca.ident); if (ret) { @@ -796,7 +837,12 @@ static int convert_to_working_tree_internal(const char *path, const char *src, len = dst->len; } } - return ret | apply_filter(path, src, len, dst, filter); + + ret_filter = apply_filter(path, src, len, dst, filter); + if (!ret_filter && required) + die("%s: smudge filter %s failed", path, ca.drv->name); + + return ret | ret_filter; } int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst) @@ -40,6 +40,11 @@ extern int convert_to_working_tree(const char *path, const char *src, size_t len, struct strbuf *dst); extern int renormalize_buffer(const char *path, const char *src, size_t len, struct strbuf *dst); +static inline int would_convert_to_git(const char *path, const char *src, + size_t len, enum safe_crlf checksafe) +{ + return convert_to_git(path, src, len, NULL, checksafe); +} /***************************************************************** * @@ -25,3 +25,39 @@ unsigned char sane_ctype[256] = { A, A, A, A, A, A, A, A, A, A, A, R, R, 0, P, 0, /* 112..127 */ /* Nothing in the 128.. range */ }; + +/* For case-insensitive kwset */ +const char tolower_trans_tbl[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + ' ', '!', '"', '#', '$', '%', '&', 0x27, + '(', ')', '*', '+', ',', '-', '.', '/', + '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', 'w', + 'x', 'y', 'z', '[', 0x5c, ']', '^', '_', + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', '{', '|', '}', '~', 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +}; @@ -31,6 +31,7 @@ static const char *external_diff_cmd_cfg; int diff_auto_refresh_index = 1; static int diff_mnemonic_prefix; static int diff_no_prefix; +static int diff_stat_graph_width; static int diff_dirstat_permille_default = 30; static struct diff_options default_diff_options; @@ -156,6 +157,10 @@ int git_diff_ui_config(const char *var, const char *value, void *cb) diff_no_prefix = git_config_bool(var, value); return 0; } + if (!strcmp(var, "diff.statgraphwidth")) { + diff_stat_graph_width = git_config_int(var, value); + return 0; + } if (!strcmp(var, "diff.external")) return git_config_string(&external_diff_cmd_cfg, var, value); if (!strcmp(var, "diff.wordregex")) @@ -177,11 +182,8 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) return 0; } - switch (userdiff_config(var, value)) { - case 0: break; - case -1: return -1; - default: return 0; - } + if (userdiff_config(var, value) < 0) + return -1; if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) { int slot = parse_diff_color_slot(var, 11); @@ -1276,13 +1278,15 @@ const char mime_boundary_leader[] = "------------"; static int scale_linear(int it, int width, int max_change) { + if (!it) + return 0; /* - * make sure that at least one '-' is printed if there were deletions, - * and likewise for '+'. + * make sure that at least one '-' or '+' is printed if + * there is any change to this path. The easiest way is to + * scale linearly as if the alloted width is one column shorter + * than it is, and then add 1 to the result. */ - if (max_change < 2) - return it; - return ((it - 1) * (width - 1) + max_change - 1) / (max_change - 1); + return 1 + (it * (width - 1) / max_change); } static void show_name(FILE *file, @@ -1322,12 +1326,61 @@ static void fill_print_name(struct diffstat_file *file) file->print_name = pname; } +int print_stat_summary(FILE *fp, int files, int insertions, int deletions) +{ + struct strbuf sb = STRBUF_INIT; + int ret; + + if (!files) { + assert(insertions == 0 && deletions == 0); + return fputs(_(" 0 files changed\n"), fp); + } + + strbuf_addf(&sb, + Q_(" %d file changed", " %d files changed", files), + files); + + /* + * For binary diff, the caller may want to print "x files + * changed" with insertions == 0 && deletions == 0. + * + * Not omitting "0 insertions(+), 0 deletions(-)" in this case + * is probably less confusing (i.e skip over "2 files changed + * but nothing about added/removed lines? Is this a bug in Git?"). + */ + if (insertions || deletions == 0) { + /* + * TRANSLATORS: "+" in (+) is a line addition marker; + * do not translate it. + */ + strbuf_addf(&sb, + Q_(", %d insertion(+)", ", %d insertions(+)", + insertions), + insertions); + } + + if (deletions || insertions == 0) { + /* + * TRANSLATORS: "-" in (-) is a line removal marker; + * do not translate it. + */ + strbuf_addf(&sb, + Q_(", %d deletion(-)", ", %d deletions(-)", + deletions), + deletions); + } + strbuf_addch(&sb, '\n'); + ret = fputs(sb.buf, fp); + strbuf_release(&sb); + return ret; +} + static void show_stats(struct diffstat_t *data, struct diff_options *options) { int i, len, add, del, adds = 0, dels = 0; uintmax_t max_change = 0, max_len = 0; int total_files = data->nr; - int width, name_width, count; + int width, name_width, graph_width, number_width = 4, count; const char *reset, *add_c, *del_c; const char *line_prefix = ""; int extra_shown = 0; @@ -1341,25 +1394,15 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) line_prefix = msg->buf; } - width = options->stat_width ? options->stat_width : 80; - name_width = options->stat_name_width ? options->stat_name_width : 50; count = options->stat_count ? options->stat_count : data->nr; - /* Sanity: give at least 5 columns to the graph, - * but leave at least 10 columns for the name. - */ - if (width < 25) - width = 25; - if (name_width < 10) - name_width = 10; - else if (width < name_width + 15) - name_width = width - 15; - - /* Find the longest filename and max number of changes */ reset = diff_get_color_opt(options, DIFF_RESET); add_c = diff_get_color_opt(options, DIFF_FILE_NEW); del_c = diff_get_color_opt(options, DIFF_FILE_OLD); + /* + * Find the longest filename and max number of changes + */ for (i = 0; (i < count) && (i < data->nr); i++) { struct diffstat_file *file = data->files[i]; uintmax_t change = file->added + file->deleted; @@ -1380,19 +1423,72 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) } count = i; /* min(count, data->nr) */ - /* Compute the width of the graph part; - * 10 is for one blank at the beginning of the line plus - * " | count " between the name and the graph. + /* + * We have width = stat_width or term_columns() columns total. + * We want a maximum of min(max_len, stat_name_width) for the name part. + * We want a maximum of min(max_change, stat_graph_width) for the +- part. + * We also need 1 for " " and 4 + decimal_width(max_change) + * for " | NNNN " and one the empty column at the end, altogether + * 6 + decimal_width(max_change). + * + * If there's not enough space, we will use the smaller of + * stat_name_width (if set) and 5/8*width for the filename, + * and the rest for constant elements + graph part, but no more + * than stat_graph_width for the graph part. + * (5/8 gives 50 for filename and 30 for the constant parts + graph + * for the standard terminal size). * - * From here on, name_width is the width of the name area, - * and width is the width of the graph area. + * In other words: stat_width limits the maximum width, and + * stat_name_width fixes the maximum width of the filename, + * and is also used to divide available columns if there + * aren't enough. */ - name_width = (name_width < max_len) ? name_width : max_len; - if (width < (name_width + 10) + max_change) - width = width - (name_width + 10); + + if (options->stat_width == -1) + width = term_columns(); else - width = max_change; + width = options->stat_width ? options->stat_width : 80; + + if (options->stat_graph_width == -1) + options->stat_graph_width = diff_stat_graph_width; + + /* + * Guarantee 3/8*16==6 for the graph part + * and 5/8*16==10 for the filename part + */ + if (width < 16 + 6 + number_width) + width = 16 + 6 + number_width; + /* + * First assign sizes that are wanted, ignoring available width. + */ + graph_width = (options->stat_graph_width && + options->stat_graph_width < max_change) ? + options->stat_graph_width : max_change; + name_width = (options->stat_name_width > 0 && + options->stat_name_width < max_len) ? + options->stat_name_width : max_len; + + /* + * Adjust adjustable widths not to exceed maximum width + */ + if (name_width + number_width + 6 + graph_width > width) { + if (graph_width > width * 3/8 - number_width - 6) + graph_width = width * 3/8 - number_width - 6; + if (options->stat_graph_width && + graph_width > options->stat_graph_width) + graph_width = options->stat_graph_width; + if (name_width > width - number_width - 6 - graph_width) + name_width = width - number_width - 6 - graph_width; + else + graph_width = width - number_width - 6 - name_width; + } + + /* + * From here name_width is the width of the name area, + * and graph_width is the width of the graph area. + * max_change is used to scale graph properly. + */ for (i = 0; i < count; i++) { const char *prefix = ""; char *name = data->files[i]->print_name; @@ -1448,9 +1544,20 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) adds += add; dels += del; - if (width <= max_change) { - add = scale_linear(add, width, max_change); - del = scale_linear(del, width, max_change); + if (graph_width <= max_change) { + int total = add + del; + + total = scale_linear(add + del, graph_width, max_change); + if (total < 2 && add && del) + /* width >= 2 due to the sanity check */ + total = 2; + if (add < del) { + add = scale_linear(add, graph_width, max_change); + del = total - add; + } else { + del = scale_linear(del, graph_width, max_change); + add = total - del; + } } fprintf(options->file, "%s", line_prefix); show_name(options->file, prefix, name, len); @@ -1475,9 +1582,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options) extra_shown = 1; } fprintf(options->file, "%s", line_prefix); - fprintf(options->file, - " %d files changed, %d insertions(+), %d deletions(-)\n", - total_files, adds, dels); + print_stat_summary(options->file, total_files, adds, dels); } static void show_shortstats(struct diffstat_t *data, struct diff_options *options) @@ -1507,8 +1612,7 @@ static void show_shortstats(struct diffstat_t *data, struct diff_options *option options->output_prefix_data); fprintf(options->file, "%s", msg->buf); } - fprintf(options->file, " %d files changed, %d insertions(+), %d deletions(-)\n", - total_files, adds, dels); + print_stat_summary(options->file, total_files, adds, dels); } static void show_numstat(struct diffstat_t *data, struct diff_options *options) @@ -2151,7 +2255,7 @@ static void builtin_diff(const char *name_a, struct emit_callback ecbdata; const struct userdiff_funcname *pe; - if (!DIFF_XDL_TST(o, WHITESPACE_FLAGS) || must_show_header) { + if (must_show_header) { fprintf(o->file, "%s", header.buf); strbuf_reset(&header); } @@ -3243,6 +3347,7 @@ static int stat_opt(struct diff_options *options, const char **av) char *end; int width = options->stat_width; int name_width = options->stat_name_width; + int graph_width = options->stat_graph_width; int count = options->stat_count; int argcount = 1; @@ -3271,6 +3376,16 @@ static int stat_opt(struct diff_options *options, const char **av) name_width = strtoul(av[1], &end, 10); argcount = 2; } + } else if (!prefixcmp(arg, "-graph-width")) { + arg += strlen("-graph-width"); + if (*arg == '=') + graph_width = strtoul(arg + 1, &end, 10); + else if (!*arg && !av[1]) + die("Option '--stat-graph-width' requires a value"); + else if (!*arg) { + graph_width = strtoul(av[1], &end, 10); + argcount = 2; + } } else if (!prefixcmp(arg, "-count")) { arg += strlen("-count"); if (*arg == '=') @@ -3296,6 +3411,7 @@ static int stat_opt(struct diff_options *options, const char **av) return 0; options->output_format |= DIFF_FORMAT_DIFFSTAT; options->stat_name_width = name_width; + options->stat_graph_width = graph_width; options->stat_width = width; options->stat_count = count; return argcount; @@ -82,6 +82,7 @@ typedef struct strbuf *(*diff_prefix_fn_t)(struct diff_options *opt, void *data) #define DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG (1 << 27) #define DIFF_OPT_DIRSTAT_BY_LINE (1 << 28) #define DIFF_OPT_FUNCCONTEXT (1 << 29) +#define DIFF_OPT_PICKAXE_IGNORE_CASE (1 << 30) #define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag) #define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag) @@ -129,6 +130,7 @@ struct diff_options { int stat_width; int stat_name_width; + int stat_graph_width; int stat_count; const char *word_regex; enum diff_words_type word_diff; @@ -324,4 +326,7 @@ extern struct userdiff_driver *get_textconv(struct diff_filespec *one); extern int parse_rename_score(const char **cp_p); +extern int print_stat_summary(FILE *fp, int files, + int insertions, int deletions); + #endif /* DIFF_H */ diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c index 380a837b5b..ed23eb4bdd 100644 --- a/diffcore-pickaxe.c +++ b/diffcore-pickaxe.c @@ -138,8 +138,12 @@ static void diffcore_pickaxe_grep(struct diff_options *o) { int err; regex_t regex; + int cflags = REG_EXTENDED | REG_NEWLINE; - err = regcomp(®ex, o->pickaxe, REG_EXTENDED | REG_NEWLINE); + if (DIFF_OPT_TST(o, PICKAXE_IGNORE_CASE)) + cflags |= REG_ICASE; + + err = regcomp(®ex, o->pickaxe, cflags); if (err) { char errbuf[1024]; regerror(err, ®ex, errbuf, 1024); @@ -237,7 +241,8 @@ static void diffcore_pickaxe_count(struct diff_options *o) } regexp = ®ex; } else { - kws = kwsalloc(NULL); + kws = kwsalloc(DIFF_OPT_TST(o, PICKAXE_IGNORE_CASE) + ? tolower_trans_tbl : NULL); kwsincr(kws, needle, len); kwsprep(kws); } diff --git a/fast-import.c b/fast-import.c index 6cd19e580b..a85275dc68 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1641,6 +1641,8 @@ static int tree_content_get( n = slash1 - p; else n = strlen(p); + if (!n) + die("Empty path component found in input"); if (!root->tree) load_tree(root); @@ -2712,7 +2714,7 @@ static void parse_new_tag(void) /* Obtain the new tag name from the rest of our command */ sp = strchr(command_buf.buf, ' ') + 1; t = pool_alloc(sizeof(struct tag)); - t->next_tag = NULL; + memset(t, 0, sizeof(struct tag)); t->name = pool_strdup(sp); if (last_tag) last_tag->next_tag = t; @@ -3028,6 +3030,8 @@ static void parse_ls(struct branch *b) store_tree(&leaf); print_ls(leaf.versions[1].mode, leaf.versions[1].sha1, p); + if (leaf.tree) + release_tree_content_recursive(leaf.tree); if (!b || root != &b->branch_tree) release_tree_entry(root); } @@ -128,15 +128,18 @@ fall_back_3way () { mkdir "$dotest/patch-merge-tmp-dir" # First see if the patch records the index info that we can use. - git apply --build-fake-ancestor "$dotest/patch-merge-tmp-index" \ - "$dotest/patch" && + cmd="git apply $git_apply_opt --build-fake-ancestor" && + cmd="$cmd "'"$dotest/patch-merge-tmp-index" "$dotest/patch"' && + eval "$cmd" && GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \ 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... - if GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \ - git apply --cached <"$dotest/patch" + + cmd='GIT_INDEX_FILE="$dotest/patch-merge-tmp-index"' + cmd="$cmd git apply --cached $git_apply_opt"' <"$dotest/patch"' + if eval "$cmd" then mv "$dotest/patch-merge-base+" "$dotest/patch-merge-base" mv "$dotest/patch-merge-tmp-index" "$dotest/patch-merge-index" @@ -202,7 +205,7 @@ check_patch_format () { l1= while test -z "$l1" do - read l1 + read l1 || break done read l2 read l3 @@ -377,7 +380,9 @@ 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." + ;; -3|--3way) threeway=t ;; -s|--signoff) diff --git a/git-compat-util.h b/git-compat-util.h index 426ae43be9..ed11ad8119 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -457,6 +457,9 @@ static inline int has_extension(const char *filename, const char *ext) return len > extlen && !memcmp(filename + len - extlen, ext, extlen); } +/* in ctype.c, for kwset users */ +extern const char tolower_trans_tbl[256]; + /* Sane ctype - no locale, and works with signed chars */ #undef isascii #undef isspace diff --git a/git-parse-remote.sh b/git-parse-remote.sh index b24119d69c..484b2e61cc 100644 --- a/git-parse-remote.sh +++ b/git-parse-remote.sh @@ -57,34 +57,31 @@ error_on_missing_default_upstream () { op_prep="$3" example="$4" branch_name=$(git symbolic-ref -q HEAD) + # If there's only one remote, use that in the suggestion + remote="<remote>" + if test $(git remote | wc -l) = 1 + then + remote=$(git remote) + fi + if test -z "$branch_name" then - echo "You are not currently on a branch, so I cannot use any -'branch.<branchname>.merge' in your configuration file. -Please specify which branch you want to $op_type $op_prep on the command -line and try again (e.g. '$example'). -See git-${cmd}(1) for details." + echo "You are not currently on a branch. Please specify which +branch you want to $op_type $op_prep. See git-${cmd}(1) for details. + + $example +" else - echo "You asked me to $cmd without telling me which branch you -want to $op_type $op_prep, and 'branch.${branch_name#refs/heads/}.merge' in -your configuration file does not tell me, either. Please -specify which branch you want to use on the command line and -try again (e.g. '$example'). -See git-${cmd}(1) for details. + echo "There is no tracking information for the current branch. +Please specify which branch you want to $op_type $op_prep. +See git-${cmd}(1) for details + + $example -If you often $op_type $op_prep the same branch, you may want to -use something like the following in your configuration file: - [branch \"${branch_name#refs/heads/}\"] - remote = <nickname> - merge = <remote-ref>" - test rebase = "$op_type" && - echo " rebase = true" - echo " - [remote \"<nickname>\"] - url = <url> - fetch = <refspec> +If you wish to set tracking information for this branch you can do so with: -See git-config(1) for details." + git branch --set-upstream ${branch_name#refs/heads/} $remote/<branch> +" fi exit 1 } diff --git a/git-pull.sh b/git-pull.sh index d8b64d7a67..2a10047eb7 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -40,7 +40,7 @@ test -f "$GIT_DIR/MERGE_HEAD" && die_merge strategy_args= diffstat= no_commit= squash= no_ff= ff_only= log_arg= verbosity= progress= recurse_submodules= -merge_args= +merge_args= edit= curr_branch=$(git symbolic-ref -q HEAD) curr_branch_short="${curr_branch#refs/heads/}" rebase=$(git config --bool branch.$curr_branch_short.rebase) @@ -70,6 +70,10 @@ do no_commit=--no-commit ;; --c|--co|--com|--comm|--commi|--commit) no_commit=--commit ;; + -e|--edit) + edit=--edit ;; + --no-edit) + edit=--no-edit ;; --sq|--squ|--squa|--squas|--squash) squash=--squash ;; --no-sq|--no-squ|--no-squa|--no-squas|--no-squash) @@ -176,7 +180,7 @@ error_on_no_merge_candidates () { elif [ -z "$curr_branch" -o -z "$upstream" ]; then . git-parse-remote error_on_missing_default_upstream "pull" $op_type $op_prep \ - "git pull <repository> <refspec>" + "git pull <remote> <branch>" else echo "Your configuration specifies to $op_type $op_prep the ref '${upstream#refs/heads/}'" echo "from the remote, but no such ref was fetched." @@ -278,7 +282,7 @@ true) eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}" ;; *) - eval="git-merge $diffstat $no_commit $squash $no_ff $ff_only" + eval="git-merge $diffstat $no_commit $edit $squash $no_ff $ff_only" eval="$eval $log_arg $strategy_args $merge_args $verbosity $progress" eval="$eval \"\$merge_name\" HEAD $merge_head" ;; diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh index 26afc75cc7..dc599077f0 100644 --- a/git-rebase--merge.sh +++ b/git-rebase--merge.sh @@ -90,10 +90,13 @@ call_merge () { finish_rb_merge () { move_to_original_branch - git notes copy --for-rewrite=rebase < "$state_dir"/rewritten - if test -x "$GIT_DIR"/hooks/post-rewrite && - test -s "$state_dir"/rewritten; then - "$GIT_DIR"/hooks/post-rewrite rebase < "$state_dir"/rewritten + if test -s "$state_dir"/rewritten + then + git notes copy --for-rewrite=rebase <"$state_dir"/rewritten + if test -x "$GIT_DIR"/hooks/post-rewrite + then + "$GIT_DIR"/hooks/post-rewrite rebase <"$state_dir"/rewritten + fi fi rm -r "$state_dir" say All done. diff --git a/git-rebase.sh b/git-rebase.sh index 00ca7b99fe..69c1374823 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -380,7 +380,7 @@ then then . git-parse-remote error_on_missing_default_upstream "rebase" "rebase" \ - "against" "git rebase <upstream branch>" + "against" "git rebase <branch>" fi ;; *) upstream_name="$1" diff --git a/git-sh-i18n.sh b/git-sh-i18n.sh index d5fae993b0..6a27f68136 100644 --- a/git-sh-i18n.sh +++ b/git-sh-i18n.sh @@ -21,7 +21,7 @@ GIT_INTERNAL_GETTEXT_SH_SCHEME=fallthrough if test -n "@@USE_GETTEXT_SCHEME@@" then GIT_INTERNAL_GETTEXT_SH_SCHEME="@@USE_GETTEXT_SCHEME@@" -elif test -n "@@USE_FALLTHROUGH_GETTEXT_SCHEME@@$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS" +elif test -n "$GIT_INTERNAL_GETTEXT_TEST_FALLBACKS" then : no probing necessary elif test -n "$GIT_GETTEXT_POISON" diff --git a/git-submodule.sh b/git-submodule.sh index 9bb2e13e92..efc86ad4e0 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -132,46 +132,46 @@ module_clone() gitdir_base= name=$(module_name "$path" 2>/dev/null) test -n "$name" || name="$path" - base_path=$(dirname "$path") + base_name=$(dirname "$name") gitdir=$(git rev-parse --git-dir) - gitdir_base="$gitdir/modules/$base_path" - gitdir="$gitdir/modules/$path" - - case $gitdir in - /*) - a="$(cd_to_toplevel && pwd)/" - b=$gitdir - while [ "$b" ] && [ "${a%%/*}" = "${b%%/*}" ] - do - a=${a#*/} b=${b#*/}; - done - - rel="$a$name" - rel=`echo $rel | sed -e 's|[^/]*|..|g'` - rel_gitdir="$rel/$b" - ;; - *) - rel=`echo $name | sed -e 's|[^/]*|..|g'` - rel_gitdir="$rel/$gitdir" - ;; - esac + gitdir_base="$gitdir/modules/$base_name" + gitdir="$gitdir/modules/$name" if test -d "$gitdir" then mkdir -p "$path" - echo "gitdir: $rel_gitdir" >"$path/.git" rm -f "$gitdir/index" else mkdir -p "$gitdir_base" - if test -n "$reference" - then - git-clone $quiet "$reference" -n "$url" "$path" --separate-git-dir "$gitdir" - else - git-clone $quiet -n "$url" "$path" --separate-git-dir "$gitdir" - fi || + git clone $quiet -n ${reference:+"$reference"} \ + --separate-git-dir "$gitdir" "$url" "$path" || die "$(eval_gettext "Clone of '\$url' into submodule path '\$path' failed")" fi + + a=$(cd "$gitdir" && pwd)/ + b=$(cd "$path" && pwd)/ + # normalize Windows-style absolute paths to POSIX-style absolute paths + case $a in [a-zA-Z]:/*) a=/${a%%:*}${a#*:} ;; esac + case $b in [a-zA-Z]:/*) b=/${b%%:*}${b#*:} ;; esac + # Remove all common leading directories after a sanity check + if test "${a#$b}" != "$a" || test "${b#$a}" != "$b"; then + die "$(eval_gettext "Gitdir '\$a' is part of the submodule path '\$b' or vice versa")" + fi + while test "${a%%/*}" = "${b%%/*}" + do + a=${a#*/} + b=${b#*/} + done + # Now chop off the trailing '/'s that were added in the beginning + a=${a%/} + b=${b%/} + + rel=$(echo $b | sed -e 's|[^/]*|..|g') + echo "gitdir: $rel/$a" >"$path/.git" + + rel=$(echo $a | sed -e 's|[^/]*|..|g') + (clear_local_git_env; cd "$path" && GIT_WORK_TREE=. git config core.worktree "$rel/$b") } # diff --git a/git-svn.perl b/git-svn.perl index eeb83d3759..4334b95f70 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -1878,8 +1878,7 @@ sub cmt_sha2rev_batch { sub working_head_info { my ($head, $refs) = @_; - my @args = qw/log --no-color --no-decorate --first-parent - --pretty=medium/; + my @args = qw/rev-list --first-parent --pretty=medium/; my ($fh, $ctx) = command_output_pipe(@args, $head); my $hash; my %max; @@ -2029,6 +2028,7 @@ 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; @@ -3287,6 +3287,14 @@ sub get_untracked { \@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 @@ -3319,8 +3327,7 @@ sub parse_svn_date { delete $ENV{TZ}; } - my $our_TZ = - POSIX::strftime('%Z', $S, $M, $H, $d, $m - 1, $Y - 1900); + my $our_TZ = get_tz(); # This converts $epoch_in_UTC into our local timezone. my ($sec, $min, $hour, $mday, $mon, $year, @@ -3920,7 +3927,7 @@ sub rebuild { my ($base_rev, $head) = ($partial ? $self->rev_map_max_norebuild(1) : (undef, undef)); my ($log, $ctx) = - command_output_pipe(qw/rev-list --pretty=raw --no-color --reverse/, + command_output_pipe(qw/rev-list --pretty=raw --reverse/, ($head ? "$head.." : "") . $self->refname, '--'); my $metadata_url = $self->metadata_url; @@ -5130,7 +5137,7 @@ sub rmdirs { } sub open_or_add_dir { - my ($self, $full_path, $baton) = @_; + my ($self, $full_path, $baton, $deletions) = @_; my $t = $self->{types}->{$full_path}; if (!defined $t) { die "$full_path not known in r$self->{r} or we have a bug!\n"; @@ -5139,7 +5146,7 @@ sub open_or_add_dir { no warnings 'once'; # SVN::Node::none and SVN::Node::file are used only once, # so we're shutting up Perl's warnings about them. - if ($t == $SVN::Node::none) { + if ($t == $SVN::Node::none || defined($deletions->{$full_path})) { return $self->add_directory($full_path, $baton, undef, -1, $self->{pool}); } elsif ($t == $SVN::Node::dir) { @@ -5154,17 +5161,18 @@ sub open_or_add_dir { } sub ensure_path { - my ($self, $path) = @_; + my ($self, $path, $deletions) = @_; my $bat = $self->{bat}; my $repo_path = $self->repo_path($path); return $bat->{''} unless (length $repo_path); + my @p = split m#/+#, $repo_path; my $c = shift @p; - $bat->{$c} ||= $self->open_or_add_dir($c, $bat->{''}); + $bat->{$c} ||= $self->open_or_add_dir($c, $bat->{''}, $deletions); while (@p) { my $c0 = $c; $c .= '/' . shift @p; - $bat->{$c} ||= $self->open_or_add_dir($c, $bat->{$c0}); + $bat->{$c} ||= $self->open_or_add_dir($c, $bat->{$c0}, $deletions); } return $bat->{$c}; } @@ -5221,9 +5229,9 @@ sub apply_autoprops { } sub A { - my ($self, $m) = @_; + my ($self, $m, $deletions) = @_; my ($dir, $file) = split_path($m->{file_b}); - my $pbat = $self->ensure_path($dir); + my $pbat = $self->ensure_path($dir, $deletions); my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat, undef, -1); print "\tA\t$m->{file_b}\n" unless $::_q; @@ -5233,9 +5241,9 @@ sub A { } sub C { - my ($self, $m) = @_; + my ($self, $m, $deletions) = @_; my ($dir, $file) = split_path($m->{file_b}); - my $pbat = $self->ensure_path($dir); + my $pbat = $self->ensure_path($dir, $deletions); my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat, $self->url_path($m->{file_a}), $self->{r}); print "\tC\t$m->{file_a} => $m->{file_b}\n" unless $::_q; @@ -5252,9 +5260,9 @@ sub delete_entry { } sub R { - my ($self, $m) = @_; + my ($self, $m, $deletions) = @_; my ($dir, $file) = split_path($m->{file_b}); - my $pbat = $self->ensure_path($dir); + my $pbat = $self->ensure_path($dir, $deletions); my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat, $self->url_path($m->{file_a}), $self->{r}); print "\tR\t$m->{file_a} => $m->{file_b}\n" unless $::_q; @@ -5263,14 +5271,14 @@ sub R { $self->close_file($fbat,undef,$self->{pool}); ($dir, $file) = split_path($m->{file_a}); - $pbat = $self->ensure_path($dir); + $pbat = $self->ensure_path($dir, $deletions); $self->delete_entry($m->{file_a}, $pbat); } sub M { - my ($self, $m) = @_; + my ($self, $m, $deletions) = @_; my ($dir, $file) = split_path($m->{file_b}); - my $pbat = $self->ensure_path($dir); + my $pbat = $self->ensure_path($dir, $deletions); my $fbat = $self->open_file($self->repo_path($m->{file_b}), $pbat,$self->{r},$self->{pool}); print "\t$m->{chg}\t$m->{file_b}\n" unless $::_q; @@ -5340,9 +5348,9 @@ sub chg_file { } sub D { - my ($self, $m) = @_; + my ($self, $m, $deletions) = @_; my ($dir, $file) = split_path($m->{file_b}); - my $pbat = $self->ensure_path($dir); + my $pbat = $self->ensure_path($dir, $deletions); print "\tD\t$m->{file_b}\n" unless $::_q; $self->delete_entry($m->{file_b}, $pbat); } @@ -5374,11 +5382,19 @@ sub DESTROY { sub apply_diff { my ($self) = @_; my $mods = $self->{mods}; - my %o = ( D => 1, R => 0, C => -1, A => 3, M => 3, T => 3 ); + my %o = ( D => 0, C => 1, R => 2, A => 3, M => 4, T => 5 ); + my %deletions; + + foreach my $m (@$mods) { + if ($m->{chg} eq "D") { + $deletions{$m->{file_b}} = 1; + } + } + foreach my $m (sort { $o{$a->{chg}} <=> $o{$b->{chg}} } @$mods) { my $f = $m->{chg}; if (defined $o{$f}) { - $self->$f($m); + $self->$f($m, \%deletions); } else { fatal("Invalid change type: $f"); } @@ -5994,7 +6010,6 @@ package Git::SVN::Log; use strict; use warnings; use POSIX qw/strftime/; -use Time::Local; use constant commit_log_separator => ('-' x 72) . "\n"; use vars qw/$TZ $limit $color $pager $non_recursive $verbose $oneline %rusers $show_commit $incremental/; @@ -6104,11 +6119,8 @@ sub run_pager { } sub format_svn_date { - # 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 ]; - my $gmoff = sprintf("%s%02d%02d", $sign, (gmtime(abs($t - $gm)))[2,1]); + my $gmoff = Git::SVN::get_tz($t); return strftime("%Y-%m-%d %H:%M:%S $gmoff (%a, %d %b %Y)", localtime($t)); } diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 9ee58114d9..a8b5fad266 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -52,7 +52,7 @@ sub evaluate_uri { # as base URL. # Therefore, if we needed to strip PATH_INFO, then we know that we have # to build the base URL ourselves: - our $path_info = $ENV{"PATH_INFO"}; + our $path_info = decode_utf8($ENV{"PATH_INFO"}); if ($path_info) { if ($my_url =~ s,\Q$path_info\E$,, && $my_uri =~ s,\Q$path_info\E$,, && @@ -817,9 +817,9 @@ sub evaluate_query_params { while (my ($name, $symbol) = each %cgi_param_mapping) { if ($symbol eq 'opt') { - $input_params{$name} = [ $cgi->param($symbol) ]; + $input_params{$name} = [ map { decode_utf8($_) } $cgi->param($symbol) ]; } else { - $input_params{$name} = $cgi->param($symbol); + $input_params{$name} = decode_utf8($cgi->param($symbol)); } } } @@ -1081,7 +1081,16 @@ sub evaluate_and_validate_params { if (length($searchtext) < 2) { die_error(403, "At least two characters are required for search parameter"); } - $search_regexp = $search_use_regexp ? $searchtext : quotemeta $searchtext; + if ($search_use_regexp) { + $search_regexp = $searchtext; + if (!eval { qr/$search_regexp/; 1; }) { + (my $error = $@) =~ s/ at \S+ line \d+.*\n?//; + die_error(400, "Invalid search regexp '$search_regexp'", + esc_html($error)); + } + } else { + $search_regexp = quotemeta $searchtext; + } } } @@ -1715,6 +1724,88 @@ sub chop_and_escape_str { } } +# Highlight selected fragments of string, using given CSS class, +# and escape HTML. It is assumed that fragments do not overlap. +# Regions are passed as list of pairs (array references). +# +# Example: esc_html_hl_regions("foobar", "mark", [ 0, 3 ]) returns +# '<span class="mark">foo</span>bar' +sub esc_html_hl_regions { + my ($str, $css_class, @sel) = @_; + return esc_html($str) unless @sel; + + my $out = ''; + my $pos = 0; + + for my $s (@sel) { + $out .= esc_html(substr($str, $pos, $s->[0] - $pos)) + if ($s->[0] - $pos > 0); + $out .= $cgi->span({-class => $css_class}, + esc_html(substr($str, $s->[0], $s->[1] - $s->[0]))); + + $pos = $s->[1]; + } + $out .= esc_html(substr($str, $pos)) + if ($pos < length($str)); + + return $out; +} + +# return positions of beginning and end of each match +sub matchpos_list { + my ($str, $regexp) = @_; + return unless (defined $str && defined $regexp); + + my @matches; + while ($str =~ /$regexp/g) { + push @matches, [$-[0], $+[0]]; + } + return @matches; +} + +# highlight match (if any), and escape HTML +sub esc_html_match_hl { + my ($str, $regexp) = @_; + return esc_html($str) unless defined $regexp; + + my @matches = matchpos_list($str, $regexp); + return esc_html($str) unless @matches; + + return esc_html_hl_regions($str, 'match', @matches); +} + + +# highlight match (if any) of shortened string, and escape HTML +sub esc_html_match_hl_chopped { + my ($str, $chopped, $regexp) = @_; + return esc_html_match_hl($str, $regexp) unless defined $chopped; + + my @matches = matchpos_list($str, $regexp); + return esc_html($chopped) unless @matches; + + # filter matches so that we mark chopped string + my $tail = "... "; # see chop_str + unless ($chopped =~ s/\Q$tail\E$//) { + $tail = ''; + } + my $chop_len = length($chopped); + my $tail_len = length($tail); + my @filtered; + + for my $m (@matches) { + if ($m->[0] > $chop_len) { + push @filtered, [ $chop_len, $chop_len + $tail_len ] if ($tail_len > 0); + last; + } elsif ($m->[1] > $chop_len) { + push @filtered, [ $m->[0], $chop_len + $tail_len ]; + last; + } + push @filtered, $m; + } + + return esc_html_hl_regions($chopped . $tail, 'match', @filtered); +} + ## ---------------------------------------------------------------------- ## functions returning short strings @@ -2775,7 +2866,7 @@ sub git_populate_project_tagcloud { } my $cloud; - my $matched = $cgi->param('by_tag'); + my $matched = $input_params{'ctag'}; if (eval { require HTML::TagCloud; 1; }) { $cloud = HTML::TagCloud->new; foreach my $ctag (sort keys %ctags_lc) { @@ -2982,11 +3073,15 @@ sub filter_forks_from_projects_list { sub search_projects_list { my ($projlist, %opts) = @_; my $tagfilter = $opts{'tagfilter'}; - my $searchtext = $opts{'searchtext'}; + my $search_re = $opts{'search_regexp'}; return @$projlist - unless ($tagfilter || $searchtext); + unless ($tagfilter || $search_re); + # searching projects require filling to be run before it; + fill_project_list_info($projlist, + $tagfilter ? 'ctags' : (), + $search_re ? ('path', 'descr') : ()); my @projects; PROJECT: foreach my $pr (@$projlist) { @@ -2997,10 +3092,10 @@ sub search_projects_list { grep { lc($_) eq lc($tagfilter) } keys %{$pr->{'ctags'}}; } - if ($searchtext) { + if ($search_re) { next unless - $pr->{'path'} =~ /$searchtext/ || - $pr->{'descr_long'} =~ /$searchtext/; + $pr->{'path'} =~ /$search_re/ || + $pr->{'descr_long'} =~ /$search_re/; } push @projects, $pr; @@ -3744,7 +3839,7 @@ sub get_page_title { unless (defined $project) { if (defined $project_filter) { - $title .= " - " . to_utf8($project_filter); + $title .= " - projects in '" . esc_path($project_filter) . "'"; } return $title; } @@ -3906,7 +4001,7 @@ sub print_search_form { -values => ['commit', 'grep', 'author', 'committer', 'pickaxe']) . $cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) . " search:\n", - $cgi->textfield(-name => "s", -value => $searchtext) . "\n" . + $cgi->textfield(-name => "s", -value => $searchtext, -override => 1) . "\n" . "<span title=\"Extended regular expression\">" . $cgi->checkbox(-name => 'sr', -value => 1, -label => 're', -checked => $search_use_regexp) . @@ -5161,7 +5256,7 @@ sub git_patchset_body { # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . sub git_project_search_form { - my ($searchtext, $search_use_regexp); + my ($searchtext, $search_use_regexp) = @_; my $limit = ''; if ($project_filter) { @@ -5188,35 +5283,70 @@ sub git_project_search_form { print "</div>\n"; } -# fills project list info (age, description, owner, category, forks) +# entry for given @keys needs filling if at least one of keys in list +# is not present in %$project_info +sub project_info_needs_filling { + my ($project_info, @keys) = @_; + + # return List::MoreUtils::any { !exists $project_info->{$_} } @keys; + foreach my $key (@keys) { + if (!exists $project_info->{$key}) { + return 1; + } + } + return; +} + +# fills project list info (age, description, owner, category, forks, etc.) # for each project in the list, removing invalid projects from -# returned list +# returned list, or fill only specified info. +# +# Invalid projects are removed from the returned list if and only if you +# ask 'age' or 'age_string' to be filled, because they are the only fields +# that run unconditionally git command that requires repository, and +# therefore do always check if project repository is invalid. +# +# USAGE: +# * fill_project_list_info(\@project_list, 'descr_long', 'ctags') +# ensures that 'descr_long' and 'ctags' fields are filled +# * @project_list = fill_project_list_info(\@project_list) +# ensures that all fields are filled (and invalid projects removed) +# # NOTE: modifies $projlist, but does not remove entries from it sub fill_project_list_info { - my $projlist = shift; + my ($projlist, @wanted_keys) = @_; my @projects; + my $filter_set = sub { return @_; }; + if (@wanted_keys) { + my %wanted_keys = map { $_ => 1 } @wanted_keys; + $filter_set = sub { return grep { $wanted_keys{$_} } @_; }; + } my $show_ctags = gitweb_check_feature('ctags'); PROJECT: foreach my $pr (@$projlist) { - my (@activity) = git_get_last_activity($pr->{'path'}); - unless (@activity) { - next PROJECT; + if (project_info_needs_filling($pr, $filter_set->('age', 'age_string'))) { + my (@activity) = git_get_last_activity($pr->{'path'}); + unless (@activity) { + next PROJECT; + } + ($pr->{'age'}, $pr->{'age_string'}) = @activity; } - ($pr->{'age'}, $pr->{'age_string'}) = @activity; - if (!defined $pr->{'descr'}) { + if (project_info_needs_filling($pr, $filter_set->('descr', 'descr_long'))) { my $descr = git_get_project_description($pr->{'path'}) || ""; $descr = to_utf8($descr); $pr->{'descr_long'} = $descr; $pr->{'descr'} = chop_str($descr, $projects_list_description_width, 5); } - if (!defined $pr->{'owner'}) { + if (project_info_needs_filling($pr, $filter_set->('owner'))) { $pr->{'owner'} = git_get_project_owner("$pr->{'path'}") || ""; } - if ($show_ctags) { + if ($show_ctags && + project_info_needs_filling($pr, $filter_set->('ctags'))) { $pr->{'ctags'} = git_get_project_ctags($pr->{'path'}); } - if ($projects_list_group_categories && !defined $pr->{'category'}) { + if ($projects_list_group_categories && + project_info_needs_filling($pr, $filter_set->('category'))) { my $cat = git_get_project_category($pr->{'path'}) || $project_list_default_category; $pr->{'category'} = to_utf8($cat); @@ -5320,10 +5450,17 @@ sub git_project_list_rows { print "</td>\n"; } print "<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"), - -class => "list"}, esc_html($pr->{'path'})) . "</td>\n" . + -class => "list"}, + esc_html_match_hl($pr->{'path'}, $search_regexp)) . + "</td>\n" . "<td>" . $cgi->a({-href => href(project=>$pr->{'path'}, action=>"summary"), - -class => "list", -title => $pr->{'descr_long'}}, - esc_html($pr->{'descr'})) . "</td>\n" . + -class => "list", + -title => $pr->{'descr_long'}}, + $search_regexp + ? esc_html_match_hl_chopped($pr->{'descr_long'}, + $pr->{'descr'}, $search_regexp) + : esc_html($pr->{'descr'})) . + "</td>\n" . "<td><i>" . chop_and_escape_str($pr->{'owner'}, 15) . "</i></td>\n"; print "<td class=\"". age_class($pr->{'age'}) . "\">" . (defined $pr->{'age_string'} ? $pr->{'age_string'} : "No commits") . "</td>\n" . @@ -5345,19 +5482,20 @@ sub git_project_list_body { my $check_forks = gitweb_check_feature('forks'); my $show_ctags = gitweb_check_feature('ctags'); - my $tagfilter = $show_ctags ? $cgi->param('by_tag') : undef; + my $tagfilter = $show_ctags ? $input_params{'ctag'} : undef; $check_forks = undef - if ($tagfilter || $searchtext); + if ($tagfilter || $search_regexp); # filtering out forks before filling info allows to do less work @projects = filter_forks_from_projects_list(\@projects) if ($check_forks); - @projects = fill_project_list_info(\@projects); - # searching projects require filling to be run before it + # search_projects_list pre-fills required info @projects = search_projects_list(\@projects, - 'searchtext' => $searchtext, + 'search_regexp' => $search_regexp, 'tagfilter' => $tagfilter) - if ($tagfilter || $searchtext); + if ($tagfilter || $search_regexp); + # fill the rest + @projects = fill_project_list_info(\@projects); $order ||= $default_projects_order; $from = 0 unless defined $from; @@ -5633,7 +5771,7 @@ sub git_tags_body { sub git_heads_body { # uses global variable $project - my ($headlist, $head, $from, $to, $extra) = @_; + my ($headlist, $head_at, $from, $to, $extra) = @_; $from = 0 unless defined $from; $to = $#{$headlist} if (!defined $to || $#{$headlist} < $to); @@ -5642,7 +5780,7 @@ sub git_heads_body { for (my $i = $from; $i <= $to; $i++) { my $entry = $headlist->[$i]; my %ref = %$entry; - my $curr = $ref{'id'} eq $head; + my $curr = defined $head_at && $ref{'id'} eq $head_at; if ($alternate) { print "<tr class=\"dark\">\n"; } else { @@ -5915,9 +6053,10 @@ sub git_search_files { my $alternate = 1; my $matches = 0; my $lastfile = ''; + my $file_href; while (my $line = <$fd>) { chomp $line; - my ($file, $file_href, $lno, $ltext, $binary); + my ($file, $lno, $ltext, $binary); last if ($matches++ > 1000); if ($line =~ /^Binary file (.+) matches$/) { $file = $1; @@ -6261,7 +6400,7 @@ sub git_tag { sub git_blame_common { my $format = shift || 'porcelain'; - if ($format eq 'porcelain' && $cgi->param('js')) { + if ($format eq 'porcelain' && $input_params{'javascript'}) { $format = 'incremental'; $action = 'blame_incremental'; # for page title etc } @@ -79,7 +79,7 @@ static void compile_pcre_regexp(struct grep_pat *p, const struct grep_opt *opt) { const char *error; int erroffset; - int options = 0; + int options = PCRE_MULTILINE; if (opt->ignore_case) options |= PCRE_CASELESS; @@ -168,15 +168,10 @@ static void compile_regexp(struct grep_pat *p, struct grep_opt *opt) p->fixed = 0; if (p->fixed) { - if (opt->regflags & REG_ICASE || p->ignore_case) { - static char trans[256]; - int i; - for (i = 0; i < 256; i++) - trans[i] = tolower(i); - p->kws = kwsalloc(trans); - } else { + if (opt->regflags & REG_ICASE || p->ignore_case) + p->kws = kwsalloc(tolower_trans_tbl); + else p->kws = kwsalloc(NULL); - } kwsincr(p->kws, p->pattern, p->patternlen); kwsprep(p->kws); return; @@ -807,38 +802,43 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol, } #ifndef NO_PTHREADS +int grep_use_locks; + /* * This lock protects access to the gitattributes machinery, which is * not thread-safe. */ pthread_mutex_t grep_attr_mutex; -static inline void grep_attr_lock(struct grep_opt *opt) +static inline void grep_attr_lock(void) { - if (opt->use_threads) + if (grep_use_locks) pthread_mutex_lock(&grep_attr_mutex); } -static inline void grep_attr_unlock(struct grep_opt *opt) +static inline void grep_attr_unlock(void) { - if (opt->use_threads) + if (grep_use_locks) pthread_mutex_unlock(&grep_attr_mutex); } + +/* + * Same as git_attr_mutex, but protecting the thread-unsafe object db access. + */ +pthread_mutex_t grep_read_mutex; + #else -#define grep_attr_lock(opt) -#define grep_attr_unlock(opt) +#define grep_attr_lock() +#define grep_attr_unlock() #endif -static int match_funcname(struct grep_opt *opt, const char *name, char *bol, char *eol) +static int match_funcname(struct grep_opt *opt, struct grep_source *gs, char *bol, char *eol) { xdemitconf_t *xecfg = opt->priv; if (xecfg && !xecfg->find_func) { - struct userdiff_driver *drv; - grep_attr_lock(opt); - drv = userdiff_find_by_path(name); - grep_attr_unlock(opt); - if (drv && drv->funcname.pattern) { - const struct userdiff_funcname *pe = &drv->funcname; + grep_source_load_driver(gs); + if (gs->driver->funcname.pattern) { + const struct userdiff_funcname *pe = &gs->driver->funcname; xdiff_set_find_func(xecfg, pe->pattern, pe->cflags); } else { xecfg = opt->priv = NULL; @@ -858,33 +858,33 @@ static int match_funcname(struct grep_opt *opt, const char *name, char *bol, cha return 0; } -static void show_funcname_line(struct grep_opt *opt, const char *name, - char *buf, char *bol, unsigned lno) +static void show_funcname_line(struct grep_opt *opt, struct grep_source *gs, + char *bol, unsigned lno) { - while (bol > buf) { + while (bol > gs->buf) { char *eol = --bol; - while (bol > buf && bol[-1] != '\n') + while (bol > gs->buf && bol[-1] != '\n') bol--; lno--; if (lno <= opt->last_shown) break; - if (match_funcname(opt, name, bol, eol)) { - show_line(opt, bol, eol, name, lno, '='); + if (match_funcname(opt, gs, bol, eol)) { + show_line(opt, bol, eol, gs->name, lno, '='); break; } } } -static void show_pre_context(struct grep_opt *opt, const char *name, char *buf, +static void show_pre_context(struct grep_opt *opt, struct grep_source *gs, char *bol, char *end, unsigned lno) { unsigned cur = lno, from = 1, funcname_lno = 0; int funcname_needed = !!opt->funcname; - if (opt->funcbody && !match_funcname(opt, name, bol, end)) + if (opt->funcbody && !match_funcname(opt, gs, bol, end)) funcname_needed = 2; if (opt->pre_context < lno) @@ -893,14 +893,14 @@ static void show_pre_context(struct grep_opt *opt, const char *name, char *buf, from = opt->last_shown + 1; /* Rewind. */ - while (bol > buf && + while (bol > gs->buf && cur > (funcname_needed == 2 ? opt->last_shown + 1 : from)) { char *eol = --bol; - while (bol > buf && bol[-1] != '\n') + while (bol > gs->buf && bol[-1] != '\n') bol--; cur--; - if (funcname_needed && match_funcname(opt, name, bol, eol)) { + if (funcname_needed && match_funcname(opt, gs, bol, eol)) { funcname_lno = cur; funcname_needed = 0; } @@ -908,7 +908,7 @@ static void show_pre_context(struct grep_opt *opt, const char *name, char *buf, /* We need to look even further back to find a function signature. */ if (opt->funcname && funcname_needed) - show_funcname_line(opt, name, buf, bol, cur); + show_funcname_line(opt, gs, bol, cur); /* Back forward. */ while (cur < lno) { @@ -916,7 +916,7 @@ static void show_pre_context(struct grep_opt *opt, const char *name, char *buf, while (*eol != '\n') eol++; - show_line(opt, bol, eol, name, cur, sign); + show_line(opt, bol, eol, gs->name, cur, sign); bol = eol + 1; cur++; } @@ -983,11 +983,10 @@ static void std_output(struct grep_opt *opt, const void *buf, size_t size) fwrite(buf, size, 1, stdout); } -static int grep_buffer_1(struct grep_opt *opt, const char *name, - char *buf, unsigned long size, int collect_hits) +static int grep_source_1(struct grep_opt *opt, struct grep_source *gs, int collect_hits) { - char *bol = buf; - unsigned long left = size; + char *bol; + unsigned long left; unsigned lno = 1; unsigned last_hit = 0; int binary_match_only = 0; @@ -1017,11 +1016,11 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, switch (opt->binary) { case GREP_BINARY_DEFAULT: - if (buffer_is_binary(buf, size)) + if (grep_source_is_binary(gs)) binary_match_only = 1; break; case GREP_BINARY_NOMATCH: - if (buffer_is_binary(buf, size)) + if (grep_source_is_binary(gs)) return 0; /* Assume unmatch */ break; case GREP_BINARY_TEXT: @@ -1035,6 +1034,11 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, try_lookahead = should_lookahead(opt); + if (grep_source_load(gs) < 0) + return 0; + + bol = gs->buf; + left = gs->size; while (left) { char *eol, ch; int hit; @@ -1083,14 +1087,14 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, if (opt->status_only) return 1; if (opt->name_only) { - show_name(opt, name); + show_name(opt, gs->name); return 1; } if (opt->count) goto next_line; if (binary_match_only) { opt->output(opt, "Binary file ", 12); - output_color(opt, name, strlen(name), + output_color(opt, gs->name, strlen(gs->name), opt->color_filename); opt->output(opt, " matches\n", 9); return 1; @@ -1099,23 +1103,23 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, * pre-context lines, we would need to show them. */ if (opt->pre_context || opt->funcbody) - show_pre_context(opt, name, buf, bol, eol, lno); + show_pre_context(opt, gs, bol, eol, lno); else if (opt->funcname) - show_funcname_line(opt, name, buf, bol, lno); - show_line(opt, bol, eol, name, lno, ':'); + show_funcname_line(opt, gs, bol, lno); + show_line(opt, bol, eol, gs->name, lno, ':'); last_hit = lno; if (opt->funcbody) show_function = 1; goto next_line; } - if (show_function && match_funcname(opt, name, bol, eol)) + if (show_function && match_funcname(opt, gs, bol, eol)) show_function = 0; if (show_function || (last_hit && lno <= last_hit + opt->post_context)) { /* If the last hit is within the post context, * we need to show this line. */ - show_line(opt, bol, eol, name, lno, '-'); + show_line(opt, bol, eol, gs->name, lno, '-'); } next_line: @@ -1133,7 +1137,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, return 0; if (opt->unmatch_name_only) { /* We did not see any hit, so we want to show this */ - show_name(opt, name); + show_name(opt, gs->name); return 1; } @@ -1147,7 +1151,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, */ if (opt->count && count) { char buf[32]; - output_color(opt, name, strlen(name), opt->color_filename); + output_color(opt, gs->name, strlen(gs->name), opt->color_filename); output_sep(opt, ':'); snprintf(buf, sizeof(buf), "%u\n", count); opt->output(opt, buf, strlen(buf)); @@ -1182,23 +1186,174 @@ static int chk_hit_marker(struct grep_expr *x) } } -int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long size) +int grep_source(struct grep_opt *opt, struct grep_source *gs) { /* * we do not have to do the two-pass grep when we do not check * buffer-wide "all-match". */ if (!opt->all_match) - return grep_buffer_1(opt, name, buf, size, 0); + return grep_source_1(opt, gs, 0); /* Otherwise the toplevel "or" terms hit a bit differently. * We first clear hit markers from them. */ clr_hit_marker(opt->pattern_expression); - grep_buffer_1(opt, name, buf, size, 1); + grep_source_1(opt, gs, 1); if (!chk_hit_marker(opt->pattern_expression)) return 0; - return grep_buffer_1(opt, name, buf, size, 0); + return grep_source_1(opt, gs, 0); +} + +int grep_buffer(struct grep_opt *opt, char *buf, unsigned long size) +{ + struct grep_source gs; + int r; + + grep_source_init(&gs, GREP_SOURCE_BUF, NULL, NULL); + gs.buf = buf; + gs.size = size; + + r = grep_source(opt, &gs); + + grep_source_clear(&gs); + return r; +} + +void grep_source_init(struct grep_source *gs, enum grep_source_type type, + const char *name, const void *identifier) +{ + gs->type = type; + gs->name = name ? xstrdup(name) : NULL; + gs->buf = NULL; + gs->size = 0; + gs->driver = NULL; + + switch (type) { + case GREP_SOURCE_FILE: + gs->identifier = xstrdup(identifier); + break; + case GREP_SOURCE_SHA1: + gs->identifier = xmalloc(20); + memcpy(gs->identifier, identifier, 20); + break; + case GREP_SOURCE_BUF: + gs->identifier = NULL; + } +} + +void grep_source_clear(struct grep_source *gs) +{ + free(gs->name); + gs->name = NULL; + free(gs->identifier); + gs->identifier = NULL; + grep_source_clear_data(gs); +} + +void grep_source_clear_data(struct grep_source *gs) +{ + switch (gs->type) { + case GREP_SOURCE_FILE: + case GREP_SOURCE_SHA1: + free(gs->buf); + gs->buf = NULL; + gs->size = 0; + break; + case GREP_SOURCE_BUF: + /* leave user-provided buf intact */ + break; + } +} + +static int grep_source_load_sha1(struct grep_source *gs) +{ + enum object_type type; + + grep_read_lock(); + gs->buf = read_sha1_file(gs->identifier, &type, &gs->size); + grep_read_unlock(); + + if (!gs->buf) + return error(_("'%s': unable to read %s"), + gs->name, + sha1_to_hex(gs->identifier)); + return 0; +} + +static int grep_source_load_file(struct grep_source *gs) +{ + const char *filename = gs->identifier; + struct stat st; + char *data; + size_t size; + int i; + + if (lstat(filename, &st) < 0) { + err_ret: + if (errno != ENOENT) + error(_("'%s': %s"), filename, strerror(errno)); + return -1; + } + if (!S_ISREG(st.st_mode)) + return -1; + size = xsize_t(st.st_size); + i = open(filename, O_RDONLY); + if (i < 0) + goto err_ret; + data = xmalloc(size + 1); + if (st.st_size != read_in_full(i, data, size)) { + error(_("'%s': short read %s"), filename, strerror(errno)); + close(i); + free(data); + return -1; + } + close(i); + data[size] = 0; + + gs->buf = data; + gs->size = size; + return 0; +} + +int grep_source_load(struct grep_source *gs) +{ + if (gs->buf) + return 0; + + switch (gs->type) { + case GREP_SOURCE_FILE: + return grep_source_load_file(gs); + case GREP_SOURCE_SHA1: + return grep_source_load_sha1(gs); + case GREP_SOURCE_BUF: + return gs->buf ? 0 : -1; + } + die("BUG: invalid grep_source type"); +} + +void grep_source_load_driver(struct grep_source *gs) +{ + if (gs->driver) + return; + + grep_attr_lock(); + gs->driver = userdiff_find_by_path(gs->name); + if (!gs->driver) + gs->driver = userdiff_find_by_name("default"); + grep_attr_unlock(); +} + +int grep_source_is_binary(struct grep_source *gs) +{ + grep_source_load_driver(gs); + if (gs->driver->binary != -1) + return gs->driver->binary; + + if (!grep_source_load(gs)) + return buffer_is_binary(gs->buf, gs->size); + + return 0; } @@ -9,6 +9,7 @@ typedef int pcre_extra; #endif #include "kwset.h" #include "thread-utils.h" +#include "userdiff.h" enum grep_pat_token { GREP_PATTERN, @@ -116,7 +117,6 @@ struct grep_opt { int show_hunk_mark; int file_break; int heading; - int use_threads; void *priv; void (*output)(struct grep_opt *opt, const void *data, size_t size); @@ -128,7 +128,33 @@ extern void append_grep_pattern(struct grep_opt *opt, const char *pat, const cha extern void append_header_grep_pattern(struct grep_opt *, enum grep_header_field, const char *); extern void compile_grep_patterns(struct grep_opt *opt); extern void free_grep_patterns(struct grep_opt *opt); -extern int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long size); +extern int grep_buffer(struct grep_opt *opt, char *buf, unsigned long size); + +struct grep_source { + char *name; + + enum grep_source_type { + GREP_SOURCE_SHA1, + GREP_SOURCE_FILE, + GREP_SOURCE_BUF, + } type; + void *identifier; + + char *buf; + unsigned long size; + + struct userdiff_driver *driver; +}; + +void grep_source_init(struct grep_source *gs, enum grep_source_type type, + const char *name, const void *identifier); +int grep_source_load(struct grep_source *gs); +void grep_source_clear_data(struct grep_source *gs); +void grep_source_clear(struct grep_source *gs); +void grep_source_load_driver(struct grep_source *gs); +int grep_source_is_binary(struct grep_source *gs); + +int grep_source(struct grep_opt *opt, struct grep_source *gs); extern struct grep_opt *grep_opt_dup(const struct grep_opt *opt); extern int grep_threads_ok(const struct grep_opt *opt); @@ -138,7 +164,25 @@ extern int grep_threads_ok(const struct grep_opt *opt); * Mutex used around access to the attributes machinery if * opt->use_threads. Must be initialized/destroyed by callers! */ +extern int grep_use_locks; extern pthread_mutex_t grep_attr_mutex; +extern pthread_mutex_t grep_read_mutex; + +static inline void grep_read_lock(void) +{ + if (grep_use_locks) + pthread_mutex_lock(&grep_read_mutex); +} + +static inline void grep_read_unlock(void) +{ + if (grep_use_locks) + pthread_mutex_unlock(&grep_read_mutex); +} + +#else +#define grep_read_lock() +#define grep_read_unlock() #endif #endif @@ -5,28 +5,6 @@ #include "help.h" #include "common-cmds.h" -/* most GUI terminals set COLUMNS (although some don't export it) */ -static int term_columns(void) -{ - char *col_string = getenv("COLUMNS"); - int n_cols; - - if (col_string && (n_cols = atoi(col_string)) > 0) - return n_cols; - -#ifdef TIOCGWINSZ - { - struct winsize ws; - if (!ioctl(1, TIOCGWINSZ, &ws)) { - if (ws.ws_col) - return ws.ws_col; - } - } -#endif - - return 80; -} - void add_cmdname(struct cmdnames *cmds, const char *name, int len) { struct cmdname *ent = xmalloc(sizeof(*ent) + len + 1); @@ -295,8 +295,10 @@ static CURL *get_curl_handle(void) if (curl_ftp_no_epsv) curl_easy_setopt(result, CURLOPT_FTP_USE_EPSV, 0); - if (curl_http_proxy) + if (curl_http_proxy) { curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy); + curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY); + } return result; } @@ -190,27 +190,27 @@ void clear_mailmap(struct string_list *map) int map_user(struct string_list *map, char *email, int maxlen_email, char *name, int maxlen_name) { - char *p; + char *end_of_email; struct string_list_item *item; struct mailmap_entry *me; char buf[1024], *mailbuf; int i; /* figure out space requirement for email */ - p = strchr(email, '>'); - if (!p) { + end_of_email = strchr(email, '>'); + if (!end_of_email) { /* email passed in might not be wrapped in <>, but end with a \0 */ - p = memchr(email, '\0', maxlen_email); - if (!p) + end_of_email = memchr(email, '\0', maxlen_email); + if (!end_of_email) return 0; } - if (p - email + 1 < sizeof(buf)) + if (end_of_email - email + 1 < sizeof(buf)) mailbuf = buf; else - mailbuf = xmalloc(p - email + 1); + mailbuf = xmalloc(end_of_email - email + 1); /* downcase the email address */ - for (i = 0; i < p - email; i++) + for (i = 0; i < end_of_email - email; i++) mailbuf[i] = tolower(email[i]); mailbuf[i] = 0; @@ -236,6 +236,8 @@ int map_user(struct string_list *map, } if (maxlen_email && mi->email) strlcpy(email, mi->email, maxlen_email); + else + *end_of_email = '\0'; if (maxlen_name && mi->name) strlcpy(name, mi->name, maxlen_name); debug_mm("map_user: to '%s' <%s>\n", name, mi->email ? mi->email : ""); diff --git a/merge-recursive.c b/merge-recursive.c index d83cd6c662..6479a60cd1 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -264,7 +264,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, 0) < 0) + active_cache, active_nr, 0) < 0) die("error building trees"); result = lookup_tree(active_cache_tree->sha1); diff --git a/mergetools/deltawalker b/mergetools/deltawalker new file mode 100644 index 0000000000..b3c71b6236 --- /dev/null +++ b/mergetools/deltawalker @@ -0,0 +1,21 @@ +diff_cmd () { + "$merge_tool_path" "$LOCAL" "$REMOTE" >/dev/null 2>&1 +} + +merge_cmd () { + # Adding $(pwd)/ in front of $MERGED should not be necessary. + # However without it, DeltaWalker (at least v1.9.8 on Windows) + # crashes with a JRE exception. The DeltaWalker user manual, + # shows $(pwd)/ whenever the '-merged' options is given. + # Adding it here seems to work around the problem. + if $base_present + then + "$merge_tool_path" "$LOCAL" "$REMOTE" "$BASE" -merged="$(pwd)/$MERGED" + else + "$merge_tool_path" "$LOCAL" "$REMOTE" -merged="$(pwd)/$MERGED" + fi >/dev/null 2>&1 +} + +translate_merge_tool_path() { + echo DeltaWalker +} diff --git a/mergetools/meld b/mergetools/meld index eaa115ccb7..cb672a5519 100644 --- a/mergetools/meld +++ b/mergetools/meld @@ -23,7 +23,7 @@ check_meld_for_output_version () { meld_path="$(git config mergetool.meld.path)" meld_path="${meld_path:-meld}" - if "$meld_path" --output /dev/null --help >/dev/null 2>&1 + if "$meld_path" --help 2>&1 | grep -e --output >/dev/null then meld_has_output_option=true else @@ -76,6 +76,12 @@ void setup_pager(void) if (!pager) return; + /* + * force computing the width of the terminal before we redirect + * the standard output to the pager. + */ + (void) term_columns(); + setenv("GIT_PAGER_IN_USE", "true", 1); /* spawn the pager */ @@ -110,3 +116,46 @@ int pager_in_use(void) env = getenv("GIT_PAGER_IN_USE"); return env ? git_config_bool("GIT_PAGER_IN_USE", env) : 0; } + +/* + * Return cached value (if set) or $COLUMNS environment variable (if + * set and positive) or ioctl(1, TIOCGWINSZ).ws_col (if positive), + * and default to 80 if all else fails. + */ +int term_columns(void) +{ + static int term_columns_at_startup; + + char *col_string; + int n_cols; + + if (term_columns_at_startup) + return term_columns_at_startup; + + term_columns_at_startup = 80; + + col_string = getenv("COLUMNS"); + if (col_string && (n_cols = atoi(col_string)) > 0) + term_columns_at_startup = n_cols; +#ifdef TIOCGWINSZ + else { + struct winsize ws; + if (!ioctl(1, TIOCGWINSZ, &ws) && ws.ws_col) + term_columns_at_startup = ws.ws_col; + } +#endif + + return term_columns_at_startup; +} + +/* + * How many columns do we need to show this number in decimal? + */ +int decimal_width(int number) +{ + int i, width; + + for (width = 1, i = 10; i <= number; width++) + i *= 10; + return width; +} diff --git a/parse-options.c b/parse-options.c index f0098eb8ea..850cfa78c9 100644 --- a/parse-options.c +++ b/parse-options.c @@ -193,13 +193,14 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg, arg_end = arg + strlen(arg); for (; options->type != OPTION_END; options++) { - const char *rest; - int flags = 0; + const char *rest, *long_name = options->long_name; + int flags = 0, opt_flags = 0; - if (!options->long_name) + if (!long_name) continue; - rest = skip_prefix(arg, options->long_name); +again: + rest = skip_prefix(arg, long_name); if (options->type == OPTION_ARGUMENT) { if (!rest) continue; @@ -212,7 +213,7 @@ static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg, } if (!rest) { /* abbreviated? */ - if (!strncmp(options->long_name, arg, arg_end - arg)) { + if (!strncmp(long_name, arg, arg_end - arg)) { is_abbreviated: if (abbrev_option) { /* @@ -227,7 +228,7 @@ is_abbreviated: if (!(flags & OPT_UNSET) && *arg_end) p->opt = arg_end + 1; abbrev_option = options; - abbrev_flags = flags; + abbrev_flags = flags ^ opt_flags; continue; } /* negation allowed? */ @@ -239,12 +240,18 @@ is_abbreviated: goto is_abbreviated; } /* negated? */ - if (strncmp(arg, "no-", 3)) + if (prefixcmp(arg, "no-")) { + if (!prefixcmp(long_name, "no-")) { + long_name += 3; + opt_flags |= OPT_UNSET; + goto again; + } continue; + } flags |= OPT_UNSET; - rest = skip_prefix(arg + 3, options->long_name); + rest = skip_prefix(arg + 3, long_name); /* abbreviated and negated? */ - if (!rest && !prefixcmp(options->long_name, arg + 3)) + if (!rest && !prefixcmp(long_name, arg + 3)) goto is_abbreviated; if (!rest) continue; @@ -254,7 +261,7 @@ is_abbreviated: continue; p->opt = rest + 1; } - return get_value(p, options, flags); + return get_value(p, options, flags ^ opt_flags); } if (ambiguous_option) @@ -386,6 +393,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, case -1: return parse_options_usage(ctx, usagestr, options, 1); case -2: + if (ctx->opt) + check_typos(arg + 1, options); goto unknown; } if (ctx->opt) @@ -526,7 +535,7 @@ static int usage_with_options_internal(struct parse_opt_ctx_t *ctx, continue; pos = fprintf(outfile, " "); - if (opts->short_name && !(opts->flags & PARSE_OPT_NEGHELP)) { + if (opts->short_name) { if (opts->flags & PARSE_OPT_NODASH) pos += fprintf(outfile, "%c", opts->short_name); else @@ -535,9 +544,7 @@ static int usage_with_options_internal(struct parse_opt_ctx_t *ctx, if (opts->long_name && opts->short_name) pos += fprintf(outfile, ", "); if (opts->long_name) - pos += fprintf(outfile, "--%s%s", - (opts->flags & PARSE_OPT_NEGHELP) ? "no-" : "", - opts->long_name); + pos += fprintf(outfile, "--%s", opts->long_name); if (opts->type == OPTION_NUMBER) pos += fprintf(outfile, "-NUM"); diff --git a/parse-options.h b/parse-options.h index 2e811dc7da..def9ced739 100644 --- a/parse-options.h +++ b/parse-options.h @@ -40,7 +40,6 @@ enum parse_opt_option_flags { PARSE_OPT_LASTARG_DEFAULT = 16, PARSE_OPT_NODASH = 32, PARSE_OPT_LITERAL_ARGHELP = 64, - PARSE_OPT_NEGHELP = 128, PARSE_OPT_SHELL_EVAL = 256 }; @@ -90,9 +89,6 @@ typedef int parse_opt_ll_cb(struct parse_opt_ctx_t *ctx, * PARSE_OPT_LITERAL_ARGHELP: says that argh shouldn't be enclosed in brackets * (i.e. '<argh>') in the help message. * Useful for options with multiple parameters. - * PARSE_OPT_NEGHELP: says that the long option should always be shown with - * the --no prefix in the usage message. Sometimes - * useful for users of OPTION_NEGBIT. * * `callback`:: * pointer to the callback to use for OPTION_CALLBACK or @@ -293,7 +293,7 @@ const char *enter_repo(const char *path, int strict) if (!strict) { static const char *suffix[] = { - ".git/.git", "/.git", ".git", "", NULL, + "/.git", "", ".git/.git", ".git", NULL, }; const char *gitfile; int len = strlen(path); @@ -324,8 +324,11 @@ const char *enter_repo(const char *path, int strict) return NULL; len = strlen(used_path); for (i = 0; suffix[i]; i++) { + struct stat st; strcpy(used_path + len, suffix[i]); - if (!access(used_path, F_OK)) { + if (!stat(used_path, &st) && + (S_ISREG(st.st_mode) || + (S_ISDIR(st.st_mode) && is_git_directory(used_path)))) { strcat(validated_path, suffix[i]); break; } diff --git a/perl/Git/I18N.pm b/perl/Git/I18N.pm index 07597dcb93..40dd897191 100644 --- a/perl/Git/I18N.pm +++ b/perl/Git/I18N.pm @@ -2,7 +2,16 @@ package Git::I18N; use 5.008; use strict; use warnings; -use Exporter 'import'; +BEGIN { + require Exporter; + if ($] < 5.008003) { + *import = \&Exporter::import; + } else { + # Exporter 5.57 which supports this invocation was + # released with perl 5.8.3 + Exporter->import('import'); + } +} our @EXPORT = qw(__); our @EXPORT_OK = @EXPORT; diff --git a/perl/Makefile b/perl/Makefile index b2977cd0bc..3e21766d8f 100644 --- a/perl/Makefile +++ b/perl/Makefile @@ -23,15 +23,18 @@ clean: ifdef NO_PERL_MAKEMAKER instdir_SQ = $(subst ','\'',$(prefix)/lib) $(makfile): ../GIT-CFLAGS Makefile - echo all: private-Error.pm Git.pm > $@ - echo ' mkdir -p blib/lib' >> $@ + echo all: private-Error.pm Git.pm Git/I18N.pm > $@ + echo ' mkdir -p blib/lib/Git' >> $@ echo ' $(RM) blib/lib/Git.pm; cp Git.pm blib/lib/' >> $@ + echo ' $(RM) blib/lib/Git/I18N.pm; cp Git/I18N.pm blib/lib/Git/' >> $@ echo ' $(RM) blib/lib/Error.pm' >> $@ '$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \ echo ' cp private-Error.pm blib/lib/Error.pm' >> $@ echo install: >> $@ echo ' mkdir -p "$$(DESTDIR)$(instdir_SQ)"' >> $@ + echo ' mkdir -p "$$(DESTDIR)$(instdir_SQ)/Git"' >> $@ echo ' $(RM) "$$(DESTDIR)$(instdir_SQ)/Git.pm"; cp Git.pm "$$(DESTDIR)$(instdir_SQ)"' >> $@ + echo ' $(RM) "$$(DESTDIR)$(instdir_SQ)/Git/I18N.pm"; cp Git/I18N.pm "$$(DESTDIR)$(instdir_SQ)/Git"' >> $@ echo ' $(RM) "$$(DESTDIR)$(instdir_SQ)/Error.pm"' >> $@ '$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \ echo ' cp private-Error.pm "$$(DESTDIR)$(instdir_SQ)/Error.pm"' >> $@ diff --git a/po/.gitignore b/po/.gitignore index 4caa631ff0..796b96d1c4 100644 --- a/po/.gitignore +++ b/po/.gitignore @@ -1,2 +1 @@ -/git.pot /build @@ -1,33 +1,79 @@ Core GIT Translations ===================== -This directory holds the translations for the core of Git. This -document describes how to add to and maintain these translations, and -how to mark source strings for translation. - +This directory holds the translations for the core of Git. This document +describes how you can contribute to the effort of enhancing the language +coverage and maintaining the translation. + +The localization (l10n) coordinator, Jiang Xin <worldhello.net@gmail.com>, +coordinates our localization effort in the l10 coordinator repository: + + https://github.com/git-l10n/git-po/ + +As a contributor for a language XX, you should first check TEAMS file in +this directory to see whether a dedicated repository for your language XX +exists. Fork the dedicated repository and start to work if it exists. + +If you are the first contributor for the language XX, please fork this +repository, prepare and/or update the translated message file po/XX.po +(described later), and ask the l10n coordinator to pull your work. + +If there are multiple contributors for the same language, please first +coordinate among yourselves and nominate the team leader for your +language, so that the l10n coordinator only needs to interact with one +person per language. + +The overall data-flow looks like this: + + +-------------------+ +------------------+ + | Git source code | ---(1)---> | L10n coordinator | + | repository | <---(4)--- | repository | + +-------------------+ +------------------+ + | ^ + (2) (3) + V | + +------------------+ + | Language Team XX | + +------------------+ + + * Translatable strings are marked in the source file. + * L10n coordinator pulls from the source (1) + * L10n coordinator updates the message template po/git.pot + * Language team pulls from L10n coordinator (2) + * Language team updates the message file po/XX.po + * L10n coordinator pulls from Language team (3) + * L10n coordinator asks the result to be pulled (4). + + +Maintaining the po/git.pot file +------------------------------- -Generating a .pot file ----------------------- +(This is done by the l10n coordinator). The po/git.pot file contains a message catalog extracted from Git's -sources. You need to generate it to add new translations with -msginit(1), or update existing ones with msgmerge(1). +sources. The l10n coordinator maintains it by adding new translations with +msginit(1), or update existing ones with msgmerge(1). In order to update +the Git sources to extract the messages from, the l10n coordinator is +expected to pull from the main git repository at strategic point in +history (e.g. when a major release and release candidates are tagged), +and then run "make pot" at the top-level directory. -Since the file can be automatically generated it's not checked into -git.git. To generate it do, at the top-level: +Language contributors use this file to prepare translations for their +language, but they are not expected to modify it. - make pot +Initializing a XX.po file +------------------------- -Initializing a .po file ------------------------ +(This is done by the language teams). -To add a new translation first generate git.pot (see above) and then -in the po/ directory do: +If your language XX does not have translated message file po/XX.po yet, +you add a translation for the first time by running: msginit --locale=XX -Where XX is your locale, e.g. "is", "de" or "pt_BR". +in the po/ directory, where XX is the locale, e.g. "de", "is", "pt_BR", +"zh_CN", etc. Then edit the automatically generated copyright info in your new XX.po to be correct, e.g. for Icelandic: @@ -46,21 +92,36 @@ just "Git": perl -pi -e 's/(?<="Project-Id-Version: )PACKAGE VERSION/Git/' XX.po +Once you are done testing the translation (see below), commit the result +and ask the l10n coordinator to pull from you. + + +Updating a XX.po file +--------------------- -Updating a .po file -------------------- +(This is done by the language teams). -If there's an existing *.po file for your language but you need to -update the translation you first need to generate git.pot (see above) -and then in the po/ directory do: +If you are replacing translation strings in an existing XX.po file to +improve the translation, just edit the file. + +If there's an existing XX.po file for your language, but the repository +of the l10n coordinator has newer po/git.pot file, you would need to first +pull from the l10n coordinator (see the beginning of this document for its +URL), and then update the existing translation by running: msgmerge --add-location --backup=off -U XX.po git.pot -Where XX.po is the file you want to update. +in the po/ directory, where XX.po is the file you want to update. + +Once you are done testing the translation (see below), commit the result +and ask the l10n coordinator to pull from you. + Testing your changes -------------------- +(This is done by the language teams, after creating or updating XX.po file). + Before you submit your changes go back to the top-level and do: make @@ -75,6 +136,8 @@ with a newline or not. Marking strings for translation ------------------------------- +(This is done by the core developers). + Before strings can be translated they first have to be marked for translation. diff --git a/po/TEAMS b/po/TEAMS new file mode 100644 index 0000000000..0184493f21 --- /dev/null +++ b/po/TEAMS @@ -0,0 +1,18 @@ +Core Git translation language teams +(please keep the list sorted alphabetically on language field) + +Language: is (Icelandic) +Leader: Ævar Arnfjörð Bjarmason <avarab@gmail.com> + +Language: sv (Swedish) +Leader: Peter Krefting <peter@softwolves.pp.se> + +Language: zh_CN (Simplified Chinese) +Repository: https://github.com/gotgit/git-po-zh_CN/ +Leader: Jiang Xin <worldhello.net@gmail.com> +Members: Riku <lu.riku AT gmail.com> + Zhuang Ya <zhuangya AT me.com> + Lian Cheng <rhythm.mail AT gmail.com> + Yichao Yu <yyc1992 AT gmail.com> + ws3389 <willsmith3389 AT gmail.com> + Thynson <lanxingcan AT gmail.com> diff --git a/po/git.pot b/po/git.pot new file mode 100644 index 0000000000..8bdaf3cc34 --- /dev/null +++ b/po/git.pot @@ -0,0 +1,3500 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" +"POT-Creation-Date: 2012-03-08 10:19+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" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#: advice.c:34 +#, c-format +msgid "hint: %.*s\n" +msgstr "" + +#. +#. * Message used both when 'git commit' fails and when +#. * other commands doing a merge do. +#. +#: advice.c:64 +msgid "" +"Fix them up in the work tree,\n" +"and then use 'git add/rm <file>' as\n" +"appropriate to mark resolution and make a commit,\n" +"or use 'git commit -a'." +msgstr "" + +#: commit.c:47 +#, c-format +msgid "could not parse %s" +msgstr "" + +#: commit.c:49 +#, c-format +msgid "%s %s is not a commit!" +msgstr "" + +#: compat/obstack.c:406 compat/obstack.c:408 +msgid "memory exhausted" +msgstr "" + +#: connected.c:39 +msgid "Could not run 'git rev-list'" +msgstr "" + +#: connected.c:48 +#, c-format +msgid "failed write to rev-list: %s" +msgstr "" + +#: connected.c:56 +#, c-format +msgid "failed to close rev-list's stdin: %s" +msgstr "" + +#: diff.c:105 +#, c-format +msgid " Failed to parse dirstat cut-off percentage '%.*s'\n" +msgstr "" + +#: diff.c:110 +#, c-format +msgid " Unknown dirstat parameter '%.*s'\n" +msgstr "" + +#: diff.c:210 +#, c-format +msgid "" +"Found errors in 'diff.dirstat' config variable:\n" +"%s" +msgstr "" + +#: diff.c:1336 +msgid " 0 files changed\n" +msgstr "" + +#: diff.c:1340 +#, c-format +msgid " %d file changed" +msgid_plural " %d files changed" +msgstr[0] "" +msgstr[1] "" + +#: diff.c:1357 +#, c-format +msgid ", %d insertion(+)" +msgid_plural ", %d insertions(+)" +msgstr[0] "" +msgstr[1] "" + +#: diff.c:1368 +#, c-format +msgid ", %d deletion(-)" +msgid_plural ", %d deletions(-)" +msgstr[0] "" +msgstr[1] "" + +#: diff.c:3424 +#, c-format +msgid "" +"Failed to parse --dirstat/-X option parameter:\n" +"%s" +msgstr "" + +#: gpg-interface.c:59 +msgid "could not run gpg." +msgstr "" + +#: gpg-interface.c:71 +msgid "gpg did not accept the data" +msgstr "" + +#: gpg-interface.c:82 +msgid "gpg failed to sign the data" +msgstr "" + +#: grep.c:1280 +#, c-format +msgid "'%s': unable to read %s" +msgstr "" + +#: grep.c:1297 +#, c-format +msgid "'%s': %s" +msgstr "" + +#: grep.c:1308 +#, c-format +msgid "'%s': short read %s" +msgstr "" + +#: help.c:287 +#, 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 "" + +#: remote.c:1607 +#, 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:1613 +#, 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] "" +msgstr[1] "" + +#: remote.c:1621 +#, c-format +msgid "" +"Your branch and '%s' have diverged,\n" +"and have %d and %d different commit each, respectively.\n" +msgid_plural "" +"Your branch and '%s' have diverged,\n" +"and have %d and %d different commits each, respectively.\n" +msgstr[0] "" +msgstr[1] "" + +#: sequencer.c:120 builtin/merge.c:864 builtin/merge.c:985 +#: builtin/merge.c:1095 builtin/merge.c:1105 +#, c-format +msgid "Could not open '%s' for writing" +msgstr "" + +#: sequencer.c:122 builtin/merge.c:334 builtin/merge.c:867 +#: builtin/merge.c:1097 builtin/merge.c:1110 +#, c-format +msgid "Could not write to '%s'" +msgstr "" + +#: sequencer.c:143 +msgid "" +"after resolving the conflicts, mark the corrected paths\n" +"with 'git add <paths>' or 'git rm <paths>'" +msgstr "" + +#: sequencer.c:146 +msgid "" +"after resolving the conflicts, mark the corrected paths\n" +"with 'git add <paths>' or 'git rm <paths>'\n" +"and commit the result with 'git commit'" +msgstr "" + +#: sequencer.c:159 sequencer.c:685 sequencer.c:768 +#, c-format +msgid "Could not write to %s" +msgstr "" + +#: sequencer.c:162 +#, c-format +msgid "Error wrapping up %s" +msgstr "" + +#: sequencer.c:177 +msgid "Your local changes would be overwritten by cherry-pick." +msgstr "" + +#: sequencer.c:179 +msgid "Your local changes would be overwritten by revert." +msgstr "" + +#: sequencer.c:182 +msgid "Commit your changes or stash them to proceed." +msgstr "" + +#. TRANSLATORS: %s will be "revert" or "cherry-pick" +#: sequencer.c:232 +#, c-format +msgid "%s: Unable to write new index file" +msgstr "" + +#: sequencer.c:298 +msgid "Your index file is unmerged." +msgstr "" + +#: sequencer.c:301 +msgid "You do not have a valid HEAD" +msgstr "" + +#: sequencer.c:316 +#, c-format +msgid "Commit %s is a merge but no -m option was given." +msgstr "" + +#: sequencer.c:324 +#, c-format +msgid "Commit %s does not have parent %d" +msgstr "" + +#: sequencer.c:328 +#, c-format +msgid "Mainline was specified but commit %s is not a merge." +msgstr "" + +#. TRANSLATORS: The first %s will be "revert" or +#. "cherry-pick", the second %s a SHA1 +#: sequencer.c:339 +#, c-format +msgid "%s: cannot parse parent commit %s" +msgstr "" + +#: sequencer.c:343 +#, c-format +msgid "Cannot get commit message for %s" +msgstr "" + +#: sequencer.c:427 +#, c-format +msgid "could not revert %s... %s" +msgstr "" + +#: sequencer.c:428 +#, c-format +msgid "could not apply %s... %s" +msgstr "" + +#: sequencer.c:450 sequencer.c:909 builtin/log.c:288 builtin/log.c:713 +#: builtin/log.c:1329 builtin/log.c:1548 builtin/merge.c:348 +#: builtin/shortlog.c:181 +msgid "revision walk setup failed" +msgstr "" + +#: sequencer.c:453 +msgid "empty commit set passed" +msgstr "" + +#: sequencer.c:461 +#, c-format +msgid "git %s: failed to read the index" +msgstr "" + +#: sequencer.c:466 +#, c-format +msgid "git %s: failed to refresh the index" +msgstr "" + +#: sequencer.c:551 +#, c-format +msgid "Cannot %s during a %s" +msgstr "" + +#: sequencer.c:573 +#, c-format +msgid "Could not parse line %d." +msgstr "" + +#: sequencer.c:578 +msgid "No commits parsed." +msgstr "" + +#: sequencer.c:591 +#, c-format +msgid "Could not open %s" +msgstr "" + +#: sequencer.c:595 +#, c-format +msgid "Could not read %s." +msgstr "" + +#: sequencer.c:602 +#, c-format +msgid "Unusable instruction sheet: %s" +msgstr "" + +#: sequencer.c:630 +#, c-format +msgid "Invalid key: %s" +msgstr "" + +#: sequencer.c:633 +#, c-format +msgid "Invalid value for %s: %s" +msgstr "" + +#: sequencer.c:645 +#, c-format +msgid "Malformed options sheet: %s" +msgstr "" + +#: sequencer.c:666 +msgid "a cherry-pick or revert is already in progress" +msgstr "" + +#: sequencer.c:667 +msgid "try \"git cherry-pick (--continue | --quit | --abort)\"" +msgstr "" + +#: sequencer.c:671 +#, c-format +msgid "Could not create sequencer directory %s" +msgstr "" + +#: sequencer.c:687 sequencer.c:772 +#, c-format +msgid "Error wrapping up %s." +msgstr "" + +#: sequencer.c:706 sequencer.c:840 +msgid "no cherry-pick or revert in progress" +msgstr "" + +#: sequencer.c:708 +msgid "cannot resolve HEAD" +msgstr "" + +#: sequencer.c:710 +msgid "cannot abort from a branch yet to be born" +msgstr "" + +#: sequencer.c:732 +#, c-format +msgid "cannot open %s: %s" +msgstr "" + +#: sequencer.c:735 +#, c-format +msgid "cannot read %s: %s" +msgstr "" + +#: sequencer.c:736 +msgid "unexpected end of file" +msgstr "" + +#: sequencer.c:742 +#, c-format +msgid "stored pre-cherry-pick HEAD file '%s' is corrupt" +msgstr "" + +#: sequencer.c:765 +#, c-format +msgid "Could not format %s." +msgstr "" + +#: sequencer.c:927 +msgid "Can't revert as initial commit" +msgstr "" + +#: sequencer.c:928 +msgid "Can't cherry-pick into empty head" +msgstr "" + +#: wt-status.c:134 +msgid "Unmerged paths:" +msgstr "" + +#: wt-status.c:140 wt-status.c:157 +#, c-format +msgid " (use \"git reset %s <file>...\" to unstage)" +msgstr "" + +#: wt-status.c:142 wt-status.c:159 +msgid " (use \"git rm --cached <file>...\" to unstage)" +msgstr "" + +#: wt-status.c:143 +msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)" +msgstr "" + +#: wt-status.c:151 +msgid "Changes to be committed:" +msgstr "" + +#: wt-status.c:169 +msgid "Changes not staged for commit:" +msgstr "" + +#: wt-status.c:173 +msgid " (use \"git add <file>...\" to update what will be committed)" +msgstr "" + +#: wt-status.c:175 +msgid " (use \"git add/rm <file>...\" to update what will be committed)" +msgstr "" + +#: wt-status.c:176 +msgid "" +" (use \"git checkout -- <file>...\" to discard changes in working directory)" +msgstr "" + +#: wt-status.c:178 +msgid " (commit or discard the untracked or modified content in submodules)" +msgstr "" + +#: wt-status.c:187 +#, c-format +msgid "%s files:" +msgstr "" + +#: wt-status.c:190 +#, c-format +msgid " (use \"git %s <file>...\" to include in what will be committed)" +msgstr "" + +#: wt-status.c:207 +msgid "bug" +msgstr "" + +#: wt-status.c:212 +msgid "both deleted:" +msgstr "" + +#: wt-status.c:213 +msgid "added by us:" +msgstr "" + +#: wt-status.c:214 +msgid "deleted by them:" +msgstr "" + +#: wt-status.c:215 +msgid "added by them:" +msgstr "" + +#: wt-status.c:216 +msgid "deleted by us:" +msgstr "" + +#: wt-status.c:217 +msgid "both added:" +msgstr "" + +#: wt-status.c:218 +msgid "both modified:" +msgstr "" + +#: wt-status.c:248 +msgid "new commits, " +msgstr "" + +#: wt-status.c:250 +msgid "modified content, " +msgstr "" + +#: wt-status.c:252 +msgid "untracked content, " +msgstr "" + +#: wt-status.c:266 +#, c-format +msgid "new file: %s" +msgstr "" + +#: wt-status.c:269 +#, c-format +msgid "copied: %s -> %s" +msgstr "" + +#: wt-status.c:272 +#, c-format +msgid "deleted: %s" +msgstr "" + +#: wt-status.c:275 +#, c-format +msgid "modified: %s" +msgstr "" + +#: wt-status.c:278 +#, c-format +msgid "renamed: %s -> %s" +msgstr "" + +#: wt-status.c:281 +#, c-format +msgid "typechange: %s" +msgstr "" + +#: wt-status.c:284 +#, c-format +msgid "unknown: %s" +msgstr "" + +#: wt-status.c:287 +#, c-format +msgid "unmerged: %s" +msgstr "" + +#: wt-status.c:290 +#, c-format +msgid "bug: unhandled diff status %c" +msgstr "" + +#: wt-status.c:713 +msgid "On branch " +msgstr "" + +#: wt-status.c:720 +msgid "Not currently on any branch." +msgstr "" + +#: wt-status.c:731 +msgid "Initial commit" +msgstr "" + +#: wt-status.c:745 +msgid "Untracked" +msgstr "" + +#: wt-status.c:747 +msgid "Ignored" +msgstr "" + +#: wt-status.c:749 +#, c-format +msgid "Untracked files not listed%s" +msgstr "" + +#: wt-status.c:751 +msgid " (use -u option to show untracked files)" +msgstr "" + +#: wt-status.c:757 +msgid "No changes" +msgstr "" + +#: wt-status.c:761 +#, c-format +msgid "no changes added to commit%s\n" +msgstr "" + +#: wt-status.c:763 +msgid " (use \"git add\" and/or \"git commit -a\")" +msgstr "" + +#: wt-status.c:765 +#, c-format +msgid "nothing added to commit but untracked files present%s\n" +msgstr "" + +#: wt-status.c:767 +msgid " (use \"git add\" to track)" +msgstr "" + +#: wt-status.c:769 wt-status.c:772 wt-status.c:775 +#, c-format +msgid "nothing to commit%s\n" +msgstr "" + +#: wt-status.c:770 +msgid " (create/copy files and use \"git add\" to track)" +msgstr "" + +#: wt-status.c:773 +msgid " (use -u to show untracked files)" +msgstr "" + +#: wt-status.c:776 +msgid " (working directory clean)" +msgstr "" + +#: wt-status.c:884 +msgid "HEAD (no branch)" +msgstr "" + +#: wt-status.c:890 +msgid "Initial commit on " +msgstr "" + +#: wt-status.c:905 +msgid "behind " +msgstr "" + +#: wt-status.c:908 wt-status.c:911 +msgid "ahead " +msgstr "" + +#: wt-status.c:913 +msgid ", behind " +msgstr "" + +#: builtin/add.c:62 +#, c-format +msgid "unexpected diff status %c" +msgstr "" + +#: builtin/add.c:67 builtin/commit.c:298 +msgid "updating files failed" +msgstr "" + +#: builtin/add.c:77 +#, c-format +msgid "remove '%s'\n" +msgstr "" + +#: builtin/add.c:176 +#, c-format +msgid "Path '%s' is in submodule '%.*s'" +msgstr "" + +#: builtin/add.c:192 +msgid "Unstaged changes after refreshing the index:" +msgstr "" + +#: builtin/add.c:195 builtin/add.c:456 builtin/rm.c:186 +#, c-format +msgid "pathspec '%s' did not match any files" +msgstr "" + +#: builtin/add.c:209 +#, c-format +msgid "'%s' is beyond a symbolic link" +msgstr "" + +#: builtin/add.c:276 +msgid "Could not read the index" +msgstr "" + +#: builtin/add.c:286 +#, c-format +msgid "Could not open '%s' for writing." +msgstr "" + +#: builtin/add.c:290 +msgid "Could not write patch" +msgstr "" + +#: builtin/add.c:295 +#, c-format +msgid "Could not stat '%s'" +msgstr "" + +#: builtin/add.c:297 +msgid "Empty patch. Aborted." +msgstr "" + +#: builtin/add.c:303 +#, c-format +msgid "Could not apply '%s'" +msgstr "" + +#: builtin/add.c:312 +msgid "The following paths are ignored by one of your .gitignore files:\n" +msgstr "" + +#: builtin/add.c:352 +#, c-format +msgid "Use -f if you really want to add them.\n" +msgstr "" + +#: builtin/add.c:353 +msgid "no files added" +msgstr "" + +#: builtin/add.c:359 +msgid "adding files failed" +msgstr "" + +#: builtin/add.c:391 +msgid "-A and -u are mutually incompatible" +msgstr "" + +#: builtin/add.c:393 +msgid "Option --ignore-missing can only be used together with --dry-run" +msgstr "" + +#: builtin/add.c:413 +#, c-format +msgid "Nothing specified, nothing added.\n" +msgstr "" + +#: builtin/add.c:414 +#, c-format +msgid "Maybe you wanted to say 'git add .'?\n" +msgstr "" + +#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:358 builtin/mv.c:82 +#: builtin/rm.c:162 +msgid "index file corrupt" +msgstr "" + +#: builtin/add.c:476 builtin/mv.c:229 builtin/rm.c:260 +msgid "Unable to write new index file" +msgstr "" + +#: builtin/archive.c:17 +#, c-format +msgid "could not create archive file '%s'" +msgstr "" + +#: builtin/archive.c:20 +msgid "could not redirect output" +msgstr "" + +#: builtin/archive.c:37 +msgid "git archive: Remote with no URL" +msgstr "" + +#: builtin/archive.c:58 +msgid "git archive: expected ACK/NAK, got EOF" +msgstr "" + +#: builtin/archive.c:63 +#, c-format +msgid "git archive: NACK %s" +msgstr "" + +#: builtin/archive.c:65 +#, c-format +msgid "remote error: %s" +msgstr "" + +#: builtin/archive.c:66 +msgid "git archive: protocol error" +msgstr "" + +#: builtin/archive.c:71 +msgid "git archive: expected a flush" +msgstr "" + +#: builtin/branch.c:137 +#, c-format +msgid "" +"deleting branch '%s' that has been merged to\n" +" '%s', but not yet merged to HEAD." +msgstr "" + +#: builtin/branch.c:141 +#, c-format +msgid "" +"not deleting branch '%s' that is not yet merged to\n" +" '%s', even though it is merged to HEAD." +msgstr "" + +#. TRANSLATORS: This is "remote " in "remote branch '%s' not found" +#: builtin/branch.c:163 +msgid "remote " +msgstr "" + +#: builtin/branch.c:171 +msgid "cannot use -a with -d" +msgstr "" + +#: builtin/branch.c:177 +msgid "Couldn't look up commit object for HEAD" +msgstr "" + +#: builtin/branch.c:182 +#, c-format +msgid "Cannot delete the branch '%s' which you are currently on." +msgstr "" + +#: builtin/branch.c:192 +#, c-format +msgid "%sbranch '%s' not found." +msgstr "" + +#: builtin/branch.c:200 +#, c-format +msgid "Couldn't look up commit object for '%s'" +msgstr "" + +#: builtin/branch.c:206 +#, c-format +msgid "" +"The branch '%s' is not fully merged.\n" +"If you are sure you want to delete it, run 'git branch -D %s'." +msgstr "" + +#: builtin/branch.c:214 +#, c-format +msgid "Error deleting %sbranch '%s'" +msgstr "" + +#: builtin/branch.c:219 +#, c-format +msgid "Deleted %sbranch %s (was %s).\n" +msgstr "" + +#: builtin/branch.c:224 +msgid "Update of config-file failed" +msgstr "" + +#: builtin/branch.c:322 +#, c-format +msgid "branch '%s' does not point at a commit" +msgstr "" + +#: builtin/branch.c:394 +#, c-format +msgid "behind %d] " +msgstr "" + +#: builtin/branch.c:396 +#, c-format +msgid "ahead %d] " +msgstr "" + +#: builtin/branch.c:398 +#, c-format +msgid "ahead %d, behind %d] " +msgstr "" + +#: builtin/branch.c:501 +msgid "(no branch)" +msgstr "" + +#: builtin/branch.c:566 +msgid "some refs could not be read" +msgstr "" + +#: builtin/branch.c:579 +msgid "cannot rename the current branch while not on any." +msgstr "" + +#: builtin/branch.c:589 +#, c-format +msgid "Invalid branch name: '%s'" +msgstr "" + +#: builtin/branch.c:604 +msgid "Branch rename failed" +msgstr "" + +#: builtin/branch.c:608 +#, c-format +msgid "Renamed a misnamed branch '%s' away" +msgstr "" + +#: builtin/branch.c:612 +#, c-format +msgid "Branch renamed to %s, but HEAD is not updated!" +msgstr "" + +#: builtin/branch.c:619 +msgid "Branch is renamed, but update of config-file failed" +msgstr "" + +#: builtin/branch.c:634 +#, c-format +msgid "malformed object name %s" +msgstr "" + +#: builtin/branch.c:658 +#, c-format +msgid "could not write branch description template: %s\n" +msgstr "" + +#: builtin/branch.c:746 +msgid "Failed to resolve HEAD as a valid ref." +msgstr "" + +#: builtin/branch.c:751 builtin/clone.c:558 +msgid "HEAD not found below refs/heads!" +msgstr "" + +#: builtin/branch.c:809 +msgid "-a and -r options to 'git branch' do not make sense with a branch name" +msgstr "" + +#: builtin/bundle.c:47 +#, c-format +msgid "%s is okay\n" +msgstr "" + +#: builtin/bundle.c:56 +msgid "Need a repository to create a bundle." +msgstr "" + +#: builtin/bundle.c:60 +msgid "Need a repository to unbundle." +msgstr "" + +#: builtin/checkout.c:113 builtin/checkout.c:146 +#, c-format +msgid "path '%s' does not have our version" +msgstr "" + +#: builtin/checkout.c:115 builtin/checkout.c:148 +#, c-format +msgid "path '%s' does not have their version" +msgstr "" + +#: builtin/checkout.c:131 +#, c-format +msgid "path '%s' does not have all necessary versions" +msgstr "" + +#: builtin/checkout.c:175 +#, c-format +msgid "path '%s' does not have necessary versions" +msgstr "" + +#: builtin/checkout.c:192 +#, c-format +msgid "path '%s': cannot merge" +msgstr "" + +#: builtin/checkout.c:209 +#, c-format +msgid "Unable to add merge result for '%s'" +msgstr "" + +#: builtin/checkout.c:212 builtin/reset.c:158 +#, c-format +msgid "make_cache_entry failed for path '%s'" +msgstr "" + +#: builtin/checkout.c:234 builtin/checkout.c:392 +msgid "corrupt index file" +msgstr "" + +#: builtin/checkout.c:264 builtin/checkout.c:271 +#, c-format +msgid "path '%s' is unmerged" +msgstr "" + +#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583 +#: builtin/merge.c:811 +msgid "unable to write new index file" +msgstr "" + +#: builtin/checkout.c:319 builtin/diff.c:302 builtin/merge.c:408 +msgid "diff_setup_done failed" +msgstr "" + +#: builtin/checkout.c:414 +msgid "you need to resolve your current index first" +msgstr "" + +#: builtin/checkout.c:533 +#, c-format +msgid "Can not do reflog for '%s'\n" +msgstr "" + +#: builtin/checkout.c:565 +msgid "HEAD is now at" +msgstr "" + +#: builtin/checkout.c:572 +#, c-format +msgid "Reset branch '%s'\n" +msgstr "" + +#: builtin/checkout.c:575 +#, c-format +msgid "Already on '%s'\n" +msgstr "" + +#: builtin/checkout.c:579 +#, c-format +msgid "Switched to and reset branch '%s'\n" +msgstr "" + +#: builtin/checkout.c:581 +#, c-format +msgid "Switched to a new branch '%s'\n" +msgstr "" + +#: builtin/checkout.c:583 +#, c-format +msgid "Switched to branch '%s'\n" +msgstr "" + +#: builtin/checkout.c:639 +#, c-format +msgid " ... and %d more.\n" +msgstr "" + +#. The singular version +#: builtin/checkout.c:645 +#, c-format +msgid "" +"Warning: you are leaving %d commit behind, not connected to\n" +"any of your branches:\n" +"\n" +"%s\n" +msgid_plural "" +"Warning: you are leaving %d commits behind, not connected to\n" +"any of your branches:\n" +"\n" +"%s\n" +msgstr[0] "" +msgstr[1] "" + +#: builtin/checkout.c:663 +#, c-format +msgid "" +"If you want to keep them by creating a new branch, this may be a good time\n" +"to do so with:\n" +"\n" +" git branch new_branch_name %s\n" +"\n" +msgstr "" + +#: builtin/checkout.c:692 +msgid "internal error in revision walk" +msgstr "" + +#: builtin/checkout.c:696 +msgid "Previous HEAD position was" +msgstr "" + +#: builtin/checkout.c:722 +msgid "You are on a branch yet to be born" +msgstr "" + +#. case (1) +#: builtin/checkout.c:853 +#, c-format +msgid "invalid reference: %s" +msgstr "" + +#. case (1): want a tree +#: builtin/checkout.c:892 +#, c-format +msgid "reference is not a tree: %s" +msgstr "" + +#: builtin/checkout.c:972 +msgid "-B cannot be used with -b" +msgstr "" + +#: builtin/checkout.c:981 +msgid "--patch is incompatible with all other options" +msgstr "" + +#: builtin/checkout.c:984 +msgid "--detach cannot be used with -b/-B/--orphan" +msgstr "" + +#: builtin/checkout.c:986 +msgid "--detach cannot be used with -t" +msgstr "" + +#: builtin/checkout.c:992 +msgid "--track needs a branch name" +msgstr "" + +#: builtin/checkout.c:999 +msgid "Missing branch name; try -b" +msgstr "" + +#: builtin/checkout.c:1005 +msgid "--orphan and -b|-B are mutually exclusive" +msgstr "" + +#: builtin/checkout.c:1007 +msgid "--orphan cannot be used with -t" +msgstr "" + +#: builtin/checkout.c:1017 +msgid "git checkout: -f and -m are incompatible" +msgstr "" + +#: builtin/checkout.c:1051 +msgid "invalid path specification" +msgstr "" + +#: builtin/checkout.c:1059 +#, 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:1061 +msgid "git checkout: updating paths is incompatible with switching branches." +msgstr "" + +#: builtin/checkout.c:1066 +msgid "git checkout: --detach does not take a path argument" +msgstr "" + +#: builtin/checkout.c:1069 +msgid "" +"git checkout: --ours/--theirs, --force and --merge are incompatible when\n" +"checking out of the index." +msgstr "" + +#: builtin/checkout.c:1088 +msgid "Cannot switch branch to a non-commit." +msgstr "" + +#: builtin/checkout.c:1091 +msgid "--ours/--theirs is incompatible with switching branches." +msgstr "" + +#: builtin/clean.c:78 +msgid "-x and -X cannot be used together" +msgstr "" + +#: builtin/clean.c:82 +msgid "" +"clean.requireForce set to true and neither -n nor -f given; refusing to clean" +msgstr "" + +#: builtin/clean.c:85 +msgid "" +"clean.requireForce defaults to true and neither -n nor -f given; refusing to " +"clean" +msgstr "" + +#: builtin/clean.c:155 builtin/clean.c:176 +#, c-format +msgid "Would remove %s\n" +msgstr "" + +#: builtin/clean.c:159 builtin/clean.c:179 +#, c-format +msgid "Removing %s\n" +msgstr "" + +#: builtin/clean.c:162 builtin/clean.c:182 +#, c-format +msgid "failed to remove %s" +msgstr "" + +#: builtin/clean.c:166 +#, c-format +msgid "Would not remove %s\n" +msgstr "" + +#: builtin/clean.c:168 +#, c-format +msgid "Not removing %s\n" +msgstr "" + +#: builtin/clone.c:243 +#, c-format +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'" +msgstr "" + +#: builtin/clone.c:308 builtin/diff.c:75 +#, c-format +msgid "failed to stat '%s'" +msgstr "" + +#: builtin/clone.c:310 +#, c-format +msgid "%s exists and is not a directory" +msgstr "" + +#: builtin/clone.c:324 +#, c-format +msgid "failed to stat %s\n" +msgstr "" + +#: builtin/clone.c:341 +#, c-format +msgid "failed to unlink '%s'" +msgstr "" + +#: builtin/clone.c:346 +#, c-format +msgid "failed to create link '%s'" +msgstr "" + +#: builtin/clone.c:350 +#, c-format +msgid "failed to copy file to '%s'" +msgstr "" + +#: builtin/clone.c:373 +#, c-format +msgid "done.\n" +msgstr "" + +#: builtin/clone.c:440 +#, c-format +msgid "Could not find remote branch %s to clone." +msgstr "" + +#: builtin/clone.c:549 +msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n" +msgstr "" + +#: builtin/clone.c:639 +msgid "Too many arguments." +msgstr "" + +#: builtin/clone.c:643 +msgid "You must specify a repository to clone." +msgstr "" + +#: builtin/clone.c:654 +#, c-format +msgid "--bare and --origin %s options are incompatible." +msgstr "" + +#: builtin/clone.c:668 +#, c-format +msgid "repository '%s' does not exist" +msgstr "" + +#: builtin/clone.c:673 +msgid "--depth is ignored in local clones; use file:// instead." +msgstr "" + +#: builtin/clone.c:683 +#, c-format +msgid "destination path '%s' already exists and is not an empty directory." +msgstr "" + +#: builtin/clone.c:693 +#, c-format +msgid "working tree '%s' already exists." +msgstr "" + +#: builtin/clone.c:706 builtin/clone.c:720 +#, c-format +msgid "could not create leading directories of '%s'" +msgstr "" + +#: builtin/clone.c:709 +#, c-format +msgid "could not create work tree dir '%s'." +msgstr "" + +#: builtin/clone.c:728 +#, c-format +msgid "Cloning into bare repository '%s'...\n" +msgstr "" + +#: builtin/clone.c:730 +#, c-format +msgid "Cloning into '%s'...\n" +msgstr "" + +#: builtin/clone.c:786 +#, c-format +msgid "Don't know how to clone %s" +msgstr "" + +#: builtin/clone.c:835 +#, c-format +msgid "Remote branch %s not found in upstream %s" +msgstr "" + +#: builtin/clone.c:842 +msgid "You appear to have cloned an empty repository." +msgstr "" + +#: builtin/commit.c:42 +msgid "" +"Your name and email address were configured automatically based\n" +"on your username and hostname. Please check that they are accurate.\n" +"You can suppress this message by setting them explicitly:\n" +"\n" +" git config --global user.name \"Your Name\"\n" +" git config --global user.email you@example.com\n" +"\n" +"After doing this, you may fix the identity used for this commit with:\n" +"\n" +" git commit --amend --reset-author\n" +msgstr "" + +#: builtin/commit.c:54 +msgid "" +"You asked to amend the most recent commit, but doing so would make\n" +"it empty. You can repeat your command with --allow-empty, or you can\n" +"remove the commit entirely with \"git reset HEAD^\".\n" +msgstr "" + +#: builtin/commit.c:59 +msgid "" +"The previous cherry-pick is now empty, possibly due to conflict resolution.\n" +"If you wish to commit it anyway, use:\n" +"\n" +" git commit --allow-empty\n" +"\n" +"Otherwise, please use 'git reset'\n" +msgstr "" + +#: builtin/commit.c:205 builtin/reset.c:33 +msgid "merge" +msgstr "" + +#: builtin/commit.c:208 +msgid "cherry-pick" +msgstr "" + +#: builtin/commit.c:325 +msgid "failed to unpack HEAD tree object" +msgstr "" + +#: builtin/commit.c:367 +msgid "unable to create temporary index" +msgstr "" + +#: builtin/commit.c:373 +msgid "interactive add failed" +msgstr "" + +#: builtin/commit.c:406 builtin/commit.c:427 builtin/commit.c:473 +msgid "unable to write new_index file" +msgstr "" + +#: builtin/commit.c:457 +#, c-format +msgid "cannot do a partial commit during a %s." +msgstr "" + +#: builtin/commit.c:466 +msgid "cannot read the index" +msgstr "" + +#: builtin/commit.c:486 +msgid "unable to write temporary index file" +msgstr "" + +#: builtin/commit.c:550 builtin/commit.c:556 +#, c-format +msgid "invalid commit: %s" +msgstr "" + +#: builtin/commit.c:579 +msgid "malformed --author parameter" +msgstr "" + +#: builtin/commit.c:635 +#, c-format +msgid "Malformed ident string: '%s'" +msgstr "" + +#: builtin/commit.c:670 builtin/commit.c:703 builtin/commit.c:1000 +#, c-format +msgid "could not lookup commit %s" +msgstr "" + +#: builtin/commit.c:682 builtin/shortlog.c:296 +#, c-format +msgid "(reading log message from standard input)\n" +msgstr "" + +#: builtin/commit.c:684 +msgid "could not read log from standard input" +msgstr "" + +#: builtin/commit.c:688 +#, c-format +msgid "could not read log file '%s'" +msgstr "" + +#: builtin/commit.c:694 +msgid "commit has empty message" +msgstr "" + +#: builtin/commit.c:710 +msgid "could not read MERGE_MSG" +msgstr "" + +#: builtin/commit.c:714 +msgid "could not read SQUASH_MSG" +msgstr "" + +#: builtin/commit.c:718 +#, c-format +msgid "could not read '%s'" +msgstr "" + +#: builtin/commit.c:746 +#, c-format +msgid "could not open '%s'" +msgstr "" + +#: builtin/commit.c:770 +msgid "could not write commit template" +msgstr "" + +#: builtin/commit.c:783 +#, c-format +msgid "" +"\n" +"It looks like you may be committing a %s.\n" +"If this is not correct, please remove the file\n" +"\t%s\n" +"and try again.\n" +msgstr "" + +#: builtin/commit.c:796 +msgid "Please enter the commit message for your changes." +msgstr "" + +#: builtin/commit.c:799 +msgid "" +" Lines starting\n" +"with '#' will be ignored, and an empty message aborts the commit.\n" +msgstr "" + +#: builtin/commit.c:804 +msgid "" +" 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:816 +#, c-format +msgid "%sAuthor: %s" +msgstr "" + +#: builtin/commit.c:823 +#, c-format +msgid "%sCommitter: %s" +msgstr "" + +#: builtin/commit.c:843 +msgid "Cannot read index" +msgstr "" + +#: builtin/commit.c:880 +msgid "Error building trees" +msgstr "" + +#: builtin/commit.c:895 builtin/tag.c:357 +#, c-format +msgid "Please supply the message using either -m or -F option.\n" +msgstr "" + +#: builtin/commit.c:975 +#, c-format +msgid "No existing author found with '%s'" +msgstr "" + +#: builtin/commit.c:990 builtin/commit.c:1182 +#, c-format +msgid "Invalid untracked files mode '%s'" +msgstr "" + +#: builtin/commit.c:1030 +msgid "Using both --reset-author and --author does not make sense" +msgstr "" + +#: builtin/commit.c:1041 +msgid "You have nothing to amend." +msgstr "" + +#: builtin/commit.c:1043 +#, c-format +msgid "You are in the middle of a %s -- cannot amend." +msgstr "" + +#: builtin/commit.c:1045 +msgid "Options --squash and --fixup cannot be used together" +msgstr "" + +#: builtin/commit.c:1055 +msgid "Only one of -c/-C/-F/--fixup can be used." +msgstr "" + +#: builtin/commit.c:1057 +msgid "Option -m cannot be combined with -c/-C/-F/--fixup." +msgstr "" + +#: builtin/commit.c:1063 +msgid "--reset-author can be used only with -C, -c or --amend." +msgstr "" + +#: builtin/commit.c:1080 +msgid "Only one of --include/--only/--all/--interactive/--patch can be used." +msgstr "" + +#: builtin/commit.c:1082 +msgid "No paths with --include/--only does not make sense." +msgstr "" + +#: builtin/commit.c:1084 +msgid "Clever... amending the last one with dirty index." +msgstr "" + +#: builtin/commit.c:1086 +msgid "Explicit paths specified without -i nor -o; assuming --only paths..." +msgstr "" + +#: builtin/commit.c:1096 builtin/tag.c:556 +#, c-format +msgid "Invalid cleanup mode %s" +msgstr "" + +#: builtin/commit.c:1101 +msgid "Paths with -a does not make sense." +msgstr "" + +#: builtin/commit.c:1280 +msgid "couldn't look up newly created commit" +msgstr "" + +#: builtin/commit.c:1282 +msgid "could not parse newly created commit" +msgstr "" + +#: builtin/commit.c:1323 +msgid "detached HEAD" +msgstr "" + +#: builtin/commit.c:1325 +msgid " (root-commit)" +msgstr "" + +#: builtin/commit.c:1415 +msgid "could not parse HEAD commit" +msgstr "" + +#: builtin/commit.c:1452 builtin/merge.c:509 +#, c-format +msgid "could not open '%s' for reading" +msgstr "" + +#: builtin/commit.c:1459 +#, c-format +msgid "Corrupt MERGE_HEAD file (%s)" +msgstr "" + +#: builtin/commit.c:1466 +msgid "could not read MERGE_MODE" +msgstr "" + +#: builtin/commit.c:1485 +#, c-format +msgid "could not read commit message: %s" +msgstr "" + +#: builtin/commit.c:1499 +#, c-format +msgid "Aborting commit due to empty commit message.\n" +msgstr "" + +#: builtin/commit.c:1514 builtin/merge.c:935 builtin/merge.c:968 +msgid "failed to write commit object" +msgstr "" + +#: builtin/commit.c:1535 +msgid "cannot lock HEAD ref" +msgstr "" + +#: builtin/commit.c:1539 +msgid "cannot update HEAD ref" +msgstr "" + +#: builtin/commit.c:1550 +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 "" + +#: builtin/describe.c:234 +#, c-format +msgid "annotated tag %s not available" +msgstr "" + +#: builtin/describe.c:238 +#, c-format +msgid "annotated tag %s has no embedded name" +msgstr "" + +#: builtin/describe.c:240 +#, c-format +msgid "tag '%s' is really '%s' here" +msgstr "" + +#: builtin/describe.c:267 +#, c-format +msgid "Not a valid object name %s" +msgstr "" + +#: builtin/describe.c:270 +#, c-format +msgid "%s is not a valid '%s' object" +msgstr "" + +#: builtin/describe.c:287 +#, c-format +msgid "no tag exactly matches '%s'" +msgstr "" + +#: builtin/describe.c:289 +#, c-format +msgid "searching to describe %s\n" +msgstr "" + +#: builtin/describe.c:329 +#, c-format +msgid "finished search at %s\n" +msgstr "" + +#: builtin/describe.c:353 +#, c-format +msgid "" +"No annotated tags can describe '%s'.\n" +"However, there were unannotated tags: try --tags." +msgstr "" + +#: builtin/describe.c:357 +#, c-format +msgid "" +"No tags can describe '%s'.\n" +"Try --always, or create some tags." +msgstr "" + +#: builtin/describe.c:378 +#, c-format +msgid "traversed %lu commits\n" +msgstr "" + +#: builtin/describe.c:381 +#, c-format +msgid "" +"more than %i tags found; listed %i most recent\n" +"gave up search at %s\n" +msgstr "" + +#: builtin/describe.c:436 +msgid "--long is incompatible with --abbrev=0" +msgstr "" + +#: builtin/describe.c:462 +msgid "No names found, cannot describe anything." +msgstr "" + +#: builtin/describe.c:482 +msgid "--dirty is incompatible with committishes" +msgstr "" + +#: builtin/diff.c:77 +#, c-format +msgid "'%s': not a regular file or symlink" +msgstr "" + +#: builtin/diff.c:220 +#, c-format +msgid "invalid option: %s" +msgstr "" + +#: builtin/diff.c:297 +msgid "Not a git repository" +msgstr "" + +#: builtin/diff.c:347 +#, c-format +msgid "invalid object '%s' given." +msgstr "" + +#: builtin/diff.c:352 +#, c-format +msgid "more than %d trees given: '%s'" +msgstr "" + +#: builtin/diff.c:362 +#, c-format +msgid "more than two blobs given: '%s'" +msgstr "" + +#: builtin/diff.c:370 +#, c-format +msgid "unhandled object '%s' given." +msgstr "" + +#: builtin/fetch.c:200 +msgid "Couldn't find remote ref HEAD" +msgstr "" + +#: builtin/fetch.c:252 +#, c-format +msgid "object %s not found" +msgstr "" + +#: builtin/fetch.c:258 +msgid "[up to date]" +msgstr "" + +#: builtin/fetch.c:272 +#, c-format +msgid "! %-*s %-*s -> %s (can't fetch in current branch)" +msgstr "" + +#: builtin/fetch.c:273 builtin/fetch.c:351 +msgid "[rejected]" +msgstr "" + +#: builtin/fetch.c:284 +msgid "[tag update]" +msgstr "" + +#: builtin/fetch.c:286 builtin/fetch.c:313 builtin/fetch.c:331 +msgid " (unable to update local ref)" +msgstr "" + +#: builtin/fetch.c:298 +msgid "[new tag]" +msgstr "" + +#: builtin/fetch.c:302 +msgid "[new branch]" +msgstr "" + +#: builtin/fetch.c:347 +msgid "unable to update local ref" +msgstr "" + +#: builtin/fetch.c:347 +msgid "forced update" +msgstr "" + +#: builtin/fetch.c:353 +msgid "(non-fast-forward)" +msgstr "" + +#: builtin/fetch.c:384 builtin/fetch.c:676 +#, c-format +msgid "cannot open %s: %s\n" +msgstr "" + +#: builtin/fetch.c:393 +#, c-format +msgid "%s did not send all necessary objects\n" +msgstr "" + +#: builtin/fetch.c:479 +#, c-format +msgid "From %.*s\n" +msgstr "" + +#: builtin/fetch.c:490 +#, c-format +msgid "" +"some local refs could not be updated; try running\n" +" 'git remote prune %s' to remove any old, conflicting branches" +msgstr "" + +#: builtin/fetch.c:540 +#, c-format +msgid " (%s will become dangling)\n" +msgstr "" + +#: builtin/fetch.c:541 +#, c-format +msgid " (%s has become dangling)\n" +msgstr "" + +#: builtin/fetch.c:548 +msgid "[deleted]" +msgstr "" + +#: builtin/fetch.c:549 +msgid "(none)" +msgstr "" + +#: builtin/fetch.c:666 +#, c-format +msgid "Refusing to fetch into current branch %s of non-bare repository" +msgstr "" + +#: builtin/fetch.c:700 +#, c-format +msgid "Don't know how to fetch from %s" +msgstr "" + +#: builtin/fetch.c:777 +#, c-format +msgid "Option \"%s\" value \"%s\" is not valid for %s" +msgstr "" + +#: builtin/fetch.c:780 +#, c-format +msgid "Option \"%s\" is ignored for %s\n" +msgstr "" + +#: builtin/fetch.c:879 +#, c-format +msgid "Fetching %s\n" +msgstr "" + +#: builtin/fetch.c:881 +#, c-format +msgid "Could not fetch %s" +msgstr "" + +#: builtin/fetch.c:898 +msgid "" +"No remote repository specified. Please, specify either a URL or a\n" +"remote name from which new revisions should be fetched." +msgstr "" + +#: builtin/fetch.c:918 +msgid "You need to specify a tag name." +msgstr "" + +#: builtin/fetch.c:970 +msgid "fetch --all does not take a repository argument" +msgstr "" + +#: builtin/fetch.c:972 +msgid "fetch --all does not make sense with refspecs" +msgstr "" + +#: builtin/fetch.c:983 +#, c-format +msgid "No such remote or remote group: %s" +msgstr "" + +#: builtin/fetch.c:991 +msgid "Fetching a group and specifying refspecs does not make sense" +msgstr "" + +#: builtin/gc.c:63 +#, c-format +msgid "Invalid %s: '%s'" +msgstr "" + +#: builtin/gc.c:78 +msgid "Too many options specified" +msgstr "" + +#: builtin/gc.c:103 +#, c-format +msgid "insanely long object directory %.*s" +msgstr "" + +#: builtin/gc.c:223 +#, c-format +msgid "Auto packing the repository for optimum performance.\n" +msgstr "" + +#: builtin/gc.c:226 +#, c-format +msgid "" +"Auto packing the repository for optimum performance. You may also\n" +"run \"git gc\" manually. See \"git help gc\" for more information.\n" +msgstr "" + +#: builtin/gc.c:256 +msgid "" +"There are too many unreachable loose objects; run 'git prune' to remove them." +msgstr "" + +#: builtin/grep.c:216 +#, c-format +msgid "grep: failed to create thread: %s" +msgstr "" + +#: builtin/grep.c:402 +#, c-format +msgid "Failed to chdir: %s" +msgstr "" + +#: builtin/grep.c:478 builtin/grep.c:512 +#, c-format +msgid "unable to read tree (%s)" +msgstr "" + +#: builtin/grep.c:526 +#, c-format +msgid "unable to grep from object of type %s" +msgstr "" + +#: builtin/grep.c:584 +#, c-format +msgid "switch `%c' expects a numerical value" +msgstr "" + +#: builtin/grep.c:601 +#, c-format +msgid "cannot open '%s'" +msgstr "" + +#: builtin/grep.c:888 +msgid "no pattern given." +msgstr "" + +#: builtin/grep.c:902 +#, c-format +msgid "bad object %s" +msgstr "" + +#: builtin/grep.c:943 +msgid "--open-files-in-pager only works on the worktree" +msgstr "" + +#: builtin/grep.c:966 +msgid "--cached or --untracked cannot be used with --no-index." +msgstr "" + +#: builtin/grep.c:971 +msgid "--no-index or --untracked cannot be used with revs." +msgstr "" + +#: builtin/grep.c:974 +msgid "--[no-]exclude-standard cannot be used for tracked contents." +msgstr "" + +#: builtin/grep.c:982 +msgid "both --cached and trees are given." +msgstr "" + +#: builtin/init-db.c:35 +#, c-format +msgid "Could not make %s writable by group" +msgstr "" + +#: builtin/init-db.c:62 +#, c-format +msgid "insanely long template name %s" +msgstr "" + +#: builtin/init-db.c:67 +#, c-format +msgid "cannot stat '%s'" +msgstr "" + +#: builtin/init-db.c:73 +#, c-format +msgid "cannot stat template '%s'" +msgstr "" + +#: builtin/init-db.c:80 +#, c-format +msgid "cannot opendir '%s'" +msgstr "" + +#: builtin/init-db.c:97 +#, c-format +msgid "cannot readlink '%s'" +msgstr "" + +#: builtin/init-db.c:99 +#, c-format +msgid "insanely long symlink %s" +msgstr "" + +#: builtin/init-db.c:102 +#, c-format +msgid "cannot symlink '%s' '%s'" +msgstr "" + +#: builtin/init-db.c:106 +#, c-format +msgid "cannot copy '%s' to '%s'" +msgstr "" + +#: builtin/init-db.c:110 +#, c-format +msgid "ignoring template %s" +msgstr "" + +#: builtin/init-db.c:133 +#, c-format +msgid "insanely long template path %s" +msgstr "" + +#: builtin/init-db.c:141 +#, c-format +msgid "templates not found %s" +msgstr "" + +#: builtin/init-db.c:154 +#, c-format +msgid "not copying templates of a wrong format version %d from '%s'" +msgstr "" + +#: builtin/init-db.c:192 +#, c-format +msgid "insane git directory %s" +msgstr "" + +#: builtin/init-db.c:322 builtin/init-db.c:325 +#, c-format +msgid "%s already exists" +msgstr "" + +#: builtin/init-db.c:354 +#, c-format +msgid "unable to handle file type %d" +msgstr "" + +#: builtin/init-db.c:357 +#, c-format +msgid "unable to move %s to %s" +msgstr "" + +#: builtin/init-db.c:362 +#, c-format +msgid "Could not create git link %s" +msgstr "" + +#. +#. * TRANSLATORS: The first '%s' is either "Reinitialized +#. * existing" or "Initialized empty", the second " shared" or +#. * "", and the last '%s%s' is the verbatim directory name. +#. +#: builtin/init-db.c:419 +#, c-format +msgid "%s%s Git repository in %s%s\n" +msgstr "" + +#: builtin/init-db.c:420 +msgid "Reinitialized existing" +msgstr "" + +#: builtin/init-db.c:420 +msgid "Initialized empty" +msgstr "" + +#: builtin/init-db.c:421 +msgid " shared" +msgstr "" + +#: builtin/init-db.c:440 +msgid "cannot tell cwd" +msgstr "" + +#: builtin/init-db.c:521 builtin/init-db.c:528 +#, c-format +msgid "cannot mkdir %s" +msgstr "" + +#: builtin/init-db.c:532 +#, c-format +msgid "cannot chdir to %s" +msgstr "" + +#: builtin/init-db.c:554 +#, c-format +msgid "" +"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-" +"dir=<directory>)" +msgstr "" + +#: builtin/init-db.c:578 +msgid "Cannot access current working directory" +msgstr "" + +#: builtin/init-db.c:585 +#, c-format +msgid "Cannot access work tree '%s'" +msgstr "" + +#: builtin/log.c:187 +#, c-format +msgid "Final output: %d %s\n" +msgstr "" + +#: builtin/log.c:395 builtin/log.c:483 +#, c-format +msgid "Could not read object %s" +msgstr "" + +#: builtin/log.c:507 +#, c-format +msgid "Unknown type: %d" +msgstr "" + +#: builtin/log.c:596 +msgid "format.headers without value" +msgstr "" + +#: builtin/log.c:669 +msgid "name of output directory is too long" +msgstr "" + +#: builtin/log.c:680 +#, c-format +msgid "Cannot open patch file %s" +msgstr "" + +#: builtin/log.c:694 +msgid "Need exactly one range." +msgstr "" + +#: builtin/log.c:702 +msgid "Not a range." +msgstr "" + +#: builtin/log.c:739 +msgid "Could not extract email from committer identity." +msgstr "" + +#: builtin/log.c:785 +msgid "Cover letter needs email format" +msgstr "" + +#: builtin/log.c:879 +#, c-format +msgid "insane in-reply-to: %s" +msgstr "" + +#: builtin/log.c:952 +msgid "Two output directories?" +msgstr "" + +#: builtin/log.c:1173 +#, c-format +msgid "bogus committer info %s" +msgstr "" + +#: builtin/log.c:1218 +msgid "-n and -k are mutually exclusive." +msgstr "" + +#: builtin/log.c:1220 +msgid "--subject-prefix and -k are mutually exclusive." +msgstr "" + +#: builtin/log.c:1225 builtin/shortlog.c:284 +#, c-format +msgid "unrecognized argument: %s" +msgstr "" + +#: builtin/log.c:1228 +msgid "--name-only does not make sense" +msgstr "" + +#: builtin/log.c:1230 +msgid "--name-status does not make sense" +msgstr "" + +#: builtin/log.c:1232 +msgid "--check does not make sense" +msgstr "" + +#: builtin/log.c:1255 +msgid "standard output, or directory, which one?" +msgstr "" + +#: builtin/log.c:1257 +#, c-format +msgid "Could not create directory '%s'" +msgstr "" + +#: builtin/log.c:1410 +msgid "Failed to create output files" +msgstr "" + +#: builtin/log.c:1514 +#, c-format +msgid "" +"Could not find a tracked remote branch, please specify <upstream> manually.\n" +msgstr "" + +#: builtin/log.c:1530 builtin/log.c:1532 builtin/log.c:1544 +#, c-format +msgid "Unknown commit %s" +msgstr "" + +#: builtin/merge.c:91 +msgid "switch `m' requires a value" +msgstr "" + +#: builtin/merge.c:128 +#, c-format +msgid "Could not find merge strategy '%s'.\n" +msgstr "" + +#: builtin/merge.c:129 +#, c-format +msgid "Available strategies are:" +msgstr "" + +#: builtin/merge.c:134 +#, c-format +msgid "Available custom strategies are:" +msgstr "" + +#: builtin/merge.c:241 +msgid "could not run stash." +msgstr "" + +#: builtin/merge.c:246 +msgid "stash failed" +msgstr "" + +#: builtin/merge.c:251 +#, c-format +msgid "not a valid object: %s" +msgstr "" + +#: builtin/merge.c:270 builtin/merge.c:287 +msgid "read-tree failed" +msgstr "" + +#: builtin/merge.c:317 +msgid " (nothing to squash)" +msgstr "" + +#: builtin/merge.c:330 +#, c-format +msgid "Squash commit -- not updating HEAD\n" +msgstr "" + +#: builtin/merge.c:362 +msgid "Writing SQUASH_MSG" +msgstr "" + +#: builtin/merge.c:364 +msgid "Finishing SQUASH_MSG" +msgstr "" + +#: builtin/merge.c:386 +#, c-format +msgid "No merge message -- not updating HEAD\n" +msgstr "" + +#: builtin/merge.c:437 +#, c-format +msgid "'%s' does not point to a commit" +msgstr "" + +#: builtin/merge.c:536 +#, c-format +msgid "Bad branch.%s.mergeoptions string: %s" +msgstr "" + +#: builtin/merge.c:629 +msgid "git write-tree failed to write a tree" +msgstr "" + +#: builtin/merge.c:679 +msgid "failed to read the cache" +msgstr "" + +#: builtin/merge.c:696 +msgid "Unable to write index." +msgstr "" + +#: builtin/merge.c:709 +msgid "Not handling anything other than two heads merge." +msgstr "" + +#: builtin/merge.c:723 +#, c-format +msgid "Unknown option for merge-recursive: -X%s" +msgstr "" + +#: builtin/merge.c:737 +#, c-format +msgid "unable to write %s" +msgstr "" + +#: builtin/merge.c:876 +#, c-format +msgid "Could not read from '%s'" +msgstr "" + +#: builtin/merge.c:885 +#, c-format +msgid "Not committing merge; use 'git commit' to complete the merge.\n" +msgstr "" + +#: builtin/merge.c:891 +msgid "" +"Please enter a commit message to explain why this merge is necessary,\n" +"especially if it merges an updated upstream into a topic branch.\n" +"\n" +"Lines starting with '#' will be ignored, and an empty message aborts\n" +"the commit.\n" +msgstr "" + +#: builtin/merge.c:915 +msgid "Empty commit message." +msgstr "" + +#: builtin/merge.c:927 +#, c-format +msgid "Wonderful.\n" +msgstr "" + +#: builtin/merge.c:1000 +#, c-format +msgid "Automatic merge failed; fix conflicts and then commit the result.\n" +msgstr "" + +#: builtin/merge.c:1016 +#, c-format +msgid "'%s' is not a commit" +msgstr "" + +#: builtin/merge.c:1057 +msgid "No current branch." +msgstr "" + +#: builtin/merge.c:1059 +msgid "No remote for the current branch." +msgstr "" + +#: builtin/merge.c:1061 +msgid "No default upstream defined for the current branch." +msgstr "" + +#: builtin/merge.c:1066 +#, c-format +msgid "No remote tracking branch for %s from %s" +msgstr "" + +#: builtin/merge.c:1188 +msgid "There is no merge to abort (MERGE_HEAD missing)." +msgstr "" + +#: builtin/merge.c:1204 git-pull.sh:31 +msgid "" +"You have not concluded your merge (MERGE_HEAD exists).\n" +"Please, commit your changes before you can merge." +msgstr "" + +#: builtin/merge.c:1207 git-pull.sh:34 +msgid "You have not concluded your merge (MERGE_HEAD exists)." +msgstr "" + +#: builtin/merge.c:1211 +msgid "" +"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n" +"Please, commit your changes before you can merge." +msgstr "" + +#: builtin/merge.c:1214 +msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)." +msgstr "" + +#: builtin/merge.c:1223 +msgid "You cannot combine --squash with --no-ff." +msgstr "" + +#: builtin/merge.c:1228 +msgid "You cannot combine --no-ff with --ff-only." +msgstr "" + +#: builtin/merge.c:1235 +msgid "No commit specified and merge.defaultToUpstream not set." +msgstr "" + +#: builtin/merge.c:1266 +msgid "Can merge only exactly one commit into empty head" +msgstr "" + +#: builtin/merge.c:1269 +msgid "Squash commit into empty head not supported yet" +msgstr "" + +#: builtin/merge.c:1271 +msgid "Non-fast-forward commit does not make sense into an empty head" +msgstr "" + +#: builtin/merge.c:1275 builtin/merge.c:1319 +#, c-format +msgid "%s - not something we can merge" +msgstr "" + +#: builtin/merge.c:1385 +#, c-format +msgid "Updating %s..%s\n" +msgstr "" + +#: builtin/merge.c:1423 +#, c-format +msgid "Trying really trivial in-index merge...\n" +msgstr "" + +#: builtin/merge.c:1430 +#, c-format +msgid "Nope.\n" +msgstr "" + +#: builtin/merge.c:1462 +msgid "Not possible to fast-forward, aborting." +msgstr "" + +#: builtin/merge.c:1485 builtin/merge.c:1562 +#, c-format +msgid "Rewinding the tree to pristine...\n" +msgstr "" + +#: builtin/merge.c:1489 +#, c-format +msgid "Trying merge strategy %s...\n" +msgstr "" + +#: builtin/merge.c:1553 +#, c-format +msgid "No merge strategy handled the merge.\n" +msgstr "" + +#: builtin/merge.c:1555 +#, c-format +msgid "Merge with strategy %s failed.\n" +msgstr "" + +#: builtin/merge.c:1564 +#, c-format +msgid "Using the %s to prepare resolving by hand.\n" +msgstr "" + +#: builtin/merge.c:1575 +#, c-format +msgid "Automatic merge went well; stopped before committing as requested\n" +msgstr "" + +#: builtin/mv.c:108 +#, c-format +msgid "Checking rename of '%s' to '%s'\n" +msgstr "" + +#: builtin/mv.c:112 +msgid "bad source" +msgstr "" + +#: builtin/mv.c:115 +msgid "can not move directory into itself" +msgstr "" + +#: builtin/mv.c:118 +msgid "cannot move directory over file" +msgstr "" + +#: builtin/mv.c:128 +#, c-format +msgid "Huh? %.*s is in index?" +msgstr "" + +#: builtin/mv.c:140 +msgid "source directory is empty" +msgstr "" + +#: builtin/mv.c:171 +msgid "not under version control" +msgstr "" + +#: builtin/mv.c:173 +msgid "destination exists" +msgstr "" + +#: builtin/mv.c:181 +#, c-format +msgid "overwriting '%s'" +msgstr "" + +#: builtin/mv.c:184 +msgid "Cannot overwrite" +msgstr "" + +#: builtin/mv.c:187 +msgid "multiple sources for the same target" +msgstr "" + +#: builtin/mv.c:202 +#, c-format +msgid "%s, source=%s, destination=%s" +msgstr "" + +#: builtin/mv.c:212 +#, c-format +msgid "Renaming %s to %s\n" +msgstr "" + +#: builtin/mv.c:215 +#, c-format +msgid "renaming '%s' failed" +msgstr "" + +#: builtin/notes.c:139 +#, c-format +msgid "unable to start 'show' for object '%s'" +msgstr "" + +#: builtin/notes.c:145 +msgid "can't fdopen 'show' output fd" +msgstr "" + +#: builtin/notes.c:155 +#, c-format +msgid "failed to close pipe to 'show' for object '%s'" +msgstr "" + +#: builtin/notes.c:158 +#, c-format +msgid "failed to finish 'show' for object '%s'" +msgstr "" + +#: builtin/notes.c:175 builtin/tag.c:343 +#, c-format +msgid "could not create file '%s'" +msgstr "" + +#: builtin/notes.c:189 +msgid "Please supply the note contents using either -m or -F option" +msgstr "" + +#: builtin/notes.c:210 builtin/notes.c:973 +#, c-format +msgid "Removing note for object %s\n" +msgstr "" + +#: builtin/notes.c:215 +msgid "unable to write note object" +msgstr "" + +#: builtin/notes.c:217 +#, c-format +msgid "The note contents has been left in %s" +msgstr "" + +#: builtin/notes.c:251 builtin/tag.c:521 +#, c-format +msgid "cannot read '%s'" +msgstr "" + +#: builtin/notes.c:253 builtin/tag.c:524 +#, c-format +msgid "could not open or read '%s'" +msgstr "" + +#: builtin/notes.c:272 builtin/notes.c:445 builtin/notes.c:447 +#: builtin/notes.c:507 builtin/notes.c:561 builtin/notes.c:644 +#: builtin/notes.c:649 builtin/notes.c:724 builtin/notes.c:766 +#: builtin/notes.c:968 builtin/reset.c:293 builtin/tag.c:537 +#, c-format +msgid "Failed to resolve '%s' as a valid ref." +msgstr "" + +#: builtin/notes.c:275 +#, c-format +msgid "Failed to read object '%s'." +msgstr "" + +#: builtin/notes.c:299 +msgid "Cannot commit uninitialized/unreferenced notes tree" +msgstr "" + +#: builtin/notes.c:340 +#, c-format +msgid "Bad notes.rewriteMode value: '%s'" +msgstr "" + +#: builtin/notes.c:350 +#, c-format +msgid "Refusing to rewrite notes in %s (outside of refs/notes/)" +msgstr "" + +#. TRANSLATORS: The first %s is the name of the +#. environment variable, the second %s is its value +#: builtin/notes.c:377 +#, c-format +msgid "Bad %s value: '%s'" +msgstr "" + +#: builtin/notes.c:441 +#, c-format +msgid "Malformed input line: '%s'." +msgstr "" + +#: builtin/notes.c:456 +#, c-format +msgid "Failed to copy notes from '%s' to '%s'" +msgstr "" + +#: builtin/notes.c:500 builtin/notes.c:554 builtin/notes.c:627 +#: builtin/notes.c:639 builtin/notes.c:712 builtin/notes.c:759 +#: builtin/notes.c:1033 +msgid "too many parameters" +msgstr "" + +#: builtin/notes.c:513 builtin/notes.c:772 +#, c-format +msgid "No note found for object %s." +msgstr "" + +#: builtin/notes.c:580 +#, c-format +msgid "" +"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite " +"existing notes" +msgstr "" + +#: builtin/notes.c:585 builtin/notes.c:662 +#, c-format +msgid "Overwriting existing notes for object %s\n" +msgstr "" + +#: builtin/notes.c:635 +msgid "too few parameters" +msgstr "" + +#: builtin/notes.c:656 +#, c-format +msgid "" +"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite " +"existing notes" +msgstr "" + +#: builtin/notes.c:668 +#, c-format +msgid "Missing notes on source object %s. Cannot copy." +msgstr "" + +#: builtin/notes.c:717 +#, c-format +msgid "" +"The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n" +"Please use 'git notes add -f -m/-F/-c/-C' instead.\n" +msgstr "" + +#: builtin/notes.c:971 +#, c-format +msgid "Object %s has no note\n" +msgstr "" + +#: builtin/notes.c:1103 +#, c-format +msgid "Unknown subcommand: %s" +msgstr "" + +#: builtin/pack-objects.c:2310 +#, c-format +msgid "unsupported index version %s" +msgstr "" + +#: builtin/pack-objects.c:2314 +#, c-format +msgid "bad index version '%s'" +msgstr "" + +#: builtin/pack-objects.c:2322 +#, c-format +msgid "option %s does not accept negative form" +msgstr "" + +#: builtin/pack-objects.c:2326 +#, c-format +msgid "unable to parse value '%s' for option %s" +msgstr "" + +#: builtin/push.c:44 +msgid "tag shorthand without <tag>" +msgstr "" + +#: builtin/push.c:63 +msgid "--delete only accepts plain target ref names" +msgstr "" + +#: builtin/push.c:73 +#, c-format +msgid "" +"You are not currently on a branch.\n" +"To push the history leading to the current (detached HEAD)\n" +"state now, use\n" +"\n" +" git push %s HEAD:<name-of-remote-branch>\n" +msgstr "" + +#: builtin/push.c:80 +#, c-format +msgid "" +"The current branch %s has no upstream branch.\n" +"To push the current branch and set the remote as upstream, use\n" +"\n" +" git push --set-upstream %s %s\n" +msgstr "" + +#: builtin/push.c:88 +#, c-format +msgid "The current branch %s has multiple upstream branches, refusing to push." +msgstr "" + +#: builtin/push.c:111 +msgid "" +"You didn't specify any refspecs to push, and push.default is \"nothing\"." +msgstr "" + +#: builtin/push.c:131 +#, c-format +msgid "Pushing to %s\n" +msgstr "" + +#: builtin/push.c:135 +#, c-format +msgid "failed to push some refs to '%s'" +msgstr "" + +#: builtin/push.c:143 +#, c-format +msgid "" +"To prevent you from losing history, non-fast-forward updates were rejected\n" +"Merge the remote changes (e.g. 'git pull') before pushing again. See the\n" +"'Note about fast-forwards' section of 'git push --help' for details.\n" +msgstr "" + +#: builtin/push.c:160 +#, c-format +msgid "bad repository '%s'" +msgstr "" + +#: builtin/push.c:161 +msgid "" +"No configured push destination.\n" +"Either specify the URL from the command-line or configure a remote " +"repository using\n" +"\n" +" git remote add <name> <url>\n" +"\n" +"and then push using the remote name\n" +"\n" +" git push <name>\n" +msgstr "" + +#: builtin/push.c:176 +msgid "--all and --tags are incompatible" +msgstr "" + +#: builtin/push.c:177 +msgid "--all can't be combined with refspecs" +msgstr "" + +#: builtin/push.c:182 +msgid "--mirror and --tags are incompatible" +msgstr "" + +#: builtin/push.c:183 +msgid "--mirror can't be combined with refspecs" +msgstr "" + +#: builtin/push.c:188 +msgid "--all and --mirror are incompatible" +msgstr "" + +#: builtin/push.c:274 +msgid "--delete is incompatible with --all, --mirror and --tags" +msgstr "" + +#: builtin/push.c:276 +msgid "--delete doesn't make sense without any refs" +msgstr "" + +#: builtin/reset.c:33 +msgid "mixed" +msgstr "" + +#: builtin/reset.c:33 +msgid "soft" +msgstr "" + +#: builtin/reset.c:33 +msgid "hard" +msgstr "" + +#: builtin/reset.c:33 +msgid "keep" +msgstr "" + +#: builtin/reset.c:77 +msgid "You do not have a valid HEAD." +msgstr "" + +#: builtin/reset.c:79 +msgid "Failed to find tree of HEAD." +msgstr "" + +#: builtin/reset.c:85 +#, c-format +msgid "Failed to find tree of %s." +msgstr "" + +#: builtin/reset.c:96 +msgid "Could not write new index file." +msgstr "" + +#: builtin/reset.c:106 +#, c-format +msgid "HEAD is now at %s" +msgstr "" + +#: builtin/reset.c:130 +msgid "Could not read index" +msgstr "" + +#: builtin/reset.c:133 +msgid "Unstaged changes after reset:" +msgstr "" + +#: builtin/reset.c:223 +#, c-format +msgid "Cannot do a %s reset in the middle of a merge." +msgstr "" + +#: builtin/reset.c:297 +#, c-format +msgid "Could not parse object '%s'." +msgstr "" + +#: builtin/reset.c:302 +msgid "--patch is incompatible with --{hard,mixed,soft}" +msgstr "" + +#: builtin/reset.c:311 +msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead." +msgstr "" + +#: builtin/reset.c:313 +#, c-format +msgid "Cannot do %s reset with paths." +msgstr "" + +#: builtin/reset.c:325 +#, c-format +msgid "%s reset is not allowed in a bare repository" +msgstr "" + +#: builtin/reset.c:341 +#, c-format +msgid "Could not reset index file to revision '%s'." +msgstr "" + +#: builtin/revert.c:70 builtin/revert.c:91 +#, c-format +msgid "%s: %s cannot be used with %s" +msgstr "" + +#: builtin/revert.c:126 +msgid "program error" +msgstr "" + +#: builtin/revert.c:209 +msgid "revert failed" +msgstr "" + +#: builtin/revert.c:224 +msgid "cherry-pick failed" +msgstr "" + +#: builtin/rm.c:109 +#, c-format +msgid "" +"'%s' has staged content different from both the file and the HEAD\n" +"(use -f to force removal)" +msgstr "" + +#: builtin/rm.c:115 +#, c-format +msgid "" +"'%s' has changes staged in the index\n" +"(use --cached to keep the file, or -f to force removal)" +msgstr "" + +#: builtin/rm.c:119 +#, c-format +msgid "" +"'%s' has local modifications\n" +"(use --cached to keep the file, or -f to force removal)" +msgstr "" + +#: builtin/rm.c:194 +#, c-format +msgid "not removing '%s' recursively without -r" +msgstr "" + +#: builtin/rm.c:230 +#, c-format +msgid "git rm: unable to remove %s" +msgstr "" + +#: builtin/shortlog.c:157 +#, c-format +msgid "Missing author: %s" +msgstr "" + +#: builtin/tag.c:58 +#, c-format +msgid "malformed object at '%s'" +msgstr "" + +#: builtin/tag.c:205 +#, c-format +msgid "tag name too long: %.*s..." +msgstr "" + +#: builtin/tag.c:210 +#, c-format +msgid "tag '%s' not found." +msgstr "" + +#: builtin/tag.c:225 +#, c-format +msgid "Deleted tag '%s' (was %s)\n" +msgstr "" + +#: builtin/tag.c:237 +#, c-format +msgid "could not verify the tag '%s'" +msgstr "" + +#: builtin/tag.c:247 +msgid "" +"\n" +"#\n" +"# Write a tag message\n" +"# Lines starting with '#' will be ignored.\n" +"#\n" +msgstr "" + +#: builtin/tag.c:254 +msgid "" +"\n" +"#\n" +"# Write a tag message\n" +"# Lines starting with '#' will be kept; you may remove them yourself if you " +"want to.\n" +"#\n" +msgstr "" + +#: builtin/tag.c:294 +msgid "unable to sign the tag" +msgstr "" + +#: builtin/tag.c:296 +msgid "unable to write tag file" +msgstr "" + +#: builtin/tag.c:321 +msgid "bad object type." +msgstr "" + +#: builtin/tag.c:334 +msgid "tag header too big." +msgstr "" + +#: builtin/tag.c:366 +msgid "no tag message?" +msgstr "" + +#: builtin/tag.c:372 +#, c-format +msgid "The tag message has been left in %s\n" +msgstr "" + +#: builtin/tag.c:421 +msgid "switch 'points-at' requires an object" +msgstr "" + +#: builtin/tag.c:423 +#, c-format +msgid "malformed object name '%s'" +msgstr "" + +#: builtin/tag.c:502 +msgid "-n option is only allowed with -l." +msgstr "" + +#: builtin/tag.c:504 +msgid "--contains option is only allowed with -l." +msgstr "" + +#: builtin/tag.c:506 +msgid "--points-at option is only allowed with -l." +msgstr "" + +#: builtin/tag.c:514 +msgid "only one -F or -m option is allowed." +msgstr "" + +#: builtin/tag.c:534 +msgid "too many params" +msgstr "" + +#: builtin/tag.c:540 +#, c-format +msgid "'%s' is not a valid tag name." +msgstr "" + +#: builtin/tag.c:545 +#, c-format +msgid "tag '%s' already exists" +msgstr "" + +#: builtin/tag.c:563 +#, c-format +msgid "%s: cannot lock the ref" +msgstr "" + +#: builtin/tag.c:565 +#, c-format +msgid "%s: cannot update the ref" +msgstr "" + +#: builtin/tag.c:567 +#, c-format +msgid "Updated tag '%s' (was %s)\n" +msgstr "" + +#: git-am.sh:49 +msgid "You need to set your committer info first" +msgstr "" + +#: git-am.sh:136 +msgid "Repository lacks necessary blobs to fall back on 3-way merge." +msgstr "" + +#: git-am.sh:147 +msgid "" +"Did you hand edit your patch?\n" +"It does not apply to blobs recorded in its index." +msgstr "" + +#: git-am.sh:156 +msgid "Falling back to patching base and 3-way merge..." +msgstr "" + +#: git-am.sh:268 +msgid "Only one StGIT patch series can be applied at once" +msgstr "" + +#: git-am.sh:355 +#, sh-format +msgid "Patch format $patch_format is not supported." +msgstr "" + +#: git-am.sh:357 +msgid "Patch format detection failed." +msgstr "" + +#: git-am.sh:409 +msgid "-d option is no longer supported. Do not use." +msgstr "" + +#: git-am.sh:472 +#, sh-format +msgid "previous rebase directory $dotest still exists but mbox given." +msgstr "" + +#: git-am.sh:477 +msgid "Please make up your mind. --skip or --abort?" +msgstr "" + +#: git-am.sh:504 +msgid "Resolve operation not in progress, we are not resuming." +msgstr "" + +#: git-am.sh:570 +#, sh-format +msgid "Dirty index: cannot apply patches (dirty: $files)" +msgstr "" + +#: git-am.sh:746 +msgid "cannot be interactive without stdin connected to a terminal." +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:757 +msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " +msgstr "" + +#: git-am.sh:793 +#, sh-format +msgid "Applying: $FIRSTLINE" +msgstr "" + +#: git-am.sh:838 +msgid "No changes -- Patch already applied." +msgstr "" + +#: git-am.sh:864 +msgid "applying to an empty history" +msgstr "" + +#. TRANSLATORS: Make sure to include [Y] and [n] in your +#. translation. The program will only accept English input +#. at this point. +#: git-bisect.sh:54 +msgid "Do you want me to do it for you [Y/n]? " +msgstr "" + +#: git-bisect.sh:95 +#, sh-format +msgid "unrecognised option: '$arg'" +msgstr "" + +#: git-bisect.sh:99 +#, sh-format +msgid "'$arg' does not appear to be a valid revision" +msgstr "" + +#: git-bisect.sh:117 +msgid "Bad HEAD - I need a HEAD" +msgstr "" + +#: git-bisect.sh:130 +#, sh-format +msgid "" +"Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'." +msgstr "" + +#: git-bisect.sh:140 +msgid "won't bisect on seeked tree" +msgstr "" + +#: git-bisect.sh:144 +msgid "Bad HEAD - strange symbolic ref" +msgstr "" + +#: git-bisect.sh:189 +#, sh-format +msgid "Bad bisect_write argument: $state" +msgstr "" + +#: git-bisect.sh:218 +#, sh-format +msgid "Bad rev input: $arg" +msgstr "" + +#: git-bisect.sh:232 +msgid "Please call 'bisect_state' with at least one argument." +msgstr "" + +#: git-bisect.sh:244 +#, sh-format +msgid "Bad rev input: $rev" +msgstr "" + +#: git-bisect.sh:250 +msgid "'git bisect bad' can take only one argument." +msgstr "" + +#. TRANSLATORS: Make sure to include [Y] and [n] in your +#. translation. The program will only accept English input +#. at this point. +#: git-bisect.sh:279 +msgid "Are you sure [Y/n]? " +msgstr "" + +#: git-bisect.sh:354 +#, sh-format +msgid "'$invalid' is not a valid commit" +msgstr "" + +#: git-bisect.sh:363 +#, sh-format +msgid "" +"Could not check out original HEAD '$branch'.\n" +"Try 'git bisect reset <commit>'." +msgstr "" + +#: git-bisect.sh:390 +msgid "No logfile given" +msgstr "" + +#: git-bisect.sh:391 +#, sh-format +msgid "cannot read $file for replaying" +msgstr "" + +#: git-bisect.sh:408 +msgid "?? what are you talking about?" +msgstr "" + +#: git-bisect.sh:474 +msgid "We are not bisecting." +msgstr "" + +#: git-pull.sh:21 +msgid "" +"Pull is not possible because you have unmerged files.\n" +"Please, fix them up in the work tree, and then use 'git add/rm <file>'\n" +"as appropriate to mark resolution, or use 'git commit -a'." +msgstr "" + +#: git-pull.sh:25 +msgid "Pull is not possible because you have unmerged files." +msgstr "" + +#: git-pull.sh:197 +msgid "updating an unborn branch with changes added to the index" +msgstr "" + +#: git-pull.sh:253 +msgid "Cannot merge multiple branches into empty head" +msgstr "" + +#: git-pull.sh:257 +msgid "Cannot rebase onto multiple branches" +msgstr "" + +#: git-stash.sh:51 +msgid "git stash clear with parameters is unimplemented" +msgstr "" + +#: git-stash.sh:74 +msgid "You do not have the initial commit yet" +msgstr "" + +#: git-stash.sh:89 +msgid "Cannot save the current index state" +msgstr "" + +#: git-stash.sh:123 git-stash.sh:136 +msgid "Cannot save the current worktree state" +msgstr "" + +#: git-stash.sh:140 +msgid "No changes selected" +msgstr "" + +#: git-stash.sh:143 +msgid "Cannot remove temporary index (can't happen)" +msgstr "" + +#: git-stash.sh:156 +msgid "Cannot record working tree state" +msgstr "" + +#: git-stash.sh:223 +msgid "No local changes to save" +msgstr "" + +#: git-stash.sh:227 +msgid "Cannot initialize stash" +msgstr "" + +#: git-stash.sh:235 +msgid "Cannot save the current status" +msgstr "" + +#: git-stash.sh:253 +msgid "Cannot remove worktree changes" +msgstr "" + +#: git-stash.sh:352 +msgid "No stash found." +msgstr "" + +#: git-stash.sh:359 +#, sh-format +msgid "Too many revisions specified: $REV" +msgstr "" + +#: git-stash.sh:365 +#, sh-format +msgid "$reference is not valid reference" +msgstr "" + +#: git-stash.sh:393 +#, sh-format +msgid "'$args' is not a stash-like commit" +msgstr "" + +#: git-stash.sh:404 +#, sh-format +msgid "'$args' is not a stash reference" +msgstr "" + +#: git-stash.sh:412 +msgid "unable to refresh index" +msgstr "" + +#: git-stash.sh:416 +msgid "Cannot apply a stash in the middle of a merge" +msgstr "" + +#: git-stash.sh:424 +msgid "Conflicts in index. Try without --index." +msgstr "" + +#: git-stash.sh:426 +msgid "Could not save index tree" +msgstr "" + +#: git-stash.sh:460 +msgid "Cannot unstage modified files" +msgstr "" + +#: git-stash.sh:491 +#, sh-format +msgid "Dropped ${REV} ($s)" +msgstr "" + +#: git-stash.sh:492 +#, sh-format +msgid "${REV}: Could not drop stash entry" +msgstr "" + +#: git-stash.sh:499 +msgid "No branch name specified" +msgstr "" + +#: git-stash.sh:570 +msgid "(To restore them type \"git stash apply\")" +msgstr "" + +#: git-submodule.sh:56 +#, sh-format +msgid "cannot strip one component off url '$remoteurl'" +msgstr "" + +#: git-submodule.sh:108 +#, sh-format +msgid "No submodule mapping found in .gitmodules for path '$path'" +msgstr "" + +#: git-submodule.sh:173 +#, sh-format +msgid "Clone of '$url' into submodule path '$path' failed" +msgstr "" + +#: git-submodule.sh:247 +#, sh-format +msgid "repo URL: '$repo' must be absolute or begin with ./|../" +msgstr "" + +#: git-submodule.sh:264 +#, sh-format +msgid "'$path' already exists in the index" +msgstr "" + +#: git-submodule.sh:281 +#, sh-format +msgid "'$path' already exists and is not a valid git repo" +msgstr "" + +#: git-submodule.sh:295 +#, sh-format +msgid "Unable to checkout submodule '$path'" +msgstr "" + +#: git-submodule.sh:300 +#, sh-format +msgid "Failed to add submodule '$path'" +msgstr "" + +#: git-submodule.sh:305 +#, sh-format +msgid "Failed to register submodule '$path'" +msgstr "" + +#: git-submodule.sh:347 +#, sh-format +msgid "Entering '$prefix$path'" +msgstr "" + +#: git-submodule.sh:359 +#, sh-format +msgid "Stopping at '$path'; script returned non-zero status." +msgstr "" + +#: git-submodule.sh:401 +#, sh-format +msgid "No url found for submodule path '$path' in .gitmodules" +msgstr "" + +#: git-submodule.sh:410 +#, sh-format +msgid "Failed to register url for submodule path '$path'" +msgstr "" + +#: git-submodule.sh:418 +#, sh-format +msgid "Failed to register update mode for submodule path '$path'" +msgstr "" + +#: git-submodule.sh:420 +#, sh-format +msgid "Submodule '$name' ($url) registered for path '$path'" +msgstr "" + +#: git-submodule.sh:519 +#, sh-format +msgid "" +"Submodule path '$path' not initialized\n" +"Maybe you want to use 'update --init'?" +msgstr "" + +#: git-submodule.sh:532 +#, sh-format +msgid "Unable to find current revision in submodule path '$path'" +msgstr "" + +#: git-submodule.sh:551 +#, sh-format +msgid "Unable to fetch in submodule path '$path'" +msgstr "" + +#: git-submodule.sh:565 +#, sh-format +msgid "Unable to rebase '$sha1' in submodule path '$path'" +msgstr "" + +#: git-submodule.sh:566 +#, sh-format +msgid "Submodule path '$path': rebased into '$sha1'" +msgstr "" + +#: git-submodule.sh:571 +#, sh-format +msgid "Unable to merge '$sha1' in submodule path '$path'" +msgstr "" + +#: git-submodule.sh:572 +#, sh-format +msgid "Submodule path '$path': merged in '$sha1'" +msgstr "" + +#: git-submodule.sh:577 +#, sh-format +msgid "Unable to checkout '$sha1' in submodule path '$path'" +msgstr "" + +#: git-submodule.sh:578 +#, sh-format +msgid "Submodule path '$path': checked out '$sha1'" +msgstr "" + +#: git-submodule.sh:600 git-submodule.sh:923 +#, sh-format +msgid "Failed to recurse into submodule path '$path'" +msgstr "" + +#: git-submodule.sh:708 +msgid "--" +msgstr "" + +#: git-submodule.sh:766 +#, sh-format +msgid " Warn: $name doesn't contain commit $sha1_src" +msgstr "" + +#: git-submodule.sh:769 +#, sh-format +msgid " Warn: $name doesn't contain commit $sha1_dst" +msgstr "" + +#: git-submodule.sh:772 +#, sh-format +msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst" +msgstr "" + +#: git-submodule.sh:797 +msgid "blob" +msgstr "" + +#: git-submodule.sh:798 +msgid "submodule" +msgstr "" + +#: git-submodule.sh:969 +#, sh-format +msgid "Synchronizing submodule url for '$name'" +msgstr "" diff --git a/po/sv.po b/po/sv.po new file mode 100644 index 0000000000..0d778dc6e5 --- /dev/null +++ b/po/sv.po @@ -0,0 +1,3860 @@ +# Swedish translations for Git. +# Copyright (C) 2010-2012 Peter krefting <peter@softwolves.pp.se> +# This file is distributed under the same license as the Git package. +# Peter Krefting <peter@softwolves.pp.se>, 2010, 2011, 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: git 1.7.3\n" +"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" +"POT-Creation-Date: 2012-03-08 10:19+0800\n" +"PO-Revision-Date: 2012-03-08 10:53+0100\n" +"Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n" +"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: advice.c:34 +#, c-format +msgid "hint: %.*s\n" +msgstr "tips: %.*s\n" + +#. +#. * Message used both when 'git commit' fails and when +#. * other commands doing a merge do. +#. +#: advice.c:64 +msgid "" +"Fix them up in the work tree,\n" +"and then use 'git add/rm <file>' as\n" +"appropriate to mark resolution and make a commit,\n" +"or use 'git commit -a'." +msgstr "" +"Rätta dem i din arbetskatalog,\n" +"och använd sedan \"git add/rm <fil>\" som\n" +"lämpligt för att ange lösning och checka in,\n" +"eller använd \"git commit -a\"." + +#: commit.c:47 +#, c-format +msgid "could not parse %s" +msgstr "kunde inte tolka %s" + +#: commit.c:49 +#, c-format +msgid "%s %s is not a commit!" +msgstr "%s %s är inte en incheckning!" + +#: compat/obstack.c:406 compat/obstack.c:408 +msgid "memory exhausted" +msgstr "minnet slut" + +#: connected.c:39 +msgid "Could not run 'git rev-list'" +msgstr "Kunde inte köra \"git rev-list\"" + +#: connected.c:48 +#, c-format +msgid "failed write to rev-list: %s" +msgstr "kunde inte skriva till rev-list: %s" + +#: connected.c:56 +#, c-format +msgid "failed to close rev-list's stdin: %s" +msgstr "kunde inte stänga rev-list:s standard in: %s" + +#: diff.c:105 +#, c-format +msgid " Failed to parse dirstat cut-off percentage '%.*s'\n" +msgstr " Misslyckades tolka dirstat-avskärningsprocentandel \"%.*s\"\n" + +#: diff.c:110 +#, c-format +msgid " Unknown dirstat parameter '%.*s'\n" +msgstr " Okänd dirstat-parameter \"%.*s\"\n" + +#: diff.c:210 +#, c-format +msgid "" +"Found errors in 'diff.dirstat' config variable:\n" +"%s" +msgstr "" +"Hittade fel i konfigurationsvariabeln \"diff.dirstat\":\n" +"%s" + +#: diff.c:1336 +msgid " 0 files changed\n" +msgstr " 0 filer ändrade\n" + +#: diff.c:1340 +#, c-format +msgid " %d file changed" +msgid_plural " %d files changed" +msgstr[0] " %d fil ändrad" +msgstr[1] " %d filer ändrade" + +#: diff.c:1357 +#, c-format +msgid ", %d insertion(+)" +msgid_plural ", %d insertions(+)" +msgstr[0] ", %d tillägg(+)" +msgstr[1] ", %d tillägg(+)" + +#: diff.c:1368 +#, c-format +msgid ", %d deletion(-)" +msgid_plural ", %d deletions(-)" +msgstr[0] ", %d borttagning(-)" +msgstr[1] ", %d borttagningar(-)" + +#: diff.c:3424 +#, c-format +msgid "" +"Failed to parse --dirstat/-X option parameter:\n" +"%s" +msgstr "" +"Misslyckades tolka argument till flaggan --dirstat/-X;\n" +"%s" + +#: gpg-interface.c:59 +msgid "could not run gpg." +msgstr "kunde inte köra gpg." + +#: gpg-interface.c:71 +msgid "gpg did not accept the data" +msgstr "gpg godtog inte data" + +#: gpg-interface.c:82 +msgid "gpg failed to sign the data" +msgstr "gpg misslyckades signera data" + +#: grep.c:1280 +#, c-format +msgid "'%s': unable to read %s" +msgstr "\"%s\" kunde inte läsa %s" + +#: grep.c:1297 +#, c-format +msgid "'%s': %s" +msgstr "\"%s\": %s" + +#: grep.c:1308 +#, c-format +msgid "'%s': short read %s" +msgstr "\"%s\": kort läsning %s" + +#: help.c:287 +#, 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 "" +"\"%s\" verkar vara ett git-kommando, men vi kan inte\n" +"köra det. Kanske git-%s är trasigt?" + +#: remote.c:1607 +#, 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:1613 +#, 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] "" +"Din gren ligger efter \"%s\" med %d incheckning, och kan snabbspolas.\n" +msgstr[1] "" +"Din gren ligger efter \"%s\" med %d incheckningar, och kan snabbspolas.\n" + +#: remote.c:1621 +#, c-format +msgid "" +"Your branch and '%s' have diverged,\n" +"and have %d and %d different commit each, respectively.\n" +msgid_plural "" +"Your branch and '%s' have diverged,\n" +"and have %d and %d different commits each, respectively.\n" +msgstr[0] "" +"Din gren och \"%s\" har divergerat,\n" +"och har %d respektive %d olika incheckning.\n" +msgstr[1] "" +"Din gren och \"%s\" har divergerat,\n" +"och har %d respektive %d olika incheckningar.\n" + +#: sequencer.c:120 builtin/merge.c:864 builtin/merge.c:985 +#: builtin/merge.c:1095 builtin/merge.c:1105 +#, c-format +msgid "Could not open '%s' for writing" +msgstr "Kunde inte öppna \"%s\" för skrivning" + +#: sequencer.c:122 builtin/merge.c:334 builtin/merge.c:867 +#: builtin/merge.c:1097 builtin/merge.c:1110 +#, c-format +msgid "Could not write to '%s'" +msgstr "Kunde inte skriva till \"%s\"" + +#: sequencer.c:143 +msgid "" +"after resolving the conflicts, mark the corrected paths\n" +"with 'git add <paths>' or 'git rm <paths>'" +msgstr "" +"efter att ha löst konflikterna, markera de rättade sökvägarna\n" +"med \"git add <sökvägar>\" eller \"git rm <sökvägar>\"" + +#: sequencer.c:146 +msgid "" +"after resolving the conflicts, mark the corrected paths\n" +"with 'git add <paths>' or 'git rm <paths>'\n" +"and commit the result with 'git commit'" +msgstr "" +"efter att ha löst konflikterna, markera de rättade sökvägarna\n" +"med \"git add <sökvägar>\" eller \"git rm <sökvägar>\"\n" +"och checka in resultatet med \"git commit\"" + +#: sequencer.c:159 sequencer.c:685 sequencer.c:768 +#, c-format +msgid "Could not write to %s" +msgstr "Kunde inte skriva till %s" + +#: sequencer.c:162 +#, c-format +msgid "Error wrapping up %s" +msgstr "Fel vid ombrytning av %s" + +#: sequencer.c:177 +msgid "Your local changes would be overwritten by cherry-pick." +msgstr "Dina lokala ändringar skulle skrivas över av \"cherry-pick\"." + +#: sequencer.c:179 +msgid "Your local changes would be overwritten by revert." +msgstr "Dina lokala ändringar skulle skrivas över av \"revert\"." + +#: sequencer.c:182 +msgid "Commit your changes or stash them to proceed." +msgstr "Checka in dina ändringar eller använd \"stash\" för att fortsätta." + +#. TRANSLATORS: %s will be "revert" or "cherry-pick" +#: sequencer.c:232 +#, c-format +msgid "%s: Unable to write new index file" +msgstr "%s: Kunde inte skriva ny indexfil" + +#: sequencer.c:298 +msgid "Your index file is unmerged." +msgstr "Din indexfil har inte slagits ihop." + +#: sequencer.c:301 +msgid "You do not have a valid HEAD" +msgstr "Du har ingen giltig HEAD" + +#: sequencer.c:316 +#, c-format +msgid "Commit %s is a merge but no -m option was given." +msgstr "Incheckning %s är en sammanslagning, men flaggan -m angavs inte." + +#: sequencer.c:324 +#, c-format +msgid "Commit %s does not have parent %d" +msgstr "Incheckning %s har inte förälder %d" + +#: sequencer.c:328 +#, c-format +msgid "Mainline was specified but commit %s is not a merge." +msgstr "Huvudlinje angavs, men incheckningen %s är inte en sammanslagning" + +#. TRANSLATORS: The first %s will be "revert" or +#. "cherry-pick", the second %s a SHA1 +#: sequencer.c:339 +#, c-format +msgid "%s: cannot parse parent commit %s" +msgstr "%s: kan inte tolka föräldraincheckningen %s" + +#: sequencer.c:343 +#, c-format +msgid "Cannot get commit message for %s" +msgstr "Kan inte hämta incheckningsmeddelande för %s" + +#: sequencer.c:427 +#, c-format +msgid "could not revert %s... %s" +msgstr "kunde inte ångra %s... %s" + +#: sequencer.c:428 +#, c-format +msgid "could not apply %s... %s" +msgstr "kunde inte applicera %s... %s" + +#: sequencer.c:450 sequencer.c:909 builtin/log.c:288 builtin/log.c:713 +#: builtin/log.c:1329 builtin/log.c:1548 builtin/merge.c:348 +#: builtin/shortlog.c:181 +msgid "revision walk setup failed" +msgstr "misslyckades skapa revisionstraversering" + +#: sequencer.c:453 +msgid "empty commit set passed" +msgstr "den angivna uppsättningen incheckningar är tom" + +#: sequencer.c:461 +#, c-format +msgid "git %s: failed to read the index" +msgstr "git %s: misslyckades läsa indexet" + +#: sequencer.c:466 +#, c-format +msgid "git %s: failed to refresh the index" +msgstr "git %s: misslyckades uppdatera indexet" + +#: sequencer.c:551 +#, c-format +msgid "Cannot %s during a %s" +msgstr "kan inte %s under en %s" + +#: sequencer.c:573 +#, c-format +msgid "Could not parse line %d." +msgstr "Kan inte tolka rad %d." + +#: sequencer.c:578 +msgid "No commits parsed." +msgstr "Inga incheckningar lästes." + +#: sequencer.c:591 +#, c-format +msgid "Could not open %s" +msgstr "Kunde inte öppna %s" + +#: sequencer.c:595 +#, c-format +msgid "Could not read %s." +msgstr "kunde inte läsa %s." + +#: sequencer.c:602 +#, c-format +msgid "Unusable instruction sheet: %s" +msgstr "Oanvändbart manus: %s" + +#: sequencer.c:630 +#, c-format +msgid "Invalid key: %s" +msgstr "Felaktig nyckel: %s" + +#: sequencer.c:633 +#, c-format +msgid "Invalid value for %s: %s" +msgstr "Felaktigt värde för %s: %s" + +#: sequencer.c:645 +#, c-format +msgid "Malformed options sheet: %s" +msgstr "Trasigt manus: %s" + +#: sequencer.c:666 +msgid "a cherry-pick or revert is already in progress" +msgstr "en \"cherry-pick\" eller \"revert\" pågår redan" + +#: sequencer.c:667 +msgid "try \"git cherry-pick (--continue | --quit | --abort)\"" +msgstr "testa \"git cherry-pick (--continue | --quit | --abort)\"" + +#: sequencer.c:671 +#, c-format +msgid "Could not create sequencer directory %s" +msgstr "Kunde inte skapa \"sequencer\"-katalogen \"%s\"" + +#: sequencer.c:687 sequencer.c:772 +#, c-format +msgid "Error wrapping up %s." +msgstr "Fel vid ombrytning av %s." + +#: sequencer.c:706 sequencer.c:840 +msgid "no cherry-pick or revert in progress" +msgstr "ingen \"cherry-pick\" eller \"revert\" pågår" + +#: sequencer.c:708 +msgid "cannot resolve HEAD" +msgstr "kan inte bestämma HEAD" + +#: sequencer.c:710 +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:732 +#, c-format +msgid "cannot open %s: %s" +msgstr "kan inte öppna %s: %s" + +#: sequencer.c:735 +#, c-format +msgid "cannot read %s: %s" +msgstr "kan inte läsa %s: %s" + +#: sequencer.c:736 +msgid "unexpected end of file" +msgstr "oväntat filslut" + +#: sequencer.c:742 +#, c-format +msgid "stored pre-cherry-pick HEAD file '%s' is corrupt" +msgstr "sparad HEAD-fil från före \"cherry-pick\", \"%s\", är trasig" + +#: sequencer.c:765 +#, c-format +msgid "Could not format %s." +msgstr "Kunde inte formatera %s." + +#: sequencer.c:927 +msgid "Can't revert as initial commit" +msgstr "Kan inte ångra som första incheckning" + +#: sequencer.c:928 +msgid "Can't cherry-pick into empty head" +msgstr "Kan inte göra \"cherry-pick\" i ett tomt huvud" + +#: wt-status.c:134 +msgid "Unmerged paths:" +msgstr "Ej sammanslagna sökvägar:" + +#: wt-status.c:140 wt-status.c:157 +#, 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:142 wt-status.c:159 +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:143 +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:151 +msgid "Changes to be committed:" +msgstr "Ändringar att checka in:" + +#: wt-status.c:169 +msgid "Changes not staged for commit:" +msgstr "Ändringar ej i incheckningskön:" + +#: wt-status.c:173 +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:175 +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:176 +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:178 +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"). +#: wt-status.c:187 +#, c-format +msgid "%s files:" +msgstr "%s filer:" + +#: wt-status.c:190 +#, 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)" + +#: wt-status.c:207 +msgid "bug" +msgstr "programfel" + +#: wt-status.c:212 +msgid "both deleted:" +msgstr "borttaget av bägge:" + +#: wt-status.c:213 +msgid "added by us:" +msgstr "tillagt av oss:" + +#: wt-status.c:214 +msgid "deleted by them:" +msgstr "borttaget av dem:" + +#: wt-status.c:215 +msgid "added by them:" +msgstr "tillagt av dem:" + +#: wt-status.c:216 +msgid "deleted by us:" +msgstr "borttaget av oss:" + +#: wt-status.c:217 +msgid "both added:" +msgstr "tillagt av bägge:" + +#: wt-status.c:218 +msgid "both modified:" +msgstr "ändrat av bägge:" + +#: wt-status.c:248 +msgid "new commits, " +msgstr "nya incheckningar, " + +#: wt-status.c:250 +msgid "modified content, " +msgstr "ändrat innehåll, " + +#: wt-status.c:252 +msgid "untracked content, " +msgstr "ospårat innehåll, " + +#: wt-status.c:266 +#, c-format +msgid "new file: %s" +msgstr "ny fil: %s" + +#: wt-status.c:269 +#, c-format +msgid "copied: %s -> %s" +msgstr "kopierad: %s -> %s" + +#: wt-status.c:272 +#, c-format +msgid "deleted: %s" +msgstr "borttagen: %s" + +#: wt-status.c:275 +#, c-format +msgid "modified: %s" +msgstr "ändrad: %s" + +#: wt-status.c:278 +#, c-format +msgid "renamed: %s -> %s" +msgstr "namnbyte: %s -> %s" + +#: wt-status.c:281 +#, c-format +msgid "typechange: %s" +msgstr "typbyte: %s" + +#: wt-status.c:284 +#, c-format +msgid "unknown: %s" +msgstr "okänd: %s" + +#: wt-status.c:287 +#, c-format +msgid "unmerged: %s" +msgstr "osammansl.: %s" + +#: wt-status.c:290 +#, c-format +msgid "bug: unhandled diff status %c" +msgstr "programfel: diff-status %c ej hanterad" + +#: wt-status.c:713 +msgid "On branch " +msgstr "På grenen " + +#: wt-status.c:720 +msgid "Not currently on any branch." +msgstr "Inte på någon gren för närvarande." + +#: wt-status.c:731 +msgid "Initial commit" +msgstr "Första incheckning" + +#: wt-status.c:745 +msgid "Untracked" +msgstr "Ospårad" + +#: wt-status.c:747 +msgid "Ignored" +msgstr "Ignorerad" + +# %s är nästa sträng eller tom. +#: wt-status.c:749 +#, c-format +msgid "Untracked files not listed%s" +msgstr "Ospårade filer visas ej%s" + +#: wt-status.c:751 +msgid " (use -u option to show untracked files)" +msgstr " (använd flaggan -u för att visa ospårade filer)" + +#: wt-status.c:757 +msgid "No changes" +msgstr "Inga ändringar" + +#: wt-status.c:761 +#, c-format +msgid "no changes added to commit%s\n" +msgstr "inga ändringar att checka in%s\n" + +#: wt-status.c:763 +msgid " (use \"git add\" and/or \"git commit -a\")" +msgstr " (använd \"git add\" och/eller \"git commit -a\")" + +#: wt-status.c:765 +#, 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:767 +msgid " (use \"git add\" to track)" +msgstr " (använd \"git add\" för att spåra)" + +#: wt-status.c:769 wt-status.c:772 wt-status.c:775 +#, c-format +msgid "nothing to commit%s\n" +msgstr "inget att checka in%s\n" + +#: wt-status.c:770 +msgid " (create/copy files and use \"git add\" to track)" +msgstr " (skapa/kopiera filer och använd \"git add\" för att spåra)" + +#: wt-status.c:773 +msgid " (use -u to show untracked files)" +msgstr " (använd -u för att visa ospårade filer)" + +#: wt-status.c:776 +msgid " (working directory clean)" +msgstr " (arbetskatalogen ren)" + +#: wt-status.c:884 +msgid "HEAD (no branch)" +msgstr "HEAD (ingen gren)" + +#: wt-status.c:890 +msgid "Initial commit on " +msgstr "Första incheckning på " + +#: wt-status.c:905 +msgid "behind " +msgstr "efter " + +#: wt-status.c:908 wt-status.c:911 +msgid "ahead " +msgstr "före " + +#: wt-status.c:913 +msgid ", behind " +msgstr ", efter " + +#: builtin/add.c:62 +#, c-format +msgid "unexpected diff status %c" +msgstr "diff-status %c förväntades inte" + +#: builtin/add.c:67 builtin/commit.c:298 +msgid "updating files failed" +msgstr "misslyckades uppdatera filer" + +#: builtin/add.c:77 +#, c-format +msgid "remove '%s'\n" +msgstr "ta bort \"%s\"\n" + +#: builtin/add.c:176 +#, c-format +msgid "Path '%s' is in submodule '%.*s'" +msgstr "Sökvägen \"%s\" är i undermodulen \"%.*s\"" + +#: builtin/add.c:192 +msgid "Unstaged changes after refreshing the index:" +msgstr "Ospårade ändringar efter att ha uppdaterat indexet:" + +#: builtin/add.c:195 builtin/add.c:456 builtin/rm.c:186 +#, c-format +msgid "pathspec '%s' did not match any files" +msgstr "sökvägsangivelsen \"%s\" motsvarade inte några filer" + +#: builtin/add.c:209 +#, c-format +msgid "'%s' is beyond a symbolic link" +msgstr "\"%s\" är på andra sidan av en symbolisk länk" + +#: builtin/add.c:276 +msgid "Could not read the index" +msgstr "Kunde inte läsa indexet" + +#: builtin/add.c:286 +#, c-format +msgid "Could not open '%s' for writing." +msgstr "Kunde inte öppna \"%s\" för skrivning" + +#: builtin/add.c:290 +msgid "Could not write patch" +msgstr "Kunde inte skriva patch" + +#: builtin/add.c:295 +#, c-format +msgid "Could not stat '%s'" +msgstr "Kunde inte ta status på \"%s\"" + +#: builtin/add.c:297 +msgid "Empty patch. Aborted." +msgstr "Tom patch. Avbryter." + +#: builtin/add.c:303 +#, c-format +msgid "Could not apply '%s'" +msgstr "Kunde inte applicera \"%s\"" + +#: builtin/add.c:312 +msgid "The following paths are ignored by one of your .gitignore files:\n" +msgstr "Följande sökvägar ignoreras av en av dina .gitignore-filer:\n" + +#: builtin/add.c:352 +#, c-format +msgid "Use -f if you really want to add them.\n" +msgstr "Använd -f om du verkligen vill lägga till dem.\n" + +#: builtin/add.c:353 +msgid "no files added" +msgstr "inga filer har lagts till" + +#: builtin/add.c:359 +msgid "adding files failed" +msgstr "misslyckades lägga till filer" + +#: builtin/add.c:391 +msgid "-A and -u are mutually incompatible" +msgstr "-A och -u är ömsesidigt inkompatibla" + +#: builtin/add.c:393 +msgid "Option --ignore-missing can only be used together with --dry-run" +msgstr "Flaggan --ignore-missing kan endast användas tillsammans med --dry-run" + +#: builtin/add.c:413 +#, c-format +msgid "Nothing specified, nothing added.\n" +msgstr "Inget angivet, inget tillagt.\n" + +#: builtin/add.c:414 +#, c-format +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:358 builtin/mv.c:82 +#: builtin/rm.c:162 +msgid "index file corrupt" +msgstr "indexfilen trasig" + +#: builtin/add.c:476 builtin/mv.c:229 builtin/rm.c:260 +msgid "Unable to write new index file" +msgstr "Kunde inte skriva ny indexfil" + +#: builtin/archive.c:17 +#, c-format +msgid "could not create archive file '%s'" +msgstr "Kunde inte skapa arkivfilen \"%s\"" + +#: builtin/archive.c:20 +msgid "could not redirect output" +msgstr "kunde inte omdirigera utdata" + +#: builtin/archive.c:37 +msgid "git archive: Remote with no URL" +msgstr "git archive: Fjärr utan URL" + +#: builtin/archive.c:58 +msgid "git archive: expected ACK/NAK, got EOF" +msgstr "git archive: förväntade ACK/NAK, fick EOF" + +#: builtin/archive.c:63 +#, c-format +msgid "git archive: NACK %s" +msgstr "git archive: NACK %s" + +#: builtin/archive.c:65 +#, c-format +msgid "remote error: %s" +msgstr "fjärrfel: %s" + +#: builtin/archive.c:66 +msgid "git archive: protocol error" +msgstr "git archive: protokollfel" + +#: builtin/archive.c:71 +msgid "git archive: expected a flush" +msgstr "git archive: förväntade en tömning (flush)" + +#: builtin/branch.c:137 +#, c-format +msgid "" +"deleting branch '%s' that has been merged to\n" +" '%s', but not yet merged to HEAD." +msgstr "" +"tar bort grenen \"%s\" som har slagits ihop med\n" +" \"%s\", men ännu inte slagits ihop med HEAD." + +#: builtin/branch.c:141 +#, c-format +msgid "" +"not deleting branch '%s' that is not yet merged to\n" +" '%s', even though it is merged to HEAD." +msgstr "" +"tar inte bort grenen \"%s\" som inte har slagits ihop med\n" +" \"%s\", trots att den har slagits ihop med HEAD." + +#. TRANSLATORS: This is "remote " in "remote branch '%s' not found" +#: builtin/branch.c:163 +msgid "remote " +msgstr "fjärr" + +#: builtin/branch.c:171 +msgid "cannot use -a with -d" +msgstr "kan inte ange -a med -d" + +#: builtin/branch.c:177 +msgid "Couldn't look up commit object for HEAD" +msgstr "Kunde inte slå upp incheckningsobjekt för HEAD" + +#: builtin/branch.c:182 +#, c-format +msgid "Cannot delete the branch '%s' which you are currently on." +msgstr "Kan inte ta bort grenen \"%s\" som du befinner dig på för närvarande." + +#: builtin/branch.c:192 +#, c-format +msgid "%sbranch '%s' not found." +msgstr "%sgrenen \"%s\" hittades inte." + +#: builtin/branch.c:200 +#, c-format +msgid "Couldn't look up commit object for '%s'" +msgstr "Kunde inte slå upp incheckningsobjekt för \"%s\"" + +#: builtin/branch.c:206 +#, c-format +msgid "" +"The branch '%s' is not fully merged.\n" +"If you are sure you want to delete it, run 'git branch -D %s'." +msgstr "" +"Grenen \"%s\" har inte slagits samman i sin helhet.\n" +"Om du är säker på att du vill ta bort den, kör \"git branch -D %s\"." + +#: builtin/branch.c:214 +#, c-format +msgid "Error deleting %sbranch '%s'" +msgstr "Fel vid borttagning av %sgrenen \"%s\"" + +#: builtin/branch.c:219 +#, c-format +msgid "Deleted %sbranch %s (was %s).\n" +msgstr "Tog bort %sgrenen %s (var %s).\n" + +#: builtin/branch.c:224 +msgid "Update of config-file failed" +msgstr "Misslyckades uppdatera konfigurationsfil" + +#: builtin/branch.c:322 +#, c-format +msgid "branch '%s' does not point at a commit" +msgstr "grenen \"%s\" pekar inte på en incheckning" + +#: builtin/branch.c:394 +#, c-format +msgid "behind %d] " +msgstr "bakom %d] " + +#: builtin/branch.c:396 +#, c-format +msgid "ahead %d] " +msgstr "före %d] " + +#: builtin/branch.c:398 +#, c-format +msgid "ahead %d, behind %d] " +msgstr "före %d, bakom %d] " + +#: builtin/branch.c:501 +msgid "(no branch)" +msgstr "(ingen gren)" + +#: builtin/branch.c:566 +msgid "some refs could not be read" +msgstr "vissa referenser kunde inte läsas" + +#: builtin/branch.c:579 +msgid "cannot rename the current branch while not on any." +msgstr "" +"kunde inte byta namn på aktuell gren när du inte befinner dig på någon." + +#: builtin/branch.c:589 +#, c-format +msgid "Invalid branch name: '%s'" +msgstr "Felaktigt namn på gren: \"%s\"" + +#: builtin/branch.c:604 +msgid "Branch rename failed" +msgstr "Misslyckades byta namn på gren" + +#: builtin/branch.c:608 +#, c-format +msgid "Renamed a misnamed branch '%s' away" +msgstr "Bytte bort namn på en felaktigt namngiven gren \"%s\"" + +#: builtin/branch.c:612 +#, c-format +msgid "Branch renamed to %s, but HEAD is not updated!" +msgstr "Grenen namnbytt till %s, men HEAD har inte uppdaterats!" + +#: builtin/branch.c:619 +msgid "Branch is renamed, but update of config-file failed" +msgstr "Grenen namnbytt, men misslyckades uppdatera konfigurationsfilen" + +#: builtin/branch.c:634 +#, c-format +msgid "malformed object name %s" +msgstr "felformat objektnamn %s" + +#: builtin/branch.c:658 +#, c-format +msgid "could not write branch description template: %s\n" +msgstr "kunde inte skriva grenbeskrivningsmall: %s\n" + +#: builtin/branch.c:746 +msgid "Failed to resolve HEAD as a valid ref." +msgstr "Misslyckades slå upp HEAD som giltig referens" + +#: builtin/branch.c:751 builtin/clone.c:558 +msgid "HEAD not found below refs/heads!" +msgstr "HEAD hittades inte under refs/heads!" + +#: builtin/branch.c:809 +msgid "-a and -r options to 'git branch' do not make sense with a branch name" +msgstr "" +"flaggorna -a och -r på \"git branch\" kan inte anges tillsammans med ett " +"grennamn" + +#: builtin/bundle.c:47 +#, c-format +msgid "%s is okay\n" +msgstr "%s är okej\n" + +#: builtin/bundle.c:56 +msgid "Need a repository to create a bundle." +msgstr "Behöver ett arkiv för att skapa ett paket (bundle)." + +#: builtin/bundle.c:60 +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 +#, 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 +#, c-format +msgid "path '%s' does not have their version" +msgstr "sökvägen \"%s\" har inte deras version" + +#: builtin/checkout.c:131 +#, 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 +#, 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 +#, c-format +msgid "path '%s': cannot merge" +msgstr "sökväg \"%s\": kan inte slå ihop" + +#: builtin/checkout.c:209 +#, c-format +msgid "Unable to add merge result for '%s'" +msgstr "Kunde inte lägga till sammanslagningsresultat för \"%s\"" + +#: builtin/checkout.c:212 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/checkout.c:234 builtin/checkout.c:392 +msgid "corrupt index file" +msgstr "indexfilen är trasig" + +#: builtin/checkout.c:264 builtin/checkout.c:271 +#, 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/merge.c:811 +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 +msgid "diff_setup_done failed" +msgstr "diff_setup_done misslyckades" + +#: builtin/checkout.c:414 +msgid "you need to resolve your current index first" +msgstr "du måste lösa ditt befintliga index först" + +#: builtin/checkout.c:533 +#, c-format +msgid "Can not do reflog for '%s'\n" +msgstr "Kan inte skapa referenslog för \"%s\"\n" + +#: builtin/checkout.c:565 +msgid "HEAD is now at" +msgstr "HEAD är nu på" + +#: builtin/checkout.c:572 +#, c-format +msgid "Reset branch '%s'\n" +msgstr "Återställ gren \"%s\"\n" + +#: builtin/checkout.c:575 +#, c-format +msgid "Already on '%s'\n" +msgstr "Redan på \"%s\"\n" + +#: builtin/checkout.c:579 +#, c-format +msgid "Switched to and reset branch '%s'\n" +msgstr "Växlade till och nollställde grenen \"%s\"\n" + +#: builtin/checkout.c:581 +#, c-format +msgid "Switched to a new branch '%s'\n" +msgstr "Växlade till en ny gren \"%s\"\n" + +#: builtin/checkout.c:583 +#, c-format +msgid "Switched to branch '%s'\n" +msgstr "Växlade till grenen \"%s\"\n" + +#: builtin/checkout.c:639 +#, c-format +msgid " ... and %d more.\n" +msgstr " ... och %d till.\n" + +#. The singular version +#: builtin/checkout.c:645 +#, c-format +msgid "" +"Warning: you are leaving %d commit behind, not connected to\n" +"any of your branches:\n" +"\n" +"%s\n" +msgid_plural "" +"Warning: you are leaving %d commits behind, not connected to\n" +"any of your branches:\n" +"\n" +"%s\n" +msgstr[0] "" +"Varning: du lämnar %d incheckning bakom dig som inte är ansluten till\n" +"någon av dina grenar:\n" +"\n" +"%s\n" +msgstr[1] "" +"Varning: du lämnar %d incheckningar bakom dig som inte är ansluta till\n" +"någon av dina grenar:\n" +"\n" +"%s\n" + +#: builtin/checkout.c:663 +#, c-format +msgid "" +"If you want to keep them by creating a new branch, this may be a good time\n" +"to do so with:\n" +"\n" +" git branch new_branch_name %s\n" +"\n" +msgstr "" +"Om du vill behålla dem genom att skapa en ny gren är nu en bra tidpunkt\n" +"att göra så, med:\n" +"\n" +" git branch nytt_grennamn %s\n" +"\n" + +#: builtin/checkout.c:692 +msgid "internal error in revision walk" +msgstr "internt fel vid genomgång av revisioner (revision walk)" + +#: builtin/checkout.c:696 +msgid "Previous HEAD position was" +msgstr "Tidigare position för HEAD var" + +#: builtin/checkout.c:722 +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:853 +#, c-format +msgid "invalid reference: %s" +msgstr "felaktig referens: %s" + +#. case (1): want a tree +#: builtin/checkout.c:892 +#, c-format +msgid "reference is not a tree: %s" +msgstr "referensen är inte ett träd: %s" + +#: builtin/checkout.c:972 +msgid "-B cannot be used with -b" +msgstr "-B kan inte användas med -b" + +#: builtin/checkout.c:981 +msgid "--patch is incompatible with all other options" +msgstr "--patch är inkompatibel med alla andra flaggor" + +#: builtin/checkout.c:984 +msgid "--detach cannot be used with -b/-B/--orphan" +msgstr "--detcah kan inte användas med -b/-B/--orphan" + +#: builtin/checkout.c:986 +msgid "--detach cannot be used with -t" +msgstr "--detach kan inte användas med -t" + +#: builtin/checkout.c:992 +msgid "--track needs a branch name" +msgstr "--track behöver ett namn på en gren" + +#: builtin/checkout.c:999 +msgid "Missing branch name; try -b" +msgstr "Grennamn saknas; försök med -b" + +#: builtin/checkout.c:1005 +msgid "--orphan and -b|-B are mutually exclusive" +msgstr "--orphan och -b|-B kan inte användas samtidigt" + +#: builtin/checkout.c:1007 +msgid "--orphan cannot be used with -t" +msgstr "--orphan kan inte användas med -t" + +#: builtin/checkout.c:1017 +msgid "git checkout: -f and -m are incompatible" +msgstr "git checkout: -f och -m är inkompatibla" + +#: builtin/checkout.c:1051 +msgid "invalid path specification" +msgstr "felaktig sökvägsangivelse" + +#: builtin/checkout.c:1059 +#, 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 "" +"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:1061 +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:1066 +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:1069 +msgid "" +"git checkout: --ours/--theirs, --force and --merge are incompatible when\n" +"checking out of the index." +msgstr "" +"git checkout: --ours/--theirs, --force och --merge är inkompatibla när\n" +"du checkar ut från indexet." + +#: builtin/checkout.c:1088 +msgid "Cannot switch branch to a non-commit." +msgstr "Kan inte växla gren på en icke-incheckning." + +#: builtin/checkout.c:1091 +msgid "--ours/--theirs is incompatible with switching branches." +msgstr "--ours/--theirs är inkompatibla med att byta gren." + +#: builtin/clean.c:78 +msgid "-x and -X cannot be used together" +msgstr "-x och -X kan inte användas samtidigt" + +#: builtin/clean.c:82 +msgid "" +"clean.requireForce set to true and neither -n nor -f given; refusing to clean" +msgstr "" +"clean.requireForce satt till true, men varken -n eller -f angavs; vägrar " +"städa" + +#: builtin/clean.c:85 +msgid "" +"clean.requireForce defaults to true and neither -n nor -f given; refusing to " +"clean" +msgstr "" +"clean.requireForce har standardvärdet true, men varken -n eller -f angavs; " +"vägrar städa" + +#: builtin/clean.c:155 builtin/clean.c:176 +#, c-format +msgid "Would remove %s\n" +msgstr "Skulle ta bort %s\n" + +#: builtin/clean.c:159 builtin/clean.c:179 +#, c-format +msgid "Removing %s\n" +msgstr "Tar bort %s\n" + +#: builtin/clean.c:162 builtin/clean.c:182 +#, c-format +msgid "failed to remove %s" +msgstr "misslyckades ta bort %s" + +#: builtin/clean.c:166 +#, c-format +msgid "Would not remove %s\n" +msgstr "Skulle inte ta bort %s\n" + +#: builtin/clean.c:168 +#, c-format +msgid "Not removing %s\n" +msgstr "Tar inte bort %s\n" + +#: builtin/clone.c:243 +#, c-format +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'" +msgstr "misslyckades skapa katalogen \"%s\"" + +#: builtin/clone.c:308 builtin/diff.c:75 +#, c-format +msgid "failed to stat '%s'" +msgstr "misslyckades ta status på \"%s\"" + +#: builtin/clone.c:310 +#, c-format +msgid "%s exists and is not a directory" +msgstr "%s finns och är ingen katalog" + +#: builtin/clone.c:324 +#, c-format +msgid "failed to stat %s\n" +msgstr "misslyckades ta status på %s\n" + +#: builtin/clone.c:341 +#, c-format +msgid "failed to unlink '%s'" +msgstr "misslyckades ta bort länken \"%s\"" + +#: builtin/clone.c:346 +#, c-format +msgid "failed to create link '%s'" +msgstr "misslyckades skapa länken \"%s\"" + +#: builtin/clone.c:350 +#, c-format +msgid "failed to copy file to '%s'" +msgstr "misslyckades kopiera filen till \"%s\"" + +#: builtin/clone.c:373 +#, c-format +msgid "done.\n" +msgstr "klart.\n" + +#: builtin/clone.c:440 +#, 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 +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 +msgid "Too many arguments." +msgstr "För många argument." + +#: builtin/clone.c:643 +msgid "You must specify a repository to clone." +msgstr "Du måste ange ett arkiv att klona." + +#: builtin/clone.c:654 +#, c-format +msgid "--bare and --origin %s options are incompatible." +msgstr "flaggorna --bare och --origin %s är inkompatibla." + +#: builtin/clone.c:668 +#, c-format +msgid "repository '%s' does not exist" +msgstr "arkivet \"%s\" finns inte" + +#: builtin/clone.c:673 +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 +#, 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 +#, c-format +msgid "working tree '%s' already exists." +msgstr "arbetsträdet \"%s\" finns redan." + +#: builtin/clone.c:706 builtin/clone.c:720 +#, c-format +msgid "could not create leading directories of '%s'" +msgstr "kunde inte skapa inledande kataloger för \"%s\"" + +#: builtin/clone.c:709 +#, c-format +msgid "could not create work tree dir '%s'." +msgstr "kunde inte skapa arbetskatalogen \"%s\"" + +#: builtin/clone.c:728 +#, c-format +msgid "Cloning into bare repository '%s'...\n" +msgstr "Klonar till ett naket arkiv \"%s\"...\n" + +#: builtin/clone.c:730 +#, c-format +msgid "Cloning into '%s'...\n" +msgstr "Klonar till \"%s\"...\n" + +#: builtin/clone.c:786 +#, c-format +msgid "Don't know how to clone %s" +msgstr "Vet inte hur man klonar %s" + +#: builtin/clone.c:835 +#, 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 +msgid "You appear to have cloned an empty repository." +msgstr "Du verkar ha klonat ett tomt arkiv." + +#: builtin/commit.c:42 +msgid "" +"Your name and email address were configured automatically based\n" +"on your username and hostname. Please check that they are accurate.\n" +"You can suppress this message by setting them explicitly:\n" +"\n" +" git config --global user.name \"Your Name\"\n" +" git config --global user.email you@example.com\n" +"\n" +"After doing this, you may fix the identity used for this commit with:\n" +"\n" +" git commit --amend --reset-author\n" +msgstr "" +"Ditt namn och e-postadress konfigurerades automatiskt baserat på\n" +"ditt användar-id och värdnamn. Kontrollera att de är riktiga. Du\n" +"kan förhindra det här meddelandet genom att ställa dem explicit:\n" +"\n" +" git config --global user.name \"Ditt namn\"\n" +" git config --global user.email du@example.com\n" +"\n" +"När du gjort det kan du rätta identiteten som användes för den här\n" +"incheckningen med:\n" +"\n" +" git commit --amend --reset-author\n" + +#: builtin/commit.c:54 +msgid "" +"You asked to amend the most recent commit, but doing so would make\n" +"it empty. You can repeat your command with --allow-empty, or you can\n" +"remove the commit entirely with \"git reset HEAD^\".\n" +msgstr "" +"Du bad om att utöka den senaste incheckningen, men om du gör det\n" +"blir den tom. Du kan köra kommandot på nytt med --allow-empty, eller\n" +"så kan du ta bort incheckningen helt med \"git reset HEAD^\".\n" + +#: builtin/commit.c:59 +msgid "" +"The previous cherry-pick is now empty, possibly due to conflict resolution.\n" +"If you wish to commit it anyway, use:\n" +"\n" +" git commit --allow-empty\n" +"\n" +"Otherwise, please use 'git reset'\n" +msgstr "" +"Den tidigare \"cherry-pick\":en är nu tom, kanske på grund av en löst\n" +"konflikt. Om du vill checka in den ändå använder du:\n" +"\n" +" git commit --allow-empty\n" +"\n" +"Annars använder du \"git reset\"\n" + +#: builtin/commit.c:205 builtin/reset.c:33 +msgid "merge" +msgstr "sammanslagning" + +#: builtin/commit.c:208 +msgid "cherry-pick" +msgstr "cherry-pick" + +#: builtin/commit.c:325 +msgid "failed to unpack HEAD tree object" +msgstr "misslyckades packa upp HEAD:s trädobjekt" + +#: builtin/commit.c:367 +msgid "unable to create temporary index" +msgstr "kunde inte skapa temporär indexfil" + +#: builtin/commit.c:373 +msgid "interactive add failed" +msgstr "interaktiv tilläggning misslyckades" + +#: builtin/commit.c:406 builtin/commit.c:427 builtin/commit.c:473 +msgid "unable to write new_index file" +msgstr "kunde inte skriva filen new_index" + +# %s är antingen "merge" eller "cherry-pick". +#: builtin/commit.c:457 +#, c-format +msgid "cannot do a partial commit during a %s." +msgstr "kan inte utföra en delvis incheckning under en %s" + +#: builtin/commit.c:466 +msgid "cannot read the index" +msgstr "kan inte läsa indexet" + +#: builtin/commit.c:486 +msgid "unable to write temporary index file" +msgstr "kunde inte skriva temporär indexfil" + +#: builtin/commit.c:550 builtin/commit.c:556 +#, c-format +msgid "invalid commit: %s" +msgstr "felaktig incheckning: %s" + +#: builtin/commit.c:579 +msgid "malformed --author parameter" +msgstr "felformad \"--author\"-flagga" + +#: builtin/commit.c:635 +#, c-format +msgid "Malformed ident string: '%s'" +msgstr "Felaktig indragningssträng: \"%s\"" + +#: builtin/commit.c:670 builtin/commit.c:703 builtin/commit.c:1000 +#, c-format +msgid "could not lookup commit %s" +msgstr "kunde inte slå upp incheckningen %s" + +#: builtin/commit.c:682 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:684 +msgid "could not read log from standard input" +msgstr "kunde inte läsa logg från standard in" + +#: builtin/commit.c:688 +#, c-format +msgid "could not read log file '%s'" +msgstr "kunde inte läsa loggfilen \"%s\"" + +#: builtin/commit.c:694 +msgid "commit has empty message" +msgstr "incheckningen har ett tomt meddelande" + +#: builtin/commit.c:710 +msgid "could not read MERGE_MSG" +msgstr "kunde inte läsa MERGE_MSG" + +#: builtin/commit.c:714 +msgid "could not read SQUASH_MSG" +msgstr "kunde inte läsa SQUASH_MSG" + +#: builtin/commit.c:718 +#, c-format +msgid "could not read '%s'" +msgstr "kunde inte läsa \"%s\"" + +#: builtin/commit.c:746 +#, c-format +msgid "could not open '%s'" +msgstr "kunde inte öppna \"%s\"" + +#: builtin/commit.c:770 +msgid "could not write commit template" +msgstr "kunde inte skriva incheckningsmall" + +# %s är "merge" eller "cherry-pick" +#: builtin/commit.c:783 +#, c-format +msgid "" +"\n" +"It looks like you may be committing a %s.\n" +"If this is not correct, please remove the file\n" +"\t%s\n" +"and try again.\n" +msgstr "" +"\n" +"Det verkar som du checkar in en %s.\n" +"Om det inte stämmer tar du bort filen\n" +"\t%s\n" +"och försöker igen.\n" + +#: builtin/commit.c:796 +msgid "Please enter the commit message for your changes." +msgstr "Ange ett incheckningsmeddelande för dina ändringar." + +#: builtin/commit.c:799 +msgid "" +" Lines starting\n" +"with '#' will be ignored, and an empty message aborts the commit.\n" +msgstr "" +" Rader som inleds\n" +"med \"#\" kommer ignoreras, och ett tomt meddelande avbryter incheckningen.\n" + +#: builtin/commit.c:804 +msgid "" +" 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 "" +" Rader som inleds\n" +"med \"#\" kommer behållas; du kan själv ta bort dem om du vill.\n" +"Ett tomt meddelande avbryter incheckningen.\n" + +#: builtin/commit.c:816 +#, c-format +msgid "%sAuthor: %s" +msgstr "%sFörfattare: %s" + +#: builtin/commit.c:823 +#, c-format +msgid "%sCommitter: %s" +msgstr "%sIncheckare: %s" + +#: builtin/commit.c:843 +msgid "Cannot read index" +msgstr "Kan inte läsa indexet" + +#: builtin/commit.c:880 +msgid "Error building trees" +msgstr "Fel vid byggande av träd" + +#: builtin/commit.c:895 builtin/tag.c:357 +#, 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:975 +#, c-format +msgid "No existing author found with '%s'" +msgstr "Hittade ingen befintlig författare med \"%s\"" + +#: builtin/commit.c:990 builtin/commit.c:1182 +#, c-format +msgid "Invalid untracked files mode '%s'" +msgstr "Ogiltigt läge för ospårade filer: \"%s\"" + +#: builtin/commit.c:1030 +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:1041 +msgid "You have nothing to amend." +msgstr "Du har inget att utöka." + +#: builtin/commit.c:1043 +#, c-format +msgid "You are in the middle of a %s -- cannot amend." +msgstr "Du är i mitten av en %s -- kan inte utöka." + +#: builtin/commit.c:1045 +msgid "Options --squash and --fixup cannot be used together" +msgstr "Flaggorna --squash och --fixup kan inte användas samtidigt" + +#: builtin/commit.c:1055 +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:1057 +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:1063 +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:1080 +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:1082 +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:1084 +msgid "Clever... amending the last one with dirty index." +msgstr "Smart... utöka den senaste med smutsigt index." + +#: builtin/commit.c:1086 +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:1096 builtin/tag.c:556 +#, c-format +msgid "Invalid cleanup mode %s" +msgstr "Felaktigt städningsläge %s" + +#: builtin/commit.c:1101 +msgid "Paths with -a does not make sense." +msgstr "Kan inte ange sökvägar med -a." + +#: builtin/commit.c:1280 +msgid "couldn't look up newly created commit" +msgstr "kunde inte slå upp en precis skapad incheckning" + +#: builtin/commit.c:1282 +msgid "could not parse newly created commit" +msgstr "kunde inte tolka en precis skapad incheckning" + +#: builtin/commit.c:1323 +msgid "detached HEAD" +msgstr "frånkopplad HEAD" + +#: builtin/commit.c:1325 +msgid " (root-commit)" +msgstr " (rotincheckning)" + +#: builtin/commit.c:1415 +msgid "could not parse HEAD commit" +msgstr "kunde inte tolka HEAD:s incheckning" + +#: builtin/commit.c:1452 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:1459 +#, c-format +msgid "Corrupt MERGE_HEAD file (%s)" +msgstr "Trasig MERGE_HEAD-fil (%s)" + +#: builtin/commit.c:1466 +msgid "could not read MERGE_MODE" +msgstr "kunde inte läsa MERGE_MODE" + +#: builtin/commit.c:1485 +#, c-format +msgid "could not read commit message: %s" +msgstr "kunde inte läsa incheckningsmeddelande: %s" + +#: builtin/commit.c:1499 +#, c-format +msgid "Aborting commit due to empty commit message.\n" +msgstr "Avbryter på grund av tomt incheckningsmeddelande.\n" + +#: builtin/commit.c:1514 builtin/merge.c:935 builtin/merge.c:968 +msgid "failed to write commit object" +msgstr "kunde inte skriva incheckningsobjekt" + +#: builtin/commit.c:1535 +msgid "cannot lock HEAD ref" +msgstr "kunde inte låsa HEAD-referens" + +#: builtin/commit.c:1539 +msgid "cannot update HEAD ref" +msgstr "kunde inte uppdatera HEAD-referens" + +#: builtin/commit.c:1550 +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 "" +"Arkivet har uppdaterats, men kunde inte skriva filen\n" +"new_index. Kontrollera att disken inte är full och\n" +"att kvoten inte har överskridits, och kör sedan\n" +"\"git reset HEAD\" för att återställa." + +#: builtin/describe.c:234 +#, c-format +msgid "annotated tag %s not available" +msgstr "den annoterade taggen %s inte tillgänglig" + +#: builtin/describe.c:238 +#, c-format +msgid "annotated tag %s has no embedded name" +msgstr "den annoterade taggen %s har inget inbäddat namn" + +#: builtin/describe.c:240 +#, c-format +msgid "tag '%s' is really '%s' here" +msgstr "taggen \"%s\" är i verkligheten \"%s\" här" + +#: builtin/describe.c:267 +#, c-format +msgid "Not a valid object name %s" +msgstr "Objektnamnet är inte giltigt: %s" + +#: builtin/describe.c:270 +#, c-format +msgid "%s is not a valid '%s' object" +msgstr "%s är inte ett giltigt \"%s\"-objekt" + +#: builtin/describe.c:287 +#, c-format +msgid "no tag exactly matches '%s'" +msgstr "ingen tagg motsvarar \"%s\" exakt" + +#: builtin/describe.c:289 +#, c-format +msgid "searching to describe %s\n" +msgstr "söker för att beskriva %s\n" + +#: builtin/describe.c:329 +#, c-format +msgid "finished search at %s\n" +msgstr "avslutade sökning på %s\n" + +#: builtin/describe.c:353 +#, c-format +msgid "" +"No annotated tags can describe '%s'.\n" +"However, there were unannotated tags: try --tags." +msgstr "" +"Inga annoterade taggar kan beskriva \"%s\".\n" +"Det finns dock oannoterade taggar: testa --tags." + +#: builtin/describe.c:357 +#, c-format +msgid "" +"No tags can describe '%s'.\n" +"Try --always, or create some tags." +msgstr "" +"Inga taggar kan beskriva \"%s\".\n" +"Testa --always, eller skapa några taggar." + +#: builtin/describe.c:378 +#, c-format +msgid "traversed %lu commits\n" +msgstr "traverserade %lu incheckningar\n" + +#: builtin/describe.c:381 +#, c-format +msgid "" +"more than %i tags found; listed %i most recent\n" +"gave up search at %s\n" +msgstr "" +"mer än %i taggar hittades; listar de %i senaste\n" +"gav upp sökningen vid %s\n" + +#: builtin/describe.c:436 +msgid "--long is incompatible with --abbrev=0" +msgstr "--long är inkompatibel med --abbrev=0" + +#: builtin/describe.c:462 +msgid "No names found, cannot describe anything." +msgstr "Inga namn hittades, kan inte beskriva något." + +#: builtin/describe.c:482 +msgid "--dirty is incompatible with committishes" +msgstr "--dirty är inkompatibelt med \"committish\"-värden" + +#: builtin/diff.c:77 +#, c-format +msgid "'%s': not a regular file or symlink" +msgstr "\"%s\": inte en normal fil eller symbolisk länk" + +#: builtin/diff.c:220 +#, c-format +msgid "invalid option: %s" +msgstr "ogiltig flagga: %s" + +#: builtin/diff.c:297 +msgid "Not a git repository" +msgstr "Inte ett git-arkiv" + +#: builtin/diff.c:347 +#, c-format +msgid "invalid object '%s' given." +msgstr "objektet \"%s\" som angavs är felaktigt." + +#: builtin/diff.c:352 +#, c-format +msgid "more than %d trees given: '%s'" +msgstr "mer än %d träd angavs: \"%s\"" + +#: builtin/diff.c:362 +#, c-format +msgid "more than two blobs given: '%s'" +msgstr "mer än två blobbar angavs: \"%s\"" + +#: builtin/diff.c:370 +#, c-format +msgid "unhandled object '%s' given." +msgstr "ej hanterat objekt \"%s\" angavs." + +#: builtin/fetch.c:200 +msgid "Couldn't find remote ref HEAD" +msgstr "Kunde inte hitta fjärr-referensen HEAD" + +#: builtin/fetch.c:252 +#, c-format +msgid "object %s not found" +msgstr "objektet %s hittades inte" + +#: builtin/fetch.c:258 +msgid "[up to date]" +msgstr "[àjour]" + +#: builtin/fetch.c:272 +#, c-format +msgid "! %-*s %-*s -> %s (can't fetch in current branch)" +msgstr "! %-*s %-*s -> %s (kan inte hämta i aktuell gren)" + +#: builtin/fetch.c:273 builtin/fetch.c:351 +msgid "[rejected]" +msgstr "[refuserad]" + +#: builtin/fetch.c:284 +msgid "[tag update]" +msgstr "[uppdaterad tagg]" + +#: builtin/fetch.c:286 builtin/fetch.c:313 builtin/fetch.c:331 +msgid " (unable to update local ref)" +msgstr " (kunde inte uppdatera lokal ref)" + +#: builtin/fetch.c:298 +msgid "[new tag]" +msgstr "[ny tagg]" + +#: builtin/fetch.c:302 +msgid "[new branch]" +msgstr "[ny gren]" + +#: builtin/fetch.c:347 +msgid "unable to update local ref" +msgstr "kunde inte uppdatera lokal ref" + +#: builtin/fetch.c:347 +msgid "forced update" +msgstr "tvingad uppdatering" + +#: builtin/fetch.c:353 +msgid "(non-fast-forward)" +msgstr "(ej snabbspolad)" + +#: builtin/fetch.c:384 builtin/fetch.c:676 +#, c-format +msgid "cannot open %s: %s\n" +msgstr "kan inte öppna %s: %s\n" + +#: builtin/fetch.c:393 +#, c-format +msgid "%s did not send all necessary objects\n" +msgstr "%s sände inte alla nödvändiga objekt\n" + +#: builtin/fetch.c:479 +#, c-format +msgid "From %.*s\n" +msgstr "Från %.*s\n" + +#: builtin/fetch.c:490 +#, c-format +msgid "" +"some local refs could not be updated; try running\n" +" 'git remote prune %s' to remove any old, conflicting branches" +msgstr "" +"några lokala referenser kunde inte uppdateras; testa att köra\n" +" \"git remote prune %s\" för att ta bort gamla grenar som står i konflikt" + +#: builtin/fetch.c:540 +#, c-format +msgid " (%s will become dangling)\n" +msgstr " (%s kommer bli dinglande)\n" + +#: builtin/fetch.c:541 +#, c-format +msgid " (%s has become dangling)\n" +msgstr " (%s har blivit dinglande)\n" + +#: builtin/fetch.c:548 +msgid "[deleted]" +msgstr "[borttagen]" + +#: builtin/fetch.c:549 +msgid "(none)" +msgstr "(ingen)" + +#: builtin/fetch.c:666 +#, c-format +msgid "Refusing to fetch into current branch %s of non-bare repository" +msgstr "Vägrar hämta till aktuell gren %s i ett icke-naket arkiv" + +#: builtin/fetch.c:700 +#, c-format +msgid "Don't know how to fetch from %s" +msgstr "Vet inte hur man hämtar från %s" + +#: builtin/fetch.c:777 +#, c-format +msgid "Option \"%s\" value \"%s\" is not valid for %s" +msgstr "Flaggan \"%s\" och värdet \"%s\" är inte giltigt för %s" + +#: builtin/fetch.c:780 +#, c-format +msgid "Option \"%s\" is ignored for %s\n" +msgstr "Flaggan \"%s\" ignoreras för %s\n" + +#: builtin/fetch.c:879 +#, c-format +msgid "Fetching %s\n" +msgstr "Hämtar %s\n" + +#: builtin/fetch.c:881 +#, c-format +msgid "Could not fetch %s" +msgstr "Kunde inte hämta %s" + +#: builtin/fetch.c:898 +msgid "" +"No remote repository specified. Please, specify either a URL or a\n" +"remote name from which new revisions should be fetched." +msgstr "" +"Inget fjärrarkiv angavs. Ange antingen en URL eller namnet på ett\n" +"fjärrarkiv som nya incheckningar skall hämtas från." + +#: builtin/fetch.c:918 +msgid "You need to specify a tag name." +msgstr "Du måste ange namnet på en tagg." + +#: builtin/fetch.c:970 +msgid "fetch --all does not take a repository argument" +msgstr "fetch --all tar inte namnet på ett arkiv som argument" + +#: builtin/fetch.c:972 +msgid "fetch --all does not make sense with refspecs" +msgstr "fetch --all kan inte anges med referensspecifikationer" + +#: builtin/fetch.c:983 +#, c-format +msgid "No such remote or remote group: %s" +msgstr "Fjärren eller fjärrgruppen finns inte: %s" + +#: builtin/fetch.c:991 +msgid "Fetching a group and specifying refspecs does not make sense" +msgstr "Kan inte hämta från grupp och ange referensspecifikationer" + +#: builtin/gc.c:63 +#, c-format +msgid "Invalid %s: '%s'" +msgstr "Felaktigt %s: \"%s\"" + +#: builtin/gc.c:78 +msgid "Too many options specified" +msgstr "För många flaggor angavs" + +#: builtin/gc.c:103 +#, c-format +msgid "insanely long object directory %.*s" +msgstr "tokigt lång objektkatalog %.*s" + +#: builtin/gc.c:223 +#, c-format +msgid "Auto packing the repository for optimum performance.\n" +msgstr "Packar arkivet automatiskt för optimal prestanda.\n" + +#: builtin/gc.c:226 +#, c-format +msgid "" +"Auto packing the repository for optimum performance. You may also\n" +"run \"git gc\" manually. See \"git help gc\" for more information.\n" +msgstr "" +"Packar arkivet automatiskt för optimal prestanda. Du kan även\n" +"köra \"git gc\" manuellt. Se \"git help gc\" för mer information.\n" + +#: builtin/gc.c:256 +msgid "" +"There are too many unreachable loose objects; run 'git prune' to remove them." +msgstr "" +"Det finns för många onåbara lösa objekt; kör \"git prune\" för att ta bort " +"dem." + +#: builtin/grep.c:216 +#, c-format +msgid "grep: failed to create thread: %s" +msgstr "grep: misslyckades skapa tråd. %s" + +#: builtin/grep.c:402 +#, c-format +msgid "Failed to chdir: %s" +msgstr "Kunde inte byta katalog (chdir): %s" + +#: builtin/grep.c:478 builtin/grep.c:512 +#, c-format +msgid "unable to read tree (%s)" +msgstr "kunde inte läsa träd (%s)" + +#: builtin/grep.c:526 +#, c-format +msgid "unable to grep from object of type %s" +msgstr "Kunde inte \"grep\" från objekt av typen %s" + +#: builtin/grep.c:584 +#, c-format +msgid "switch `%c' expects a numerical value" +msgstr "flaggan \"%c\" antar ett numeriskt värde" + +#: builtin/grep.c:601 +#, c-format +msgid "cannot open '%s'" +msgstr "kan inte öppna \"%s\"" + +#: builtin/grep.c:888 +msgid "no pattern given." +msgstr "inget mönster angavs." + +#: builtin/grep.c:902 +#, c-format +msgid "bad object %s" +msgstr "felaktigt objekt %s" + +#: builtin/grep.c:943 +msgid "--open-files-in-pager only works on the worktree" +msgstr "--open-files-in-pager fungerar endast i arbetskatalogen" + +#: builtin/grep.c:966 +msgid "--cached or --untracked cannot be used with --no-index." +msgstr "--cached och --untracked kan inte användas med --no-index." + +#: builtin/grep.c:971 +msgid "--no-index or --untracked cannot be used with revs." +msgstr "--no-index och --untracked kan inte användas med revisioner." + +#: builtin/grep.c:974 +msgid "--[no-]exclude-standard cannot be used for tracked contents." +msgstr "--[no-]exclude-standard kan inte användas för spårat innehåll." + +#: builtin/grep.c:982 +msgid "both --cached and trees are given." +msgstr "både --cached och träd angavs." + +#: builtin/init-db.c:35 +#, c-format +msgid "Could not make %s writable by group" +msgstr "Kunde inte göra %s skrivbar för gruppen" + +#: builtin/init-db.c:62 +#, c-format +msgid "insanely long template name %s" +msgstr "tokigt långt namn på mallen %s" + +#: builtin/init-db.c:67 +#, c-format +msgid "cannot stat '%s'" +msgstr "kan inte ta status på \"%s\"" + +#: builtin/init-db.c:73 +#, c-format +msgid "cannot stat template '%s'" +msgstr "kan inte ta status på mallen \"%s\"" + +#: builtin/init-db.c:80 +#, c-format +msgid "cannot opendir '%s'" +msgstr "kan inte öppna katalogen (opendir) \"%s\"" + +#: builtin/init-db.c:97 +#, c-format +msgid "cannot readlink '%s'" +msgstr "kan inte läsa länk (readlink) \"%s\"" + +#: builtin/init-db.c:99 +#, c-format +msgid "insanely long symlink %s" +msgstr "tokigt lång symbolisk länk %s" + +#: builtin/init-db.c:102 +#, c-format +msgid "cannot symlink '%s' '%s'" +msgstr "kan inte skapa symbolisk länk \"%s\" \"%s\"" + +#: builtin/init-db.c:106 +#, c-format +msgid "cannot copy '%s' to '%s'" +msgstr "kan inte kopiera \"%s\" till \"%s\"" + +#: builtin/init-db.c:110 +#, c-format +msgid "ignoring template %s" +msgstr "ignorerar mallen %s" + +#: builtin/init-db.c:133 +#, c-format +msgid "insanely long template path %s" +msgstr "tokigt lång mallsökväg %s" + +#: builtin/init-db.c:141 +#, c-format +msgid "templates not found %s" +msgstr "mallarna hittades inte %s" + +#: builtin/init-db.c:154 +#, c-format +msgid "not copying templates of a wrong format version %d from '%s'" +msgstr "kopierade inte mallar från felaktig formatversion %d från \"%s\"" + +#: builtin/init-db.c:192 +#, c-format +msgid "insane git directory %s" +msgstr "tokig git-katalog %s" + +#: builtin/init-db.c:322 builtin/init-db.c:325 +#, c-format +msgid "%s already exists" +msgstr "%s finns redan" + +#: builtin/init-db.c:354 +#, c-format +msgid "unable to handle file type %d" +msgstr "kan inte hantera filtyp %d" + +#: builtin/init-db.c:357 +#, c-format +msgid "unable to move %s to %s" +msgstr "kan inte flytta %s till %s" + +#: builtin/init-db.c:362 +#, c-format +msgid "Could not create git link %s" +msgstr "Kunde inte skapa gitlänk %s" + +#. +#. * TRANSLATORS: The first '%s' is either "Reinitialized +#. * existing" or "Initialized empty", the second " shared" or +#. * "", and the last '%s%s' is the verbatim directory name. +#. +#: builtin/init-db.c:419 +#, 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 +msgid "Reinitialized existing" +msgstr "Ominitierade befintligt" + +#: builtin/init-db.c:420 +msgid "Initialized empty" +msgstr "Initierade tomt" + +#: builtin/init-db.c:421 +msgid " shared" +msgstr " delat" + +#: builtin/init-db.c:440 +msgid "cannot tell cwd" +msgstr "kan inte läsa aktuell katalog (cwd)" + +#: builtin/init-db.c:521 builtin/init-db.c:528 +#, c-format +msgid "cannot mkdir %s" +msgstr "kan inte skapa katalogen (mkdir) %s" + +#: builtin/init-db.c:532 +#, c-format +msgid "cannot chdir to %s" +msgstr "kan inte byta katalog (chdir) till %s" + +#: builtin/init-db.c:554 +#, c-format +msgid "" +"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-" +"dir=<directory>)" +msgstr "" +"%s (eller --work-tree=<katalog>) inte tillåtet utan att ange %s (eller --git-" +"dir=<katalog>)" + +#: builtin/init-db.c:578 +msgid "Cannot access current working directory" +msgstr "Kan inte komma åt aktuell arbetskatalog" + +#: builtin/init-db.c:585 +#, c-format +msgid "Cannot access work tree '%s'" +msgstr "Kan inte komma åt arbetskatalogen \"%s\"" + +#: builtin/log.c:187 +#, c-format +msgid "Final output: %d %s\n" +msgstr "Slututdata: %d %s\n" + +#: builtin/log.c:395 builtin/log.c:483 +#, c-format +msgid "Could not read object %s" +msgstr "Kunde inte läsa objektet %s" + +#: builtin/log.c:507 +#, c-format +msgid "Unknown type: %d" +msgstr "Okänd typ: %d" + +#: builtin/log.c:596 +msgid "format.headers without value" +msgstr "format.headers utan värde" + +#: builtin/log.c:669 +msgid "name of output directory is too long" +msgstr "namnet på utdatakatalogen är för långt" + +#: builtin/log.c:680 +#, c-format +msgid "Cannot open patch file %s" +msgstr "Kan inte öppna patchfilen %s" + +#: builtin/log.c:694 +msgid "Need exactly one range." +msgstr "Behöver precis ett intervall." + +#: builtin/log.c:702 +msgid "Not a range." +msgstr "Inte ett intervall." + +#: builtin/log.c:739 +msgid "Could not extract email from committer identity." +msgstr "Kunde inte extrahera e-postadress från incheckarens identitet." + +#: builtin/log.c:785 +msgid "Cover letter needs email format" +msgstr "Omslagsbrevet behöver e-postformat" + +#: builtin/log.c:879 +#, c-format +msgid "insane in-reply-to: %s" +msgstr "tokigt in-reply-to: %s" + +#: builtin/log.c:952 +msgid "Two output directories?" +msgstr "Två utdatakataloger?" + +#: builtin/log.c:1173 +#, c-format +msgid "bogus committer info %s" +msgstr "felaktig incheckarinformation %s" + +#: builtin/log.c:1218 +msgid "-n and -k are mutually exclusive." +msgstr "-n och -k kan inte användas samtidigt." + +#: builtin/log.c:1220 +msgid "--subject-prefix and -k are mutually exclusive." +msgstr "--subject-prefix och -k kan inte användas samtidigt." + +#: builtin/log.c:1225 builtin/shortlog.c:284 +#, c-format +msgid "unrecognized argument: %s" +msgstr "okänt argument: %s" + +#: builtin/log.c:1228 +msgid "--name-only does not make sense" +msgstr "kan inte använda --name-only" + +#: builtin/log.c:1230 +msgid "--name-status does not make sense" +msgstr "kan inte använda --name-status" + +#: builtin/log.c:1232 +msgid "--check does not make sense" +msgstr "kan inte använda --check" + +#: builtin/log.c:1255 +msgid "standard output, or directory, which one?" +msgstr "standard ut, eller katalog, vilken skall det vara?" + +#: builtin/log.c:1257 +#, c-format +msgid "Could not create directory '%s'" +msgstr "Kunde inte skapa katalogen \"%s\"" + +#: builtin/log.c:1410 +msgid "Failed to create output files" +msgstr "Misslyckades skapa utdatafiler" + +#: builtin/log.c:1514 +#, 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:1530 builtin/log.c:1532 builtin/log.c:1544 +#, c-format +msgid "Unknown commit %s" +msgstr "Okänd incheckning %s" + +#: builtin/merge.c:91 +msgid "switch `m' requires a value" +msgstr "flaggan \"m\" behöver ett värde" + +#: builtin/merge.c:128 +#, c-format +msgid "Could not find merge strategy '%s'.\n" +msgstr "Kunde inte hitta sammanslagningsstrategin \"%s\".\n" + +#: builtin/merge.c:129 +#, c-format +msgid "Available strategies are:" +msgstr "Tillgängliga strategier är:" + +#: builtin/merge.c:134 +#, c-format +msgid "Available custom strategies are:" +msgstr "Tillgängliga skräddarsydda strategier är:" + +#: builtin/merge.c:241 +msgid "could not run stash." +msgstr "kunde köra stash." + +#: builtin/merge.c:246 +msgid "stash failed" +msgstr "stash misslyckades" + +#: builtin/merge.c:251 +#, c-format +msgid "not a valid object: %s" +msgstr "inte ett giltigt objekt: %s" + +#: builtin/merge.c:270 builtin/merge.c:287 +msgid "read-tree failed" +msgstr "read-tree misslyckades" + +#: builtin/merge.c:317 +msgid " (nothing to squash)" +msgstr " (inget att platta till)" + +#: builtin/merge.c:330 +#, c-format +msgid "Squash commit -- not updating HEAD\n" +msgstr "Tillplattningsincheckning -- uppdaterar inte HEAD\n" + +#: builtin/merge.c:362 +msgid "Writing SQUASH_MSG" +msgstr "Skriver SQUASH_MSG" + +#: builtin/merge.c:364 +msgid "Finishing SQUASH_MSG" +msgstr "Avslutar SQUASH_MSG" + +#: builtin/merge.c:386 +#, c-format +msgid "No merge message -- not updating HEAD\n" +msgstr "Inget sammanslagningsmeddelande -- uppdaterar inte HEAD\n" + +#: builtin/merge.c:437 +#, c-format +msgid "'%s' does not point to a commit" +msgstr "\"%s\" verkar inte peka på en incheckning" + +#: builtin/merge.c:536 +#, c-format +msgid "Bad branch.%s.mergeoptions string: %s" +msgstr "Felaktig branch.%s.mergeoptions-sträng: %s" + +#: builtin/merge.c:629 +msgid "git write-tree failed to write a tree" +msgstr "git write-tree misslyckades skriva ett träd" + +#: builtin/merge.c:679 +msgid "failed to read the cache" +msgstr "misslyckads läsa cachen" + +#: builtin/merge.c:696 +msgid "Unable to write index." +msgstr "Kunde inte skriva indexet." + +#: builtin/merge.c:709 +msgid "Not handling anything other than two heads merge." +msgstr "Hanterar inte något annat än en sammanslagning av två huvuden." + +#: builtin/merge.c:723 +#, c-format +msgid "Unknown option for merge-recursive: -X%s" +msgstr "Felaktig flagga för merge-recursive: -X%s" + +#: builtin/merge.c:737 +#, c-format +msgid "unable to write %s" +msgstr "kunde inte skriva %s" + +#: builtin/merge.c:876 +#, c-format +msgid "Could not read from '%s'" +msgstr "Kunde inte läsa från \"%s\"" + +#: builtin/merge.c:885 +#, c-format +msgid "Not committing merge; use 'git commit' to complete the merge.\n" +msgstr "" +"Checkar inte in sammanslagningen; använd \"git commit\" för att slutföra " +"den.\n" + +#: builtin/merge.c:891 +msgid "" +"Please enter a commit message to explain why this merge is necessary,\n" +"especially if it merges an updated upstream into a topic branch.\n" +"\n" +"Lines starting with '#' will be ignored, and an empty message aborts\n" +"the commit.\n" +msgstr "" +"Ange ett incheckningsmeddelande för att förklara varför sammanslagningen\n" +"är nödvändig, speciellt om den slår in en uppdaterad uppström i en\n" +"temagren.\n" +"\n" +"Rader som inleds med \"#\" kommer ignoreras, och ett tomt meddelande\n" +"avbryter incheckningen.\n" + +#: builtin/merge.c:915 +msgid "Empty commit message." +msgstr "Tomt incheckningsmeddelande." + +#: builtin/merge.c:927 +#, c-format +msgid "Wonderful.\n" +msgstr "Underbart.\n" + +#: builtin/merge.c:1000 +#, c-format +msgid "Automatic merge failed; fix conflicts and then commit the result.\n" +msgstr "" +"Kunde inte slå ihop automatiskt; fixa konflikter och checka in resultatet.\n" + +#: builtin/merge.c:1016 +#, c-format +msgid "'%s' is not a commit" +msgstr "\"%s\" är inte en incheckning" + +#: builtin/merge.c:1057 +msgid "No current branch." +msgstr "Inte på någon gren." + +#: builtin/merge.c:1059 +msgid "No remote for the current branch." +msgstr "Ingen fjärr för aktuell gren." + +#: builtin/merge.c:1061 +msgid "No default upstream defined for the current branch." +msgstr "Ingen standarduppström angiven för aktuell gren." + +#: builtin/merge.c:1066 +#, c-format +msgid "No remote tracking branch for %s from %s" +msgstr "Ingen fjärrspårande gren för %s från %s" + +#: builtin/merge.c:1188 +msgid "There is no merge to abort (MERGE_HEAD missing)." +msgstr "Det finns ingen sammanslagning att avbryta (MERGE_HEAD saknas)." + +#: builtin/merge.c:1204 git-pull.sh:31 +msgid "" +"You have not concluded your merge (MERGE_HEAD exists).\n" +"Please, commit your changes before you can merge." +msgstr "" +"Du har inte avslutat sammanslagningen (MERGE_HEAD finns).\n" +"Checka in dina ändringar innan du kan slå ihop." + +#: builtin/merge.c:1207 git-pull.sh:34 +msgid "You have not concluded your merge (MERGE_HEAD exists)." +msgstr "Du har inte avslutat sammanslagningen (MERGE_HEAD finns)." + +#: builtin/merge.c:1211 +msgid "" +"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n" +"Please, commit your changes before you can merge." +msgstr "" +"Du har inte avslutat din \"cherry-pick\" (CHERRY_PICK_HEAD finns).\n" +"Checka in dina ändringar innan du kan slå ihop." + +#: builtin/merge.c:1214 +msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)." +msgstr "Du har inte avslutat din \"cherry-pick\" (CHERRY_PICK_HEAD finns)." + +#: builtin/merge.c:1223 +msgid "You cannot combine --squash with --no-ff." +msgstr "Du kan inte kombinera --squash med --no-ff." + +#: builtin/merge.c:1228 +msgid "You cannot combine --no-ff with --ff-only." +msgstr "Du kan inte kombinera --no-ff med --ff-only." + +#: builtin/merge.c:1235 +msgid "No commit specified and merge.defaultToUpstream not set." +msgstr "Ingen incheckning angiven och merge.defaultToUpstream är ej satt." + +#: builtin/merge.c:1266 +msgid "Can merge only exactly one commit into empty head" +msgstr "Kan endast slå ihop en enda incheckning i ett tomt huvud." + +#: builtin/merge.c:1269 +msgid "Squash commit into empty head not supported yet" +msgstr "Stöder inte en tillplattningsincheckning på ett tomt huvud ännu" + +#: builtin/merge.c:1271 +msgid "Non-fast-forward commit does not make sense into an empty head" +msgstr "Icke-snabbspolad incheckning kan inte användas med ett tomt huvud" + +#: builtin/merge.c:1275 builtin/merge.c:1319 +#, c-format +msgid "%s - not something we can merge" +msgstr "%s - inte något vi kan slå ihop" + +#: builtin/merge.c:1385 +#, c-format +msgid "Updating %s..%s\n" +msgstr "Uppdaterar %s..%s\n" + +#: builtin/merge.c:1423 +#, c-format +msgid "Trying really trivial in-index merge...\n" +msgstr "Försöker riktigt enkel sammanslagning i indexet...\n" + +#: builtin/merge.c:1430 +#, c-format +msgid "Nope.\n" +msgstr "Nej.\n" + +#: builtin/merge.c:1462 +msgid "Not possible to fast-forward, aborting." +msgstr "Kan inte snabbspola, avbryter." + +#: builtin/merge.c:1485 builtin/merge.c:1562 +#, c-format +msgid "Rewinding the tree to pristine...\n" +msgstr "Återspolar trädet till orört...\n" + +#: builtin/merge.c:1489 +#, c-format +msgid "Trying merge strategy %s...\n" +msgstr "Försöker sammanslagninsstrategin %s...\n" + +#: builtin/merge.c:1553 +#, c-format +msgid "No merge strategy handled the merge.\n" +msgstr "Ingen sammanslagningsstrategi hanterade sammanslagningen.\n" + +#: builtin/merge.c:1555 +#, c-format +msgid "Merge with strategy %s failed.\n" +msgstr "Sammanslaning med strategin %s misslyckades.\n" + +#: builtin/merge.c:1564 +#, c-format +msgid "Using the %s to prepare resolving by hand.\n" +msgstr "Använder %s för att förbereda lösning för hand.\n" + +#: builtin/merge.c:1575 +#, c-format +msgid "Automatic merge went well; stopped before committing as requested\n" +msgstr "" +"Automatisk sammanslagning lyckades; stoppar före incheckning som önskat\n" + +#: builtin/mv.c:108 +#, c-format +msgid "Checking rename of '%s' to '%s'\n" +msgstr "Kontrollerar namnbyte av \"%s\" till \"%s\"\n" + +#: builtin/mv.c:112 +msgid "bad source" +msgstr "felaktig källa" + +#: builtin/mv.c:115 +msgid "can not move directory into itself" +msgstr "kan inte flytta katalog till sig själv" + +#: builtin/mv.c:118 +msgid "cannot move directory over file" +msgstr "kan inte flytta katalog över fil" + +#: builtin/mv.c:128 +#, c-format +msgid "Huh? %.*s is in index?" +msgstr "Vad? %.*s är i indexet?" + +#: builtin/mv.c:140 +msgid "source directory is empty" +msgstr "källkatalogen är tom" + +#: builtin/mv.c:171 +msgid "not under version control" +msgstr "inte versionshanterad" + +#: builtin/mv.c:173 +msgid "destination exists" +msgstr "destinationen finns" + +#: builtin/mv.c:181 +#, c-format +msgid "overwriting '%s'" +msgstr "skriver över \"%s\"" + +#: builtin/mv.c:184 +msgid "Cannot overwrite" +msgstr "Kan inte skriva över" + +#: builtin/mv.c:187 +msgid "multiple sources for the same target" +msgstr "flera källor för samma mål" + +#: builtin/mv.c:202 +#, c-format +msgid "%s, source=%s, destination=%s" +msgstr "%s, källa=%s, mål=%s" + +#: builtin/mv.c:212 +#, c-format +msgid "Renaming %s to %s\n" +msgstr "Byter namn på %s till %s\n" + +#: builtin/mv.c:215 +#, c-format +msgid "renaming '%s' failed" +msgstr "misslyckades byta namn på \"%s\"" + +#: builtin/notes.c:139 +#, c-format +msgid "unable to start 'show' for object '%s'" +msgstr "kunde inte starta \"show\" för objektet \"%s\"" + +#: builtin/notes.c:145 +msgid "can't fdopen 'show' output fd" +msgstr "kunde inte öppna (fdopen) \"show\"-utdata-filhandtag" + +#: builtin/notes.c:155 +#, c-format +msgid "failed to close pipe to 'show' for object '%s'" +msgstr "kunde inte stänga röret till \"show\" för objektet \"%s\"" + +#: builtin/notes.c:158 +#, c-format +msgid "failed to finish 'show' for object '%s'" +msgstr "kunde inte avsluta \"show\" för objektet \"%s\"" + +#: builtin/notes.c:175 builtin/tag.c:343 +#, c-format +msgid "could not create file '%s'" +msgstr "kunde inte skapa filen \"%s\"" + +#: builtin/notes.c:189 +msgid "Please supply the note contents using either -m or -F option" +msgstr "Ange innehåll för anteckningen med antingen -m eller -F" + +#: builtin/notes.c:210 builtin/notes.c:973 +#, c-format +msgid "Removing note for object %s\n" +msgstr "Tar bort anteckning för objektet %s\n" + +#: builtin/notes.c:215 +msgid "unable to write note object" +msgstr "kunde inte skriva anteckningsobjekt" + +#: builtin/notes.c:217 +#, c-format +msgid "The note contents has been left in %s" +msgstr "Anteckningens innehåll har lämnats kvar i %s" + +#: builtin/notes.c:251 builtin/tag.c:521 +#, c-format +msgid "cannot read '%s'" +msgstr "kunde inte läsa \"%s\"" + +#: builtin/notes.c:253 builtin/tag.c:524 +#, c-format +msgid "could not open or read '%s'" +msgstr "kunde inte öppna eller läsa \"%s\"" + +#: builtin/notes.c:272 builtin/notes.c:445 builtin/notes.c:447 +#: builtin/notes.c:507 builtin/notes.c:561 builtin/notes.c:644 +#: builtin/notes.c:649 builtin/notes.c:724 builtin/notes.c:766 +#: builtin/notes.c:968 builtin/reset.c:293 builtin/tag.c:537 +#, c-format +msgid "Failed to resolve '%s' as a valid ref." +msgstr "Kunde inte slå upp \"%s\" som en giltig referens." + +#: builtin/notes.c:275 +#, c-format +msgid "Failed to read object '%s'." +msgstr "Kunde inte läsa objektet \"%s\"." + +#: builtin/notes.c:299 +msgid "Cannot commit uninitialized/unreferenced notes tree" +msgstr "Kan inte checka in oinitierat/orefererat anteckningsträd" + +#: builtin/notes.c:340 +#, c-format +msgid "Bad notes.rewriteMode value: '%s'" +msgstr "Felaktigt värde för notes.rewriteMode: '%s'" + +#: builtin/notes.c:350 +#, c-format +msgid "Refusing to rewrite notes in %s (outside of refs/notes/)" +msgstr "Vägrar skriva över anteckningar i %s (utanför refs/notes/)" + +#. TRANSLATORS: The first %s is the name of the +#. environment variable, the second %s is its value +#: builtin/notes.c:377 +#, c-format +msgid "Bad %s value: '%s'" +msgstr "Felaktigt värde på %s: \"%s\"" + +#: builtin/notes.c:441 +#, c-format +msgid "Malformed input line: '%s'." +msgstr "Felaktig indatarad: \"%s\"." + +#: builtin/notes.c:456 +#, c-format +msgid "Failed to copy notes from '%s' to '%s'" +msgstr "Misslyckades kopiera anteckningar från \"%s\" till \"%s\"" + +#: builtin/notes.c:500 builtin/notes.c:554 builtin/notes.c:627 +#: builtin/notes.c:639 builtin/notes.c:712 builtin/notes.c:759 +#: builtin/notes.c:1033 +msgid "too many parameters" +msgstr "för många parametrar" + +#: builtin/notes.c:513 builtin/notes.c:772 +#, c-format +msgid "No note found for object %s." +msgstr "Inga anteckningar hittades för objektet %s." + +#: builtin/notes.c:580 +#, c-format +msgid "" +"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite " +"existing notes" +msgstr "" +"Kan inte lägga till anteckningar. Hittade befintliga anteckningar för " +"objektet %s. Använd \"-f\" för att skriva över befintliga anteckningar" + +#: builtin/notes.c:585 builtin/notes.c:662 +#, c-format +msgid "Overwriting existing notes for object %s\n" +msgstr "Skriver över befintliga anteckningar för objektet %s\n" + +#: builtin/notes.c:635 +msgid "too few parameters" +msgstr "för få parametrar" + +#: builtin/notes.c:656 +#, c-format +msgid "" +"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite " +"existing notes" +msgstr "" +"Kan inte kopiera anteckningar. Hittade befintliga anteckningar för objektet " +"%s. Använd \"-f\" för att skriva över befintliga anteckningar" + +#: builtin/notes.c:668 +#, c-format +msgid "Missing notes on source object %s. Cannot copy." +msgstr "Anteckningar på källobjektet %s saknas. Kan inte kopiera." + +#: builtin/notes.c:717 +#, c-format +msgid "" +"The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n" +"Please use 'git notes add -f -m/-F/-c/-C' instead.\n" +msgstr "" +"Flaggorna -m/-F/-c/-C rekommenderas inte för underkommandot \"edit\".\n" +"Använd \"git notes add -f -m/-F/-c/-C\" istället.\n" + +#: builtin/notes.c:971 +#, c-format +msgid "Object %s has no note\n" +msgstr "Objektet %s har ingen anteckning\n" + +#: builtin/notes.c:1103 +#, c-format +msgid "Unknown subcommand: %s" +msgstr "Okänt underkommando: %s" + +#: builtin/pack-objects.c:2310 +#, c-format +msgid "unsupported index version %s" +msgstr "indexversionen %s stöds ej" + +#: builtin/pack-objects.c:2314 +#, c-format +msgid "bad index version '%s'" +msgstr "felaktig indexversion \"%s\"" + +#: builtin/pack-objects.c:2322 +#, c-format +msgid "option %s does not accept negative form" +msgstr "flaggan %s godtar inte negativ form" + +#: builtin/pack-objects.c:2326 +#, c-format +msgid "unable to parse value '%s' for option %s" +msgstr "kunde inte tolka värdet \"%s\" för flaggan %s" + +#: builtin/push.c:44 +msgid "tag shorthand without <tag>" +msgstr "taggförkortning utan <tagg>" + +#: builtin/push.c:63 +msgid "--delete only accepts plain target ref names" +msgstr "--delete godtar endast enkla målreferensnamn" + +#: builtin/push.c:73 +#, c-format +msgid "" +"You are not currently on a branch.\n" +"To push the history leading to the current (detached HEAD)\n" +"state now, use\n" +"\n" +" git push %s HEAD:<name-of-remote-branch>\n" +msgstr "" +"Du är inte på någon gren för närvarande.\n" +"För att sända in historiken som leder till den aktuella (frånkopplat\n" +"HEAD) situationen använder du\n" +"\n" +" git push %s HEAD:<namn-på-fjärrgren>\n" + +#: builtin/push.c:80 +#, c-format +msgid "" +"The current branch %s has no upstream branch.\n" +"To push the current branch and set the remote as upstream, use\n" +"\n" +" git push --set-upstream %s %s\n" +msgstr "" +"Den aktuella grenen %s har ingen uppströmsgren.\n" +"För att sända aktuell gren och ange fjärrarkiv som uppström använder du\n" +"\n" +" git push --set-upstream %s %s\n" + +#: builtin/push.c:88 +#, c-format +msgid "The current branch %s has multiple upstream branches, refusing to push." +msgstr "Den aktuella grenen %s har flera uppströmsgrenar, vägrar sända." + +#: builtin/push.c:111 +msgid "" +"You didn't specify any refspecs to push, and push.default is \"nothing\"." +msgstr "" +"Du angav inga referensspecifikationer att sända, och push.default är " +"\"nothing\"." + +#: builtin/push.c:131 +#, c-format +msgid "Pushing to %s\n" +msgstr "Sänder till %s\n" + +#: builtin/push.c:135 +#, c-format +msgid "failed to push some refs to '%s'" +msgstr "misslyckades sända några referenser till \"%s\"" + +#: builtin/push.c:143 +#, c-format +msgid "" +"To prevent you from losing history, non-fast-forward updates were rejected\n" +"Merge the remote changes (e.g. 'git pull') before pushing again. See the\n" +"'Note about fast-forwards' section of 'git push --help' for details.\n" +msgstr "" +"För att förhindra att du tappar historik har icke snabbspolande " +"uppdateringar\n" +"avvisats. Slå ihop fjärrändringarna (t.ex \"git pull\") innan du sänder " +"igen.\n" +"Se avsnittet \"Note about fast-forward\" i \"git push --help\" för " +"detaljer.\n" + +#: builtin/push.c:160 +#, c-format +msgid "bad repository '%s'" +msgstr "felaktigt arkiv \"%s\"" + +#: builtin/push.c:161 +msgid "" +"No configured push destination.\n" +"Either specify the URL from the command-line or configure a remote " +"repository using\n" +"\n" +" git remote add <name> <url>\n" +"\n" +"and then push using the remote name\n" +"\n" +" git push <name>\n" +msgstr "" +"Ingen destination har angivits.\n" +"Ange antingen URL:en på kommandoraden eller ställ in ett uppströmsarkiv med\n" +"\n" +" git remote add <namn> <url>\n" +"\n" +"och sänd sedan med hjälp av fjärrnamnet\n" +"\n" +" git push <namn>\n" + +#: builtin/push.c:176 +msgid "--all and --tags are incompatible" +msgstr "--all och --tags är inkompatibla" + +#: builtin/push.c:177 +msgid "--all can't be combined with refspecs" +msgstr "--all kan inte kombineras med referensspecifikationer" + +#: builtin/push.c:182 +msgid "--mirror and --tags are incompatible" +msgstr "--mirror och --tags är inkompatibla" + +#: builtin/push.c:183 +msgid "--mirror can't be combined with refspecs" +msgstr "--mirror kan inte kombineras med referensspecifikationer" + +#: builtin/push.c:188 +msgid "--all and --mirror are incompatible" +msgstr "--all och --mirror är inkompatibla" + +#: builtin/push.c:274 +msgid "--delete is incompatible with --all, --mirror and --tags" +msgstr "--delete är imkompatibel med --all, --mirror och --tags" + +#: builtin/push.c:276 +msgid "--delete doesn't make sense without any refs" +msgstr "--delete kan inte användas utan referenser" + +#: builtin/reset.c:33 +msgid "mixed" +msgstr "blandad" + +#: builtin/reset.c:33 +msgid "soft" +msgstr "mjuk" + +#: builtin/reset.c:33 +msgid "hard" +msgstr "hård" + +#: builtin/reset.c:33 +msgid "keep" +msgstr "behåll" + +#: builtin/reset.c:77 +msgid "You do not have a valid HEAD." +msgstr "Du har inte en giltig HEAD." + +#: builtin/reset.c:79 +msgid "Failed to find tree of HEAD." +msgstr "Kunde inte hitta träder för HEAD." + +#: builtin/reset.c:85 +#, c-format +msgid "Failed to find tree of %s." +msgstr "Kunde inte hitta träder för %s." + +#: builtin/reset.c:96 +msgid "Could not write new index file." +msgstr "Kunde inte skriva ny indexfil." + +#: builtin/reset.c:106 +#, c-format +msgid "HEAD is now at %s" +msgstr "HEAD är nu på %s" + +#: builtin/reset.c:130 +msgid "Could not read index" +msgstr "Kunde inte läsa indexet" + +#: builtin/reset.c:133 +msgid "Unstaged changes after reset:" +msgstr "Oköade ändringar efter återställning:" + +#: builtin/reset.c:223 +#, c-format +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 +#, c-format +msgid "Could not parse object '%s'." +msgstr "Kan inte tolka objektet \"%s\"" + +#: builtin/reset.c:302 +msgid "--patch is incompatible with --{hard,mixed,soft}" +msgstr "--patch är inkompatibel med --{hard,mixed,soft}" + +#: builtin/reset.c:311 +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 +#, 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 +#, 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 +#, c-format +msgid "Could not reset index file to revision '%s'." +msgstr "Kunde inte återställa indexfilen till versionen \"%s\"." + +#: builtin/revert.c:70 builtin/revert.c:91 +#, c-format +msgid "%s: %s cannot be used with %s" +msgstr "%s: %s kan inte användas med %s" + +#: builtin/revert.c:126 +msgid "program error" +msgstr "programfel" + +#: builtin/revert.c:209 +msgid "revert failed" +msgstr "\"revert\" misslyckades" + +#: builtin/revert.c:224 +msgid "cherry-pick failed" +msgstr "\"cherry-pick\" misslyckades" + +#: builtin/rm.c:109 +#, c-format +msgid "" +"'%s' has staged content different from both the file and the HEAD\n" +"(use -f to force removal)" +msgstr "" +"\"%s\" har köat ändringar som skiljer sig både från filen och HEAD\n" +"(använd -f för att tvinga borttagning)" + +#: builtin/rm.c:115 +#, c-format +msgid "" +"'%s' has changes staged in the index\n" +"(use --cached to keep the file, or -f to force removal)" +msgstr "" +"\"%s\" har köade ändringar i indexet\n" +"(använd --cached för att behålla filen eller -f för att tvinga borttagning)" + +#: builtin/rm.c:119 +#, c-format +msgid "" +"'%s' has local modifications\n" +"(use --cached to keep the file, or -f to force removal)" +msgstr "" +"\"%s\" har lokala ändringar\n" +"(använd --cached för att behålla filen eller -f för att tvinga borttagning)" + +#: builtin/rm.c:194 +#, c-format +msgid "not removing '%s' recursively without -r" +msgstr "tar inte bort \"%s\" rekursivt utan -r" + +#: builtin/rm.c:230 +#, c-format +msgid "git rm: unable to remove %s" +msgstr "git rm: kan inte ta bort %s" + +#: builtin/shortlog.c:157 +#, c-format +msgid "Missing author: %s" +msgstr "Författare saknas: %s" + +#: builtin/tag.c:58 +#, c-format +msgid "malformed object at '%s'" +msgstr "felformat objekt vid \"%s\"" + +#: builtin/tag.c:205 +#, c-format +msgid "tag name too long: %.*s..." +msgstr "taggnamnet för långt: %.*s..." + +#: builtin/tag.c:210 +#, c-format +msgid "tag '%s' not found." +msgstr "taggen \"%s\" hittades inte." + +#: builtin/tag.c:225 +#, c-format +msgid "Deleted tag '%s' (was %s)\n" +msgstr "Tog bort tagg \"%s\" (var %s)\n" + +#: builtin/tag.c:237 +#, c-format +msgid "could not verify the tag '%s'" +msgstr "kunde inte bekräfta taggen \"%s\"" + +#: builtin/tag.c:247 +msgid "" +"\n" +"#\n" +"# Write a tag message\n" +"# Lines starting with '#' will be ignored.\n" +"#\n" +msgstr "" +"\n" +"#\n" +"# Skriv ett taggmeddelande\n" +"# Rader som inleds med \"#\" ignoreras.\n" +"#\n" + +#: builtin/tag.c:254 +msgid "" +"\n" +"#\n" +"# Write a tag message\n" +"# Lines starting with '#' will be kept; you may remove them yourself if you " +"want to.\n" +"#\n" +msgstr "" +"\n" +"#\n" +"# Skriv ett taggmeddelande\n" +"# Rader som inleds med \"#\" kommer behållas; du kan själv ta bort dem om\n" +"# du vill.\n" +"#\n" + +#: builtin/tag.c:294 +msgid "unable to sign the tag" +msgstr "kunde inte signera taggen" + +#: builtin/tag.c:296 +msgid "unable to write tag file" +msgstr "kunde inte skriva tagg-filen" + +#: builtin/tag.c:321 +msgid "bad object type." +msgstr "felaktig objekttyp" + +#: builtin/tag.c:334 +msgid "tag header too big." +msgstr "tagghuvud för stort." + +#: builtin/tag.c:366 +msgid "no tag message?" +msgstr "inget taggmeddelande?" + +#: builtin/tag.c:372 +#, c-format +msgid "The tag message has been left in %s\n" +msgstr "Taggmeddelandet har lämnats i %s\n" + +#: builtin/tag.c:421 +msgid "switch 'points-at' requires an object" +msgstr "flaggan \"points-at\" behöver ett object" + +#: builtin/tag.c:423 +#, c-format +msgid "malformed object name '%s'" +msgstr "felformat objektnamn \"%s\"" + +#: builtin/tag.c:502 +msgid "-n option is only allowed with -l." +msgstr "Flaggan -n är endast tillåten tillsammans med -l." + +#: builtin/tag.c:504 +msgid "--contains option is only allowed with -l." +msgstr "Flaggan --contains är endast tillåten tillsammans med -l" + +#: builtin/tag.c:506 +msgid "--points-at option is only allowed with -l." +msgstr "Flaggan --points-at är endast tillåten tillsammans med -l." + +#: builtin/tag.c:514 +msgid "only one -F or -m option is allowed." +msgstr "endast en av flaggorna -F eller -m tillåts." + +#: builtin/tag.c:534 +msgid "too many params" +msgstr "för många parametrar" + +#: builtin/tag.c:540 +#, c-format +msgid "'%s' is not a valid tag name." +msgstr "\"%s\" är inte ett giltigt taggnamn." + +#: builtin/tag.c:545 +#, c-format +msgid "tag '%s' already exists" +msgstr "taggen \"%s\" finns redan" + +#: builtin/tag.c:563 +#, c-format +msgid "%s: cannot lock the ref" +msgstr "%s: kan inte låsa referensen" + +#: builtin/tag.c:565 +#, c-format +msgid "%s: cannot update the ref" +msgstr "%s: kan inte uppdatera referensen" + +#: builtin/tag.c:567 +#, c-format +msgid "Updated tag '%s' (was %s)\n" +msgstr "Uppdaterad tagg \"%s\" (var %s)\n" + +#: git-am.sh:49 +msgid "You need to set your committer info first" +msgstr "Du måste ställa in din incheckarinformation först" + +#: git-am.sh:136 +msgid "Repository lacks necessary blobs to fall back on 3-way merge." +msgstr "" +"Arkivet saknar objekt som behövs för att falla tillbaka på 3-" +"vägssammanslagning." + +#: git-am.sh:147 +msgid "" +"Did you hand edit your patch?\n" +"It does not apply to blobs recorded in its index." +msgstr "" +"Har du handredigerat din patch?\n" +"Den kan inte appliceras på blobbar som antecknats i dess index." + +#: git-am.sh:156 +msgid "Falling back to patching base and 3-way merge..." +msgstr "" +"Faller tillbaka på att pacha grundversionen och trevägssammanslagning..." + +#: git-am.sh:268 +msgid "Only one StGIT patch series can be applied at once" +msgstr "Endast en StGIT-patchserie kan appliceras åt gången" + +#: git-am.sh:355 +#, sh-format +msgid "Patch format $patch_format is not supported." +msgstr "Patchformatet $patch_format stöds inte." + +#: git-am.sh:357 +msgid "Patch format detection failed." +msgstr "Misslyckades detektera patchformat." + +#: git-am.sh:409 +msgid "-d option is no longer supported. Do not use." +msgstr "Flaggan -d stöds inte lägre. Använd inte." + +#: git-am.sh:472 +#, 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:477 +msgid "Please make up your mind. --skip or --abort?" +msgstr "Bestäm dig. --skip eller --abort?" + +#: git-am.sh:504 +msgid "Resolve operation not in progress, we are not resuming." +msgstr "Lösningsoperation pågår inte, vi återupptar inte." + +#: git-am.sh:570 +#, sh-format +msgid "Dirty index: cannot apply patches (dirty: $files)" +msgstr "Smutsigt index: kan inte applicera patchar (smutsiga: $files)" + +#: git-am.sh:746 +msgid "cannot be interactive without stdin connected to a terminal." +msgstr "" +"kan inte vara interaktiv om standard in inte är ansluten till en terminal." + +#. 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:757 +msgid "Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all " +msgstr "Applicera? Y=ja/N=nej/E=redigera/V=visa patch/A=godta alla " + +#: git-am.sh:793 +#, sh-format +msgid "Applying: $FIRSTLINE" +msgstr "Applicerar: $FIRSTLINE" + +#: git-am.sh:838 +msgid "No changes -- Patch already applied." +msgstr "Inga ändringar -- Patchen har redan applicerats." + +#: git-am.sh:864 +msgid "applying to an empty history" +msgstr "applicerar på en tom historik" + +#. TRANSLATORS: Make sure to include [Y] and [n] in your +#. translation. The program will only accept English input +#. at this point. +#: git-bisect.sh:54 +msgid "Do you want me to do it for you [Y/n]? " +msgstr "Vill du att jag ska göra det åt dig [Y=ja/N=nej]?" + +#: git-bisect.sh:95 +#, sh-format +msgid "unrecognised option: '$arg'" +msgstr "flaggan känns inte igen: \"$arg\"" + +#: git-bisect.sh:99 +#, sh-format +msgid "'$arg' does not appear to be a valid revision" +msgstr "\"$arg\" verkar inte vara en giltig revision" + +#: git-bisect.sh:117 +msgid "Bad HEAD - I need a HEAD" +msgstr "Felaktigt HEAD - Jag behöver ett HEAD" + +#: git-bisect.sh:130 +#, sh-format +msgid "" +"Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'." +msgstr "" +"Misslyckades checka ut \"$start_head\". Försök \"git bisect reset " +"<giltiggren>\"" + +# cogito-relaterat +#: git-bisect.sh:140 +msgid "won't bisect on seeked tree" +msgstr "kör inte \"bisect\" på ett \"seeked\"-träd" + +#: git-bisect.sh:144 +msgid "Bad HEAD - strange symbolic ref" +msgstr "Felaktigt HEAD - konstig symbolisk referens" + +#: git-bisect.sh:189 +#, sh-format +msgid "Bad bisect_write argument: $state" +msgstr "Felaktigt argument till bisect_write: $state" + +#: git-bisect.sh:218 +#, sh-format +msgid "Bad rev input: $arg" +msgstr "Felaktig rev-indata: $arg" + +#: git-bisect.sh:232 +msgid "Please call 'bisect_state' with at least one argument." +msgstr "Anropa \"bisect_state\" med minst ett argument." + +#: git-bisect.sh:244 +#, sh-format +msgid "Bad rev input: $rev" +msgstr "Felaktig rev-indata: $rev" + +#: git-bisect.sh:250 +msgid "'git bisect bad' can take only one argument." +msgstr "\"git bisect bad\" kan bara ta ett argument." + +#. TRANSLATORS: Make sure to include [Y] and [n] in your +#. translation. The program will only accept English input +#. at this point. +#: git-bisect.sh:279 +msgid "Are you sure [Y/n]? " +msgstr "Är du säker [Y=ja/N=nej]? " + +#: git-bisect.sh:354 +#, sh-format +msgid "'$invalid' is not a valid commit" +msgstr "\"$invalid\" är inte en giltig incheckning" + +#: git-bisect.sh:363 +#, sh-format +msgid "" +"Could not check out original HEAD '$branch'.\n" +"Try 'git bisect reset <commit>'." +msgstr "" +"Kunde inte checka ut original-HEAD \"$branch\".\n" +"Försök \"git bisect reset <incheckning>\"." + +#: git-bisect.sh:390 +msgid "No logfile given" +msgstr "Ingen loggfil angiven" + +#: git-bisect.sh:391 +#, sh-format +msgid "cannot read $file for replaying" +msgstr "kan inte läsa $file för uppspelning" + +#: git-bisect.sh:408 +msgid "?? what are you talking about?" +msgstr "?? vad menar du?" + +#: git-bisect.sh:474 +msgid "We are not bisecting." +msgstr "Vi utför ingen bisect för tillfället." + +#: git-pull.sh:21 +msgid "" +"Pull is not possible because you have unmerged files.\n" +"Please, fix them up in the work tree, and then use 'git add/rm <file>'\n" +"as appropriate to mark resolution, or use 'git commit -a'." +msgstr "" +"Du kan inte göra en \"pull\" då du har ändringar som inte checkats in.\n" +"Rätta dem i din arbetskatalog och använd sedan \"git add/rm <fil>\"\n" +"där det är lämpligt för att ange lösning, eller använd \"git commit -a\"." + +#: git-pull.sh:25 +msgid "Pull is not possible because you have unmerged files." +msgstr "Du kan inte göra en \"pull\" då du har ändringar som inte checkats in." + +#: git-pull.sh:197 +msgid "updating an unborn branch with changes added to the index" +msgstr "uppdaterar en ofödd gren med ändringar som lagts till i indexet" + +#: git-pull.sh:253 +msgid "Cannot merge multiple branches into empty head" +msgstr "Kan inte slå ihop flera grenar i ett tomt huvud." + +#: git-pull.sh:257 +msgid "Cannot rebase onto multiple branches" +msgstr "Kan inte utföra en \"rebase\" ovanpå flera grenar" + +#: git-stash.sh:51 +msgid "git stash clear with parameters is unimplemented" +msgstr "\"git stash clear\" med parametrar har inte implementerats" + +#: git-stash.sh:74 +msgid "You do not have the initial commit yet" +msgstr "Du har inte den första incheckningen ännu" + +#: git-stash.sh:89 +msgid "Cannot save the current index state" +msgstr "Kan inte spara aktuellt tillstånd för indexet" + +#: git-stash.sh:123 git-stash.sh:136 +msgid "Cannot save the current worktree state" +msgstr "Kan inte spara aktuellt tillstånd för arbetskatalogen" + +#: git-stash.sh:140 +msgid "No changes selected" +msgstr "Inga ändringar valda" + +#: git-stash.sh:143 +msgid "Cannot remove temporary index (can't happen)" +msgstr "Kan inte ta bort temporärt index (kan inte inträffa)" + +#: git-stash.sh:156 +msgid "Cannot record working tree state" +msgstr "Kan inte registrera tillstånd för arbetskatalog" + +#: git-stash.sh:223 +msgid "No local changes to save" +msgstr "Inga lokala ändringar att spara" + +#: git-stash.sh:227 +msgid "Cannot initialize stash" +msgstr "Kan inte initiera \"stash\"" + +#: git-stash.sh:235 +msgid "Cannot save the current status" +msgstr "Kan inte spara aktuell status" + +#: git-stash.sh:253 +msgid "Cannot remove worktree changes" +msgstr "Kan inte ta bort ändringar i arbetskatalogen" + +#: git-stash.sh:352 +msgid "No stash found." +msgstr "Ingen \"stash\" hittades." + +#: git-stash.sh:359 +#, sh-format +msgid "Too many revisions specified: $REV" +msgstr "För många revisioner angivna: $REV" + +#: git-stash.sh:365 +#, sh-format +msgid "$reference is not valid reference" +msgstr "$reference är inte en giltig referens." + +#: git-stash.sh:393 +#, sh-format +msgid "'$args' is not a stash-like commit" +msgstr "\"$args\" är inte en \"stash\"-liknande incheckning" + +#: git-stash.sh:404 +#, sh-format +msgid "'$args' is not a stash reference" +msgstr "\"$args\" är inte en \"stash\"-referens" + +#: git-stash.sh:412 +msgid "unable to refresh index" +msgstr "kan inte uppdatera indexet" + +#: git-stash.sh:416 +msgid "Cannot apply a stash in the middle of a merge" +msgstr "Kan inte applicera en \"stash\" mitt i en sammanslagning" + +#: git-stash.sh:424 +msgid "Conflicts in index. Try without --index." +msgstr "Konflikter i indexet. Testa utan --index." + +#: git-stash.sh:426 +msgid "Could not save index tree" +msgstr "Kunde inte spara indexträd" + +#: git-stash.sh:460 +msgid "Cannot unstage modified files" +msgstr "Kan inte ta bort ändrade filer ur kön" + +#: git-stash.sh:491 +#, sh-format +msgid "Dropped ${REV} ($s)" +msgstr "Kastade ${REV} ($s)" + +#: git-stash.sh:492 +#, sh-format +msgid "${REV}: Could not drop stash entry" +msgstr "${REV}: Kunde inte kasta \"stash\"-post" + +#: git-stash.sh:499 +msgid "No branch name specified" +msgstr "Inget grennamn angavs" + +#: git-stash.sh:570 +msgid "(To restore them type \"git stash apply\")" +msgstr "(För att återställa dem, skriv \"git stash apply\")" + +#: git-submodule.sh:56 +#, sh-format +msgid "cannot strip one component off url '$remoteurl'" +msgstr "kan inte ta bort en komponent från url:en \"$remoteurl\"" + +#: git-submodule.sh:108 +#, sh-format +msgid "No submodule mapping found in .gitmodules for path '$path'" +msgstr "Hittade ingen undermodulmappning i .gitmodules för sökvägen \"$path\"" + +#: git-submodule.sh:173 +#, sh-format +msgid "Clone of '$url' into submodule path '$path' failed" +msgstr "Misslyckades klona \"$url\" till undermodulsökvägen \"$path\"" + +#: git-submodule.sh:247 +#, 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:264 +#, sh-format +msgid "'$path' already exists in the index" +msgstr "\"$path\" finns redan i indexet" + +#: git-submodule.sh:281 +#, sh-format +msgid "'$path' already exists and is not a valid git repo" +msgstr "\"$path\" finns redan och är inte ett giltigt git-arkiv" + +#: git-submodule.sh:295 +#, sh-format +msgid "Unable to checkout submodule '$path'" +msgstr "Kan inte checka ut undermodul \"$path\"" + +#: git-submodule.sh:300 +#, sh-format +msgid "Failed to add submodule '$path'" +msgstr "Misslyckades lägga till underkatalog \"$path\"" + +#: git-submodule.sh:305 +#, sh-format +msgid "Failed to register submodule '$path'" +msgstr "Misslyckades registrera undermodul \"$path\"" + +#: git-submodule.sh:347 +#, sh-format +msgid "Entering '$prefix$path'" +msgstr "Går in i \"$prefix$path\"" + +#: git-submodule.sh:359 +#, sh-format +msgid "Stopping at '$path'; script returned non-zero status." +msgstr "Stoppar på \"$path\"; skriptet returnerade en status skild från noll." + +#: git-submodule.sh:401 +#, sh-format +msgid "No url found for submodule path '$path' in .gitmodules" +msgstr "Hittade ingen url för undermodulsökvägen \"$path\" i .gitmodules" + +#: git-submodule.sh:410 +#, sh-format +msgid "Failed to register url for submodule path '$path'" +msgstr "Misslyckades registrera url för underkatalogsökväg \"$path\"" + +#: git-submodule.sh:418 +#, sh-format +msgid "Failed to register update mode for submodule path '$path'" +msgstr "" +"Misslyckades registrera uppdateringsläge för undermodulsökväg \"$path\"" + +#: git-submodule.sh:420 +#, sh-format +msgid "Submodule '$name' ($url) registered for path '$path'" +msgstr "Undermodulen \"$name\" ($url) registrerad för sökvägen \"$path\"" + +#: git-submodule.sh:519 +#, sh-format +msgid "" +"Submodule path '$path' not initialized\n" +"Maybe you want to use 'update --init'?" +msgstr "" +"Undermodulen \"$path\" har inte initierats\n" +"Kanske du vill köra \"update --init\"?" + +#: git-submodule.sh:532 +#, sh-format +msgid "Unable to find current revision in submodule path '$path'" +msgstr "Kan inte hitta aktuell revision i undermodulsökväg \"$path\"" + +#: git-submodule.sh:551 +#, sh-format +msgid "Unable to fetch in submodule path '$path'" +msgstr "Kan inte hämta i undermodulsökväg \"$path\"" + +#: git-submodule.sh:565 +#, sh-format +msgid "Unable to rebase '$sha1' in submodule path '$path'" +msgstr "Kan inte göra \"rebase\" av \"$sha1\" i undermodulsökväg \"$path\"" + +#: git-submodule.sh:566 +#, sh-format +msgid "Submodule path '$path': rebased into '$sha1'" +msgstr "Undermodulsökvägen \"$path\": \"rebase\":ad in i \"$sha1\"" + +#: git-submodule.sh:571 +#, sh-format +msgid "Unable to merge '$sha1' in submodule path '$path'" +msgstr "Kan inte slå ihop \"$sha1\" i undermodulsökvägen \"$path\"" + +#: git-submodule.sh:572 +#, sh-format +msgid "Submodule path '$path': merged in '$sha1'" +msgstr "Undermodulsökvägen \"$path\": sammanslagen i \"$sha1\"" + +#: git-submodule.sh:577 +#, sh-format +msgid "Unable to checkout '$sha1' in submodule path '$path'" +msgstr "Kan inte checka ut \"$sha1\" i undermodulsökvägen \"$path\"" + +#: git-submodule.sh:578 +#, sh-format +msgid "Submodule path '$path': checked out '$sha1'" +msgstr "Undermodulsökvägen \"$path\": checkade ut \"$sha1\"" + +#: git-submodule.sh:600 git-submodule.sh:923 +#, sh-format +msgid "Failed to recurse into submodule path '$path'" +msgstr "Misslyckades rekursera in i undermodulsökvägen \"$path\"" + +#: git-submodule.sh:708 +msgid "--" +msgstr "--" + +#: git-submodule.sh:766 +#, sh-format +msgid " Warn: $name doesn't contain commit $sha1_src" +msgstr " Varning: $name innehåller inte incheckning $sha1_src" + +#: git-submodule.sh:769 +#, sh-format +msgid " Warn: $name doesn't contain commit $sha1_dst" +msgstr " Varning: $name innehåller inte incheckning $sha1_dst" + +#: git-submodule.sh:772 +#, 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:797 +msgid "blob" +msgstr "blob" + +#: git-submodule.sh:798 +msgid "submodule" +msgstr "undermodul" + +#: git-submodule.sh:969 +#, sh-format +msgid "Synchronizing submodule url for '$name'" +msgstr "Synkroniserar undermodul-url för \"$name\"" + +#~ msgid "# Changed but not updated:" +#~ msgstr "# Ändrade men inte uppdaterade:" + +#~ msgid "A branch named '%s' already exists." +#~ msgstr "Det finns redan en gren som heter \"%s\"" + +#~ msgid "path '%s' does not have all 3 versions" +#~ msgstr "sökvägen \"%s\" har inte alla 3 versionerna" + +#~ msgid "git checkout: we do not like '%s' as a branch name." +#~ msgstr "git checkout: vi tycker inte om \"%s\" som namn på en gren." + +#~ msgid "git checkout: branch %s already exists" +#~ msgstr "git checkout: grenen %s finns redan" + +#~ msgid "Paths with --interactive does not make sense." +#~ msgstr "Kan inte ange sökvägar med --interactive." + +#~ msgid "No HEAD commit to compare with (yet)" +#~ msgstr "Ingen HEAD-incheckning att jämföra med (ännu)" + +#~ msgid "cannot mix --fixed-strings and regexp" +#~ msgstr "kan inte blanda --fixed-strings och reguljära uttryck" + +#~ msgid "invalid --decorate option: %s" +#~ msgstr "felaktigt värde till --decorate: %s" + +#~ msgid "%s; will overwrite!" +#~ msgstr "%s; kommer skriva över!" + +#~ msgid "Failed to write current notes tree to database" +#~ msgstr "Kunde inte skriva aktuellt anteckningsträd till databasen" + +#~ msgid "Failed to commit notes tree to database" +#~ msgstr "Kunde inte checka in anteckningsträd i databasen" + +# FIXME: Untranslatable! +# +#~ msgid "Refusing to %s notes in %s (outside of refs/notes/)" +#~ msgstr "Vägrar %s anteckningar i %s (utanför refs/notes/)" + +#~ msgid "list" +#~ msgstr "list" + +#~ msgid "add" +#~ msgstr "add" + +#~ msgid "copy" +#~ msgstr "copy" + +#~ msgid "show" +#~ msgstr "show" + +#~ msgid "remove" +#~ msgstr "remove" + +#~ msgid "prune" +#~ msgstr "prune" + +#~ msgid "The current branch %s is not tracking anything." +#~ msgstr "Den aktuella grenen %s spårar ingenting." + +#~ msgid "No destination configured to push to." +#~ msgstr "Har inte ställt in någon destination att sända till." + +#~ msgid "Reflog action message too long: %.*s..." +#~ msgstr "Reflog-händelsemeddelande för långt: %.*s..." + +#~ msgid "Could not read commit message of %s" +#~ msgstr "Kunde inte läsa incheckningsmeddelandet för %s" + +#~ msgid "Could not extract author email from %s" +#~ msgstr "Kunde inte hämta författarens e-postadress från %s" + +#~ msgid "Could not extract author time from %s" +#~ msgstr "Kunde inte hämta författartid från %s" + +#~ msgid "No author information found in %s" +#~ msgstr "Hittade ingen författarinformation i %s" + +#~ msgid "cherry-pick --ff cannot be used with --signoff" +#~ msgstr "cherry-pick --ff kan inte användas med --signoff" + +#~ msgid "cherry-pick --ff cannot be used with --no-commit" +#~ msgstr "cherry-pick --ff kan inte användas med --no-commit" + +#~ msgid "cherry-pick --ff cannot be used with -x" +#~ msgstr "cherry-pick --ff kan inte användas med -x" + +#~ msgid "cherry-pick --ff cannot be used with --edit" +#~ msgstr "cherry-pick --ff kan inte användas med --edit" + +#~ msgid "committer info too long." +#~ msgstr "incheckarinformation för lång." + +#~ msgid "" +#~ "\n" +#~ "#\n" +#~ "# Write a tag message\n" +#~ "#\n" +#~ msgstr "" +#~ "\n" +#~ "#\n" +#~ "# Skriv ett taggmeddelande\n" +#~ "#\n" + +#~ msgid "signing key value too long (%.10s...)" +#~ msgstr "signeringsnyckelvärdet för långt (%.10s...)" + +#~ 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\"." +#~ 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" +#~ "För att återställa originalgrenen och avbryta kör du \"$cmdline --abort\"." + +#~ msgid "" +#~ "Patch is empty. Was it split wrong?\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\"." +#~ msgstr "" +#~ "Patchen är tom. Delades den upp felaktigt?\n" +#~ "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\"." + +#~ msgid "Patch does not have a valid e-mail address." +#~ msgstr "Patchen har inte någon giltig e-postadress." + +#~ msgid "Commit Body is:" +#~ msgstr "Incheckningskroppen är:" + +#~ 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 "" +#~ "Inga ändringar - glömde du använda \"git add\"?\n" +#~ "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." + +#~ msgid "" +#~ "You still have unmerged paths in your index\n" +#~ "did you forget to use 'git add'?" +#~ msgstr "" +#~ "Du har fortfarande sökvägar som inte slagits samman i ditt index\n" +#~ "glömde du använda \"git add\"?" + +#~ msgid "Patch failed at $msgnum $FIRSTLINE" +#~ msgstr "Patchen misslyckades vid $msgnum $FIRSTLINE" + +#, fuzzy +#~ msgid "You need to start by \"git bisect start\"" +#~ msgstr "Du måste ställa in din incheckarinformation först" + +#, fuzzy +#~ msgid "Index was not unstashed." +#~ msgstr "kunde köra stash." + +#, fuzzy +#~ msgid "# Submodules changed but not updated:" +#~ msgstr "# Ändrade men inte uppdaterade:" + +#, fuzzy +#~ msgid "# Submodule changes to be committed:" +#~ msgstr "# Ändringar att checka in:" diff --git a/po/zh_CN.po b/po/zh_CN.po new file mode 100644 index 0000000000..713542fdcd --- /dev/null +++ b/po/zh_CN.po @@ -0,0 +1,3683 @@ +# Chinese translations for Git package +# Git 软件包的简体中文翻译. +# Copyright (C) 2012 Jiang Xin <worldhello.net AT gmail.com> +# This file is distributed under the same license as the Git package. +# Contributers: +# - Jiang Xin <worldhello.net AT gmail.com> +# - Riku <lu.riku AT gmail.com> +# - Zhuang Ya <zhuangya AT me.com> +# - Lian Cheng <rhythm.mail AT gmail.com> +# +msgid "" +msgstr "" +"Project-Id-Version: Git\n" +"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n" +"POT-Creation-Date: 2012-03-08 10:19+0800\n" +"PO-Revision-Date: 2012-01-30 00:00+0800\n" +"Last-Translator: Jiang Xin <worldhello.net@gmail.com>\n" +"Language-Team: GitHub <https://github.com/gotgit/git/>\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: advice.c:34 +#, c-format +msgid "hint: %.*s\n" +msgstr "提示:%.*s\n" + +#. +#. * Message used both when 'git commit' fails and when +#. * other commands doing a merge do. +#. +#: advice.c:64 +msgid "" +"Fix them up in the work tree,\n" +"and then use 'git add/rm <file>' as\n" +"appropriate to mark resolution and make a commit,\n" +"or use 'git commit -a'." +msgstr "" +"请先在工作区改正文件,然后酌情使用\n" +"'git add/rm <file>' 标记解决方案,\n" +"或使用 'git commit -a'。" + +#: commit.c:47 +#, c-format +msgid "could not parse %s" +msgstr "不能解析 %s" + +#: commit.c:49 +#, c-format +msgid "%s %s is not a commit!" +msgstr "%s %s 不是一个提交!" + +#: compat/obstack.c:406 compat/obstack.c:408 +msgid "memory exhausted" +msgstr "内存耗尽" + +#: connected.c:39 +msgid "Could not run 'git rev-list'" +msgstr "不能执行 'git rev-list'" + +#: connected.c:48 +#, c-format +msgid "failed write to rev-list: %s" +msgstr "无法写入 rev-list:%s" + +#: connected.c:56 +#, c-format +msgid "failed to close rev-list's stdin: %s" +msgstr "无法关闭 rev-list 的标准输入:%s" + +# 注意保持前导空格 +#: diff.c:105 +#, c-format +msgid " Failed to parse dirstat cut-off percentage '%.*s'\n" +msgstr " 无法解析 dirstat 阈值 '%.*s'\n" + +# 注意保持前导空格 +#: diff.c:110 +#, c-format +msgid " Unknown dirstat parameter '%.*s'\n" +msgstr " 未知 dirstat 参数 '%.*s'\n" + +#: diff.c:210 +#, c-format +msgid "" +"Found errors in 'diff.dirstat' config variable:\n" +"%s" +msgstr "" +"配置变量 'diff.dirstat' 出错:\n" +"%s" + +#: diff.c:1336 +msgid " 0 files changed\n" +msgstr "0 个文件被修改\n" + +#: diff.c:1340 +#, c-format +msgid " %d file changed" +msgid_plural " %d files changed" +msgstr[0] " %d 个文件被修改" + +#: diff.c:1357 +#, c-format +msgid ", %d insertion(+)" +msgid_plural ", %d insertions(+)" +msgstr[0] ",插入 %d 行(+)" + +#: diff.c:1368 +#, c-format +msgid ", %d deletion(-)" +msgid_plural ", %d deletions(-)" +msgstr[0] ",删除 %d 行(-)" + +#: diff.c:3424 +#, c-format +msgid "" +"Failed to parse --dirstat/-X option parameter:\n" +"%s" +msgstr "" +"无法解析 --dirstat/-X 选项的参数:\n" +"%s" + +#: gpg-interface.c:59 +msgid "could not run gpg." +msgstr "不能执行 gpg。" + +#: gpg-interface.c:71 +msgid "gpg did not accept the data" +msgstr "gpg 没有接受数据" + +#: gpg-interface.c:82 +msgid "gpg failed to sign the data" +msgstr "gpg 无法为数据签名" + +#: grep.c:1280 +#, c-format +msgid "'%s': unable to read %s" +msgstr "'%s':无法读取 %s" + +#: grep.c:1297 +#, c-format +msgid "'%s': %s" +msgstr "'%s':%s" + +#: grep.c:1308 +#, c-format +msgid "'%s': short read %s" +msgstr "'%s':读取不完整 %s" + +#: help.c:287 +#, 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 "" +"'%s' 像是一个 git 命令,但却无法运行。\n" +"可能是 git-%s 受损?" + +#: remote.c:1607 +#, 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" + +#: remote.c:1613 +#, 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] "您的分支落后 '%s' 共 %d 个提交,且可以快进。\n" + +#: remote.c:1621 +#, c-format +msgid "" +"Your branch and '%s' have diverged,\n" +"and have %d and %d different commit each, respectively.\n" +msgid_plural "" +"Your branch and '%s' have diverged,\n" +"and have %d and %d different commits each, respectively.\n" +msgstr[0] "" +"您的分支和 '%s' 出现了偏离,\n" +"并且各自分别有 %d 和 %d 处不同的提交。\n" + +#: sequencer.c:120 builtin/merge.c:864 builtin/merge.c:985 +#: builtin/merge.c:1095 builtin/merge.c:1105 +#, c-format +msgid "Could not open '%s' for writing" +msgstr "无法打开 '%s' 以写入" + +#: sequencer.c:122 builtin/merge.c:334 builtin/merge.c:867 +#: builtin/merge.c:1097 builtin/merge.c:1110 +#, c-format +msgid "Could not write to '%s'" +msgstr "无法写入 '%s'" + +#: sequencer.c:143 +msgid "" +"after resolving the conflicts, mark the corrected paths\n" +"with 'git add <paths>' or 'git rm <paths>'" +msgstr "" +"冲突解决完毕后,用 'git add <paths>' 或 'git rm <paths>'\n" +"命令标记修正后的文件" + +#: sequencer.c:146 +msgid "" +"after resolving the conflicts, mark the corrected paths\n" +"with 'git add <paths>' or 'git rm <paths>'\n" +"and commit the result with 'git commit'" +msgstr "" +"冲突解决完毕后,用 'git add <paths>' 或 'git rm <paths>'\n" +"对修正后的文件做标记,然后用 'git commit' 提交" + +#: sequencer.c:159 sequencer.c:685 sequencer.c:768 +#, c-format +msgid "Could not write to %s" +msgstr "不能写入 %s" + +#: sequencer.c:162 +#, c-format +msgid "Error wrapping up %s" +msgstr "错误收尾 %s" + +#: sequencer.c:177 +msgid "Your local changes would be overwritten by cherry-pick." +msgstr "您的本地修改将被拣选操作覆盖。" + +#: sequencer.c:179 +msgid "Your local changes would be overwritten by revert." +msgstr "您的本地修改将被还原操作覆盖。" + +#: sequencer.c:182 +msgid "Commit your changes or stash them to proceed." +msgstr "提交您的修改或保存进度后再继续。" + +#. TRANSLATORS: %s will be "revert" or "cherry-pick" +#: sequencer.c:232 +#, c-format +msgid "%s: Unable to write new index file" +msgstr "%s:无法写入新暂存区文件" + +#: sequencer.c:298 +msgid "Your index file is unmerged." +msgstr "您的暂存区文件未完成合并。" + +#: sequencer.c:301 +msgid "You do not have a valid HEAD" +msgstr "您没有一个有效的 HEAD" + +#: sequencer.c:316 +#, c-format +msgid "Commit %s is a merge but no -m option was given." +msgstr "提交 %s 是一个合并提交但未提供 -m 选项。" + +#: sequencer.c:324 +#, c-format +msgid "Commit %s does not have parent %d" +msgstr "提交 %s 没有父提交 %d" + +#: sequencer.c:328 +#, c-format +msgid "Mainline was specified but commit %s is not a merge." +msgstr "提供了主线但提交 %s 不是一个合并。" + +#. TRANSLATORS: The first %s will be "revert" or +#. "cherry-pick", the second %s a SHA1 +#: sequencer.c:339 +#, c-format +msgid "%s: cannot parse parent commit %s" +msgstr "%s:不能解析父提交 %s" + +#: sequencer.c:343 +#, c-format +msgid "Cannot get commit message for %s" +msgstr "不能得到 %s 的提交说明" + +#: sequencer.c:427 +#, c-format +msgid "could not revert %s... %s" +msgstr "不能还原 %s... %s" + +#: sequencer.c:428 +#, c-format +msgid "could not apply %s... %s" +msgstr "不能应用 %s... %s" + +#: sequencer.c:450 sequencer.c:909 builtin/log.c:288 builtin/log.c:713 +#: builtin/log.c:1329 builtin/log.c:1548 builtin/merge.c:348 +#: builtin/shortlog.c:181 +msgid "revision walk setup failed" +msgstr "版本遍历设置失败" + +#: sequencer.c:453 +msgid "empty commit set passed" +msgstr "提供了空的提交集" + +#: sequencer.c:461 +#, c-format +msgid "git %s: failed to read the index" +msgstr "git %s: 无法读取暂存区" + +#: sequencer.c:466 +#, c-format +msgid "git %s: failed to refresh the index" +msgstr "git %s: 无法刷新暂存区" + +#: sequencer.c:551 +#, c-format +msgid "Cannot %s during a %s" +msgstr "无法 %s 在 %s 过程中" + +#: sequencer.c:573 +#, c-format +msgid "Could not parse line %d." +msgstr "无法解析第 %d 行。" + +#: sequencer.c:578 +msgid "No commits parsed." +msgstr "未有提交被解析。" + +#: sequencer.c:591 +#, c-format +msgid "Could not open %s" +msgstr "不能打开 %s" + +#: sequencer.c:595 +#, c-format +msgid "Could not read %s." +msgstr "不能读取 %s。" + +#: sequencer.c:602 +#, c-format +msgid "Unusable instruction sheet: %s" +msgstr "无用的指令表单:%s" + +#: sequencer.c:630 +#, c-format +msgid "Invalid key: %s" +msgstr "无效键名:%s" + +#: sequencer.c:633 +#, c-format +msgid "Invalid value for %s: %s" +msgstr "无效的 %s 值:%s" + +#: sequencer.c:645 +#, c-format +msgid "Malformed options sheet: %s" +msgstr "非法的选项表单:%s" + +#: sequencer.c:666 +msgid "a cherry-pick or revert is already in progress" +msgstr "一个拣选或还原操作已在进行" + +#: sequencer.c:667 +msgid "try \"git cherry-pick (--continue | --quit | --abort)\"" +msgstr "尝试 \"git cherry-pick (--continue | --quit | --abort)\"" + +#: sequencer.c:671 +#, c-format +msgid "Could not create sequencer directory %s" +msgstr "无法创建序列目录 %s" + +#: sequencer.c:687 sequencer.c:772 +#, c-format +msgid "Error wrapping up %s." +msgstr "错误收尾 %s。" + +#: sequencer.c:706 sequencer.c:840 +msgid "no cherry-pick or revert in progress" +msgstr "没有拣选或还原操作在进行" + +#: sequencer.c:708 +msgid "cannot resolve HEAD" +msgstr "不能解析 HEAD" + +#: sequencer.c:710 +msgid "cannot abort from a branch yet to be born" +msgstr "不能从未初始分支终止" + +#: sequencer.c:732 +#, c-format +msgid "cannot open %s: %s" +msgstr "不能打开 %s:%s" + +#: sequencer.c:735 +#, c-format +msgid "cannot read %s: %s" +msgstr "不能读取 %s:%s" + +#: sequencer.c:736 +msgid "unexpected end of file" +msgstr "未预期的文件结束" + +#: sequencer.c:742 +#, c-format +msgid "stored pre-cherry-pick HEAD file '%s' is corrupt" +msgstr "保存预拣选提交的 HEAD 文件 '%s' 损坏" + +#: sequencer.c:765 +#, c-format +msgid "Could not format %s." +msgstr "不能格式化 %s。" + +#: sequencer.c:927 +msgid "Can't revert as initial commit" +msgstr "不能作为初始提交还原" + +#: sequencer.c:928 +msgid "Can't cherry-pick into empty head" +msgstr "不能拣选到空分支" + +#: wt-status.c:134 +msgid "Unmerged paths:" +msgstr "未合并的路径:" + +# 注意保持前导空格 +#: wt-status.c:140 wt-status.c:157 +#, c-format +msgid " (use \"git reset %s <file>...\" to unstage)" +msgstr " (使用 \"git reset %s <file>...\" 撤出暂存区)" + +# 注意保持前导空格 +#: wt-status.c:142 wt-status.c:159 +msgid " (use \"git rm --cached <file>...\" to unstage)" +msgstr " (使用 \"git rm --cached <file>...\" 撤出暂存区)" + +# 注意保持前导空格 +#: wt-status.c:143 +msgid " (use \"git add/rm <file>...\" as appropriate to mark resolution)" +msgstr " (酌情使用 \"git add/rm <file>...\" 标记解决方案)" + +#: wt-status.c:151 +msgid "Changes to be committed:" +msgstr "要提交的变更:" + +#: wt-status.c:169 +msgid "Changes not staged for commit:" +msgstr "未暂存至提交的变更:" + +# 注意保持前导空格 +#: wt-status.c:173 +msgid " (use \"git add <file>...\" to update what will be committed)" +msgstr " (使用 \"git add <file>...\" 更新要提交的内容)" + +# 注意保持前导空格 +#: wt-status.c:175 +msgid " (use \"git add/rm <file>...\" to update what will be committed)" +msgstr " (使用 \"git add/rm <file>...\" 更新要提交的内容)" + +# 注意保持前导空格 +#: wt-status.c:176 +msgid "" +" (use \"git checkout -- <file>...\" to discard changes in working directory)" +msgstr " (使用 \"git checkout -- <file>...\" 丢弃工作区的改动)" + +# 注意保持前导空格 +#: wt-status.c:178 +msgid " (commit or discard the untracked or modified content in submodules)" +msgstr " (提交或丢弃子模组中未跟踪或修改的内容)" + +#: wt-status.c:187 +#, c-format +msgid "%s files:" +msgstr "%s文件:" + +# 注意保持前导空格 +#: wt-status.c:190 +#, c-format +msgid " (use \"git %s <file>...\" to include in what will be committed)" +msgstr " (使用 \"git %s <file>...\" 包含到提交列表)" + +#: wt-status.c:207 +msgid "bug" +msgstr "bug" + +#: wt-status.c:212 +msgid "both deleted:" +msgstr "双方删除:" + +#: wt-status.c:213 +msgid "added by us:" +msgstr "由我们添加:" + +#: wt-status.c:214 +msgid "deleted by them:" +msgstr "由他们删除:" + +#: wt-status.c:215 +msgid "added by them:" +msgstr "由他们添加:" + +#: wt-status.c:216 +msgid "deleted by us:" +msgstr "由我们删除:" + +#: wt-status.c:217 +msgid "both added:" +msgstr "双方添加:" + +#: wt-status.c:218 +msgid "both modified:" +msgstr "双方修改:" + +#: wt-status.c:248 +msgid "new commits, " +msgstr "新提交, " + +#: wt-status.c:250 +msgid "modified content, " +msgstr "修改的内容, " + +#: wt-status.c:252 +msgid "untracked content, " +msgstr "未跟踪的内容, " + +# 为保证在输出中对齐,注意调整句中空格! +#: wt-status.c:266 +#, c-format +msgid "new file: %s" +msgstr "新文件: %s" + +# 为保证在输出中对齐,注意调整句中空格! +#: wt-status.c:269 +#, c-format +msgid "copied: %s -> %s" +msgstr "拷贝: %s -> %s" + +# 为保证在输出中对齐,注意调整句中空格! +#: wt-status.c:272 +#, c-format +msgid "deleted: %s" +msgstr "删除: %s" + +# 为保证在输出中对齐,注意调整句中空格! +#: wt-status.c:275 +#, c-format +msgid "modified: %s" +msgstr "修改: %s" + +# 为保证在输出中对齐,注意调整句中空格! +#: wt-status.c:278 +#, c-format +msgid "renamed: %s -> %s" +msgstr "重命名: %s -> %s" + +# 为保证在输出中对齐,注意调整句中空格! +#: wt-status.c:281 +#, c-format +msgid "typechange: %s" +msgstr "类型变更: %s" + +# 为保证在输出中对齐,注意调整句中空格! +#: wt-status.c:284 +#, c-format +msgid "unknown: %s" +msgstr "未知: %s" + +# 为保证在输出中对齐,注意调整句中空格! +#: wt-status.c:287 +#, c-format +msgid "unmerged: %s" +msgstr "未合并: %s" + +#: wt-status.c:290 +#, c-format +msgid "bug: unhandled diff status %c" +msgstr "bug: 未处理的差异状态 %c" + +#: wt-status.c:713 +msgid "On branch " +msgstr "位于分支 " + +#: wt-status.c:720 +msgid "Not currently on any branch." +msgstr "当前不在任何分支上。" + +#: wt-status.c:731 +msgid "Initial commit" +msgstr "初始提交" + +#: wt-status.c:745 +msgid "Untracked" +msgstr "未跟踪的" + +#: wt-status.c:747 +msgid "Ignored" +msgstr "忽略的" + +#: wt-status.c:749 +#, c-format +msgid "Untracked files not listed%s" +msgstr "未跟踪的文件没有列出%s" + +# 注意保持前导空格 +#: wt-status.c:751 +msgid " (use -u option to show untracked files)" +msgstr " (使用 -u 参数显示未跟踪的文件)" + +#: wt-status.c:757 +msgid "No changes" +msgstr "没有修改" + +#: wt-status.c:761 +#, c-format +msgid "no changes added to commit%s\n" +msgstr "修改尚未加入提交%s\n" + +# 注意保持前导空格 +#: wt-status.c:763 +msgid " (use \"git add\" and/or \"git commit -a\")" +msgstr " (使用 \"git add\" 和/或 \"git commit -a\")" + +#: wt-status.c:765 +#, c-format +msgid "nothing added to commit but untracked files present%s\n" +msgstr "空提交但存在未跟踪文件%s\n" + +# 注意保持前导空格 +#: wt-status.c:767 +msgid " (use \"git add\" to track)" +msgstr " (使用 \"git add\" 建立跟踪)" + +#: wt-status.c:769 wt-status.c:772 wt-status.c:775 +#, c-format +msgid "nothing to commit%s\n" +msgstr "无须提交%s\n" + +# 注意保持前导空格 +#: wt-status.c:770 +msgid " (create/copy files and use \"git add\" to track)" +msgstr " (新建/拷贝的文件使用 \"git add\" 建立跟踪)" + +# 注意保持前导空格 +#: wt-status.c:773 +msgid " (use -u to show untracked files)" +msgstr " (使用 -u 显示未跟踪文件)" + +# 注意保持前导空格 +#: wt-status.c:776 +msgid " (working directory clean)" +msgstr " (干净的工作区)" + +#: wt-status.c:884 +msgid "HEAD (no branch)" +msgstr "HEAD(非分支)" + +# 注意保持句尾空格 +#: wt-status.c:890 +msgid "Initial commit on " +msgstr "初始提交于 " + +# 注意保持句尾空格 +#: wt-status.c:905 +msgid "behind " +msgstr "落后 " + +# 注意保持句尾空格 +#: wt-status.c:908 wt-status.c:911 +msgid "ahead " +msgstr "领先 " + +# 注意保持句尾空格 +#: wt-status.c:913 +msgid ", behind " +msgstr ",落后 " + +#: builtin/add.c:62 +#, c-format +msgid "unexpected diff status %c" +msgstr "意外的差异状态 %c" + +#: builtin/add.c:67 builtin/commit.c:298 +msgid "updating files failed" +msgstr "更新文件失败" + +#: builtin/add.c:77 +#, c-format +msgid "remove '%s'\n" +msgstr "删除 '%s'\n" + +#: builtin/add.c:176 +#, c-format +msgid "Path '%s' is in submodule '%.*s'" +msgstr "路径 '%s' 属于模组 '%.*s'" + +#: builtin/add.c:192 +msgid "Unstaged changes after refreshing the index:" +msgstr "刷新暂存区后未暂存的变更:" + +#: builtin/add.c:195 builtin/add.c:456 builtin/rm.c:186 +#, c-format +msgid "pathspec '%s' did not match any files" +msgstr "路径 '%s' 未匹配任何文件" + +#: builtin/add.c:209 +#, c-format +msgid "'%s' is beyond a symbolic link" +msgstr "'%s' 位于符号链接中" + +#: builtin/add.c:276 +msgid "Could not read the index" +msgstr "无法读取暂存区" + +#: builtin/add.c:286 +#, c-format +msgid "Could not open '%s' for writing." +msgstr "无法打开 '%s' 以写入。" + +#: builtin/add.c:290 +msgid "Could not write patch" +msgstr "无法写补丁" + +#: builtin/add.c:295 +#, c-format +msgid "Could not stat '%s'" +msgstr "无法查看文件状态 '%s'" + +#: builtin/add.c:297 +msgid "Empty patch. Aborted." +msgstr "空补丁。异常终止。" + +#: builtin/add.c:303 +#, c-format +msgid "Could not apply '%s'" +msgstr "无法应用 '%s'" + +#: builtin/add.c:312 +msgid "The following paths are ignored by one of your .gitignore files:\n" +msgstr "下列路径被您的一个 .gitignore 文件所忽略:\n" + +#: builtin/add.c:352 +#, c-format +msgid "Use -f if you really want to add them.\n" +msgstr "使用 -f 参数如果你确实要添加它们。\n" + +#: builtin/add.c:353 +msgid "no files added" +msgstr "没有文件被添加" + +#: builtin/add.c:359 +msgid "adding files failed" +msgstr "添加文件失败" + +#: builtin/add.c:391 +msgid "-A and -u are mutually incompatible" +msgstr "-A 和 -u 选项互斥" + +#: builtin/add.c:393 +msgid "Option --ignore-missing can only be used together with --dry-run" +msgstr "选项 --ignore-missing 只能和 --dry-run 共用" + +#: builtin/add.c:413 +#, c-format +msgid "Nothing specified, nothing added.\n" +msgstr "未提供参数,没有文件被添加。\n" + +#: builtin/add.c:414 +#, c-format +msgid "Maybe you wanted to say 'git add .'?\n" +msgstr "也许您想要执行 'git add .'?\n" + +#: builtin/add.c:420 builtin/clean.c:95 builtin/commit.c:358 builtin/mv.c:82 +#: builtin/rm.c:162 +msgid "index file corrupt" +msgstr "暂存区文件损坏" + +#: builtin/add.c:476 builtin/mv.c:229 builtin/rm.c:260 +msgid "Unable to write new index file" +msgstr "无法写入新暂存区文件" + +#: builtin/archive.c:17 +#, c-format +msgid "could not create archive file '%s'" +msgstr "无法创建归档文件 '%s'" + +#: builtin/archive.c:20 +msgid "could not redirect output" +msgstr "无法重定向输出" + +#: builtin/archive.c:37 +msgid "git archive: Remote with no URL" +msgstr "git archive: 未提供远程URL" + +#: builtin/archive.c:58 +msgid "git archive: expected ACK/NAK, got EOF" +msgstr "git archive: 期待ACK/NACK,却得到EOF" + +#: builtin/archive.c:63 +#, c-format +msgid "git archive: NACK %s" +msgstr "git archive: NACK %s" + +#: builtin/archive.c:65 +#, c-format +msgid "remote error: %s" +msgstr "远程错误:%s" + +#: builtin/archive.c:66 +msgid "git archive: protocol error" +msgstr "git archive: 协议错误" + +#: builtin/archive.c:71 +msgid "git archive: expected a flush" +msgstr "git archive: 预期一个刷新" + +# 保持原换行格式,在输出时 %s 的替代内容会让字串变长 +#: builtin/branch.c:137 +#, c-format +msgid "" +"deleting branch '%s' that has been merged to\n" +" '%s', but not yet merged to HEAD." +msgstr "" +"将要删除的分支 '%s' 已经被合并到\n" +" '%s',但未合并到 HEAD。" + +# 保持原换行格式,在输出时 %s 的替代内容会让字串变长 +#: builtin/branch.c:141 +#, c-format +msgid "" +"not deleting branch '%s' that is not yet merged to\n" +" '%s', even though it is merged to HEAD." +msgstr "" +"并未删除分支 '%s', 虽然它已经合并到 HEAD,\n" +" 然而却尚未被合并到分支 '%s' 。" + +# 汉字之间无空格,故删除尾部空格 +#. TRANSLATORS: This is "remote " in "remote branch '%s' not found" +#: builtin/branch.c:163 +msgid "remote " +msgstr "远程" + +#: builtin/branch.c:171 +msgid "cannot use -a with -d" +msgstr "不能将 -a 和 -d 共用" + +#: builtin/branch.c:177 +msgid "Couldn't look up commit object for HEAD" +msgstr "无法查询 HEAD 指向的提交对象" + +#: builtin/branch.c:182 +#, c-format +msgid "Cannot delete the branch '%s' which you are currently on." +msgstr "无法删除您当前所在的分支 '%s'。" + +#: builtin/branch.c:192 +#, c-format +msgid "%sbranch '%s' not found." +msgstr "%s分支 '%s' 未发现。" + +#: builtin/branch.c:200 +#, c-format +msgid "Couldn't look up commit object for '%s'" +msgstr "无法查询 '%s' 指向的提交对象" + +#: builtin/branch.c:206 +#, c-format +msgid "" +"The branch '%s' is not fully merged.\n" +"If you are sure you want to delete it, run 'git branch -D %s'." +msgstr "" +"分支 '%s' 没有完全合并。\n" +"如果您确认要删除它,执行 'git branch -D %s'。" + +#: builtin/branch.c:214 +#, c-format +msgid "Error deleting %sbranch '%s'" +msgstr "删除 %s分支 '%s' 时错误" + +#: builtin/branch.c:219 +#, c-format +msgid "Deleted %sbranch %s (was %s).\n" +msgstr "已删除 %s分支 %s(曾为 %s)。\n" + +#: builtin/branch.c:224 +msgid "Update of config-file failed" +msgstr "无法更新 config 文件" + +#: builtin/branch.c:322 +#, c-format +msgid "branch '%s' does not point at a commit" +msgstr "分支 '%s' 未指向一个提交" + +# 注意保持句尾空格 +#: builtin/branch.c:394 +#, c-format +msgid "behind %d] " +msgstr "落后 %d] " + +# 注意保持句尾空格 +#: builtin/branch.c:396 +#, c-format +msgid "ahead %d] " +msgstr "领先 %d] " + +# 注意保持句尾空格 +#: builtin/branch.c:398 +#, c-format +msgid "ahead %d, behind %d] " +msgstr "领先 %d,落后 %d] " + +#: builtin/branch.c:501 +msgid "(no branch)" +msgstr "(非分支)" + +#: builtin/branch.c:566 +msgid "some refs could not be read" +msgstr "一些引用无法读取" + +#: builtin/branch.c:579 +msgid "cannot rename the current branch while not on any." +msgstr "无法重命名不存在的当前分支。" + +#: builtin/branch.c:589 +#, c-format +msgid "Invalid branch name: '%s'" +msgstr "无效的分支名:'%s'" + +#: builtin/branch.c:604 +msgid "Branch rename failed" +msgstr "分支重命名失败" + +#: builtin/branch.c:608 +#, c-format +msgid "Renamed a misnamed branch '%s' away" +msgstr "重命名掉一个错误命名的旧分支 '%s'" + +#: builtin/branch.c:612 +#, c-format +msgid "Branch renamed to %s, but HEAD is not updated!" +msgstr "分支重命名为 %s,但 HEAD 没有更新!" + +#: builtin/branch.c:619 +msgid "Branch is renamed, but update of config-file failed" +msgstr "分支被重命名,但更新 config 文件失败" + +#: builtin/branch.c:634 +#, c-format +msgid "malformed object name %s" +msgstr "非法的对象名 %s" + +#: builtin/branch.c:658 +#, c-format +msgid "could not write branch description template: %s\n" +msgstr "不能写分支描述模版:%s\n" + +#: builtin/branch.c:746 +msgid "Failed to resolve HEAD as a valid ref." +msgstr "无法将 HEAD 解析为有效引用。" + +#: builtin/branch.c:751 builtin/clone.c:558 +msgid "HEAD not found below refs/heads!" +msgstr "未在 /refs/heads 下发现 HEAD!" + +#: builtin/branch.c:809 +msgid "-a and -r options to 'git branch' do not make sense with a branch name" +msgstr "'git branch' 的 -a 和 -r 选项带一个分支名参数没有意义" + +#: builtin/bundle.c:47 +#, c-format +msgid "%s is okay\n" +msgstr "%s 可以\n" + +#: builtin/bundle.c:56 +msgid "Need a repository to create a bundle." +msgstr "需要一个版本库来创建包" + +#: builtin/bundle.c:60 +msgid "Need a repository to unbundle." +msgstr "需要一个版本库来解包" + +#: builtin/checkout.c:113 builtin/checkout.c:146 +#, c-format +msgid "path '%s' does not have our version" +msgstr "路径 '%s' 没有我们的版本" + +#: builtin/checkout.c:115 builtin/checkout.c:148 +#, c-format +msgid "path '%s' does not have their version" +msgstr "路径 '%s' 没有他们的版本" + +#: builtin/checkout.c:131 +#, c-format +msgid "path '%s' does not have all necessary versions" +msgstr "路径 '%s' 没有全部必须的版本" + +#: builtin/checkout.c:175 +#, c-format +msgid "path '%s' does not have necessary versions" +msgstr "路径 '%s' 没有必须的版本" + +#: builtin/checkout.c:192 +#, c-format +msgid "path '%s': cannot merge" +msgstr "path '%s': 无法合并" + +#: builtin/checkout.c:209 +#, c-format +msgid "Unable to add merge result for '%s'" +msgstr "无法为 '%s' 添加合并结果" + +#: builtin/checkout.c:212 builtin/reset.c:158 +#, c-format +msgid "make_cache_entry failed for path '%s'" +msgstr "对路径 '%s' 的 make_cache_entry 操作失败" + +#: builtin/checkout.c:234 builtin/checkout.c:392 +msgid "corrupt index file" +msgstr "冲突的暂存区文件" + +#: builtin/checkout.c:264 builtin/checkout.c:271 +#, c-format +msgid "path '%s' is unmerged" +msgstr "路径 '%s' 未合并" + +#: builtin/checkout.c:302 builtin/checkout.c:498 builtin/clone.c:583 +#: builtin/merge.c:811 +msgid "unable to write new index file" +msgstr "无法写新的暂存区文件" + +#: builtin/checkout.c:319 builtin/diff.c:302 builtin/merge.c:408 +msgid "diff_setup_done failed" +msgstr "diff_setup_done 失败" + +#: builtin/checkout.c:414 +msgid "you need to resolve your current index first" +msgstr "您需要先解决当前暂存区的冲突" + +#: builtin/checkout.c:533 +#, c-format +msgid "Can not do reflog for '%s'\n" +msgstr "不能对 '%s' 保存引用日志\n" + +#: builtin/checkout.c:565 +msgid "HEAD is now at" +msgstr "HEAD 目前位于" + +#: builtin/checkout.c:572 +#, c-format +msgid "Reset branch '%s'\n" +msgstr "重置分支 '%s'\n" + +#: builtin/checkout.c:575 +#, c-format +msgid "Already on '%s'\n" +msgstr "已经位于 '%s'\n" + +#: builtin/checkout.c:579 +#, c-format +msgid "Switched to and reset branch '%s'\n" +msgstr "切换并重置分支 '%s'\n" + +#: builtin/checkout.c:581 +#, c-format +msgid "Switched to a new branch '%s'\n" +msgstr "切换到一个新分支 '%s'\n" + +#: builtin/checkout.c:583 +#, c-format +msgid "Switched to branch '%s'\n" +msgstr "切换到分支 '%s'\n" + +# 注意保持前导空格 +#: builtin/checkout.c:639 +#, c-format +msgid " ... and %d more.\n" +msgstr " ... 及 %d 更多。\n" + +#. The singular version +#: builtin/checkout.c:645 +#, c-format +msgid "" +"Warning: you are leaving %d commit behind, not connected to\n" +"any of your branches:\n" +"\n" +"%s\n" +msgid_plural "" +"Warning: you are leaving %d commits behind, not connected to\n" +"any of your branches:\n" +"\n" +"%s\n" +msgstr[0] "" +"警告:您正丢下 %d 个提交,未和任何分支关联:\n" +"\n" +"%s\n" + +#: builtin/checkout.c:663 +#, c-format +msgid "" +"If you want to keep them by creating a new branch, this may be a good time\n" +"to do so with:\n" +"\n" +" git branch new_branch_name %s\n" +"\n" +msgstr "" +"如果您想要通过创建新分支保存他们,这可能是一个好时候。\n" +"如下操作:\n" +"\n" +" git branch new_branch_name %s\n" +"\n" + +#: builtin/checkout.c:692 +msgid "internal error in revision walk" +msgstr "在版本遍历时遇到内部错误" + +#: builtin/checkout.c:696 +msgid "Previous HEAD position was" +msgstr "之前的 HEAD 位置是" + +#: builtin/checkout.c:722 +msgid "You are on a branch yet to be born" +msgstr "您位于一个未初始化的分支" + +#. case (1) +#: builtin/checkout.c:853 +#, c-format +msgid "invalid reference: %s" +msgstr "无效引用:%s" + +#. case (1): want a tree +#: builtin/checkout.c:892 +#, c-format +msgid "reference is not a tree: %s" +msgstr "引用不是一个树:%s" + +#: builtin/checkout.c:972 +msgid "-B cannot be used with -b" +msgstr "-B 不能和 -b 共用" + +#: builtin/checkout.c:981 +msgid "--patch is incompatible with all other options" +msgstr "--patch 选项和其他选项不兼容" + +#: builtin/checkout.c:984 +msgid "--detach cannot be used with -b/-B/--orphan" +msgstr "--detach 不能和 -b/-B/--orphan 共用" + +#: builtin/checkout.c:986 +msgid "--detach cannot be used with -t" +msgstr "--detach 不能和 -t 共用" + +#: builtin/checkout.c:992 +msgid "--track needs a branch name" +msgstr "--track 需要一个分支名" + +#: builtin/checkout.c:999 +msgid "Missing branch name; try -b" +msgstr "缺少分支名;尝试 -b" + +#: builtin/checkout.c:1005 +msgid "--orphan and -b|-B are mutually exclusive" +msgstr "--orphan 和 -b|-B 互斥" + +#: builtin/checkout.c:1007 +msgid "--orphan cannot be used with -t" +msgstr "--orphan 不能和 -t 共用" + +#: builtin/checkout.c:1017 +msgid "git checkout: -f and -m are incompatible" +msgstr "git checkout: -f 和 -m 不兼容" + +#: builtin/checkout.c:1051 +msgid "invalid path specification" +msgstr "无效的路径" + +#: builtin/checkout.c:1059 +#, 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 "" +"git checkout: 更新路径和切换分支不兼容。\n" +"您是想要检出 '%s' 但未能将其解析为提交么?" + +#: builtin/checkout.c:1061 +msgid "git checkout: updating paths is incompatible with switching branches." +msgstr "git checkout: 更新路径和切换分支不兼容。" + +#: builtin/checkout.c:1066 +msgid "git checkout: --detach does not take a path argument" +msgstr "git checkout: --detach 不跟路径参数" + +#: builtin/checkout.c:1069 +msgid "" +"git checkout: --ours/--theirs, --force and --merge are incompatible when\n" +"checking out of the index." +msgstr "" +"git checkout: --ours/--theirs, --force 和 --merge 不兼容当\n" +"检出暂存区时。" + +#: builtin/checkout.c:1088 +msgid "Cannot switch branch to a non-commit." +msgstr "无法切换分支到一个非提交。" + +#: builtin/checkout.c:1091 +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 不能共用" + +#: builtin/clean.c:82 +msgid "" +"clean.requireForce set to true and neither -n nor -f given; refusing to clean" +msgstr "" +"clean.requireForce 设置为 true,若未提供 -n 或 -f 选项,拒绝执行清理动作" + +#: builtin/clean.c:85 +msgid "" +"clean.requireForce defaults to true and neither -n nor -f given; refusing to " +"clean" +msgstr "" +"clean.requireForce 默认为 true,若未提供 -n 或 -f 选项,拒绝执行清理动作" + +#: builtin/clean.c:155 builtin/clean.c:176 +#, c-format +msgid "Would remove %s\n" +msgstr "将删除 %s\n" + +#: builtin/clean.c:159 builtin/clean.c:179 +#, c-format +msgid "Removing %s\n" +msgstr "正删除 %s\n" + +#: builtin/clean.c:162 builtin/clean.c:182 +#, c-format +msgid "failed to remove %s" +msgstr "无法删除 %s" + +#: builtin/clean.c:166 +#, c-format +msgid "Would not remove %s\n" +msgstr "不会删除 %s\n" + +#: builtin/clean.c:168 +#, c-format +msgid "Not removing %s\n" +msgstr "未删除 %s\n" + +#: builtin/clone.c:243 +#, c-format +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'" +msgstr "创建目录 '%s' 失败" + +#: builtin/clone.c:308 builtin/diff.c:75 +#, c-format +msgid "failed to stat '%s'" +msgstr "枚举 '%s' 状态失败" + +#: builtin/clone.c:310 +#, c-format +msgid "%s exists and is not a directory" +msgstr "%s 存在且不是一个目录" + +#: builtin/clone.c:324 +#, c-format +msgid "failed to stat %s\n" +msgstr "枚举 %s 状态失败\n" + +#: builtin/clone.c:341 +#, c-format +msgid "failed to unlink '%s'" +msgstr "删除 '%s' 失败" + +#: builtin/clone.c:346 +#, c-format +msgid "failed to create link '%s'" +msgstr "创建链接 '%s' 失败" + +#: builtin/clone.c:350 +#, c-format +msgid "failed to copy file to '%s'" +msgstr "拷贝文件至 '%s' 失败" + +#: builtin/clone.c:373 +#, c-format +msgid "done.\n" +msgstr "完成。\n" + +#: builtin/clone.c:440 +#, c-format +msgid "Could not find remote branch %s to clone." +msgstr "无法发现要克隆的远程分支 %s。" + +#: builtin/clone.c:549 +msgid "remote HEAD refers to nonexistent ref, unable to checkout.\n" +msgstr "远程 HEAD 指向一个不存在的引用,无法检出。\n" + +#: builtin/clone.c:639 +msgid "Too many arguments." +msgstr "太多参数。" + +#: builtin/clone.c:643 +msgid "You must specify a repository to clone." +msgstr "你必须指定一个版本库来克隆" + +#: builtin/clone.c:654 +#, c-format +msgid "--bare and --origin %s options are incompatible." +msgstr "--bare 和 --origin %s 选项不兼容。" + +#: builtin/clone.c:668 +#, c-format +msgid "repository '%s' does not exist" +msgstr "版本库 '%s' 不存在" + +#: builtin/clone.c:673 +msgid "--depth is ignored in local clones; use file:// instead." +msgstr "--depth 在本地克隆被忽略,改为 file:// 协议试试。" + +#: builtin/clone.c:683 +#, c-format +msgid "destination path '%s' already exists and is not an empty directory." +msgstr "目标路径 '%s' 已经存在且不是一个空目录。" + +#: builtin/clone.c:693 +#, c-format +msgid "working tree '%s' already exists." +msgstr "工作区 '%s' 已经存在。" + +#: builtin/clone.c:706 builtin/clone.c:720 +#, c-format +msgid "could not create leading directories of '%s'" +msgstr "无法为 '%s' 创建目录" + +#: builtin/clone.c:709 +#, c-format +msgid "could not create work tree dir '%s'." +msgstr "无法为 '%s' 创建工作区目录。" + +#: builtin/clone.c:728 +#, c-format +msgid "Cloning into bare repository '%s'...\n" +msgstr "克隆到裸版本库 '%s'...\n" + +#: builtin/clone.c:730 +#, c-format +msgid "Cloning into '%s'...\n" +msgstr "正克隆到 '%s'...\n" + +#: builtin/clone.c:786 +#, c-format +msgid "Don't know how to clone %s" +msgstr "不知道如何克隆 %s" + +#: builtin/clone.c:835 +#, c-format +msgid "Remote branch %s not found in upstream %s" +msgstr "远程分支 %s 在上游 %s 未发现" + +#: builtin/clone.c:842 +msgid "You appear to have cloned an empty repository." +msgstr "您似乎克隆了一个空版本库。" + +#: builtin/commit.c:42 +msgid "" +"Your name and email address were configured automatically based\n" +"on your username and hostname. Please check that they are accurate.\n" +"You can suppress this message by setting them explicitly:\n" +"\n" +" git config --global user.name \"Your Name\"\n" +" git config --global user.email you@example.com\n" +"\n" +"After doing this, you may fix the identity used for this commit with:\n" +"\n" +" git commit --amend --reset-author\n" +msgstr "" +"您的姓名和邮件地址会基于您的用户名和主机地址自动配置。请检查它们\n" +"正确与否。您可通过下面命令对其显式声明以避免重复出现类似提示:\n" +"\n" +" git config --global user.name \"Your Name\"\n" +" git config --global user.email you@example.com\n" +"\n" +"设置完毕后,您可用下面命令来更改此次提交所使用的用户ID:\n" +"\n" +" git commit --amend --reset-author\n" + +#: builtin/commit.c:54 +msgid "" +"You asked to amend the most recent commit, but doing so would make\n" +"it empty. You can repeat your command with --allow-empty, or you can\n" +"remove the commit entirely with \"git reset HEAD^\".\n" +msgstr "" +"您要修补最近的提交,但这么做会让它成为空提交。您可以重复您的命令并带上\n" +"--allow-empty 选项,或者您可用命令 \"git reset HEAD^\" 整个删除该提交。\n" + +#: builtin/commit.c:59 +msgid "" +"The previous cherry-pick is now empty, possibly due to conflict resolution.\n" +"If you wish to commit it anyway, use:\n" +"\n" +" git commit --allow-empty\n" +"\n" +"Otherwise, please use 'git reset'\n" +msgstr "" +"之前的拣选操作现在是一个空提交,可能是由冲突解决导致的。如果您无论如何\n" +"也要提交,使用命令:\n" +"\n" +" git commit --allow-empty\n" +"\n" +"否则,请使用命令 'git reset'\n" + +#: builtin/commit.c:205 builtin/reset.c:33 +msgid "merge" +msgstr "合并" + +#: builtin/commit.c:208 +msgid "cherry-pick" +msgstr "拣选" + +#: builtin/commit.c:325 +msgid "failed to unpack HEAD tree object" +msgstr "解包 HEAD 树对象失败" + +#: builtin/commit.c:367 +msgid "unable to create temporary index" +msgstr "不能创建临时暂存区" + +#: builtin/commit.c:373 +msgid "interactive add failed" +msgstr "交互式添加失败" + +#: builtin/commit.c:406 builtin/commit.c:427 builtin/commit.c:473 +msgid "unable to write new_index file" +msgstr "无法写入新暂存区文件" + +# %s若翻为中文,前后不需要空格 +#: builtin/commit.c:457 +#, c-format +msgid "cannot do a partial commit during a %s." +msgstr "在%s过程中不能做部分提交。" + +#: builtin/commit.c:466 +msgid "cannot read the index" +msgstr "无法读取暂存区" + +#: builtin/commit.c:486 +msgid "unable to write temporary index file" +msgstr "无法写临时暂存区文件" + +#: builtin/commit.c:550 builtin/commit.c:556 +#, c-format +msgid "invalid commit: %s" +msgstr "无效的提交:%s" + +#: builtin/commit.c:579 +msgid "malformed --author parameter" +msgstr "非法的 --author 参数" + +#: builtin/commit.c:635 +#, c-format +msgid "Malformed ident string: '%s'" +msgstr "非法的识别字串:'%s'" + +#: builtin/commit.c:670 builtin/commit.c:703 builtin/commit.c:1000 +#, c-format +msgid "could not lookup commit %s" +msgstr "不能查询提交 %s" + +#: builtin/commit.c:682 builtin/shortlog.c:296 +#, c-format +msgid "(reading log message from standard input)\n" +msgstr "(正从标准输入中读取说明信息)\n" + +#: builtin/commit.c:684 +msgid "could not read log from standard input" +msgstr "无法从标准输入中读取说明信息" + +#: builtin/commit.c:688 +#, c-format +msgid "could not read log file '%s'" +msgstr "无法读取说明文件 '%s'" + +#: builtin/commit.c:694 +msgid "commit has empty message" +msgstr "提交说明为空" + +#: builtin/commit.c:710 +msgid "could not read MERGE_MSG" +msgstr "无法读取 MERGE_MSG" + +#: builtin/commit.c:714 +msgid "could not read SQUASH_MSG" +msgstr "无法读取 SQUASH_MSG" + +#: builtin/commit.c:718 +#, c-format +msgid "could not read '%s'" +msgstr "无法读取 '%s'" + +#: builtin/commit.c:746 +#, c-format +msgid "could not open '%s'" +msgstr "无法打开 '%s'" + +#: builtin/commit.c:770 +msgid "could not write commit template" +msgstr "无法写提交模版" + +# %s若翻为中文,前后不需要空格 +#: builtin/commit.c:783 +#, c-format +msgid "" +"\n" +"It looks like you may be committing a %s.\n" +"If this is not correct, please remove the file\n" +"\t%s\n" +"and try again.\n" +msgstr "" +"\n" +"看起来您正在提交一个%s。\n" +"如果不是这样,请删除文件\n" +"\t%s\n" +"然后重试。\n" + +#: builtin/commit.c:796 +msgid "Please enter the commit message for your changes." +msgstr "请为您的修改输入提交说明。" + +# 前导空格用于拼接英文字串,中文字串拼接无需空格 +#: builtin/commit.c:799 +msgid "" +" Lines starting\n" +"with '#' will be ignored, and an empty message aborts the commit.\n" +msgstr "" +"以 '#' 开头\n" +"的行将被忽略,并且空的提交说明将会中止提交。\n" + +# 前导空格用于拼接英文字串,中文字串拼接无需空格 +#: builtin/commit.c:804 +msgid "" +" 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 "" +"以 '#' 开头\n" +"的行将被保留,您可以删除它们如果您想这样做的话。空的提交说明将会\n" +"中止提交。\n" + +# 为保证在输出中对齐,注意调整句中空格! +#: builtin/commit.c:816 +#, c-format +msgid "%sAuthor: %s" +msgstr "%s作者: %s" + +# 为保证在输出中对齐,注意调整句中空格! +#: builtin/commit.c:823 +#, c-format +msgid "%sCommitter: %s" +msgstr "%s提交者: %s" + +#: builtin/commit.c:843 +msgid "Cannot read index" +msgstr "无法读取暂存区" + +#: builtin/commit.c:880 +msgid "Error building trees" +msgstr "无法创建树对象" + +#: builtin/commit.c:895 builtin/tag.c:357 +#, c-format +msgid "Please supply the message using either -m or -F option.\n" +msgstr "请使用 -m 或者 -F 选项提供说明。\n" + +#: builtin/commit.c:975 +#, c-format +msgid "No existing author found with '%s'" +msgstr "没有找到匹配 '%s' 的作者" + +#: builtin/commit.c:990 builtin/commit.c:1182 +#, c-format +msgid "Invalid untracked files mode '%s'" +msgstr "无效的非追踪文件参数 '%s'" + +#: builtin/commit.c:1030 +msgid "Using both --reset-author and --author does not make sense" +msgstr "同时使用 --reset-author 和 --author 没有意义" + +#: builtin/commit.c:1041 +msgid "You have nothing to amend." +msgstr "您没有要修补。" + +# %s若翻为中文,前后不需要空格 +#: builtin/commit.c:1043 +#, c-format +msgid "You are in the middle of a %s -- cannot amend." +msgstr "您正处于一个%s过程中 -- 无法修补提交。" + +#: builtin/commit.c:1045 +msgid "Options --squash and --fixup cannot be used together" +msgstr "选项 --squash 和 --fixup 不能共用" + +#: builtin/commit.c:1055 +msgid "Only one of -c/-C/-F/--fixup can be used." +msgstr "只能用一个 -c/-C/-F/--fixup 选项。" + +#: builtin/commit.c:1057 +msgid "Option -m cannot be combined with -c/-C/-F/--fixup." +msgstr "选项 -m 不能和 -c/-C/-F/--fixup 共用。" + +#: builtin/commit.c:1063 +msgid "--reset-author can be used only with -C, -c or --amend." +msgstr "--reset-author 只能和 -C, -c 或 --amend 共用。" + +#: builtin/commit.c:1080 +msgid "Only one of --include/--only/--all/--interactive/--patch can be used." +msgstr "只能用一个 --include/--only/--all/--interactive/--patch 选项。" + +#: builtin/commit.c:1082 +msgid "No paths with --include/--only does not make sense." +msgstr "参数 --include/--only 不跟路径没有意义。" + +#: builtin/commit.c:1084 +msgid "Clever... amending the last one with dirty index." +msgstr "聪明... 在暂存区不干净下修补最后的提交。" + +#: builtin/commit.c:1086 +msgid "Explicit paths specified without -i nor -o; assuming --only paths..." +msgstr "没有用 -i 或 -o 选项而显式地提供路径,认为是 --only paths..." + +#: builtin/commit.c:1096 builtin/tag.c:556 +#, c-format +msgid "Invalid cleanup mode %s" +msgstr "无效的清理模式 %s" + +#: builtin/commit.c:1101 +msgid "Paths with -a does not make sense." +msgstr "路径和 -a 选项共用没有意义。" + +#: builtin/commit.c:1280 +msgid "couldn't look up newly created commit" +msgstr "无法找到新创建的提交" + +#: builtin/commit.c:1282 +msgid "could not parse newly created commit" +msgstr "无法解析新创建的提交" + +#: builtin/commit.c:1323 +msgid "detached HEAD" +msgstr "分离头指针" + +# 注意保持前导空格 +#: builtin/commit.c:1325 +msgid " (root-commit)" +msgstr " (根提交)" + +#: builtin/commit.c:1415 +msgid "could not parse HEAD commit" +msgstr "无法解析 HEAD 提交" + +#: builtin/commit.c:1452 builtin/merge.c:509 +#, c-format +msgid "could not open '%s' for reading" +msgstr "无法打开 '%s' 读取" + +#: builtin/commit.c:1459 +#, c-format +msgid "Corrupt MERGE_HEAD file (%s)" +msgstr "损坏的 MERGE_HEAD 文件 (%s)" + +#: builtin/commit.c:1466 +msgid "could not read MERGE_MODE" +msgstr "无法读取 MERGE_MODE" + +#: builtin/commit.c:1485 +#, c-format +msgid "could not read commit message: %s" +msgstr "无法读取提交说明:%s" + +#: builtin/commit.c:1499 +#, c-format +msgid "Aborting commit due to empty commit message.\n" +msgstr "终止提交因为提交说明为空。\n" + +#: builtin/commit.c:1514 builtin/merge.c:935 builtin/merge.c:968 +msgid "failed to write commit object" +msgstr "写提交对象失败" + +#: builtin/commit.c:1535 +msgid "cannot lock HEAD ref" +msgstr "无法锁定 HEAD 引用" + +#: builtin/commit.c:1539 +msgid "cannot update HEAD ref" +msgstr "无法更新 HEAD 引用" + +#: builtin/commit.c:1550 +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 "" +"版本库已被更新,但无法写入新暂存区文件。检查是否磁盘\n" +"已满或磁盘配额耗尽,然后执行 \"git reset HEAD\" 恢复。" + +#: builtin/describe.c:234 +#, c-format +msgid "annotated tag %s not available" +msgstr "注释 tag %s 无效" + +#: builtin/describe.c:238 +#, c-format +msgid "annotated tag %s has no embedded name" +msgstr "注释 tag %s 没有嵌入名称" + +#: builtin/describe.c:240 +#, c-format +msgid "tag '%s' is really '%s' here" +msgstr "tag '%s' 确是在 '%s'" + +#: builtin/describe.c:267 +#, c-format +msgid "Not a valid object name %s" +msgstr "不是一个有效的对象名 %s" + +#: builtin/describe.c:270 +#, c-format +msgid "%s is not a valid '%s' object" +msgstr "%s 不是一个有效的 '%s' 对象" + +#: builtin/describe.c:287 +#, c-format +msgid "no tag exactly matches '%s'" +msgstr "没有 tag 准确匹配 '%s'" + +#: builtin/describe.c:289 +#, c-format +msgid "searching to describe %s\n" +msgstr "搜索描述 %s\n" + +#: builtin/describe.c:329 +#, c-format +msgid "finished search at %s\n" +msgstr "完成搜索 %s\n" + +#: builtin/describe.c:353 +#, c-format +msgid "" +"No annotated tags can describe '%s'.\n" +"However, there were unannotated tags: try --tags." +msgstr "" +"没有注释 tag 能描述 '%s'。\n" +"然而,有非注释 tag:尝试 --tags。" + +#: builtin/describe.c:357 +#, c-format +msgid "" +"No tags can describe '%s'.\n" +"Try --always, or create some tags." +msgstr "" +"没有注释 tag 能描述 '%s'。\n" +"尝试 --always,或创建一些 tag。" + +#: builtin/describe.c:378 +#, c-format +msgid "traversed %lu commits\n" +msgstr "已遍历 %lu 个提交\n" + +#: builtin/describe.c:381 +#, c-format +msgid "" +"more than %i tags found; listed %i most recent\n" +"gave up search at %s\n" +msgstr "" +"发现多于 %i 个 tag;列出最近的 %i 个\n" +"放弃搜索 %s\n" + +#: builtin/describe.c:436 +msgid "--long is incompatible with --abbrev=0" +msgstr "--long 与 --abbrev=0 不兼容" + +#: builtin/describe.c:462 +msgid "No names found, cannot describe anything." +msgstr "没有发现名称,无法描述任何东西" + +#: builtin/describe.c:482 +msgid "--dirty is incompatible with committishes" +msgstr "--dirty 不能与提交共用" + +#: builtin/diff.c:77 +#, c-format +msgid "'%s': not a regular file or symlink" +msgstr "'%s':不是一个正规文件或符号链接" + +#: builtin/diff.c:220 +#, c-format +msgid "invalid option: %s" +msgstr "无效选项:%s" + +#: builtin/diff.c:297 +msgid "Not a git repository" +msgstr "不是一个 git 版本库" + +#: builtin/diff.c:347 +#, c-format +msgid "invalid object '%s' given." +msgstr "提供了无效对象 '%s'。" + +#: builtin/diff.c:352 +#, c-format +msgid "more than %d trees given: '%s'" +msgstr "提供了超过 %d 个树对象:'%s'" + +#: builtin/diff.c:362 +#, c-format +msgid "more than two blobs given: '%s'" +msgstr "提供了超过两个 blob 对象:'%s'" + +#: builtin/diff.c:370 +#, c-format +msgid "unhandled object '%s' given." +msgstr "提供了无法处理的对象 '%s'。" + +#: builtin/fetch.c:200 +msgid "Couldn't find remote ref HEAD" +msgstr "无法发现远程 HEAD 引用" + +#: builtin/fetch.c:252 +#, c-format +msgid "object %s not found" +msgstr "对象 %s 未发现" + +#: builtin/fetch.c:258 +msgid "[up to date]" +msgstr "[最新]" + +#: builtin/fetch.c:272 +#, c-format +msgid "! %-*s %-*s -> %s (can't fetch in current branch)" +msgstr "! %-*s %-*s -> %s (在当前分支下不能获取)" + +#: builtin/fetch.c:273 builtin/fetch.c:351 +msgid "[rejected]" +msgstr "[已拒绝]" + +#: builtin/fetch.c:284 +msgid "[tag update]" +msgstr "[tag更新]" + +# 注意保持前导空格 +#: builtin/fetch.c:286 builtin/fetch.c:313 builtin/fetch.c:331 +msgid " (unable to update local ref)" +msgstr " (不能更新本地引用)" + +#: builtin/fetch.c:298 +msgid "[new tag]" +msgstr "[新tag]" + +#: builtin/fetch.c:302 +msgid "[new branch]" +msgstr "[新分支]" + +#: builtin/fetch.c:347 +msgid "unable to update local ref" +msgstr "不能更新本地引用" + +#: builtin/fetch.c:347 +msgid "forced update" +msgstr "强制更新" + +#: builtin/fetch.c:353 +msgid "(non-fast-forward)" +msgstr "(非快进式推送)" + +#: builtin/fetch.c:384 builtin/fetch.c:676 +#, c-format +msgid "cannot open %s: %s\n" +msgstr "无法打开 %s:%s\n" + +#: builtin/fetch.c:393 +#, c-format +msgid "%s did not send all necessary objects\n" +msgstr "%s 未发送所有必须的对象\n" + +#: builtin/fetch.c:479 +#, c-format +msgid "From %.*s\n" +msgstr "来自 %.*s\n" + +#: builtin/fetch.c:490 +#, c-format +msgid "" +"some local refs could not be updated; try running\n" +" 'git remote prune %s' to remove any old, conflicting branches" +msgstr "" +"一些本地引用不能被更新;尝试运行\n" +" 'git remote prune %s' 来删除旧的、有冲突的分支" + +# 注意保持前导空格 +#: builtin/fetch.c:540 +#, c-format +msgid " (%s will become dangling)\n" +msgstr " (%s 将成为悬空状态)\n" + +# 注意保持前导空格 +#: builtin/fetch.c:541 +#, c-format +msgid " (%s has become dangling)\n" +msgstr " (%s 已成为悬空状态)\n" + +#: builtin/fetch.c:548 +msgid "[deleted]" +msgstr "[已删除]" + +#: builtin/fetch.c:549 +msgid "(none)" +msgstr "(无)" + +#: builtin/fetch.c:666 +#, c-format +msgid "Refusing to fetch into current branch %s of non-bare repository" +msgstr "拒绝获取到非裸版本库的当前分支 %s" + +#: builtin/fetch.c:700 +#, c-format +msgid "Don't know how to fetch from %s" +msgstr "不知道如何从 %s 获取" + +#: builtin/fetch.c:777 +#, c-format +msgid "Option \"%s\" value \"%s\" is not valid for %s" +msgstr "选项 \"%s\" 的值 \"%s\" 对于 %s 是无效的" + +#: builtin/fetch.c:780 +#, c-format +msgid "Option \"%s\" is ignored for %s\n" +msgstr "选项 \"%s\" 对于 %s 被忽略\n" + +#: builtin/fetch.c:879 +#, c-format +msgid "Fetching %s\n" +msgstr "正在获取 %s\n" + +#: builtin/fetch.c:881 +#, c-format +msgid "Could not fetch %s" +msgstr "不能获取 %s" + +#: builtin/fetch.c:898 +msgid "" +"No remote repository specified. Please, specify either a URL or a\n" +"remote name from which new revisions should be fetched." +msgstr "未提供远程版本库。请提供一个URL或远程版本库名,用于获取新版本。" + +#: builtin/fetch.c:918 +msgid "You need to specify a tag name." +msgstr "你需要提供一个 tag 名称" + +#: builtin/fetch.c:970 +msgid "fetch --all does not take a repository argument" +msgstr "fetch --all 不能带一个版本库参数" + +#: builtin/fetch.c:972 +msgid "fetch --all does not make sense with refspecs" +msgstr "fetch --all 带引用表达式没有任何意义" + +#: builtin/fetch.c:983 +#, c-format +msgid "No such remote or remote group: %s" +msgstr "没有这样的远程或远程组:%s" + +#: builtin/fetch.c:991 +msgid "Fetching a group and specifying refspecs does not make sense" +msgstr "获取组并提供引用表达式没有意义" + +#: builtin/gc.c:63 +#, c-format +msgid "Invalid %s: '%s'" +msgstr "无效的 %s:'%s'" + +#: builtin/gc.c:78 +msgid "Too many options specified" +msgstr "提供了太多的选项" + +#: builtin/gc.c:103 +#, c-format +msgid "insanely long object directory %.*s" +msgstr "不正常的长对象目录 %.*s" + +#: builtin/gc.c:223 +#, c-format +msgid "Auto packing the repository for optimum performance.\n" +msgstr "自动打包版本库以求最佳性能。\n" + +#: builtin/gc.c:226 +#, c-format +msgid "" +"Auto packing the repository for optimum performance. You may also\n" +"run \"git gc\" manually. See \"git help gc\" for more information.\n" +msgstr "" +"自动打包版本库以求最佳性能。你还可以\n" +"手动运行 \"git gc\"。 参见 \"git help gc\" 获取更多信息。\n" + +#: builtin/gc.c:256 +msgid "" +"There are too many unreachable loose objects; run 'git prune' to remove them." +msgstr "有太多无指向的松散对象,运行 'git prune' 删除它们。" + +#: builtin/grep.c:216 +#, c-format +msgid "grep: failed to create thread: %s" +msgstr "grep: 无法创建线程:%s" + +#: builtin/grep.c:402 +#, c-format +msgid "Failed to chdir: %s" +msgstr "无法切换目录:%s" + +#: builtin/grep.c:478 builtin/grep.c:512 +#, c-format +msgid "unable to read tree (%s)" +msgstr "无法读取代码树(%s)" + +#: builtin/grep.c:526 +#, c-format +msgid "unable to grep from object of type %s" +msgstr "无法抓取来自于 %s 类型的对象" + +#: builtin/grep.c:584 +#, c-format +msgid "switch `%c' expects a numerical value" +msgstr "开关 `%c' 期望一个数字值" + +#: builtin/grep.c:601 +#, c-format +msgid "cannot open '%s'" +msgstr "不能打开 '%s'" + +#: builtin/grep.c:888 +msgid "no pattern given." +msgstr "未提供模式匹配。" + +#: builtin/grep.c:902 +#, c-format +msgid "bad object %s" +msgstr "坏对象 %s" + +#: builtin/grep.c:943 +msgid "--open-files-in-pager only works on the worktree" +msgstr "--open-files-in-pager 仅用于工作区" + +#: builtin/grep.c:966 +msgid "--cached or --untracked cannot be used with --no-index." +msgstr "--cached 或 --untracked 不能与 --no-index 共用" + +#: builtin/grep.c:971 +msgid "--no-index or --untracked cannot be used with revs." +msgstr "--no-index 或 --untracked 不能和版本共用。" + +#: builtin/grep.c:974 +msgid "--[no-]exclude-standard cannot be used for tracked contents." +msgstr "--[no-]exclude-standard 不能用于跟踪内容。" + +#: builtin/grep.c:982 +msgid "both --cached and trees are given." +msgstr "同时给出了 --cached 和树对象。" + +#: builtin/init-db.c:35 +#, c-format +msgid "Could not make %s writable by group" +msgstr "不能设置 %s 为组可写" + +#: builtin/init-db.c:62 +#, c-format +msgid "insanely long template name %s" +msgstr "太长的模版名 %s" + +#: builtin/init-db.c:67 +#, c-format +msgid "cannot stat '%s'" +msgstr "不能枚举 '%s' 状态" + +#: builtin/init-db.c:73 +#, c-format +msgid "cannot stat template '%s'" +msgstr "不能枚举模版 '%s' 状态" + +#: builtin/init-db.c:80 +#, c-format +msgid "cannot opendir '%s'" +msgstr "不能打开目录 '%s'" + +#: builtin/init-db.c:97 +#, c-format +msgid "cannot readlink '%s'" +msgstr "不能读取链接 '%s'" + +#: builtin/init-db.c:99 +#, c-format +msgid "insanely long symlink %s" +msgstr "太长的符号链接 %s" + +#: builtin/init-db.c:102 +#, c-format +msgid "cannot symlink '%s' '%s'" +msgstr "不能创建符号链接 '%s' 到 '%s'" + +#: builtin/init-db.c:106 +#, c-format +msgid "cannot copy '%s' to '%s'" +msgstr "不能拷贝 '%s' 至 '%s'" + +#: builtin/init-db.c:110 +#, c-format +msgid "ignoring template %s" +msgstr "忽略模版 %s" + +#: builtin/init-db.c:133 +#, c-format +msgid "insanely long template path %s" +msgstr "太长的模版路径 %s" + +#: builtin/init-db.c:141 +#, c-format +msgid "templates not found %s" +msgstr "模版未找到 %s" + +#: builtin/init-db.c:154 +#, c-format +msgid "not copying templates of a wrong format version %d from '%s'" +msgstr "未复制错误版本 %d 的模版自 '%s'" + +#: builtin/init-db.c:192 +#, c-format +msgid "insane git directory %s" +msgstr "不正常的 git 目录 %s" + +#: builtin/init-db.c:322 builtin/init-db.c:325 +#, c-format +msgid "%s already exists" +msgstr "%s 已经存在" + +#: builtin/init-db.c:354 +#, c-format +msgid "unable to handle file type %d" +msgstr "不能处理 %d 类型的文件" + +#: builtin/init-db.c:357 +#, c-format +msgid "unable to move %s to %s" +msgstr "不能移动 %s 至 %s" + +#: builtin/init-db.c:362 +#, c-format +msgid "Could not create git link %s" +msgstr "不能创建 git link %s" + +#. +#. * TRANSLATORS: The first '%s' is either "Reinitialized +#. * existing" or "Initialized empty", the second " shared" or +#. * "", and the last '%s%s' is the verbatim directory name. +#. +#: builtin/init-db.c:419 +#, c-format +msgid "%s%s Git repository in %s%s\n" +msgstr "%s%s Git 版本库于 %s%s\n" + +#: builtin/init-db.c:420 +msgid "Reinitialized existing" +msgstr "重新初始化现存的" + +#: builtin/init-db.c:420 +msgid "Initialized empty" +msgstr "初始化空的" + +# 汉字字串合并,之间无空格,故删除前导空格 +#: builtin/init-db.c:421 +msgid " shared" +msgstr "共享的" + +#: builtin/init-db.c:440 +msgid "cannot tell cwd" +msgstr "无法获知当前路径" + +#: builtin/init-db.c:521 builtin/init-db.c:528 +#, c-format +msgid "cannot mkdir %s" +msgstr "不能创建目录 %s" + +#: builtin/init-db.c:532 +#, c-format +msgid "cannot chdir to %s" +msgstr "不能切换目录到 %s" + +#: builtin/init-db.c:554 +#, c-format +msgid "" +"%s (or --work-tree=<directory>) not allowed without specifying %s (or --git-" +"dir=<directory>)" +msgstr "" +"不允许 %s(或 --work-tree=<directory>)而没有 %s(或 --git-dir=<directory>)" + +#: builtin/init-db.c:578 +msgid "Cannot access current working directory" +msgstr "不能访问当前工作目录" + +#: builtin/init-db.c:585 +#, c-format +msgid "Cannot access work tree '%s'" +msgstr "不能访问工作区 '%s'" + +#: builtin/log.c:187 +#, c-format +msgid "Final output: %d %s\n" +msgstr "最终输出:%d %s\n" + +#: builtin/log.c:395 builtin/log.c:483 +#, c-format +msgid "Could not read object %s" +msgstr "无法读取对象 %s" + +#: builtin/log.c:507 +#, c-format +msgid "Unknown type: %d" +msgstr "未知类型:%d" + +#: builtin/log.c:596 +msgid "format.headers without value" +msgstr "format.headers 没有值" + +#: builtin/log.c:669 +msgid "name of output directory is too long" +msgstr "输出目录名太长" + +#: builtin/log.c:680 +#, c-format +msgid "Cannot open patch file %s" +msgstr "无法打开补丁文件 %s" + +#: builtin/log.c:694 +msgid "Need exactly one range." +msgstr "只需要一个范围。" + +#: builtin/log.c:702 +msgid "Not a range." +msgstr "不是一个范围。" + +#: builtin/log.c:739 +msgid "Could not extract email from committer identity." +msgstr "无法从提交者身份中提取邮件地址。" + +#: builtin/log.c:785 +msgid "Cover letter needs email format" +msgstr "信封需要邮件地址格式" + +#: builtin/log.c:879 +#, c-format +msgid "insane in-reply-to: %s" +msgstr "不正常的 in-reply-to:%s" + +#: builtin/log.c:952 +msgid "Two output directories?" +msgstr "两个输出目录?" + +#: builtin/log.c:1173 +#, c-format +msgid "bogus committer info %s" +msgstr "虚假的提交者信息 %s" + +#: builtin/log.c:1218 +msgid "-n and -k are mutually exclusive." +msgstr "-n 和 -k 互斥。" + +#: builtin/log.c:1220 +msgid "--subject-prefix and -k are mutually exclusive." +msgstr "--subject-prefix 和 -k 互斥。" + +#: builtin/log.c:1225 builtin/shortlog.c:284 +#, c-format +msgid "unrecognized argument: %s" +msgstr "未识别的参数:%s" + +#: builtin/log.c:1228 +msgid "--name-only does not make sense" +msgstr "--name-only 无意义" + +#: builtin/log.c:1230 +msgid "--name-status does not make sense" +msgstr "--name-status 无意义" + +#: builtin/log.c:1232 +msgid "--check does not make sense" +msgstr "--check 无意义" + +#: builtin/log.c:1255 +msgid "standard output, or directory, which one?" +msgstr "标准输出或目录,哪一个?" + +#: builtin/log.c:1257 +#, c-format +msgid "Could not create directory '%s'" +msgstr "无法创建目录 '%s'" + +#: builtin/log.c:1410 +msgid "Failed to create output files" +msgstr "无法创建输出文件" + +#: builtin/log.c:1514 +#, c-format +msgid "" +"Could not find a tracked remote branch, please specify <upstream> manually.\n" +msgstr "无法找到跟踪的远程分支,请手工提供 <upstream>。\n" + +#: builtin/log.c:1530 builtin/log.c:1532 builtin/log.c:1544 +#, c-format +msgid "Unknown commit %s" +msgstr "未知提交 %s" + +#: builtin/merge.c:91 +msgid "switch `m' requires a value" +msgstr "开关 `m' 需要一个值" + +#: builtin/merge.c:128 +#, c-format +msgid "Could not find merge strategy '%s'.\n" +msgstr "无法找到合并策略 '%s'。\n" + +#: builtin/merge.c:129 +#, c-format +msgid "Available strategies are:" +msgstr "可用的策略有:" + +#: builtin/merge.c:134 +#, c-format +msgid "Available custom strategies are:" +msgstr "可用的自定义策略有:" + +#: builtin/merge.c:241 +msgid "could not run stash." +msgstr "不能进行进度保存。" + +#: builtin/merge.c:246 +msgid "stash failed" +msgstr "进度保存失败" + +#: builtin/merge.c:251 +#, c-format +msgid "not a valid object: %s" +msgstr "不是一个有效对象:%s" + +#: builtin/merge.c:270 builtin/merge.c:287 +msgid "read-tree failed" +msgstr "读取树失败" + +# 注意保持前导空格 +#: builtin/merge.c:317 +msgid " (nothing to squash)" +msgstr " (无可压缩)" + +#: builtin/merge.c:330 +#, c-format +msgid "Squash commit -- not updating HEAD\n" +msgstr "压缩提交 -- 未更新 HEAD\n" + +#: builtin/merge.c:362 +msgid "Writing SQUASH_MSG" +msgstr "写入 SQUASH_MSG" + +#: builtin/merge.c:364 +msgid "Finishing SQUASH_MSG" +msgstr "完成 SQUASH_MSG" + +#: builtin/merge.c:386 +#, c-format +msgid "No merge message -- not updating HEAD\n" +msgstr "无合并信息 -- 未更新 HEAD\n" + +#: builtin/merge.c:437 +#, c-format +msgid "'%s' does not point to a commit" +msgstr "'%s' 没有指向一个提交" + +#: builtin/merge.c:536 +#, c-format +msgid "Bad branch.%s.mergeoptions string: %s" +msgstr "错的 branch.%s.mergeoptions 字串:%s" + +#: builtin/merge.c:629 +msgid "git write-tree failed to write a tree" +msgstr "git write-tree 无法写入一树对象" + +#: builtin/merge.c:679 +msgid "failed to read the cache" +msgstr "无法读取缓存" + +#: builtin/merge.c:696 +msgid "Unable to write index." +msgstr "不能写暂存区。" + +#: builtin/merge.c:709 +msgid "Not handling anything other than two heads merge." +msgstr "不能处理两个头合并之外的任何操作。" + +#: builtin/merge.c:723 +#, c-format +msgid "Unknown option for merge-recursive: -X%s" +msgstr "merge-recursive 的未知选项:-X%s" + +#: builtin/merge.c:737 +#, c-format +msgid "unable to write %s" +msgstr "不能写 %s" + +#: builtin/merge.c:876 +#, c-format +msgid "Could not read from '%s'" +msgstr "不能从 '%s' 读取" + +#: builtin/merge.c:885 +#, c-format +msgid "Not committing merge; use 'git commit' to complete the merge.\n" +msgstr "未提交合并,使用 'git commit' 完成此次合并。\n" + +#: builtin/merge.c:891 +msgid "" +"Please enter a commit message to explain why this merge is necessary,\n" +"especially if it merges an updated upstream into a topic branch.\n" +"\n" +"Lines starting with '#' will be ignored, and an empty message aborts\n" +"the commit.\n" +msgstr "" +"请输入一个提交信息以解释此合并的必要性,尤其是将一个更新后的上游分支\n" +"合并到主题分支。\n" +"\n" +"以 '#' 开头的行将被忽略,而且空提交说明将会终止提交。\n" + +#: builtin/merge.c:915 +msgid "Empty commit message." +msgstr "空提交信息。" + +#: builtin/merge.c:927 +#, c-format +msgid "Wonderful.\n" +msgstr "太棒了。\n" + +#: builtin/merge.c:1000 +#, c-format +msgid "Automatic merge failed; fix conflicts and then commit the result.\n" +msgstr "自动合并失败,修正冲突然后提交修正的结果。\n" + +#: builtin/merge.c:1016 +#, c-format +msgid "'%s' is not a commit" +msgstr "'%s' 不是一个提交" + +#: builtin/merge.c:1057 +msgid "No current branch." +msgstr "当前不在分支上。" + +#: builtin/merge.c:1059 +msgid "No remote for the current branch." +msgstr "当前分支没有远程版本库。" + +#: builtin/merge.c:1061 +msgid "No default upstream defined for the current branch." +msgstr "当前分支未定义默认上游分支。" + +#: builtin/merge.c:1066 +#, c-format +msgid "No remote tracking branch for %s from %s" +msgstr "%s 没有来自 %s 的远程跟踪分支" + +#: builtin/merge.c:1188 +msgid "There is no merge to abort (MERGE_HEAD missing)." +msgstr "没有要终止的合并(MERGE_HEAD 丢失)" + +#: builtin/merge.c:1204 git-pull.sh:31 +msgid "" +"You have not concluded your merge (MERGE_HEAD exists).\n" +"Please, commit your changes before you can merge." +msgstr "" +"您尚未结束您的合并(存在 MERGE_HEAD)。\n" +"请先提交您的修改,您才能合并。" + +#: builtin/merge.c:1207 git-pull.sh:34 +msgid "You have not concluded your merge (MERGE_HEAD exists)." +msgstr "您尚未结束您的合并(存在 MERGE_HEAD)。" + +#: builtin/merge.c:1211 +msgid "" +"You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n" +"Please, commit your changes before you can merge." +msgstr "" +"您尚未结束您的拣选(存在 CHERRY_PICK_HEAD)。\n" +"请先提交您的修改,您才能合并。" + +#: builtin/merge.c:1214 +msgid "You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)." +msgstr "您尚未结束您的拣选(存在 CHERRY_PICK_HEAD)。" + +#: builtin/merge.c:1223 +msgid "You cannot combine --squash with --no-ff." +msgstr "您不能将 --squash 与 --no-ff 共用。" + +#: builtin/merge.c:1228 +msgid "You cannot combine --no-ff with --ff-only." +msgstr "您不能将 --no-ff 与 --ff-only 共用。" + +#: builtin/merge.c:1235 +msgid "No commit specified and merge.defaultToUpstream not set." +msgstr "未指出提交并且 merge.defaultToUpstream 未设置。" + +#: builtin/merge.c:1266 +msgid "Can merge only exactly one commit into empty head" +msgstr "只可将一个提交合并到空分支上" + +#: builtin/merge.c:1269 +msgid "Squash commit into empty head not supported yet" +msgstr "尚不支持到空分支的压缩提交" + +#: builtin/merge.c:1271 +msgid "Non-fast-forward commit does not make sense into an empty head" +msgstr "到空分支的非快进式提交没有意义" + +#: builtin/merge.c:1275 builtin/merge.c:1319 +#, c-format +msgid "%s - not something we can merge" +msgstr "%s - 不能被合并" + +#: builtin/merge.c:1385 +#, c-format +msgid "Updating %s..%s\n" +msgstr "更新 %s..%s\n" + +#: builtin/merge.c:1423 +#, c-format +msgid "Trying really trivial in-index merge...\n" +msgstr "尝试非常小的暂存区内合并...\n" + +#: builtin/merge.c:1430 +#, c-format +msgid "Nope.\n" +msgstr "无。\n" + +#: builtin/merge.c:1462 +msgid "Not possible to fast-forward, aborting." +msgstr "无法快进,终止。" + +#: builtin/merge.c:1485 builtin/merge.c:1562 +#, c-format +msgid "Rewinding the tree to pristine...\n" +msgstr "将树回滚至原始状态...\n" + +#: builtin/merge.c:1489 +#, c-format +msgid "Trying merge strategy %s...\n" +msgstr "尝试合并策略 %s...\n" + +#: builtin/merge.c:1553 +#, c-format +msgid "No merge strategy handled the merge.\n" +msgstr "没有合并策略处理此合并。\n" + +#: builtin/merge.c:1555 +#, c-format +msgid "Merge with strategy %s failed.\n" +msgstr "使用策略 %s 合并失败。\n" + +#: builtin/merge.c:1564 +#, c-format +msgid "Using the %s to prepare resolving by hand.\n" +msgstr "使用 %s 以准备手工解决。\n" + +#: builtin/merge.c:1575 +#, c-format +msgid "Automatic merge went well; stopped before committing as requested\n" +msgstr "自动合并进展顺利,按要求在提交前停止\n" + +#: builtin/mv.c:108 +#, c-format +msgid "Checking rename of '%s' to '%s'\n" +msgstr "检查 '%s' 到 '%s' 的重命名\n" + +#: builtin/mv.c:112 +msgid "bad source" +msgstr "坏的源" + +#: builtin/mv.c:115 +msgid "can not move directory into itself" +msgstr "不能将目录移动到自身" + +#: builtin/mv.c:118 +msgid "cannot move directory over file" +msgstr "不能将目录移动到文件" + +#: builtin/mv.c:128 +#, c-format +msgid "Huh? %.*s is in index?" +msgstr "嗯?%.*s 在暂存区中?" + +#: builtin/mv.c:140 +msgid "source directory is empty" +msgstr "源目录为空" + +#: builtin/mv.c:171 +msgid "not under version control" +msgstr "不在版本控制之下" + +#: builtin/mv.c:173 +msgid "destination exists" +msgstr "目标已存在" + +#: builtin/mv.c:181 +#, c-format +msgid "overwriting '%s'" +msgstr "覆盖 '%s'" + +#: builtin/mv.c:184 +msgid "Cannot overwrite" +msgstr "不能覆盖" + +#: builtin/mv.c:187 +msgid "multiple sources for the same target" +msgstr "同一目标具有多个源" + +#: builtin/mv.c:202 +#, c-format +msgid "%s, source=%s, destination=%s" +msgstr "%s,源=%s,目标=%s" + +#: builtin/mv.c:212 +#, c-format +msgid "Renaming %s to %s\n" +msgstr "重命名 %s 至 %s\n" + +#: builtin/mv.c:215 +#, c-format +msgid "renaming '%s' failed" +msgstr "重命名 '%s' 失败" + +#: builtin/notes.c:139 +#, c-format +msgid "unable to start 'show' for object '%s'" +msgstr "不能为对象 '%s' 开始 'show'" + +#: builtin/notes.c:145 +msgid "can't fdopen 'show' output fd" +msgstr "不能打开 'show' 输出文件句柄" + +#: builtin/notes.c:155 +#, c-format +msgid "failed to close pipe to 'show' for object '%s'" +msgstr "无法为对象 '%s' 的 'show' 关闭管道" + +#: builtin/notes.c:158 +#, c-format +msgid "failed to finish 'show' for object '%s'" +msgstr "无法为对象 '%s' 完成 'show'" + +#: builtin/notes.c:175 builtin/tag.c:343 +#, c-format +msgid "could not create file '%s'" +msgstr "不能创建文件 '%s'" + +#: builtin/notes.c:189 +msgid "Please supply the note contents using either -m or -F option" +msgstr "请通过 -m 或 -F 选项为注解提供内容" + +#: builtin/notes.c:210 builtin/notes.c:973 +#, c-format +msgid "Removing note for object %s\n" +msgstr "删除对象 %s 的注解\n" + +#: builtin/notes.c:215 +msgid "unable to write note object" +msgstr "不能写注解对象" + +#: builtin/notes.c:217 +#, c-format +msgid "The note contents has been left in %s" +msgstr "注解内容被留在文件 %s 中" + +#: builtin/notes.c:251 builtin/tag.c:521 +#, c-format +msgid "cannot read '%s'" +msgstr "不能读取 '%s'" + +#: builtin/notes.c:253 builtin/tag.c:524 +#, c-format +msgid "could not open or read '%s'" +msgstr "不能打开或读取 '%s'" + +#: builtin/notes.c:272 builtin/notes.c:445 builtin/notes.c:447 +#: builtin/notes.c:507 builtin/notes.c:561 builtin/notes.c:644 +#: builtin/notes.c:649 builtin/notes.c:724 builtin/notes.c:766 +#: builtin/notes.c:968 builtin/reset.c:293 builtin/tag.c:537 +#, c-format +msgid "Failed to resolve '%s' as a valid ref." +msgstr "无法解析 '%s' 为一个有效引用" + +#: builtin/notes.c:275 +#, c-format +msgid "Failed to read object '%s'." +msgstr "无法读取对象 '%s'。" + +#: builtin/notes.c:299 +msgid "Cannot commit uninitialized/unreferenced notes tree" +msgstr "不能提交未初始化/未引用的注解树" + +#: builtin/notes.c:340 +#, c-format +msgid "Bad notes.rewriteMode value: '%s'" +msgstr "错误的 notes.rewriteMode 值:'%s'" + +#: builtin/notes.c:350 +#, c-format +msgid "Refusing to rewrite notes in %s (outside of refs/notes/)" +msgstr "拒绝向 %s(在 refs/notes/ 之外)写入注解" + +#. TRANSLATORS: The first %s is the name of the +#. environment variable, the second %s is its value +#: builtin/notes.c:377 +#, c-format +msgid "Bad %s value: '%s'" +msgstr "错误的 %s 值:'%s'" + +#: builtin/notes.c:441 +#, c-format +msgid "Malformed input line: '%s'." +msgstr "非法的输入行:'%s'。" + +#: builtin/notes.c:456 +#, c-format +msgid "Failed to copy notes from '%s' to '%s'" +msgstr "无法从 '%s' 拷贝注解到 '%s'" + +#: builtin/notes.c:500 builtin/notes.c:554 builtin/notes.c:627 +#: builtin/notes.c:639 builtin/notes.c:712 builtin/notes.c:759 +#: builtin/notes.c:1033 +msgid "too many parameters" +msgstr "参数太多" + +#: builtin/notes.c:513 builtin/notes.c:772 +#, c-format +msgid "No note found for object %s." +msgstr "未发现对象 %s 的注解。" + +#: builtin/notes.c:580 +#, c-format +msgid "" +"Cannot add notes. Found existing notes for object %s. Use '-f' to overwrite " +"existing notes" +msgstr "不能添加注解。发现对象 %s 已存在注解。使用 '-f' 覆盖现存注解" + +#: builtin/notes.c:585 builtin/notes.c:662 +#, c-format +msgid "Overwriting existing notes for object %s\n" +msgstr "覆盖对象 %s 现存注解\n" + +#: builtin/notes.c:635 +msgid "too few parameters" +msgstr "参数太少" + +#: builtin/notes.c:656 +#, c-format +msgid "" +"Cannot copy notes. Found existing notes for object %s. Use '-f' to overwrite " +"existing notes" +msgstr "不能拷贝注解。发现对象 %s 已存在注解。使用 '-f' 覆盖现存注解" + +#: builtin/notes.c:668 +#, c-format +msgid "Missing notes on source object %s. Cannot copy." +msgstr "源对象 %s 缺少注解。不能拷贝。" + +#: builtin/notes.c:717 +#, c-format +msgid "" +"The -m/-F/-c/-C options have been deprecated for the 'edit' subcommand.\n" +"Please use 'git notes add -f -m/-F/-c/-C' instead.\n" +msgstr "" +"选项 -m/-F/-c/-C 已为 'edit' 子命令废弃。\n" +"请换用 'git notes add -f -m/-F/-c/-C'。\n" + +#: builtin/notes.c:971 +#, c-format +msgid "Object %s has no note\n" +msgstr "对象 %s 没有注解\n" + +#: builtin/notes.c:1103 +#, c-format +msgid "Unknown subcommand: %s" +msgstr "未知子命令:%s" + +#: builtin/pack-objects.c:2310 +#, c-format +msgid "unsupported index version %s" +msgstr "不支持的暂存区版本 %s" + +#: builtin/pack-objects.c:2314 +#, c-format +msgid "bad index version '%s'" +msgstr "错误的暂存区版本 '%s'" + +#: builtin/pack-objects.c:2322 +#, c-format +msgid "option %s does not accept negative form" +msgstr "选项 '%s' 不接受否定格式" + +#: builtin/pack-objects.c:2326 +#, c-format +msgid "unable to parse value '%s' for option %s" +msgstr "不能解析值 '%s' 针对于选项 %s" + +#: builtin/push.c:44 +msgid "tag shorthand without <tag>" +msgstr "tag 简写没有跟 <tag> 参数" + +#: builtin/push.c:63 +msgid "--delete only accepts plain target ref names" +msgstr "--delete 只接受简单的引用名称" + +#: builtin/push.c:73 +#, c-format +msgid "" +"You are not currently on a branch.\n" +"To push the history leading to the current (detached HEAD)\n" +"state now, use\n" +"\n" +" git push %s HEAD:<name-of-remote-branch>\n" +msgstr "" +"您当前不在一个分支上。\n" +"现在为推送当前历史(分离头指针),使用\n" +"\n" +" git push %s HEAD:<name-of-remote-branch>\n" + +#: builtin/push.c:80 +#, c-format +msgid "" +"The current branch %s has no upstream branch.\n" +"To push the current branch and set the remote as upstream, use\n" +"\n" +" git push --set-upstream %s %s\n" +msgstr "" +"当前分支 %s 没有对应的上游分支。\n" +"为推送当前分支并建立与远程上游的跟踪,使用\n" +"\n" +" git push --set-upstream %s %s\n" + +#: builtin/push.c:88 +#, c-format +msgid "The current branch %s has multiple upstream branches, refusing to push." +msgstr "当前分支 %s 有多个上游分支,拒绝推送。" + +#: builtin/push.c:111 +msgid "" +"You didn't specify any refspecs to push, and push.default is \"nothing\"." +msgstr "您没有为推送提供任何引用表达式,并且 push.default 为 \"nothing\"。" + +#: builtin/push.c:131 +#, c-format +msgid "Pushing to %s\n" +msgstr "推送到 %s\n" + +#: builtin/push.c:135 +#, c-format +msgid "failed to push some refs to '%s'" +msgstr "无法推送一些引用到 '%s'" + +#: builtin/push.c:143 +#, c-format +msgid "" +"To prevent you from losing history, non-fast-forward updates were rejected\n" +"Merge the remote changes (e.g. 'git pull') before pushing again. See the\n" +"'Note about fast-forwards' section of 'git push --help' for details.\n" +msgstr "" +"为防止您丢失提交历史,禁止非快进式推送。\n" +"再次推送前先与远程变更合并(如 'git pull')。详见\n" +"'git push --help' 中的 'Note about fast-forwards' 小节。\n" + +#: builtin/push.c:160 +#, c-format +msgid "bad repository '%s'" +msgstr "错误的版本库 '%s'" + +#: builtin/push.c:161 +msgid "" +"No configured push destination.\n" +"Either specify the URL from the command-line or configure a remote " +"repository using\n" +"\n" +" git remote add <name> <url>\n" +"\n" +"and then push using the remote name\n" +"\n" +" git push <name>\n" +msgstr "" +"未配置推送目标。\n" +"或者通过命令行提供URL,或者用下面命令配置一个远程版本库\n" +"\n" +" git remote add <name> <url>\n" +"\n" +"然后使用该远程版本库名执行推送\n" +"\n" +" git push <name>\n" + +#: builtin/push.c:176 +msgid "--all and --tags are incompatible" +msgstr "--all 和 --tags 不兼容" + +#: builtin/push.c:177 +msgid "--all can't be combined with refspecs" +msgstr "--all 不能和引用表达式共用" + +#: builtin/push.c:182 +msgid "--mirror and --tags are incompatible" +msgstr "--mirror 和 --tags 不兼容" + +#: builtin/push.c:183 +msgid "--mirror can't be combined with refspecs" +msgstr "--mirror 不能和引用表达式共用" + +#: builtin/push.c:188 +msgid "--all and --mirror are incompatible" +msgstr "--all 和 --mirror 不兼容" + +#: builtin/push.c:274 +msgid "--delete is incompatible with --all, --mirror and --tags" +msgstr "--delete 与 --all、--mirror 及 --tags 不兼容" + +#: builtin/push.c:276 +msgid "--delete doesn't make sense without any refs" +msgstr "--delete 未接任何引用没有意义" + +#: builtin/reset.c:33 +msgid "mixed" +msgstr "混杂" + +#: builtin/reset.c:33 +msgid "soft" +msgstr "软性" + +#: builtin/reset.c:33 +msgid "hard" +msgstr "硬性" + +#: builtin/reset.c:33 +msgid "keep" +msgstr "保持" + +#: builtin/reset.c:77 +msgid "You do not have a valid HEAD." +msgstr "您没有一个有效的 HEAD。" + +#: builtin/reset.c:79 +msgid "Failed to find tree of HEAD." +msgstr "无法找到 HEAD 指向的树。" + +#: builtin/reset.c:85 +#, c-format +msgid "Failed to find tree of %s." +msgstr "无法找到 %s 指向的树。" + +#: builtin/reset.c:96 +msgid "Could not write new index file." +msgstr "无法写入新的暂存区文件。" + +#: builtin/reset.c:106 +#, c-format +msgid "HEAD is now at %s" +msgstr "HEAD 现在位于 %s" + +#: builtin/reset.c:130 +msgid "Could not read index" +msgstr "不能读取暂存区" + +#: builtin/reset.c:133 +msgid "Unstaged changes after reset:" +msgstr "重置后变更撤出暂存区:" + +# 汉字之间无空格,故删除%s前后空格 +#: builtin/reset.c:223 +#, c-format +msgid "Cannot do a %s reset in the middle of a merge." +msgstr "在合并过程中不能做%s重置操作。" + +#: builtin/reset.c:297 +#, c-format +msgid "Could not parse object '%s'." +msgstr "不能解析对象 '%s'。" + +#: builtin/reset.c:302 +msgid "--patch is incompatible with --{hard,mixed,soft}" +msgstr "--patch 与 --{hard,mixed,soft} 不兼容" + +#: builtin/reset.c:311 +msgid "--mixed with paths is deprecated; use 'git reset -- <paths>' instead." +msgstr "--mixed 带路径已弃用,代之以 'git reset -- <paths>'。" + +# 汉字之间无空格,故删除%s前后空格 +#: builtin/reset.c:313 +#, c-format +msgid "Cannot do %s reset with paths." +msgstr "不能带路径进行%s重置。" + +# 汉字之间无空格,故删除%s前后空格 +#: builtin/reset.c:325 +#, c-format +msgid "%s reset is not allowed in a bare repository" +msgstr "不能对裸版本库进行%s重置" + +#: builtin/reset.c:341 +#, c-format +msgid "Could not reset index file to revision '%s'." +msgstr "不能重置暂存区至版本 '%s'。" + +#: builtin/revert.c:70 builtin/revert.c:91 +#, c-format +msgid "%s: %s cannot be used with %s" +msgstr "%s: %s 不能和 %s 共用" + +#: builtin/revert.c:126 +msgid "program error" +msgstr "程序错误" + +#: builtin/revert.c:209 +msgid "revert failed" +msgstr "还原失败" + +#: builtin/revert.c:224 +msgid "cherry-pick failed" +msgstr "拣选失败" + +#: builtin/rm.c:109 +#, c-format +msgid "" +"'%s' has staged content different from both the file and the HEAD\n" +"(use -f to force removal)" +msgstr "" +"'%s' 暂存的内容和工作区文件及 HEAD 中的都不一样\n" +"(使用 -f 强制删除)" + +#: builtin/rm.c:115 +#, c-format +msgid "" +"'%s' has changes staged in the index\n" +"(use --cached to keep the file, or -f to force removal)" +msgstr "" +"'%s' 有变更已加入暂存区中\n" +"(使用 --cached 保存文件,或用 -f 强制删除)" + +#: builtin/rm.c:119 +#, c-format +msgid "" +"'%s' has local modifications\n" +"(use --cached to keep the file, or -f to force removal)" +msgstr "" +"'%s' 有本地修改\n" +"(使用 --cached 保存文件,或用 -f 强制删除)" + +#: builtin/rm.c:194 +#, c-format +msgid "not removing '%s' recursively without -r" +msgstr "未提供 -r 选项不会递归删除 '%s'" + +#: builtin/rm.c:230 +#, c-format +msgid "git rm: unable to remove %s" +msgstr "git rm:不能删除 %s" + +#: builtin/shortlog.c:157 +#, c-format +msgid "Missing author: %s" +msgstr "缺少作者:%s" + +#: builtin/tag.c:58 +#, c-format +msgid "malformed object at '%s'" +msgstr "非法的对象于 '%s'" + +#: builtin/tag.c:205 +#, c-format +msgid "tag name too long: %.*s..." +msgstr "tag 名字太长:%.*s..." + +#: builtin/tag.c:210 +#, c-format +msgid "tag '%s' not found." +msgstr "tag '%s' 未发现。" + +#: builtin/tag.c:225 +#, c-format +msgid "Deleted tag '%s' (was %s)\n" +msgstr "已删除 tag '%s'(曾为 %s)\n" + +#: builtin/tag.c:237 +#, c-format +msgid "could not verify the tag '%s'" +msgstr "不能校验 tag '%s'" + +#: builtin/tag.c:247 +msgid "" +"\n" +"#\n" +"# Write a tag message\n" +"# Lines starting with '#' will be ignored.\n" +"#\n" +msgstr "" +"\n" +"#\n" +"# 输入一个 tag 说明\n" +"# 以 '#' 开头的行将被忽略。\n" +"#\n" + +#: builtin/tag.c:254 +msgid "" +"\n" +"#\n" +"# Write a tag message\n" +"# Lines starting with '#' will be kept; you may remove them yourself if you " +"want to.\n" +"#\n" +msgstr "" +"\n" +"#\n" +"# 输入一个 tag 说明\n" +"# 以 '#' 开头的行将被忽略,您可以删除它们如果您想这样做。\n" +"#\n" + +#: builtin/tag.c:294 +msgid "unable to sign the tag" +msgstr "无法签署 tag" + +#: builtin/tag.c:296 +msgid "unable to write tag file" +msgstr "无法写 tag 文件" + +#: builtin/tag.c:321 +msgid "bad object type." +msgstr "无效的对象类型" + +#: builtin/tag.c:334 +msgid "tag header too big." +msgstr "tag 头信息太大" + +#: builtin/tag.c:366 +msgid "no tag message?" +msgstr "无 tag 说明?" + +#: builtin/tag.c:372 +#, c-format +msgid "The tag message has been left in %s\n" +msgstr "tag 说明被保留在 %s\n" + +#: builtin/tag.c:421 +msgid "switch 'points-at' requires an object" +msgstr "开关 'points-at' 需要一个对象" + +#: builtin/tag.c:423 +#, c-format +msgid "malformed object name '%s'" +msgstr "非法的对象名 '%s'" + +#: builtin/tag.c:502 +msgid "-n option is only allowed with -l." +msgstr "-n 选项只允许和 -l 共用。" + +#: builtin/tag.c:504 +msgid "--contains option is only allowed with -l." +msgstr "--contains 选项只允许和 -l 共用。" + +#: builtin/tag.c:506 +msgid "--points-at option is only allowed with -l." +msgstr "--points-at 选项只允许和 -l 共用。" + +#: builtin/tag.c:514 +msgid "only one -F or -m option is allowed." +msgstr "只允许一个 -F 或 -m 选项。" + +#: builtin/tag.c:534 +msgid "too many params" +msgstr "太多参数" + +#: builtin/tag.c:540 +#, c-format +msgid "'%s' is not a valid tag name." +msgstr "'%s' 不是一个有效的tag名称" + +#: builtin/tag.c:545 +#, c-format +msgid "tag '%s' already exists" +msgstr "tag '%s' 已存在" + +#: builtin/tag.c:563 +#, c-format +msgid "%s: cannot lock the ref" +msgstr "%s:不能锁定引用" + +#: builtin/tag.c:565 +#, c-format +msgid "%s: cannot update the ref" +msgstr "%s:不能更新引用" + +#: builtin/tag.c:567 +#, c-format +msgid "Updated tag '%s' (was %s)\n" +msgstr "已更新tag '%s'(曾为 %s)\n" + +#: git-am.sh:49 +msgid "You need to set your committer info first" +msgstr "您需要先设置你的提交者信息" + +#: git-am.sh:136 +msgid "Repository lacks necessary blobs to fall back on 3-way merge." +msgstr "版本库缺乏必要的 blob 数据以进行三路合并。" + +#: git-am.sh:147 +msgid "" +"Did you hand edit your patch?\n" +"It does not apply to blobs recorded in its index." +msgstr "" +"您是否曾手动编辑过您的补丁?\n" +"无法应用补丁到暂存区的数据中。" + +#: git-am.sh:156 +msgid "Falling back to patching base and 3-way merge..." +msgstr "转而使用补丁应用的基础版本和三路合并..." + +#: git-am.sh:268 +msgid "Only one StGIT patch series can be applied at once" +msgstr "一次只能有一个 StGIT 补丁队列被应用" + +#: git-am.sh:355 +#, sh-format +msgid "Patch format $patch_format is not supported." +msgstr "不支持 $patch_format 补丁格式。" + +#: git-am.sh:357 +msgid "Patch format detection failed." +msgstr "补丁格式检测失败。" + +#: git-am.sh:409 +msgid "-d option is no longer supported. Do not use." +msgstr "不再支持 -d 选项。不要使用。" + +#: git-am.sh:472 +#, sh-format +msgid "previous rebase directory $dotest still exists but mbox given." +msgstr "之前的变基目录 $dotest 仍然存在但给出了mbox。" + +#: git-am.sh:477 +msgid "Please make up your mind. --skip or --abort?" +msgstr "请下决心。--skip 或是 --abort ?" + +#: git-am.sh:504 +msgid "Resolve operation not in progress, we are not resuming." +msgstr "解决操作未进行,我们不会继续。" + +#: git-am.sh:570 +#, sh-format +msgid "Dirty index: cannot apply patches (dirty: $files)" +msgstr "脏的暂存区:不能应用补丁(脏文件:$files)" + +#: git-am.sh:746 +msgid "cannot be interactive without stdin connected to a terminal." +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:757 +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:793 +#, sh-format +msgid "Applying: $FIRSTLINE" +msgstr "正应用:$FIRSTLINE" + +#: git-am.sh:838 +msgid "No changes -- Patch already applied." +msgstr "没有变更 -- 补丁已经应用过。" + +#: git-am.sh:864 +msgid "applying to an empty history" +msgstr "正应用到一个空历史上" + +# 注意保持句尾空格 +#. TRANSLATORS: Make sure to include [Y] and [n] in your +#. translation. The program will only accept English input +#. at this point. +#: git-bisect.sh:54 +msgid "Do you want me to do it for you [Y/n]? " +msgstr "您想让我为您这样做么[Y/n]? " + +#: git-bisect.sh:95 +#, sh-format +msgid "unrecognised option: '$arg'" +msgstr "未识别的选项:'$arg'" + +#: git-bisect.sh:99 +#, sh-format +msgid "'$arg' does not appear to be a valid revision" +msgstr "'$arg' 看起来不像是一个有效的版本" + +#: git-bisect.sh:117 +msgid "Bad HEAD - I need a HEAD" +msgstr "坏的 HEAD - 我需要一个 HEAD" + +#: git-bisect.sh:130 +#, sh-format +msgid "" +"Checking out '$start_head' failed. Try 'git bisect reset <validbranch>'." +msgstr "检出 '$start_head' 失败。尝试 'git bisect reset <validbranch>'。" + +#: git-bisect.sh:140 +msgid "won't bisect on seeked tree" +msgstr "不会在已查找过的树上二分查找" + +#: git-bisect.sh:144 +msgid "Bad HEAD - strange symbolic ref" +msgstr "错误的 HEAD - 奇怪的符号引用" + +#: git-bisect.sh:189 +#, sh-format +msgid "Bad bisect_write argument: $state" +msgstr "错误的bisect_write参数:$state" + +#: git-bisect.sh:218 +#, sh-format +msgid "Bad rev input: $arg" +msgstr "输入错误版本:$arg" + +#: git-bisect.sh:232 +msgid "Please call 'bisect_state' with at least one argument." +msgstr "请在调用 'bisect_state' 时跟至少一个参数。" + +#: git-bisect.sh:244 +#, sh-format +msgid "Bad rev input: $rev" +msgstr "输入坏的版本:$rev" + +#: git-bisect.sh:250 +msgid "'git bisect bad' can take only one argument." +msgstr "'git bisect bad' 只能带一个参数。" + +# 注意保持句尾空格 +#. TRANSLATORS: Make sure to include [Y] and [n] in your +#. translation. The program will only accept English input +#. at this point. +#: git-bisect.sh:279 +msgid "Are you sure [Y/n]? " +msgstr "您确认么[Y/n]? " + +#: git-bisect.sh:354 +#, sh-format +msgid "'$invalid' is not a valid commit" +msgstr "'$invalid' 不是一个有效的提交" + +#: git-bisect.sh:363 +#, sh-format +msgid "" +"Could not check out original HEAD '$branch'.\n" +"Try 'git bisect reset <commit>'." +msgstr "" +"不能检出原始 HEAD '$branch'。\n" +"尝试 'git bisect reset <commit>'。" + +#: git-bisect.sh:390 +msgid "No logfile given" +msgstr "未提供日志文件" + +#: git-bisect.sh:391 +#, sh-format +msgid "cannot read $file for replaying" +msgstr "不能读取 $file 来重放" + +#: git-bisect.sh:408 +msgid "?? what are you talking about?" +msgstr "?? 您在说什么?" + +#: git-bisect.sh:474 +msgid "We are not bisecting." +msgstr "我们没有进行二分查找。" + +#: git-pull.sh:21 +msgid "" +"Pull is not possible because you have unmerged files.\n" +"Please, fix them up in the work tree, and then use 'git add/rm <file>'\n" +"as appropriate to mark resolution, or use 'git commit -a'." +msgstr "" +"Pull 不可用,因为你尚有未合并的文件。请先在工作区改正文件,\n" +"然后酌情使用 'git add/rm <file>' 标记解决方案,\n" +"或使用 'git commit -a'。" + +#: git-pull.sh:25 +msgid "Pull is not possible because you have unmerged files." +msgstr "Pull 不可用,因为你尚有未合并的文件。" + +#: git-pull.sh:197 +msgid "updating an unborn branch with changes added to the index" +msgstr "更新尚未诞生的分支,变更添加至暂存区" + +#: git-pull.sh:253 +msgid "Cannot merge multiple branches into empty head" +msgstr "无法将多个分支合并到空分支" + +#: git-pull.sh:257 +msgid "Cannot rebase onto multiple branches" +msgstr "无法变基到多个分支" + +#: git-stash.sh:51 +msgid "git stash clear with parameters is unimplemented" +msgstr "git stash clear 不支持参数" + +#: git-stash.sh:74 +msgid "You do not have the initial commit yet" +msgstr "您尚未建立初始提交" + +#: git-stash.sh:89 +msgid "Cannot save the current index state" +msgstr "无法保存当前暂存区状态" + +#: git-stash.sh:123 git-stash.sh:136 +msgid "Cannot save the current worktree state" +msgstr "无法保存当前工作区状态" + +#: git-stash.sh:140 +msgid "No changes selected" +msgstr "没有修改被选择" + +#: git-stash.sh:143 +msgid "Cannot remove temporary index (can't happen)" +msgstr "无法删除临时暂存区(不应发生)" + +#: git-stash.sh:156 +msgid "Cannot record working tree state" +msgstr "不能记录工作区状态" + +#: git-stash.sh:223 +msgid "No local changes to save" +msgstr "没有要保存的本地修改" + +#: git-stash.sh:227 +msgid "Cannot initialize stash" +msgstr "无法初始化stash" + +#: git-stash.sh:235 +msgid "Cannot save the current status" +msgstr "无法保存当前状态" + +#: git-stash.sh:253 +msgid "Cannot remove worktree changes" +msgstr "无法删除工作区变更" + +#: git-stash.sh:352 +msgid "No stash found." +msgstr "未发现stash。" + +#: git-stash.sh:359 +#, sh-format +msgid "Too many revisions specified: $REV" +msgstr "提供太多的版本:$REV" + +#: git-stash.sh:365 +#, sh-format +msgid "$reference is not valid reference" +msgstr "$reference 不是有效的引用" + +#: git-stash.sh:393 +#, sh-format +msgid "'$args' is not a stash-like commit" +msgstr "'$args' 不是stash样提交" + +#: git-stash.sh:404 +#, sh-format +msgid "'$args' is not a stash reference" +msgstr "'$args' 不是一个stash引用" + +#: git-stash.sh:412 +msgid "unable to refresh index" +msgstr "无法刷新暂存区" + +#: git-stash.sh:416 +msgid "Cannot apply a stash in the middle of a merge" +msgstr "无法在合并过程中恢复进度" + +#: git-stash.sh:424 +msgid "Conflicts in index. Try without --index." +msgstr "暂存区冲突。尝试不用 --index。" + +#: git-stash.sh:426 +msgid "Could not save index tree" +msgstr "无法保存暂存区" + +#: git-stash.sh:460 +msgid "Cannot unstage modified files" +msgstr "无法还原修改的文件" + +#: git-stash.sh:491 +#, sh-format +msgid "Dropped ${REV} ($s)" +msgstr "丢弃了 ${REV} ($s)" + +#: git-stash.sh:492 +#, sh-format +msgid "${REV}: Could not drop stash entry" +msgstr "${REV}: 无法丢弃进度条目" + +#: git-stash.sh:499 +msgid "No branch name specified" +msgstr "未指定分支名" + +#: git-stash.sh:570 +msgid "(To restore them type \"git stash apply\")" +msgstr "(为恢复数据输入 \"git stash apply\")" + +#: git-submodule.sh:56 +#, sh-format +msgid "cannot strip one component off url '$remoteurl'" +msgstr "无法从 url '$remoteurl' 剥离一个组件" + +#: git-submodule.sh:108 +#, sh-format +msgid "No submodule mapping found in .gitmodules for path '$path'" +msgstr "未在 .gitmodules 中发现路径 '$path' 的子模组映射" + +#: git-submodule.sh:173 +#, sh-format +msgid "Clone of '$url' into submodule path '$path' failed" +msgstr "克隆 '$url' 到子模组路径 '$path' 失败" + +#: git-submodule.sh:247 +#, sh-format +msgid "repo URL: '$repo' must be absolute or begin with ./|../" +msgstr "版本库URL:'$repo' 必须是绝对路径或以 ./|../ 起始" + +#: git-submodule.sh:264 +#, sh-format +msgid "'$path' already exists in the index" +msgstr "'$path' 已经存在于暂存区中" + +#: git-submodule.sh:281 +#, sh-format +msgid "'$path' already exists and is not a valid git repo" +msgstr "'$path' 已存在且不是一个有效的 git 版本库" + +#: git-submodule.sh:295 +#, sh-format +msgid "Unable to checkout submodule '$path'" +msgstr "不能检出子模组 '$path'" + +#: git-submodule.sh:300 +#, sh-format +msgid "Failed to add submodule '$path'" +msgstr "无法添加子模组 '$path'" + +#: git-submodule.sh:305 +#, sh-format +msgid "Failed to register submodule '$path'" +msgstr "无法注册子模组 '$path'" + +#: git-submodule.sh:347 +#, sh-format +msgid "Entering '$prefix$path'" +msgstr "正在进入 '$prefix$path'" + +#: git-submodule.sh:359 +#, sh-format +msgid "Stopping at '$path'; script returned non-zero status." +msgstr "停止于 '$path',脚本返回非零值。" + +#: git-submodule.sh:401 +#, sh-format +msgid "No url found for submodule path '$path' in .gitmodules" +msgstr "在 .gitmodules 中未找到子模组路径 '$path' 的url" + +#: git-submodule.sh:410 +#, sh-format +msgid "Failed to register url for submodule path '$path'" +msgstr "无法为子模组路径 '$path' 注册 url" + +#: git-submodule.sh:418 +#, sh-format +msgid "Failed to register update mode for submodule path '$path'" +msgstr "无法为子模组路径 '$path' 注册更新模式" + +#: git-submodule.sh:420 +#, sh-format +msgid "Submodule '$name' ($url) registered for path '$path'" +msgstr "子模组 '$name' ($url) 已为路径 '$path' 注册" + +#: git-submodule.sh:519 +#, sh-format +msgid "" +"Submodule path '$path' not initialized\n" +"Maybe you want to use 'update --init'?" +msgstr "" +"子模组路径 '$path' 没有初始化\n" +"也许你想用 'update --init'?" + +#: git-submodule.sh:532 +#, sh-format +msgid "Unable to find current revision in submodule path '$path'" +msgstr "无法在子模组路径 '$path' 中找到当前版本" + +#: git-submodule.sh:551 +#, sh-format +msgid "Unable to fetch in submodule path '$path'" +msgstr "无法在子模组路径 '$path' 中获取" + +#: git-submodule.sh:565 +#, sh-format +msgid "Unable to rebase '$sha1' in submodule path '$path'" +msgstr "无法在子模组路径 '$path' 中变基 '$sha1'" + +#: git-submodule.sh:566 +#, sh-format +msgid "Submodule path '$path': rebased into '$sha1'" +msgstr "子模组路径 '$path':变基至 '$sha1'" + +#: git-submodule.sh:571 +#, sh-format +msgid "Unable to merge '$sha1' in submodule path '$path'" +msgstr "无法合并 '$sha1' 到子模组路径 '$path' 中" + +#: git-submodule.sh:572 +#, sh-format +msgid "Submodule path '$path': merged in '$sha1'" +msgstr "子模组路径 '$path':已合并入 '$sha1'" + +#: git-submodule.sh:577 +#, sh-format +msgid "Unable to checkout '$sha1' in submodule path '$path'" +msgstr "无法在子模组路径 '$path' 中检出 '$sha1'" + +#: git-submodule.sh:578 +#, sh-format +msgid "Submodule path '$path': checked out '$sha1'" +msgstr "子模组路径 '$path':检出 '$sha1'" + +#: git-submodule.sh:600 git-submodule.sh:923 +#, sh-format +msgid "Failed to recurse into submodule path '$path'" +msgstr "无法递归进子模组路径 '$path'" + +#: git-submodule.sh:708 +msgid "--" +msgstr "--" + +# 注意保持前导空格 +#: git-submodule.sh:766 +#, sh-format +msgid " Warn: $name doesn't contain commit $sha1_src" +msgstr " 警告:$name 未包含提交 $sha1_src" + +# 注意保持前导空格 +#: git-submodule.sh:769 +#, sh-format +msgid " Warn: $name doesn't contain commit $sha1_dst" +msgstr " 警告:$name 未包含提交 $sha1_dst" + +# 注意保持前导空格 +#: git-submodule.sh:772 +#, sh-format +msgid " Warn: $name doesn't contain commits $sha1_src and $sha1_dst" +msgstr " 警告:$name 未包含提交 $sha1_src 和 $sha1_dst" + +#: git-submodule.sh:797 +msgid "blob" +msgstr "blob" + +#: git-submodule.sh:798 +msgid "submodule" +msgstr "子模组" + +#: git-submodule.sh:969 +#, sh-format +msgid "Synchronizing submodule url for '$name'" +msgstr "为 '$name' 同步子模组url" @@ -9,6 +9,7 @@ static char *do_askpass(const char *cmd, const char *prompt) struct child_process pass; const char *args[3]; static struct strbuf buffer = STRBUF_INIT; + int err = 0; args[0] = cmd; args[1] = prompt; @@ -19,25 +20,30 @@ static char *do_askpass(const char *cmd, const char *prompt) pass.out = -1; if (start_command(&pass)) - exit(1); + return NULL; - strbuf_reset(&buffer); if (strbuf_read(&buffer, pass.out, 20) < 0) - die("failed to get '%s' from %s\n", prompt, cmd); + err = 1; close(pass.out); if (finish_command(&pass)) - exit(1); + err = 1; + + if (err) { + error("unable to read askpass response from '%s'", cmd); + strbuf_release(&buffer); + return NULL; + } strbuf_setlen(&buffer, strcspn(buffer.buf, "\r\n")); - return buffer.buf; + return strbuf_detach(&buffer, NULL); } char *git_prompt(const char *prompt, int flags) { - char *r; + char *r = NULL; if (flags & PROMPT_ASKPASS) { const char *askpass; @@ -48,12 +54,15 @@ char *git_prompt(const char *prompt, int flags) if (!askpass) askpass = getenv("SSH_ASKPASS"); if (askpass && *askpass) - return do_askpass(askpass, prompt); + r = do_askpass(askpass, prompt); } - r = git_terminal_prompt(prompt, flags & PROMPT_ECHO); if (!r) - die_errno("could not read '%s'", prompt); + r = git_terminal_prompt(prompt, flags & PROMPT_ECHO); + if (!r) { + /* prompts already contain ": " at the end */ + die("could not read %s%s", prompt, strerror(errno)); + } return r; } diff --git a/read-cache.c b/read-cache.c index a51bba1b95..274e54b4f3 100644 --- a/read-cache.c +++ b/read-cache.c @@ -1120,11 +1120,16 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p struct cache_entry *ce, *new; int cache_errno = 0; int changed = 0; + int filtered = 0; ce = istate->cache[i]; if (ignore_submodules && S_ISGITLINK(ce->ce_mode)) continue; + if (pathspec && + !match_pathspec(pathspec, ce->name, strlen(ce->name), 0, seen)) + filtered = 1; + if (ce_stage(ce)) { while ((i < istate->cache_nr) && ! strcmp(istate->cache[i]->name, ce->name)) @@ -1132,12 +1137,14 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p i--; if (allow_unmerged) continue; - show_file(unmerged_fmt, ce->name, in_porcelain, &first, header_msg); + if (!filtered) + show_file(unmerged_fmt, ce->name, in_porcelain, + &first, header_msg); has_errors = 1; continue; } - if (pathspec && !match_pathspec(pathspec, ce->name, strlen(ce->name), 0, seen)) + if (filtered) continue; new = refresh_cache_ent(istate, ce, options, &cache_errno, &changed); @@ -183,12 +183,6 @@ static struct ref_cache { static struct ref_entry *current_ref; -/* - * Never call sort_ref_array() on the extra_refs, because it is - * allowed to contain entries with duplicate names. - */ -static struct ref_array extra_refs; - static void clear_ref_array(struct ref_array *array) { int i; @@ -289,16 +283,6 @@ static void read_packed_refs(FILE *f, struct ref_array *array) } } -void add_extra_ref(const char *refname, const unsigned char *sha1, int flag) -{ - add_ref(&extra_refs, create_ref_entry(refname, sha1, flag, 0)); -} - -void clear_extra_refs(void) -{ - clear_ref_array(&extra_refs); -} - static struct ref_array *get_packed_refs(struct ref_cache *refs) { if (!refs->did_packed) { @@ -733,16 +717,11 @@ fallback: static int do_for_each_ref(const char *submodule, const char *base, each_ref_fn fn, int trim, int flags, void *cb_data) { - int retval = 0, i, p = 0, l = 0; + int retval = 0, p = 0, l = 0; struct ref_cache *refs = get_ref_cache(submodule); struct ref_array *packed = get_packed_refs(refs); struct ref_array *loose = get_loose_refs(refs); - struct ref_array *extra = &extra_refs; - - for (i = 0; i < extra->nr; i++) - retval = do_one_ref(base, fn, trim, flags, cb_data, extra->refs[i]); - sort_ref_array(packed); sort_ref_array(loose); while (p < packed->nr && l < loose->nr) { @@ -56,14 +56,6 @@ extern void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refn */ extern void add_packed_ref(const char *refname, const unsigned char *sha1); -/* - * Extra refs will be listed by for_each_ref() before any actual refs - * for the duration of this process or until clear_extra_refs() is - * called. Only extra refs added before for_each_ref() is called will - * be listed on a given call of for_each_ref(). - */ -extern void add_extra_ref(const char *refname, const unsigned char *sha1, int flags); -extern void clear_extra_refs(void); extern int ref_exists(const char *); extern int peel_ref(const char *refname, unsigned char *sha1); @@ -8,6 +8,8 @@ #include "tag.h" #include "string-list.h" +enum map_direction { FROM_SRC, FROM_DST }; + static struct refspec s_tag_refspec = { 0, 1, @@ -978,16 +980,20 @@ static void tail_link_ref(struct ref *ref, struct ref ***tail) *tail = &ref->next; } +static struct ref *alloc_delete_ref(void) +{ + struct ref *ref = alloc_ref("(delete)"); + hashclr(ref->new_sha1); + return ref; +} + static struct ref *try_explicit_object_name(const char *name) { unsigned char sha1[20]; struct ref *ref; - if (!*name) { - ref = alloc_ref("(delete)"); - hashclr(ref->new_sha1); - return ref; - } + if (!*name) + return alloc_delete_ref(); if (get_sha1(name, sha1)) return NULL; ref = alloc_ref(name); @@ -1110,10 +1116,11 @@ static int match_explicit_refs(struct ref *src, struct ref *dst, return errs; } -static const struct refspec *check_pattern_match(const struct refspec *rs, - int rs_nr, - const struct ref *src) +static char *get_ref_match(const struct refspec *rs, int rs_nr, const struct ref *ref, + int send_mirror, int direction, const struct refspec **ret_pat) { + const struct refspec *pat; + char *name; int i; int matching_refs = -1; for (i = 0; i < rs_nr; i++) { @@ -1123,14 +1130,36 @@ static const struct refspec *check_pattern_match(const struct refspec *rs, continue; } - if (rs[i].pattern && match_name_with_pattern(rs[i].src, src->name, - NULL, NULL)) - return rs + i; + if (rs[i].pattern) { + const char *dst_side = rs[i].dst ? rs[i].dst : rs[i].src; + int match; + if (direction == FROM_SRC) + match = match_name_with_pattern(rs[i].src, ref->name, dst_side, &name); + else + match = match_name_with_pattern(dst_side, ref->name, rs[i].src, &name); + if (match) { + matching_refs = i; + break; + } + } } - if (matching_refs != -1) - return rs + matching_refs; - else + if (matching_refs == -1) return NULL; + + pat = rs + matching_refs; + if (pat->matching) { + /* + * "matching refs"; traditionally we pushed everything + * including refs outside refs/heads/ hierarchy, but + * that does not make much sense these days. + */ + if (!send_mirror && prefixcmp(ref->name, "refs/heads/")) + return NULL; + name = xstrdup(ref->name); + } + if (ret_pat) + *ret_pat = pat; + return name; } static struct ref **tail_ref(struct ref **head) @@ -1155,9 +1184,10 @@ int match_push_refs(struct ref *src, struct ref **dst, struct refspec *rs; int send_all = flags & MATCH_REFS_ALL; int send_mirror = flags & MATCH_REFS_MIRROR; + int send_prune = flags & MATCH_REFS_PRUNE; int errs; static const char *default_refspec[] = { ":", NULL }; - struct ref **dst_tail = tail_ref(dst); + struct ref *ref, **dst_tail = tail_ref(dst); if (!nr_refspec) { nr_refspec = 1; @@ -1167,39 +1197,23 @@ int match_push_refs(struct ref *src, struct ref **dst, errs = match_explicit_refs(src, *dst, &dst_tail, rs, nr_refspec); /* pick the remainder */ - for ( ; src; src = src->next) { + for (ref = src; ref; ref = ref->next) { struct ref *dst_peer; const struct refspec *pat = NULL; char *dst_name; - if (src->peer_ref) - continue; - pat = check_pattern_match(rs, nr_refspec, src); - if (!pat) + if (ref->peer_ref) continue; - if (pat->matching) { - /* - * "matching refs"; traditionally we pushed everything - * including refs outside refs/heads/ hierarchy, but - * that does not make much sense these days. - */ - if (!send_mirror && prefixcmp(src->name, "refs/heads/")) - continue; - dst_name = xstrdup(src->name); + dst_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_SRC, &pat); + if (!dst_name) + continue; - } else { - const char *dst_side = pat->dst ? pat->dst : pat->src; - if (!match_name_with_pattern(pat->src, src->name, - dst_side, &dst_name)) - die("Didn't think it matches any more"); - } dst_peer = find_ref_by_name(*dst, dst_name); if (dst_peer) { if (dst_peer->peer_ref) /* We're already sending something to this ref. */ goto free_name; - } else { if (pat->matching && !(send_all || send_mirror)) /* @@ -1211,13 +1225,30 @@ int match_push_refs(struct ref *src, struct ref **dst, /* Create a new one and link it */ dst_peer = make_linked_ref(dst_name, &dst_tail); - hashcpy(dst_peer->new_sha1, src->new_sha1); + hashcpy(dst_peer->new_sha1, ref->new_sha1); } - dst_peer->peer_ref = copy_ref(src); + dst_peer->peer_ref = copy_ref(ref); dst_peer->force = pat->force; free_name: free(dst_name); } + if (send_prune) { + /* check for missing refs on the remote */ + for (ref = *dst; ref; ref = ref->next) { + char *src_name; + + if (ref->peer_ref) + /* We're already sending something to this ref. */ + continue; + + src_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_DST, NULL); + if (src_name) { + if (!find_ref_by_name(src, src_name)) + ref->peer_ref = alloc_delete_ref(); + free(src_name); + } + } + } if (errs) return -1; return 0; @@ -145,7 +145,8 @@ int branch_merge_matches(struct branch *, int n, const char *); enum match_refs_flags { MATCH_REFS_NONE = 0, MATCH_REFS_ALL = (1 << 0), - MATCH_REFS_MIRROR = (1 << 1) + MATCH_REFS_MIRROR = (1 << 1), + MATCH_REFS_PRUNE = (1 << 2) }; /* Reporting of tracking info */ diff --git a/revision.c b/revision.c index c97d834484..b3554ed11b 100644 --- a/revision.c +++ b/revision.c @@ -1582,6 +1582,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg revs->grep_filter.regflags |= REG_EXTENDED; } else if (!strcmp(arg, "--regexp-ignore-case") || !strcmp(arg, "-i")) { revs->grep_filter.regflags |= REG_ICASE; + DIFF_OPT_SET(&revs->diffopt, PICKAXE_IGNORE_CASE); } else if (!strcmp(arg, "--fixed-strings") || !strcmp(arg, "-F")) { revs->grep_filter.fixed = 1; } else if (!strcmp(arg, "--all-match")) { @@ -2149,7 +2150,6 @@ static int commit_match(struct commit *commit, struct rev_info *opt) if (!opt->grep_filter.pattern_list && !opt->grep_filter.header_list) return 1; return grep_buffer(&opt->grep_filter, - NULL, /* we say nothing, not even filename */ commit->buffer, strlen(commit->buffer)); } diff --git a/sequencer.c b/sequencer.c index 5fcbcb8875..a37846a594 100644 --- a/sequencer.c +++ b/sequencer.c @@ -123,7 +123,7 @@ static void write_cherry_pick_head(struct commit *commit, const char *pseudoref) strbuf_release(&buf); } -static void print_advice(int show_hint) +static void print_advice(int show_hint, struct replay_opts *opts) { char *msg = getenv("GIT_CHERRY_PICK_HELP"); @@ -138,10 +138,15 @@ static void print_advice(int show_hint) return; } - if (show_hint) - advise(_("after resolving the conflicts, mark the corrected paths\n" - "with 'git add <paths>' or 'git rm <paths>'\n" - "and commit the result with 'git commit'")); + if (show_hint) { + if (opts->no_commit) + advise(_("after resolving the conflicts, mark the corrected paths\n" + "with 'git add <paths>' or 'git rm <paths>'")); + else + advise(_("after resolving the conflicts, mark the corrected paths\n" + "with 'git add <paths>' or 'git rm <paths>'\n" + "and commit the result with 'git commit'")); + } } static void write_message(struct strbuf *msgbuf, const char *filename) @@ -423,7 +428,7 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts) : _("could not apply %s... %s"), find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV), msg.subject); - print_advice(res == 1); + print_advice(res == 1, opts); rerere(opts->allow_rerere_auto); } else { if (!opts->no_commit) @@ -247,7 +247,7 @@ const char **get_pathspec(const char *prefix, const char **pathspec) * a proper "ref:", or a regular file HEAD that has a properly * formatted sha1 object name. */ -static int is_git_directory(const char *suspect) +int is_git_directory(const char *suspect) { char path[PATH_MAX]; size_t len = strlen(suspect); diff --git a/sha1_file.c b/sha1_file.c index d9aa0e0a2c..4f06a0e450 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -54,6 +54,8 @@ static struct cached_object empty_tree = { 0 }; +static struct packed_git *last_found_pack; + static struct cached_object *find_cached_object(const unsigned char *sha1) { int i; @@ -720,6 +722,8 @@ void free_pack_by_name(const char *pack_name) close_pack_index(p); free(p->bad_object_sha1); *pp = p->next; + if (last_found_pack == p) + last_found_pack = NULL; free(p); return; } @@ -2015,54 +2019,58 @@ int is_pack_valid(struct packed_git *p) return !open_packed_git(p); } +static int fill_pack_entry(const unsigned char *sha1, + struct pack_entry *e, + struct packed_git *p) +{ + off_t offset; + + if (p->num_bad_objects) { + unsigned i; + for (i = 0; i < p->num_bad_objects; i++) + if (!hashcmp(sha1, p->bad_object_sha1 + 20 * i)) + return 0; + } + + offset = find_pack_entry_one(sha1, p); + if (!offset) + return 0; + + /* + * We are about to tell the caller where they can locate the + * requested object. We better make sure the packfile is + * still here and can be accessed before supplying that + * answer, as it may have been deleted since the index was + * loaded! + */ + if (!is_pack_valid(p)) { + warning("packfile %s cannot be accessed", p->pack_name); + return 0; + } + e->offset = offset; + e->p = p; + hashcpy(e->sha1, sha1); + return 1; +} + static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e) { - static struct packed_git *last_found = (void *)1; struct packed_git *p; - off_t offset; prepare_packed_git(); if (!packed_git) return 0; - p = (last_found == (void *)1) ? packed_git : last_found; - do { - if (p->num_bad_objects) { - unsigned i; - for (i = 0; i < p->num_bad_objects; i++) - if (!hashcmp(sha1, p->bad_object_sha1 + 20 * i)) - goto next; - } + if (last_found_pack && fill_pack_entry(sha1, e, last_found_pack)) + return 1; - offset = find_pack_entry_one(sha1, p); - if (offset) { - /* - * We are about to tell the caller where they can - * locate the requested object. We better make - * sure the packfile is still here and can be - * accessed before supplying that answer, as - * it may have been deleted since the index - * was loaded! - */ - if (!is_pack_valid(p)) { - warning("packfile %s cannot be accessed", p->pack_name); - goto next; - } - e->offset = offset; - e->p = p; - hashcpy(e->sha1, sha1); - last_found = p; - return 1; - } + for (p = packed_git; p; p = p->next) { + if (p == last_found_pack || !fill_pack_entry(sha1, e, p)) + continue; - next: - if (p == last_found) - p = packed_git; - else - p = p->next; - if (p == last_found) - p = p->next; - } while (p); + last_found_pack = p; + return 1; + } return 0; } @@ -2692,10 +2700,13 @@ static int index_core(unsigned char *sha1, int fd, size_t size, * This also bypasses the usual "convert-to-git" dance, and that is on * purpose. We could write a streaming version of the converting * functions and insert that before feeding the data to fast-import - * (or equivalent in-core API described above), but the primary - * motivation for trying to stream from the working tree file and to - * avoid mmaping it in core is to deal with large binary blobs, and - * by definition they do _not_ want to get any conversion. + * (or equivalent in-core API described above). However, that is + * somewhat complicated, as we do not know the size of the filter + * result, which we need to know beforehand when writing a git object. + * Since the primary motivation for trying to stream from the working + * tree file and to avoid mmaping it in core is to deal with large + * binary blobs, they generally do not want to get any conversion, and + * callers should avoid this code path when filters are requested. */ static int index_stream(unsigned char *sha1, int fd, size_t size, enum object_type type, const char *path, @@ -2712,7 +2723,8 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, if (!S_ISREG(st->st_mode)) ret = index_pipe(sha1, fd, type, path, flags); - else if (size <= big_file_threshold || type != OBJ_BLOB) + else if (size <= big_file_threshold || type != OBJ_BLOB || + (path && would_convert_to_git(path, NULL, 0, 0))) ret = index_core(sha1, fd, size, type, path, flags); else ret = index_stream(sha1, fd, size, type, path, flags); @@ -383,6 +383,22 @@ int strbuf_getline(struct strbuf *sb, FILE *fp, int term) return 0; } +int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term) +{ + strbuf_reset(sb); + + while (1) { + char ch; + ssize_t len = xread(fd, &ch, 1); + if (len <= 0) + return EOF; + strbuf_addch(sb, ch); + if (ch == term) + break; + } + return 0; +} + int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint) { int fd, len; @@ -116,6 +116,7 @@ extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint); extern int strbuf_getwholeline(struct strbuf *, FILE *, int); extern int strbuf_getline(struct strbuf *, FILE *, int); +extern int strbuf_getwholeline_fd(struct strbuf *, int, int); extern void stripspace(struct strbuf *buf, int skip_comments); extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env); diff --git a/symlinks.c b/symlinks.c index 034943bda0..290036744b 100644 --- a/symlinks.c +++ b/symlinks.c @@ -219,7 +219,20 @@ int has_symlink_leading_path(const char *name, int len) */ int check_leading_path(const char *name, int len) { - struct cache_def *cache = &default_cache; /* FIXME */ + return threaded_check_leading_path(&default_cache, name, len); +} + +/* + * Return zero if path 'name' has a leading symlink component or + * if some leading path component does not exists. + * + * Return -1 if leading path exists and is a directory. + * + * Return path length if leading path exists and is neither a + * directory nor a symlink. + */ +int threaded_check_leading_path(struct cache_def *cache, const char *name, int len) +{ int flags; int match_len = lstat_cache_matchlen(cache, name, len, &flags, FL_SYMLINK|FL_NOENT|FL_DIR, USE_ONLY_LSTAT); @@ -240,7 +253,18 @@ int check_leading_path(const char *name, int len) */ int has_dirs_only_path(const char *name, int len, int prefix_len) { - struct cache_def *cache = &default_cache; /* FIXME */ + return threaded_has_dirs_only_path(&default_cache, name, len, prefix_len); +} + +/* + * Return non-zero if all path components of 'name' exists as a + * directory. If prefix_len > 0, we will test with the stat() + * function instead of the lstat() function for a prefix length of + * 'prefix_len', thus we then allow for symlinks in the prefix part as + * long as those points to real existing directories. + */ +int threaded_has_dirs_only_path(struct cache_def *cache, const char *name, int len, int prefix_len) +{ return lstat_cache(cache, name, len, FL_DIR|FL_FULLPATH, prefix_len) & FL_DIR; diff --git a/t/Makefile b/t/Makefile index 66ceefefcc..6091211f10 100644 --- a/t/Makefile +++ b/t/Makefile @@ -73,6 +73,9 @@ gitweb-test: valgrind: $(MAKE) GIT_TEST_OPTS="$(GIT_TEST_OPTS) --valgrind" +perf: + $(MAKE) -C perf/ all + # Smoke testing targets -include ../GIT-VERSION-FILE uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo unknown') @@ -111,4 +114,4 @@ smoke_report: smoke http://smoke.git.nix.is/app/projects/process_add_report/1 \ | grep -v ^Redirecting -.PHONY: pre-clean $(T) aggregate-results clean valgrind smoke smoke_report +.PHONY: pre-clean $(T) aggregate-results clean valgrind perf @@ -671,76 +671,3 @@ Then, at the top-level: That'll generate a detailed cover report in the "cover_db_html" directory, which you can then copy to a webserver, or inspect locally in a browser. - -Smoke testing -------------- - -The Git test suite has support for smoke testing. Smoke testing is -when you submit the results of a test run to a central server for -analysis and aggregation. - -Running a smoke tester is an easy and valuable way of contributing to -Git development, particularly if you have access to an uncommon OS on -obscure hardware. - -After building Git you can generate a smoke report like this in the -"t" directory: - - make clean smoke - -You can also pass arguments via the environment. This should make it -faster: - - GIT_TEST_OPTS='--root=/dev/shm' TEST_JOBS=10 make clean smoke - -The "smoke" target will run the Git test suite with Perl's -"TAP::Harness" module, and package up the results in a .tar.gz archive -with "TAP::Harness::Archive". The former is included with Perl v5.10.1 -or later, but you'll need to install the latter from the CPAN. See the -"Test coverage" section above for how you might do that. - -Once the "smoke" target finishes you'll see a message like this: - - TAP Archive created at <path to git>/t/test-results/git-smoke.tar.gz - -To upload the smoke report you need to have curl(1) installed, then -do: - - make smoke_report - -To upload the report anonymously. Hopefully that'll return something -like "Reported #7 added.". - -If you're going to be uploading reports frequently please request a -user account by E-Mailing gitsmoke@v.nix.is. Once you have a username -and password you'll be able to do: - - SMOKE_USERNAME=<username> SMOKE_PASSWORD=<password> make smoke_report - -You can also add an additional comment to attach to the report, and/or -a comma separated list of tags: - - SMOKE_USERNAME=<username> SMOKE_PASSWORD=<password> \ - SMOKE_COMMENT=<comment> SMOKE_TAGS=<tags> \ - make smoke_report - -Once the report is uploaded it'll be made available at -http://smoke.git.nix.is, here's an overview of Recent Smoke Reports -for Git: - - http://smoke.git.nix.is/app/projects/smoke_reports/1 - -The reports will also be mirrored to GitHub every few hours: - - http://github.com/gitsmoke/smoke-reports - -The Smolder SQLite database is also mirrored and made available for -download: - - http://github.com/gitsmoke/smoke-database - -Note that the database includes hashed (with crypt()) user passwords -and E-Mail addresses. Don't use a valuable password for the smoke -service if you have an account, or an E-Mail address you don't want to -be publicly known. The user accounts are just meant to be convenient -labels, they're not meant to be secure. diff --git a/t/harness b/t/harness deleted file mode 100755 index f5c02f49b7..0000000000 --- a/t/harness +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/perl -use strict; -use warnings; -use Getopt::Long (); -use TAP::Harness::Archive; - -Getopt::Long::Parser->new( - config => [ qw/ pass_through / ], -)->getoptions( - 'jobs:1' => \(my $jobs = $ENV{TEST_JOBS}), - 'archive=s' => \my $archive, -) or die "$0: Couldn't getoptions()"; - -TAP::Harness::Archive->new({ - jobs => $jobs, - archive => $archive, - ($ENV{GIT_TEST_OPTS} - ? (test_args => [ split /\s+/, $ENV{GIT_TEST_OPTS} ]) - : ()), - extra_properties => {}, -})->runtests(@ARGV); diff --git a/t/perf/.gitignore b/t/perf/.gitignore new file mode 100644 index 0000000000..50f5cc1ed9 --- /dev/null +++ b/t/perf/.gitignore @@ -0,0 +1,2 @@ +build/ +test-results/ diff --git a/t/perf/Makefile b/t/perf/Makefile new file mode 100644 index 0000000000..8c47155a7c --- /dev/null +++ b/t/perf/Makefile @@ -0,0 +1,15 @@ +-include ../../config.mak +export GIT_TEST_OPTIONS + +all: perf + +perf: pre-clean + ./run + +pre-clean: + rm -rf test-results + +clean: + rm -rf build "trash directory".* test-results + +.PHONY: all perf pre-clean clean diff --git a/t/perf/README b/t/perf/README new file mode 100644 index 0000000000..b2dbad4d50 --- /dev/null +++ b/t/perf/README @@ -0,0 +1,146 @@ +Git performance tests +===================== + +This directory holds performance testing scripts for git tools. The +first part of this document describes the various ways in which you +can run them. + +When fixing the tools or adding enhancements, you are strongly +encouraged to add tests in this directory to cover what you are +trying to fix or enhance. The later part of this short document +describes how your test scripts should be organized. + + +Running Tests +------------- + +The easiest way to run tests is to say "make". This runs all +the tests on the current git repository. + + === Running 2 tests in this tree === + [...] + Test this tree + --------------------------------------------------------- + 0001.1: rev-list --all 0.54(0.51+0.02) + 0001.2: rev-list --all --objects 6.14(5.99+0.11) + 7810.1: grep worktree, cheap regex 0.16(0.16+0.35) + 7810.2: grep worktree, expensive regex 7.90(29.75+0.37) + 7810.3: grep --cached, cheap regex 3.07(3.02+0.25) + 7810.4: grep --cached, expensive regex 9.39(30.57+0.24) + +You can compare multiple repositories and even git revisions with the +'run' script: + + $ ./run . origin/next /path/to/git-tree p0001-rev-list.sh + +where . stands for the current git tree. The full invocation is + + ./run [<revision|directory>...] [--] [<test-script>...] + +A '.' argument is implied if you do not pass any other +revisions/directories. + +You can also manually test this or another git build tree, and then +call the aggregation script to summarize the results: + + $ ./p0001-rev-list.sh + [...] + $ GIT_BUILD_DIR=/path/to/other/git ./p0001-rev-list.sh + [...] + $ ./aggregate.perl . /path/to/other/git ./p0001-rev-list.sh + +aggregate.perl has the same invocation as 'run', it just does not run +anything beforehand. + +You can set the following variables (also in your config.mak): + + GIT_PERF_REPEAT_COUNT + Number of times a test should be repeated for best-of-N + measurements. Defaults to 5. + + GIT_PERF_MAKE_OPTS + Options to use when automatically building a git tree for + performance testing. E.g., -j6 would be useful. + + GIT_PERF_REPO + GIT_PERF_LARGE_REPO + Repositories to copy for the performance tests. The normal + repo should be at least git.git size. The large repo should + probably be about linux-2.6.git size for optimal results. + Both default to the git.git you are running from. + +You can also pass the options taken by ordinary git tests; the most +useful one is: + +--root=<directory>:: + Create "trash" directories used to store all temporary data during + testing under <directory>, instead of the t/ directory. + Using this option with a RAM-based filesystem (such as tmpfs) + can massively speed up the test suite. + + +Naming Tests +------------ + +The performance test files are named as: + + pNNNN-commandname-details.sh + +where N is a decimal digit. The same conventions for choosing NNNN as +for normal tests apply. + + +Writing Tests +------------- + +The perf script starts much like a normal test script, except it +sources perf-lib.sh: + + #!/bin/sh + # + # Copyright (c) 2005 Junio C Hamano + # + + test_description='xxx performance test' + . ./perf-lib.sh + +After that you will want to use some of the following: + + test_perf_default_repo # sets up a "normal" repository + test_perf_large_repo # sets up a "large" repository + + test_perf_default_repo sub # ditto, in a subdir "sub" + + test_checkout_worktree # if you need the worktree too + +At least one of the first two is required! + +You can use test_expect_success as usual. For actual performance +tests, use + + test_perf 'descriptive string' ' + command1 && + command2 + ' + +test_perf spawns a subshell, for lack of better options. This means +that + +* you _must_ export all variables that you need in the subshell + +* you _must_ flag all variables that you want to persist from the + subshell with 'test_export': + + test_perf 'descriptive string' ' + foo=$(git rev-parse HEAD) && + test_export foo + ' + + The so-exported variables are automatically marked for export in the + shell executing the perf test. For your convenience, test_export is + the same as export in the main shell. + + This feature relies on a bit of magic using 'set' and 'source'. + While we have tried to make sure that it can cope with embedded + whitespace and other special characters, it will not work with + multi-line data. diff --git a/t/perf/aggregate.perl b/t/perf/aggregate.perl new file mode 100755 index 0000000000..15f7fc1b80 --- /dev/null +++ b/t/perf/aggregate.perl @@ -0,0 +1,166 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Git; + +sub get_times { + my $name = shift; + open my $fh, "<", $name or return undef; + my $line = <$fh>; + return undef if not defined $line; + close $fh or die "cannot close $name: $!"; + $line =~ /^(?:(\d+):)?(\d+):(\d+(?:\.\d+)?) (\d+(?:\.\d+)?) (\d+(?:\.\d+)?)$/ + or die "bad input line: $line"; + my $rt = ((defined $1 ? $1 : 0.0)*60+$2)*60+$3; + return ($rt, $4, $5); +} + +sub format_times { + my ($r, $u, $s, $firstr) = @_; + if (!defined $r) { + return "<missing>"; + } + my $out = sprintf "%.2f(%.2f+%.2f)", $r, $u, $s; + if (defined $firstr) { + if ($firstr > 0) { + $out .= sprintf " %+.1f%%", 100.0*($r-$firstr)/$firstr; + } elsif ($r == 0) { + $out .= " ="; + } else { + $out .= " +inf"; + } + } + return $out; +} + +my (@dirs, %dirnames, %dirabbrevs, %prefixes, @tests); +while (scalar @ARGV) { + my $arg = $ARGV[0]; + my $dir; + last if -f $arg or $arg eq "--"; + if (! -d $arg) { + my $rev = Git::command_oneline(qw(rev-parse --verify), $arg); + $dir = "build/".$rev; + } else { + $arg =~ s{/*$}{}; + $dir = $arg; + $dirabbrevs{$dir} = $dir; + } + push @dirs, $dir; + $dirnames{$dir} = $arg; + my $prefix = $dir; + $prefix =~ tr/^a-zA-Z0-9/_/c; + $prefixes{$dir} = $prefix . '.'; + shift @ARGV; +} + +if (not @dirs) { + @dirs = ('.'); +} +$dirnames{'.'} = $dirabbrevs{'.'} = "this tree"; +$prefixes{'.'} = ''; + +shift @ARGV if scalar @ARGV and $ARGV[0] eq "--"; + +@tests = @ARGV; +if (not @tests) { + @tests = glob "p????-*.sh"; +} + +my @subtests; +my %shorttests; +for my $t (@tests) { + $t =~ s{(?:.*/)?(p(\d+)-[^/]+)\.sh$}{$1} or die "bad test name: $t"; + my $n = $2; + my $fname = "test-results/$t.subtests"; + open my $fp, "<", $fname or die "cannot open $fname: $!"; + for (<$fp>) { + chomp; + /^(\d+)$/ or die "malformed subtest line: $_"; + push @subtests, "$t.$1"; + $shorttests{"$t.$1"} = "$n.$1"; + } + close $fp or die "cannot close $fname: $!"; +} + +sub read_descr { + my $name = shift; + open my $fh, "<", $name or return "<error reading description>"; + my $line = <$fh>; + close $fh or die "cannot close $name"; + chomp $line; + return $line; +} + +my %descrs; +my $descrlen = 4; # "Test" +for my $t (@subtests) { + $descrs{$t} = $shorttests{$t}.": ".read_descr("test-results/$t.descr"); + $descrlen = length $descrs{$t} if length $descrs{$t}>$descrlen; +} + +sub have_duplicate { + my %seen; + for (@_) { + return 1 if exists $seen{$_}; + $seen{$_} = 1; + } + return 0; +} +sub have_slash { + for (@_) { + return 1 if m{/}; + } + return 0; +} + +my %newdirabbrevs = %dirabbrevs; +while (!have_duplicate(values %newdirabbrevs)) { + %dirabbrevs = %newdirabbrevs; + last if !have_slash(values %dirabbrevs); + %newdirabbrevs = %dirabbrevs; + for (values %newdirabbrevs) { + s{^[^/]*/}{}; + } +} + +my %times; +my @colwidth = ((0)x@dirs); +for my $i (0..$#dirs) { + my $d = $dirs[$i]; + my $w = length (exists $dirabbrevs{$d} ? $dirabbrevs{$d} : $dirnames{$d}); + $colwidth[$i] = $w if $w > $colwidth[$i]; +} +for my $t (@subtests) { + my $firstr; + for my $i (0..$#dirs) { + my $d = $dirs[$i]; + $times{$prefixes{$d}.$t} = [get_times("test-results/$prefixes{$d}$t.times")]; + my ($r,$u,$s) = @{$times{$prefixes{$d}.$t}}; + my $w = length format_times($r,$u,$s,$firstr); + $colwidth[$i] = $w if $w > $colwidth[$i]; + $firstr = $r unless defined $firstr; + } +} +my $totalwidth = 3*@dirs+$descrlen; +$totalwidth += $_ for (@colwidth); + +printf "%-${descrlen}s", "Test"; +for my $i (0..$#dirs) { + my $d = $dirs[$i]; + printf " %-$colwidth[$i]s", (exists $dirabbrevs{$d} ? $dirabbrevs{$d} : $dirnames{$d}); +} +print "\n"; +print "-"x$totalwidth, "\n"; +for my $t (@subtests) { + printf "%-${descrlen}s", $descrs{$t}; + my $firstr; + for my $i (0..$#dirs) { + my $d = $dirs[$i]; + my ($r,$u,$s) = @{$times{$prefixes{$d}.$t}}; + printf " %-$colwidth[$i]s", format_times($r,$u,$s,$firstr); + $firstr = $r unless defined $firstr; + } + print "\n"; +} diff --git a/t/perf/min_time.perl b/t/perf/min_time.perl new file mode 100755 index 0000000000..c1a2717e07 --- /dev/null +++ b/t/perf/min_time.perl @@ -0,0 +1,21 @@ +#!/usr/bin/perl + +my $minrt = 1e100; +my $min; + +while (<>) { + # [h:]m:s.xx U.xx S.xx + /^(?:(\d+):)?(\d+):(\d+(?:\.\d+)?) (\d+(?:\.\d+)?) (\d+(?:\.\d+)?)$/ + or die "bad input line: $_"; + my $rt = ((defined $1 ? $1 : 0.0)*60+$2)*60+$3; + if ($rt < $minrt) { + $min = $_; + $minrt = $rt; + } +} + +if (!defined $min) { + die "no input found"; +} + +print $min; diff --git a/t/perf/p0000-perf-lib-sanity.sh b/t/perf/p0000-perf-lib-sanity.sh new file mode 100755 index 0000000000..cf8e1efce7 --- /dev/null +++ b/t/perf/p0000-perf-lib-sanity.sh @@ -0,0 +1,55 @@ +#!/bin/sh + +test_description='Tests whether perf-lib facilities work' +. ./perf-lib.sh + +test_perf_default_repo + +test_perf 'test_perf_default_repo works' ' + foo=$(git rev-parse HEAD) && + test_export foo +' + +test_checkout_worktree + +test_perf 'test_checkout_worktree works' ' + wt=$(find . | wc -l) && + idx=$(git ls-files | wc -l) && + test $wt -gt $idx +' + +baz=baz +test_export baz + +test_expect_success 'test_export works' ' + echo "$foo" && + test "$foo" = "$(git rev-parse HEAD)" && + echo "$baz" && + test "$baz" = baz +' + +test_perf 'export a weird var' ' + bar="weird # variable" && + test_export bar +' + +test_expect_success 'test_export works with weird vars' ' + echo "$bar" && + test "$bar" = "weird # variable" +' + +test_perf 'important variables available in subshells' ' + test -n "$HOME" && + test -n "$TEST_DIRECTORY" && + test -n "$TRASH_DIRECTORY" && + test -n "$GIT_BUILD_DIR" +' + +test_perf 'test-lib-functions correctly loaded in subshells' ' + : >a && + test_path_is_file a && + : >b && + test_cmp a b +' + +test_done diff --git a/t/perf/p0001-rev-list.sh b/t/perf/p0001-rev-list.sh new file mode 100755 index 0000000000..4f71a63b0a --- /dev/null +++ b/t/perf/p0001-rev-list.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +test_description="Tests history walking performance" + +. ./perf-lib.sh + +test_perf_default_repo + +test_perf 'rev-list --all' ' + git rev-list --all >/dev/null +' + +test_perf 'rev-list --all --objects' ' + git rev-list --all --objects >/dev/null +' + +test_done diff --git a/t/perf/p4000-diff-algorithms.sh b/t/perf/p4000-diff-algorithms.sh new file mode 100755 index 0000000000..7e00c9da47 --- /dev/null +++ b/t/perf/p4000-diff-algorithms.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +test_description="Tests diff generation performance" + +. ./perf-lib.sh + +test_perf_default_repo + +test_perf 'log -3000 (baseline)' ' + git log -3000 >/dev/null +' + +test_perf 'log --raw -3000 (tree-only)' ' + git log --raw -3000 >/dev/null +' + +test_perf 'log -p -3000 (Myers)' ' + git log -p -3000 >/dev/null +' + +test_perf 'log -p -3000 --histogram' ' + git log -p -3000 --histogram >/dev/null +' + +test_perf 'log -p -3000 --patience' ' + git log -p -3000 --patience >/dev/null +' + +test_done diff --git a/t/perf/p7810-grep.sh b/t/perf/p7810-grep.sh new file mode 100755 index 0000000000..9f4ade639f --- /dev/null +++ b/t/perf/p7810-grep.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +test_description="git-grep performance in various modes" + +. ./perf-lib.sh + +test_perf_large_repo +test_checkout_worktree + +test_perf 'grep worktree, cheap regex' ' + git grep some_nonexistent_string || : +' +test_perf 'grep worktree, expensive regex' ' + git grep "^.* *some_nonexistent_string$" || : +' +test_perf 'grep --cached, cheap regex' ' + git grep --cached some_nonexistent_string || : +' +test_perf 'grep --cached, expensive regex' ' + git grep --cached "^.* *some_nonexistent_string$" || : +' + +test_done diff --git a/t/perf/perf-lib.sh b/t/perf/perf-lib.sh new file mode 100644 index 0000000000..5580c22812 --- /dev/null +++ b/t/perf/perf-lib.sh @@ -0,0 +1,202 @@ +#!/bin/sh +# +# Copyright (c) 2011 Thomas Rast +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see http://www.gnu.org/licenses/ . + +# do the --tee work early; it otherwise confuses our careful +# GIT_BUILD_DIR mangling +case "$GIT_TEST_TEE_STARTED, $* " in +done,*) + # do not redirect again + ;; +*' --tee '*|*' --va'*) + mkdir -p test-results + BASE=test-results/$(basename "$0" .sh) + (GIT_TEST_TEE_STARTED=done ${SHELL-sh} "$0" "$@" 2>&1; + echo $? > $BASE.exit) | tee $BASE.out + test "$(cat $BASE.exit)" = 0 + exit + ;; +esac + +TEST_DIRECTORY=$(pwd)/.. +TEST_OUTPUT_DIRECTORY=$(pwd) +if test -z "$GIT_TEST_INSTALLED"; then + perf_results_prefix= +else + perf_results_prefix=$(printf "%s" "${GIT_TEST_INSTALLED%/bin-wrappers}" | tr -c "[a-zA-Z0-9]" "[_*]")"." + # make the tested dir absolute + GIT_TEST_INSTALLED=$(cd "$GIT_TEST_INSTALLED" && pwd) +fi + +TEST_NO_CREATE_REPO=t + +. ../test-lib.sh + +# Variables from test-lib that are normally internal to the tests; we +# need to export them for test_perf subshells +export TEST_DIRECTORY TRASH_DIRECTORY GIT_BUILD_DIR GIT_TEST_CMP + +perf_results_dir=$TEST_OUTPUT_DIRECTORY/test-results +mkdir -p "$perf_results_dir" +rm -f "$perf_results_dir"/$(basename "$0" .sh).subtests + +if test -z "$GIT_PERF_REPEAT_COUNT"; then + GIT_PERF_REPEAT_COUNT=3 +fi +die_if_build_dir_not_repo () { + if ! ( cd "$TEST_DIRECTORY/.." && + git rev-parse --build-dir >/dev/null 2>&1 ); then + error "No $1 defined, and your build directory is not a repo" + fi +} + +if test -z "$GIT_PERF_REPO"; then + die_if_build_dir_not_repo '$GIT_PERF_REPO' + GIT_PERF_REPO=$TEST_DIRECTORY/.. +fi +if test -z "$GIT_PERF_LARGE_REPO"; then + die_if_build_dir_not_repo '$GIT_PERF_LARGE_REPO' + GIT_PERF_LARGE_REPO=$TEST_DIRECTORY/.. +fi + +test_perf_create_repo_from () { + test "$#" = 2 || + error "bug in the test script: not 2 parameters to test-create-repo" + repo="$1" + source="$2" + source_git=$source/$(cd "$source" && git rev-parse --git-dir) + mkdir -p "$repo/.git" + ( + cd "$repo/.git" && + { cp -Rl "$source_git/objects" . 2>/dev/null || + cp -R "$source_git/objects" .; } && + for stuff in "$source_git"/*; do + case "$stuff" in + */objects|*/hooks|*/config) + ;; + *) + cp -R "$stuff" . || break + ;; + esac + done && + cd .. && + git init -q && + mv .git/hooks .git/hooks-disabled 2>/dev/null + ) || error "failed to copy repository '$source' to '$repo'" +} + +# call at least one of these to establish an appropriately-sized repository +test_perf_default_repo () { + test_perf_create_repo_from "${1:-$TRASH_DIRECTORY}" "$GIT_PERF_REPO" +} +test_perf_large_repo () { + if test "$GIT_PERF_LARGE_REPO" = "$GIT_BUILD_DIR"; then + echo "warning: \$GIT_PERF_LARGE_REPO is \$GIT_BUILD_DIR." >&2 + echo "warning: This will work, but may not be a sufficiently large repo" >&2 + echo "warning: for representative measurements." >&2 + fi + test_perf_create_repo_from "${1:-$TRASH_DIRECTORY}" "$GIT_PERF_LARGE_REPO" +} +test_checkout_worktree () { + git checkout-index -u -a || + error "git checkout-index failed" +} + +# Performance tests should never fail. If they do, stop immediately +immediate=t + +test_run_perf_ () { + test_cleanup=: + test_export_="test_cleanup" + export test_cleanup test_export_ + /usr/bin/time -f "%E %U %S" -o test_time.$i "$SHELL" -c ' +. '"$TEST_DIRECTORY"/test-lib-functions.sh' +test_export () { + [ $# != 0 ] || return 0 + test_export_="$test_export_\\|$1" + shift + test_export "$@" +} +'"$1"' +ret=$? +set | sed -n "s'"/'/'\\\\''/g"';s/^\\($test_export_\\)/export '"'&'"'/p" >test_vars +exit $ret' >&3 2>&4 + eval_ret=$? + + if test $eval_ret = 0 || test -n "$expecting_failure" + then + test_eval_ "$test_cleanup" + . ./test_vars || error "failed to load updated environment" + fi + if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"; then + echo "" + fi + return "$eval_ret" +} + + +test_perf () { + test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= + test "$#" = 2 || + error "bug in the test script: not 2 or 3 parameters to test-expect-success" + export test_prereq + if ! test_skip "$@" + then + base=$(basename "$0" .sh) + echo "$test_count" >>"$perf_results_dir"/$base.subtests + echo "$1" >"$perf_results_dir"/$base.$test_count.descr + if test -z "$verbose"; then + echo -n "perf $test_count - $1:" + else + echo "perf $test_count - $1:" + fi + for i in $(seq 1 $GIT_PERF_REPEAT_COUNT); do + say >&3 "running: $2" + if test_run_perf_ "$2" + then + if test -z "$verbose"; then + echo -n " $i" + else + echo "* timing run $i/$GIT_PERF_REPEAT_COUNT:" + fi + else + test -z "$verbose" && echo + test_failure_ "$@" + break + fi + done + if test -z "$verbose"; then + echo " ok" + else + test_ok_ "$1" + fi + base="$perf_results_dir"/"$perf_results_prefix$(basename "$0" .sh)"."$test_count" + "$TEST_DIRECTORY"/perf/min_time.perl test_time.* >"$base".times + fi + echo >&3 "" +} + +# We extend test_done to print timings at the end (./run disables this +# and does it after running everything) +test_at_end_hook_ () { + if test -z "$GIT_PERF_AGGREGATING_LATER"; then + ( cd "$TEST_DIRECTORY"/perf && ./aggregate.perl $(basename "$0") ) + fi +} + +test_export () { + export "$@" +} diff --git a/t/perf/run b/t/perf/run new file mode 100755 index 0000000000..cfd70129bb --- /dev/null +++ b/t/perf/run @@ -0,0 +1,82 @@ +#!/bin/sh + +case "$1" in + --help) + echo "usage: $0 [other_git_tree...] [--] [test_scripts]" + exit 0 + ;; +esac + +die () { + echo >&2 "error: $*" + exit 1 +} + +run_one_dir () { + if test $# -eq 0; then + set -- p????-*.sh + fi + echo "=== Running $# tests in ${GIT_TEST_INSTALLED:-this tree} ===" + for t in "$@"; do + ./$t $GIT_TEST_OPTS + done +} + +unpack_git_rev () { + rev=$1 + mkdir -p build/$rev + (cd "$(git rev-parse --show-cdup)" && git archive --format=tar $rev) | + (cd build/$rev && tar x) +} +build_git_rev () { + rev=$1 + cp ../../config.mak build/$rev/config.mak + (cd build/$rev && make $GIT_PERF_MAKE_OPTS) || + die "failed to build revision '$mydir'" +} + +run_dirs_helper () { + mydir=${1%/} + shift + while test $# -gt 0 -a "$1" != -- -a ! -f "$1"; do + shift + done + if test $# -gt 0 -a "$1" = --; then + shift + fi + if [ ! -d "$mydir" ]; then + rev=$(git rev-parse --verify "$mydir" 2>/dev/null) || + die "'$mydir' is neither a directory nor a valid revision" + if [ ! -d build/$rev ]; then + unpack_git_rev $rev + fi + build_git_rev $rev + mydir=build/$rev + fi + if test "$mydir" = .; then + unset GIT_TEST_INSTALLED + else + GIT_TEST_INSTALLED="$mydir/bin-wrappers" + export GIT_TEST_INSTALLED + fi + run_one_dir "$@" +} + +run_dirs () { + while test $# -gt 0 -a "$1" != -- -a ! -f "$1"; do + run_dirs_helper "$@" + shift + done +} + +GIT_PERF_AGGREGATING_LATER=t +export GIT_PERF_AGGREGATING_LATER + +cd "$(dirname $0)" +. ../../GIT-BUILD-OPTIONS + +if test $# = 0 -o "$1" = -- -o -f "$1"; then + set -- . "$@" +fi +run_dirs "$@" +./aggregate.perl "$@" diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh index f4e8f43bae..ccb5435b2a 100755 --- a/t/t0000-basic.sh +++ b/t/t0000-basic.sh @@ -34,69 +34,69 @@ fi # git init has been done in an empty repository. # make sure it is empty. -find .git/objects -type f -print >should-be-empty -test_expect_success \ - '.git/objects should be empty after git init in an empty repo.' \ - 'cmp -s /dev/null should-be-empty' +test_expect_success '.git/objects should be empty after git init in an empty repo' ' + find .git/objects -type f -print >should-be-empty && + test_line_count = 0 should-be-empty +' # also it should have 2 subdirectories; no fan-out anymore, pack, and info. # 3 is counting "objects" itself -find .git/objects -type d -print >full-of-directories -test_expect_success \ - '.git/objects should have 3 subdirectories.' \ - 'test $(wc -l < full-of-directories) = 3' +test_expect_success '.git/objects should have 3 subdirectories' ' + find .git/objects -type d -print >full-of-directories && + test_line_count = 3 full-of-directories +' ################################################################ # Test harness test_expect_success 'success is reported like this' ' - : + : ' test_expect_failure 'pretend we have a known breakage' ' - false + false ' test_expect_success 'pretend we have fixed a known breakage (run in sub test-lib)' " - mkdir passing-todo && - (cd passing-todo && - cat >passing-todo.sh <<EOF && -#!$SHELL_PATH - -test_description='A passing TODO test - -This is run in a sub test-lib so that we do not get incorrect passing -metrics -' - -# Point to the t/test-lib.sh, which isn't in ../ as usual -TEST_DIRECTORY=\"$TEST_DIRECTORY\" -. \"\$TEST_DIRECTORY\"/test-lib.sh - -test_expect_failure 'pretend we have fixed a known breakage' ' - : -' - -test_done -EOF - chmod +x passing-todo.sh && - ./passing-todo.sh >out 2>err && - ! test -s err && -sed -e 's/^> //' >expect <<EOF && -> ok 1 - pretend we have fixed a known breakage # TODO known breakage -> # fixed 1 known breakage(s) -> # passed all 1 test(s) -> 1..1 -EOF - test_cmp expect out) + mkdir passing-todo && + (cd passing-todo && + cat >passing-todo.sh <<-EOF && + #!$SHELL_PATH + + test_description='A passing TODO test + + This is run in a sub test-lib so that we do not get incorrect + passing metrics + ' + + # Point to the t/test-lib.sh, which isn't in ../ as usual + TEST_DIRECTORY=\"$TEST_DIRECTORY\" + . \"\$TEST_DIRECTORY\"/test-lib.sh + + test_expect_failure 'pretend we have fixed a known breakage' ' + : + ' + + test_done + EOF + chmod +x passing-todo.sh && + ./passing-todo.sh >out 2>err && + ! test -s err && + sed -e 's/^> //' >expect <<-\\EOF && + > ok 1 - pretend we have fixed a known breakage # TODO known breakage + > # fixed 1 known breakage(s) + > # passed all 1 test(s) + > 1..1 + EOF + test_cmp expect out) " test_set_prereq HAVEIT haveit=no test_expect_success HAVEIT 'test runs if prerequisite is satisfied' ' - test_have_prereq HAVEIT && - haveit=yes + test_have_prereq HAVEIT && + haveit=yes ' donthaveit=yes test_expect_success DONTHAVEIT 'unmet prerequisite causes test to be skipped' ' - donthaveit=no + donthaveit=no ' if test $haveit$donthaveit != yesyes then @@ -107,17 +107,17 @@ fi test_set_prereq HAVETHIS haveit=no test_expect_success HAVETHIS,HAVEIT 'test runs if prerequisites are satisfied' ' - test_have_prereq HAVEIT && - test_have_prereq HAVETHIS && - haveit=yes + test_have_prereq HAVEIT && + test_have_prereq HAVETHIS && + haveit=yes ' donthaveit=yes test_expect_success HAVEIT,DONTHAVEIT 'unmet prerequisites causes test to be skipped' ' - donthaveit=no + donthaveit=no ' donthaveiteither=yes test_expect_success DONTHAVEIT,HAVEIT 'unmet prerequisites causes test to be skipped' ' - donthaveiteither=no + donthaveiteither=no ' if test $haveit$donthaveit$donthaveiteither != yesyesyes then @@ -127,7 +127,7 @@ fi clean=no test_expect_success 'tests clean up after themselves' ' - test_when_finished clean=yes + test_when_finished clean=yes ' if test $clean != yes @@ -137,106 +137,100 @@ then fi test_expect_success 'tests clean up even on failures' " - mkdir failing-cleanup && - (cd failing-cleanup && - cat >failing-cleanup.sh <<EOF && -#!$SHELL_PATH - -test_description='Failing tests with cleanup commands' - -# Point to the t/test-lib.sh, which isn't in ../ as usual -TEST_DIRECTORY=\"$TEST_DIRECTORY\" -. \"\$TEST_DIRECTORY\"/test-lib.sh - -test_expect_success 'tests clean up even after a failure' ' - touch clean-after-failure && - test_when_finished rm clean-after-failure && - (exit 1) -' - -test_expect_success 'failure to clean up causes the test to fail' ' - test_when_finished \"(exit 2)\" -' - -test_done -EOF - chmod +x failing-cleanup.sh && - test_must_fail ./failing-cleanup.sh >out 2>err && - ! test -s err && - ! test -f \"trash directory.failing-cleanup/clean-after-failure\" && -sed -e 's/Z$//' -e 's/^> //' >expect <<\EOF && -> not ok - 1 tests clean up even after a failure -> # Z -> # touch clean-after-failure && -> # test_when_finished rm clean-after-failure && -> # (exit 1) -> # Z -> not ok - 2 failure to clean up causes the test to fail -> # Z -> # test_when_finished \"(exit 2)\" -> # Z -> # failed 2 among 2 test(s) -> 1..2 -EOF - test_cmp expect out) + mkdir failing-cleanup && + ( + cd failing-cleanup && + + cat >failing-cleanup.sh <<-EOF && + #!$SHELL_PATH + + test_description='Failing tests with cleanup commands' + + # Point to the t/test-lib.sh, which isn't in ../ as usual + TEST_DIRECTORY=\"$TEST_DIRECTORY\" + . \"\$TEST_DIRECTORY\"/test-lib.sh + + test_expect_success 'tests clean up even after a failure' ' + touch clean-after-failure && + test_when_finished rm clean-after-failure && + (exit 1) + ' + test_expect_success 'failure to clean up causes the test to fail' ' + test_when_finished \"(exit 2)\" + ' + test_done + + EOF + + chmod +x failing-cleanup.sh && + test_must_fail ./failing-cleanup.sh >out 2>err && + ! test -s err && + ! test -f \"trash directory.failing-cleanup/clean-after-failure\" && + sed -e 's/Z$//' -e 's/^> //' >expect <<-\\EOF && + > not ok - 1 tests clean up even after a failure + > # Z + > # touch clean-after-failure && + > # test_when_finished rm clean-after-failure && + > # (exit 1) + > # Z + > not ok - 2 failure to clean up causes the test to fail + > # Z + > # test_when_finished \"(exit 2)\" + > # Z + > # failed 2 among 2 test(s) + > 1..2 + EOF + test_cmp expect out + ) " ################################################################ # Basics of the basics # updating a new file without --add should fail. -test_expect_success 'git update-index without --add should fail adding.' ' - test_must_fail git update-index should-be-empty +test_expect_success 'git update-index without --add should fail adding' ' + test_must_fail git update-index should-be-empty ' # and with --add it should succeed, even if it is empty (it used to fail). -test_expect_success \ - 'git update-index with --add should succeed.' \ - 'git update-index --add should-be-empty' +test_expect_success 'git update-index with --add should succeed' ' + git update-index --add should-be-empty +' -test_expect_success \ - 'writing tree out with git write-tree' \ - 'tree=$(git write-tree)' +test_expect_success 'writing tree out with git write-tree' ' + tree=$(git write-tree) +' # we know the shape and contents of the tree and know the object ID for it. -test_expect_success \ - 'validate object ID of a known tree.' \ - 'test "$tree" = 7bb943559a305bdd6bdee2cef6e5df2413c3d30a' +test_expect_success 'validate object ID of a known tree' ' + test "$tree" = 7bb943559a305bdd6bdee2cef6e5df2413c3d30a + ' # Removing paths. -rm -f should-be-empty full-of-directories -test_expect_success 'git update-index without --remove should fail removing.' ' - test_must_fail git update-index should-be-empty +test_expect_success 'git update-index without --remove should fail removing' ' + rm -f should-be-empty full-of-directories && + test_must_fail git update-index should-be-empty ' -test_expect_success \ - 'git update-index with --remove should be able to remove.' \ - 'git update-index --remove should-be-empty' +test_expect_success 'git update-index with --remove should be able to remove' ' + git update-index --remove should-be-empty +' # Empty tree can be written with recent write-tree. -test_expect_success \ - 'git write-tree should be able to write an empty tree.' \ - 'tree=$(git write-tree)' +test_expect_success 'git write-tree should be able to write an empty tree' ' + tree=$(git write-tree) +' -test_expect_success \ - 'validate object ID of a known tree.' \ - 'test "$tree" = 4b825dc642cb6eb9a060e54bf8d69288fbee4904' +test_expect_success 'validate object ID of a known tree' ' + test "$tree" = 4b825dc642cb6eb9a060e54bf8d69288fbee4904 +' # Various types of objects + # Some filesystems do not support symblic links; on such systems # some expected values are different -mkdir path2 path3 path3/subp3 -paths='path0 path2/file2 path3/file3 path3/subp3/file3' -for p in $paths -do - echo "hello $p" >$p -done if test_have_prereq SYMLINKS then - for p in $paths - do - ln -s "hello $p" ${p}sym - done expectfilter=cat expectedtree=087704a96baf1c2d1c869a8b084481e121c88b5b expectedptree1=21ae8269cacbe57ae09138dcc3a2887f904d02b3 @@ -248,135 +242,154 @@ else expectedptree2=ce580448f0148b985a513b693fdf7d802cacb44f fi -test_expect_success \ - 'adding various types of objects with git update-index --add.' \ - 'find path* ! -type d -print | xargs git update-index --add' + +test_expect_success 'adding various types of objects with git update-index --add' ' + mkdir path2 path3 path3/subp3 && + paths="path0 path2/file2 path3/file3 path3/subp3/file3" && + ( + for p in $paths + do + echo "hello $p" >$p || exit 1 + if test_have_prereq SYMLINKS + then + ln -s "hello $p" ${p}sym || exit 1 + fi + done + ) && + find path* ! -type d -print | xargs git update-index --add +' # Show them and see that matches what we expect. -test_expect_success \ - 'showing stage with git ls-files --stage' \ - 'git ls-files --stage >current' - -$expectfilter >expected <<\EOF -100644 f87290f8eb2cbbea7857214459a0739927eab154 0 path0 -120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0 path0sym -100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0 path2/file2 -120000 d8ce161addc5173867a3c3c730924388daedbc38 0 path2/file2sym -100644 0aa34cae68d0878578ad119c86ca2b5ed5b28376 0 path3/file3 -120000 8599103969b43aff7e430efea79ca4636466794f 0 path3/file3sym -100644 00fb5908cb97c2564a9783c0c64087333b3b464f 0 path3/subp3/file3 -120000 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c 0 path3/subp3/file3sym -EOF -test_expect_success \ - 'validate git ls-files output for a known tree.' \ - 'test_cmp expected current' - -test_expect_success \ - 'writing tree out with git write-tree.' \ - 'tree=$(git write-tree)' -test_expect_success \ - 'validate object ID for a known tree.' \ - 'test "$tree" = "$expectedtree"' - -test_expect_success \ - 'showing tree with git ls-tree' \ - 'git ls-tree $tree >current' -cat >expected <<\EOF -100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 -120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym -040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2 -040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3 -EOF -test_expect_success SYMLINKS \ - 'git ls-tree output for a known tree.' \ - 'test_cmp expected current' +test_expect_success 'showing stage with git ls-files --stage' ' + git ls-files --stage >current +' + +test_expect_success 'validate git ls-files output for a known tree' ' + $expectfilter >expected <<-\EOF && + 100644 f87290f8eb2cbbea7857214459a0739927eab154 0 path0 + 120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0 path0sym + 100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0 path2/file2 + 120000 d8ce161addc5173867a3c3c730924388daedbc38 0 path2/file2sym + 100644 0aa34cae68d0878578ad119c86ca2b5ed5b28376 0 path3/file3 + 120000 8599103969b43aff7e430efea79ca4636466794f 0 path3/file3sym + 100644 00fb5908cb97c2564a9783c0c64087333b3b464f 0 path3/subp3/file3 + 120000 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c 0 path3/subp3/file3sym + EOF + test_cmp expected current +' + +test_expect_success 'writing tree out with git write-tree' ' + tree=$(git write-tree) +' + +test_expect_success 'validate object ID for a known tree' ' + test "$tree" = "$expectedtree" +' + +test_expect_success 'showing tree with git ls-tree' ' + git ls-tree $tree >current +' + +test_expect_success SYMLINKS 'git ls-tree output for a known tree' ' + cat >expected <<-\EOF && + 100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 + 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym + 040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2 + 040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3 + EOF + test_cmp expected current +' # This changed in ls-tree pathspec change -- recursive does # not show tree nodes anymore. -test_expect_success \ - 'showing tree with git ls-tree -r' \ - 'git ls-tree -r $tree >current' -$expectfilter >expected <<\EOF -100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 -120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym -100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2 -120000 blob d8ce161addc5173867a3c3c730924388daedbc38 path2/file2sym -100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376 path3/file3 -120000 blob 8599103969b43aff7e430efea79ca4636466794f path3/file3sym -100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3 -120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym -EOF -test_expect_success \ - 'git ls-tree -r output for a known tree.' \ - 'test_cmp expected current' +test_expect_success 'showing tree with git ls-tree -r' ' + git ls-tree -r $tree >current +' + +test_expect_success 'git ls-tree -r output for a known tree' ' + $expectfilter >expected <<-\EOF && + 100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 + 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym + 100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2 + 120000 blob d8ce161addc5173867a3c3c730924388daedbc38 path2/file2sym + 100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376 path3/file3 + 120000 blob 8599103969b43aff7e430efea79ca4636466794f path3/file3sym + 100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3 + 120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym + EOF + test_cmp expected current +' # But with -r -t we can have both. -test_expect_success \ - 'showing tree with git ls-tree -r -t' \ - 'git ls-tree -r -t $tree >current' -cat >expected <<\EOF -100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 -120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym -040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2 -100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2 -120000 blob d8ce161addc5173867a3c3c730924388daedbc38 path2/file2sym -040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3 -100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376 path3/file3 -120000 blob 8599103969b43aff7e430efea79ca4636466794f path3/file3sym -040000 tree 3c5e5399f3a333eddecce7a9b9465b63f65f51e2 path3/subp3 -100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3 -120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym -EOF -test_expect_success SYMLINKS \ - 'git ls-tree -r output for a known tree.' \ - 'test_cmp expected current' - -test_expect_success \ - 'writing partial tree out with git write-tree --prefix.' \ - 'ptree=$(git write-tree --prefix=path3)' -test_expect_success \ - 'validate object ID for a known tree.' \ - 'test "$ptree" = "$expectedptree1"' - -test_expect_success \ - 'writing partial tree out with git write-tree --prefix.' \ - 'ptree=$(git write-tree --prefix=path3/subp3)' -test_expect_success \ - 'validate object ID for a known tree.' \ - 'test "$ptree" = "$expectedptree2"' - -cat >badobjects <<EOF -100644 blob 1000000000000000000000000000000000000000 dir/file1 -100644 blob 2000000000000000000000000000000000000000 dir/file2 -100644 blob 3000000000000000000000000000000000000000 dir/file3 -100644 blob 4000000000000000000000000000000000000000 dir/file4 -100644 blob 5000000000000000000000000000000000000000 dir/file5 -EOF +test_expect_success 'showing tree with git ls-tree -r -t' ' + git ls-tree -r -t $tree >current +' -rm .git/index -test_expect_success \ - 'put invalid objects into the index.' \ - 'git update-index --index-info < badobjects' +test_expect_success SYMLINKS 'git ls-tree -r output for a known tree' ' + cat >expected <<-\EOF && + 100644 blob f87290f8eb2cbbea7857214459a0739927eab154 path0 + 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01 path0sym + 040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe path2 + 100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 path2/file2 + 120000 blob d8ce161addc5173867a3c3c730924388daedbc38 path2/file2sym + 040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3 path3 + 100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376 path3/file3 + 120000 blob 8599103969b43aff7e430efea79ca4636466794f path3/file3sym + 040000 tree 3c5e5399f3a333eddecce7a9b9465b63f65f51e2 path3/subp3 + 100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f path3/subp3/file3 + 120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c path3/subp3/file3sym + EOF + test_cmp expected current +' -test_expect_success 'writing this tree without --missing-ok.' ' - test_must_fail git write-tree +test_expect_success 'writing partial tree out with git write-tree --prefix' ' + ptree=$(git write-tree --prefix=path3) ' -test_expect_success \ - 'writing this tree with --missing-ok.' \ - 'git write-tree --missing-ok' +test_expect_success 'validate object ID for a known tree' ' + test "$ptree" = "$expectedptree1" +' + +test_expect_success 'writing partial tree out with git write-tree --prefix' ' + ptree=$(git write-tree --prefix=path3/subp3) +' + +test_expect_success 'validate object ID for a known tree' ' + test "$ptree" = "$expectedptree2" +' + +test_expect_success 'put invalid objects into the index' ' + rm -f .git/index && + cat >badobjects <<-\EOF && + 100644 blob 1000000000000000000000000000000000000000 dir/file1 + 100644 blob 2000000000000000000000000000000000000000 dir/file2 + 100644 blob 3000000000000000000000000000000000000000 dir/file3 + 100644 blob 4000000000000000000000000000000000000000 dir/file4 + 100644 blob 5000000000000000000000000000000000000000 dir/file5 + EOF + git update-index --index-info <badobjects +' + +test_expect_success 'writing this tree without --missing-ok' ' + test_must_fail git write-tree +' + +test_expect_success 'writing this tree with --missing-ok' ' + git write-tree --missing-ok +' ################################################################ -rm .git/index -test_expect_success \ - 'git read-tree followed by write-tree should be idempotent.' \ - 'git read-tree $tree && - test -f .git/index && - newtree=$(git write-tree) && - test "$newtree" = "$tree"' - -$expectfilter >expected <<\EOF +test_expect_success 'git read-tree followed by write-tree should be idempotent' ' + rm -f .git/index + git read-tree $tree && + test -f .git/index && + newtree=$(git write-tree) && + test "$newtree" = "$tree" +' + +test_expect_success 'validate git diff-files output for a know cache/work tree state' ' + $expectfilter >expected <<\EOF && :100644 100644 f87290f8eb2cbbea7857214459a0739927eab154 0000000000000000000000000000000000000000 M path0 :120000 120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0000000000000000000000000000000000000000 M path0sym :100644 100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0000000000000000000000000000000000000000 M path2/file2 @@ -386,45 +399,47 @@ $expectfilter >expected <<\EOF :100644 100644 00fb5908cb97c2564a9783c0c64087333b3b464f 0000000000000000000000000000000000000000 M path3/subp3/file3 :120000 120000 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c 0000000000000000000000000000000000000000 M path3/subp3/file3sym EOF -test_expect_success \ - 'validate git diff-files output for a know cache/work tree state.' \ - 'git diff-files >current && test_cmp current expected >/dev/null' + git diff-files >current && + test_cmp current expected +' -test_expect_success \ - 'git update-index --refresh should succeed.' \ - 'git update-index --refresh' +test_expect_success 'git update-index --refresh should succeed' ' + git update-index --refresh +' -test_expect_success \ - 'no diff after checkout and git update-index --refresh.' \ - 'git diff-files >current && cmp -s current /dev/null' +test_expect_success 'no diff after checkout and git update-index --refresh' ' + git diff-files >current && + cmp -s current /dev/null +' ################################################################ P=$expectedtree -test_expect_success \ - 'git commit-tree records the correct tree in a commit.' \ - 'commit0=$(echo NO | git commit-tree $P) && - tree=$(git show --pretty=raw $commit0 | - sed -n -e "s/^tree //p" -e "/^author /q") && - test "z$tree" = "z$P"' - -test_expect_success \ - 'git commit-tree records the correct parent in a commit.' \ - 'commit1=$(echo NO | git commit-tree $P -p $commit0) && - parent=$(git show --pretty=raw $commit1 | - sed -n -e "s/^parent //p" -e "/^author /q") && - test "z$commit0" = "z$parent"' - -test_expect_success \ - 'git commit-tree omits duplicated parent in a commit.' \ - 'commit2=$(echo NO | git commit-tree $P -p $commit0 -p $commit0) && - parent=$(git show --pretty=raw $commit2 | - sed -n -e "s/^parent //p" -e "/^author /q" | - sort -u) && - test "z$commit0" = "z$parent" && - numparent=$(git show --pretty=raw $commit2 | - sed -n -e "s/^parent //p" -e "/^author /q" | - wc -l) && - test $numparent = 1' + +test_expect_success 'git commit-tree records the correct tree in a commit' ' + commit0=$(echo NO | git commit-tree $P) && + tree=$(git show --pretty=raw $commit0 | + sed -n -e "s/^tree //p" -e "/^author /q") && + test "z$tree" = "z$P" +' + +test_expect_success 'git commit-tree records the correct parent in a commit' ' + commit1=$(echo NO | git commit-tree $P -p $commit0) && + parent=$(git show --pretty=raw $commit1 | + sed -n -e "s/^parent //p" -e "/^author /q") && + test "z$commit0" = "z$parent" +' + +test_expect_success 'git commit-tree omits duplicated parent in a commit' ' + commit2=$(echo NO | git commit-tree $P -p $commit0 -p $commit0) && + parent=$(git show --pretty=raw $commit2 | + sed -n -e "s/^parent //p" -e "/^author /q" | + sort -u) && + test "z$commit0" = "z$parent" && + numparent=$(git show --pretty=raw $commit2 | + sed -n -e "s/^parent //p" -e "/^author /q" | + wc -l) && + test $numparent = 1 +' test_expect_success 'update-index D/F conflict' ' mv path0 tmp && diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh index f19e6510d0..e50f0f742f 100755 --- a/t/t0021-conversion.sh +++ b/t/t0021-conversion.sh @@ -153,4 +153,41 @@ test_expect_success 'filter shell-escaped filenames' ' : ' +test_expect_success 'required filter success' ' + git config filter.required.smudge cat && + git config filter.required.clean cat && + git config filter.required.required true && + + echo "*.r filter=required" >.gitattributes && + + echo test >test.r && + git add test.r && + rm -f test.r && + git checkout -- test.r +' + +test_expect_success 'required filter smudge failure' ' + git config filter.failsmudge.smudge false && + git config filter.failsmudge.clean cat && + git config filter.failsmudge.required true && + + echo "*.fs filter=failsmudge" >.gitattributes && + + echo test >test.fs && + git add test.fs && + rm -f test.fs && + test_must_fail git checkout -- test.fs +' + +test_expect_success 'required filter clean failure' ' + git config filter.failclean.smudge cat && + git config filter.failclean.clean false && + git config filter.failclean.required true && + + echo "*.fc filter=failclean" >.gitattributes && + + echo test >test.fc && + test_must_fail git add test.fc +' + test_done diff --git a/t/t0040-parse-options.sh b/t/t0040-parse-options.sh index a1e4616feb..e3f354a45e 100755 --- a/t/t0040-parse-options.sh +++ b/t/t0040-parse-options.sh @@ -10,7 +10,10 @@ test_description='our own option parser' cat > expect << EOF usage: test-parse-options <options> - -b, --boolean get a boolean + --yes get a boolean + -D, --no-doubt begins with 'no-' + -B, --no-fear be brave + -b, --boolean increment by one -4, --or4 bitwise-or boolean with ...0100 --neg-or4 same as --no-or4 @@ -53,6 +56,59 @@ test_expect_success 'test help' ' mv expect expect.err +cat >expect.template <<EOF +boolean: 0 +integer: 0 +timestamp: 0 +string: (not set) +abbrev: 7 +verbose: 0 +quiet: no +dry run: no +file: (not set) +EOF + +check() { + what="$1" && + shift && + expect="$1" && + shift && + sed "s/^$what .*/$what $expect/" <expect.template >expect && + test-parse-options $* >output 2>output.err && + test ! -s output.err && + test_cmp expect output +} + +check_unknown() { + case "$1" in + --*) + echo error: unknown option \`${1#--}\' >expect ;; + -*) + echo error: unknown switch \`${1#-}\' >expect ;; + esac && + cat expect.err >>expect && + test_must_fail test-parse-options $* >output 2>output.err && + test ! -s output && + test_cmp expect output.err +} + +test_expect_success 'OPT_BOOL() #1' 'check boolean: 1 --yes' +test_expect_success 'OPT_BOOL() #2' 'check boolean: 1 --no-doubt' +test_expect_success 'OPT_BOOL() #3' 'check boolean: 1 -D' +test_expect_success 'OPT_BOOL() #4' 'check boolean: 1 --no-fear' +test_expect_success 'OPT_BOOL() #5' 'check boolean: 1 -B' + +test_expect_success 'OPT_BOOL() is idempotent #1' 'check boolean: 1 --yes --yes' +test_expect_success 'OPT_BOOL() is idempotent #2' 'check boolean: 1 -DB' + +test_expect_success 'OPT_BOOL() negation #1' 'check boolean: 0 -D --no-yes' +test_expect_success 'OPT_BOOL() negation #2' 'check boolean: 0 -D --no-no-doubt' + +test_expect_success 'OPT_BOOL() no negation #1' 'check_unknown --fear' +test_expect_success 'OPT_BOOL() no negation #2' 'check_unknown --no-no-fear' + +test_expect_success 'OPT_BOOL() positivation' 'check boolean: 0 -D --doubt' + cat > expect << EOF boolean: 2 integer: 1729 @@ -180,6 +236,16 @@ test_expect_success 'detect possible typos' ' test_cmp typo.err output.err ' +cat > typo.err << EOF +error: did you mean \`--ambiguous\` (with two dashes ?) +EOF + +test_expect_success 'detect possible typos' ' + test_must_fail test-parse-options -ambiguous > output 2> output.err && + test ! -s output && + test_cmp typo.err output.err +' + cat > expect <<EOF boolean: 0 integer: 0 @@ -296,7 +362,7 @@ test_expect_success 'OPT_NEGBIT() works' ' test_cmp expect output ' -test_expect_success 'OPT_BOOLEAN() with PARSE_OPT_NODASH works' ' +test_expect_success 'OPT_COUNTUP() with PARSE_OPT_NODASH works' ' test-parse-options + + + + + + > output 2> output.err && test ! -s output.err && test_cmp expect output diff --git a/t/t0204-gettext-reencode-sanity.sh b/t/t0204-gettext-reencode-sanity.sh index 189af90c02..8437e51eb5 100755 --- a/t/t0204-gettext-reencode-sanity.sh +++ b/t/t0204-gettext-reencode-sanity.sh @@ -7,6 +7,10 @@ test_description="Gettext reencoding of our *.po/*.mo files works" . ./lib-gettext.sh +# The constants used in a tricky observation for undefined behaviour +RUNES="TILRAUN: ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ" +PUNTS="TILRAUN: ?? ???? ??? ?? ???? ?? ??? ????? ??????????? ??? ?? ????" +MSGKEY="TEST: Old English Runes" test_expect_success GETTEXT_LOCALE 'gettext: Emitting UTF-8 from our UTF-8 *.mo files / Icelandic' ' printf "TILRAUN: Halló Heimur!" >expect && @@ -15,8 +19,8 @@ test_expect_success GETTEXT_LOCALE 'gettext: Emitting UTF-8 from our UTF-8 *.mo ' test_expect_success GETTEXT_LOCALE 'gettext: Emitting UTF-8 from our UTF-8 *.mo files / Runes' ' - printf "TILRAUN: ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ" >expect && - LANGUAGE=is LC_ALL="$is_IS_locale" gettext "TEST: Old English Runes" >actual && + printf "%s" "$RUNES" >expect && + LANGUAGE=is LC_ALL="$is_IS_locale" gettext "$MSGKEY" >actual && test_cmp expect actual ' @@ -26,18 +30,23 @@ test_expect_success GETTEXT_ISO_LOCALE 'gettext: Emitting ISO-8859-1 from our UT test_cmp expect actual ' -test_expect_success GETTEXT_ISO_LOCALE 'gettext: Emitting ISO-8859-1 from our UTF-8 *.mo files / Runes' ' - LANGUAGE=is LC_ALL="$is_IS_iso_locale" gettext "TEST: Old English Runes" >runes && - - if grep "^TEST: Old English Runes$" runes - then - say "Your system can not handle this complexity and returns the string as-is" - else - # Both Solaris and GNU libintl will return this stream of - # question marks, so it is s probably portable enough - printf "TILRAUN: ?? ???? ??? ?? ???? ?? ??? ????? ??????????? ??? ?? ????" >runes-expect && - test_cmp runes-expect runes - fi +test_expect_success GETTEXT_ISO_LOCALE 'gettext: impossible ISO-8859-1 output' ' + LANGUAGE=is LC_ALL="$is_IS_iso_locale" gettext "$MSGKEY" >runes && + case "$(cat runes)" in + "$MSGKEY") + say "Your system gives back the key to message catalog" + ;; + "$PUNTS") + say "Your system replaces an impossible character with ?" + ;; + "$RUNES") + say "Your system gives back the raw message for an impossible request" + ;; + *) + say "We never saw the error behaviour your system exhibits" + false + ;; + esac ' test_expect_success GETTEXT_LOCALE 'gettext: Fetching a UTF-8 msgid -> UTF-8' ' diff --git a/t/t0300-credentials.sh b/t/t0300-credentials.sh index 8621ab036f..20e28e34e7 100755 --- a/t/t0300-credentials.sh +++ b/t/t0300-credentials.sh @@ -8,10 +8,13 @@ test_expect_success 'setup helper scripts' ' cat >dump <<-\EOF && whoami=`echo $0 | sed s/.*git-credential-//` echo >&2 "$whoami: $*" - while IFS== read key value; do + OIFS=$IFS + IFS== + while read key value; do echo >&2 "$whoami: $key=$value" eval "$key=$value" done + IFS=$OIFS EOF write_script git-credential-useless <<-\EOF && diff --git a/t/t1051-large-conversion.sh b/t/t1051-large-conversion.sh new file mode 100755 index 0000000000..8b7640b3ba --- /dev/null +++ b/t/t1051-large-conversion.sh @@ -0,0 +1,86 @@ +#!/bin/sh + +test_description='test conversion filters on large files' +. ./test-lib.sh + +set_attr() { + test_when_finished 'rm -f .gitattributes' && + echo "* $*" >.gitattributes +} + +check_input() { + git read-tree --empty && + git add small large && + git cat-file blob :small >small.index && + git cat-file blob :large | head -n 1 >large.index && + test_cmp small.index large.index +} + +check_output() { + rm -f small large && + git checkout small large && + head -n 1 large >large.head && + test_cmp small large.head +} + +test_expect_success 'setup input tests' ' + printf "\$Id: foo\$\\r\\n" >small && + cat small small >large && + git config core.bigfilethreshold 20 && + git config filter.test.clean "sed s/.*/CLEAN/" +' + +test_expect_success 'autocrlf=true converts on input' ' + test_config core.autocrlf true && + check_input +' + +test_expect_success 'eol=crlf converts on input' ' + set_attr eol=crlf && + check_input +' + +test_expect_success 'ident converts on input' ' + set_attr ident && + check_input +' + +test_expect_success 'user-defined filters convert on input' ' + set_attr filter=test && + check_input +' + +test_expect_success 'setup output tests' ' + echo "\$Id\$" >small && + cat small small >large && + git add small large && + git config core.bigfilethreshold 7 && + git config filter.test.smudge "sed s/.*/SMUDGE/" +' + +test_expect_success 'autocrlf=true converts on output' ' + test_config core.autocrlf true && + check_output +' + +test_expect_success 'eol=crlf converts on output' ' + set_attr eol=crlf && + check_output +' + +test_expect_success 'user-defined filters convert on output' ' + set_attr filter=test && + check_output +' + +test_expect_success 'ident converts on output' ' + set_attr ident && + rm -f small large && + git checkout small large && + sed -n "s/Id: .*/Id: SHA/p" <small >small.clean && + head -n 1 large >large.head && + sed -n "s/Id: .*/Id: SHA/p" <large.head >large.clean && + test_cmp small.clean large.clean +' + +test_done diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh index 5e29e13782..9356beaf4b 100755 --- a/t/t1200-tutorial.sh +++ b/t/t1200-tutorial.sh @@ -156,7 +156,7 @@ Updating VARIABLE..VARIABLE FASTFORWARD (no commit created; -m option ignored) example | 1 + hello | 1 + - 2 files changed, 2 insertions(+), 0 deletions(-) + 2 files changed, 2 insertions(+) EOF test_expect_success 'git resolve' ' diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 0690e0edf4..36e227b3bb 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -451,13 +451,21 @@ test_expect_success 'refer config from subdirectory' ' mkdir x && ( cd x && - echo strasse >expect + echo strasse >expect && git config --get --file ../other-config ein.bahn >actual && test_cmp expect actual ) ' +test_expect_success 'refer config from subdirectory via GIT_CONFIG' ' + ( + cd x && + GIT_CONFIG=../other-config git config --get ein.bahn >actual && + test_cmp expect actual + ) +' + cat > expect << EOF [ein] bahn = strasse @@ -960,4 +968,52 @@ test_expect_success 'git -c complains about empty key and value' ' test_must_fail git -c "" rev-parse ' +test_expect_success 'git config --edit works' ' + git config -f tmp test.value no && + echo test.value=yes >expect && + GIT_EDITOR="echo [test]value=yes >" git config -f tmp --edit && + git config -f tmp --list >actual && + test_cmp expect actual +' + +test_expect_success 'git config --edit respects core.editor' ' + git config -f tmp test.value no && + echo test.value=yes >expect && + test_config core.editor "echo [test]value=yes >" && + git config -f tmp --edit && + git config -f tmp --list >actual && + test_cmp expect actual +' + +# malformed configuration files +test_expect_success 'barf on syntax error' ' + cat >.git/config <<-\EOF && + # broken section line + [section] + key garbage + EOF + test_must_fail git config --get section.key >actual 2>error && + grep " line 3 " error +' + +test_expect_success 'barf on incomplete section header' ' + cat >.git/config <<-\EOF && + # broken section line + [section + key = value + EOF + test_must_fail git config --get section.key >actual 2>error && + grep " line 2 " error +' + +test_expect_success 'barf on incomplete string' ' + cat >.git/config <<-\EOF && + # broken section line + [section] + key = "value string + EOF + test_must_fail git config --get section.key >actual 2>error && + grep " line 3 " error +' + test_done diff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh new file mode 100755 index 0000000000..4b1cbaa028 --- /dev/null +++ b/t/t1305-config-include.sh @@ -0,0 +1,134 @@ +#!/bin/sh + +test_description='test config file include directives' +. ./test-lib.sh + +test_expect_success 'include file by absolute path' ' + echo "[test]one = 1" >one && + echo "[include]path = \"$(pwd)/one\"" >.gitconfig && + echo 1 >expect && + git config test.one >actual && + test_cmp expect actual +' + +test_expect_success 'include file by relative path' ' + echo "[test]one = 1" >one && + echo "[include]path = one" >.gitconfig && + echo 1 >expect && + git config test.one >actual && + test_cmp expect actual +' + +test_expect_success 'chained relative paths' ' + mkdir subdir && + echo "[test]three = 3" >subdir/three && + echo "[include]path = three" >subdir/two && + echo "[include]path = subdir/two" >.gitconfig && + echo 3 >expect && + git config test.three >actual && + test_cmp expect actual +' + +test_expect_success 'include options can still be examined' ' + echo "[test]one = 1" >one && + echo "[include]path = one" >.gitconfig && + echo one >expect && + git config include.path >actual && + test_cmp expect actual +' + +test_expect_success 'listing includes option and expansion' ' + echo "[test]one = 1" >one && + echo "[include]path = one" >.gitconfig && + cat >expect <<-\EOF && + include.path=one + test.one=1 + EOF + git config --list >actual.full && + grep -v ^core actual.full >actual && + test_cmp expect actual +' + +test_expect_success 'single file lookup does not expand includes by default' ' + echo "[test]one = 1" >one && + echo "[include]path = one" >.gitconfig && + test_must_fail git config -f .gitconfig test.one && + test_must_fail git config --global test.one && + echo 1 >expect && + git config --includes -f .gitconfig test.one >actual && + test_cmp expect actual +' + +test_expect_success 'single file list does not expand includes by default' ' + echo "[test]one = 1" >one && + echo "[include]path = one" >.gitconfig && + echo "include.path=one" >expect && + git config -f .gitconfig --list >actual && + test_cmp expect actual +' + +test_expect_success 'writing config file does not expand includes' ' + echo "[test]one = 1" >one && + echo "[include]path = one" >.gitconfig && + git config test.two 2 && + echo 2 >expect && + git config --no-includes test.two >actual && + test_cmp expect actual && + test_must_fail git config --no-includes test.one +' + +test_expect_success 'config modification does not affect includes' ' + echo "[test]one = 1" >one && + echo "[include]path = one" >.gitconfig && + git config test.one 2 && + echo 1 >expect && + git config -f one test.one >actual && + test_cmp expect actual && + cat >expect <<-\EOF && + 1 + 2 + EOF + git config --get-all test.one >actual && + test_cmp expect actual +' + +test_expect_success 'missing include files are ignored' ' + cat >.gitconfig <<-\EOF && + [include]path = foo + [test]value = yes + EOF + echo yes >expect && + git config test.value >actual && + test_cmp expect actual +' + +test_expect_success 'absolute includes from command line work' ' + echo "[test]one = 1" >one && + echo 1 >expect && + git -c include.path="$PWD/one" config test.one >actual && + test_cmp expect actual +' + +test_expect_success 'relative includes from command line fail' ' + echo "[test]one = 1" >one && + test_must_fail git -c include.path=one config test.one +' + +test_expect_success 'include cycles are detected' ' + cat >.gitconfig <<-\EOF && + [test]value = gitconfig + [include]path = cycle + EOF + cat >cycle <<-\EOF && + [test]value = cycle + [include]path = .gitconfig + EOF + cat >expect <<-\EOF && + gitconfig + cycle + EOF + test_must_fail git config --get-all test.value 2>stderr && + grep "exceeded maximum include depth" stderr +' + +test_done diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index 523ce9c45b..5b79c51b8c 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -27,12 +27,8 @@ test_expect_success 'loose objects borrowed from alternate are not missing' ' git init && echo ../../../.git/objects >.git/objects/info/alternates && test_commit C fileC one && - git fsck >../out 2>&1 + git fsck --no-dangling >../actual 2>&1 ) && - { - grep -v dangling out >actual || - : - } && test_cmp empty actual ' @@ -191,4 +187,30 @@ test_expect_success 'cleaned up' ' test_cmp empty actual ' +test_expect_success 'rev-list --verify-objects' ' + git rev-list --verify-objects --all >/dev/null 2>out && + test_cmp empty out +' + +test_expect_success 'rev-list --verify-objects with bad sha1' ' + sha=$(echo blob | git hash-object -w --stdin) && + old=$(echo $sha | sed "s+^..+&/+") && + new=$(dirname $old)/ffffffffffffffffffffffffffffffffffffff && + sha="$(dirname $new)$(basename $new)" && + mv .git/objects/$old .git/objects/$new && + test_when_finished "remove_object $sha" && + git update-index --add --cacheinfo 100644 $sha foo && + test_when_finished "git read-tree -u --reset HEAD" && + tree=$(git write-tree) && + test_when_finished "remove_object $tree" && + cmt=$(echo bogus | git commit-tree $tree) && + test_when_finished "remove_object $cmt" && + git update-ref refs/heads/bogus $cmt && + test_when_finished "git update-ref -d refs/heads/bogus" && + + test_might_fail git rev-list --verify-objects refs/heads/bogus >/dev/null 2>out && + cat out && + grep -q "error: sha1 mismatch 63ffffffffffffffffffffffffffffffffffffff" out +' + test_done diff --git a/t/t2015-checkout-unborn.sh b/t/t2015-checkout-unborn.sh index c551d39a66..6352b74e2e 100755 --- a/t/t2015-checkout-unborn.sh +++ b/t/t2015-checkout-unborn.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='checkout from unborn branch protects contents' +test_description='checkout from unborn branch' . ./test-lib.sh test_expect_success 'setup' ' @@ -37,4 +37,13 @@ test_expect_success 'checkout from unborn merges identical index contents' ' git checkout -b new origin ' +test_expect_success 'checking out another branch from unborn state' ' + git checkout --orphan newroot && + git checkout -b anothername && + test_must_fail git show-ref --verify refs/heads/newroot && + git symbolic-ref HEAD >actual && + echo refs/heads/anothername >expect && + test_cmp expect actual +' + test_done diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index dd1acebd88..9fe1d8feab 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -653,4 +653,8 @@ test_expect_success 'refuse --edit-description on unborn branch for now' ' ) ' +test_expect_success '--merged catches invalid object names' ' + test_must_fail git branch --merged 0000000000000000000000000000000000000000 +' + test_done diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh index 5e29a05259..9f00ada5f7 100755 --- a/t/t3300-funny-names.sh +++ b/t/t3300-funny-names.sh @@ -167,7 +167,7 @@ test_expect_success TABS_IN_FILENAMES 'git diff-tree delete with-funny' \ test_expect_success TABS_IN_FILENAMES 'setup expect' ' cat >expected <<\EOF "tabs\t,\" (dq) and spaces" - 1 files changed, 0 insertions(+), 0 deletions(-) + 1 file changed, 0 insertions(+), 0 deletions(-) EOF ' diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index e647272a01..7788ae02ad 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -160,14 +160,12 @@ rm -f B test_expect_success 'fail when upstream arg is missing and not on branch' ' git checkout topic && - test_must_fail git rebase >output.out && - grep "You are not currently on a branch" output.out + test_must_fail git rebase ' test_expect_success 'fail when upstream arg is missing and not configured' ' git checkout -b no-config topic && - test_must_fail git rebase >output.out && - grep "branch.no-config.merge" output.out + test_must_fail git rebase ' test_expect_success 'default to @{upstream} when upstream arg is missing' ' diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh index ee1659c178..0c81b3c427 100755 --- a/t/t3507-cherry-pick-conflict.sh +++ b/t/t3507-cherry-pick-conflict.sh @@ -59,6 +59,20 @@ test_expect_success 'advice from failed cherry-pick' " test_i18ncmp expected actual " +test_expect_success 'advice from failed cherry-pick --no-commit' " + pristine_detach initial && + + picked=\$(git rev-parse --short picked) && + cat <<-EOF >expected && + error: could not apply \$picked... picked + hint: after resolving the conflicts, mark the corrected paths + hint: with 'git add <paths>' or 'git rm <paths>' + EOF + test_must_fail git cherry-pick --no-commit picked 2>actual && + + test_i18ncmp expected actual +" + test_expect_success 'failed cherry-pick sets CHERRY_PICK_HEAD' ' pristine_detach initial && test_must_fail git cherry-pick picked && diff --git a/t/t3508-cherry-pick-many-commits.sh b/t/t3508-cherry-pick-many-commits.sh index 8e09fd0319..1b3a344158 100755 --- a/t/t3508-cherry-pick-many-commits.sh +++ b/t/t3508-cherry-pick-many-commits.sh @@ -38,13 +38,13 @@ test_expect_success 'cherry-pick first..fourth works' ' cat <<-\EOF >expected && [master OBJID] second Author: A U Thor <author@example.com> - 1 files changed, 1 insertions(+), 0 deletions(-) + 1 file changed, 1 insertion(+) [master OBJID] third Author: A U Thor <author@example.com> - 1 files changed, 1 insertions(+), 0 deletions(-) + 1 file changed, 1 insertion(+) [master OBJID] fourth Author: A U Thor <author@example.com> - 1 files changed, 1 insertions(+), 0 deletions(-) + 1 file changed, 1 insertion(+) EOF git checkout -f master && @@ -64,15 +64,15 @@ test_expect_success 'cherry-pick --strategy resolve first..fourth works' ' Trying simple merge. [master OBJID] second Author: A U Thor <author@example.com> - 1 files changed, 1 insertions(+), 0 deletions(-) + 1 file changed, 1 insertion(+) Trying simple merge. [master OBJID] third Author: A U Thor <author@example.com> - 1 files changed, 1 insertions(+), 0 deletions(-) + 1 file changed, 1 insertion(+) Trying simple merge. [master OBJID] fourth Author: A U Thor <author@example.com> - 1 files changed, 1 insertions(+), 0 deletions(-) + 1 file changed, 1 insertion(+) EOF git checkout -f master && diff --git a/t/t3700-add.sh b/t/t3700-add.sh index 575d9508a0..874b3a6444 100755 --- a/t/t3700-add.sh +++ b/t/t3700-add.sh @@ -179,6 +179,21 @@ test_expect_success 'git add --refresh' ' test -z "`git diff-index HEAD -- foo`" ' +test_expect_success 'git add --refresh with pathspec' ' + git reset --hard && + echo >foo && echo >bar && echo >baz && + git add foo bar baz && H=$(git rev-parse :foo) && git rm -f foo && + echo "100644 $H 3 foo" | git update-index --index-info && + test-chmtime -60 bar baz && + >expect && + git add --refresh bar >actual && + test_cmp expect actual && + + git diff-files --name-only >actual && + ! grep bar actual&& + grep baz actual +' + test_expect_success POSIXPERM,SANITY 'git add should fail atomically upon an unreadable file' ' git reset --hard && date >foo1 && diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index dbe2ac179d..663c60a12e 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -444,7 +444,7 @@ test_expect_success 'stash show - stashes on stack, stash-like argument' ' git reset --hard && cat >expected <<-EOF && file | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) + 1 file changed, 1 insertion(+) EOF git stash show ${STASH_ID} >actual && test_cmp expected actual @@ -482,7 +482,7 @@ test_expect_success 'stash show - no stashes on stack, stash-like argument' ' git reset --hard && cat >expected <<-EOF && file | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) + 1 file changed, 1 insertion(+) EOF git stash show ${STASH_ID} >actual && test_cmp expected actual diff --git a/t/t4011-diff-symlink.sh b/t/t4011-diff-symlink.sh index 408a19c4c2..f0d5041c11 100755 --- a/t/t4011-diff-symlink.sh +++ b/t/t4011-diff-symlink.sh @@ -9,85 +9,110 @@ test_description='Test diff of symlinks. . ./test-lib.sh . "$TEST_DIRECTORY"/diff-lib.sh -cat > expected << EOF -diff --git a/frotz b/frotz -new file mode 120000 -index 0000000..7c465af ---- /dev/null -+++ b/frotz -@@ -0,0 +1 @@ -+xyzzy -\ No newline at end of file -EOF - -test_expect_success SYMLINKS \ - 'diff new symlink' \ - 'ln -s xyzzy frotz && - git update-index && - tree=$(git write-tree) && - git update-index --add frotz && - GIT_DIFF_OPTS=--unified=0 git diff-index -M -p $tree > current && - compare_diff_patch current expected' - -test_expect_success SYMLINKS \ - 'diff unchanged symlink' \ - 'tree=$(git write-tree) && - git update-index frotz && - test -z "$(git diff-index --name-only $tree)"' - -cat > expected << EOF -diff --git a/frotz b/frotz -deleted file mode 120000 -index 7c465af..0000000 ---- a/frotz -+++ /dev/null -@@ -1 +0,0 @@ --xyzzy -\ No newline at end of file -EOF +test_expect_success SYMLINKS 'diff new symlink and file' ' + cat >expected <<-\EOF && + diff --git a/frotz b/frotz + new file mode 120000 + index 0000000..7c465af + --- /dev/null + +++ b/frotz + @@ -0,0 +1 @@ + +xyzzy + \ No newline at end of file + diff --git a/nitfol b/nitfol + new file mode 100644 + index 0000000..7c465af + --- /dev/null + +++ b/nitfol + @@ -0,0 +1 @@ + +xyzzy + EOF + ln -s xyzzy frotz && + echo xyzzy >nitfol && + git update-index && + tree=$(git write-tree) && + git update-index --add frotz nitfol && + GIT_DIFF_OPTS=--unified=0 git diff-index -M -p $tree >current && + compare_diff_patch expected current +' -test_expect_success SYMLINKS \ - 'diff removed symlink' \ - 'mv frotz frotz2 && - git diff-index -M -p $tree > current && - compare_diff_patch current expected' +test_expect_success SYMLINKS 'diff unchanged symlink and file' ' + tree=$(git write-tree) && + git update-index frotz nitfol && + test -z "$(git diff-index --name-only $tree)" +' -cat > expected << EOF -diff --git a/frotz b/frotz -EOF +test_expect_success SYMLINKS 'diff removed symlink and file' ' + cat >expected <<-\EOF && + diff --git a/frotz b/frotz + deleted file mode 120000 + index 7c465af..0000000 + --- a/frotz + +++ /dev/null + @@ -1 +0,0 @@ + -xyzzy + \ No newline at end of file + diff --git a/nitfol b/nitfol + deleted file mode 100644 + index 7c465af..0000000 + --- a/nitfol + +++ /dev/null + @@ -1 +0,0 @@ + -xyzzy + EOF + mv frotz frotz2 && + mv nitfol nitfol2 && + git diff-index -M -p $tree >current && + compare_diff_patch expected current +' -test_expect_success SYMLINKS \ - 'diff identical, but newly created symlink' \ - 'ln -s xyzzy frotz && - git diff-index -M -p $tree > current && - compare_diff_patch current expected' +test_expect_success SYMLINKS 'diff identical, but newly created symlink and file' ' + >expected && + rm -f frotz nitfol && + echo xyzzy >nitfol && + test-chmtime +10 nitfol && + ln -s xyzzy frotz && + git diff-index -M -p $tree >current && + compare_diff_patch expected current && -cat > expected << EOF -diff --git a/frotz b/frotz -index 7c465af..df1db54 120000 ---- a/frotz -+++ b/frotz -@@ -1 +1 @@ --xyzzy -\ No newline at end of file -+yxyyz -\ No newline at end of file -EOF + >expected && + git diff-index -M -p -w $tree >current && + compare_diff_patch expected current +' -test_expect_success SYMLINKS \ - 'diff different symlink' \ - 'rm frotz && - ln -s yxyyz frotz && - git diff-index -M -p $tree > current && - compare_diff_patch current expected' +test_expect_success SYMLINKS 'diff different symlink and file' ' + cat >expected <<-\EOF && + diff --git a/frotz b/frotz + index 7c465af..df1db54 120000 + --- a/frotz + +++ b/frotz + @@ -1 +1 @@ + -xyzzy + \ No newline at end of file + +yxyyz + \ No newline at end of file + diff --git a/nitfol b/nitfol + index 7c465af..df1db54 100644 + --- a/nitfol + +++ b/nitfol + @@ -1 +1 @@ + -xyzzy + +yxyyz + EOF + rm -f frotz && + ln -s yxyyz frotz && + echo yxyyz >nitfol && + git diff-index -M -p $tree >current && + compare_diff_patch expected current +' -test_expect_success SYMLINKS \ - 'diff symlinks with non-existing targets' \ - 'ln -s narf pinky && - ln -s take\ over brain && - test_must_fail git diff --no-index pinky brain > output 2> output.err && - grep narf output && - ! grep error output.err' +test_expect_success SYMLINKS 'diff symlinks with non-existing targets' ' + ln -s narf pinky && + ln -s take\ over brain && + test_must_fail git diff --no-index pinky brain >output 2>output.err && + grep narf output && + ! test -s output.err +' test_expect_success SYMLINKS 'setup symlinks with attributes' ' echo "*.bin diff=bin" >>.gitattributes && @@ -96,19 +121,19 @@ test_expect_success SYMLINKS 'setup symlinks with attributes' ' git add -N file.bin link.bin ' -cat >expect <<'EOF' -diff --git a/file.bin b/file.bin -index e69de29..d95f3ad 100644 -Binary files a/file.bin and b/file.bin differ -diff --git a/link.bin b/link.bin -index e69de29..dce41ec 120000 ---- a/link.bin -+++ b/link.bin -@@ -0,0 +1 @@ -+file.bin -\ No newline at end of file -EOF test_expect_success SYMLINKS 'symlinks do not respect userdiff config by path' ' + cat >expect <<-\EOF && + diff --git a/file.bin b/file.bin + index e69de29..d95f3ad 100644 + Binary files a/file.bin and b/file.bin differ + diff --git a/link.bin b/link.bin + index e69de29..dce41ec 120000 + --- a/link.bin + +++ b/link.bin + @@ -0,0 +1 @@ + +file.bin + \ No newline at end of file + EOF git config diff.bin.binary true && git diff file.bin link.bin >actual && test_cmp expect actual diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master index 3a9f78a09d..2f8560c369 100644 --- a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master +++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master @@ -2,7 +2,7 @@ $ git diff-tree --cc --patch-with-stat --summary master 59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) diff --cc dir/sub index cead32e,7289e35..992913c diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side index a61ad8cb13..72e03c14fb 100644 --- a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side +++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side @@ -3,7 +3,7 @@ c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master index 49f23b9215..8b357d964b 100644 --- a/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master +++ b/t/t4013/diff.diff-tree_--cc_--patch-with-stat_master @@ -2,7 +2,7 @@ $ git diff-tree --cc --patch-with-stat master 59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) diff --cc dir/sub index cead32e,7289e35..992913c diff --git a/t/t4013/diff.diff-tree_--cc_--stat_--summary_master b/t/t4013/diff.diff-tree_--cc_--stat_--summary_master index cc6eb3b3d5..e0568d6883 100644 --- a/t/t4013/diff.diff-tree_--cc_--stat_--summary_master +++ b/t/t4013/diff.diff-tree_--cc_--stat_--summary_master @@ -2,5 +2,5 @@ $ git diff-tree --cc --stat --summary master 59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) $ diff --git a/t/t4013/diff.diff-tree_--cc_--stat_--summary_side b/t/t4013/diff.diff-tree_--cc_--stat_--summary_side index 50362be7bf..5afc8239a1 100644 --- a/t/t4013/diff.diff-tree_--cc_--stat_--summary_side +++ b/t/t4013/diff.diff-tree_--cc_--stat_--summary_side @@ -3,6 +3,6 @@ c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 $ diff --git a/t/t4013/diff.diff-tree_--cc_--stat_master b/t/t4013/diff.diff-tree_--cc_--stat_master index fae7f33255..f48367a89a 100644 --- a/t/t4013/diff.diff-tree_--cc_--stat_master +++ b/t/t4013/diff.diff-tree_--cc_--stat_master @@ -2,5 +2,5 @@ $ git diff-tree --cc --stat master 59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) $ diff --git a/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial index d5c333a378..590864c2d7 100644 --- a/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial +++ b/t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial @@ -3,7 +3,7 @@ $ git diff-tree --pretty=oneline --root --patch-with-stat initial dir/sub | 2 ++ file0 | 3 +++ file2 | 3 +++ - 3 files changed, 8 insertions(+), 0 deletions(-) + 3 files changed, 8 insertions(+) diff --git a/dir/sub b/dir/sub new file mode 100644 diff --git a/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side b/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side index 4d30e7eddc..e05e77875c 100644 --- a/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side +++ b/t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side @@ -8,7 +8,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) diff --git a/dir/sub b/dir/sub index 35d242b..7289e35 100644 diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial index 7dfa6af3c9..0e2c956633 100644 --- a/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial +++ b/t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial @@ -8,7 +8,7 @@ Date: Mon Jun 26 00:00:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file2 | 3 +++ - 3 files changed, 8 insertions(+), 0 deletions(-) + 3 files changed, 8 insertions(+) diff --git a/dir/sub b/dir/sub new file mode 100644 diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial b/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial index 43bfce253e..384fa44ddd 100644 --- a/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial +++ b/t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial @@ -8,7 +8,7 @@ Date: Mon Jun 26 00:00:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file2 | 3 +++ - 3 files changed, 8 insertions(+), 0 deletions(-) + 3 files changed, 8 insertions(+) create mode 100644 dir/sub create mode 100644 file0 create mode 100644 file2 diff --git a/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial b/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial index 9154aa4d47..10384a83d3 100644 --- a/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial +++ b/t/t4013/diff.diff-tree_--pretty_--root_--stat_initial @@ -8,5 +8,5 @@ Date: Mon Jun 26 00:00:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file2 | 3 +++ - 3 files changed, 8 insertions(+), 0 deletions(-) + 3 files changed, 8 insertions(+) $ diff --git a/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial b/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial index 1562b62708..f57062ea07 100644 --- a/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial +++ b/t/t4013/diff.diff-tree_--root_--patch-with-stat_initial @@ -3,7 +3,7 @@ $ git diff-tree --root --patch-with-stat initial dir/sub | 2 ++ file0 | 3 +++ file2 | 3 +++ - 3 files changed, 8 insertions(+), 0 deletions(-) + 3 files changed, 8 insertions(+) diff --git a/dir/sub b/dir/sub new file mode 100644 diff --git a/t/t4013/diff.diff-tree_-c_--stat_--summary_master b/t/t4013/diff.diff-tree_-c_--stat_--summary_master index ac9f641fb4..7088683444 100644 --- a/t/t4013/diff.diff-tree_-c_--stat_--summary_master +++ b/t/t4013/diff.diff-tree_-c_--stat_--summary_master @@ -2,5 +2,5 @@ $ git diff-tree -c --stat --summary master 59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) $ diff --git a/t/t4013/diff.diff-tree_-c_--stat_--summary_side b/t/t4013/diff.diff-tree_-c_--stat_--summary_side index 2afcca11f4..ef216abb1d 100644 --- a/t/t4013/diff.diff-tree_-c_--stat_--summary_side +++ b/t/t4013/diff.diff-tree_-c_--stat_--summary_side @@ -3,6 +3,6 @@ c7a2ab9e8eac7b117442a607d5a9b3950ae34d5a dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 $ diff --git a/t/t4013/diff.diff-tree_-c_--stat_master b/t/t4013/diff.diff-tree_-c_--stat_master index c2fe6a98c5..ad19f103eb 100644 --- a/t/t4013/diff.diff-tree_-c_--stat_master +++ b/t/t4013/diff.diff-tree_-c_--stat_master @@ -2,5 +2,5 @@ $ git diff-tree -c --stat master 59d314ad6f356dd08601a4cd5e530381da3e3c64 dir/sub | 2 ++ file0 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) $ diff --git a/t/t4013/diff.diff_--patch-with-stat_-r_initial..side b/t/t4013/diff.diff_--patch-with-stat_-r_initial..side index 9ed317a198..ddad917ae8 100644 --- a/t/t4013/diff.diff_--patch-with-stat_-r_initial..side +++ b/t/t4013/diff.diff_--patch-with-stat_-r_initial..side @@ -2,7 +2,7 @@ $ git diff --patch-with-stat -r initial..side dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) diff --git a/dir/sub b/dir/sub index 35d242b..7289e35 100644 diff --git a/t/t4013/diff.diff_--patch-with-stat_initial..side b/t/t4013/diff.diff_--patch-with-stat_initial..side index 8b50629e66..bdbd114d8e 100644 --- a/t/t4013/diff.diff_--patch-with-stat_initial..side +++ b/t/t4013/diff.diff_--patch-with-stat_initial..side @@ -2,7 +2,7 @@ $ git diff --patch-with-stat initial..side dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) diff --git a/dir/sub b/dir/sub index 35d242b..7289e35 100644 diff --git a/t/t4013/diff.diff_--stat_initial..side b/t/t4013/diff.diff_--stat_initial..side index 0517b5d631..6d08f3d355 100644 --- a/t/t4013/diff.diff_--stat_initial..side +++ b/t/t4013/diff.diff_--stat_initial..side @@ -2,5 +2,5 @@ $ git diff --stat initial..side dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) $ diff --git a/t/t4013/diff.diff_-r_--stat_initial..side b/t/t4013/diff.diff_-r_--stat_initial..side index 245220d3f9..2ddb2540e6 100644 --- a/t/t4013/diff.diff_-r_--stat_initial..side +++ b/t/t4013/diff.diff_-r_--stat_initial..side @@ -2,5 +2,5 @@ $ git diff -r --stat initial..side dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) $ diff --git a/t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side b/t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side index 52116d3ead..3cab049f7d 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side +++ b/t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side @@ -15,7 +15,7 @@ Content-Transfer-Encoding: 8bit dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master b/t/t4013/diff.format-patch_--attach_--stdout_initial..master index ce49bd676e..564a4d38f2 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master @@ -75,7 +75,7 @@ Content-Transfer-Encoding: 8bit --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) create mode 100644 file1 @@ -124,7 +124,7 @@ Content-Transfer-Encoding: 8bit dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ index 5f1b23863b..4f28460b83 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..master^ @@ -75,7 +75,7 @@ Content-Transfer-Encoding: 8bit --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) create mode 100644 file1 diff --git a/t/t4013/diff.format-patch_--attach_--stdout_initial..side b/t/t4013/diff.format-patch_--attach_--stdout_initial..side index 4a2364abc2..b10cc2e251 100644 --- a/t/t4013/diff.format-patch_--attach_--stdout_initial..side +++ b/t/t4013/diff.format-patch_--attach_--stdout_initial..side @@ -15,7 +15,7 @@ Content-Transfer-Encoding: 8bit dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master b/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master index 43b81eba54..a976a8aaf4 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master +++ b/t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master @@ -75,7 +75,7 @@ Content-Transfer-Encoding: 8bit --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) create mode 100644 file1 @@ -124,7 +124,7 @@ Content-Transfer-Encoding: 8bit dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master b/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master index ca3f60bf0e..b4fd66477a 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master +++ b/t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master @@ -75,7 +75,7 @@ Content-Transfer-Encoding: 8bit --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) create mode 100644 file1 @@ -124,7 +124,7 @@ Content-Transfer-Encoding: 8bit dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..master b/t/t4013/diff.format-patch_--inline_--stdout_initial..master index 08f23014bc..0d31036e7f 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_initial..master +++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master @@ -75,7 +75,7 @@ Content-Transfer-Encoding: 8bit --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) create mode 100644 file1 @@ -124,7 +124,7 @@ Content-Transfer-Encoding: 8bit dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master^ index 07f1230d31..18d4714423 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^ +++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master^ @@ -75,7 +75,7 @@ Content-Transfer-Encoding: 8bit --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) create mode 100644 file1 diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..side b/t/t4013/diff.format-patch_--inline_--stdout_initial..side index 67633d424a..3572f20b5d 100644 --- a/t/t4013/diff.format-patch_--inline_--stdout_initial..side +++ b/t/t4013/diff.format-patch_--inline_--stdout_initial..side @@ -15,7 +15,7 @@ Content-Transfer-Encoding: 8bit dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ index 3b4e113012..54cdcdab40 100644 --- a/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ +++ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ @@ -75,7 +75,7 @@ Subject: [DIFFERENT_PREFIX 2/2] Third --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) create mode 100644 file1 diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master b/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master index f7752ebbea..23194ebdaa 100644 --- a/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master +++ b/t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master @@ -53,7 +53,7 @@ Subject: [PATCH] Third --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) create mode 100644 file1 diff --git a/dir/sub b/dir/sub @@ -88,7 +88,7 @@ Subject: [PATCH] Side dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.format-patch_--stdout_--numbered_initial..master b/t/t4013/diff.format-patch_--stdout_--numbered_initial..master index 8e67dbf76f..78f1a80a97 100644 --- a/t/t4013/diff.format-patch_--stdout_--numbered_initial..master +++ b/t/t4013/diff.format-patch_--stdout_--numbered_initial..master @@ -53,7 +53,7 @@ Subject: [PATCH 2/3] Third --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) create mode 100644 file1 diff --git a/dir/sub b/dir/sub @@ -88,7 +88,7 @@ Subject: [PATCH 3/3] Side dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.format-patch_--stdout_initial..master b/t/t4013/diff.format-patch_--stdout_initial..master index 7b89978e32..a3dab7f773 100644 --- a/t/t4013/diff.format-patch_--stdout_initial..master +++ b/t/t4013/diff.format-patch_--stdout_initial..master @@ -53,7 +53,7 @@ Subject: [PATCH 2/3] Third --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) create mode 100644 file1 diff --git a/dir/sub b/dir/sub @@ -88,7 +88,7 @@ Subject: [PATCH 3/3] Side dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.format-patch_--stdout_initial..master^ b/t/t4013/diff.format-patch_--stdout_initial..master^ index b7f9725dc4..39f4a3f2d1 100644 --- a/t/t4013/diff.format-patch_--stdout_initial..master^ +++ b/t/t4013/diff.format-patch_--stdout_initial..master^ @@ -53,7 +53,7 @@ Subject: [PATCH 2/2] Third --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) create mode 100644 file1 diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.format-patch_--stdout_initial..side b/t/t4013/diff.format-patch_--stdout_initial..side index e765088475..88109209db 100644 --- a/t/t4013/diff.format-patch_--stdout_initial..side +++ b/t/t4013/diff.format-patch_--stdout_initial..side @@ -8,7 +8,7 @@ Subject: [PATCH] Side dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ b/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ index bd7f5c0f70..4085bbde87 100644 --- a/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ +++ b/t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_ @@ -13,7 +13,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- dir/sub | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) + 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub index 35d242b..7289e35 100644 @@ -32,7 +32,7 @@ Date: Mon Jun 26 00:02:00 2006 +0000 Third --- dir/sub | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) + 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub index 8422d40..cead32e 100644 @@ -54,7 +54,7 @@ Date: Mon Jun 26 00:01:00 2006 +0000 This is the second commit. --- dir/sub | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) + 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 diff --git a/t/t4013/diff.log_--patch-with-stat_master b/t/t4013/diff.log_--patch-with-stat_master index 14595a614c..458627953e 100644 --- a/t/t4013/diff.log_--patch-with-stat_master +++ b/t/t4013/diff.log_--patch-with-stat_master @@ -15,7 +15,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) diff --git a/dir/sub b/dir/sub index 35d242b..7289e35 100644 @@ -56,7 +56,7 @@ Date: Mon Jun 26 00:02:00 2006 +0000 --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) diff --git a/dir/sub b/dir/sub index 8422d40..cead32e 100644 diff --git a/t/t4013/diff.log_--patch-with-stat_master_--_dir_ b/t/t4013/diff.log_--patch-with-stat_master_--_dir_ index 5a4e72765d..6e172cfadd 100644 --- a/t/t4013/diff.log_--patch-with-stat_master_--_dir_ +++ b/t/t4013/diff.log_--patch-with-stat_master_--_dir_ @@ -13,7 +13,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- dir/sub | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) + 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub index 35d242b..7289e35 100644 @@ -32,7 +32,7 @@ Date: Mon Jun 26 00:02:00 2006 +0000 Third --- dir/sub | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) + 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub index 8422d40..cead32e 100644 @@ -54,7 +54,7 @@ Date: Mon Jun 26 00:01:00 2006 +0000 This is the second commit. --- dir/sub | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) + 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 diff --git a/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master index df0aaa9f2c..48b0d4b91d 100644 --- a/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master +++ b/t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master @@ -8,7 +8,7 @@ Date: Mon Jun 26 00:04:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) diff --cc dir/sub index cead32e,7289e35..992913c @@ -47,7 +47,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/dir/sub b/dir/sub @@ -89,7 +89,7 @@ Date: Mon Jun 26 00:02:00 2006 +0000 --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) create mode 100644 file1 diff --git a/dir/sub b/dir/sub @@ -165,7 +165,7 @@ Date: Mon Jun 26 00:00:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file2 | 3 +++ - 3 files changed, 8 insertions(+), 0 deletions(-) + 3 files changed, 8 insertions(+) create mode 100644 dir/sub create mode 100644 file0 create mode 100644 file2 diff --git a/t/t4013/diff.log_--root_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_--patch-with-stat_--summary_master index c11b5f2c7f..f9dc5122e2 100644 --- a/t/t4013/diff.log_--root_--patch-with-stat_--summary_master +++ b/t/t4013/diff.log_--root_--patch-with-stat_--summary_master @@ -15,7 +15,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/dir/sub b/dir/sub @@ -57,7 +57,7 @@ Date: Mon Jun 26 00:02:00 2006 +0000 --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) create mode 100644 file1 diff --git a/dir/sub b/dir/sub @@ -133,7 +133,7 @@ Date: Mon Jun 26 00:00:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file2 | 3 +++ - 3 files changed, 8 insertions(+), 0 deletions(-) + 3 files changed, 8 insertions(+) create mode 100644 dir/sub create mode 100644 file0 create mode 100644 file2 diff --git a/t/t4013/diff.log_--root_--patch-with-stat_master b/t/t4013/diff.log_--root_--patch-with-stat_master index 5f0c98f9ce..0807ece234 100644 --- a/t/t4013/diff.log_--root_--patch-with-stat_master +++ b/t/t4013/diff.log_--root_--patch-with-stat_master @@ -15,7 +15,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) diff --git a/dir/sub b/dir/sub index 35d242b..7289e35 100644 @@ -56,7 +56,7 @@ Date: Mon Jun 26 00:02:00 2006 +0000 --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) diff --git a/dir/sub b/dir/sub index 8422d40..cead32e 100644 @@ -130,7 +130,7 @@ Date: Mon Jun 26 00:00:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file2 | 3 +++ - 3 files changed, 8 insertions(+), 0 deletions(-) + 3 files changed, 8 insertions(+) diff --git a/dir/sub b/dir/sub new file mode 100644 diff --git a/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master index e62c368dc6..84f5ef6911 100644 --- a/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master +++ b/t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master @@ -8,7 +8,7 @@ Date: Mon Jun 26 00:04:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) diff --combined dir/sub index cead32e,7289e35..992913c @@ -47,7 +47,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/dir/sub b/dir/sub @@ -89,7 +89,7 @@ Date: Mon Jun 26 00:02:00 2006 +0000 --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) create mode 100644 file1 diff --git a/dir/sub b/dir/sub @@ -165,7 +165,7 @@ Date: Mon Jun 26 00:00:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file2 | 3 +++ - 3 files changed, 8 insertions(+), 0 deletions(-) + 3 files changed, 8 insertions(+) create mode 100644 dir/sub create mode 100644 file0 create mode 100644 file2 diff --git a/t/t4013/diff.show_--patch-with-stat_--summary_side b/t/t4013/diff.show_--patch-with-stat_--summary_side index 377f2b7b7a..e60384d24d 100644 --- a/t/t4013/diff.show_--patch-with-stat_--summary_side +++ b/t/t4013/diff.show_--patch-with-stat_--summary_side @@ -8,7 +8,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/dir/sub b/dir/sub diff --git a/t/t4013/diff.show_--patch-with-stat_side b/t/t4013/diff.show_--patch-with-stat_side index fb14c530d2..a3a3255fd3 100644 --- a/t/t4013/diff.show_--patch-with-stat_side +++ b/t/t4013/diff.show_--patch-with-stat_side @@ -8,7 +8,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) diff --git a/dir/sub b/dir/sub index 35d242b..7289e35 100644 diff --git a/t/t4013/diff.show_--stat_--summary_side b/t/t4013/diff.show_--stat_--summary_side index 5bd5977628..d16f464aca 100644 --- a/t/t4013/diff.show_--stat_--summary_side +++ b/t/t4013/diff.show_--stat_--summary_side @@ -8,6 +8,6 @@ Date: Mon Jun 26 00:03:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 $ diff --git a/t/t4013/diff.show_--stat_side b/t/t4013/diff.show_--stat_side index 3b22327e48..6300c0535f 100644 --- a/t/t4013/diff.show_--stat_side +++ b/t/t4013/diff.show_--stat_side @@ -8,5 +8,5 @@ Date: Mon Jun 26 00:03:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) $ diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ b/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ index 6a467cccc1..16ae54345f 100644 --- a/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ +++ b/t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_ @@ -6,7 +6,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- dir/sub | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) + 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub index 35d242b..7289e35 100644 @@ -25,7 +25,7 @@ Date: Mon Jun 26 00:02:00 2006 +0000 Third --- dir/sub | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) + 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub index 8422d40..cead32e 100644 @@ -47,7 +47,7 @@ Date: Mon Jun 26 00:01:00 2006 +0000 This is the second commit. --- dir/sub | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) + 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_master b/t/t4013/diff.whatchanged_--patch-with-stat_master index 1e1bbe1963..f3e45ec270 100644 --- a/t/t4013/diff.whatchanged_--patch-with-stat_master +++ b/t/t4013/diff.whatchanged_--patch-with-stat_master @@ -8,7 +8,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) diff --git a/dir/sub b/dir/sub index 35d242b..7289e35 100644 @@ -49,7 +49,7 @@ Date: Mon Jun 26 00:02:00 2006 +0000 --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) diff --git a/dir/sub b/dir/sub index 8422d40..cead32e 100644 diff --git a/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ b/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ index 13789f169b..c77f0bc320 100644 --- a/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ +++ b/t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_ @@ -6,7 +6,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 Side --- dir/sub | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) + 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub index 35d242b..7289e35 100644 @@ -25,7 +25,7 @@ Date: Mon Jun 26 00:02:00 2006 +0000 Third --- dir/sub | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) + 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub index 8422d40..cead32e 100644 @@ -47,7 +47,7 @@ Date: Mon Jun 26 00:01:00 2006 +0000 This is the second commit. --- dir/sub | 2 ++ - 1 files changed, 2 insertions(+), 0 deletions(-) + 1 file changed, 2 insertions(+) diff --git a/dir/sub b/dir/sub index 35d242b..8422d40 100644 diff --git a/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master index e96ff1fb8c..8d03efea6c 100644 --- a/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master +++ b/t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master @@ -8,7 +8,7 @@ Date: Mon Jun 26 00:04:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) diff --cc dir/sub index cead32e,7289e35..992913c @@ -47,7 +47,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/dir/sub b/dir/sub @@ -89,7 +89,7 @@ Date: Mon Jun 26 00:02:00 2006 +0000 --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) create mode 100644 file1 diff --git a/dir/sub b/dir/sub @@ -165,7 +165,7 @@ Date: Mon Jun 26 00:00:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file2 | 3 +++ - 3 files changed, 8 insertions(+), 0 deletions(-) + 3 files changed, 8 insertions(+) create mode 100644 dir/sub create mode 100644 file0 create mode 100644 file2 diff --git a/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master index 0291153587..1874d0616c 100644 --- a/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master +++ b/t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master @@ -8,7 +8,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/dir/sub b/dir/sub @@ -50,7 +50,7 @@ Date: Mon Jun 26 00:02:00 2006 +0000 --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) create mode 100644 file1 diff --git a/dir/sub b/dir/sub @@ -126,7 +126,7 @@ Date: Mon Jun 26 00:00:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file2 | 3 +++ - 3 files changed, 8 insertions(+), 0 deletions(-) + 3 files changed, 8 insertions(+) create mode 100644 dir/sub create mode 100644 file0 create mode 100644 file2 diff --git a/t/t4013/diff.whatchanged_--root_--patch-with-stat_master b/t/t4013/diff.whatchanged_--root_--patch-with-stat_master index 9b0349cd55..5211ff2a75 100644 --- a/t/t4013/diff.whatchanged_--root_--patch-with-stat_master +++ b/t/t4013/diff.whatchanged_--root_--patch-with-stat_master @@ -8,7 +8,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) diff --git a/dir/sub b/dir/sub index 35d242b..7289e35 100644 @@ -49,7 +49,7 @@ Date: Mon Jun 26 00:02:00 2006 +0000 --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) diff --git a/dir/sub b/dir/sub index 8422d40..cead32e 100644 @@ -123,7 +123,7 @@ Date: Mon Jun 26 00:00:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file2 | 3 +++ - 3 files changed, 8 insertions(+), 0 deletions(-) + 3 files changed, 8 insertions(+) diff --git a/dir/sub b/dir/sub new file mode 100644 diff --git a/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master index c0aff68ef6..ad30245a59 100644 --- a/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master +++ b/t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master @@ -8,7 +8,7 @@ Date: Mon Jun 26 00:04:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) diff --combined dir/sub index cead32e,7289e35..992913c @@ -47,7 +47,7 @@ Date: Mon Jun 26 00:03:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file3 | 4 ++++ - 3 files changed, 9 insertions(+), 0 deletions(-) + 3 files changed, 9 insertions(+) create mode 100644 file3 diff --git a/dir/sub b/dir/sub @@ -89,7 +89,7 @@ Date: Mon Jun 26 00:02:00 2006 +0000 --- dir/sub | 2 ++ file1 | 3 +++ - 2 files changed, 5 insertions(+), 0 deletions(-) + 2 files changed, 5 insertions(+) create mode 100644 file1 diff --git a/dir/sub b/dir/sub @@ -165,7 +165,7 @@ Date: Mon Jun 26 00:00:00 2006 +0000 dir/sub | 2 ++ file0 | 3 +++ file2 | 3 +++ - 3 files changed, 8 insertions(+), 0 deletions(-) + 3 files changed, 8 insertions(+) create mode 100644 dir/sub create mode 100644 file0 create mode 100644 file2 diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 67975129bc..7dfe716cf9 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -520,7 +520,7 @@ test_expect_success 'shortlog of cover-letter wraps overly-long onelines' ' cat > expect << EOF --- file | 16 ++++++++++++++++ - 1 files changed, 16 insertions(+), 0 deletions(-) + 1 file changed, 16 insertions(+) diff --git a/file b/file index 40f36c6..2dc5c23 100644 diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh index 88c5619ae7..4ac162cfcf 100755 --- a/t/t4030-diff-textconv.sh +++ b/t/t4030-diff-textconv.sh @@ -86,7 +86,7 @@ test_expect_success 'status -v produces text' ' cat >expect.stat <<'EOF' file | Bin 2 -> 4 bytes - 1 files changed, 0 insertions(+), 0 deletions(-) + 1 file changed, 0 insertions(+), 0 deletions(-) EOF test_expect_success 'diffstat does not run textconv' ' echo file diff=fail >.gitattributes && diff --git a/t/t4045-diff-relative.sh b/t/t4045-diff-relative.sh index 8a3c63b9e2..bd119be106 100755 --- a/t/t4045-diff-relative.sh +++ b/t/t4045-diff-relative.sh @@ -33,7 +33,7 @@ check_stat() { expect=$1; shift cat >expected <<EOF $expect | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) + 1 file changed, 1 insertion(+) EOF test_expect_success "--stat $*" " git diff --stat $* HEAD^ >actual && diff --git a/t/t4049-diff-stat-count.sh b/t/t4049-diff-stat-count.sh index 641e70d14d..a6d1887536 100755 --- a/t/t4049-diff-stat-count.sh +++ b/t/t4049-diff-stat-count.sh @@ -16,7 +16,7 @@ test_expect_success setup ' cat >expect <<-\EOF a | 1 + b | 1 + - 2 files changed, 2 insertions(+), 0 deletions(-) + 2 files changed, 2 insertions(+) EOF git diff --stat --stat-count=2 >actual && test_cmp expect actual diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh new file mode 100755 index 0000000000..328aa8f398 --- /dev/null +++ b/t/t4052-stat-output.sh @@ -0,0 +1,220 @@ +#!/bin/sh +# +# Copyright (c) 2012 Zbigniew Jędrzejewski-Szmek +# + +test_description='test --stat output of various commands' + +. ./test-lib.sh +. "$TEST_DIRECTORY"/lib-terminal.sh + +# 120 character name +name=aaaaaaaaaa +name=$name$name$name$name$name$name$name$name$name$name$name$name +test_expect_success 'preparation' ' + >"$name" && + git add "$name" && + git commit -m message && + echo a >"$name" && + git commit -m message "$name" +' + +while read cmd args +do + cat >expect <<-'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 + + EOF + test_expect_success "$cmd: small change with long name gives more space to the name" ' + git $cmd $args >output && + grep " | " output >actual && + test_cmp expect actual + ' + + cat >expect <<-'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaa | 1 + + EOF + test_expect_success "$cmd --stat=width: a long name is given more room when the bar is short" ' + git $cmd $args --stat=40 >output && + grep " | " output >actual && + test_cmp expect actual + ' + + test_expect_success "$cmd --stat-width=width with long name" ' + git $cmd $args --stat-width=40 >output && + grep " | " output >actual && + test_cmp expect actual + ' + + cat >expect <<-'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaa | 1 + + EOF + test_expect_success "$cmd --stat=...,name-width with long name" ' + git $cmd $args --stat=60,30 >output && + grep " | " output >actual && + test_cmp expect actual + ' + + test_expect_success "$cmd --stat-name-width with long name" ' + git $cmd $args --stat-name-width=30 >output && + grep " | " output >actual && + test_cmp expect actual + ' +done <<\EOF +format-patch -1 --stdout +diff HEAD^ HEAD --stat +show --stat +log -1 --stat +EOF + + +test_expect_success 'preparation for big change tests' ' + >abcd && + git add abcd && + git commit -m message && + i=0 && + while test $i -lt 1000 + do + echo $i && i=$(($i + 1)) + done >abcd && + git commit -m message abcd +' + +cat >expect80 <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF + +cat >expect200 <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF + +while read verb expect cmd args +do + test_expect_success "$cmd $verb COLUMNS (big change)" ' + COLUMNS=200 git $cmd $args >output + grep " | " output >actual && + test_cmp "$expect" actual + ' +done <<\EOF +ignores expect80 format-patch -1 --stdout +respects expect200 diff HEAD^ HEAD --stat +respects expect200 show --stat +respects expect200 log -1 --stat +EOF + +cat >expect40 <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++ +EOF + +while read verb expect cmd args +do + test_expect_success "$cmd $verb not enough COLUMNS (big change)" ' + COLUMNS=40 git $cmd $args >output + grep " | " output >actual && + test_cmp "$expect" actual + ' + + test_expect_success "$cmd $verb statGraphWidth config" ' + git -c diff.statGraphWidth=26 $cmd $args >output + grep " | " output >actual && + test_cmp "$expect" actual + ' +done <<\EOF +ignores expect80 format-patch -1 --stdout +respects expect40 diff HEAD^ HEAD --stat +respects expect40 show --stat +respects expect40 log -1 --stat +EOF + + +cat >expect <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++ +EOF +while read cmd args +do + test_expect_success "$cmd --stat=width with big change" ' + git $cmd $args --stat=40 >output + grep " | " output >actual && + test_cmp expect actual + ' + + test_expect_success "$cmd --stat-width=width with big change" ' + git $cmd $args --stat-width=40 >output + grep " | " output >actual && + test_cmp expect actual + ' + + test_expect_success "$cmd --stat-graph--width with big change" ' + git $cmd $args --stat-graph-width=26 >output + grep " | " output >actual && + test_cmp expect actual + ' +done <<\EOF +format-patch -1 --stdout +diff HEAD^ HEAD --stat +show --stat +log -1 --stat +EOF + +test_expect_success 'preparation for long filename tests' ' + cp abcd aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa && + git add aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa && + git commit -m message +' + +cat >expect <<'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++ +EOF +while read cmd args +do + test_expect_success "$cmd --stat=width with big change is more balanced" ' + git $cmd $args --stat-width=60 >output && + grep " | " output >actual && + test_cmp expect actual + ' +done <<\EOF +format-patch -1 --stdout +diff HEAD^ HEAD --stat +show --stat +log -1 --stat +EOF + +cat >expect80 <<'EOF' + ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 ++++++++++++++++++++ +EOF +cat >expect200 <<'EOF' + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF +while read verb expect cmd args +do + test_expect_success "$cmd $verb COLUMNS (long filename)" ' + COLUMNS=200 git $cmd $args >output + grep " | " output >actual && + test_cmp "$expect" actual + ' +done <<\EOF +ignores expect80 format-patch -1 --stdout +respects expect200 diff HEAD^ HEAD --stat +respects expect200 show --stat +respects expect200 log -1 --stat +EOF + +cat >expect <<'EOF' + abcd | 1000 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +EOF +test_expect_success 'merge --stat respects COLUMNS (big change)' ' + git checkout -b branch HEAD^^ && + COLUMNS=100 git merge --stat --no-ff master^ >output && + grep " | " output >actual + test_cmp expect actual +' + +cat >expect <<'EOF' + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 1000 +++++++++++++++++++++++++++++++++++++++ +EOF +test_expect_success 'merge --stat respects COLUMNS (long filename)' ' + COLUMNS=100 git merge --stat --no-ff master >output && + grep " | " output >actual + test_cmp expect actual +' + +test_done diff --git a/t/t4100/t-apply-8.expect b/t/t4100/t-apply-8.expect index eef7f2e65c..55a55c3cc7 100644 --- a/t/t4100/t-apply-8.expect +++ b/t/t4100/t-apply-8.expect @@ -1,2 +1,2 @@ t/t4100-apply-stat.sh | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) + 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t4100/t-apply-9.expect b/t/t4100/t-apply-9.expect index eef7f2e65c..55a55c3cc7 100644 --- a/t/t4100/t-apply-9.expect +++ b/t/t4100/t-apply-9.expect @@ -1,2 +1,2 @@ t/t4100-apply-stat.sh | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) + 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t4150-am.sh b/t/t4150-am.sh index 8807b602a5..ccc0280f52 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -123,6 +123,7 @@ test_expect_success setup ' git commit -m "added another file" && git format-patch --stdout master >lorem-move.patch && + git format-patch --no-prefix --stdout master >lorem-zero.patch && git checkout -b rename && git mv file renamed && @@ -136,7 +137,7 @@ test_expect_success setup ' git format-patch -M --stdout lorem^ >rename-add.patch && # reset time - unset test_tick && + sane_unset test_tick && test_tick ' @@ -286,6 +287,20 @@ test_expect_success 'am -3 falls back to 3-way merge' ' git diff --exit-code lorem ' +test_expect_success 'am -3 -p0 can read --no-prefix patch' ' + rm -fr .git/rebase-apply && + git reset --hard && + git checkout -b lorem3 master2 && + sed -n -e "3,\$p" msg >file && + head -n 9 msg >>file && + git add file && + test_tick && + git commit -m "copied stuff" && + git am -3 -p0 lorem-zero.patch && + ! test -d .git/rebase-apply && + git diff --exit-code lorem +' + test_expect_success 'am can rename a file' ' grep "^rename from" rename.patch && rm -fr .git/rebase-apply && @@ -505,4 +520,14 @@ test_expect_success 'am -q is quiet' ' ! test -s output.out ' +test_expect_success 'am empty-file does not infloop' ' + rm -fr .git/rebase-apply && + git reset --hard && + touch empty-file && + test_tick && + { git am empty-file > actual 2>&1 && false || :; } && + echo Patch format detection failed. >expected && + test_cmp expected actual +' + test_done diff --git a/t/t4209-log-pickaxe.sh b/t/t4209-log-pickaxe.sh new file mode 100755 index 0000000000..eed727341d --- /dev/null +++ b/t/t4209-log-pickaxe.sh @@ -0,0 +1,119 @@ +#!/bin/sh + +test_description='log --grep/--author/--regexp-ignore-case/-S/-G' +. ./test-lib.sh + +test_expect_success setup ' + >file && + git add file && + test_tick && + git commit -m initial && + + echo Picked >file && + test_tick && + git commit -a --author="Another Person <another@example.com>" -m second +' + +test_expect_success 'log --grep' ' + git log --grep=initial --format=%H >actual && + git rev-parse --verify HEAD^ >expect && + test_cmp expect actual +' + +test_expect_success 'log --grep --regexp-ignore-case' ' + git log --regexp-ignore-case --grep=InItial --format=%H >actual && + git rev-parse --verify HEAD^ >expect && + test_cmp expect actual +' + +test_expect_success 'log --grep -i' ' + git log -i --grep=InItial --format=%H >actual && + git rev-parse --verify HEAD^ >expect && + test_cmp expect actual +' + +test_expect_success 'log --author --regexp-ignore-case' ' + git log --regexp-ignore-case --author=person --format=%H >actual && + git rev-parse --verify HEAD >expect && + test_cmp expect actual +' + +test_expect_success 'log --author -i' ' + git log -i --author=person --format=%H >actual && + git rev-parse --verify HEAD >expect && + test_cmp expect actual +' + +test_expect_success 'log -G (nomatch)' ' + git log -Gpicked --format=%H >actual && + >expect && + test_cmp expect actual +' + +test_expect_success 'log -G (match)' ' + git log -GPicked --format=%H >actual && + git rev-parse --verify HEAD >expect && + test_cmp expect actual +' + +test_expect_success 'log -G --regexp-ignore-case (nomatch)' ' + git log --regexp-ignore-case -Gpickle --format=%H >actual && + >expect && + test_cmp expect actual +' + +test_expect_success 'log -G -i (nomatch)' ' + git log -i -Gpickle --format=%H >actual && + >expect && + test_cmp expect actual +' + +test_expect_success 'log -G --regexp-ignore-case (match)' ' + git log --regexp-ignore-case -Gpicked --format=%H >actual && + git rev-parse --verify HEAD >expect && + test_cmp expect actual +' + +test_expect_success 'log -G -i (match)' ' + git log -i -Gpicked --format=%H >actual && + git rev-parse --verify HEAD >expect && + test_cmp expect actual +' + +test_expect_success 'log -S (nomatch)' ' + git log -Spicked --format=%H >actual && + >expect && + test_cmp expect actual +' + +test_expect_success 'log -S (match)' ' + git log -SPicked --format=%H >actual && + git rev-parse --verify HEAD >expect && + test_cmp expect actual +' + +test_expect_success 'log -S --regexp-ignore-case (match)' ' + git log --regexp-ignore-case -Spicked --format=%H >actual && + git rev-parse --verify HEAD >expect && + test_cmp expect actual +' + +test_expect_success 'log -S -i (match)' ' + git log -i -Spicked --format=%H >actual && + git rev-parse --verify HEAD >expect && + test_cmp expect actual +' + +test_expect_success 'log -S --regexp-ignore-case (nomatch)' ' + git log --regexp-ignore-case -Spickle --format=%H >actual && + >expect && + test_cmp expect actual +' + +test_expect_success 'log -S -i (nomatch)' ' + git log -i -Spickle --format=%H >actual && + >expect && + test_cmp expect actual +' + +test_done diff --git a/t/t5150-request-pull.sh b/t/t5150-request-pull.sh index 7c1dc641de..2af8947eeb 100755 --- a/t/t5150-request-pull.sh +++ b/t/t5150-request-pull.sh @@ -95,7 +95,7 @@ test_expect_success 'setup: two scripts for reading pull requests' ' b : diffstat n - / [0-9]* files changed/ { + / [0-9]* files* changed/ { a\\ DIFFSTAT b diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index 602806d09c..d9d856b87b 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -38,6 +38,10 @@ test_expect_success \ 'pack without delta' \ 'packname_1=$(git pack-objects --window=0 test-1 <obj-list)' +test_expect_success \ + 'pack-objects with bogus arguments' \ + 'test_must_fail git pack-objects --window=0 test-1 blah blah <obj-list' + rm -fr .git2 mkdir .git2 diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index f8fa92446c..fe82025d4a 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -74,6 +74,10 @@ test_expect_success 'index-pack --verify on index version 2' ' ' test_expect_success \ + 'pack-objects --index-version=2, is not accepted' \ + 'test_must_fail git pack-objects --index-version=2, test-3 <obj-list' + +test_expect_success \ 'index v2: force some 64-bit offsets with pack-objects' \ 'pack3=$(git pack-objects --index-version=2,0x40000 test-3 <obj-list)' diff --git a/t/t5504-fetch-receive-strict.sh b/t/t5504-fetch-receive-strict.sh index 8341fc4d15..35ec294d9a 100755 --- a/t/t5504-fetch-receive-strict.sh +++ b/t/t5504-fetch-receive-strict.sh @@ -58,6 +58,11 @@ test_expect_success 'fetch with transfer.fsckobjects' ' ) ' +cat >exp <<EOF +To dst +! refs/heads/master:refs/heads/test [remote rejected] (missing necessary objects) +EOF + test_expect_success 'push without strict' ' rm -rf dst && git init dst && @@ -66,7 +71,8 @@ test_expect_success 'push without strict' ' git config fetch.fsckobjects false && git config transfer.fsckobjects false ) && - git push dst master:refs/heads/test + test_must_fail git push --porcelain dst master:refs/heads/test >act && + test_cmp exp act ' test_expect_success 'push with !receive.fsckobjects' ' @@ -77,9 +83,15 @@ test_expect_success 'push with !receive.fsckobjects' ' git config receive.fsckobjects false && git config transfer.fsckobjects true ) && - git push dst master:refs/heads/test + test_must_fail git push --porcelain dst master:refs/heads/test >act && + test_cmp exp act ' +cat >exp <<EOF +To dst +! refs/heads/master:refs/heads/test [remote rejected] (n/a (unpacker error)) +EOF + test_expect_success 'push with receive.fsckobjects' ' rm -rf dst && git init dst && @@ -88,7 +100,8 @@ test_expect_success 'push with receive.fsckobjects' ' git config receive.fsckobjects true && git config transfer.fsckobjects false ) && - test_must_fail git push dst master:refs/heads/test + test_must_fail git push --porcelain dst master:refs/heads/test >act && + test_cmp exp act ' test_expect_success 'push with transfer.fsckobjects' ' @@ -98,7 +111,8 @@ test_expect_success 'push with transfer.fsckobjects' ' cd dst && git config transfer.fsckobjects true ) && - test_must_fail git push dst master:refs/heads/test + test_must_fail git push --porcelain dst master:refs/heads/test >act && + test_cmp exp act ' test_done diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 79ee913130..308c02ea75 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -14,6 +14,14 @@ test_bundle_object_count () { test "$2" = $(grep '^[0-9a-f]\{40\} ' verify.out | wc -l) } +convert_bundle_to_pack () { + while read x && test -n "$x" + do + :; + done + cat +} + test_expect_success setup ' echo >file original && git add file && @@ -206,13 +214,7 @@ test_expect_success 'unbundle 1' ' test_expect_success 'bundle 1 has only 3 files ' ' cd "$D" && - ( - while read x && test -n "$x" - do - :; - done - cat - ) <bundle1 >bundle.pack && + convert_bundle_to_pack <bundle1 >bundle.pack && git index-pack bundle.pack && test_bundle_object_count bundle.pack 3 ' @@ -229,13 +231,7 @@ test_expect_success 'bundle does not prerequisite objects' ' git add file2 && git commit -m add.file2 file2 && git bundle create bundle3 -1 HEAD && - ( - while read x && test -n "$x" - do - :; - done - cat - ) <bundle3 >bundle.pack && + convert_bundle_to_pack <bundle3 >bundle.pack && git index-pack bundle.pack && test_bundle_object_count bundle.pack 3 ' @@ -433,14 +429,31 @@ test_expect_success 'fetch --dry-run' ' ' test_expect_success "should be able to fetch with duplicate refspecs" ' - mkdir dups && - cd dups && - git init && - git config branch.master.remote three && - git config remote.three.url ../three/.git && - git config remote.three.fetch +refs/heads/*:refs/remotes/origin/* && - git config --add remote.three.fetch +refs/heads/*:refs/remotes/origin/* && - git fetch three + mkdir dups && + ( + cd dups && + git init && + git config branch.master.remote three && + git config remote.three.url ../three/.git && + git config remote.three.fetch +refs/heads/*:refs/remotes/origin/* && + git config --add remote.three.fetch +refs/heads/*:refs/remotes/origin/* && + git fetch three + ) +' + +test_expect_success 'all boundary commits are excluded' ' + test_commit base && + test_commit oneside && + git checkout HEAD^ && + test_commit otherside && + git checkout master && + test_tick && + git merge otherside && + ad=$(git log --no-walk --format=%ad HEAD) && + git bundle create twoside-boundary.bdl master --since="$ad" && + convert_bundle_to_pack <twoside-boundary.bdl >twoside-boundary.pack && + pack=$(git index-pack --fix-thin --stdin <twoside-boundary.pack) && + test_bundle_object_count .git/objects/pack/pack-${pack##pack }.pack 3 ' test_done diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh index 5c546c99a5..6764d511ce 100755 --- a/t/t5512-ls-remote.sh +++ b/t/t5512-ls-remote.sh @@ -5,7 +5,6 @@ test_description='git ls-remote' . ./test-lib.sh test_expect_success setup ' - >file && git add file && test_tick && @@ -18,45 +17,33 @@ test_expect_success setup ' ) >expected.all && git remote add self "$(pwd)/.git" - ' test_expect_success 'ls-remote --tags .git' ' - git ls-remote --tags .git >actual && test_cmp expected.tag actual - ' test_expect_success 'ls-remote .git' ' - git ls-remote .git >actual && test_cmp expected.all actual - ' test_expect_success 'ls-remote --tags self' ' - git ls-remote --tags self >actual && test_cmp expected.tag actual - ' test_expect_success 'ls-remote self' ' - git ls-remote self >actual && test_cmp expected.all actual - ' test_expect_success 'dies when no remote specified and no default remotes found' ' - test_must_fail git ls-remote - ' test_expect_success 'use "origin" when no remote specified' ' - URL="$(pwd)/.git" && echo "From $URL" >exp_err && @@ -65,18 +52,14 @@ test_expect_success 'use "origin" when no remote specified' ' test_cmp exp_err actual_err && test_cmp expected.all actual - ' test_expect_success 'suppress "From <url>" with -q' ' - git ls-remote -q 2>actual_err && test_must_fail test_cmp exp_err actual_err - ' test_expect_success 'use branch.<name>.remote if possible' ' - # # Test that we are indeed using branch.<name>.remote, not "origin", even # though the "origin" remote has been set. @@ -99,14 +82,13 @@ test_expect_success 'use branch.<name>.remote if possible' ' git ls-remote 2>actual_err >actual && test_cmp exp_err actual_err && test_cmp exp actual - ' -cat >exp <<EOF -fatal: 'refs*master' does not appear to be a git repository -fatal: The remote end hung up unexpectedly -EOF test_expect_success 'confuses pattern as remote when no remote specified' ' + cat >exp <<-\EOF && + fatal: '\''refs*master'\'' does not appear to be a git repository + fatal: The remote end hung up unexpectedly + EOF # # Do not expect "git ls-remote <pattern>" to work; ls-remote, correctly, # confuses <pattern> for <remote>. Although ugly, this behaviour is akin @@ -120,7 +102,6 @@ test_expect_success 'confuses pattern as remote when no remote specified' ' # role as a pattern. test_must_fail git ls-remote refs*master >actual 2>&1 && test_cmp exp actual - ' test_expect_success 'die with non-2 for wrong repository even with --exit-code' ' diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index b69cf574d7..b5417cc951 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -979,4 +979,20 @@ test_expect_success 'push --porcelain --dry-run rejected' ' test_cmp .git/foo .git/bar ' +test_expect_success 'push --prune' ' + mk_test heads/master heads/second heads/foo heads/bar && + git push --prune testrepo && + check_push_result $the_commit heads/master && + check_push_result $the_first_commit heads/second && + ! check_push_result $the_first_commit heads/foo heads/bar +' + +test_expect_success 'push --prune refspec' ' + mk_test tmp/master tmp/second tmp/foo tmp/bar && + git push --prune testrepo "refs/heads/*:refs/tmp/*" && + check_push_result $the_commit tmp/master && + check_push_result $the_first_commit tmp/second && + ! check_push_result $the_first_commit tmp/foo tmp/bar +' + test_done diff --git a/t/t5523-push-upstream.sh b/t/t5523-push-upstream.sh index 9ee52cfc45..3683df13a6 100755 --- a/t/t5523-push-upstream.sh +++ b/t/t5523-push-upstream.sh @@ -101,10 +101,11 @@ test_expect_success TTY 'push -q suppresses progress' ' ! grep "Writing objects" err ' -test_expect_failure TTY 'push --no-progress suppresses progress' ' +test_expect_success TTY 'push --no-progress suppresses progress' ' ensure_fresh_upstream && test_terminal git push -u --no-progress upstream master >out 2>err && + ! grep "Unpacking objects" err && ! grep "Writing objects" err ' diff --git a/t/t5541-http-push.sh b/t/t5541-http-push.sh index d66ed24508..cc6f081711 100755 --- a/t/t5541-http-push.sh +++ b/t/t5541-http-push.sh @@ -106,7 +106,7 @@ cat >exp <<EOF remote: error: hook declined to update refs/heads/dev2 To http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git ! [remote rejected] dev2 -> dev2 (hook declined) -error: failed to push some refs to 'http://127.0.0.1:5541/smart/test_repo.git' +error: failed to push some refs to 'http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git' EOF test_expect_success 'rejected update prints status' ' diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh index 0ad7ce07c4..ef98d95e00 100755 --- a/t/t5560-http-backend-noserver.sh +++ b/t/t5560-http-backend-noserver.sh @@ -17,7 +17,7 @@ run_backend() { GET() { REQUEST_METHOD="GET" && export REQUEST_METHOD && run_backend "/repo.git/$1" && - unset REQUEST_METHOD && + sane_unset REQUEST_METHOD && if ! grep "Status" act.out >act then printf "Status: 200 OK\r\n" >act @@ -30,8 +30,8 @@ POST() { REQUEST_METHOD="POST" && export REQUEST_METHOD && CONTENT_TYPE="application/x-$1-request" && export CONTENT_TYPE && run_backend "/repo.git/$1" "$2" && - unset REQUEST_METHOD && - unset CONTENT_TYPE && + sane_unset REQUEST_METHOD && + sane_unset CONTENT_TYPE && if ! grep "Status" act.out >act then printf "Status: 200 OK\r\n" >act diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh index c4c375ac04..bbc4691bd7 100755 --- a/t/t5700-clone-reference.sh +++ b/t/t5700-clone-reference.sh @@ -52,13 +52,13 @@ test_cmp expected current' cd "$base_dir" -rm -f "$U" +rm -f "$U.D" test_expect_success 'cloning with reference (no -l -s)' \ -'GIT_DEBUG_SEND_PACK=3 git clone --reference B "file://$(pwd)/A" D 3>"$U"' +'GIT_DEBUG_SEND_PACK=3 git clone --reference B "file://$(pwd)/A" D 3>"$U.D"' test_expect_success 'fetched no objects' \ -'! grep "^want" "$U"' +'! grep "^want" "$U.D"' cd "$base_dir" @@ -153,4 +153,32 @@ test_expect_success 'clone with reference from a tagged repository' ' git clone --reference=A A I ' +test_expect_success 'prepare branched repository' ' + git clone A J && + ( + cd J && + git checkout -b other master^ && + echo other >otherfile && + git add otherfile && + git commit -m other && + git checkout master + ) +' + +rm -f "$U.K" + +test_expect_success 'fetch with incomplete alternates' ' + git init K && + echo "$base_dir/A/.git/objects" >K/.git/objects/info/alternates && + ( + cd K && + git remote add J "file://$base_dir/J" && + GIT_DEBUG_SEND_PACK=3 git fetch J 3>"$U.K" + ) && + master_object=$(cd A && git for-each-ref --format="%(objectname)" refs/heads/master) && + ! grep "^want $master_object" "$U.K" && + tag_object=$(cd A && git for-each-ref --format="%(objectname)" refs/tags/HEAD) && + ! grep "^want $tag_object" "$U.K" +' + test_done diff --git a/t/t5704-bundle.sh b/t/t5704-bundle.sh index 4ae127d106..9e43731fe5 100755 --- a/t/t5704-bundle.sh +++ b/t/t5704-bundle.sh @@ -4,59 +4,58 @@ test_description='some bundle related tests' . ./test-lib.sh test_expect_success 'setup' ' - - : > file && - git add file && - test_tick && - git commit -m initial && + test_commit initial && test_tick && git tag -m tag tag && - : > file2 && - git add file2 && - : > file3 && - test_tick && - git commit -m second && - git add file3 && - test_tick && - git commit -m third - + test_commit second && + test_commit third && + git tag -d initial && + git tag -d second && + git tag -d third ' test_expect_success 'tags can be excluded by rev-list options' ' - git bundle create bundle --all --since=7.Apr.2005.15:16:00.-0700 && git ls-remote bundle > output && ! grep tag output - ' test_expect_success 'die if bundle file cannot be created' ' - mkdir adir && test_must_fail git bundle create adir --all - ' test_expect_failure 'bundle --stdin' ' - echo master | git bundle create stdin-bundle.bdl --stdin && git ls-remote stdin-bundle.bdl >output && grep master output - ' test_expect_failure 'bundle --stdin <rev-list options>' ' - echo master | git bundle create hybrid-bundle.bdl --stdin tag && git ls-remote hybrid-bundle.bdl >output && grep master output - ' test_expect_success 'empty bundle file is rejected' ' + : >empty-bundle && + test_must_fail git fetch empty-bundle +' - >empty-bundle && test_must_fail git fetch empty-bundle - +# This triggers a bug in older versions where the resulting line (with +# --pretty=oneline) was longer than a 1024-char buffer. +test_expect_success 'ridiculously long subject in boundary' ' + : >file4 && + test_tick && + git add file4 && + printf "%01200d\n" 0 | git commit -F - && + test_commit fifth && + git bundle create long-subject-bundle.bdl HEAD^..HEAD && + git bundle list-heads long-subject-bundle.bdl >heads && + test -s heads && + git fetch long-subject-bundle.bdl && + sed -n "/^-/{p;q;}" long-subject-bundle.bdl >boundary && + grep "^-[0-9a-f]\\{40\\} " boundary ' test_done diff --git a/t/t5900-repo-selection.sh b/t/t5900-repo-selection.sh new file mode 100755 index 0000000000..3d5b418bb4 --- /dev/null +++ b/t/t5900-repo-selection.sh @@ -0,0 +1,100 @@ +#!/bin/sh + +test_description='selecting remote repo in ambiguous cases' +. ./test-lib.sh + +reset() { + rm -rf foo foo.git fetch clone +} + +make_tree() { + git init "$1" && + (cd "$1" && test_commit "$1") +} + +make_bare() { + git init --bare "$1" && + (cd "$1" && + tree=`git hash-object -w -t tree /dev/null` && + commit=$(echo "$1" | git commit-tree $tree) && + git update-ref HEAD $commit + ) +} + +get() { + git init --bare fetch && + (cd fetch && git fetch "../$1") && + git clone "$1" clone +} + +check() { + echo "$1" >expect && + (cd fetch && git log -1 --format=%s FETCH_HEAD) >actual.fetch && + (cd clone && git log -1 --format=%s HEAD) >actual.clone && + test_cmp expect actual.fetch && + test_cmp expect actual.clone +} + +test_expect_success 'find .git dir in worktree' ' + reset && + make_tree foo && + get foo && + check foo +' + +test_expect_success 'automagically add .git suffix' ' + reset && + make_bare foo.git && + get foo && + check foo.git +' + +test_expect_success 'automagically add .git suffix to worktree' ' + reset && + make_tree foo.git && + get foo && + check foo.git +' + +test_expect_success 'prefer worktree foo over bare foo.git' ' + reset && + make_tree foo && + make_bare foo.git && + get foo && + check foo +' + +test_expect_success 'prefer bare foo over bare foo.git' ' + reset && + make_bare foo && + make_bare foo.git && + get foo && + check foo +' + +test_expect_success 'disambiguate with full foo.git' ' + reset && + make_bare foo && + make_bare foo.git && + get foo.git && + check foo.git +' + +test_expect_success 'we are not fooled by non-git foo directory' ' + reset && + make_bare foo.git && + mkdir foo && + get foo && + check foo.git +' + +test_expect_success 'prefer inner .git over outer bare' ' + reset && + make_tree foo && + make_bare foo.git && + mv foo/.git foo.git && + get foo.git && + check foo +' + +test_done diff --git a/t/t6032-merge-large-rename.sh b/t/t6032-merge-large-rename.sh index fdb6c25371..94f010be8a 100755 --- a/t/t6032-merge-large-rename.sh +++ b/t/t6032-merge-large-rename.sh @@ -95,7 +95,7 @@ test_expect_success 'setup large simple rename' ' ' test_expect_success 'massive simple rename does not spam added files' ' - unset GIT_MERGE_VERBOSITY && + sane_unset GIT_MERGE_VERBOSITY && git merge --no-stat simple-rename | grep -v Removing >output && test 5 -gt "$(wc -l < output)" ' diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 4ef79aabc4..f8c247a750 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -1282,4 +1282,43 @@ test_expect_success 'mixing incompatibles modes and options is forbidden' ' test_must_fail git tag -v -s ' +# check points-at + +test_expect_success '--points-at cannot be used in non-list mode' ' + test_must_fail git tag --points-at=v4.0 foo +' + +test_expect_success '--points-at finds lightweight tags' ' + echo v4.0 >expect && + git tag --points-at v4.0 >actual && + test_cmp expect actual +' + +test_expect_success '--points-at finds annotated tags of commits' ' + git tag -m "v4.0, annotated" annotated-v4.0 v4.0 && + echo annotated-v4.0 >expect && + git tag -l --points-at v4.0 "annotated*" >actual && + test_cmp expect actual +' + +test_expect_success '--points-at finds annotated tags of tags' ' + git tag -m "describing the v4.0 tag object" \ + annotated-again-v4.0 annotated-v4.0 && + cat >expect <<-\EOF && + annotated-again-v4.0 + annotated-v4.0 + EOF + git tag --points-at=annotated-v4.0 >actual && + test_cmp expect actual +' + +test_expect_success 'multiple --points-at are OR-ed together' ' + cat >expect <<-\EOF && + v2.0 + v3.0 + EOF + git tag --points-at=v2.0 --points-at=v3.0 >actual && + test_cmp expect actual +' + test_done diff --git a/t/t7008-grep-binary.sh b/t/t7008-grep-binary.sh index 917a264eea..fd6410fc71 100755 --- a/t/t7008-grep-binary.sh +++ b/t/t7008-grep-binary.sh @@ -99,4 +99,28 @@ test_expect_success 'git grep y<NUL>x a' " test_must_fail git grep -f f a " +test_expect_success 'grep respects binary diff attribute' ' + echo text >t && + git add t && + echo t:text >expect && + git grep text t >actual && + test_cmp expect actual && + echo "t -diff" >.gitattributes && + echo "Binary file t matches" >expect && + git grep text t >actual && + test_cmp expect actual +' + +test_expect_success 'grep respects not-binary diff attribute' ' + echo binQary | q_to_nul >b && + git add b && + echo "Binary file b matches" >expect && + git grep bin b >actual && + test_cmp expect actual && + echo "b diff" >.gitattributes && + echo "b:binQary" >expect && + git grep bin b | nul_to_q >actual && + test_cmp expect actual +' + test_done diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 695f7afdf3..b377a7af28 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -79,6 +79,15 @@ test_expect_success 'submodule add' ' cd addtest && git submodule add -q "$submodurl" submod >actual && test ! -s actual && + echo "gitdir: ../.git/modules/submod" >expect && + test_cmp expect submod/.git && + ( + cd submod && + git config core.worktree >actual && + echo "../../../submod" >expect && + test_cmp expect actual && + rm -f actual expect + ) && git submodule init ) && @@ -498,4 +507,17 @@ test_expect_success 'relative path works with user@host:path' ' ) ' +test_expect_success 'moving the superproject does not break submodules' ' + ( + cd addtest && + git submodule status >expect + ) + mv addtest addtest2 && + ( + cd addtest2 && + git submodule status >actual && + test_cmp expect actual + ) +' + test_done diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh index 5b97222c48..dcb195b4cf 100755 --- a/t/t7406-submodule-update.sh +++ b/t/t7406-submodule-update.sh @@ -619,4 +619,21 @@ test_expect_success 'submodule add properly re-creates deeper level submodules' ) ' +test_expect_success 'submodule update properly revives a moved submodule' ' + (cd super && + git commit -am "pre move" && + git status >expect&& + H=$(cd submodule2; git rev-parse HEAD) && + git rm --cached submodule2 && + rm -rf submodule2 && + mkdir -p "moved/sub module" && + git update-index --add --cacheinfo 160000 $H "moved/sub module" && + git config -f .gitmodules submodule.submodule2.path "moved/sub module" + git commit -am "post move" && + git submodule update && + git status >actual && + test_cmp expect actual + ) +' + test_done diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index 61f36baa1f..5783ebf3ab 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -57,7 +57,7 @@ Merge made by the 'octopus' strategy. c2.c | 1 + c3.c | 1 + c4.c | 1 + - 3 files changed, 3 insertions(+), 0 deletions(-) + 3 files changed, 3 insertions(+) create mode 100644 c2.c create mode 100644 c3.c create mode 100644 c4.c @@ -74,7 +74,7 @@ Already up-to-date with c4 Trying simple merge with c5 Merge made by the 'octopus' strategy. c5.c | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) + 1 file changed, 1 insertion(+) create mode 100644 c5.c EOF @@ -89,7 +89,7 @@ Trying simple merge with c2 Merge made by the 'octopus' strategy. c1.c | 1 + c2.c | 1 + - 2 files changed, 2 insertions(+), 0 deletions(-) + 2 files changed, 2 insertions(+) create mode 100644 c1.c create mode 100644 c2.c EOF diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index 75f4716d8c..d9ad633310 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -47,6 +47,13 @@ test_expect_success setup ' echo vvv >t/v && mkdir t/a && echo vvv >t/a/v && + { + echo "line without leading space1" + echo " line with leading space1" + echo " line with leading space2" + echo " line with leading space3" + echo "line without leading space2" + } >space && git add . && test_tick && git commit -m initial @@ -893,4 +900,20 @@ test_expect_success 'mimic ack-grep --group' ' test_cmp expected actual ' +cat >expected <<EOF +space: line with leading space1 +space: line with leading space2 +space: line with leading space3 +EOF + +test_expect_success LIBPCRE 'grep -E "^ "' ' + git grep -E "^ " space >actual && + test_cmp expected actual +' + +test_expect_success LIBPCRE 'grep -P "^ "' ' + git grep -P "^ " space >actual && + test_cmp expected actual +' + test_done diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh index b041516a1d..749b75e8d4 100755 --- a/t/t9100-git-svn-basic.sh +++ b/t/t9100-git-svn-basic.sh @@ -65,7 +65,8 @@ test_expect_success "$name" " git update-index --add dir/file/file && git commit -m '$name' && test_must_fail git svn set-tree --find-copies-harder --rmdir \ - ${remotes_git_svn}..mybranch" || true + ${remotes_git_svn}..mybranch +" name='detect node change from directory to file #1' @@ -79,7 +80,8 @@ test_expect_success "$name" ' git update-index --add -- bar && git commit -m "$name" && test_must_fail git svn set-tree --find-copies-harder --rmdir \ - ${remotes_git_svn}..mybranch2' || true + ${remotes_git_svn}..mybranch2 +' name='detect node change from file to directory #2' @@ -92,9 +94,12 @@ test_expect_success "$name" ' echo yyy > bar/zzz/yyy && git update-index --add bar/zzz/yyy && git commit -m "$name" && - test_must_fail git svn set-tree --find-copies-harder --rmdir \ - ${remotes_git_svn}..mybranch3' || true - + git svn set-tree --find-copies-harder --rmdir \ + ${remotes_git_svn}..mybranch3 && + svn_cmd up "$SVN_TREE" && + test -d "$SVN_TREE"/bar/zzz && + test -e "$SVN_TREE"/bar/zzz/yyy +' name='detect node change from directory to file #2' test_expect_success "$name" ' @@ -107,7 +112,8 @@ test_expect_success "$name" ' git update-index --add -- dir && git commit -m "$name" && test_must_fail git svn set-tree --find-copies-harder --rmdir \ - ${remotes_git_svn}..mybranch4' || true + ${remotes_git_svn}..mybranch4 +' name='remove executable bit from a file' @@ -134,10 +140,10 @@ test_expect_success "$name" ' test -x "$SVN_TREE"/exec.sh' -name='executable file becomes a symlink to bar/zzz (file)' +name='executable file becomes a symlink to file' test_expect_success "$name" ' rm exec.sh && - ln -s bar/zzz exec.sh && + ln -s file exec.sh && git update-index exec.sh && git commit -m "$name" && git svn set-tree --find-copies-harder --rmdir \ @@ -148,19 +154,19 @@ test_expect_success "$name" ' name='new symlink is added to a file that was also just made executable' test_expect_success "$name" ' - chmod +x bar/zzz && - ln -s bar/zzz exec-2.sh && - git update-index --add bar/zzz exec-2.sh && + chmod +x file && + ln -s file exec-2.sh && + git update-index --add file exec-2.sh && git commit -m "$name" && git svn set-tree --find-copies-harder --rmdir \ ${remotes_git_svn}..mybranch5 && svn_cmd up "$SVN_TREE" && - test -x "$SVN_TREE"/bar/zzz && + test -x "$SVN_TREE"/file && test -h "$SVN_TREE"/exec-2.sh' name='modify a symlink to become a file' test_expect_success "$name" ' - echo git help > help || true && + echo git help >help && rm exec-2.sh && cp help exec-2.sh && git update-index exec-2.sh && @@ -195,14 +201,15 @@ name='check imported tree checksums expected tree checksums' rm -f expected if test_have_prereq UTF8 then - echo tree bf522353586b1b883488f2bc73dab0d9f774b9a9 > expected + echo tree dc68b14b733e4ec85b04ab6f712340edc5dc936e > expected fi cat >> expected <<\EOF -tree 83654bb36f019ae4fe77a0171f81075972087624 -tree 031b8d557afc6fea52894eaebb45bec52f1ba6d1 -tree 0b094cbff17168f24c302e297f55bfac65eb8bd3 -tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e -tree 56a30b966619b863674f5978696f4a3594f2fca9 +tree c3322890dcf74901f32d216f05c5044f670ce632 +tree d3ccd5035feafd17b030c5732e7808cc49122853 +tree d03e1630363d4881e68929d532746b20b0986b83 +tree 149d63cd5878155c846e8c55d7d8487de283f89e +tree 312b76e4f64ce14893aeac8591eb3960b065e247 +tree 149d63cd5878155c846e8c55d7d8487de283f89e tree d667270a1f7b109f5eb3aaea21ede14b56bfdd6e tree 8f51f74cf0163afc9ad68a4b1537288c4558b5a4 EOF diff --git a/t/t9130-git-svn-authors-file.sh b/t/t9130-git-svn-authors-file.sh index b324c491c5..c3443ceb25 100755 --- a/t/t9130-git-svn-authors-file.sh +++ b/t/t9130-git-svn-authors-file.sh @@ -96,8 +96,8 @@ test_expect_success 'fresh clone with svn.authors-file in config' ' rm -r "$GIT_DIR" && test x = x"$(git config svn.authorsfile)" && test_config="$HOME"/.gitconfig && - unset GIT_DIR && - unset GIT_CONFIG && + sane_unset GIT_DIR && + sane_unset GIT_CONFIG && git config --global \ svn.authorsfile "$HOME"/svn-authors && test x"$HOME"/svn-authors = x"$(git config svn.authorsfile)" && diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index 518358aa64..b59be9a894 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -321,7 +321,7 @@ test_expect_success 'use the same checkout for Git and CVS' ' (mkdir shared && cd shared && - unset GIT_DIR && + sane_unset GIT_DIR && cvs co . && git init && git add " space" && diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 438aaf6b14..0f5b5e5964 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -1307,6 +1307,45 @@ test_expect_success \ INPUT_END' test_expect_success \ + 'N: reject foo/ syntax in copy source' \ + 'test_must_fail git fast-import <<-INPUT_END + commit refs/heads/N5C + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + copy with invalid syntax + COMMIT + + from refs/heads/branch^0 + C file2/ file3 + INPUT_END' + +test_expect_success \ + 'N: reject foo/ syntax in rename source' \ + 'test_must_fail git fast-import <<-INPUT_END + commit refs/heads/N5D + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + rename with invalid syntax + COMMIT + + from refs/heads/branch^0 + R file2/ file3 + INPUT_END' + +test_expect_success \ + 'N: reject foo/ syntax in ls argument' \ + 'test_must_fail git fast-import <<-INPUT_END + commit refs/heads/N5E + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + copy with invalid syntax + COMMIT + + from refs/heads/branch^0 + ls "file2/" + INPUT_END' + +test_expect_success \ 'N: copy to root by id and modify' \ 'echo "hello, world" >expect.foo && echo hello >expect.bar && diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index 0f771c673d..90bb6050c1 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -638,6 +638,45 @@ test_expect_success \ 'gitweb_run "p=.git;a=tree"' # ---------------------------------------------------------------------- +# searching + +cat >>gitweb_config.perl <<\EOF + +# enable search +$feature{'search'}{'default'} = [1]; +$feature{'grep'}{'default'} = [1]; +$feature{'pickaxe'}{'default'} = [1]; +EOF + +test_expect_success \ + 'search: preparation' \ + 'echo "1st MATCH" >>file && + echo "2nd MATCH" >>file && + echo "MATCH" >>bar && + git add file bar && + git commit -m "Added MATCH word"' + +test_expect_success \ + 'search: commit author' \ + 'gitweb_run "p=.git;a=search;h=HEAD;st=author;s=A+U+Thor"' + +test_expect_success \ + 'search: commit message' \ + 'gitweb_run "p=.git;a=search;h=HEAD;st=commitr;s=MATCH"' + +test_expect_success \ + 'search: grep' \ + 'gitweb_run "p=.git;a=search;h=HEAD;st=grep;s=MATCH"' + +test_expect_success \ + 'search: pickaxe' \ + 'gitweb_run "p=.git;a=search;h=HEAD;st=pickaxe;s=MATCH"' + +test_expect_success \ + 'search: projects' \ + 'gitweb_run "a=project_list;s=.git"' + +# ---------------------------------------------------------------------- # non-ASCII in README.html test_expect_success \ @@ -739,4 +778,13 @@ test_expect_success \ 'echo "\$projects_list_group_categories = 1;" >>gitweb_config.perl && gitweb_run' +# ---------------------------------------------------------------------- +# unborn branches + +test_expect_success \ + 'unborn HEAD: "summary" page (with "heads" subview)' \ + 'git checkout orphan_branch || git checkout --orphan orphan_branch && + test_when_finished "git checkout master" && + gitweb_run "p=.git;a=summary"' + test_done diff --git a/t/t9501-gitweb-standalone-http-status.sh b/t/t9501-gitweb-standalone-http-status.sh index 26102ee9b0..31076edc5b 100755 --- a/t/t9501-gitweb-standalone-http-status.sh +++ b/t/t9501-gitweb-standalone-http-status.sh @@ -134,4 +134,14 @@ our $maxload = undef; EOF +# ---------------------------------------------------------------------- +# invalid arguments + +test_expect_success 'invalid arguments: invalid regexp (in project search)' ' + gitweb_run "a=project_list;s=*\.git;sr=1" && + grep "Status: 400" gitweb.headers && + grep "400 - Invalid.*regexp" gitweb.body +' +test_debug 'cat gitweb.headers' + test_done diff --git a/t/t9800-git-p4-basic.sh b/t/t9800-git-p4-basic.sh index 04ee20e642..486c8eeb7e 100755 --- a/t/t9800-git-p4-basic.sh +++ b/t/t9800-git-p4-basic.sh @@ -234,8 +234,10 @@ test_expect_success 'refuse to preserve users without perms' ' git config git-p4.skipSubmitEditCheck true && echo "username-noperms: a change by alice" >>file1 && git commit --author "Alice <alice@localhost>" -m "perms: a change by alice" file1 && - P4EDITOR=touch P4USER=bob P4PASSWD=secret test_must_fail "$GITP4" commit --preserve-user && - test_must_fail git diff --exit-code HEAD..p4/master + P4EDITOR=touch P4USER=bob P4PASSWD=secret && + export P4EDITOR P4USER P4PASSWD && + test_must_fail "$GITP4" commit --preserve-user && + ! git diff --exit-code HEAD..p4/master ) ' @@ -250,13 +252,15 @@ test_expect_success 'preserve user where author is unknown to p4' ' git commit --author "Bob <bob@localhost>" -m "preserve: a change by bob" file1 && echo "username-unknown: a change by charlie" >>file1 && git commit --author "Charlie <charlie@localhost>" -m "preserve: a change by charlie" file1 && - P4EDITOR=touch P4USER=alice P4PASSWD=secret test_must_fail "$GITP4" commit --preserve-user && - test_must_fail git diff --exit-code HEAD..p4/master && + P4EDITOR=touch P4USER=alice P4PASSWD=secret && + export P4EDITOR P4USER P4PASSWD && + test_must_fail "$GITP4" commit --preserve-user && + ! git diff --exit-code HEAD..p4/master && echo "$0: repeat with allowMissingP4Users enabled" && git config git-p4.allowMissingP4Users true && git config git-p4.preserveUser true && - P4EDITOR=touch P4USER=alice P4PASSWD=secret "$GITP4" commit && + "$GITP4" commit && git diff --exit-code HEAD..p4/master && p4_check_commit_author file1 alice ) @@ -275,20 +279,22 @@ test_expect_success 'not preserving user with mixed authorship' ' p4_add_user derek Derek && make_change_by_user usernamefile3 Derek derek@localhost && - P4EDITOR=cat P4USER=alice P4PASSWD=secret "$GITP4" commit |\ + P4EDITOR=cat P4USER=alice P4PASSWD=secret && + export P4EDITOR P4USER P4PASSWD && + "$GITP4" commit |\ grep "git author derek@localhost does not match" && make_change_by_user usernamefile3 Charlie charlie@localhost && - P4EDITOR=cat P4USER=alice P4PASSWD=secret "$GITP4" commit |\ + "$GITP4" commit |\ grep "git author charlie@localhost does not match" && make_change_by_user usernamefile3 alice alice@localhost && - P4EDITOR=cat P4USER=alice P4PASSWD=secret "$GITP4" |\ + "$GITP4" commit |\ test_must_fail grep "git author.*does not match" && git config git-p4.skipUserNameCheck true && make_change_by_user usernamefile3 Charlie charlie@localhost && - P4EDITOR=cat P4USER=alice P4PASSWD=secret "$GITP4" commit |\ + "$GITP4" commit |\ test_must_fail grep "git author.*does not match" && p4_check_commit_author usernamefile3 alice diff --git a/t/t9804-git-p4-label.sh b/t/t9804-git-p4-label.sh index 80d01ea438..a9e04efb88 100755 --- a/t/t9804-git-p4-label.sh +++ b/t/t9804-git-p4-label.sh @@ -1,3 +1,5 @@ +#!/bin/sh + test_description='git-p4 p4 label tests' . ./lib-git-p4.sh diff --git a/t/t9808-git-p4-chdir.sh b/t/t9808-git-p4-chdir.sh index eb8cc9523e..f0022839c7 100755 --- a/t/t9808-git-p4-chdir.sh +++ b/t/t9808-git-p4-chdir.sh @@ -25,7 +25,7 @@ test_expect_success 'P4CONFIG and absolute dir clone' ' test_when_finished cleanup_git && ( P4CONFIG=p4config && export P4CONFIG && - unset P4PORT P4CLIENT && + sane_unset P4PORT P4CLIENT && "$GITP4" clone --verbose --dest="$git" //depot ) ' @@ -37,7 +37,7 @@ test_expect_success 'P4CONFIG and relative dir clone' ' test_when_finished cleanup_git && ( P4CONFIG=p4config && export P4CONFIG && - unset P4PORT P4CLIENT && + sane_unset P4PORT P4CLIENT && "$GITP4" clone --verbose --dest="git" //depot ) ' diff --git a/t/t9809-git-p4-client-view.sh b/t/t9809-git-p4-client-view.sh index ae9145e307..773a516ff0 100755 --- a/t/t9809-git-p4-client-view.sh +++ b/t/t9809-git-p4-client-view.sh @@ -31,7 +31,7 @@ client_view() { # check_files_exist() { ok=0 && - num=${#@} && + num=$# && for arg ; do test_path_is_file "$arg" && ok=$(($ok + 1)) @@ -71,20 +71,24 @@ git_verify() { # - dir2 # - file21 # - file22 +init_depot() { + for d in 1 2 ; do + mkdir -p dir$d && + for f in 1 2 ; do + echo dir$d/file$d$f >dir$d/file$d$f && + p4 add dir$d/file$d$f && + p4 submit -d "dir$d/file$d$f" + done + done && + find . -type f ! -name files >files && + check_files_exist dir1/file11 dir1/file12 \ + dir2/file21 dir2/file22 +} + test_expect_success 'init depot' ' ( cd "$cli" && - for d in 1 2 ; do - mkdir -p dir$d && - for f in 1 2 ; do - echo dir$d/file$d$f >dir$d/file$d$f && - p4 add dir$d/file$d$f && - p4 submit -d "dir$d/file$d$f" - done - done && - find . -type f ! -name files >files && - check_files_exist dir1/file11 dir1/file12 \ - dir2/file21 dir2/file22 + init_depot ) ' @@ -247,6 +251,139 @@ test_expect_success 'quotes on rhs only' ' ' # +# Submit tests +# + +# clone sets variable +test_expect_success 'clone --use-client-spec sets useClientSpec' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + "$GITP4" clone --use-client-spec --dest="$git" //depot && + ( + cd "$git" && + git config --bool git-p4.useClientSpec >actual && + echo true >true && + test_cmp actual true + ) +' + +# clone just a subdir of the client spec +test_expect_success 'subdir clone' ' + client_view "//depot/... //client/..." && + files="dir1/file11 dir1/file12 dir2/file21 dir2/file22" && + client_verify $files && + test_when_finished cleanup_git && + "$GITP4" clone --use-client-spec --dest="$git" //depot/dir1 && + git_verify dir1/file11 dir1/file12 +' + +# +# submit back, see what happens: five cases +# +test_expect_success 'subdir clone, submit modify' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + "$GITP4" clone --use-client-spec --dest="$git" //depot/dir1 && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + echo line >>dir1/file12 && + git add dir1/file12 && + git commit -m dir1/file12 && + "$GITP4" submit + ) && + ( + cd "$cli" && + test_path_is_file dir1/file12 && + test_line_count = 2 dir1/file12 + ) +' + +test_expect_success 'subdir clone, submit add' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + "$GITP4" clone --use-client-spec --dest="$git" //depot/dir1 && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + echo file13 >dir1/file13 && + git add dir1/file13 && + git commit -m dir1/file13 && + "$GITP4" submit + ) && + ( + cd "$cli" && + test_path_is_file dir1/file13 + ) +' + +test_expect_success 'subdir clone, submit delete' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + "$GITP4" clone --use-client-spec --dest="$git" //depot/dir1 && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + git rm dir1/file12 && + git commit -m "delete dir1/file12" && + "$GITP4" submit + ) && + ( + cd "$cli" && + test_path_is_missing dir1/file12 + ) +' + +test_expect_success 'subdir clone, submit copy' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + "$GITP4" clone --use-client-spec --dest="$git" //depot/dir1 && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.detectCopies true && + cp dir1/file11 dir1/file11a && + git add dir1/file11a && + git commit -m "copy to dir1/file11a" && + "$GITP4" submit + ) && + ( + cd "$cli" && + test_path_is_file dir1/file11a + ) +' + +test_expect_success 'subdir clone, submit rename' ' + client_view "//depot/... //client/..." && + test_when_finished cleanup_git && + "$GITP4" clone --use-client-spec --dest="$git" //depot/dir1 && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.detectRenames true && + git mv dir1/file13 dir1/file13a && + git commit -m "rename dir1/file13 to dir1/file13a" && + "$GITP4" submit + ) && + ( + cd "$cli" && + test_path_is_missing dir1/file13 && + test_path_is_file dir1/file13a + ) +' + +test_expect_success 'reinit depot' ' + ( + cd "$cli" && + p4 sync -f && + rm files && + p4 delete */* && + p4 submit -d "delete all files" && + init_depot + ) +' + +# # What happens when two files of the same name are overlayed together? # The last-listed file should take preference. # diff --git a/t/t9810-git-p4-rcs.sh b/t/t9810-git-p4-rcs.sh new file mode 100755 index 0000000000..49dfde0616 --- /dev/null +++ b/t/t9810-git-p4-rcs.sh @@ -0,0 +1,388 @@ +#!/bin/sh + +test_description='git-p4 rcs keywords' + +. ./lib-git-p4.sh + +test_expect_success 'start p4d' ' + start_p4d +' + +# +# Make one file with keyword lines at the top, and +# enough plain text to be able to test modifications +# far away from the keywords. +# +test_expect_success 'init depot' ' + ( + cd "$cli" && + cat <<-\EOF >filek && + $Id$ + /* $Revision$ */ + # $Change$ + line4 + line5 + line6 + line7 + line8 + EOF + cp filek fileko && + sed -i "s/Revision/Revision: do not scrub me/" fileko + cp fileko file_text && + sed -i "s/Id/Id: do not scrub me/" file_text + p4 add -t text+k filek && + p4 submit -d "filek" && + p4 add -t text+ko fileko && + p4 submit -d "fileko" && + p4 add -t text file_text && + p4 submit -d "file_text" + ) +' + +# +# Generate these in a function to make it easy to use single quote marks. +# +write_scrub_scripts () { + cat >"$TRASH_DIRECTORY/scrub_k.py" <<-\EOF && + import re, sys + sys.stdout.write(re.sub(r'(?i)\$(Id|Header|Author|Date|DateTime|Change|File|Revision):[^$]*\$', r'$\1$', sys.stdin.read())) + EOF + cat >"$TRASH_DIRECTORY/scrub_ko.py" <<-\EOF + import re, sys + sys.stdout.write(re.sub(r'(?i)\$(Id|Header):[^$]*\$', r'$\1$', sys.stdin.read())) + EOF +} + +test_expect_success 'scrub scripts' ' + write_scrub_scripts +' + +# +# Compare $cli/file to its scrubbed version, should be different. +# Compare scrubbed $cli/file to $git/file, should be same. +# +scrub_k_check () { + file="$1" && + scrub="$TRASH_DIRECTORY/$file" && + "$PYTHON_PATH" "$TRASH_DIRECTORY/scrub_k.py" <"$git/$file" >"$scrub" && + ! test_cmp "$cli/$file" "$scrub" && + test_cmp "$git/$file" "$scrub" && + rm "$scrub" +} +scrub_ko_check () { + file="$1" && + scrub="$TRASH_DIRECTORY/$file" && + "$PYTHON_PATH" "$TRASH_DIRECTORY/scrub_ko.py" <"$git/$file" >"$scrub" && + ! test_cmp "$cli/$file" "$scrub" && + test_cmp "$git/$file" "$scrub" && + rm "$scrub" +} + +# +# Modify far away from keywords. If no RCS lines show up +# in the diff, there is no conflict. +# +test_expect_success 'edit far away from RCS lines' ' + test_when_finished cleanup_git && + "$GITP4" clone --dest="$git" //depot && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + sed -i "s/^line7/line7 edit/" filek && + git commit -m "filek line7 edit" filek && + "$GITP4" submit && + scrub_k_check filek + ) +' + +# +# Modify near the keywords. This will require RCS scrubbing. +# +test_expect_success 'edit near RCS lines' ' + test_when_finished cleanup_git && + "$GITP4" clone --dest="$git" //depot && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.attemptRCSCleanup true && + sed -i "s/^line4/line4 edit/" filek && + git commit -m "filek line4 edit" filek && + "$GITP4" submit && + scrub_k_check filek + ) +' + +# +# Modify the keywords themselves. This also will require RCS scrubbing. +# +test_expect_success 'edit keyword lines' ' + test_when_finished cleanup_git && + "$GITP4" clone --dest="$git" //depot && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.attemptRCSCleanup true && + sed -i "/Revision/d" filek && + git commit -m "filek remove Revision line" filek && + "$GITP4" submit && + scrub_k_check filek + ) +' + +# +# Scrubbing text+ko files should not alter all keywords, just Id, Header. +# +test_expect_success 'scrub ko files differently' ' + test_when_finished cleanup_git && + "$GITP4" clone --dest="$git" //depot && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.attemptRCSCleanup true && + sed -i "s/^line4/line4 edit/" fileko && + git commit -m "fileko line4 edit" fileko && + "$GITP4" submit && + scrub_ko_check fileko && + ! scrub_k_check fileko + ) +' + +# hack; git-p4 submit should do it on its own +test_expect_success 'cleanup after failure' ' + ( + cd "$cli" && + p4 revert ... + ) +' + +# +# Do not scrub anything but +k or +ko files. Sneak a change into +# the cli file so that submit will get a conflict. Make sure that +# scrubbing doesn't make a mess of things. +# +# Assumes that git-p4 exits leaving the p4 file open, with the +# conflict-generating patch unapplied. +# +# This might happen only if the git repo is behind the p4 repo at +# submit time, and there is a conflict. +# +test_expect_success 'do not scrub plain text' ' + test_when_finished cleanup_git && + "$GITP4" clone --dest="$git" //depot && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.attemptRCSCleanup true && + sed -i "s/^line4/line4 edit/" file_text && + git commit -m "file_text line4 edit" file_text && + ( + cd "$cli" && + p4 open file_text && + sed -i "s/^line5/line5 p4 edit/" file_text && + p4 submit -d "file5 p4 edit" + ) && + ! "$GITP4" submit && + ( + # exepct something like: + # file_text - file(s) not opened on this client + # but not copious diff output + cd "$cli" && + p4 diff file_text >wc && + test_line_count = 1 wc + ) + ) +' + +# hack; git-p4 submit should do it on its own +test_expect_success 'cleanup after failure 2' ' + ( + cd "$cli" && + p4 revert ... + ) +' + +create_kw_file () { + cat <<\EOF >"$1" +/* A file + Id: $Id$ + Revision: $Revision$ + File: $File$ + */ +int main(int argc, const char **argv) { + return 0; +} +EOF +} + +test_expect_success 'add kwfile' ' + ( + cd "$cli" && + echo file1 >file1 && + p4 add file1 && + p4 submit -d "file 1" && + create_kw_file kwfile1.c && + p4 add kwfile1.c && + p4 submit -d "Add rcw kw file" kwfile1.c + ) +' + +p4_append_to_file () { + f="$1" && + p4 edit -t ktext "$f" && + echo "/* $(date) */" >>"$f" && + p4 submit -d "appending a line in p4" +} + +# Create some files with RCS keywords. If they get modified +# elsewhere then the version number gets bumped which then +# results in a merge conflict if we touch the RCS kw lines, +# even though the change itself would otherwise apply cleanly. +test_expect_success 'cope with rcs keyword expansion damage' ' + test_when_finished cleanup_git && + "$GITP4" clone --dest="$git" //depot && + ( + cd "$git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.attemptRCSCleanup true && + (cd ../cli && p4_append_to_file kwfile1.c) && + old_lines=$(wc -l <kwfile1.c) && + perl -n -i -e "print unless m/Revision:/" kwfile1.c && + new_lines=$(wc -l <kwfile1.c) && + test $new_lines = $(($old_lines - 1)) && + + git add kwfile1.c && + git commit -m "Zap an RCS kw line" && + "$GITP4" submit && + "$GITP4" rebase && + git diff p4/master && + "$GITP4" commit && + echo "try modifying in both" && + cd "$cli" && + p4 edit kwfile1.c && + echo "line from p4" >>kwfile1.c && + p4 submit -d "add a line in p4" kwfile1.c && + cd "$git" && + echo "line from git at the top" | cat - kwfile1.c >kwfile1.c.new && + mv kwfile1.c.new kwfile1.c && + git commit -m "Add line in git at the top" kwfile1.c && + "$GITP4" rebase && + "$GITP4" submit + ) +' + +test_expect_success 'cope with rcs keyword file deletion' ' + test_when_finished cleanup_git && + ( + cd "$cli" && + echo "\$Revision\$" >kwdelfile.c && + p4 add -t ktext kwdelfile.c && + p4 submit -d "Add file to be deleted" && + cat kwdelfile.c && + grep 1 kwdelfile.c + ) && + "$GITP4" clone --dest="$git" //depot && + ( + cd "$git" && + grep Revision kwdelfile.c && + git rm -f kwdelfile.c && + git commit -m "Delete a file containing RCS keywords" && + git config git-p4.skipSubmitEdit true && + git config git-p4.attemptRCSCleanup true && + "$GITP4" submit + ) && + ( + cd "$cli" && + p4 sync && + ! test -f kwdelfile.c + ) +' + +# If you add keywords in git of the form $Header$ then everything should +# work fine without any special handling. +test_expect_success 'Add keywords in git which match the default p4 values' ' + test_when_finished cleanup_git && + "$GITP4" clone --dest="$git" //depot && + ( + cd "$git" && + echo "NewKW: \$Revision\$" >>kwfile1.c && + git add kwfile1.c && + git commit -m "Adding RCS keywords in git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.attemptRCSCleanup true && + "$GITP4" submit + ) && + ( + cd "$cli" && + p4 sync && + test -f kwfile1.c && + grep "NewKW.*Revision.*[0-9]" kwfile1.c + + ) +' + +# If you add keywords in git of the form $Header:#1$ then things will fail +# unless git-p4 takes steps to scrub the *git* commit. +# +test_expect_failure 'Add keywords in git which do not match the default p4 values' ' + test_when_finished cleanup_git && + "$GITP4" clone --dest="$git" //depot && + ( + cd "$git" && + echo "NewKW2: \$Revision:1\$" >>kwfile1.c && + git add kwfile1.c && + git commit -m "Adding RCS keywords in git" && + git config git-p4.skipSubmitEdit true && + git config git-p4.attemptRCSCleanup true && + "$GITP4" submit + ) && + ( + cd "$cli" && + p4 sync && + grep "NewKW2.*Revision.*[0-9]" kwfile1.c + + ) +' + +# Check that the existing merge conflict handling still works. +# Modify kwfile1.c in git, and delete in p4. We should be able +# to skip the git commit. +# +test_expect_success 'merge conflict handling still works' ' + test_when_finished cleanup_git && + ( + cd "$cli" && + echo "Hello:\$Id\$" >merge2.c && + echo "World" >>merge2.c && + p4 add -t ktext merge2.c && + p4 submit -d "add merge test file" + ) && + "$GITP4" clone --dest="$git" //depot && + ( + cd "$git" && + sed -e "/Hello/d" merge2.c >merge2.c.tmp && + mv merge2.c.tmp merge2.c && + git add merge2.c && + git commit -m "Modifying merge2.c" + ) && + ( + cd "$cli" && + p4 delete merge2.c && + p4 submit -d "remove merge test file" + ) && + ( + cd "$git" && + test -f merge2.c && + git config git-p4.skipSubmitEdit true && + git config git-p4.attemptRCSCleanup true && + !(echo "s" | "$GITP4" submit) && + git rebase --skip && + ! test -f merge2.c + ) +' + + +test_expect_success 'kill p4d' ' + kill_p4d +' + +test_done diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh new file mode 100644 index 0000000000..7b3b4bef30 --- /dev/null +++ b/t/test-lib-functions.sh @@ -0,0 +1,565 @@ +#!/bin/sh +# +# Copyright (c) 2005 Junio C Hamano +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see http://www.gnu.org/licenses/ . + +# The semantics of the editor variables are that of invoking +# sh -c "$EDITOR \"$@\"" files ... +# +# If our trash directory contains shell metacharacters, they will be +# interpreted if we just set $EDITOR directly, so do a little dance with +# environment variables to work around this. +# +# In particular, quoting isn't enough, as the path may contain the same quote +# that we're using. +test_set_editor () { + FAKE_EDITOR="$1" + export FAKE_EDITOR + EDITOR='"$FAKE_EDITOR"' + export EDITOR +} + +test_decode_color () { + awk ' + function name(n) { + if (n == 0) return "RESET"; + if (n == 1) return "BOLD"; + if (n == 30) return "BLACK"; + if (n == 31) return "RED"; + if (n == 32) return "GREEN"; + if (n == 33) return "YELLOW"; + if (n == 34) return "BLUE"; + if (n == 35) return "MAGENTA"; + if (n == 36) return "CYAN"; + if (n == 37) return "WHITE"; + if (n == 40) return "BLACK"; + if (n == 41) return "BRED"; + if (n == 42) return "BGREEN"; + if (n == 43) return "BYELLOW"; + if (n == 44) return "BBLUE"; + if (n == 45) return "BMAGENTA"; + if (n == 46) return "BCYAN"; + if (n == 47) return "BWHITE"; + } + { + while (match($0, /\033\[[0-9;]*m/) != 0) { + printf "%s<", substr($0, 1, RSTART-1); + codes = substr($0, RSTART+2, RLENGTH-3); + if (length(codes) == 0) + printf "%s", name(0) + else { + n = split(codes, ary, ";"); + sep = ""; + for (i = 1; i <= n; i++) { + printf "%s%s", sep, name(ary[i]); + sep = ";" + } + } + printf ">"; + $0 = substr($0, RSTART + RLENGTH, length($0) - RSTART - RLENGTH + 1); + } + print + } + ' +} + +nul_to_q () { + perl -pe 'y/\000/Q/' +} + +q_to_nul () { + perl -pe 'y/Q/\000/' +} + +q_to_cr () { + tr Q '\015' +} + +q_to_tab () { + tr Q '\011' +} + +append_cr () { + sed -e 's/$/Q/' | tr Q '\015' +} + +remove_cr () { + tr '\015' Q | sed -e 's/Q$//' +} + +# In some bourne shell implementations, the "unset" builtin returns +# nonzero status when a variable to be unset was not set in the first +# place. +# +# Use sane_unset when that should not be considered an error. + +sane_unset () { + unset "$@" + return 0 +} + +test_tick () { + if test -z "${test_tick+set}" + then + test_tick=1112911993 + else + test_tick=$(($test_tick + 60)) + fi + GIT_COMMITTER_DATE="$test_tick -0700" + GIT_AUTHOR_DATE="$test_tick -0700" + export GIT_COMMITTER_DATE GIT_AUTHOR_DATE +} + +# Stop execution and start a shell. This is useful for debugging tests and +# only makes sense together with "-v". +# +# Be sure to remove all invocations of this command before submitting. + +test_pause () { + if test "$verbose" = t; then + "$SHELL_PATH" <&6 >&3 2>&4 + else + error >&5 "test_pause requires --verbose" + fi +} + +# Call test_commit with the arguments "<message> [<file> [<contents>]]" +# +# This will commit a file with the given contents and the given commit +# message. It will also add a tag with <message> as name. +# +# Both <file> and <contents> default to <message>. + +test_commit () { + file=${2:-"$1.t"} + echo "${3-$1}" > "$file" && + git add "$file" && + test_tick && + git commit -m "$1" && + git tag "$1" +} + +# Call test_merge with the arguments "<message> <commit>", where <commit> +# can be a tag pointing to the commit-to-merge. + +test_merge () { + test_tick && + git merge -m "$1" "$2" && + git tag "$1" +} + +# This function helps systems where core.filemode=false is set. +# Use it instead of plain 'chmod +x' to set or unset the executable bit +# of a file in the working directory and add it to the index. + +test_chmod () { + chmod "$@" && + git update-index --add "--chmod=$@" +} + +# Unset a configuration variable, but don't fail if it doesn't exist. +test_unconfig () { + git config --unset-all "$@" + config_status=$? + case "$config_status" in + 5) # ok, nothing to unset + config_status=0 + ;; + esac + return $config_status +} + +# Set git config, automatically unsetting it after the test is over. +test_config () { + test_when_finished "test_unconfig '$1'" && + git config "$@" +} + +test_config_global () { + test_when_finished "test_unconfig --global '$1'" && + git config --global "$@" +} + +write_script () { + { + echo "#!${2-"$SHELL_PATH"}" && + cat + } >"$1" && + chmod +x "$1" +} + +# Use test_set_prereq to tell that a particular prerequisite is available. +# The prerequisite can later be checked for in two ways: +# +# - Explicitly using test_have_prereq. +# +# - Implicitly by specifying the prerequisite tag in the calls to +# test_expect_{success,failure,code}. +# +# The single parameter is the prerequisite tag (a simple word, in all +# capital letters by convention). + +test_set_prereq () { + satisfied="$satisfied$1 " +} +satisfied=" " + +test_have_prereq () { + # prerequisites can be concatenated with ',' + save_IFS=$IFS + IFS=, + set -- $* + IFS=$save_IFS + + total_prereq=0 + ok_prereq=0 + missing_prereq= + + for prerequisite + do + total_prereq=$(($total_prereq + 1)) + case $satisfied in + *" $prerequisite "*) + ok_prereq=$(($ok_prereq + 1)) + ;; + *) + # Keep a list of missing prerequisites + if test -z "$missing_prereq" + then + missing_prereq=$prerequisite + else + missing_prereq="$prerequisite,$missing_prereq" + fi + esac + done + + test $total_prereq = $ok_prereq +} + +test_declared_prereq () { + case ",$test_prereq," in + *,$1,*) + return 0 + ;; + esac + return 1 +} + +test_expect_failure () { + test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= + test "$#" = 2 || + error "bug in the test script: not 2 or 3 parameters to test-expect-failure" + export test_prereq + if ! test_skip "$@" + then + say >&3 "checking known breakage: $2" + if test_run_ "$2" expecting_failure + then + test_known_broken_ok_ "$1" + else + test_known_broken_failure_ "$1" + fi + fi + echo >&3 "" +} + +test_expect_success () { + test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= + test "$#" = 2 || + error "bug in the test script: not 2 or 3 parameters to test-expect-success" + export test_prereq + if ! test_skip "$@" + then + say >&3 "expecting success: $2" + if test_run_ "$2" + then + test_ok_ "$1" + else + test_failure_ "$@" + fi + fi + echo >&3 "" +} + +# test_external runs external test scripts that provide continuous +# test output about their progress, and succeeds/fails on +# zero/non-zero exit code. It outputs the test output on stdout even +# in non-verbose mode, and announces the external script with "# run +# <n>: ..." before running it. When providing relative paths, keep in +# mind that all scripts run in "trash directory". +# Usage: test_external description command arguments... +# Example: test_external 'Perl API' perl ../path/to/test.pl +test_external () { + test "$#" = 4 && { test_prereq=$1; shift; } || test_prereq= + test "$#" = 3 || + error >&5 "bug in the test script: not 3 or 4 parameters to test_external" + descr="$1" + shift + export test_prereq + if ! test_skip "$descr" "$@" + then + # Announce the script to reduce confusion about the + # test output that follows. + say_color "" "# run $test_count: $descr ($*)" + # Export TEST_DIRECTORY, TRASH_DIRECTORY and GIT_TEST_LONG + # to be able to use them in script + export TEST_DIRECTORY TRASH_DIRECTORY GIT_TEST_LONG + # Run command; redirect its stderr to &4 as in + # test_run_, but keep its stdout on our stdout even in + # non-verbose mode. + "$@" 2>&4 + if [ "$?" = 0 ] + then + if test $test_external_has_tap -eq 0; then + test_ok_ "$descr" + else + say_color "" "# test_external test $descr was ok" + test_success=$(($test_success + 1)) + fi + else + if test $test_external_has_tap -eq 0; then + test_failure_ "$descr" "$@" + else + say_color error "# test_external test $descr failed: $@" + test_failure=$(($test_failure + 1)) + fi + fi + fi +} + +# Like test_external, but in addition tests that the command generated +# no output on stderr. +test_external_without_stderr () { + # The temporary file has no (and must have no) security + # implications. + tmp=${TMPDIR:-/tmp} + stderr="$tmp/git-external-stderr.$$.tmp" + test_external "$@" 4> "$stderr" + [ -f "$stderr" ] || error "Internal error: $stderr disappeared." + descr="no stderr: $1" + shift + say >&3 "# expecting no stderr from previous command" + if [ ! -s "$stderr" ]; then + rm "$stderr" + + if test $test_external_has_tap -eq 0; then + test_ok_ "$descr" + else + say_color "" "# test_external_without_stderr test $descr was ok" + test_success=$(($test_success + 1)) + fi + else + if [ "$verbose" = t ]; then + output=`echo; echo "# Stderr is:"; cat "$stderr"` + else + output= + fi + # rm first in case test_failure exits. + rm "$stderr" + if test $test_external_has_tap -eq 0; then + test_failure_ "$descr" "$@" "$output" + else + say_color error "# test_external_without_stderr test $descr failed: $@: $output" + test_failure=$(($test_failure + 1)) + fi + fi +} + +# debugging-friendly alternatives to "test [-f|-d|-e]" +# The commands test the existence or non-existence of $1. $2 can be +# given to provide a more precise diagnosis. +test_path_is_file () { + if ! [ -f "$1" ] + then + echo "File $1 doesn't exist. $*" + false + fi +} + +test_path_is_dir () { + if ! [ -d "$1" ] + then + echo "Directory $1 doesn't exist. $*" + false + fi +} + +test_path_is_missing () { + if [ -e "$1" ] + then + echo "Path exists:" + ls -ld "$1" + if [ $# -ge 1 ]; then + echo "$*" + fi + false + fi +} + +# test_line_count checks that a file has the number of lines it +# ought to. For example: +# +# test_expect_success 'produce exactly one line of output' ' +# do something >output && +# test_line_count = 1 output +# ' +# +# is like "test $(wc -l <output) = 1" except that it passes the +# output through when the number of lines is wrong. + +test_line_count () { + if test $# != 3 + then + error "bug in the test script: not 3 parameters to test_line_count" + elif ! test $(wc -l <"$3") "$1" "$2" + then + echo "test_line_count: line count for $3 !$1 $2" + cat "$3" + return 1 + fi +} + +# This is not among top-level (test_expect_success | test_expect_failure) +# but is a prefix that can be used in the test script, like: +# +# test_expect_success 'complain and die' ' +# do something && +# do something else && +# test_must_fail git checkout ../outerspace +# ' +# +# Writing this as "! git checkout ../outerspace" is wrong, because +# the failure could be due to a segv. We want a controlled failure. + +test_must_fail () { + "$@" + exit_code=$? + if test $exit_code = 0; then + echo >&2 "test_must_fail: command succeeded: $*" + return 1 + elif test $exit_code -gt 129 -a $exit_code -le 192; then + echo >&2 "test_must_fail: died by signal: $*" + return 1 + elif test $exit_code = 127; then + echo >&2 "test_must_fail: command not found: $*" + return 1 + fi + return 0 +} + +# Similar to test_must_fail, but tolerates success, too. This is +# meant to be used in contexts like: +# +# test_expect_success 'some command works without configuration' ' +# test_might_fail git config --unset all.configuration && +# do something +# ' +# +# Writing "git config --unset all.configuration || :" would be wrong, +# because we want to notice if it fails due to segv. + +test_might_fail () { + "$@" + exit_code=$? + if test $exit_code -gt 129 -a $exit_code -le 192; then + echo >&2 "test_might_fail: died by signal: $*" + return 1 + elif test $exit_code = 127; then + echo >&2 "test_might_fail: command not found: $*" + return 1 + fi + return 0 +} + +# Similar to test_must_fail and test_might_fail, but check that a +# given command exited with a given exit code. Meant to be used as: +# +# test_expect_success 'Merge with d/f conflicts' ' +# test_expect_code 1 git merge "merge msg" B master +# ' + +test_expect_code () { + want_code=$1 + shift + "$@" + exit_code=$? + if test $exit_code = $want_code + then + return 0 + fi + + echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*" + return 1 +} + +# test_cmp is a helper function to compare actual and expected output. +# You can use it like: +# +# test_expect_success 'foo works' ' +# echo expected >expected && +# foo >actual && +# test_cmp expected actual +# ' +# +# This could be written as either "cmp" or "diff -u", but: +# - cmp's output is not nearly as easy to read as diff -u +# - not all diff versions understand "-u" + +test_cmp() { + $GIT_TEST_CMP "$@" +} + +# This function can be used to schedule some commands to be run +# unconditionally at the end of the test to restore sanity: +# +# test_expect_success 'test core.capslock' ' +# git config core.capslock true && +# test_when_finished "git config --unset core.capslock" && +# hello world +# ' +# +# That would be roughly equivalent to +# +# test_expect_success 'test core.capslock' ' +# git config core.capslock true && +# hello world +# git config --unset core.capslock +# ' +# +# except that the greeting and config --unset must both succeed for +# the test to pass. +# +# Note that under --immediate mode, no clean-up is done to help diagnose +# what went wrong. + +test_when_finished () { + test_cleanup="{ $* + } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup" +} + +# Most tests can use the created repository, but some may need to create more. +# Usage: test_create_repo <directory> +test_create_repo () { + test "$#" = 1 || + error "bug in the test script: not 1 parameter to test-create-repo" + repo="$1" + mkdir -p "$repo" + ( + cd "$repo" || error "Cannot setup test environment" + "$GIT_EXEC_PATH/git-init" "--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 || + error "cannot run git init -- have you built things yet?" + mv .git/hooks .git/hooks-disabled + ) || exit +} diff --git a/t/test-lib.sh b/t/test-lib.sh index e28d5fdebe..30ed4d74bb 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -42,10 +42,11 @@ TZ=UTC TERM=dumb export LANG LC_ALL PAGER TERM TZ EDITOR=: -unset VISUAL -unset EMAIL -unset LANGUAGE -unset $(perl -e ' +# A call to "unset" with no arguments causes at least Solaris 10 +# /usr/xpg4/bin/sh and /bin/ksh to bail out. So keep the unsets +# deriving from the command substitution clustered with the other +# ones. +unset VISUAL EMAIL LANGUAGE $(perl -e ' my @env = keys %ENV; my $ok = join("|", qw( TRACE @@ -55,6 +56,7 @@ unset $(perl -e ' .*_TEST PROVE VALGRIND + PERF_AGGREGATING_LATER )); my @vars = grep(/^GIT_/ && !/^GIT_($ok)/o, @env); print join("\n", @vars); @@ -98,6 +100,8 @@ _z40=0000000000000000000000000000000000000000 LF=' ' +export _x05 _x40 _z40 LF + # Each test should start with something like this, after copyright notices: # # test_description='Description of this test... @@ -223,248 +227,9 @@ die () { GIT_EXIT_OK= trap 'die' EXIT -# The semantics of the editor variables are that of invoking -# sh -c "$EDITOR \"$@\"" files ... -# -# If our trash directory contains shell metacharacters, they will be -# interpreted if we just set $EDITOR directly, so do a little dance with -# environment variables to work around this. -# -# In particular, quoting isn't enough, as the path may contain the same quote -# that we're using. -test_set_editor () { - FAKE_EDITOR="$1" - export FAKE_EDITOR - EDITOR='"$FAKE_EDITOR"' - export EDITOR -} - -test_decode_color () { - awk ' - function name(n) { - if (n == 0) return "RESET"; - if (n == 1) return "BOLD"; - if (n == 30) return "BLACK"; - if (n == 31) return "RED"; - if (n == 32) return "GREEN"; - if (n == 33) return "YELLOW"; - if (n == 34) return "BLUE"; - if (n == 35) return "MAGENTA"; - if (n == 36) return "CYAN"; - if (n == 37) return "WHITE"; - if (n == 40) return "BLACK"; - if (n == 41) return "BRED"; - if (n == 42) return "BGREEN"; - if (n == 43) return "BYELLOW"; - if (n == 44) return "BBLUE"; - if (n == 45) return "BMAGENTA"; - if (n == 46) return "BCYAN"; - if (n == 47) return "BWHITE"; - } - { - while (match($0, /\033\[[0-9;]*m/) != 0) { - printf "%s<", substr($0, 1, RSTART-1); - codes = substr($0, RSTART+2, RLENGTH-3); - if (length(codes) == 0) - printf "%s", name(0) - else { - n = split(codes, ary, ";"); - sep = ""; - for (i = 1; i <= n; i++) { - printf "%s%s", sep, name(ary[i]); - sep = ";" - } - } - printf ">"; - $0 = substr($0, RSTART + RLENGTH, length($0) - RSTART - RLENGTH + 1); - } - print - } - ' -} - -nul_to_q () { - perl -pe 'y/\000/Q/' -} - -q_to_nul () { - perl -pe 'y/Q/\000/' -} - -q_to_cr () { - tr Q '\015' -} - -q_to_tab () { - tr Q '\011' -} - -append_cr () { - sed -e 's/$/Q/' | tr Q '\015' -} - -remove_cr () { - tr '\015' Q | sed -e 's/Q$//' -} - -# In some bourne shell implementations, the "unset" builtin returns -# nonzero status when a variable to be unset was not set in the first -# place. -# -# Use sane_unset when that should not be considered an error. - -sane_unset () { - unset "$@" - return 0 -} - -test_tick () { - if test -z "${test_tick+set}" - then - test_tick=1112911993 - else - test_tick=$(($test_tick + 60)) - fi - GIT_COMMITTER_DATE="$test_tick -0700" - GIT_AUTHOR_DATE="$test_tick -0700" - export GIT_COMMITTER_DATE GIT_AUTHOR_DATE -} - -# Stop execution and start a shell. This is useful for debugging tests and -# only makes sense together with "-v". -# -# Be sure to remove all invocations of this command before submitting. - -test_pause () { - if test "$verbose" = t; then - "$SHELL_PATH" <&6 >&3 2>&4 - else - error >&5 "test_pause requires --verbose" - fi -} - -# Call test_commit with the arguments "<message> [<file> [<contents>]]" -# -# This will commit a file with the given contents and the given commit -# message. It will also add a tag with <message> as name. -# -# Both <file> and <contents> default to <message>. - -test_commit () { - file=${2:-"$1.t"} - echo "${3-$1}" > "$file" && - git add "$file" && - test_tick && - git commit -m "$1" && - git tag "$1" -} - -# Call test_merge with the arguments "<message> <commit>", where <commit> -# can be a tag pointing to the commit-to-merge. - -test_merge () { - test_tick && - git merge -m "$1" "$2" && - git tag "$1" -} - -# This function helps systems where core.filemode=false is set. -# Use it instead of plain 'chmod +x' to set or unset the executable bit -# of a file in the working directory and add it to the index. - -test_chmod () { - chmod "$@" && - git update-index --add "--chmod=$@" -} - -# Unset a configuration variable, but don't fail if it doesn't exist. -test_unconfig () { - git config --unset-all "$@" - config_status=$? - case "$config_status" in - 5) # ok, nothing to unset - config_status=0 - ;; - esac - return $config_status -} - -# Set git config, automatically unsetting it after the test is over. -test_config () { - test_when_finished "test_unconfig '$1'" && - git config "$@" -} - - -test_config_global () { - test_when_finished "test_unconfig --global '$1'" && - git config --global "$@" -} - -write_script () { - { - echo "#!${2-"$SHELL_PATH"}" && - cat - } >"$1" && - chmod +x "$1" -} - -# Use test_set_prereq to tell that a particular prerequisite is available. -# The prerequisite can later be checked for in two ways: -# -# - Explicitly using test_have_prereq. -# -# - Implicitly by specifying the prerequisite tag in the calls to -# test_expect_{success,failure,code}. -# -# The single parameter is the prerequisite tag (a simple word, in all -# capital letters by convention). - -test_set_prereq () { - satisfied="$satisfied$1 " -} -satisfied=" " - -test_have_prereq () { - # prerequisites can be concatenated with ',' - save_IFS=$IFS - IFS=, - set -- $* - IFS=$save_IFS - - total_prereq=0 - ok_prereq=0 - missing_prereq= - - for prerequisite - do - total_prereq=$(($total_prereq + 1)) - case $satisfied in - *" $prerequisite "*) - ok_prereq=$(($ok_prereq + 1)) - ;; - *) - # Keep a list of missing prerequisites - if test -z "$missing_prereq" - then - missing_prereq=$prerequisite - else - missing_prereq="$prerequisite,$missing_prereq" - fi - esac - done - - test $total_prereq = $ok_prereq -} - -test_declared_prereq () { - case ",$test_prereq," in - *,$1,*) - return 0 - ;; - esac - return 1 -} +# The user-facing functions are loaded from a separate file so that +# test_perf subshells can have them too +. "${TEST_DIRECTORY:-.}"/test-lib-functions.sh # You are not expected to call test_ok_ and test_failure_ directly, use # the text_expect_* functions instead. @@ -552,318 +317,16 @@ test_skip () { esac } -test_expect_failure () { - test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= - test "$#" = 2 || - error "bug in the test script: not 2 or 3 parameters to test-expect-failure" - export test_prereq - if ! test_skip "$@" - then - say >&3 "checking known breakage: $2" - if test_run_ "$2" expecting_failure - then - test_known_broken_ok_ "$1" - else - test_known_broken_failure_ "$1" - fi - fi - echo >&3 "" -} - -test_expect_success () { - test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq= - test "$#" = 2 || - error "bug in the test script: not 2 or 3 parameters to test-expect-success" - export test_prereq - if ! test_skip "$@" - then - say >&3 "expecting success: $2" - if test_run_ "$2" - then - test_ok_ "$1" - else - test_failure_ "$@" - fi - fi - echo >&3 "" -} - -# test_external runs external test scripts that provide continuous -# test output about their progress, and succeeds/fails on -# zero/non-zero exit code. It outputs the test output on stdout even -# in non-verbose mode, and announces the external script with "# run -# <n>: ..." before running it. When providing relative paths, keep in -# mind that all scripts run in "trash directory". -# Usage: test_external description command arguments... -# Example: test_external 'Perl API' perl ../path/to/test.pl -test_external () { - test "$#" = 4 && { test_prereq=$1; shift; } || test_prereq= - test "$#" = 3 || - error >&5 "bug in the test script: not 3 or 4 parameters to test_external" - descr="$1" - shift - export test_prereq - if ! test_skip "$descr" "$@" - then - # Announce the script to reduce confusion about the - # test output that follows. - say_color "" "# run $test_count: $descr ($*)" - # Export TEST_DIRECTORY, TRASH_DIRECTORY and GIT_TEST_LONG - # to be able to use them in script - export TEST_DIRECTORY TRASH_DIRECTORY GIT_TEST_LONG - # Run command; redirect its stderr to &4 as in - # test_run_, but keep its stdout on our stdout even in - # non-verbose mode. - "$@" 2>&4 - if [ "$?" = 0 ] - then - if test $test_external_has_tap -eq 0; then - test_ok_ "$descr" - else - say_color "" "# test_external test $descr was ok" - test_success=$(($test_success + 1)) - fi - else - if test $test_external_has_tap -eq 0; then - test_failure_ "$descr" "$@" - else - say_color error "# test_external test $descr failed: $@" - test_failure=$(($test_failure + 1)) - fi - fi - fi -} - -# Like test_external, but in addition tests that the command generated -# no output on stderr. -test_external_without_stderr () { - # The temporary file has no (and must have no) security - # implications. - tmp=${TMPDIR:-/tmp} - stderr="$tmp/git-external-stderr.$$.tmp" - test_external "$@" 4> "$stderr" - [ -f "$stderr" ] || error "Internal error: $stderr disappeared." - descr="no stderr: $1" - shift - say >&3 "# expecting no stderr from previous command" - if [ ! -s "$stderr" ]; then - rm "$stderr" - - if test $test_external_has_tap -eq 0; then - test_ok_ "$descr" - else - say_color "" "# test_external_without_stderr test $descr was ok" - test_success=$(($test_success + 1)) - fi - else - if [ "$verbose" = t ]; then - output=`echo; echo "# Stderr is:"; cat "$stderr"` - else - output= - fi - # rm first in case test_failure exits. - rm "$stderr" - if test $test_external_has_tap -eq 0; then - test_failure_ "$descr" "$@" "$output" - else - say_color error "# test_external_without_stderr test $descr failed: $@: $output" - test_failure=$(($test_failure + 1)) - fi - fi -} - -# debugging-friendly alternatives to "test [-f|-d|-e]" -# The commands test the existence or non-existence of $1. $2 can be -# given to provide a more precise diagnosis. -test_path_is_file () { - if ! [ -f "$1" ] - then - echo "File $1 doesn't exist. $*" - false - fi -} - -test_path_is_dir () { - if ! [ -d "$1" ] - then - echo "Directory $1 doesn't exist. $*" - false - fi -} - -test_path_is_missing () { - if [ -e "$1" ] - then - echo "Path exists:" - ls -ld "$1" - if [ $# -ge 1 ]; then - echo "$*" - fi - false - fi -} - -# test_line_count checks that a file has the number of lines it -# ought to. For example: -# -# test_expect_success 'produce exactly one line of output' ' -# do something >output && -# test_line_count = 1 output -# ' -# -# is like "test $(wc -l <output) = 1" except that it passes the -# output through when the number of lines is wrong. - -test_line_count () { - if test $# != 3 - then - error "bug in the test script: not 3 parameters to test_line_count" - elif ! test $(wc -l <"$3") "$1" "$2" - then - echo "test_line_count: line count for $3 !$1 $2" - cat "$3" - return 1 - fi -} - -# This is not among top-level (test_expect_success | test_expect_failure) -# but is a prefix that can be used in the test script, like: -# -# test_expect_success 'complain and die' ' -# do something && -# do something else && -# test_must_fail git checkout ../outerspace -# ' -# -# Writing this as "! git checkout ../outerspace" is wrong, because -# the failure could be due to a segv. We want a controlled failure. - -test_must_fail () { - "$@" - exit_code=$? - if test $exit_code = 0; then - echo >&2 "test_must_fail: command succeeded: $*" - return 1 - elif test $exit_code -gt 129 -a $exit_code -le 192; then - echo >&2 "test_must_fail: died by signal: $*" - return 1 - elif test $exit_code = 127; then - echo >&2 "test_must_fail: command not found: $*" - return 1 - fi - return 0 -} - -# Similar to test_must_fail, but tolerates success, too. This is -# meant to be used in contexts like: -# -# test_expect_success 'some command works without configuration' ' -# test_might_fail git config --unset all.configuration && -# do something -# ' -# -# Writing "git config --unset all.configuration || :" would be wrong, -# because we want to notice if it fails due to segv. - -test_might_fail () { - "$@" - exit_code=$? - if test $exit_code -gt 129 -a $exit_code -le 192; then - echo >&2 "test_might_fail: died by signal: $*" - return 1 - elif test $exit_code = 127; then - echo >&2 "test_might_fail: command not found: $*" - return 1 - fi - return 0 -} - -# Similar to test_must_fail and test_might_fail, but check that a -# given command exited with a given exit code. Meant to be used as: -# -# test_expect_success 'Merge with d/f conflicts' ' -# test_expect_code 1 git merge "merge msg" B master -# ' - -test_expect_code () { - want_code=$1 - shift - "$@" - exit_code=$? - if test $exit_code = $want_code - then - return 0 - fi - - echo >&2 "test_expect_code: command exited with $exit_code, we wanted $want_code $*" - return 1 -} - -# test_cmp is a helper function to compare actual and expected output. -# You can use it like: -# -# test_expect_success 'foo works' ' -# echo expected >expected && -# foo >actual && -# test_cmp expected actual -# ' -# -# This could be written as either "cmp" or "diff -u", but: -# - cmp's output is not nearly as easy to read as diff -u -# - not all diff versions understand "-u" - -test_cmp() { - $GIT_TEST_CMP "$@" -} - -# This function can be used to schedule some commands to be run -# unconditionally at the end of the test to restore sanity: -# -# test_expect_success 'test core.capslock' ' -# git config core.capslock true && -# test_when_finished "git config --unset core.capslock" && -# hello world -# ' -# -# That would be roughly equivalent to -# -# test_expect_success 'test core.capslock' ' -# git config core.capslock true && -# hello world -# git config --unset core.capslock -# ' -# -# except that the greeting and config --unset must both succeed for -# the test to pass. -# -# Note that under --immediate mode, no clean-up is done to help diagnose -# what went wrong. - -test_when_finished () { - test_cleanup="{ $* - } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup" -} - -# Most tests can use the created repository, but some may need to create more. -# Usage: test_create_repo <directory> -test_create_repo () { - test "$#" = 1 || - error "bug in the test script: not 1 parameter to test-create-repo" - repo="$1" - mkdir -p "$repo" - ( - cd "$repo" || error "Cannot setup test environment" - "$GIT_EXEC_PATH/git-init" "--template=$GIT_BUILD_DIR/templates/blt/" >&3 2>&4 || - error "cannot run git init -- have you built things yet?" - mv .git/hooks .git/hooks-disabled - ) || exit +# stub; perf-lib overrides it +test_at_end_hook_ () { + : } test_done () { GIT_EXIT_OK=t if test -z "$HARNESS_ACTIVE"; then - test_results_dir="$TEST_DIRECTORY/test-results" + test_results_dir="$TEST_OUTPUT_DIRECTORY/test-results" mkdir -p "$test_results_dir" test_results_path="$test_results_dir/${0%.sh}-$$.counts" @@ -902,6 +365,8 @@ test_done () { cd "$(dirname "$remove_trash")" && rm -rf "$(basename "$remove_trash")" + test_at_end_hook_ + exit 0 ;; *) @@ -924,6 +389,12 @@ then # itself. TEST_DIRECTORY=$(pwd) fi +if test -z "$TEST_OUTPUT_DIRECTORY" +then + # Similarly, override this to store the test-results subdir + # elsewhere + TEST_OUTPUT_DIRECTORY=$TEST_DIRECTORY +fi GIT_BUILD_DIR="$TEST_DIRECTORY"/.. if test -n "$valgrind" @@ -1059,7 +530,7 @@ test="trash directory.$(basename "$0" .sh)" test -n "$root" && test="$root/$test" case "$test" in /*) TRASH_DIRECTORY="$test" ;; - *) TRASH_DIRECTORY="$TEST_DIRECTORY/$test" ;; + *) TRASH_DIRECTORY="$TEST_OUTPUT_DIRECTORY/$test" ;; esac test ! -z "$debug" || remove_trash=$TRASH_DIRECTORY rm -fr "$test" || { @@ -1071,7 +542,11 @@ rm -fr "$test" || { HOME="$TRASH_DIRECTORY" export HOME -test_create_repo "$test" +if test -z "$TEST_NO_CREATE_REPO"; then + test_create_repo "$test" +else + mkdir -p "$test" +fi # Use -P to resolve symlinks in our working directory so that the cwd # in subprocesses like git equals our $PWD (for pathname comparisons). cd -P "$test" || exit 1 diff --git a/test-dump-cache-tree.c b/test-dump-cache-tree.c index e6c292385f..a6ffdf39d5 100644 --- a/test-dump-cache-tree.c +++ b/test-dump-cache-tree.c @@ -59,6 +59,6 @@ int main(int ac, char **av) struct cache_tree *another = cache_tree(); if (read_cache() < 0) die("unable to read index file"); - cache_tree_update(another, active_cache, active_nr, 0, 1, 0); + cache_tree_update(another, active_cache, active_nr, WRITE_TREE_DRY_RUN); return dump_cache_tree(active_cache_tree, another, ""); } diff --git a/test-parse-options.c b/test-parse-options.c index 36487c402b..3c9510a701 100644 --- a/test-parse-options.c +++ b/test-parse-options.c @@ -37,7 +37,11 @@ int main(int argc, const char **argv) NULL }; struct option options[] = { - OPT_BOOLEAN('b', "boolean", &boolean, "get a boolean"), + OPT_BOOL(0, "yes", &boolean, "get a boolean"), + OPT_BOOL('D', "no-doubt", &boolean, "begins with 'no-'"), + { OPTION_SET_INT, 'B', "no-fear", &boolean, NULL, + "be brave", PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, 1 }, + OPT_COUNTUP('b', "boolean", &boolean, "increment by one"), OPT_BIT('4', "or4", &boolean, "bitwise-or boolean with ...0100", 4), OPT_NEGBIT(0, "neg-or4", &boolean, "same as --no-or4", 4), @@ -62,11 +66,11 @@ int main(int argc, const char **argv) OPT_ARGUMENT("quux", "means --quux"), OPT_NUMBER_CALLBACK(&integer, "set integer to NUM", number_callback), - { OPTION_BOOLEAN, '+', NULL, &boolean, NULL, "same as -b", + { OPTION_COUNTUP, '+', NULL, &boolean, NULL, "same as -b", PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH }, - { OPTION_BOOLEAN, 0, "ambiguous", &ambiguous, NULL, + { OPTION_COUNTUP, 0, "ambiguous", &ambiguous, NULL, "positive ambiguity", PARSE_OPT_NOARG | PARSE_OPT_NONEG }, - { OPTION_BOOLEAN, 0, "no-ambiguous", &ambiguous, NULL, + { OPTION_COUNTUP, 0, "no-ambiguous", &ambiguous, NULL, "negative ambiguity", PARSE_OPT_NOARG | PARSE_OPT_NONEG }, OPT_GROUP("Standard options"), OPT__ABBREV(&abbrev), diff --git a/transport-helper.c b/transport-helper.c index 6f227e253b..f6b3b1fb79 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -9,6 +9,7 @@ #include "remote.h" #include "string-list.h" #include "thread-utils.h" +#include "sigchain.h" static int debug; @@ -220,15 +221,21 @@ static struct child_process *get_helper(struct transport *transport) static int disconnect_helper(struct transport *transport) { struct helper_data *data = transport->data; - struct strbuf buf = STRBUF_INIT; int res = 0; if (data->helper) { if (debug) fprintf(stderr, "Debug: Disconnecting.\n"); if (!data->no_disconnect_req) { - strbuf_addf(&buf, "\n"); - sendline(data, &buf); + /* + * Ignore write errors; there's nothing we can do, + * since we're about to close the pipe anyway. And the + * most likely error is EPIPE due to the helper dying + * to report an error itself. + */ + sigchain_push(SIGPIPE, SIG_IGN); + xwrite(data->helper->in, "\n", 1); + sigchain_pop(SIGPIPE); } close(data->helper->in); close(data->helper->out); diff --git a/transport.c b/transport.c index cac0c065ff..181f8f24d1 100644 --- a/transport.c +++ b/transport.c @@ -993,11 +993,15 @@ void transport_set_verbosity(struct transport *transport, int verbosity, * Rules used to determine whether to report progress (processing aborts * when a rule is satisfied): * - * 1. Report progress, if force_progress is 1 (ie. --progress). - * 2. Don't report progress, if verbosity < 0 (ie. -q/--quiet ). - * 3. Report progress if isatty(2) is 1. + * . Report progress, if force_progress is 1 (ie. --progress). + * . Don't report progress, if force_progress is 0 (ie. --no-progress). + * . Don't report progress, if verbosity < 0 (ie. -q/--quiet ). + * . Report progress if isatty(2) is 1. **/ - transport->progress = force_progress || (verbosity >= 0 && isatty(2)); + if (force_progress >= 0) + transport->progress = !!force_progress; + else + transport->progress = verbosity >= 0 && isatty(2); } int transport_push(struct transport *transport, @@ -1028,6 +1032,8 @@ int transport_push(struct transport *transport, match_flags |= MATCH_REFS_ALL; if (flags & TRANSPORT_PUSH_MIRROR) match_flags |= MATCH_REFS_MIRROR; + if (flags & TRANSPORT_PUSH_PRUNE) + match_flags |= MATCH_REFS_PRUNE; if (match_push_refs(local_refs, &remote_refs, refspec_nr, refspec, match_flags)) { diff --git a/transport.h b/transport.h index 059b3303e2..ce99ef8b7e 100644 --- a/transport.h +++ b/transport.h @@ -102,6 +102,7 @@ struct transport { #define TRANSPORT_PUSH_PORCELAIN 16 #define TRANSPORT_PUSH_SET_UPSTREAM 32 #define TRANSPORT_RECURSE_SUBMODULES_CHECK 64 +#define TRANSPORT_PUSH_PRUNE 128 #define TRANSPORT_SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3) diff --git a/userdiff.c b/userdiff.c index 76109da4bc..1e7184f7f0 100644 --- a/userdiff.c +++ b/userdiff.c @@ -210,14 +210,7 @@ static int parse_funcname(struct userdiff_funcname *f, const char *k, if (git_config_string(&f->pattern, k, v) < 0) return -1; f->cflags = cflags; - return 1; -} - -static int parse_string(const char **d, const char *k, const char *v) -{ - if (git_config_string(d, k, v) < 0) - return -1; - return 1; + return 0; } static int parse_tristate(int *b, const char *k, const char *v) @@ -226,13 +219,13 @@ static int parse_tristate(int *b, const char *k, const char *v) *b = -1; else *b = git_config_bool(k, v); - return 1; + return 0; } static int parse_bool(int *b, const char *k, const char *v) { *b = git_config_bool(k, v); - return 1; + return 0; } int userdiff_config(const char *k, const char *v) @@ -246,13 +239,13 @@ int userdiff_config(const char *k, const char *v) if ((drv = parse_driver(k, v, "binary"))) return parse_tristate(&drv->binary, k, v); if ((drv = parse_driver(k, v, "command"))) - return parse_string(&drv->external, k, v); + return git_config_string(&drv->external, k, v); if ((drv = parse_driver(k, v, "textconv"))) - return parse_string(&drv->textconv, k, v); + return git_config_string(&drv->textconv, k, v); if ((drv = parse_driver(k, v, "cachetextconv"))) return parse_bool(&drv->textconv_want_cache, k, v); if ((drv = parse_driver(k, v, "wordregex"))) - return parse_string(&drv->word_regex, k, v); + return git_config_string(&drv->word_regex, k, v); return 0; } |