diff options
120 files changed, 4422 insertions, 1285 deletions
diff --git a/Documentation/Makefile b/Documentation/Makefile index e117bc4315..36989b7f65 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -63,35 +63,28 @@ endif # # For asciidoc ... -# -7.1.2, no extra settings are needed. -# 8.0-, set ASCIIDOC8. +# -7.1.2, set ASCIIDOC7 +# 8.0-, no extra settings are needed # # # For docbook-xsl ... -# -1.68.1, set ASCIIDOC_NO_ROFF? (based on changelog from 1.73.0) -# 1.69.0, no extra settings are needed? +# -1.68.1, no extra settings are needed? +# 1.69.0, set ASCIIDOC_ROFF? # 1.69.1-1.71.0, set DOCBOOK_SUPPRESS_SP? -# 1.71.1, no extra settings are needed? +# 1.71.1, set ASCIIDOC_ROFF? # 1.72.0, set DOCBOOK_XSL_172. -# 1.73.0-, set ASCIIDOC_NO_ROFF +# 1.73.0-, no extra settings are needed # -# -# If you had been using DOCBOOK_XSL_172 in an attempt to get rid -# of 'the ".ft C" problem' in your generated manpages, and you -# instead ended up with weird characters around callouts, try -# using ASCIIDOC_NO_ROFF instead (it works fine with ASCIIDOC8). -# - -ifdef ASCIIDOC8 +ifndef ASCIIDOC7 ASCIIDOC_EXTRA += -a asciidoc7compatible -a no-inline-literal endif ifdef DOCBOOK_XSL_172 ASCIIDOC_EXTRA += -a git-asciidoc-no-roff MANPAGE_XSL = manpage-1.72.xsl else - ifdef ASCIIDOC_NO_ROFF + ifndef ASCIIDOC_ROFF # docbook-xsl after 1.72 needs the regular XSL, but will not # pass-thru raw roff codes from asciidoc.conf, so turn them off. ASCIIDOC_EXTRA += -a git-asciidoc-no-roff diff --git a/Documentation/RelNotes/1.6.4.5.txt b/Documentation/RelNotes/1.6.4.5.txt new file mode 100644 index 0000000000..eb6307dcbb --- /dev/null +++ b/Documentation/RelNotes/1.6.4.5.txt @@ -0,0 +1,20 @@ +Git v1.6.4.5 Release Notes +========================== + +Fixes since v1.6.4.4 +-------------------- + + * Simplified base85 implementation. + + * An overlong line after ".gitdir: " in a git file caused out of bounds + access to an array on the stack. + + * "git count-objects" did not handle packs larger than 4G. + + * "git rev-parse --parseopt --stop-at-non-option" did not stop at non option + when --keep-dashdash was in effect. + + * "gitweb" can sometimes be tricked into parrotting a filename argument + given in a request without properly quoting. + +Other minor fixes and documentation updates are included. diff --git a/Documentation/RelNotes/1.6.5.9.txt b/Documentation/RelNotes/1.6.5.9.txt new file mode 100644 index 0000000000..bb469dd71e --- /dev/null +++ b/Documentation/RelNotes/1.6.5.9.txt @@ -0,0 +1,18 @@ +Git v1.6.5.9 Release Notes +========================== + +Fixes since v1.6.5.8 +-------------------- + + * An overlong line after ".gitdir: " in a git file caused out of bounds + access to an array on the stack. + + * "git blame -L $start,$end" segfaulted when too large $start was given. + + * "git rev-parse --parseopt --stop-at-non-option" did not stop at non option + when --keep-dashdash was in effect. + + * "gitweb" can sometimes be tricked into parrotting a filename argument + given in a request without properly quoting. + +Other minor fixes and documentation updates are included. diff --git a/Documentation/RelNotes/1.6.6.3.txt b/Documentation/RelNotes/1.6.6.3.txt new file mode 100644 index 0000000000..11483acaec --- /dev/null +++ b/Documentation/RelNotes/1.6.6.3.txt @@ -0,0 +1,23 @@ +Git v1.6.6.3 Release Notes +========================== + +Fixes since v1.6.6.2 +-------------------- + + * An overlong line after ".gitdir: " in a git file caused out of bounds + access to an array on the stack. + + * "git bisect $path" did not correctly diagnose an error when given a + non-existent path. + + * "git blame -L $start,$end" segfaulted when too large $start was given. + + * "git imap-send" did not write draft box with CRLF line endings per RFC. + + * "git rev-parse --parseopt --stop-at-non-option" did not stop at non option + when --keep-dashdash was in effect. + + * "gitweb" can sometimes be tricked into parrotting a filename argument + given in a request without properly quoting. + +Other minor fixes and documentation updates are included. diff --git a/Documentation/RelNotes/1.7.0.9.txt b/Documentation/RelNotes/1.7.0.9.txt new file mode 100644 index 0000000000..bfb3166387 --- /dev/null +++ b/Documentation/RelNotes/1.7.0.9.txt @@ -0,0 +1,8 @@ +Git v1.7.0.9 Release Notes +========================== + +Fixes since v1.7.0.8 +-------------------- + + * "gitweb" can sometimes be tricked into parrotting a filename argument + given in a request without properly quoting. diff --git a/Documentation/RelNotes/1.7.1.4.txt b/Documentation/RelNotes/1.7.1.4.txt new file mode 100644 index 0000000000..7c734b4f7b --- /dev/null +++ b/Documentation/RelNotes/1.7.1.4.txt @@ -0,0 +1,8 @@ +Git v1.7.1.4 Release Notes +========================== + +Fixes since v1.7.1.3 +-------------------- + + * "gitweb" can sometimes be tricked into parrotting a filename argument + given in a request without properly quoting. diff --git a/Documentation/RelNotes/1.7.2.5.txt b/Documentation/RelNotes/1.7.2.5.txt new file mode 100644 index 0000000000..bf976c40db --- /dev/null +++ b/Documentation/RelNotes/1.7.2.5.txt @@ -0,0 +1,8 @@ +Git v1.7.2.5 Release Notes +========================== + +Fixes since v1.7.2.4 +-------------------- + + * "gitweb" can sometimes be tricked into parrotting a filename argument + given in a request without properly quoting. diff --git a/Documentation/RelNotes/1.7.3.4.txt b/Documentation/RelNotes/1.7.3.4.txt index 925178f608..e57f7c176d 100644 --- a/Documentation/RelNotes/1.7.3.4.txt +++ b/Documentation/RelNotes/1.7.3.4.txt @@ -14,6 +14,11 @@ Fixes since v1.7.3.3 colon between the hours and minutes part (e.g. "-08:00" instead of "-0800"). + * "git checkout" removed an untracked file "foo" from the working + tree when switching to a branch that contains a tracked path + "foo/bar". Prevent this, just like the case where the conflicting + path were "foo" (c752e7f..7980872d). + * "git cherry-pick" or "git revert" refused to work when a path that would be modified by the operation was stat-dirty without a real difference in the contents of the file. @@ -21,12 +26,20 @@ Fixes since v1.7.3.3 * "git diff --check" reported an incorrect line number for added blank lines at the end of file. + * "git imap-send" failed to build under NO_OPENSSL. + * Setting log.decorate configuration variable to "0" or "1" to mean "false" or "true" did not work. + * "git push" over dumb HTTP protocol did not work against WebDAV + servers that did not terminate a collection name with a slash. + * "git tag -v" did not work with GPG signatures in rfc1991 mode. * The post-receive-email sample hook was accidentally broken in 1.7.3.3 update. + * "gitweb" can sometimes be tricked into parrotting a filename argument + given in a request without properly quoting. + Other minor fixes and documentation updates are also included. diff --git a/Documentation/RelNotes/1.7.4.txt b/Documentation/RelNotes/1.7.4.txt index c1d06694e1..ace061f5fe 100644 --- a/Documentation/RelNotes/1.7.4.txt +++ b/Documentation/RelNotes/1.7.4.txt @@ -4,6 +4,10 @@ Git v1.7.4 Release Notes (draft) Updates since v1.7.3 -------------------- + * The documentation Makefile now assumes by default asciidoc 8 and + docbook-xsl >= 1.73. If you have older versions, you can set + ASCIIDOC7 and ASCIIDOC_ROFF, respectively. + * The option parsers of various commands that create new branch (or rename existing ones to a new name) were too loose and users were allowed to call a branch with a name that begins with a dash by @@ -25,17 +29,42 @@ Updates since v1.7.3 * Bash completion script in contrib/ has been adjusted to be also usable by zsh. + * Different pagers can be chosen depending on which subcommand is + being run under the pager, using "pager.<subcommand>" variable. + + * The hardcoded tab-width of 8 used in whitespace breakage checks is now + configurable via the attributes mechanism. + + * Support of case insensitive filesystems (i.e. "core.ignorecase") has + been improved. For example, the gitignore mechanism didn't pay attention + to the case insensitivity. + + * The <tree>:<path> syntax to name a blob in a tree, and :<path> + syntax to name a blob in the index (e.g. "master:Makefile", + ":hello.c") have been extended. You can start <path> with "./" to + implicitly have the (sub)directory you are in prefixed to the + lookup. Similarly, ":../Makefile" from a subdirectory would mean + "the Makefile of the parent directory in the index". + * "git blame" learned --show-email option to display the e-mail addresses instead of the names of authors. + * "git commit" learned --fixup and --squash options to help later invocation + of the interactive rebase. + * "git daemon" can be built in MinGW environment. * "git daemon" can take more than one --listen option to listen to multiple addresses. + * "git describe --exact-match" was optimized not to read commit + objects unnecessarily. + * "git diff" and "git grep" learned how functions and subroutines in Fortran look like. + * "git fetch" learned "--recurse-submodules" option. + * "git mergetool" tells vim/gvim to show three-way diff by default (use vimdiff2/gvimdiff2 as the tool name for old behaviour). @@ -77,11 +106,16 @@ Updates since v1.7.3 git-only login over ssh as login shell, with custom set of commands. + * The current branch name in "git status" output can be colored differently + from the generic header color by setting "color.status.branch" variable. + * "git submodule sync" updates metainformation for all submodules, not just the ones that have been checked out. * gitweb can use custom 'highlight' command with its configuration file. + * other gitweb updates. + Also contains various documentation updates. @@ -92,11 +126,6 @@ Fixes since v1.7.3 All of the fixes in v1.7.3.X maintenance series are included in this release, unless otherwise noted. - * "git checkout" removed an untracked file "foo" from the working - tree when switching to a branch that contains a tracked path - "foo/bar". Prevent this, just like the case where the conflicting - path were "foo" (c752e7f..7980872d). - * "git log --author=me --author=her" did not find commits written by me or by her; instead it looked for commits written by me and by her, which is impossible. @@ -114,6 +143,6 @@ release, unless otherwise noted. --- exec >/var/tmp/1 -O=v1.7.3.2-450-g5b9c331 +O=v1.7.3.4-567-g38a5932 echo O=$(git describe master) git shortlog --no-merges ^maint ^$O master diff --git a/Documentation/config.txt b/Documentation/config.txt index 0f8579331e..54597f1897 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -522,6 +522,9 @@ core.whitespace:: part of the line terminator, i.e. with it, `trailing-space` does not trigger if the character before such a carriage-return is not a whitespace (not enabled by default). +* `tabwidth=<n>` tells how many character positions a tab occupies; this + is relevant for `indent-with-non-tab` and when git fixes `tab-in-indent` + errors. The default tab width is 8. Allowed values are 1 to 63. core.fsyncobjectfiles:: This boolean will enable 'fsync()' when writing object files. @@ -787,7 +790,8 @@ color.status.<slot>:: one of `header` (the header text of the status message), `added` or `updated` (files which are added but not committed), `changed` (files which are changed but not added in the index), - `untracked` (files which are not tracked by git), or + `untracked` (files which are not tracked by git), + `branch` (the current branch), or `nobranch` (the color the 'no branch' warning is shown in, defaulting to red). The values of these variables may be specified as in color.branch.<slot>. @@ -893,6 +897,11 @@ diff.wordRegex:: sequences that match the regular expression are "words", all other characters are *ignorable* whitespace. +fetch.recurseSubmodules:: + A boolean value which changes the behavior for fetch and pull, the + default is to not recursively fetch populated sumodules unless + configured otherwise. + fetch.unpackLimit:: If the number of objects fetched over the git native transfer is below this @@ -987,7 +996,7 @@ gc.packrefs:: Running `git pack-refs` in a repository renders it unclonable by Git versions prior to 1.5.1.2 over dumb transports such as HTTP. This variable determines whether - 'git gc' runs `git pack-refs`. This can be set to `nobare` + 'git gc' runs `git pack-refs`. This can be set to `notbare` to enable it within all non-bare repos or it can be set to a boolean value. The default is `true`. @@ -1807,6 +1816,13 @@ submodule.<name>.update:: URL and other values found in the `.gitmodules` file. See linkgit:git-submodule[1] and linkgit:gitmodules[5] for details. +submodule.<name>.fetchRecurseSubmodules:: + This option can be used to enable/disable recursive fetching of this + submodule. It can be overriden by using the --[no-]recurse-submodules + command line option to "git fetch" and "git pull". + This setting will override that from in the linkgit:gitmodules[5] + file. + submodule.<name>.ignore:: Defines under what circumstances "git status" and the diff family show a submodule as modified. When set to "all", it will never be considered diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index f3e95389aa..c93124be79 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -230,7 +230,7 @@ eligible for being picked up as a possible source of a rename to another file. -M[<n>]:: ---detect-renames[=<n>]:: +--find-renames[=<n>]:: ifndef::git-log[] Detect renames. endif::git-log[] @@ -246,7 +246,7 @@ endif::git-log[] hasn't changed. -C[<n>]:: ---detect-copies[=<n>]:: +--find-copies[=<n>]:: Detect copies as well as renames. See also `--find-copies-harder`. If `n` is specified, it has the same meaning as for `-M<n>`. diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt index 678675ccdf..695696da1b 100644 --- a/Documentation/fetch-options.txt +++ b/Documentation/fetch-options.txt @@ -66,6 +66,17 @@ ifndef::git-pull[] linkgit:git-config[1]. endif::git-pull[] +--[no-]recurse-submodules:: + This option controls if new commits of all populated submodules should + be fetched too (see linkgit:git-config[1] and linkgit:gitmodules[5]). + +ifndef::git-pull[] +--submodule-prefix=<path>:: + Prepend <path> to paths printed in informative messages + such as "Fetching submodule foo". This option is used + internally when recursing over submodules. +endif::git-pull[] + -u:: --update-head-ok:: By default 'git fetch' refuses to update the head which diff --git a/Documentation/git-difftool.txt b/Documentation/git-difftool.txt index 6fffbc7bf8..db87f1d423 100644 --- a/Documentation/git-difftool.txt +++ b/Documentation/git-difftool.txt @@ -56,14 +56,16 @@ the configured command line will be invoked with the following variables available: `$LOCAL` is set to the name of the temporary file containing the contents of the diff pre-image and `$REMOTE` is set to the name of the temporary file containing the contents -of the diff post-image. `$BASE` is provided for compatibility -with custom merge tool commands and has the same value as `$LOCAL`. +of the diff post-image. `$MERGED` is the name of the file which is +being compared. `$BASE` is provided for compatibility +with custom merge tool commands and has the same value as `$MERGED`. -x <command>:: --extcmd=<command>:: Specify a custom command for viewing diffs. 'git-difftool' ignores the configured defaults and runs `$command $LOCAL $REMOTE` when this option is specified. + Additionally, `$BASE` is set in the environment. -g:: --gui:: diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt index 5d0c245e38..f56dfcabb9 100644 --- a/Documentation/git-fast-import.txt +++ b/Documentation/git-fast-import.txt @@ -92,6 +92,11 @@ OPTIONS --(no-)-relative-marks= with the --(import|export)-marks= options. +--cat-blob-fd=<fd>:: + Specify the file descriptor that will be written to + when the `cat-blob` command is encountered in the stream. + The default behaviour is to write to `stdout`. + --export-pack-edges=<file>:: After creating a packfile, print a line of data to <file> listing the filename of the packfile and the last @@ -320,6 +325,11 @@ and control the current import process. More detailed discussion standard output. This command is optional and is not needed to perform an import. +`cat-blob`:: + Causes fast-import to print a blob in 'cat-file --batch' + format to the file descriptor set with `--cat-blob-fd` or + `stdout` if unspecified. + `feature`:: Require that fast-import supports the specified feature, or abort if it does not. @@ -879,34 +889,65 @@ Placing a `progress` command immediately after a `checkpoint` will inform the reader when the `checkpoint` has been completed and it can safely access the refs that fast-import updated. -`feature` -~~~~~~~~~ -Require that fast-import supports the specified feature, or abort if -it does not. +`cat-blob` +~~~~~~~~~~ +Causes fast-import to print a blob to a file descriptor previously +arranged with the `--cat-blob-fd` argument. The command otherwise +has no impact on the current import; its main purpose is to +retrieve blobs that may be in fast-import's memory but not +accessible from the target repository. .... - 'feature' SP <feature> LF + 'cat-blob' SP <dataref> LF .... -The <feature> part of the command may be any string matching -^[a-zA-Z][a-zA-Z-]*$ and should be understood by fast-import. +The `<dataref>` can be either a mark reference (`:<idnum>`) +set previously or a full 40-byte SHA-1 of a Git blob, preexisting or +ready to be written. -Feature work identical as their option counterparts with the -exception of the import-marks feature, see below. +output uses the same format as `git cat-file --batch`: -The following features are currently supported: +==== + <sha1> SP 'blob' SP <size> LF + <contents> LF +==== -* date-format -* import-marks -* export-marks -* relative-marks -* no-relative-marks -* force +This command can be used anywhere in the stream that comments are +accepted. In particular, the `cat-blob` command can be used in the +middle of a commit but not in the middle of a `data` command. -The import-marks behaves differently from when it is specified as -commandline option in that only one "feature import-marks" is allowed -per stream. Also, any --import-marks= specified on the commandline -will override those from the stream (if any). +`feature` +~~~~~~~~~ +Require that fast-import supports the specified feature, or abort if +it does not. + +.... + 'feature' SP <feature> ('=' <argument>)? LF +.... + +The <feature> part of the command may be any one of the following: + +date-format:: +export-marks:: +relative-marks:: +no-relative-marks:: +force:: + Act as though the corresponding command-line option with + a leading '--' was passed on the command line + (see OPTIONS, above). + +import-marks:: + Like --import-marks except in two respects: first, only one + "feature import-marks" command is allowed per stream; + second, an --import-marks= command-line option overrides + any "feature import-marks" command in the stream. + +cat-blob:: + Ignored. Versions of fast-import not supporting the + "cat-blob" command will exit with a message indicating so. + This lets the import error out early with a clear message, + rather than wasting time on the early part of an import + before the unsupported command is detected. `option` ~~~~~~~~ @@ -933,6 +974,7 @@ not be passed as option: * date-format * import-marks * export-marks +* cat-blob-fd * force Crash Reports @@ -1233,6 +1275,13 @@ and lazy loading of subtrees, allows fast-import to efficiently import projects with 2,000+ branches and 45,114+ files in a very limited memory footprint (less than 2.7 MiB per active branch). +Signals +------- +Sending *SIGUSR1* to the 'git fast-import' process ends the current +packfile early, simulating a `checkpoint` command. The impatient +operator can use this facility to peek at the objects and refs from an +import in progress, at the cost of some added running time and worse +compression. Author ------ diff --git a/Documentation/git-fsck.txt b/Documentation/git-fsck.txt index 3ad48a6336..86f9b2bf91 100644 --- a/Documentation/git-fsck.txt +++ b/Documentation/git-fsck.txt @@ -123,9 +123,6 @@ dangling <type> <object>:: The <type> object <object>, is present in the database but never 'directly' used. A dangling commit could be a root node. -warning: git-fsck: tree <tree> has full pathnames in it:: - And it shouldn't... - sha1 mismatch <object>:: The database has an object who's sha1 doesn't match the database value. diff --git a/Documentation/git-gc.txt b/Documentation/git-gc.txt index 801aede609..26632414b2 100644 --- a/Documentation/git-gc.txt +++ b/Documentation/git-gc.txt @@ -107,7 +107,7 @@ how long records of conflicted merge you have not resolved are kept. This defaults to 15 days. The optional configuration variable 'gc.packrefs' determines if -'git gc' runs 'git pack-refs'. This can be set to "nobare" to enable +'git gc' runs 'git pack-refs'. This can be set to "notbare" to enable it within all non-bare repos or it can be set to a boolean value. This defaults to true. diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt index 4db73737b0..30466917da 100644 --- a/Documentation/git-pull.txt +++ b/Documentation/git-pull.txt @@ -98,8 +98,9 @@ include::merge-options.txt[] fetched, the rebase uses that information to avoid rebasing non-local changes. + -See `branch.<name>.rebase` in linkgit:git-config[1] if you want to make -`git pull` always use `{litdd}rebase` instead of merging. +See `branch.<name>.rebase` and `branch.autosetuprebase` in +linkgit:git-config[1] if you want to make `git pull` always use +`{litdd}rebase` instead of merging. + [NOTE] This is a potentially _dangerous_ mode of operation. diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index 30e5c0eb14..96680c8456 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -279,6 +279,10 @@ which makes little sense. --no-verify:: This option bypasses the pre-rebase hook. See also linkgit:githooks[5]. +--verify:: + Allows the pre-rebase hook to run, which is the default. This option can + be used to override --no-verify. See also linkgit:githooks[5]. + -C<n>:: Ensure at least <n> lines of surrounding context match before and after each change. When fewer lines of surrounding diff --git a/Documentation/git-web--browse.txt b/Documentation/git-web--browse.txt index 51e8e0af1e..c0416e5e1a 100644 --- a/Documentation/git-web--browse.txt +++ b/Documentation/git-web--browse.txt @@ -20,8 +20,14 @@ The following browsers (or commands) are currently supported: * firefox (this is the default under X Window when not using KDE) * iceweasel +* seamonkey +* iceape +* chromium (also supported as chromium-browser) +* google-chrome (also supported as chrome) * konqueror (this is the default under KDE, see 'Note about konqueror' below) +* opera * w3m (this is the default outside graphical environments) +* elinks * links * lynx * dillo diff --git a/Documentation/git.txt b/Documentation/git.txt index 8216083081..012837145e 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -44,34 +44,38 @@ 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.3.3/git.html[documentation for release 1.7.3.3] +* link:v1.7.3.4/git.html[documentation for release 1.7.3.4] * release notes for + link:RelNotes/1.7.3.4.txt[1.7.3.4], link:RelNotes/1.7.3.3.txt[1.7.3.3], link:RelNotes/1.7.3.2.txt[1.7.3.2], link:RelNotes/1.7.3.1.txt[1.7.3.1], link:RelNotes/1.7.3.txt[1.7.3]. -* link:v1.7.2.4/git.html[documentation for release 1.7.2.4] +* link:v1.7.2.5/git.html[documentation for release 1.7.2.5] * release notes for + link:RelNotes/1.7.2.5.txt[1.7.2.5], link:RelNotes/1.7.2.4.txt[1.7.2.4], link:RelNotes/1.7.2.3.txt[1.7.2.3], link:RelNotes/1.7.2.2.txt[1.7.2.2], link:RelNotes/1.7.2.1.txt[1.7.2.1], link:RelNotes/1.7.2.txt[1.7.2]. -* link:v1.7.1.3/git.html[documentation for release 1.7.1.3] +* link:v1.7.1.4/git.html[documentation for release 1.7.1.4] * release notes for + link:RelNotes/1.7.1.4.txt[1.7.1.4], link:RelNotes/1.7.1.3.txt[1.7.1.3], link:RelNotes/1.7.1.2.txt[1.7.1.2], link:RelNotes/1.7.1.1.txt[1.7.1.1], link:RelNotes/1.7.1.txt[1.7.1]. -* link:v1.7.0.8/git.html[documentation for release 1.7.0.8] +* link:v1.7.0.9/git.html[documentation for release 1.7.0.9] * release notes for + link:RelNotes/1.7.0.9.txt[1.7.0.9], link:RelNotes/1.7.0.8.txt[1.7.0.8], link:RelNotes/1.7.0.7.txt[1.7.0.7], link:RelNotes/1.7.0.6.txt[1.7.0.6], @@ -82,16 +86,18 @@ Documentation for older releases are available here: link:RelNotes/1.7.0.1.txt[1.7.0.1], link:RelNotes/1.7.0.txt[1.7.0]. -* link:v1.6.6.2/git.html[documentation for release 1.6.6.2] +* link:v1.6.6.3/git.html[documentation for release 1.6.6.3] * release notes for + link:RelNotes/1.6.6.3.txt[1.6.6.3], link:RelNotes/1.6.6.2.txt[1.6.6.2], link:RelNotes/1.6.6.1.txt[1.6.6.1], link:RelNotes/1.6.6.txt[1.6.6]. -* link:v1.6.5.8/git.html[documentation for release 1.6.5.8] +* link:v1.6.5.9/git.html[documentation for release 1.6.5.9] * release notes for + link:RelNotes/1.6.5.9.txt[1.6.5.9], link:RelNotes/1.6.5.8.txt[1.6.5.8], link:RelNotes/1.6.5.7.txt[1.6.5.7], link:RelNotes/1.6.5.6.txt[1.6.5.6], @@ -102,9 +108,10 @@ Documentation for older releases are available here: link:RelNotes/1.6.5.1.txt[1.6.5.1], link:RelNotes/1.6.5.txt[1.6.5]. -* link:v1.6.4.4/git.html[documentation for release 1.6.4.4] +* link:v1.6.4.5/git.html[documentation for release 1.6.4.5] * release notes for + link:RelNotes/1.6.4.5.txt[1.6.4.5], link:RelNotes/1.6.4.4.txt[1.6.4.4], link:RelNotes/1.6.4.3.txt[1.6.4.3], link:RelNotes/1.6.4.2.txt[1.6.4.2], diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index c80ca5da43..5a7f936429 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -723,6 +723,8 @@ control per path. Set:: Notice all types of potential whitespace errors known to git. + The tab width is taken from the value of the `core.whitespace` + configuration variable. Unset:: @@ -730,13 +732,13 @@ Unset:: Unspecified:: - Use the value of `core.whitespace` configuration variable to + Use the value of the `core.whitespace` configuration variable to decide what to notice as error. String:: Specify a comma separate list of common whitespace problems to - notice in the same format as `core.whitespace` configuration + notice in the same format as the `core.whitespace` configuration variable. diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt index bcffd95ada..6c93202e73 100644 --- a/Documentation/gitmodules.txt +++ b/Documentation/gitmodules.txt @@ -44,6 +44,14 @@ submodule.<name>.update:: This config option is overridden if 'git submodule update' is given the '--merge' or '--rebase' options. +submodule.<name>.fetchRecurseSubmodules:: + This option can be used to enable/disable recursive fetching of this + submodule. If this option is also present in the submodules entry in + .git/config of the superproject, the setting there will override the + one found in .gitmodules. + Both settings can be overriden on the command line by using the + "--[no-]recurse-submodules" option to "git fetch" and "git pull".. + submodule.<name>.ignore:: Defines under what circumstances "git status" and the diff family show a submodule as modified. When set to "all", it will never be considered diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt index 174fa8e90d..9e92734bc1 100644 --- a/Documentation/revisions.txt +++ b/Documentation/revisions.txt @@ -127,6 +127,10 @@ the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file. ':path' (with an empty part before the colon, e.g. `:README`) is a special case of the syntax described next: content recorded in the index at the given path. + A path starting with './' or '../' is relative to current working directory. + The given path will be converted to be relative to working tree's root directory. + This is most useful to address a blob or tree from a commit or tree that has + the same tree structure with the working tree. * A colon, optionally followed by a stage number (0 to 3) and a colon, followed by a path (e.g. `:0:README`); this names a blob object in the @@ -122,8 +122,9 @@ Issues of note: Building and installing the pdf file additionally requires dblatex. Version 0.2.7 with asciidoc >= 8.2.7 is known to work. - The documentation is written for AsciiDoc 7, but "make - ASCIIDOC8=YesPlease doc" will let you format with AsciiDoc 8. + The documentation is written for AsciiDoc 7, but by default + uses some compatibility wrappers to work on AsciiDoc 8. If you have + AsciiDoc 7, try "make ASCIIDOC7=YesPlease". Alternatively, pre-formatted documentation is available in "html" and "man" branches of the git repository itself. For @@ -167,13 +167,13 @@ all:: # Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks # field that counts the on-disk footprint in 512-byte blocks. # -# Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8 +# Define ASCIIDOC7 if you want to format documentation with AsciiDoc 7 # # Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72 # (not v1.73 or v1.71). # -# Define ASCIIDOC_NO_ROFF if your DocBook XSL escapes raw roff directives -# (versions 1.72 and later and 1.68.1 and earlier). +# Define ASCIIDOC_ROFF if your DocBook XSL does not escape raw roff directives +# (versions 1.68.1 through v1.72). # # Define GNU_ROFF if your target system uses GNU groff. This forces # apostrophes to be ASCII so that cut&pasting examples to the shell @@ -504,6 +504,7 @@ LIB_H += compat/mingw.h LIB_H += compat/win32/pthread.h LIB_H += compat/win32/syslog.h LIB_H += compat/win32/sys/poll.h +LIB_H += compat/win32/dirent.h LIB_H += csum-file.h LIB_H += decorate.h LIB_H += delta.h @@ -1096,10 +1097,12 @@ ifeq ($(uname_S),Windows) AR = compat/vcbuild/scripts/lib.pl CFLAGS = BASIC_CFLAGS = -nologo -I. -I../zlib -Icompat/vcbuild -Icompat/vcbuild/include -DWIN32 -D_CONSOLE -DHAVE_STRING_H -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE - COMPAT_OBJS = compat/msvc.o compat/winansi.o compat/win32/pthread.o compat/win32/syslog.o compat/win32/sys/poll.o + COMPAT_OBJS = compat/msvc.o compat/winansi.o \ + compat/win32/pthread.o compat/win32/syslog.o \ + compat/win32/sys/poll.o compat/win32/dirent.o COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\" BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib - EXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib + EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib PTHREAD_LIBS = lib = ifndef DEBUG @@ -1169,7 +1172,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" COMPAT_OBJS += compat/mingw.o compat/winansi.o \ compat/win32/pthread.o compat/win32/syslog.o \ - compat/win32/sys/poll.o + compat/win32/sys/poll.o compat/win32/dirent.o EXTLIBS += -lws2_32 PTHREAD_LIBS = X = .exe @@ -1300,11 +1303,15 @@ else BLK_SHA1 = 1 OPENSSL_LIBSSL = endif +ifdef NO_OPENSSL + LIB_4_CRYPTO = +else ifdef NEEDS_SSL_WITH_CRYPTO LIB_4_CRYPTO = $(OPENSSL_LINK) -lcrypto -lssl else LIB_4_CRYPTO = $(OPENSSL_LINK) -lcrypto endif +endif ifdef NEEDS_LIBICONV ifdef ICONVDIR BASIC_CFLAGS += -I$(ICONVDIR)/include @@ -1579,8 +1586,8 @@ ifndef V endif endif -ifdef ASCIIDOC8 - export ASCIIDOC8 +ifdef ASCIIDOC7 + export ASCIIDOC7 endif # Shell quote (do not use $(call) to accommodate ancient setups); @@ -1672,6 +1679,8 @@ git$X: git.o $(BUILTIN_OBJS) $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \ $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS) +help.o: common-cmds.h + builtin/help.o: common-cmds.h builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \ '-DGIT_HTML_PATH="$(htmldir_SQ)"' \ @@ -1945,7 +1954,7 @@ builtin/commit.o builtin/revert.o wt-status.o: wt-status.h builtin/tar-tree.o archive-tar.o: tar.h connect.o transport.o http-backend.o: url.h http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h -http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h +http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h xdiff-interface.o $(XDIFF_OBJS): \ xdiff/xinclude.h xdiff/xmacros.h xdiff/xdiff.h xdiff/xtypes.h \ diff --git a/builtin/blame.c b/builtin/blame.c index cb25ec9ce8..aa30ec5269 100644 --- a/builtin/blame.c +++ b/builtin/blame.c @@ -2325,8 +2325,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix) save_commit_buffer = 0; dashdash_pos = 0; - parse_options_start(&ctx, argc, argv, prefix, PARSE_OPT_KEEP_DASHDASH | - PARSE_OPT_KEEP_ARGV0); + parse_options_start(&ctx, argc, argv, prefix, options, + PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0); for (;;) { switch (parse_options_step(&ctx, options, blame_opt_usage)) { case PARSE_OPT_HELP: diff --git a/builtin/branch.c b/builtin/branch.c index 807355a198..9e546e4a83 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -313,12 +313,7 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags, (struct object *)commit, refname); } - /* Resize buffer */ - if (ref_list->index >= ref_list->alloc) { - ref_list->alloc = alloc_nr(ref_list->alloc); - ref_list->list = xrealloc(ref_list->list, - ref_list->alloc * sizeof(struct ref_item)); - } + ALLOC_GROW(ref_list->list, ref_list->index + 1, ref_list->alloc); /* Record the new item */ newitem = &(ref_list->list[ref_list->index++]); @@ -668,6 +663,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix) OPT_END(), }; + if (argc == 2 && !strcmp(argv[1], "-h")) + usage_with_options(builtin_branch_usage, options); + git_config(git_branch_config, NULL); if (branch_use_color == -1) diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c index 1ee3044307..f1fec24745 100644 --- a/builtin/checkout-index.c +++ b/builtin/checkout-index.c @@ -241,6 +241,9 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) OPT_END() }; + if (argc == 2 && !strcmp(argv[1], "-h")) + usage_with_options(builtin_checkout_index_usage, + builtin_checkout_index_options); git_config(git_default_config, NULL); state.base_dir = ""; prefix_length = prefix ? strlen(prefix) : 0; diff --git a/builtin/commit.c b/builtin/commit.c index 6d867d4018..6c09857a60 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -1011,6 +1011,8 @@ static int parse_status_slot(const char *var, int offset) { if (!strcasecmp(var+offset, "header")) return WT_STATUS_HEADER; + if (!strcasecmp(var+offset, "branch")) + return WT_STATUS_ONBRANCH; if (!strcasecmp(var+offset, "updated") || !strcasecmp(var+offset, "added")) return WT_STATUS_UPDATED; @@ -1097,6 +1099,9 @@ int cmd_status(int argc, const char **argv, const char *prefix) OPT_END(), }; + if (argc == 2 && !strcmp(argv[1], "-h")) + usage_with_options(builtin_status_usage, builtin_status_options); + if (null_termination && status_format == STATUS_FORMAT_LONG) status_format = STATUS_FORMAT_PORCELAIN; @@ -1282,6 +1287,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix) int allow_fast_forward = 1; struct wt_status s; + if (argc == 2 && !strcmp(argv[1], "-h")) + usage_with_options(builtin_commit_usage, builtin_commit_options); + wt_status_prepare(&s); git_config(git_commit_config, &s); in_merge = file_exists(git_path("MERGE_HEAD")); diff --git a/builtin/describe.c b/builtin/describe.c index 43caff2ffe..a0f52c1b72 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -6,6 +6,7 @@ #include "exec_cmd.h" #include "parse-options.h" #include "diff.h" +#include "hash.h" #define SEEN (1u<<0) #define MAX_TAGS (FLAG_BITS - 1) @@ -22,7 +23,8 @@ static int tags; /* Allow lightweight tags */ static int longformat; static int abbrev = DEFAULT_ABBREV; static int max_candidates = 10; -static int found_names; +static struct hash_table names; +static int have_util; static const char *pattern; static int always; static const char *dirty; @@ -34,16 +36,44 @@ static const char *diff_index_args[] = { struct commit_name { + struct commit_name *next; + unsigned char peeled[20]; struct tag *tag; unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */ unsigned name_checked:1; unsigned char sha1[20]; - char path[FLEX_ARRAY]; /* more */ + const char *path; }; static const char *prio_names[] = { "head", "lightweight", "annotated", }; +static inline unsigned int hash_sha1(const unsigned char *sha1) +{ + unsigned int hash; + memcpy(&hash, sha1, sizeof(hash)); + return hash; +} + +static inline struct commit_name *find_commit_name(const unsigned char *peeled) +{ + struct commit_name *n = lookup_hash(hash_sha1(peeled), &names); + while (n && !!hashcmp(peeled, n->peeled)) + n = n->next; + return n; +} + +static int set_util(void *chain) +{ + struct commit_name *n; + for (n = chain; n; n = n->next) { + struct commit *c = lookup_commit_reference_gently(n->peeled, 1); + if (c) + c->util = n; + } + return 0; +} + static int replace_name(struct commit_name *e, int prio, const unsigned char *sha1, @@ -78,31 +108,36 @@ static int replace_name(struct commit_name *e, } static void add_to_known_names(const char *path, - struct commit *commit, + const unsigned char *peeled, int prio, const unsigned char *sha1) { - struct commit_name *e = commit->util; + struct commit_name *e = find_commit_name(peeled); struct tag *tag = NULL; if (replace_name(e, prio, sha1, &tag)) { - size_t len = strlen(path)+1; - free(e); - e = xmalloc(sizeof(struct commit_name) + len); + if (!e) { + void **pos; + e = xmalloc(sizeof(struct commit_name)); + hashcpy(e->peeled, peeled); + pos = insert_hash(hash_sha1(peeled), e, &names); + if (pos) { + e->next = *pos; + *pos = e; + } else { + e->next = NULL; + } + } e->tag = tag; e->prio = prio; e->name_checked = 0; hashcpy(e->sha1, sha1); - memcpy(e->path, path, len); - commit->util = e; + e->path = path; } - found_names = 1; } static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data) { int might_be_tag = !prefixcmp(path, "refs/tags/"); - struct commit *commit; - struct object *object; unsigned char peeled[20]; int is_tag, prio; @@ -110,16 +145,10 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void return 0; if (!peel_ref(path, peeled) && !is_null_sha1(peeled)) { - commit = lookup_commit_reference_gently(peeled, 1); - if (!commit) - return 0; - is_tag = !!hashcmp(sha1, commit->object.sha1); + is_tag = !!hashcmp(sha1, peeled); } else { - commit = lookup_commit_reference_gently(sha1, 1); - object = parse_object(sha1); - if (!commit || !object) - return 0; - is_tag = object->type == OBJ_TAG; + hashcpy(peeled, sha1); + is_tag = 0; } /* If --all, then any refs are used. @@ -142,7 +171,7 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void if (!prio) return 0; } - add_to_known_names(all ? path + 5 : path + 10, commit, prio, sha1); + add_to_known_names(all ? path + 5 : path + 10, peeled, prio, sha1); return 0; } @@ -240,7 +269,7 @@ static void describe(const char *arg, int last_one) if (!cmit) die("%s is not a valid '%s' object", arg, commit_type); - n = cmit->util; + n = find_commit_name(cmit->object.sha1); if (n && (tags || all || n->prio == 2)) { /* * Exact match to an existing ref. @@ -259,6 +288,11 @@ static void describe(const char *arg, int last_one) if (debug) fprintf(stderr, "searching to describe %s\n", arg); + if (!have_util) { + for_each_hash(&names, set_util); + have_util = 1; + } + list = NULL; cmit->object.flags = SEEN; commit_list_insert(cmit, &list); @@ -418,8 +452,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix) return cmd_name_rev(i + argc, args, prefix); } - for_each_ref(get_name, NULL); - if (!found_names && !always) + init_hash(&names); + for_each_rawref(get_name, NULL); + if (!names.nr && !always) die("No names found, cannot describe anything."); if (argc == 0) { diff --git a/builtin/fetch.c b/builtin/fetch.c index 6bcce55c0c..357f3cdbbf 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -12,6 +12,7 @@ #include "parse-options.h" #include "sigchain.h" #include "transport.h" +#include "submodule.h" static const char * const builtin_fetch_usage[] = { "git fetch [<options>] [<repository> [<refspec>...]]", @@ -27,13 +28,20 @@ enum { TAGS_SET = 2 }; +enum { + RECURSE_SUBMODULES_OFF = 0, + RECURSE_SUBMODULES_DEFAULT = 1, + RECURSE_SUBMODULES_ON = 2 +}; + static int all, append, dry_run, force, keep, multiple, prune, update_head_ok, verbosity; -static int progress; +static int progress, recurse_submodules = RECURSE_SUBMODULES_DEFAULT; static int tags = TAGS_DEFAULT; static const char *depth; static const char *upload_pack; static struct strbuf default_rla = STRBUF_INIT; static struct transport *transport; +static const char *submodule_prefix = ""; static struct option builtin_fetch_options[] = { OPT__VERBOSITY(&verbosity), @@ -52,6 +60,9 @@ static struct option builtin_fetch_options[] = { "do not fetch all tags (--no-tags)", TAGS_UNSET), OPT_BOOLEAN('p', "prune", &prune, "prune remote-tracking branches no longer on remote"), + OPT_SET_INT(0, "recurse-submodules", &recurse_submodules, + "control recursive fetching of submodules", + RECURSE_SUBMODULES_ON), OPT_BOOLEAN(0, "dry-run", &dry_run, "dry run"), OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"), @@ -60,6 +71,8 @@ static struct option builtin_fetch_options[] = { OPT_BOOLEAN(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", + "prepend this to submodule path output", PARSE_OPT_HIDDEN }, OPT_END() }; @@ -783,28 +796,36 @@ static int add_remote_or_group(const char *name, struct string_list *list) return 1; } -static int fetch_multiple(struct string_list *list) +static void add_options_to_argv(int *argc, const char **argv) { - int i, result = 0; - const char *argv[11] = { "fetch", "--append" }; - int argc = 2; - if (dry_run) - argv[argc++] = "--dry-run"; + argv[(*argc)++] = "--dry-run"; if (prune) - argv[argc++] = "--prune"; + argv[(*argc)++] = "--prune"; if (update_head_ok) - argv[argc++] = "--update-head-ok"; + argv[(*argc)++] = "--update-head-ok"; if (force) - argv[argc++] = "--force"; + argv[(*argc)++] = "--force"; if (keep) - argv[argc++] = "--keep"; + argv[(*argc)++] = "--keep"; + if (recurse_submodules == RECURSE_SUBMODULES_ON) + argv[(*argc)++] = "--recurse-submodules"; if (verbosity >= 2) - argv[argc++] = "-v"; + argv[(*argc)++] = "-v"; if (verbosity >= 1) - argv[argc++] = "-v"; + argv[(*argc)++] = "-v"; else if (verbosity < 0) - argv[argc++] = "-q"; + argv[(*argc)++] = "-q"; + +} + +static int fetch_multiple(struct string_list *list) +{ + int i, result = 0; + const char *argv[12] = { "fetch", "--append" }; + int argc = 2; + + add_options_to_argv(&argc, argv); if (!append && !dry_run) { int errcode = truncate_fetch_head(); @@ -925,6 +946,21 @@ int cmd_fetch(int argc, const char **argv, const char *prefix) } } + if (!result && (recurse_submodules != RECURSE_SUBMODULES_OFF)) { + const char *options[10]; + int num_options = 0; + /* Set recursion as default when we already are recursing */ + if (submodule_prefix[0]) + set_config_fetch_recurse_submodules(1); + gitmodules_config(); + git_config(submodule_config, NULL); + add_options_to_argv(&num_options, options); + result = fetch_populated_submodules(num_options, options, + submodule_prefix, + recurse_submodules == RECURSE_SUBMODULES_ON, + verbosity < 0); + } + /* All names were strdup()ed or strndup()ed */ list.strdup_strings = 1; string_list_clear(&list, 0); diff --git a/builtin/gc.c b/builtin/gc.c index 397a1e6eb3..1a80702b3d 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -189,6 +189,9 @@ int cmd_gc(int argc, const char **argv, const char *prefix) OPT_END() }; + if (argc == 2 && !strcmp(argv[1], "-h")) + usage_with_options(builtin_gc_usage, builtin_gc_options); + git_config(gc_config, NULL); if (pack_refs < 0) diff --git a/builtin/log.c b/builtin/log.c index 4191d9c4e5..d8c6c28d2f 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -1158,6 +1158,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (!use_stdout) output_directory = set_outdir(prefix, output_directory); + else + setup_pager(); if (output_directory) { if (use_stdout) diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 6a307ab784..fb2d5f4b1f 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -530,6 +530,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) OPT_END() }; + if (argc == 2 && !strcmp(argv[1], "-h")) + usage_with_options(ls_files_usage, builtin_ls_files_options); + memset(&dir, 0, sizeof(dir)); prefix = cmd_prefix; if (prefix) diff --git a/builtin/merge.c b/builtin/merge.c index 3921cd3040..42fff387e6 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -922,6 +922,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix) const char *best_strategy = NULL, *wt_strategy = NULL; struct commit_list **remotes = &remoteheads; + if (argc == 2 && !strcmp(argv[1], "-h")) + usage_with_options(builtin_merge_usage, builtin_merge_options); + /* * Check if we are _not_ on a detached HEAD, i.e. if there is a * current branch. diff --git a/builtin/rm.c b/builtin/rm.c index c7b7bb37a2..ff491d7761 100644 --- a/builtin/rm.c +++ b/builtin/rm.c @@ -20,15 +20,6 @@ static struct { const char **name; } list; -static void add_list(const char *name) -{ - if (list.nr >= list.alloc) { - list.alloc = alloc_nr(list.alloc); - list.name = xrealloc(list.name, list.alloc * sizeof(const char *)); - } - list.name[list.nr++] = name; -} - static int check_local_mod(unsigned char *head, int index_only) { /* @@ -182,7 +173,8 @@ int cmd_rm(int argc, const char **argv, const char *prefix) struct cache_entry *ce = active_cache[i]; if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen)) continue; - add_list(ce->name); + ALLOC_GROW(list.name, list.nr + 1, list.alloc); + list.name[list.nr++] = ce->name; } if (pathspec) { diff --git a/builtin/shortlog.c b/builtin/shortlog.c index 2135b0dde1..1a21e4b053 100644 --- a/builtin/shortlog.c +++ b/builtin/shortlog.c @@ -268,8 +268,8 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix) git_config(git_default_config, NULL); shortlog_init(&log); init_revisions(&rev, prefix); - parse_options_start(&ctx, argc, argv, prefix, PARSE_OPT_KEEP_DASHDASH | - PARSE_OPT_KEEP_ARGV0); + parse_options_start(&ctx, argc, argv, prefix, options, + PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0); for (;;) { switch (parse_options_step(&ctx, options, shortlog_usage)) { diff --git a/builtin/update-index.c b/builtin/update-index.c index 62d9f3f0fa..56baf27fb7 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -10,6 +10,7 @@ #include "builtin.h" #include "refs.h" #include "resolve-undo.h" +#include "parse-options.h" /* * Default to not allowing changes to the list of files. The @@ -397,8 +398,10 @@ static void read_index_info(int line_termination) strbuf_release(&uq); } -static const char update_index_usage[] = -"git update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--skip-worktree|--no-skip-worktree] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again | -g] [--ignore-missing] [-z] [--verbose] [--] [<file>...]"; +static const char * const update_index_usage[] = { + "git update-index [options] [--] [<file>...]", + NULL +}; static unsigned char head_sha1[20]; static unsigned char merge_head_sha1[20]; @@ -578,16 +581,214 @@ static int do_reupdate(int ac, const char **av, return 0; } +struct refresh_params { + unsigned int flags; + int *has_errors; +}; + +static int refresh(struct refresh_params *o, unsigned int flag) +{ + setup_work_tree(); + *o->has_errors |= refresh_cache(o->flags | flag); + return 0; +} + +static int refresh_callback(const struct option *opt, + const char *arg, int unset) +{ + return refresh(opt->value, 0); +} + +static int really_refresh_callback(const struct option *opt, + const char *arg, int unset) +{ + return refresh(opt->value, REFRESH_REALLY); +} + +static int chmod_callback(const struct option *opt, + const char *arg, int unset) +{ + char *flip = opt->value; + if ((arg[0] != '-' && arg[0] != '+') || arg[1] != 'x' || arg[2]) + return error("option 'chmod' expects \"+x\" or \"-x\""); + *flip = arg[0]; + return 0; +} + +static int resolve_undo_clear_callback(const struct option *opt, + const char *arg, int unset) +{ + resolve_undo_clear(); + return 0; +} + +static int cacheinfo_callback(struct parse_opt_ctx_t *ctx, + const struct option *opt, int unset) +{ + unsigned char sha1[20]; + unsigned int mode; + + if (ctx->argc <= 3) + return error("option 'cacheinfo' expects three arguments"); + if (strtoul_ui(*++ctx->argv, 8, &mode) || + get_sha1_hex(*++ctx->argv, sha1) || + add_cacheinfo(mode, sha1, *++ctx->argv, 0)) + die("git update-index: --cacheinfo cannot add %s", *ctx->argv); + ctx->argc -= 3; + return 0; +} + +static int stdin_cacheinfo_callback(struct parse_opt_ctx_t *ctx, + const struct option *opt, int unset) +{ + int *line_termination = opt->value; + + if (ctx->argc != 1) + return error("option '%s' must be the last argument", opt->long_name); + allow_add = allow_replace = allow_remove = 1; + read_index_info(*line_termination); + return 0; +} + +static int stdin_callback(struct parse_opt_ctx_t *ctx, + const struct option *opt, int unset) +{ + int *read_from_stdin = opt->value; + + if (ctx->argc != 1) + return error("option '%s' must be the last argument", opt->long_name); + *read_from_stdin = 1; + return 0; +} + +static int unresolve_callback(struct parse_opt_ctx_t *ctx, + const struct option *opt, int flags) +{ + int *has_errors = opt->value; + const char *prefix = startup_info->prefix; + + /* consume remaining arguments. */ + *has_errors = do_unresolve(ctx->argc, ctx->argv, + prefix, prefix ? strlen(prefix) : 0); + if (*has_errors) + active_cache_changed = 0; + + ctx->argv += ctx->argc - 1; + ctx->argc = 1; + return 0; +} + +static int reupdate_callback(struct parse_opt_ctx_t *ctx, + const struct option *opt, int flags) +{ + int *has_errors = opt->value; + const char *prefix = startup_info->prefix; + + /* consume remaining arguments. */ + setup_work_tree(); + *has_errors = do_reupdate(ctx->argc, ctx->argv, + prefix, prefix ? strlen(prefix) : 0); + if (*has_errors) + active_cache_changed = 0; + + ctx->argv += ctx->argc - 1; + ctx->argc = 1; + return 0; +} + int cmd_update_index(int argc, const char **argv, const char *prefix) { - int i, newfd, entries, has_errors = 0, line_termination = '\n'; - int allow_options = 1; + int newfd, entries, has_errors = 0, line_termination = '\n'; int read_from_stdin = 0; int prefix_length = prefix ? strlen(prefix) : 0; char set_executable_bit = 0; - unsigned int refresh_flags = 0; + struct refresh_params refresh_args = {0, &has_errors}; int lock_error = 0; struct lock_file *lock_file; + struct parse_opt_ctx_t ctx; + int parseopt_state = PARSE_OPT_UNKNOWN; + struct option options[] = { + OPT_BIT('q', NULL, &refresh_args.flags, + "continue refresh even when index needs update", + REFRESH_QUIET), + OPT_BIT(0, "ignore-submodules", &refresh_args.flags, + "refresh: ignore submodules", + REFRESH_IGNORE_SUBMODULES), + OPT_SET_INT(0, "add", &allow_add, + "do not ignore new files", 1), + OPT_SET_INT(0, "replace", &allow_replace, + "let files replace directories and vice-versa", 1), + OPT_SET_INT(0, "remove", &allow_remove, + "notice files missing from worktree", 1), + OPT_BIT(0, "unmerged", &refresh_args.flags, + "refresh even if index contains unmerged entries", + REFRESH_UNMERGED), + {OPTION_CALLBACK, 0, "refresh", &refresh_args, NULL, + "refresh stat information", + PARSE_OPT_NOARG | PARSE_OPT_NONEG, + refresh_callback}, + {OPTION_CALLBACK, 0, "really-refresh", &refresh_args, NULL, + "like --refresh, but ignore assume-unchanged setting", + PARSE_OPT_NOARG | PARSE_OPT_NONEG, + really_refresh_callback}, + {OPTION_LOWLEVEL_CALLBACK, 0, "cacheinfo", NULL, + "<mode> <object> <path>", + "add the specified entry to the index", + PARSE_OPT_NOARG | /* disallow --cacheinfo=<mode> form */ + PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, + (parse_opt_cb *) cacheinfo_callback}, + {OPTION_CALLBACK, 0, "chmod", &set_executable_bit, "(+/-)x", + "override the executable bit of the listed files", + PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, + chmod_callback}, + {OPTION_SET_INT, 0, "assume-unchanged", &mark_valid_only, NULL, + "mark files as \"not changing\"", + PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG}, + {OPTION_SET_INT, 0, "no-assume-unchanged", &mark_valid_only, NULL, + "clear assumed-unchanged bit", + PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG}, + {OPTION_SET_INT, 0, "skip-worktree", &mark_skip_worktree_only, NULL, + "mark files as \"index-only\"", + PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG}, + {OPTION_SET_INT, 0, "no-skip-worktree", &mark_skip_worktree_only, NULL, + "clear skip-worktree bit", + PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG}, + OPT_SET_INT(0, "info-only", &info_only, + "add to index only; do not add content to object database", 1), + OPT_SET_INT(0, "force-remove", &force_remove, + "remove named paths even if present in worktree", 1), + OPT_SET_INT('z', NULL, &line_termination, + "with --stdin: input lines are terminated by null bytes", '\0'), + {OPTION_LOWLEVEL_CALLBACK, 0, "stdin", &read_from_stdin, NULL, + "read list of paths to be updated from standard input", + PARSE_OPT_NONEG | PARSE_OPT_NOARG, + (parse_opt_cb *) stdin_callback}, + {OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &line_termination, NULL, + "add entries from standard input to the index", + PARSE_OPT_NONEG | PARSE_OPT_NOARG, + (parse_opt_cb *) stdin_cacheinfo_callback}, + {OPTION_LOWLEVEL_CALLBACK, 0, "unresolve", &has_errors, NULL, + "repopulate stages #2 and #3 for the listed paths", + PARSE_OPT_NONEG | PARSE_OPT_NOARG, + (parse_opt_cb *) unresolve_callback}, + {OPTION_LOWLEVEL_CALLBACK, 'g', "again", &has_errors, NULL, + "only update entries that differ from HEAD", + PARSE_OPT_NONEG | PARSE_OPT_NOARG, + (parse_opt_cb *) reupdate_callback}, + OPT_BIT(0, "ignore-missing", &refresh_args.flags, + "ignore files missing from worktree", + REFRESH_IGNORE_MISSING), + OPT_SET_INT(0, "verbose", &verbose, + "report actions to standard output", 1), + {OPTION_CALLBACK, 0, "clear-resolve-undo", NULL, NULL, + "(for porcelains) forget saved unresolved conflicts", + PARSE_OPT_NOARG | PARSE_OPT_NONEG, + resolve_undo_clear_callback}, + OPT_END() + }; + + if (argc == 2 && !strcmp(argv[1], "-h")) + usage(update_index_usage[0]); git_config(git_default_config, NULL); @@ -602,151 +803,48 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) if (entries < 0) die("cache corrupted"); - for (i = 1 ; i < argc; i++) { - const char *path = argv[i]; - const char *p; + /* + * Custom copy of parse_options() because we want to handle + * filename arguments as they come. + */ + parse_options_start(&ctx, argc, argv, prefix, + options, PARSE_OPT_STOP_AT_NON_OPTION); + while (ctx.argc) { + if (parseopt_state != PARSE_OPT_DONE) + parseopt_state = parse_options_step(&ctx, options, + update_index_usage); + if (!ctx.argc) + break; + switch (parseopt_state) { + case PARSE_OPT_HELP: + exit(129); + case PARSE_OPT_NON_OPTION: + case PARSE_OPT_DONE: + { + const char *path = ctx.argv[0]; + const char *p; - if (allow_options && *path == '-') { - if (!strcmp(path, "--")) { - allow_options = 0; - continue; - } - if (!strcmp(path, "-q")) { - refresh_flags |= REFRESH_QUIET; - continue; - } - if (!strcmp(path, "--ignore-submodules")) { - refresh_flags |= REFRESH_IGNORE_SUBMODULES; - continue; - } - if (!strcmp(path, "--add")) { - allow_add = 1; - continue; - } - if (!strcmp(path, "--replace")) { - allow_replace = 1; - continue; - } - if (!strcmp(path, "--remove")) { - allow_remove = 1; - continue; - } - if (!strcmp(path, "--unmerged")) { - refresh_flags |= REFRESH_UNMERGED; - continue; - } - if (!strcmp(path, "--refresh")) { - setup_work_tree(); - has_errors |= refresh_cache(refresh_flags); - continue; - } - if (!strcmp(path, "--really-refresh")) { - setup_work_tree(); - has_errors |= refresh_cache(REFRESH_REALLY | refresh_flags); - continue; - } - if (!strcmp(path, "--cacheinfo")) { - unsigned char sha1[20]; - unsigned int mode; - - if (i+3 >= argc) - die("git update-index: --cacheinfo <mode> <sha1> <path>"); - - if (strtoul_ui(argv[i+1], 8, &mode) || - get_sha1_hex(argv[i+2], sha1) || - add_cacheinfo(mode, sha1, argv[i+3], 0)) - die("git update-index: --cacheinfo" - " cannot add %s", argv[i+3]); - i += 3; - continue; - } - if (!strcmp(path, "--chmod=-x") || - !strcmp(path, "--chmod=+x")) { - if (argc <= i+1) - die("git update-index: %s <path>", path); - set_executable_bit = path[8]; - continue; - } - if (!strcmp(path, "--assume-unchanged")) { - mark_valid_only = MARK_FLAG; - continue; - } - if (!strcmp(path, "--no-assume-unchanged")) { - mark_valid_only = UNMARK_FLAG; - continue; - } - if (!strcmp(path, "--no-skip-worktree")) { - mark_skip_worktree_only = UNMARK_FLAG; - continue; - } - if (!strcmp(path, "--skip-worktree")) { - mark_skip_worktree_only = MARK_FLAG; - continue; - } - if (!strcmp(path, "--info-only")) { - info_only = 1; - continue; - } - if (!strcmp(path, "--force-remove")) { - force_remove = 1; - continue; - } - if (!strcmp(path, "-z")) { - line_termination = 0; - continue; - } - if (!strcmp(path, "--stdin")) { - if (i != argc - 1) - die("--stdin must be at the end"); - read_from_stdin = 1; - break; - } - if (!strcmp(path, "--index-info")) { - if (i != argc - 1) - die("--index-info must be at the end"); - allow_add = allow_replace = allow_remove = 1; - read_index_info(line_termination); - break; - } - if (!strcmp(path, "--unresolve")) { - has_errors = do_unresolve(argc - i, argv + i, - prefix, prefix_length); - if (has_errors) - active_cache_changed = 0; - goto finish; - } - if (!strcmp(path, "--again") || !strcmp(path, "-g")) { - setup_work_tree(); - has_errors = do_reupdate(argc - i, argv + i, - prefix, prefix_length); - if (has_errors) - active_cache_changed = 0; - goto finish; - } - if (!strcmp(path, "--ignore-missing")) { - refresh_flags |= REFRESH_IGNORE_MISSING; - continue; - } - if (!strcmp(path, "--verbose")) { - verbose = 1; - continue; - } - if (!strcmp(path, "--clear-resolve-undo")) { - resolve_undo_clear(); - continue; - } - if (!strcmp(path, "-h") || !strcmp(path, "--help")) - usage(update_index_usage); - die("unknown option %s", path); + setup_work_tree(); + p = prefix_path(prefix, prefix_length, path); + update_one(p, NULL, 0); + if (set_executable_bit) + chmod_path(set_executable_bit, p); + if (p < path || p > path + strlen(path)) + free((char *)p); + ctx.argc--; + ctx.argv++; + break; + } + case PARSE_OPT_UNKNOWN: + if (ctx.argv[0][1] == '-') + error("unknown option '%s'", ctx.argv[0] + 2); + else + error("unknown switch '%c'", *ctx.opt); + usage_with_options(update_index_usage, options); } - setup_work_tree(); - p = prefix_path(prefix, prefix_length, path); - update_one(p, NULL, 0); - if (set_executable_bit) - chmod_path(set_executable_bit, p); - if (p < path || p > path + strlen(path)) - free((char *)p); } + argc = parse_options_end(&ctx); + if (read_from_stdin) { struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT; @@ -770,10 +868,9 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) strbuf_release(&buf); } - finish: if (active_cache_changed) { if (newfd < 0) { - if (refresh_flags & REFRESH_QUIET) + if (refresh_args.flags & REFRESH_QUIET) exit(128); unable_to_lock_index_die(get_index_file(), lock_error); } @@ -428,7 +428,7 @@ extern const char **get_pathspec(const char *prefix, const char **pathspec); extern void setup_work_tree(void); extern const char *setup_git_directory_gently(int *); extern const char *setup_git_directory(void); -extern const char *prefix_path(const char *prefix, int len, const char *path); +extern char *prefix_path(const char *prefix, int len, const char *path); extern const char *prefix_filename(const char *prefix, int len, const char *path); extern int check_filename(const char *prefix, const char *name); extern void verify_filename(const char *prefix, const char *name); @@ -1091,15 +1091,17 @@ void shift_tree_by(const unsigned char *, const unsigned char *, unsigned char * /* * whitespace rules. * used by both diff and apply + * last two digits are tab width */ -#define WS_BLANK_AT_EOL 01 -#define WS_SPACE_BEFORE_TAB 02 -#define WS_INDENT_WITH_NON_TAB 04 -#define WS_CR_AT_EOL 010 -#define WS_BLANK_AT_EOF 020 -#define WS_TAB_IN_INDENT 040 +#define WS_BLANK_AT_EOL 0100 +#define WS_SPACE_BEFORE_TAB 0200 +#define WS_INDENT_WITH_NON_TAB 0400 +#define WS_CR_AT_EOL 01000 +#define WS_BLANK_AT_EOF 02000 +#define WS_TAB_IN_INDENT 04000 #define WS_TRAILING_SPACE (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF) -#define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB) +#define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB|8) +#define WS_TAB_WIDTH_MASK 077 extern unsigned whitespace_rule_cfg; extern unsigned whitespace_rule(const char *); extern unsigned parse_whitespace_rule(const char *); @@ -1108,6 +1110,7 @@ extern void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *str extern char *whitespace_error_string(unsigned ws); extern void ws_fix_copy(struct strbuf *, const char *, int, unsigned, int *); extern int ws_blank_line(const char *line, int len, unsigned ws_rule); +#define ws_tab_width(rule) ((rule) & WS_TAB_WIDTH_MASK) /* ls-files */ int report_path_error(const char *ps_matched, const char **pathspec, int prefix_offset); @@ -1121,6 +1124,7 @@ const char *split_cmdline_strerror(int cmdline_errno); /* git.c */ struct startup_info { int have_repository; + const char *prefix; }; extern struct startup_info *startup_info; @@ -211,3 +211,8 @@ int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...) va_end(args); return r; } + +int color_is_nil(const char *c) +{ + return !strcmp(c, "NIL"); +} @@ -43,6 +43,9 @@ #define GIT_COLOR_BG_MAGENTA "\033[45m" #define GIT_COLOR_BG_CYAN "\033[46m" +/* A special value meaning "no color selected" */ +#define GIT_COLOR_NIL "NIL" + /* * This variable stores the value of color.ui */ @@ -62,4 +65,6 @@ int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); __attribute__((format (printf, 3, 4))) int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); +int color_is_nil(const char *color); + #endif /* COLOR_H */ diff --git a/compat/mingw.c b/compat/mingw.c index fdbf093f6e..bee6054419 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -1566,63 +1566,3 @@ pid_t waitpid(pid_t pid, int *status, unsigned options) errno = EINVAL; return -1; } - -#ifndef NO_MINGW_REPLACE_READDIR -/* MinGW readdir implementation to avoid extra lstats for Git */ -struct mingw_DIR -{ - struct _finddata_t dd_dta; /* disk transfer area for this dir */ - struct mingw_dirent dd_dir; /* Our own implementation, including d_type */ - long dd_handle; /* _findnext handle */ - int dd_stat; /* 0 = next entry to read is first entry, -1 = off the end, positive = 0 based index of next entry */ - char dd_name[1]; /* given path for dir with search pattern (struct is extended) */ -}; - -struct dirent *mingw_readdir(DIR *dir) -{ - WIN32_FIND_DATAA buf; - HANDLE handle; - struct mingw_DIR *mdir = (struct mingw_DIR*)dir; - - if (!dir->dd_handle) { - errno = EBADF; /* No set_errno for mingw */ - return NULL; - } - - if (dir->dd_handle == (long)INVALID_HANDLE_VALUE && dir->dd_stat == 0) - { - DWORD lasterr; - handle = FindFirstFileA(dir->dd_name, &buf); - lasterr = GetLastError(); - dir->dd_handle = (long)handle; - if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) { - errno = err_win_to_posix(lasterr); - return NULL; - } - } else if (dir->dd_handle == (long)INVALID_HANDLE_VALUE) { - return NULL; - } else if (!FindNextFileA((HANDLE)dir->dd_handle, &buf)) { - DWORD lasterr = GetLastError(); - FindClose((HANDLE)dir->dd_handle); - dir->dd_handle = (long)INVALID_HANDLE_VALUE; - /* POSIX says you shouldn't set errno when readdir can't - find any more files; so, if another error we leave it set. */ - if (lasterr != ERROR_NO_MORE_FILES) - errno = err_win_to_posix(lasterr); - return NULL; - } - - /* We get here if `buf' contains valid data. */ - strcpy(dir->dd_dir.d_name, buf.cFileName); - ++dir->dd_stat; - - /* Set file type, based on WIN32_FIND_DATA */ - mdir->dd_dir.d_type = 0; - if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - mdir->dd_dir.d_type |= DT_DIR; - else - mdir->dd_dir.d_type |= DT_REG; - - return (struct dirent*)&dir->dd_dir; -} -#endif // !NO_MINGW_REPLACE_READDIR diff --git a/compat/mingw.h b/compat/mingw.h index 35d9813b6b..cafc1eb08a 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -14,12 +14,6 @@ typedef int socklen_t; #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK) #define S_ISSOCK(x) 0 -#ifndef _STAT_H_ -#define S_IRUSR 0 -#define S_IWUSR 0 -#define S_IXUSR 0 -#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR) -#endif #define S_IRGRP 0 #define S_IWGRP 0 #define S_IXGRP 0 @@ -322,35 +316,6 @@ int main(int argc, const char **argv) \ } \ static int mingw_main(c,v) -#ifndef NO_MINGW_REPLACE_READDIR -/* - * A replacement of readdir, to ensure that it reads the file type at - * the same time. This avoid extra unneeded lstats in git on MinGW - */ -#undef DT_UNKNOWN -#undef DT_DIR -#undef DT_REG -#undef DT_LNK -#define DT_UNKNOWN 0 -#define DT_DIR 1 -#define DT_REG 2 -#define DT_LNK 3 - -struct mingw_dirent -{ - long d_ino; /* Always zero. */ - union { - unsigned short d_reclen; /* Always zero. */ - unsigned char d_type; /* Reimplementation adds this */ - }; - unsigned short d_namlen; /* Length of name in d_name. */ - char d_name[FILENAME_MAX]; /* File name. */ -}; -#define dirent mingw_dirent -#define readdir(x) mingw_readdir(x) -struct dirent *mingw_readdir(DIR *dir); -#endif // !NO_MINGW_REPLACE_READDIR - /* * Used by Pthread API implementation for Windows */ diff --git a/compat/msvc.c b/compat/msvc.c index ac04a4ccbd..71843d7eef 100644 --- a/compat/msvc.c +++ b/compat/msvc.c @@ -3,33 +3,4 @@ #include <conio.h> #include "../strbuf.h" -DIR *opendir(const char *name) -{ - int len; - DIR *p; - p = (DIR*)malloc(sizeof(DIR)); - memset(p, 0, sizeof(DIR)); - strncpy(p->dd_name, name, PATH_MAX); - len = strlen(p->dd_name); - p->dd_name[len] = '/'; - p->dd_name[len+1] = '*'; - - if (p == NULL) - return NULL; - - p->dd_handle = _findfirst(p->dd_name, &p->dd_dta); - - if (p->dd_handle == -1) { - free(p); - return NULL; - } - return p; -} -int closedir(DIR *dir) -{ - _findclose(dir->dd_handle); - free(dir); - return 0; -} - #include "mingw.c" diff --git a/compat/vcbuild/include/dirent.h b/compat/vcbuild/include/dirent.h deleted file mode 100644 index 440618db0d..0000000000 --- a/compat/vcbuild/include/dirent.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * DIRENT.H (formerly DIRLIB.H) - * This file has no copyright assigned and is placed in the Public Domain. - * This file is a part of the mingw-runtime package. - * - * The mingw-runtime package and its code is distributed in the hope that it - * will be useful but WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESSED OR - * IMPLIED ARE HEREBY DISCLAIMED. This includes but is not limited to - * warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You are free to use this package and its code without limitation. - */ -#ifndef _DIRENT_H_ -#define _DIRENT_H_ -#include <io.h> - -#define PATH_MAX 512 - -#define __MINGW_NOTHROW - -#ifndef RC_INVOKED - -#ifdef __cplusplus -extern "C" { -#endif - -struct dirent -{ - long d_ino; /* Always zero. */ - unsigned short d_reclen; /* Always zero. */ - unsigned short d_namlen; /* Length of name in d_name. */ - char d_name[FILENAME_MAX]; /* File name. */ -}; - -/* - * This is an internal data structure. Good programmers will not use it - * except as an argument to one of the functions below. - * dd_stat field is now int (was short in older versions). - */ -typedef struct -{ - /* disk transfer area for this dir */ - struct _finddata_t dd_dta; - - /* dirent struct to return from dir (NOTE: this makes this thread - * safe as long as only one thread uses a particular DIR struct at - * a time) */ - struct dirent dd_dir; - - /* _findnext handle */ - long dd_handle; - - /* - * Status of search: - * 0 = not started yet (next entry to read is first entry) - * -1 = off the end - * positive = 0 based index of next entry - */ - int dd_stat; - - /* given path for dir with search pattern (struct is extended) */ - char dd_name[PATH_MAX+3]; -} DIR; - -DIR* __cdecl __MINGW_NOTHROW opendir (const char*); -struct dirent* __cdecl __MINGW_NOTHROW readdir (DIR*); -int __cdecl __MINGW_NOTHROW closedir (DIR*); -void __cdecl __MINGW_NOTHROW rewinddir (DIR*); -long __cdecl __MINGW_NOTHROW telldir (DIR*); -void __cdecl __MINGW_NOTHROW seekdir (DIR*, long); - - -/* wide char versions */ - -struct _wdirent -{ - long d_ino; /* Always zero. */ - unsigned short d_reclen; /* Always zero. */ - unsigned short d_namlen; /* Length of name in d_name. */ - wchar_t d_name[FILENAME_MAX]; /* File name. */ -}; - -/* - * This is an internal data structure. Good programmers will not use it - * except as an argument to one of the functions below. - */ -typedef struct -{ - /* disk transfer area for this dir */ - //struct _wfinddata_t dd_dta; - - /* dirent struct to return from dir (NOTE: this makes this thread - * safe as long as only one thread uses a particular DIR struct at - * a time) */ - struct _wdirent dd_dir; - - /* _findnext handle */ - long dd_handle; - - /* - * Status of search: - * 0 = not started yet (next entry to read is first entry) - * -1 = off the end - * positive = 0 based index of next entry - */ - int dd_stat; - - /* given path for dir with search pattern (struct is extended) */ - wchar_t dd_name[1]; -} _WDIR; - - - -_WDIR* __cdecl __MINGW_NOTHROW _wopendir (const wchar_t*); -struct _wdirent* __cdecl __MINGW_NOTHROW _wreaddir (_WDIR*); -int __cdecl __MINGW_NOTHROW _wclosedir (_WDIR*); -void __cdecl __MINGW_NOTHROW _wrewinddir (_WDIR*); -long __cdecl __MINGW_NOTHROW _wtelldir (_WDIR*); -void __cdecl __MINGW_NOTHROW _wseekdir (_WDIR*, long); - - -#ifdef __cplusplus -} -#endif - -#endif /* Not RC_INVOKED */ - -#endif /* Not _DIRENT_H_ */ diff --git a/compat/vcbuild/include/unistd.h b/compat/vcbuild/include/unistd.h index 2a4f276869..b14fcf94da 100644 --- a/compat/vcbuild/include/unistd.h +++ b/compat/vcbuild/include/unistd.h @@ -45,6 +45,10 @@ typedef unsigned long long uintmax_t; typedef int64_t off64_t; +#define INTMAX_MIN _I64_MIN +#define INTMAX_MAX _I64_MAX +#define UINTMAX_MAX _UI64_MAX + #define STDOUT_FILENO 1 #define STDERR_FILENO 2 diff --git a/compat/win32/dirent.c b/compat/win32/dirent.c new file mode 100644 index 0000000000..7a0debe51b --- /dev/null +++ b/compat/win32/dirent.c @@ -0,0 +1,108 @@ +#include "../git-compat-util.h" +#include "dirent.h" + +struct DIR { + struct dirent dd_dir; /* includes d_type */ + HANDLE dd_handle; /* FindFirstFile handle */ + int dd_stat; /* 0-based index */ + char dd_name[1]; /* extend struct */ +}; + +DIR *opendir(const char *name) +{ + DWORD attrs = GetFileAttributesA(name); + int len; + DIR *p; + + /* check for valid path */ + if (attrs == INVALID_FILE_ATTRIBUTES) { + errno = ENOENT; + return NULL; + } + + /* check if it's a directory */ + if (!(attrs & FILE_ATTRIBUTE_DIRECTORY)) { + errno = ENOTDIR; + return NULL; + } + + /* check that the pattern won't be too long for FindFirstFileA */ + len = strlen(name); + if (is_dir_sep(name[len - 1])) + len--; + if (len + 2 >= MAX_PATH) { + errno = ENAMETOOLONG; + return NULL; + } + + p = malloc(sizeof(DIR) + len + 2); + if (!p) + return NULL; + + memset(p, 0, sizeof(DIR) + len + 2); + strcpy(p->dd_name, name); + p->dd_name[len] = '/'; + p->dd_name[len+1] = '*'; + + p->dd_handle = INVALID_HANDLE_VALUE; + return p; +} + +struct dirent *readdir(DIR *dir) +{ + WIN32_FIND_DATAA buf; + HANDLE handle; + + if (!dir || !dir->dd_handle) { + errno = EBADF; /* No set_errno for mingw */ + return NULL; + } + + if (dir->dd_handle == INVALID_HANDLE_VALUE && dir->dd_stat == 0) { + DWORD lasterr; + handle = FindFirstFileA(dir->dd_name, &buf); + lasterr = GetLastError(); + dir->dd_handle = handle; + if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES)) { + errno = err_win_to_posix(lasterr); + return NULL; + } + } else if (dir->dd_handle == INVALID_HANDLE_VALUE) { + return NULL; + } else if (!FindNextFileA(dir->dd_handle, &buf)) { + DWORD lasterr = GetLastError(); + FindClose(dir->dd_handle); + dir->dd_handle = INVALID_HANDLE_VALUE; + /* POSIX says you shouldn't set errno when readdir can't + find any more files; so, if another error we leave it set. */ + if (lasterr != ERROR_NO_MORE_FILES) + errno = err_win_to_posix(lasterr); + return NULL; + } + + /* We get here if `buf' contains valid data. */ + strcpy(dir->dd_dir.d_name, buf.cFileName); + ++dir->dd_stat; + + /* Set file type, based on WIN32_FIND_DATA */ + dir->dd_dir.d_type = 0; + if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + dir->dd_dir.d_type |= DT_DIR; + else + dir->dd_dir.d_type |= DT_REG; + + return &dir->dd_dir; +} + +int closedir(DIR *dir) +{ + if (!dir) { + errno = EBADF; + return -1; + } + + if (dir->dd_handle != INVALID_HANDLE_VALUE) + FindClose(dir->dd_handle); + free(dir); + return 0; +} diff --git a/compat/win32/dirent.h b/compat/win32/dirent.h new file mode 100644 index 0000000000..927a25ca76 --- /dev/null +++ b/compat/win32/dirent.h @@ -0,0 +1,24 @@ +#ifndef DIRENT_H +#define DIRENT_H + +typedef struct DIR DIR; + +#define DT_UNKNOWN 0 +#define DT_DIR 1 +#define DT_REG 2 +#define DT_LNK 3 + +struct dirent { + long d_ino; /* Always zero. */ + char d_name[FILENAME_MAX]; /* File name. */ + union { + unsigned short d_reclen; /* Always zero. */ + unsigned char d_type; /* Reimplementation adds this */ + }; +}; + +DIR *opendir(const char *dirname); +struct dirent *readdir(DIR *dir); +int closedir(DIR *dir); + +#endif /* DIRENT_H */ diff --git a/compat/win32/sys/poll.c b/compat/win32/sys/poll.c index 7e74ebe59a..708a6c9bec 100644 --- a/compat/win32/sys/poll.c +++ b/compat/win32/sys/poll.c @@ -34,6 +34,9 @@ #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ # define WIN32_NATIVE +# if defined (_MSC_VER) +# define _WIN32_WINNT 0x0502 +# endif # include <winsock2.h> # include <windows.h> # include <io.h> diff --git a/config.mak.in b/config.mak.in index 56343bab50..9614973057 100644 --- a/config.mak.in +++ b/config.mak.in @@ -27,7 +27,7 @@ VPATH = @srcdir@ export exec_prefix mandir export srcdir VPATH -ASCIIDOC8=@ASCIIDOC8@ +ASCIIDOC7=@ASCIIDOC7@ NEEDS_SSL_WITH_CRYPTO=@NEEDS_SSL_WITH_CRYPTO@ NO_OPENSSL=@NO_OPENSSL@ NO_CURL=@NO_CURL@ diff --git a/configure.ac b/configure.ac index 33dd46262b..5792425a49 100644 --- a/configure.ac +++ b/configure.ac @@ -398,21 +398,21 @@ if test -n "$ASCIIDOC"; then AC_MSG_CHECKING([for asciidoc version]) asciidoc_version=`$ASCIIDOC --version 2>/dev/null` case "${asciidoc_version}" in - asciidoc' '8*) - ASCIIDOC8=YesPlease + asciidoc' '7*) + ASCIIDOC7=YesPlease AC_MSG_RESULT([${asciidoc_version} > 7]) ;; - asciidoc' '7*) - ASCIIDOC8= + asciidoc' '8*) + ASCIIDOC7= AC_MSG_RESULT([${asciidoc_version}]) ;; *) - ASCIIDOC8= + ASCIIDOC7= AC_MSG_RESULT([${asciidoc_version} (unknown)]) ;; esac fi -AC_SUBST(ASCIIDOC8) +AC_SUBST(ASCIIDOC7) ## Checks for libraries. diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 604fa794cc..25c431469f 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1864,30 +1864,50 @@ _git_config () ;; esac __gitcomp " - add.ignore-errors + add.ignoreErrors + advice.commitBeforeMerge + advice.detachedHead + advice.implicitIdentity + advice.pushNonFastForward + advice.resolveConflict + advice.statusHints alias. + am.keepcr apply.ignorewhitespace apply.whitespace branch.autosetupmerge branch.autosetuprebase + browser. clean.requireForce color.branch color.branch.current color.branch.local color.branch.plain color.branch.remote + color.decorate.HEAD + color.decorate.branch + color.decorate.remoteBranch + color.decorate.stash + color.decorate.tag color.diff color.diff.commit color.diff.frag + color.diff.func color.diff.meta color.diff.new color.diff.old color.diff.plain color.diff.whitespace color.grep - color.grep.external + color.grep.context + color.grep.filename + color.grep.function + color.grep.linenumber color.grep.match + color.grep.selected + color.grep.separator color.interactive + color.interactive.error color.interactive.header color.interactive.help color.interactive.prompt @@ -1901,21 +1921,29 @@ _git_config () color.status.untracked color.status.updated color.ui + commit.status commit.template + core.abbrevguard + core.askpass + core.attributesfile core.autocrlf core.bare + core.bigFileThreshold core.compression core.createObject core.deltaBaseCacheLimit core.editor + core.eol core.excludesfile core.fileMode core.fsyncobjectfiles core.gitProxy core.ignoreCygwinFSTricks core.ignoreStat + core.ignorecase core.logAllRefUpdates core.loosecompression + core.notesRef core.packedGitLimit core.packedGitWindowSize core.pager @@ -1925,6 +1953,7 @@ _git_config () core.repositoryFormatVersion core.safecrlf core.sharedRepository + core.sparseCheckout core.symlinks core.trustctime core.warnAmbiguousRefs @@ -1932,15 +1961,17 @@ _git_config () core.worktree diff.autorefreshindex diff.external + diff.ignoreSubmodules diff.mnemonicprefix + diff.noprefix diff.renameLimit - diff.renameLimit. diff.renames diff.suppressBlankEmpty diff.tool diff.wordRegex difftool. difftool.prompt + fetch.recurseSubmodules fetch.unpackLimit format.attach format.cc @@ -1952,6 +1983,8 @@ _git_config () format.subjectprefix format.suffix format.thread + format.to + gc. gc.aggressiveWindow gc.auto gc.autopacklimit @@ -1989,15 +2022,20 @@ _git_config () http.lowSpeedLimit http.lowSpeedTime http.maxRequests + http.minSessions http.noEPSV + http.postBuffer http.proxy http.sslCAInfo http.sslCAPath http.sslCert + http.sslCertPasswordProtected http.sslKey http.sslVerify + http.useragent i18n.commitEncoding i18n.logOutputEncoding + imap.authMethod imap.folder imap.host imap.pass @@ -2006,6 +2044,7 @@ _git_config () imap.sslverify imap.tunnel imap.user + init.templatedir instaweb.browser instaweb.httpd instaweb.local @@ -2013,19 +2052,29 @@ _git_config () instaweb.port interactive.singlekey log.date + log.decorate log.showroot mailmap.file man. man.viewer + merge. merge.conflictstyle merge.log merge.renameLimit + merge.renormalize merge.stat merge.tool merge.verbosity mergetool. mergetool.keepBackup + mergetool.keepTemporaries mergetool.prompt + notes.displayRef + notes.rewrite. + notes.rewrite.amend + notes.rewrite.rebase + notes.rewriteMode + notes.rewriteRef pack.compression pack.deltaCacheLimit pack.deltaCacheSize @@ -2036,31 +2085,42 @@ _git_config () pack.window pack.windowMemory pager. + pretty. pull.octopus pull.twohead push.default + rebase.autosquash rebase.stat + receive.autogc receive.denyCurrentBranch + receive.denyDeleteCurrent receive.denyDeletes receive.denyNonFastForwards receive.fsckObjects receive.unpackLimit + receive.updateserverinfo + remotes. repack.usedeltabaseoffset rerere.autoupdate rerere.enabled + sendemail. sendemail.aliasesfile - sendemail.aliasesfiletype + sendemail.aliasfiletype sendemail.bcc sendemail.cc sendemail.cccmd sendemail.chainreplyto sendemail.confirm sendemail.envelopesender + sendemail.from + sendemail.identity sendemail.multiedit sendemail.signedoffbycc + sendemail.smtpdomain sendemail.smtpencryption sendemail.smtppass sendemail.smtpserver + sendemail.smtpserveroption sendemail.smtpserverport sendemail.smtpuser sendemail.suppresscc @@ -2071,6 +2131,8 @@ _git_config () showbranch.default status.relativePaths status.showUntrackedFiles + status.submodulesummary + submodule. tar.umask transfer.unpackLimit url. @@ -3154,14 +3154,14 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) if ((options->break_opt = diff_scoreopt_parse(arg)) == -1) return error("invalid argument to -B: %s", arg+2); } - else if (!prefixcmp(arg, "-M") || !prefixcmp(arg, "--detect-renames=") || - !strcmp(arg, "--detect-renames")) { + else if (!prefixcmp(arg, "-M") || !prefixcmp(arg, "--find-renames=") || + !strcmp(arg, "--find-renames")) { if ((options->rename_score = diff_scoreopt_parse(arg)) == -1) return error("invalid argument to -M: %s", arg+2); options->detect_rename = DIFF_DETECT_RENAME; } - else if (!prefixcmp(arg, "-C") || !prefixcmp(arg, "--detect-copies=") || - !strcmp(arg, "--detect-copies")) { + else if (!prefixcmp(arg, "-C") || !prefixcmp(arg, "--find-copies=") || + !strcmp(arg, "--find-copies")) { if (options->detect_rename == DIFF_DETECT_COPY) DIFF_OPT_SET(options, FIND_COPIES_HARDER); if ((options->rename_score = diff_scoreopt_parse(arg)) == -1) @@ -3384,12 +3384,12 @@ static int diff_scoreopt_parse(const char *opt) opt += strlen("break-rewrites"); if (*opt == 0 || *opt++ == '=') cmd = 'B'; - } else if (!prefixcmp(opt, "detect-copies")) { - opt += strlen("detect-copies"); + } else if (!prefixcmp(opt, "find-copies")) { + opt += strlen("find-copies"); if (*opt == 0 || *opt++ == '=') cmd = 'C'; - } else if (!prefixcmp(opt, "detect-renames")) { - opt += strlen("detect-renames"); + } else if (!prefixcmp(opt, "find-renames")) { + opt += strlen("find-renames"); if (*opt == 0 || *opt++ == '=') cmd = 'M'; } @@ -1033,6 +1033,12 @@ char *get_relative_cwd(char *buffer, int size, const char *dir) case '/': return cwd + 1; default: + /* + * dir can end with a path separator when it's root + * directory. Return proper prefix in that case. + */ + if (dir[-1] == '/') + return cwd; return NULL; } } @@ -106,14 +106,14 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout case S_IFLNK: new = read_blob_entry(ce, &size); if (!new) - return error("git checkout-index: unable to read sha1 file of %s (%s)", + return error("unable to read sha1 file of %s (%s)", path, sha1_to_hex(ce->sha1)); if (ce_mode_s_ifmt == S_IFLNK && has_symlinks && !to_tempfile) { ret = symlink(new, path); free(new); if (ret) - return error("git checkout-index: unable to create symlink %s (%s)", + return error("unable to create symlink %s (%s)", path, strerror(errno)); break; } @@ -141,7 +141,7 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout } if (fd < 0) { free(new); - return error("git checkout-index: unable to create file %s (%s)", + return error("unable to create file %s (%s)", path, strerror(errno)); } @@ -155,16 +155,16 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout close(fd); free(new); if (wrote != size) - return error("git checkout-index: unable to write file %s", path); + return error("unable to write file %s", path); break; case S_IFGITLINK: if (to_tempfile) - return error("git checkout-index: cannot create temporary subproject %s", path); + return error("cannot create temporary subproject %s", path); if (mkdir(path, 0777) < 0) - return error("git checkout-index: cannot create subproject directory %s", path); + return error("cannot create subproject directory %s", path); break; default: - return error("git checkout-index: unknown file mode for %s", path); + return error("unknown file mode for %s in index", path); } if (state->refresh_cache) { @@ -211,7 +211,7 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t return 0; if (!state->force) { if (!state->quiet) - fprintf(stderr, "git-checkout-index: %s already exists\n", path); + fprintf(stderr, "%s already exists, no checkout\n", path); return -1; } diff --git a/fast-import.c b/fast-import.c index 534c68db6f..785776086c 100644 --- a/fast-import.c +++ b/fast-import.c @@ -132,14 +132,17 @@ Format of STDIN stream: ts ::= # time since the epoch in seconds, ascii base10 notation; tz ::= # GIT style timezone; - # note: comments may appear anywhere in the input, except - # within a data command. Any form of the data command - # always escapes the related input from comment processing. + # note: comments and cat requests may appear anywhere + # in the input, except within a data command. Any form + # of the data command always escapes the related input + # from comment processing. # # In case it is not clear, the '#' that starts the comment # must be the first character on that line (an lf # preceded it). # + cat_blob ::= 'cat-blob' sp (hexsha1 | idnum) lf; + comment ::= '#' not_lf* lf; not_lf ::= # Any byte that is not ASCII newline (LF); */ @@ -362,7 +365,14 @@ static uintmax_t next_mark; static struct strbuf new_data = STRBUF_INIT; static int seen_data_command; +/* Signal handling */ +static volatile sig_atomic_t checkpoint_requested; + +/* Where to write output of cat-blob commands */ +static int cat_blob_fd = STDOUT_FILENO; + static void parse_argv(void); +static void parse_cat_blob(void); static void write_branch_report(FILE *rpt, struct branch *b) { @@ -501,6 +511,32 @@ static NORETURN void die_nicely(const char *err, va_list params) exit(128); } +#ifndef SIGUSR1 /* Windows, for example */ + +static void set_checkpoint_signal(void) +{ +} + +#else + +static void checkpoint_signal(int signo) +{ + checkpoint_requested = 1; +} + +static void set_checkpoint_signal(void) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = checkpoint_signal; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sigaction(SIGUSR1, &sa, NULL); +} + +#endif + static void alloc_objects(unsigned int cnt) { struct object_entry_pool *b; @@ -540,22 +576,17 @@ static struct object_entry *insert_object(unsigned char *sha1) { unsigned int h = sha1[0] << 8 | sha1[1]; struct object_entry *e = object_table[h]; - struct object_entry *p = NULL; while (e) { if (!hashcmp(sha1, e->idx.sha1)) return e; - p = e; e = e->next; } e = new_object(sha1); - e->next = NULL; + e->next = object_table[h]; e->idx.offset = 0; - if (p) - p->next = e; - else - object_table[h] = e; + object_table[h] = e; return e; } @@ -1805,7 +1836,7 @@ static int read_next_command(void) return EOF; } - do { + for (;;) { if (unread_command_buf) { unread_command_buf = 0; } else { @@ -1838,9 +1869,14 @@ static int read_next_command(void) rc->prev->next = rc; cmd_tail = rc; } - } while (command_buf.buf[0] == '#'); - - return 0; + if (!prefixcmp(command_buf.buf, "cat-blob ")) { + parse_cat_blob(); + continue; + } + if (command_buf.buf[0] == '#') + continue; + return 0; + } } static void skip_optional_lf(void) @@ -2715,14 +2751,95 @@ static void parse_reset_branch(void) unread_command_buf = 1; } -static void parse_checkpoint(void) +static void cat_blob_write(const char *buf, unsigned long size) { + if (write_in_full(cat_blob_fd, buf, size) != size) + die_errno("Write to frontend failed"); +} + +static void cat_blob(struct object_entry *oe, unsigned char sha1[20]) +{ + struct strbuf line = STRBUF_INIT; + unsigned long size; + enum object_type type = 0; + char *buf; + + if (!oe || oe->pack_id == MAX_PACK_ID) { + buf = read_sha1_file(sha1, &type, &size); + } else { + type = oe->type; + buf = gfi_unpack_entry(oe, &size); + } + + /* + * Output based on batch_one_object() from cat-file.c. + */ + if (type <= 0) { + strbuf_reset(&line); + strbuf_addf(&line, "%s missing\n", sha1_to_hex(sha1)); + cat_blob_write(line.buf, line.len); + strbuf_release(&line); + free(buf); + return; + } + if (!buf) + die("Can't read object %s", sha1_to_hex(sha1)); + if (type != OBJ_BLOB) + die("Object %s is a %s but a blob was expected.", + sha1_to_hex(sha1), typename(type)); + strbuf_reset(&line); + strbuf_addf(&line, "%s %s %lu\n", sha1_to_hex(sha1), + typename(type), size); + cat_blob_write(line.buf, line.len); + strbuf_release(&line); + cat_blob_write(buf, size); + cat_blob_write("\n", 1); + free(buf); +} + +static void parse_cat_blob(void) +{ + const char *p; + struct object_entry *oe = oe; + unsigned char sha1[20]; + + /* cat-blob SP <object> LF */ + p = command_buf.buf + strlen("cat-blob "); + if (*p == ':') { + char *x; + oe = find_mark(strtoumax(p + 1, &x, 10)); + if (x == p + 1) + die("Invalid mark: %s", command_buf.buf); + if (!oe) + die("Unknown mark: %s", command_buf.buf); + if (*x) + die("Garbage after mark: %s", command_buf.buf); + hashcpy(sha1, oe->idx.sha1); + } else { + if (get_sha1_hex(p, sha1)) + die("Invalid SHA1: %s", command_buf.buf); + if (p[40]) + die("Garbage after SHA1: %s", command_buf.buf); + oe = find_object(sha1); + } + + cat_blob(oe, sha1); +} + +static void checkpoint(void) +{ + checkpoint_requested = 0; if (object_count) { cycle_packfile(); dump_branches(); dump_tags(); dump_marks(); } +} + +static void parse_checkpoint(void) +{ + checkpoint_requested = 1; skip_optional_lf(); } @@ -2772,16 +2889,25 @@ static void option_date_format(const char *fmt) die("unknown --date-format argument %s", fmt); } +static unsigned long ulong_arg(const char *option, const char *arg) +{ + char *endptr; + unsigned long rv = strtoul(arg, &endptr, 0); + if (strchr(arg, '-') || endptr == arg || *endptr) + die("%s: argument must be a non-negative integer", option); + return rv; +} + static void option_depth(const char *depth) { - max_depth = strtoul(depth, NULL, 0); + max_depth = ulong_arg("--depth", depth); if (max_depth > MAX_DEPTH) die("--depth cannot exceed %u", MAX_DEPTH); } static void option_active_branches(const char *branches) { - max_active_branches = strtoul(branches, NULL, 0); + max_active_branches = ulong_arg("--active-branches", branches); } static void option_export_marks(const char *marks) @@ -2790,6 +2916,14 @@ static void option_export_marks(const char *marks) safe_create_leading_directories_const(export_marks_file); } +static void option_cat_blob_fd(const char *fd) +{ + unsigned long n = ulong_arg("--cat-blob-fd", fd); + if (n > (unsigned long) INT_MAX) + die("--cat-blob-fd cannot exceed %d", INT_MAX); + cat_blob_fd = (int) n; +} + static void option_export_pack_edges(const char *edges) { if (pack_edges) @@ -2843,6 +2977,8 @@ static int parse_one_feature(const char *feature, int from_stream) option_import_marks(feature + 13, from_stream); } else if (!prefixcmp(feature, "export-marks=")) { option_export_marks(feature + 13); + } else if (!strcmp(feature, "cat-blob")) { + ; /* Don't die - this feature is supported */ } else if (!prefixcmp(feature, "relative-marks")) { relative_marks_paths = 1; } else if (!prefixcmp(feature, "no-relative-marks")) { @@ -2937,6 +3073,11 @@ static void parse_argv(void) if (parse_one_feature(a + 2, 0)) continue; + if (!prefixcmp(a + 2, "cat-blob-fd=")) { + option_cat_blob_fd(a + 2 + strlen("cat-blob-fd=")); + continue; + } + die("unknown option %s", a); } if (i != global_argc) @@ -2979,6 +3120,7 @@ int main(int argc, const char **argv) prepare_packed_git(); start_packfile(); set_die_routine(die_nicely); + set_checkpoint_signal(); while (read_next_command() != EOF) { if (!strcmp("blob", command_buf.buf)) parse_new_blob(); @@ -3000,6 +3142,9 @@ int main(int argc, const char **argv) /* ignore non-git options*/; else die("Unsupported command: %s", command_buf.buf); + + if (checkpoint_requested) + checkpoint(); } /* argv hasn't been parsed yet, do so */ diff --git a/git-difftool--helper.sh b/git-difftool--helper.sh index 524f5ea8ab..0594bf7ca5 100755 --- a/git-difftool--helper.sh +++ b/git-difftool--helper.sh @@ -49,6 +49,7 @@ launch_merge_tool () { fi if use_ext_cmd; then + export BASE eval $GIT_DIFFTOOL_EXTCMD '"$LOCAL"' '"$REMOTE"' else run_merge_tool "$merge_tool" diff --git a/git-parse-remote.sh b/git-parse-remote.sh index 4da72aefbd..1cc2ba6e09 100644 --- a/git-parse-remote.sh +++ b/git-parse-remote.sh @@ -89,7 +89,13 @@ get_remote_merge_branch () { refs/heads/*) remote=${remote#refs/heads/} ;; refs/* | tags/* | remotes/* ) remote= esac - - [ -n "$remote" ] && echo "refs/remotes/$repo/$remote" + [ -n "$remote" ] && case "$repo" in + .) + echo "refs/heads/$remote" + ;; + *) + echo "refs/remotes/$repo/$remote" + ;; + esac esac } diff --git a/git-pull.sh b/git-pull.sh index 20a3bbea07..eb87f49062 100755 --- a/git-pull.sh +++ b/git-pull.sh @@ -38,7 +38,7 @@ test -z "$(git ls-files -u)" || die_conflict test -f "$GIT_DIR/MERGE_HEAD" && die_merge strategy_args= diffstat= no_commit= squash= no_ff= ff_only= -log_arg= verbosity= progress= +log_arg= verbosity= progress= recurse_submodules= merge_args= curr_branch=$(git symbolic-ref -q HEAD) curr_branch_short="${curr_branch#refs/heads/}" @@ -105,6 +105,12 @@ do --no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase) rebase=false ;; + --recurse-submodules) + recurse_submodules=--recurse-submodules + ;; + --no-recurse-submodules) + recurse_submodules=--no-recurse-submodules + ;; --d|--dr|--dry|--dry-|--dry-r|--dry-ru|--dry-run) dry_run=--dry-run ;; @@ -217,7 +223,7 @@ test true = "$rebase" && { done } orig_head=$(git rev-parse -q --verify HEAD) -git fetch $verbosity $progress $dry_run --update-head-ok "$@" || exit 1 +git fetch $verbosity $progress $dry_run $recurse_submodules --update-head-ok "$@" || exit 1 test -z "$dry_run" || exit 0 curr_head=$(git rev-parse -q --verify HEAD) diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 5934b97fa1..a5ffd9a31e 100755 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -28,6 +28,7 @@ continue continue rebasing process abort abort rebasing process and restore original branch skip skip current patch and continue rebasing process no-verify override pre-rebase hook from stopping the operation +verify allow pre-rebase hook to run root rebase all reachable commmits up to the root(s) autosquash move commits that begin with squash!/fixup! under -i " @@ -749,6 +750,7 @@ do OK_TO_SKIP_PRE_REBASE=yes ;; --verify) + OK_TO_SKIP_PRE_REBASE= ;; --continue) is_standalone "$@" || usage diff --git a/git-rebase.sh b/git-rebase.sh index 0e9d52a500..d8e1903026 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -49,7 +49,8 @@ do_merge= dotest="$GIT_DIR"/rebase-merge prec=4 verbose= -diffstat=$(git config --bool rebase.stat) +diffstat= +test "$(git config --bool rebase.stat)" = true && diffstat=t git_am_opt= rebase_root= force_rebase= @@ -205,6 +206,9 @@ do --no-verify) OK_TO_SKIP_PRE_REBASE=yes ;; + --verify) + OK_TO_SKIP_PRE_REBASE= + ;; --continue) test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply || die "No rebase in progress?" @@ -274,15 +278,16 @@ do die "No rebase in progress?" git rerere clear - if test -d "$dotest" - then - GIT_QUIET=$(cat "$dotest/quiet") - move_to_original_branch - else - dotest="$GIT_DIR"/rebase-apply - GIT_QUIET=$(cat "$dotest/quiet") - move_to_original_branch - fi + + test -d "$dotest" || dotest="$GIT_DIR"/rebase-apply + + head_name="$(cat "$dotest"/head-name)" && + case "$head_name" in + refs/*) + git symbolic-ref HEAD $head_name || + die "Could not move back to $head_name" + ;; + esac git reset --hard $(cat "$dotest/orig-head") rm -r "$dotest" exit diff --git a/git-submodule.sh b/git-submodule.sh index 33bc41f069..c21b77aee5 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -93,20 +93,6 @@ module_clone() url=$2 reference="$3" - # If there already is a directory at the submodule path, - # expect it to be empty (since that is the default checkout - # action) and try to remove it. - # Note: if $path is a symlink to a directory the test will - # succeed but the rmdir will fail. We might want to fix this. - if test -d "$path" - then - rmdir "$path" 2>/dev/null || - die "Directory '$path' exists, but is neither empty nor a git repository" - fi - - test -e "$path" && - die "A file already exist at path '$path'" - if test -n "$reference" then git-clone "$reference" -n "$url" "$path" @@ -241,7 +227,7 @@ cmd_add() # ash fails to wordsplit ${branch:+-b "$branch"...} case "$branch" in '') git checkout -f -q ;; - ?*) git checkout -f -q -b "$branch" "origin/$branch" ;; + ?*) git checkout -f -q -B "$branch" "origin/$branch" ;; esac ) || die "Unable to checkout submodule '$path'" fi diff --git a/git-web--browse.sh b/git-web--browse.sh index 3fc4166b25..e9de241dd0 100755 --- a/git-web--browse.sh +++ b/git-web--browse.sh @@ -31,154 +31,161 @@ valid_custom_tool() valid_tool() { case "$1" in - firefox | iceweasel | chrome | google-chrome | chromium | konqueror | w3m | links | lynx | dillo | open | start) - ;; # happy - *) - valid_custom_tool "$1" || return 1 - ;; + firefox | iceweasel | seamonkey | iceape | \ + chrome | google-chrome | chromium | chromium-browser |\ + konqueror | opera | w3m | elinks | links | lynx | dillo | open | start) + ;; # happy + *) + valid_custom_tool "$1" || return 1 + ;; esac } init_browser_path() { browser_path=$(git config "browser.$1.path") - test -z "$browser_path" && browser_path="$1" + if test -z "$browser_path" && + test "$1" = chromium && + type chromium-browser >/dev/null 2>&1 + then + browser_path=chromium-browser + fi + : ${browser_path:="$1"} } while test $# != 0 do - case "$1" in + case "$1" in -b|--browser*|-t|--tool*) - case "$#,$1" in + case "$#,$1" in *,*=*) - browser=`expr "z$1" : 'z-[^=]*=\(.*\)'` - ;; + browser=`expr "z$1" : 'z-[^=]*=\(.*\)'` + ;; 1,*) - usage ;; + usage ;; *) - browser="$2" - shift ;; - esac - ;; + browser="$2" + shift ;; + esac + ;; -c|--config*) - case "$#,$1" in + case "$#,$1" in *,*=*) - conf=`expr "z$1" : 'z-[^=]*=\(.*\)'` - ;; + conf=`expr "z$1" : 'z-[^=]*=\(.*\)'` + ;; 1,*) - usage ;; + usage ;; *) - conf="$2" - shift ;; - esac - ;; + conf="$2" + shift ;; + esac + ;; --) - break - ;; + break + ;; -*) - usage - ;; + usage + ;; *) - break - ;; - esac - shift + break + ;; + esac + shift done test $# = 0 && usage if test -z "$browser" then - for opt in "$conf" "web.browser" - do - test -z "$opt" && continue - browser="`git config $opt`" - test -z "$browser" || break - done - if test -n "$browser" && ! valid_tool "$browser"; then - echo >&2 "git config option $opt set to unknown browser: $browser" - echo >&2 "Resetting to default..." - unset browser - fi + for opt in "$conf" "web.browser" + do + test -z "$opt" && continue + browser="`git config $opt`" + test -z "$browser" || break + done + if test -n "$browser" && ! valid_tool "$browser"; then + echo >&2 "git config option $opt set to unknown browser: $browser" + echo >&2 "Resetting to default..." + unset browser + fi fi if test -z "$browser" ; then - if test -n "$DISPLAY"; then - browser_candidates="firefox iceweasel google-chrome chrome chromium konqueror w3m links lynx dillo" - if test "$KDE_FULL_SESSION" = "true"; then - browser_candidates="konqueror $browser_candidates" + if test -n "$DISPLAY"; then + browser_candidates="firefox iceweasel google-chrome chrome chromium chromium-browser konqueror opera seamonkey iceape w3m elinks links lynx dillo" + if test "$KDE_FULL_SESSION" = "true"; then + browser_candidates="konqueror $browser_candidates" + fi + else + browser_candidates="w3m elinks links lynx" fi - else - browser_candidates="w3m links lynx" - fi - # SECURITYSESSIONID indicates an OS X GUI login session - if test -n "$SECURITYSESSIONID" \ - -o "$TERM_PROGRAM" = "Apple_Terminal" ; then - browser_candidates="open $browser_candidates" - fi - # /bin/start indicates MinGW - if test -x /bin/start; then - browser_candidates="start $browser_candidates" - fi - - for i in $browser_candidates; do - init_browser_path $i - if type "$browser_path" > /dev/null 2>&1; then - browser=$i - break + # SECURITYSESSIONID indicates an OS X GUI login session + if test -n "$SECURITYSESSIONID" \ + -o "$TERM_PROGRAM" = "Apple_Terminal" ; then + browser_candidates="open $browser_candidates" fi - done - test -z "$browser" && die "No known browser available." + # /bin/start indicates MinGW + if test -x /bin/start; then + browser_candidates="start $browser_candidates" + fi + + for i in $browser_candidates; do + init_browser_path $i + if type "$browser_path" > /dev/null 2>&1; then + browser=$i + break + fi + done + test -z "$browser" && die "No known browser available." else - valid_tool "$browser" || die "Unknown browser '$browser'." + valid_tool "$browser" || die "Unknown browser '$browser'." - init_browser_path "$browser" + init_browser_path "$browser" - if test -z "$browser_cmd" && ! type "$browser_path" > /dev/null 2>&1; then - die "The browser $browser is not available as '$browser_path'." - fi + if test -z "$browser_cmd" && ! type "$browser_path" > /dev/null 2>&1; then + die "The browser $browser is not available as '$browser_path'." + fi fi case "$browser" in - firefox|iceweasel) +firefox|iceweasel|seamonkey|iceape) # Check version because firefox < 2.0 does not support "-new-tab". vers=$(expr "$($browser_path -version)" : '.* \([0-9][0-9]*\)\..*') NEWTAB='-new-tab' test "$vers" -lt 2 && NEWTAB='' "$browser_path" $NEWTAB "$@" & ;; - google-chrome|chrome|chromium) - # Actual command for chromium is chromium-browser. +google-chrome|chrome|chromium|chromium-browser) # No need to specify newTab. It's default in chromium eval "$browser_path" "$@" & ;; - konqueror) +konqueror) case "$(basename "$browser_path")" in - konqueror) + konqueror) # It's simpler to use kfmclient to open a new tab in konqueror. browser_path="$(echo "$browser_path" | sed -e 's/konqueror$/kfmclient/')" type "$browser_path" > /dev/null 2>&1 || die "No '$browser_path' found." eval "$browser_path" newTab "$@" ;; - kfmclient) + kfmclient) eval "$browser_path" newTab "$@" ;; - *) + *) "$browser_path" "$@" & ;; esac ;; - w3m|links|lynx|open) +w3m|elinks|links|lynx|open) eval "$browser_path" "$@" ;; - start) - exec "$browser_path" '"web-browse"' "$@" - ;; - dillo) +start) + exec "$browser_path" '"web-browse"' "$@" + ;; +opera|dillo) "$browser_path" "$@" & ;; - *) +*) if test -n "$browser_cmd"; then - ( eval $browser_cmd "$@" ) + ( eval $browser_cmd "$@" ) fi ;; esac diff --git a/gitk-git/gitk b/gitk-git/gitk index 1b0e09a561..e82c6bfede 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -131,6 +131,7 @@ proc unmerged_files {files} { proc parseviewargs {n arglist} { global vdatemode vmergeonly vflags vdflags vrevs vfiltered vorigargs env + global worddiff git_version set vdatemode($n) 0 set vmergeonly($n) 0 @@ -168,7 +169,7 @@ proc parseviewargs {n arglist} { lappend diffargs $arg } "--raw" - "--patch-with-raw" - "--patch-with-stat" - - "--name-only" - "--name-status" - "--color" - "--color-words" - + "--name-only" - "--name-status" - "--color" - "--log-size" - "--pretty=*" - "--decorate" - "--abbrev-commit" - "--cc" - "-z" - "--header" - "--parents" - "--boundary" - "--no-color" - "-g" - "--walk-reflogs" - "--no-walk" - @@ -177,6 +178,18 @@ proc parseviewargs {n arglist} { # These cause our parsing of git log's output to fail, or else # they're options we want to set ourselves, so ignore them. } + "--color-words*" - "--word-diff=color" { + # These trigger a word diff in the console interface, + # so help the user by enabling our own support + if {[package vcompare $git_version "1.7.2"] >= 0} { + set worddiff [mc "Color words"] + } + } + "--word-diff*" { + if {[package vcompare $git_version "1.7.2"] >= 0} { + set worddiff [mc "Markup words"] + } + } "--stat=*" - "--numstat" - "--shortstat" - "--summary" - "--check" - "--exit-code" - "--quiet" - "--topo-order" - "--full-history" - "--dense" - "--sparse" - @@ -313,6 +326,7 @@ proc start_rev_list {view} { global viewactive viewinstances vmergeonly global mainheadid viewmainheadid viewmainheadid_orig global vcanopt vflags vrevs vorigargs + global show_notes set startmsecs [clock clicks -milliseconds] set commitidx($view) 0 @@ -361,8 +375,8 @@ proc start_rev_list {view} { } if {[catch { - set fd [open [concat | git log --no-color -z --pretty=raw --parents \ - --boundary $args "--" $files] r] + set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \ + --parents --boundary $args "--" $files] r] } err]} { error_popup "[mc "Error executing git log:"] $err" return 0 @@ -456,6 +470,7 @@ proc updatecommits {} { global mainheadid viewmainheadid viewmainheadid_orig pending_select global isworktree global varcid vposids vnegids vflags vrevs + global show_notes set isworktree [expr {[exec git rev-parse --is-inside-work-tree] == "true"}] rereadrefs @@ -508,8 +523,8 @@ proc updatecommits {} { set args $vorigargs($view) } if {[catch { - set fd [open [concat | git log --no-color -z --pretty=raw --parents \ - --boundary $args "--" $vfilelimit($view)] r] + set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \ + --parents --boundary $args "--" $vfilelimit($view)] r] } err]} { error_popup "[mc "Error executing git log:"] $err" return @@ -1970,6 +1985,8 @@ proc makewindow {} { global fprogitem fprogcoord lastprogupdate progupdatepending global rprogitem rprogcoord rownumsel numcommits global have_tk85 use_ttk NS + global git_version + global worddiff # The "mc" arguments here are purely so that xgettext # sees the following string as needing to be translated @@ -2243,6 +2260,15 @@ proc makewindow {} { ${NS}::checkbutton .bleft.mid.ignspace -text [mc "Ignore space change"] \ -command changeignorespace -variable ignorespace pack .bleft.mid.ignspace -side left -padx 5 + + set worddiff [mc "Line diff"] + if {[package vcompare $git_version "1.7.2"] >= 0} { + makedroplist .bleft.mid.worddiff worddiff [mc "Line diff"] \ + [mc "Markup words"] [mc "Color words"] + trace add variable worddiff write changeworddiff + pack .bleft.mid.worddiff -side left -padx 5 + } + set ctext .bleft.bottom.ctext text $ctext -background $bgcolor -foreground $fgcolor \ -state disabled -font textfont \ @@ -2451,6 +2477,7 @@ proc makewindow {} { global ctxbut bind $cflist $ctxbut {pop_flist_menu %W %X %Y %x %y} bind $ctext $ctxbut {pop_diff_menu %W %X %Y %x %y} + bind $ctext <Button-1> {focus %W} set maincursor [. cget -cursor] set textcursor [$ctext cget -cursor] @@ -7301,6 +7328,7 @@ proc getblobline {bf id} { [lindex [split $commentend .] 0]}] mark_ctext_line $lnum } + $ctext config -state disabled return 0 } $ctext config -state disabled @@ -7502,11 +7530,16 @@ proc changeignorespace {} { reselectline } +proc changeworddiff {name ix op} { + reselectline +} + proc getblobdiffs {ids} { global blobdifffd diffids env global diffinhdr treediffs global diffcontext global ignorespace + global worddiff global limitdiffs vfilelimit curview global diffencoding targetline diffnparents global git_version currdiffsubmod @@ -7523,6 +7556,9 @@ proc getblobdiffs {ids} { if {$ignorespace} { append cmd " -w" } + if {$worddiff ne [mc "Line diff"]} { + append cmd " --word-diff=porcelain" + } if {$limitdiffs && $vfilelimit($curview) ne {}} { set cmd [concat $cmd -- $vfilelimit($curview)] } @@ -7608,6 +7644,7 @@ proc getblobdiffline {bdf ids} { global ctext_file_names ctext_file_lines global diffinhdr treediffs mergemax diffnparents global diffencoding jump_to_here targetline diffline currdiffsubmod + global worddiff set nr 0 $ctext conf -state normal @@ -7747,15 +7784,28 @@ proc getblobdiffline {bdf ids} { # parse the prefix - one ' ', '-' or '+' for each parent set prefix [string range $line 0 [expr {$diffnparents - 1}]] set tag [expr {$diffnparents > 1? "m": "d"}] + set dowords [expr {$worddiff ne [mc "Line diff"] && $diffnparents == 1}] + set words_pre_markup "" + set words_post_markup "" if {[string trim $prefix " -+"] eq {}} { # prefix only has " ", "-" and "+" in it: normal diff line set num [string first "-" $prefix] + if {$dowords} { + set line [string range $line 1 end] + } if {$num >= 0} { # removed line, first parent with line is $num if {$num >= $mergemax} { set num "max" } - $ctext insert end "$line\n" $tag$num + if {$dowords && $worddiff eq [mc "Markup words"]} { + $ctext insert end "\[-$line-\]" $tag$num + } else { + $ctext insert end "$line" $tag$num + } + if {!$dowords} { + $ctext insert end "\n" $tag$num + } } else { set tags {} if {[string first "+" $prefix] >= 0} { @@ -7770,6 +7820,8 @@ proc getblobdiffline {bdf ids} { lappend tags m$num } } + set words_pre_markup "{+" + set words_post_markup "+}" } if {$targetline ne {}} { if {$diffline == $targetline} { @@ -7779,8 +7831,17 @@ proc getblobdiffline {bdf ids} { incr diffline } } - $ctext insert end "$line\n" $tags + if {$dowords && $worddiff eq [mc "Markup words"]} { + $ctext insert end "$words_pre_markup$line$words_post_markup" $tags + } else { + $ctext insert end "$line" $tags + } + if {!$dowords} { + $ctext insert end "\n" $tags + } } + } elseif {$dowords && $prefix eq "~"} { + $ctext insert end "\n" {} } else { # "\ No newline at end of file", # or something else we don't recognize @@ -11391,6 +11452,7 @@ if {[tk windowingsystem] eq "win32"} { set diffcolors {red "#00a000" blue} set diffcontext 3 set ignorespace 0 +set worddiff "" set markbgcolor "#e0e0ff" set circlecolors {white blue gray blue blue} @@ -11521,6 +11583,11 @@ set NS [expr {$use_ttk ? "ttk" : ""}] set git_version [join [lrange [split [lindex [exec git version] end] .] 0 2] .] +set show_notes {} +if {[package vcompare $git_version "1.6.6.2"] >= 0} { + set show_notes "--show-notes" +} + set runq {} set history {} set historyindex 0 diff --git a/gitk-git/po/pt_br.po b/gitk-git/po/pt_br.po new file mode 100644 index 0000000000..1486e3205a --- /dev/null +++ b/gitk-git/po/pt_br.po @@ -0,0 +1,1277 @@ +# Translation of gitk to Brazilian Portuguese. +# Copyright (C) 2007 Paul Mackerras, et al. +# This file is distributed under the same license as the gitk package. +# +# Alexandre Erwin Ittner <alexandre@ittner.com.br>, 2010. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: gitk\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2010-01-26 15:47-0800\n" +"PO-Revision-Date: 2010-12-06 23:39-0200\n" +"Last-Translator: Alexandre Erwin Ittner <alexandre@ittner.com.br>\n" +"Language-Team: Brazilian Portuguese <>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: gitk:115 +msgid "Couldn't get list of unmerged files:" +msgstr "Não foi possível obter a lista dos arquivos não mesclados:" + +#: gitk:274 +msgid "Error parsing revisions:" +msgstr "Erro ao interpretar revisões:" + +#: gitk:330 +msgid "Error executing --argscmd command:" +msgstr "Erro ao executar o comando--argscmd:" + +#: gitk:343 +msgid "No files selected: --merge specified but no files are unmerged." +msgstr "" +"Nenhum arquivo foi selecionado: --merge especificado mas não há arquivos não-" +"mesclados." + +#: gitk:346 +msgid "" +"No files selected: --merge specified but no unmerged files are within file " +"limit." +msgstr "" +"Nenhum arquivo foi selecionado: --merge especificado mas não há arquivos não-" +"mesclados dentro dos limites." + +#: gitk:368 gitk:516 +msgid "Error executing git log:" +msgstr "Erro ao executar git log:" + +#: gitk:386 gitk:532 +msgid "Reading" +msgstr "Lendo" + +#: gitk:446 gitk:4271 +msgid "Reading commits..." +msgstr "Lendo revisões..." + +#: gitk:449 gitk:1580 gitk:4274 +msgid "No commits selected" +msgstr "Nenhuma revisão foi selecionada" + +#: gitk:1456 +msgid "Can't parse git log output:" +msgstr "Não foi possível interpretar a saída do \"git log\":" + +#: gitk:1676 +msgid "No commit information available" +msgstr "Não há informações disponíveis sobre a revisão" + +#: gitk:1818 +msgid "mc" +msgstr "mc" + +#: gitk:1853 gitk:4064 gitk:9067 gitk:10607 gitk:10817 +msgid "OK" +msgstr "Ok" + +#: gitk:1855 gitk:4066 gitk:8657 gitk:8736 gitk:8851 gitk:8900 gitk:9069 +#: gitk:10608 gitk:10818 +msgid "Cancel" +msgstr "Cancelar" + +#: gitk:1980 +msgid "Update" +msgstr "Atualizar" + +#: gitk:1981 +msgid "Reload" +msgstr "Recarregar" + +#: gitk:1982 +msgid "Reread references" +msgstr "Ler as referências novamente" + +#: gitk:1983 +msgid "List references" +msgstr "Listar referências" + +#: gitk:1985 +msgid "Start git gui" +msgstr "Iniciar Git GUI" + +#: gitk:1987 +msgid "Quit" +msgstr "Sair" + +#: gitk:1979 +msgid "File" +msgstr "Arquivo" + +#: gitk:1991 +msgid "Preferences" +msgstr "Preferências" + +#: gitk:1990 +msgid "Edit" +msgstr "Editar" + +#: gitk:1995 +msgid "New view..." +msgstr "Nova vista..." + +#: gitk:1996 +msgid "Edit view..." +msgstr "Editar vista..." + +#: gitk:1997 +msgid "Delete view" +msgstr "Apagar vista" + +#: gitk:1999 +msgid "All files" +msgstr "Todos os arquivos" + +#: gitk:1994 gitk:3817 +msgid "View" +msgstr "Exibir" + +#: gitk:2004 gitk:2014 gitk:2787 +msgid "About gitk" +msgstr "Sobre o gitk" + +#: gitk:2005 gitk:2019 +msgid "Key bindings" +msgstr "Atalhos de teclado" + +#: gitk:2003 gitk:2018 +msgid "Help" +msgstr "Ajuda" + +#: gitk:2096 gitk:8132 +msgid "SHA1 ID:" +msgstr "SHA1 ID:" + +#: gitk:2127 +msgid "Row" +msgstr "Linha" + +#: gitk:2165 +msgid "Find" +msgstr "Encontrar" + +#: gitk:2166 +msgid "next" +msgstr "Próximo" + +#: gitk:2167 +msgid "prev" +msgstr "Anterior" + +#: gitk:2168 +msgid "commit" +msgstr "Revisão" + +#: gitk:2171 gitk:2173 gitk:4432 gitk:4455 gitk:4479 gitk:6420 gitk:6492 +#: gitk:6576 +msgid "containing:" +msgstr "contendo:" + +#: gitk:2174 gitk:3298 gitk:3303 gitk:4507 +msgid "touching paths:" +msgstr "envolvendo os caminhos:" + +#: gitk:2175 gitk:4512 +msgid "adding/removing string:" +msgstr "Adicionando/removendo texto:" + +#: gitk:2184 gitk:2186 +msgid "Exact" +msgstr "Exatamente" + +#: gitk:2186 gitk:4587 gitk:6388 +msgid "IgnCase" +msgstr "Ignorar maiúsculas/minúsculas" + +#: gitk:2186 gitk:4481 gitk:4585 gitk:6384 +msgid "Regexp" +msgstr "Expressão regular" + +#: gitk:2188 gitk:2189 gitk:4606 gitk:4636 gitk:4643 gitk:6512 gitk:6580 +msgid "All fields" +msgstr "Todos os campos" + +#: gitk:2189 gitk:4604 gitk:4636 gitk:6451 +msgid "Headline" +msgstr "Assunto" + +#: gitk:2190 gitk:4604 gitk:6451 gitk:6580 gitk:7013 +msgid "Comments" +msgstr "Descrição da revisão" + +#: gitk:2190 gitk:4604 gitk:4608 gitk:4643 gitk:6451 gitk:6948 gitk:8307 +#: gitk:8322 +msgid "Author" +msgstr "Autor" + +#: gitk:2190 gitk:4604 gitk:6451 gitk:6950 +msgid "Committer" +msgstr "Revisor" + +#: gitk:2221 +msgid "Search" +msgstr "Buscar" + +#: gitk:2229 +msgid "Diff" +msgstr "Diferenças" + +#: gitk:2231 +msgid "Old version" +msgstr "Versão antiga" + +#: gitk:2233 +msgid "New version" +msgstr "Versão nova" + +#: gitk:2235 +msgid "Lines of context" +msgstr "Número de linhas de contexto" + +#: gitk:2245 +msgid "Ignore space change" +msgstr "Ignorar mudanças de caixa" + +#: gitk:2304 +msgid "Patch" +msgstr "Diferenças" + +#: gitk:2306 +msgid "Tree" +msgstr "Árvore" + +#: gitk:2463 gitk:2480 +msgid "Diff this -> selected" +msgstr "Comparar esta revisão com a selecionada" + +#: gitk:2464 gitk:2481 +msgid "Diff selected -> this" +msgstr "Comparar a revisão selecionada com esta" + +#: gitk:2465 gitk:2482 +msgid "Make patch" +msgstr "Criar patch" + +#: gitk:2466 gitk:8715 +msgid "Create tag" +msgstr "Criar etiqueta" + +#: gitk:2467 gitk:8831 +msgid "Write commit to file" +msgstr "Salvar revisão para um arquivo" + +#: gitk:2468 gitk:8888 +msgid "Create new branch" +msgstr "Criar novo ramo" + +#: gitk:2469 +msgid "Cherry-pick this commit" +msgstr "Fazer cherry-pick desta revisão" + +#: gitk:2470 +msgid "Reset HEAD branch to here" +msgstr "Redefinir HEAD para cá" + +#: gitk:2471 +msgid "Mark this commit" +msgstr "Marcar esta revisão" + +#: gitk:2472 +msgid "Return to mark" +msgstr "Voltar à marca" + +#: gitk:2473 +msgid "Find descendant of this and mark" +msgstr "Encontrar descendente e marcar" + +#: gitk:2474 +msgid "Compare with marked commit" +msgstr "Comparar com a revisão marcada" + +#: gitk:2488 +msgid "Check out this branch" +msgstr "Efetuar checkout deste ramo" + +#: gitk:2489 +msgid "Remove this branch" +msgstr "Excluir este ramo" + +#: gitk:2496 +msgid "Highlight this too" +msgstr "Marcar este também" + +#: gitk:2497 +msgid "Highlight this only" +msgstr "Marcar apenas este" + +#: gitk:2498 +msgid "External diff" +msgstr "Diff externo" + +#: gitk:2499 +msgid "Blame parent commit" +msgstr "Anotar revisão anterior" + +#: gitk:2506 +msgid "Show origin of this line" +msgstr "Exibir origem desta linha" + +#: gitk:2507 +msgid "Run git gui blame on this line" +msgstr "Executar 'git blame' nesta linha" + +#: gitk:2789 +msgid "\n" +"Gitk - a commit viewer for git\n" +"\n" +"Copyright ©9 2005-2010 Paul Mackerras\n" +"\n" +"Use and redistribute under the terms of the GNU General Public License" +msgstr "\n" +"Gitk - um visualizador de revisões para o git \n" +"\n" +"Copyright ©9 2005-2010 Paul Mackerras\n" +"\n" +"Uso e distribuição segundo os termos da Licença Pública Geral GNU" + +#: gitk:2797 gitk:2862 gitk:9253 +msgid "Close" +msgstr "Fechar" + +#: gitk:2818 +msgid "Gitk key bindings" +msgstr "Atalhos de teclado" + +#: gitk:2821 +msgid "Gitk key bindings:" +msgstr "Atalhos de teclado:" + +#: gitk:2823 +#, tcl-format +msgid "<%s-Q>\t\tQuit" +msgstr "<%s-Q>\t\tSair" + +#: gitk:2824 +#, tcl-format +msgid "<%s-W>\t\tClose window" +msgstr "<%s-W>\t\tFechar janela" + +#: gitk:2825 +msgid "<Home>\t\tMove to first commit" +msgstr "<Home>\t\tIr para a primeira revisão" + +#: gitk:2826 +msgid "<End>\t\tMove to last commit" +msgstr "<End>\t\tIr para a última revisão" + +#: gitk:2827 +msgid "<Up>, p, i\tMove up one commit" +msgstr "<Up>, p, i\tIr para uma revisão acima" + +#: gitk:2828 +msgid "<Down>, n, k\tMove down one commit" +msgstr "<Down>, n, k\tIr para uma revisão abaixo" + +#: gitk:2829 +msgid "<Left>, z, j\tGo back in history list" +msgstr "<Left>, z, j\tVoltar no histórico" + +#: gitk:2830 +msgid "<Right>, x, l\tGo forward in history list" +msgstr "<Right>, x, l\tAvançar no histórico" + +#: gitk:2831 +msgid "<PageUp>\tMove up one page in commit list" +msgstr "<PageUp>\tSubir uma página na lista de revisões" + +#: gitk:2832 +msgid "<PageDown>\tMove down one page in commit list" +msgstr "<PageDown>\tDescer uma página na lista de revisões" + +#: gitk:2833 +#, tcl-format +msgid "<%s-Home>\tScroll to top of commit list" +msgstr "<%s-Home>\tRolar para o início da lista de revisões" + +#: gitk:2834 +#, tcl-format +msgid "<%s-End>\tScroll to bottom of commit list" +msgstr "<%s-End>\tRolar para o final da lista de revisões" + +#: gitk:2835 +#, tcl-format +msgid "<%s-Up>\tScroll commit list up one line" +msgstr "<%s-Up>\tRolar uma linha acima na lista de revisões" + +#: gitk:2836 +#, tcl-format +msgid "<%s-Down>\tScroll commit list down one line" +msgstr "<%s-Down>\tRolar uma linha abaixo na lista de revisões" + +#: gitk:2837 +#, tcl-format +msgid "<%s-PageUp>\tScroll commit list up one page" +msgstr "<%s-PageUp>\tRolar uma página acima na lista de revisões" + +#: gitk:2838 +#, tcl-format +msgid "<%s-PageDown>\tScroll commit list down one page" +msgstr "<%s-PageDown>\tRolar uma página abaixo na lista de revisões" + +#: gitk:2839 +msgid "<Shift-Up>\tFind backwards (upwards, later commits)" +msgstr "<Shift-Up>\tProcurar próxima (revisões mas recentes)" + +#: gitk:2840 +msgid "<Shift-Down>\tFind forwards (downwards, earlier commits)" +msgstr "<Shift-Down>\tProcurar anterior (revisões mais antigas)" + +#: gitk:2841 +msgid "<Delete>, b\tScroll diff view up one page" +msgstr "<Delete>, b\tRola alterações uma página acima" + +#: gitk:2842 +msgid "<Backspace>\tScroll diff view up one page" +msgstr "<Backspace>\tRolar alterações uma página abaixo" + +#: gitk:2843 +msgid "<Space>\t\tScroll diff view down one page" +msgstr "<Space>\t\tRolar alterações uma página abaixo" + +#: gitk:2844 +msgid "u\t\tScroll diff view up 18 lines" +msgstr "u\t\tRolar alterações 18 linhas acima" + +#: gitk:2845 +msgid "d\t\tScroll diff view down 18 lines" +msgstr "d\t\tRolar alterações 18 linhas abaixo" + +#: gitk:2846 +#, tcl-format +msgid "<%s-F>\t\tFind" +msgstr "<%s-F>\t\tProcurar" + +#: gitk:2847 +#, tcl-format +msgid "<%s-G>\t\tMove to next find hit" +msgstr "<%s-G>\t\tIr para a próxima ocorrência" + +#: gitk:2848 +msgid "<Return>\tMove to next find hit" +msgstr "<Return>\tIr para a próxima ocorrência" + +#: gitk:2849 +msgid "/\t\tFocus the search box" +msgstr "/\t\tPor foco na caixa de busca" + +#: gitk:2850 +msgid "?\t\tMove to previous find hit" +msgstr "?\t\tIr para a ocorrência anterior" + +#: gitk:2851 +msgid "f\t\tScroll diff view to next file" +msgstr "f\t\tRolar alterações para o próximo arquivo" + +#: gitk:2852 +#, tcl-format +msgid "<%s-S>\t\tSearch for next hit in diff view" +msgstr "<%s-S>\t\tProcurar a próxima ocorrência na lista de alterações" + +#: gitk:2853 +#, tcl-format +msgid "<%s-R>\t\tSearch for previous hit in diff view" +msgstr "<%s-R>\t\tProcurar ocorrência anterior na lista de alterações" + +#: gitk:2854 +#, tcl-format +msgid "<%s-KP+>\tIncrease font size" +msgstr "<%s-KP+>\tAumentar tamanho da fonte" + +#: gitk:2855 +#, tcl-format +msgid "<%s-plus>\tIncrease font size" +msgstr "<%s-plus>\tAumentar tamanho da fonte" + +#: gitk:2856 +#, tcl-format +msgid "<%s-KP->\tDecrease font size" +msgstr "<%s-KP->\tReduzir tamanho da fonte" + +#: gitk:2857 +#, tcl-format +msgid "<%s-minus>\tDecrease font size" +msgstr "<%s-minus>\tReduzir tamanho da fonte" + +#: gitk:2858 +msgid "<F5>\t\tUpdate" +msgstr "<F5>\t\tAtualizar" + +#: gitk:3313 gitk:3322 +#, tcl-format +msgid "Error creating temporary directory %s:" +msgstr "Erro ao criar o diretório temporário %s:" + +#: gitk:3335 +#, tcl-format +msgid "Error getting \"%s\" from %s:" +msgstr "Erro ao ler \"%s\" de %s:" + +#: gitk:3398 +msgid "command failed:" +msgstr "O comando falhou:" + +#: gitk:3547 +msgid "No such commit" +msgstr "Revisão não encontrada" + +#: gitk:3561 +msgid "git gui blame: command failed:" +msgstr "Comando 'git gui blame' falhou:" + +#: gitk:3592 +#, tcl-format +msgid "Couldn't read merge head: %s" +msgstr "Impossível ler merge head: %s" + +#: gitk:3600 +#, tcl-format +msgid "Error reading index: %s" +msgstr "Erro ao ler o índice: %s" + +#: gitk:3625 +#, tcl-format +msgid "Couldn't start git blame: %s" +msgstr "Não foi possível inciar o 'git blame': %s" + +#: gitk:3628 gitk:6419 +msgid "Searching" +msgstr "Procurando" + +#: gitk:3660 +#, tcl-format +msgid "Error running git blame: %s" +msgstr "Erro ao executar 'git blame': %s" + +#: gitk:3688 +#, tcl-format +msgid "That line comes from commit %s, which is not in this view" +msgstr "Esta linha vem da revisão %s, que não está nesta vista" + +#: gitk:3702 +msgid "External diff viewer failed:" +msgstr "Erro do visualizador de alterações externo:" + +#: gitk:3820 +msgid "Gitk view definition" +msgstr "Definir vista" + +#: gitk:3824 +msgid "Remember this view" +msgstr "Lembrar esta vista" + +#: gitk:3825 +msgid "References (space separated list):" +msgstr "Referências (separar a lista com um espaço):" + +#: gitk:3826 +msgid "Branches & tags:" +msgstr "Ramos & etiquetas:" + +#: gitk:3827 +msgid "All refs" +msgstr "Todas as referências" + +#: gitk:3828 +msgid "All (local) branches" +msgstr "Todos os ramos locais" + +#: gitk:3829 +msgid "All tags" +msgstr "Todas as etiquetas" + +#: gitk:3830 +msgid "All remote-tracking branches" +msgstr "Todos os ramos de rastreio" + +#: gitk:3831 +msgid "Commit Info (regular expressions):" +msgstr "Informações da revisão (expressões regulares):" + +#: gitk:3832 +msgid "Author:" +msgstr "Autor:" + +#: gitk:3833 +msgid "Committer:" +msgstr "Revisor:" + +#: gitk:3834 +msgid "Commit Message:" +msgstr "Descrição da revisão:" + +#: gitk:3835 +msgid "Matches all Commit Info criteria" +msgstr "Coincidir todos os critérios de informações da revisão" + +#: gitk:3836 +msgid "Changes to Files:" +msgstr "Mudanças para os arquivos:" + +#: gitk:3837 +msgid "Fixed String" +msgstr "Texto fixo" + +#: gitk:3838 +msgid "Regular Expression" +msgstr "Expressão regular" + +#: gitk:3839 +msgid "Search string:" +msgstr "Texto de busca" + +#: gitk:3840 +msgid "" +"Commit Dates (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 " +"15:27:38\"):" +msgstr "" +"Datas de revisão (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 " +"15:27:38\"):" + +#: gitk:3841 +msgid "Since:" +msgstr "Desde:" + +#: gitk:3842 +msgid "Until:" +msgstr "Até:" + +#: gitk:3843 +msgid "Limit and/or skip a number of revisions (positive integer):" +msgstr "Limitar e/ou ignorar um número de revisões (inteiro positivo):" + +#: gitk:3844 +msgid "Number to show:" +msgstr "Número para mostrar:" + +#: gitk:3845 +msgid "Number to skip:" +msgstr "Número para ignorar:" + +#: gitk:3846 +msgid "Miscellaneous options:" +msgstr "Opções diversas:" + +#: gitk:3847 +msgid "Strictly sort by date" +msgstr "Ordenar estritamente pela data" + +#: gitk:3848 +msgid "Mark branch sides" +msgstr "Marcar os dois lados do ramo" + +#: gitk:3849 +msgid "Limit to first parent" +msgstr "Limitar ao primeiro antecessor" + +#: gitk:3850 +msgid "Simple history" +msgstr "Histórico simplificado" + +#: gitk:3851 +msgid "Additional arguments to git log:" +msgstr "Argumentos adicionais para o 'git log':" + +#: gitk:3852 +msgid "Enter files and directories to include, one per line:" +msgstr "Arquivos e diretórios para incluir, um por linha" + +#: gitk:3853 +msgid "Command to generate more commits to include:" +msgstr "Comando para gerar mais revisões para incluir:" + +#: gitk:3977 +msgid "Gitk: edit view" +msgstr "Gitk: editar vista" + +#: gitk:3985 +msgid "-- criteria for selecting revisions" +msgstr "-- critérios para selecionar revisões" + +#: gitk:3990 +msgid "View Name" +msgstr "Nome da vista" + +#: gitk:4065 +msgid "Apply (F5)" +msgstr "Aplicar (F5)" + +#: gitk:4103 +msgid "Error in commit selection arguments:" +msgstr "Erro nos argumentos de seleção de revisões:" + +#: gitk:4156 gitk:4208 gitk:4656 gitk:4670 gitk:5931 gitk:11551 gitk:11552 +msgid "None" +msgstr "Nenhum" + +#: gitk:4604 gitk:6451 gitk:8309 gitk:8324 +msgid "Date" +msgstr "Data" + +#: gitk:4604 gitk:6451 +msgid "CDate" +msgstr "DataR" + +#: gitk:4753 gitk:4758 +msgid "Descendant" +msgstr "Descendente de" + +#: gitk:4754 +msgid "Not descendant" +msgstr "Não descendente de" + +#: gitk:4761 gitk:4766 +msgid "Ancestor" +msgstr "Antecessor de" + +#: gitk:4762 +msgid "Not ancestor" +msgstr "Não antecessor de" + +#: gitk:5052 +msgid "Local changes checked in to index but not committed" +msgstr "Mudanças locais marcadas, porém não salvas" + +#: gitk:5088 +msgid "Local uncommitted changes, not checked in to index" +msgstr "Mudanças locais não marcadas" + +#: gitk:6769 +msgid "many" +msgstr "muitas" + +#: gitk:6952 +msgid "Tags:" +msgstr "Etiquetas:" + +#: gitk:6969 gitk:6975 gitk:8302 +msgid "Parent" +msgstr "Antecessor" + +#: gitk:6980 +msgid "Child" +msgstr "Descendente" + +#: gitk:6989 +msgid "Branch" +msgstr "Ramo" + +#: gitk:6992 +msgid "Follows" +msgstr "Segue" + +#: gitk:6995 +msgid "Precedes" +msgstr "Precede" + +#: gitk:7532 +#, tcl-format +msgid "Error getting diffs: %s" +msgstr "Erro ao obter diferenças: %s" + +#: gitk:8130 +msgid "Goto:" +msgstr "Ir para:" + +#: gitk:8151 +#, tcl-format +msgid "Short SHA1 id %s is ambiguous" +msgstr "O id SHA1 %s é ambíguo" + +#: gitk:8158 +#, tcl-format +msgid "Revision %s is not known" +msgstr "Revisão %s desconhecida" + +#: gitk:8168 +#, tcl-format +msgid "SHA1 id %s is not known" +msgstr "Id SHA1 %s desconhecido" + +#: gitk:8170 +#, tcl-format +msgid "Revision %s is not in the current view" +msgstr "A revisão %s não está na vista atual" + +#: gitk:8312 +msgid "Children" +msgstr "Descendentes" + +#: gitk:8370 +#, tcl-format +msgid "Reset %s branch to here" +msgstr "Redefinir ramo %s para este ponto" + +#: gitk:8372 +msgid "Detached head: can't reset" +msgstr "Detached head: impossível redefinir" + +#: gitk:8481 gitk:8487 +msgid "Skipping merge commit " +msgstr "Saltando revisão de mesclagem" + +#: gitk:8496 gitk:8501 +msgid "Error getting patch ID for " +msgstr "Erro ao obter patch ID para" + +#: gitk:8497 gitk:8502 +msgid " - stopping\n" +msgstr "- parando\n" + +#: gitk:8507 gitk:8510 gitk:8518 gitk:8532 gitk:8541 +msgid "Commit " +msgstr "Revisão" + +#: gitk:8511 +msgid "" +" is the same patch as\n" +" " +msgstr "" +"é o mesmo patch que\n" +" " + +#: gitk:8519 +msgid "" +" differs from\n" +" " +msgstr "difere de" + +#: gitk:8521 +msgid "" +"Diff of commits:\n" +"\n" +msgstr "" +"Diferença de revisões:\n" +"\n" + +#: gitk:8533 gitk:8542 +#, tcl-format +msgid " has %s children - stopping\n" +msgstr "possui %s descendentes - parando\n" + +#: gitk:8561 +#, tcl-format +msgid "Error writing commit to file: %s" +msgstr "Erro ao salvar revisão para o arquivo: %s" + +#: gitk:8567 +#, tcl-format +msgid "Error diffing commits: %s" +msgstr "Erro ao comparar revisões: %s" + +#: gitk:8598 +msgid "Top" +msgstr "Início" + +#: gitk:8599 +msgid "From" +msgstr "De" + +#: gitk:8604 +msgid "To" +msgstr "Para" + +#: gitk:8628 +msgid "Generate patch" +msgstr "Gerar patch" + +#: gitk:8630 +msgid "From:" +msgstr "De:" + +#: gitk:8639 +msgid "To:" +msgstr "Para:" + +#: gitk:8648 +msgid "Reverse" +msgstr "Inverter" + +#: gitk:8650 gitk:8845 +msgid "Output file:" +msgstr "Arquivo de saída:" + +#: gitk:8656 +msgid "Generate" +msgstr "Gerar" + +#: gitk:8694 +msgid "Error creating patch:" +msgstr "Erro ao criar patch:" + +#: gitk:8717 gitk:8833 gitk:8890 +msgid "ID:" +msgstr "ID:" + +#: gitk:8726 +msgid "Tag name:" +msgstr "Nome da etiqueta:" + +#: gitk:8729 +msgid "Tag message is optional" +msgstr "A descrição da etiqueta é opcional" + +#: gitk:8731 +msgid "Tag message:" +msgstr "Descrição da etiqueta" + +#: gitk:8735 gitk:8899 +msgid "Create" +msgstr "Criar" + +#: gitk:8753 +msgid "No tag name specified" +msgstr "Nome da etiqueta não indicado" + +#: gitk:8757 +#, tcl-format +msgid "Tag \"%s\" already exists" +msgstr "Etiqueta \"%s\" já existe" + +#: gitk:8767 +msgid "Error creating tag:" +msgstr "Erro ao criar etiqueta:" + +#: gitk:8842 +msgid "Command:" +msgstr "Comando:" + +#: gitk:8850 +msgid "Write" +msgstr "Exportar" + +#: gitk:8868 +msgid "Error writing commit:" +msgstr "Erro ao exportar revisão" + +#: gitk:8895 +msgid "Name:" +msgstr "Nome:" + +#: gitk:8918 +msgid "Please specify a name for the new branch" +msgstr "Indique um nome para o novo ramo" + +#: gitk:8923 +#, tcl-format +msgid "Branch '%s' already exists. Overwrite?" +msgstr "O ramo \"%s\" já existe. Sobrescrever?" + +#: gitk:8989 +#, tcl-format +msgid "Commit %s is already included in branch %s -- really re-apply it?" +msgstr "Revisão %s já inclusa no ramo %s -- você realmente deseja reaplicá-la?" + +#: gitk:8994 +msgid "Cherry-picking" +msgstr "Cherry-picking" + +#: gitk:9003 +#, tcl-format +msgid "" +"Cherry-pick failed because of local changes to file '%s'.\n" +"Please commit, reset or stash your changes and try again." +msgstr "" +"O cherry-pick falhou porque o arquivo \"%s\" possui mudanças locais.\n" +"Salve a uma revisão, redefina ou armazene (stash) suas mudanças e tente " +"novamente." + +#: gitk:9009 +msgid "" +"Cherry-pick failed because of merge conflict.\n" +"Do you wish to run git citool to resolve it?" +msgstr "" +"O cherry-pick falhou porque houve um conflito na mesclagem.\n" +"Executar o 'git citool' para resolvê-lo?" + +#: gitk:9025 +msgid "No changes committed" +msgstr "Nenhuma revisão foi salva" + +#: gitk:9051 +msgid "Confirm reset" +msgstr "Confirmar redefinição" + +#: gitk:9053 +#, tcl-format +msgid "Reset branch %s to %s?" +msgstr "Você realmente deseja redefinir o ramo %s para %s?" + +#: gitk:9055 +msgid "Reset type:" +msgstr "Tipo de redefinição" + +#: gitk:9058 +msgid "Soft: Leave working tree and index untouched" +msgstr "Soft: deixa a árvore de trabalho e o índice intocados" + +#: gitk:9061 +msgid "Mixed: Leave working tree untouched, reset index" +msgstr "Misto: Deixa a árvore de trabalho intocada, redefine o índice" + +#: gitk:9064 +msgid "" +"Hard: Reset working tree and index\n" +"(discard ALL local changes)" +msgstr "" +"Hard: Redefine a árvore de trabalho e o índice\n" +"(descarta TODAS as mudanças locais)" + +#: gitk:9081 +msgid "Resetting" +msgstr "Redefinindo" + +#: gitk:9141 +msgid "Checking out" +msgstr "Abrindo" + +#: gitk:9194 +msgid "Cannot delete the currently checked-out branch" +msgstr "Impossível excluir o ramo atualmente aberto" + +#: gitk:9200 +#, tcl-format +msgid "" +"The commits on branch %s aren't on any other branch.\n" +"Really delete branch %s?" +msgstr "" +"As revisões do ramo \"%s\" não existem em nenhum outro ramo.\n" +"Você realmente deseja excluir ramo \"%s\"?" + +#: gitk:9231 +#, tcl-format +msgid "Tags and heads: %s" +msgstr "Referências: %s" + +#: gitk:9246 +msgid "Filter" +msgstr "Filtro" + +#: gitk:9541 +msgid "" +"Error reading commit topology information; branch and preceding/following " +"tag information will be incomplete." +msgstr "" +"Erro ao ler a topologia das revisões; as informações dos ramos e etiquetas " +"antecessoras/sucessoras estarão incompletas" + +#: gitk:10527 +msgid "Tag" +msgstr "Etiqueta" + +#: gitk:10527 +msgid "Id" +msgstr "Id" + +#: gitk:10576 +msgid "Gitk font chooser" +msgstr "Selecionar fontes do Gitk" + +#: gitk:10593 +msgid "B" +msgstr "B" + +#: gitk:10596 +msgid "I" +msgstr "I" + +#: gitk:10714 +msgid "Gitk preferences" +msgstr "Preferências do Gitk" + +#: gitk:10716 +msgid "Commit list display options" +msgstr "Opções da lista de revisões" + +#: gitk:10719 +msgid "Maximum graph width (lines)" +msgstr "Largura máxima do grafo (linhas)" + +#: gitk:10722 +#, tcl-format +msgid "Maximum graph width (% of pane)" +msgstr "Largura máxima do grafo (% do painel)" + +#: gitk:10725 +msgid "Show local changes" +msgstr "Exibir mudanças locais" + +#: gitk:10728 +msgid "Auto-select SHA1" +msgstr "Selecionar o SHA1 automaticamente" + +#: gitk:10731 +msgid "Hide remote refs" +msgstr "Ocultar referências remotas" + +#: gitk:10735 +msgid "Diff display options" +msgstr "Opções de exibição das alterações" + +#: gitk:10737 +msgid "Tab spacing" +msgstr "Espaços por tabulação" + +#: gitk:10740 +msgid "Display nearby tags" +msgstr "Exibir etiquetas próximas" + +#: gitk:10743 +msgid "Limit diffs to listed paths" +msgstr "Limitar diferenças aos caminhos listados" + +#: gitk:10746 +msgid "Support per-file encodings" +msgstr "Usar codificações distintas por arquivo" + +#: gitk:10752 gitk:10832 +msgid "External diff tool" +msgstr "Ferramenta 'diff' externa" + +#: gitk:10753 +msgid "Choose..." +msgstr "Selecionar..." + +#: gitk:10758 +msgid "General options" +msgstr "Opções gerais" + +#: gitk:10761 +msgid "Use themed widgets" +msgstr "Usar temas para as janelas" + +#: gitk:10763 +msgid "(change requires restart)" +msgstr "(exige reinicialização)" + +#: gitk:10765 +msgid "(currently unavailable)" +msgstr "(atualmente indisponível)" + +#: gitk:10769 +msgid "Colors: press to choose" +msgstr "Cores: clique para escolher" + +#: gitk:10772 +msgid "Interface" +msgstr "Interface" + +#: gitk:10773 +msgid "interface" +msgstr "interface" + +#: gitk:10776 +msgid "Background" +msgstr "Segundo plano" + +#: gitk:10777 gitk:10807 +msgid "background" +msgstr "segundo plano" + +#: gitk:10780 +msgid "Foreground" +msgstr "Primeiro plano" + +#: gitk:10781 +msgid "foreground" +msgstr "primeiro plano" + +#: gitk:10784 +msgid "Diff: old lines" +msgstr "Diff: linhas excluídas" + +#: gitk:10785 +msgid "diff old lines" +msgstr "linhas excluídas" + +#: gitk:10789 +msgid "Diff: new lines" +msgstr "Diff: linhas adicionadas" + +#: gitk:10790 +msgid "diff new lines" +msgstr "linhas adicionadas" + +#: gitk:10794 +msgid "Diff: hunk header" +msgstr "Diff: cabeçalho do bloco" + +#: gitk:10796 +msgid "diff hunk header" +msgstr "cabeçalho do bloco" + +#: gitk:10800 +msgid "Marked line bg" +msgstr "2º plano da linha marcada" + +#: gitk:10802 +msgid "marked line background" +msgstr "segundo plano da linha marcada" + +#: gitk:10806 +msgid "Select bg" +msgstr "2º plano da seleção" + +#: gitk:10810 +msgid "Fonts: press to choose" +msgstr "Fontes: clique para escolher" + +#: gitk:10812 +msgid "Main font" +msgstr "Fonte principal" + +#: gitk:10813 +msgid "Diff display font" +msgstr "Fonte da lista de mudanças" + +#: gitk:10814 +msgid "User interface font" +msgstr "Fonte da interface" + +#: gitk:10842 +#, tcl-format +msgid "Gitk: choose color for %s" +msgstr "Gitk: selecionar cor para %s" + +#: gitk:11445 +msgid "Cannot find a git repository here." +msgstr "Não há nenhum repositório git aqui." + +#: gitk:11449 +#, tcl-format +msgid "Cannot find the git directory \"%s\"." +msgstr "Impossível encontrar o diretório git \"%s\"." + +#: gitk:11496 +#, tcl-format +msgid "Ambiguous argument '%s': both revision and filename" +msgstr "" +"O argumento \"%s\" é ambíguo (especifica tanto uma revisão e um nome de " +"arquivo)" + +#: gitk:11508 +msgid "Bad arguments to gitk:" +msgstr "Argumentos incorretos para o gitk:" + +#: gitk:11604 +msgid "Command line" +msgstr "Linha de comando" diff --git a/gitk-git/po/sv.po b/gitk-git/po/sv.po index 386763ade7..2f07a2e2d9 100644 --- a/gitk-git/po/sv.po +++ b/gitk-git/po/sv.po @@ -1,5 +1,5 @@ # Swedish translation for gitk -# Copyright (C) 2005-2009 Paul Mackerras +# Copyright (C) 2005-2010 Paul Mackerras # This file is distributed under the same license as the gitk package. # # Peter Krefting <peter@softwolves.pp.se>, 2008-2010. @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: sv\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-01-28 13:16+0100\n" -"PO-Revision-Date: 2010-01-28 13:48+0100\n" +"POT-Creation-Date: 2010-09-12 21:14+0100\n" +"PO-Revision-Date: 2010-09-12 21:16+0100\n" "Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n" "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n" "MIME-Version: 1.0\n" @@ -24,17 +24,17 @@ msgstr "Kunde inte hämta lista över ej sammanslagna filer:" msgid "Error parsing revisions:" msgstr "Fel vid tolkning av revisioner:" -#: gitk:329 +#: gitk:330 msgid "Error executing --argscmd command:" msgstr "Fel vid körning av --argscmd-kommando:" -#: gitk:342 +#: gitk:343 msgid "No files selected: --merge specified but no files are unmerged." msgstr "" "Inga filer valdes: --merge angavs men det finns inga filer som inte har " "slagits samman." -#: gitk:345 +#: gitk:346 msgid "" "No files selected: --merge specified but no unmerged files are within file " "limit." @@ -42,600 +42,605 @@ msgstr "" "Inga filer valdes: --merge angavs men det finns inga filer inom " "filbegränsningen." -#: gitk:367 gitk:514 +#: gitk:368 gitk:516 msgid "Error executing git log:" msgstr "Fel vid körning av git log:" -#: gitk:385 gitk:530 +#: gitk:386 gitk:532 msgid "Reading" msgstr "Läser" -#: gitk:445 gitk:4261 +#: gitk:446 gitk:4271 msgid "Reading commits..." msgstr "Läser incheckningar..." -#: gitk:448 gitk:1578 gitk:4264 +#: gitk:449 gitk:1580 gitk:4274 msgid "No commits selected" msgstr "Inga incheckningar markerade" -#: gitk:1454 +#: gitk:1456 msgid "Can't parse git log output:" msgstr "Kan inte tolka utdata från git log:" -#: gitk:1674 +#: gitk:1676 msgid "No commit information available" msgstr "Ingen incheckningsinformation är tillgänglig" -#: gitk:1816 +#: gitk:1818 msgid "mc" msgstr "mc" -#: gitk:1851 gitk:4054 gitk:9044 gitk:10585 gitk:10804 +#: gitk:1853 gitk:4064 gitk:9067 gitk:10607 gitk:10817 msgid "OK" msgstr "OK" -#: gitk:1853 gitk:4056 gitk:8634 gitk:8713 gitk:8828 gitk:8877 gitk:9046 -#: gitk:10586 gitk:10805 +#: gitk:1855 gitk:4066 gitk:8657 gitk:8736 gitk:8851 gitk:8900 gitk:9069 +#: gitk:10608 gitk:10818 msgid "Cancel" msgstr "Avbryt" -#: gitk:1975 +#: gitk:1980 msgid "Update" msgstr "Uppdatera" -#: gitk:1976 +#: gitk:1981 msgid "Reload" msgstr "Ladda om" -#: gitk:1977 +#: gitk:1982 msgid "Reread references" msgstr "Läs om referenser" -#: gitk:1978 +#: gitk:1983 msgid "List references" msgstr "Visa referenser" -#: gitk:1980 +#: gitk:1985 msgid "Start git gui" msgstr "Starta git gui" -#: gitk:1982 +#: gitk:1987 msgid "Quit" msgstr "Avsluta" -#: gitk:1974 +#: gitk:1979 msgid "File" msgstr "Arkiv" -#: gitk:1986 +#: gitk:1991 msgid "Preferences" msgstr "Inställningar" -#: gitk:1985 +#: gitk:1990 msgid "Edit" msgstr "Redigera" -#: gitk:1990 +#: gitk:1995 msgid "New view..." msgstr "Ny vy..." -#: gitk:1991 +#: gitk:1996 msgid "Edit view..." msgstr "Ändra vy..." -#: gitk:1992 +#: gitk:1997 msgid "Delete view" msgstr "Ta bort vy" -#: gitk:1994 +#: gitk:1999 msgid "All files" msgstr "Alla filer" -#: gitk:1989 gitk:3808 +#: gitk:1994 gitk:3817 msgid "View" msgstr "Visa" -#: gitk:1999 gitk:2009 gitk:2780 +#: gitk:2004 gitk:2014 gitk:2787 msgid "About gitk" msgstr "Om gitk" -#: gitk:2000 gitk:2014 +#: gitk:2005 gitk:2019 msgid "Key bindings" msgstr "Tangentbordsbindningar" -#: gitk:1998 gitk:2013 +#: gitk:2003 gitk:2018 msgid "Help" msgstr "Hjälp" -#: gitk:2091 gitk:8110 +#: gitk:2096 gitk:8132 msgid "SHA1 ID:" msgstr "SHA1-id:" -#: gitk:2122 +#: gitk:2127 msgid "Row" msgstr "Rad" -#: gitk:2160 +#: gitk:2165 msgid "Find" msgstr "Sök" -#: gitk:2161 +#: gitk:2166 msgid "next" msgstr "nästa" -#: gitk:2162 +#: gitk:2167 msgid "prev" msgstr "föreg" -#: gitk:2163 +#: gitk:2168 msgid "commit" msgstr "incheckning" -#: gitk:2166 gitk:2168 gitk:4422 gitk:4445 gitk:4469 gitk:6410 gitk:6482 -#: gitk:6566 +#: gitk:2171 gitk:2173 gitk:4432 gitk:4455 gitk:4479 gitk:6420 gitk:6492 +#: gitk:6576 msgid "containing:" msgstr "som innehåller:" -#: gitk:2169 gitk:3290 gitk:3295 gitk:4497 +#: gitk:2174 gitk:3298 gitk:3303 gitk:4507 msgid "touching paths:" msgstr "som rör sökväg:" -#: gitk:2170 gitk:4502 +#: gitk:2175 gitk:4512 msgid "adding/removing string:" msgstr "som lägger/till tar bort sträng:" -#: gitk:2179 gitk:2181 +#: gitk:2184 gitk:2186 msgid "Exact" msgstr "Exakt" -#: gitk:2181 gitk:4577 gitk:6378 +#: gitk:2186 gitk:4587 gitk:6388 msgid "IgnCase" msgstr "IgnVersaler" -#: gitk:2181 gitk:4471 gitk:4575 gitk:6374 +#: gitk:2186 gitk:4481 gitk:4585 gitk:6384 msgid "Regexp" msgstr "Reg.uttr." -#: gitk:2183 gitk:2184 gitk:4596 gitk:4626 gitk:4633 gitk:6502 gitk:6570 +#: gitk:2188 gitk:2189 gitk:4606 gitk:4636 gitk:4643 gitk:6512 gitk:6580 msgid "All fields" msgstr "Alla fält" -#: gitk:2184 gitk:4594 gitk:4626 gitk:6441 +#: gitk:2189 gitk:4604 gitk:4636 gitk:6451 msgid "Headline" msgstr "Rubrik" -#: gitk:2185 gitk:4594 gitk:6441 gitk:6570 gitk:7003 +#: gitk:2190 gitk:4604 gitk:6451 gitk:6580 gitk:7013 msgid "Comments" msgstr "Kommentarer" -#: gitk:2185 gitk:4594 gitk:4598 gitk:4633 gitk:6441 gitk:6938 gitk:8285 -#: gitk:8300 +#: gitk:2190 gitk:4604 gitk:4608 gitk:4643 gitk:6451 gitk:6948 gitk:8307 +#: gitk:8322 msgid "Author" msgstr "Författare" -#: gitk:2185 gitk:4594 gitk:6441 gitk:6940 +#: gitk:2190 gitk:4604 gitk:6451 gitk:6950 msgid "Committer" msgstr "Incheckare" -#: gitk:2216 +#: gitk:2221 msgid "Search" msgstr "Sök" -#: gitk:2224 +#: gitk:2229 msgid "Diff" msgstr "Diff" -#: gitk:2226 +#: gitk:2231 msgid "Old version" msgstr "Gammal version" -#: gitk:2228 +#: gitk:2233 msgid "New version" msgstr "Ny version" -#: gitk:2230 +#: gitk:2235 msgid "Lines of context" msgstr "Rader sammanhang" -#: gitk:2240 +#: gitk:2245 msgid "Ignore space change" msgstr "Ignorera ändringar i blanksteg" -#: gitk:2299 +#: gitk:2304 msgid "Patch" msgstr "Patch" -#: gitk:2301 +#: gitk:2306 msgid "Tree" msgstr "Träd" -#: gitk:2456 gitk:2473 +#: gitk:2463 gitk:2480 msgid "Diff this -> selected" msgstr "Diff denna -> markerad" -#: gitk:2457 gitk:2474 +#: gitk:2464 gitk:2481 msgid "Diff selected -> this" msgstr "Diff markerad -> denna" -#: gitk:2458 gitk:2475 +#: gitk:2465 gitk:2482 msgid "Make patch" msgstr "Skapa patch" -#: gitk:2459 gitk:8692 +#: gitk:2466 gitk:8715 msgid "Create tag" msgstr "Skapa tagg" -#: gitk:2460 gitk:8808 +#: gitk:2467 gitk:8831 msgid "Write commit to file" msgstr "Skriv incheckning till fil" -#: gitk:2461 gitk:8865 +#: gitk:2468 gitk:8888 msgid "Create new branch" msgstr "Skapa ny gren" -#: gitk:2462 +#: gitk:2469 msgid "Cherry-pick this commit" msgstr "Plocka denna incheckning" -#: gitk:2463 +#: gitk:2470 msgid "Reset HEAD branch to here" msgstr "Återställ HEAD-grenen hit" -#: gitk:2464 +#: gitk:2471 msgid "Mark this commit" msgstr "Markera denna incheckning" -#: gitk:2465 +#: gitk:2472 msgid "Return to mark" msgstr "Återgå till markering" -#: gitk:2466 +#: gitk:2473 msgid "Find descendant of this and mark" msgstr "Hitta efterföljare till denna och markera" -#: gitk:2467 +#: gitk:2474 msgid "Compare with marked commit" msgstr "Jämför med markerad incheckning" -#: gitk:2481 +#: gitk:2488 msgid "Check out this branch" msgstr "Checka ut denna gren" -#: gitk:2482 +#: gitk:2489 msgid "Remove this branch" msgstr "Ta bort denna gren" -#: gitk:2489 +#: gitk:2496 msgid "Highlight this too" msgstr "Markera även detta" -#: gitk:2490 +#: gitk:2497 msgid "Highlight this only" msgstr "Markera bara detta" -#: gitk:2491 +#: gitk:2498 msgid "External diff" msgstr "Extern diff" -#: gitk:2492 +#: gitk:2499 msgid "Blame parent commit" msgstr "Klandra föräldraincheckning" -#: gitk:2499 +#: gitk:2506 msgid "Show origin of this line" msgstr "Visa ursprunget för den här raden" -#: gitk:2500 +#: gitk:2507 msgid "Run git gui blame on this line" msgstr "Kör git gui blame på den här raden" -#: gitk:2782 +#: gitk:2789 msgid "" "\n" "Gitk - a commit viewer for git\n" "\n" -"Copyright \\u00a9 2005-2010 Paul Mackerras\n" +"Copyright ©9 2005-2010 Paul Mackerras\n" "\n" "Use and redistribute under the terms of the GNU General Public License" msgstr "" "\n" "Gitk - en incheckningsvisare för git\n" "\n" -"Copyright \\u00a9 2005-2010 Paul Mackerras\n" +"Copyright ©9 2005-2010 Paul Mackerras\n" "\n" "Använd och vidareförmedla enligt villkoren i GNU General Public License" -#: gitk:2790 gitk:2854 gitk:9230 +#: gitk:2797 gitk:2862 gitk:9253 msgid "Close" msgstr "Stäng" -#: gitk:2811 +#: gitk:2818 msgid "Gitk key bindings" msgstr "Tangentbordsbindningar för Gitk" -#: gitk:2814 +#: gitk:2821 msgid "Gitk key bindings:" msgstr "Tangentbordsbindningar för Gitk:" -#: gitk:2816 +#: gitk:2823 #, tcl-format msgid "<%s-Q>\t\tQuit" msgstr "<%s-Q>\t\tAvsluta" -#: gitk:2817 +#: gitk:2824 +#, tcl-format +msgid "<%s-W>\t\tClose window" +msgstr "<%s-W>\t\tStäng fönster" + +#: gitk:2825 msgid "<Home>\t\tMove to first commit" msgstr "<Home>\t\tGå till första incheckning" -#: gitk:2818 +#: gitk:2826 msgid "<End>\t\tMove to last commit" msgstr "<End>\t\tGå till sista incheckning" -#: gitk:2819 +#: gitk:2827 msgid "<Up>, p, i\tMove up one commit" msgstr "<Upp>, p, i\tGå en incheckning upp" -#: gitk:2820 +#: gitk:2828 msgid "<Down>, n, k\tMove down one commit" msgstr "<Ned>, n, k\tGå en incheckning ned" -#: gitk:2821 +#: gitk:2829 msgid "<Left>, z, j\tGo back in history list" msgstr "<Vänster>, z, j\tGå bakåt i historiken" -#: gitk:2822 +#: gitk:2830 msgid "<Right>, x, l\tGo forward in history list" msgstr "<Höger>, x, l\tGå framåt i historiken" -#: gitk:2823 +#: gitk:2831 msgid "<PageUp>\tMove up one page in commit list" msgstr "<PageUp>\tGå upp en sida i incheckningslistan" -#: gitk:2824 +#: gitk:2832 msgid "<PageDown>\tMove down one page in commit list" msgstr "<PageDown>\tGå ned en sida i incheckningslistan" -#: gitk:2825 +#: gitk:2833 #, tcl-format msgid "<%s-Home>\tScroll to top of commit list" msgstr "<%s-Home>\tRulla till början av incheckningslistan" -#: gitk:2826 +#: gitk:2834 #, tcl-format msgid "<%s-End>\tScroll to bottom of commit list" msgstr "<%s-End>\tRulla till slutet av incheckningslistan" -#: gitk:2827 +#: gitk:2835 #, tcl-format msgid "<%s-Up>\tScroll commit list up one line" msgstr "<%s-Upp>\tRulla incheckningslistan upp ett steg" -#: gitk:2828 +#: gitk:2836 #, tcl-format msgid "<%s-Down>\tScroll commit list down one line" msgstr "<%s-Ned>\tRulla incheckningslistan ned ett steg" -#: gitk:2829 +#: gitk:2837 #, tcl-format msgid "<%s-PageUp>\tScroll commit list up one page" msgstr "<%s-PageUp>\tRulla incheckningslistan upp en sida" -#: gitk:2830 +#: gitk:2838 #, tcl-format msgid "<%s-PageDown>\tScroll commit list down one page" msgstr "<%s-PageDown>\tRulla incheckningslistan ned en sida" -#: gitk:2831 +#: gitk:2839 msgid "<Shift-Up>\tFind backwards (upwards, later commits)" msgstr "<Skift-Upp>\tSök bakåt (uppåt, senare incheckningar)" -#: gitk:2832 +#: gitk:2840 msgid "<Shift-Down>\tFind forwards (downwards, earlier commits)" msgstr "<Skift-Ned>\tSök framåt (nedåt, tidigare incheckningar)" -#: gitk:2833 +#: gitk:2841 msgid "<Delete>, b\tScroll diff view up one page" msgstr "<Delete>, b\tRulla diffvisningen upp en sida" -#: gitk:2834 +#: gitk:2842 msgid "<Backspace>\tScroll diff view up one page" msgstr "<Baksteg>\tRulla diffvisningen upp en sida" -#: gitk:2835 +#: gitk:2843 msgid "<Space>\t\tScroll diff view down one page" msgstr "<Blanksteg>\tRulla diffvisningen ned en sida" -#: gitk:2836 +#: gitk:2844 msgid "u\t\tScroll diff view up 18 lines" msgstr "u\t\tRulla diffvisningen upp 18 rader" -#: gitk:2837 +#: gitk:2845 msgid "d\t\tScroll diff view down 18 lines" msgstr "d\t\tRulla diffvisningen ned 18 rader" -#: gitk:2838 +#: gitk:2846 #, tcl-format msgid "<%s-F>\t\tFind" msgstr "<%s-F>\t\tSök" -#: gitk:2839 +#: gitk:2847 #, tcl-format msgid "<%s-G>\t\tMove to next find hit" msgstr "<%s-G>\t\tGå till nästa sökträff" -#: gitk:2840 +#: gitk:2848 msgid "<Return>\tMove to next find hit" msgstr "<Return>\t\tGå till nästa sökträff" -#: gitk:2841 +#: gitk:2849 msgid "/\t\tFocus the search box" msgstr "/\t\tFokusera sökrutan" -#: gitk:2842 +#: gitk:2850 msgid "?\t\tMove to previous find hit" msgstr "?\t\tGå till föregående sökträff" -#: gitk:2843 +#: gitk:2851 msgid "f\t\tScroll diff view to next file" msgstr "f\t\tRulla diffvisningen till nästa fil" -#: gitk:2844 +#: gitk:2852 #, tcl-format msgid "<%s-S>\t\tSearch for next hit in diff view" msgstr "<%s-S>\t\tGå till nästa sökträff i diffvisningen" -#: gitk:2845 +#: gitk:2853 #, tcl-format msgid "<%s-R>\t\tSearch for previous hit in diff view" msgstr "<%s-R>\t\tGå till föregående sökträff i diffvisningen" -#: gitk:2846 +#: gitk:2854 #, tcl-format msgid "<%s-KP+>\tIncrease font size" msgstr "<%s-Num+>\tÖka teckenstorlek" -#: gitk:2847 +#: gitk:2855 #, tcl-format msgid "<%s-plus>\tIncrease font size" msgstr "<%s-plus>\tÖka teckenstorlek" -#: gitk:2848 +#: gitk:2856 #, tcl-format msgid "<%s-KP->\tDecrease font size" msgstr "<%s-Num->\tMinska teckenstorlek" -#: gitk:2849 +#: gitk:2857 #, tcl-format msgid "<%s-minus>\tDecrease font size" msgstr "<%s-minus>\tMinska teckenstorlek" -#: gitk:2850 +#: gitk:2858 msgid "<F5>\t\tUpdate" msgstr "<F5>\t\tUppdatera" -#: gitk:3305 gitk:3314 +#: gitk:3313 gitk:3322 #, tcl-format msgid "Error creating temporary directory %s:" msgstr "Fel vid skapande av temporär katalog %s:" -#: gitk:3327 +#: gitk:3335 #, tcl-format msgid "Error getting \"%s\" from %s:" msgstr "Fel vid hämtning av \"%s\" från %s:" -#: gitk:3390 +#: gitk:3398 msgid "command failed:" msgstr "kommando misslyckades:" -#: gitk:3539 +#: gitk:3547 msgid "No such commit" msgstr "Incheckning saknas" -#: gitk:3553 +#: gitk:3561 msgid "git gui blame: command failed:" msgstr "git gui blame: kommando misslyckades:" -#: gitk:3584 +#: gitk:3592 #, tcl-format msgid "Couldn't read merge head: %s" msgstr "Kunde inte läsa sammanslagningshuvud: %s" -#: gitk:3592 +#: gitk:3600 #, tcl-format msgid "Error reading index: %s" msgstr "Fel vid läsning av index: %s" -#: gitk:3617 +#: gitk:3625 #, tcl-format msgid "Couldn't start git blame: %s" msgstr "Kunde inte starta git blame: %s" -#: gitk:3620 gitk:6409 +#: gitk:3628 gitk:6419 msgid "Searching" msgstr "Söker" -#: gitk:3652 +#: gitk:3660 #, tcl-format msgid "Error running git blame: %s" msgstr "Fel vid körning av git blame: %s" -#: gitk:3680 +#: gitk:3688 #, tcl-format msgid "That line comes from commit %s, which is not in this view" msgstr "Raden kommer från incheckningen %s, som inte finns i denna vy" -#: gitk:3694 +#: gitk:3702 msgid "External diff viewer failed:" msgstr "Externt diff-verktyg misslyckades:" -#: gitk:3812 +#: gitk:3820 msgid "Gitk view definition" msgstr "Definition av Gitk-vy" -#: gitk:3816 +#: gitk:3824 msgid "Remember this view" msgstr "Spara denna vy" -#: gitk:3817 +#: gitk:3825 msgid "References (space separated list):" msgstr "Referenser (blankstegsavdelad lista):" -#: gitk:3818 +#: gitk:3826 msgid "Branches & tags:" msgstr "Grenar & taggar:" -#: gitk:3819 +#: gitk:3827 msgid "All refs" msgstr "Alla referenser" -#: gitk:3820 +#: gitk:3828 msgid "All (local) branches" msgstr "Alla (lokala) grenar" -#: gitk:3821 +#: gitk:3829 msgid "All tags" msgstr "Alla taggar" -#: gitk:3822 +#: gitk:3830 msgid "All remote-tracking branches" msgstr "Alla fjärrspårande grenar" -#: gitk:3823 +#: gitk:3831 msgid "Commit Info (regular expressions):" msgstr "Incheckningsinfo (reguljära uttryck):" -#: gitk:3824 +#: gitk:3832 msgid "Author:" msgstr "Författare:" -#: gitk:3825 +#: gitk:3833 msgid "Committer:" msgstr "Incheckare:" -#: gitk:3826 +#: gitk:3834 msgid "Commit Message:" msgstr "Incheckningsmeddelande:" -#: gitk:3827 +#: gitk:3835 msgid "Matches all Commit Info criteria" msgstr "Motsvarar alla kriterier för incheckningsinfo" -#: gitk:3828 +#: gitk:3836 msgid "Changes to Files:" msgstr "Ändringar av filer:" -#: gitk:3829 +#: gitk:3837 msgid "Fixed String" msgstr "Fast sträng" -#: gitk:3830 +#: gitk:3838 msgid "Regular Expression" msgstr "Reguljärt uttryck" -#: gitk:3831 +#: gitk:3839 msgid "Search string:" msgstr "Söksträng:" -#: gitk:3832 +#: gitk:3840 msgid "" "Commit Dates (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 " "15:27:38\"):" @@ -643,201 +648,201 @@ msgstr "" "Incheckingsdatum (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 " "15:27:38\"):" -#: gitk:3833 +#: gitk:3841 msgid "Since:" msgstr "Från:" -#: gitk:3834 +#: gitk:3842 msgid "Until:" msgstr "Till:" -#: gitk:3835 +#: gitk:3843 msgid "Limit and/or skip a number of revisions (positive integer):" msgstr "Begränsa och/eller hoppa över ett antal revisioner (positivt heltal):" -#: gitk:3836 +#: gitk:3844 msgid "Number to show:" msgstr "Antal att visa:" -#: gitk:3837 +#: gitk:3845 msgid "Number to skip:" msgstr "Antal att hoppa över:" -#: gitk:3838 +#: gitk:3846 msgid "Miscellaneous options:" msgstr "Diverse alternativ:" -#: gitk:3839 +#: gitk:3847 msgid "Strictly sort by date" msgstr "Strikt datumsortering" -#: gitk:3840 +#: gitk:3848 msgid "Mark branch sides" msgstr "Markera sidogrenar" -#: gitk:3841 +#: gitk:3849 msgid "Limit to first parent" msgstr "Begränsa till första förälder" -#: gitk:3842 +#: gitk:3850 msgid "Simple history" msgstr "Enkel historik" -#: gitk:3843 +#: gitk:3851 msgid "Additional arguments to git log:" msgstr "Ytterligare argument till git log:" -#: gitk:3844 +#: gitk:3852 msgid "Enter files and directories to include, one per line:" msgstr "Ange filer och kataloger att ta med, en per rad:" -#: gitk:3845 +#: gitk:3853 msgid "Command to generate more commits to include:" msgstr "Kommando för att generera fler incheckningar att ta med:" -#: gitk:3967 +#: gitk:3977 msgid "Gitk: edit view" msgstr "Gitk: redigera vy" -#: gitk:3975 +#: gitk:3985 msgid "-- criteria for selecting revisions" msgstr " - kriterier för val av revisioner" -#: gitk:3980 +#: gitk:3990 msgid "View Name" msgstr "Namn på vy" -#: gitk:4055 +#: gitk:4065 msgid "Apply (F5)" msgstr "Använd (F5)" -#: gitk:4093 +#: gitk:4103 msgid "Error in commit selection arguments:" msgstr "Fel i argument för val av incheckningar:" -#: gitk:4146 gitk:4198 gitk:4646 gitk:4660 gitk:5921 gitk:11534 gitk:11535 +#: gitk:4156 gitk:4208 gitk:4656 gitk:4670 gitk:5931 gitk:11551 gitk:11552 msgid "None" msgstr "Inget" -#: gitk:4594 gitk:6441 gitk:8287 gitk:8302 +#: gitk:4604 gitk:6451 gitk:8309 gitk:8324 msgid "Date" msgstr "Datum" -#: gitk:4594 gitk:6441 +#: gitk:4604 gitk:6451 msgid "CDate" msgstr "Skapat datum" -#: gitk:4743 gitk:4748 +#: gitk:4753 gitk:4758 msgid "Descendant" msgstr "Avkomling" -#: gitk:4744 +#: gitk:4754 msgid "Not descendant" msgstr "Inte avkomling" -#: gitk:4751 gitk:4756 +#: gitk:4761 gitk:4766 msgid "Ancestor" msgstr "Förfader" -#: gitk:4752 +#: gitk:4762 msgid "Not ancestor" msgstr "Inte förfader" -#: gitk:5042 +#: gitk:5052 msgid "Local changes checked in to index but not committed" msgstr "Lokala ändringar sparade i indexet men inte incheckade" -#: gitk:5078 +#: gitk:5088 msgid "Local uncommitted changes, not checked in to index" msgstr "Lokala ändringar, ej sparade i indexet" -#: gitk:6759 +#: gitk:6769 msgid "many" msgstr "många" -#: gitk:6942 +#: gitk:6952 msgid "Tags:" msgstr "Taggar:" -#: gitk:6959 gitk:6965 gitk:8280 +#: gitk:6969 gitk:6975 gitk:8302 msgid "Parent" msgstr "Förälder" -#: gitk:6970 +#: gitk:6980 msgid "Child" msgstr "Barn" -#: gitk:6979 +#: gitk:6989 msgid "Branch" msgstr "Gren" -#: gitk:6982 +#: gitk:6992 msgid "Follows" msgstr "Följer" -#: gitk:6985 +#: gitk:6995 msgid "Precedes" msgstr "Föregår" -#: gitk:7522 +#: gitk:7532 #, tcl-format msgid "Error getting diffs: %s" msgstr "Fel vid hämtning av diff: %s" -#: gitk:8108 +#: gitk:8130 msgid "Goto:" msgstr "Gå till:" -#: gitk:8129 +#: gitk:8151 #, tcl-format msgid "Short SHA1 id %s is ambiguous" msgstr "Förkortat SHA1-id %s är tvetydigt" -#: gitk:8136 +#: gitk:8158 #, tcl-format msgid "Revision %s is not known" msgstr "Revisionen %s är inte känd" -#: gitk:8146 +#: gitk:8168 #, tcl-format msgid "SHA1 id %s is not known" msgstr "SHA-id:t %s är inte känt" -#: gitk:8148 +#: gitk:8170 #, tcl-format msgid "Revision %s is not in the current view" msgstr "Revisionen %s finns inte i den nuvarande vyn" -#: gitk:8290 +#: gitk:8312 msgid "Children" msgstr "Barn" -#: gitk:8348 +#: gitk:8370 #, tcl-format msgid "Reset %s branch to here" msgstr "Återställ grenen %s hit" -#: gitk:8350 +#: gitk:8372 msgid "Detached head: can't reset" msgstr "Frånkopplad head: kan inte återställa" -#: gitk:8459 gitk:8465 +#: gitk:8481 gitk:8487 msgid "Skipping merge commit " msgstr "Hoppar över sammanslagningsincheckning " -#: gitk:8474 gitk:8479 +#: gitk:8496 gitk:8501 msgid "Error getting patch ID for " msgstr "Fel vid hämtning av patch-id för " -#: gitk:8475 gitk:8480 +#: gitk:8497 gitk:8502 msgid " - stopping\n" msgstr " - stannar\n" -#: gitk:8485 gitk:8488 gitk:8496 gitk:8510 gitk:8519 +#: gitk:8507 gitk:8510 gitk:8518 gitk:8532 gitk:8541 msgid "Commit " msgstr "Incheckning " -#: gitk:8489 +#: gitk:8511 msgid "" " is the same patch as\n" " " @@ -845,7 +850,7 @@ msgstr "" " är samma patch som\n" " " -#: gitk:8497 +#: gitk:8519 msgid "" " differs from\n" " " @@ -853,139 +858,139 @@ msgstr "" " skiljer sig från\n" " " -#: gitk:8499 +#: gitk:8521 msgid "" "Diff of commits:\n" "\n" -msgstr "Skillnad mellan incheckningar:\n" +msgstr "" +"Skillnad mellan incheckningar:\n" "\n" -"" -#: gitk:8511 gitk:8520 +#: gitk:8533 gitk:8542 #, tcl-format msgid " has %s children - stopping\n" msgstr " har %s barn - stannar\n" -#: gitk:8539 +#: gitk:8561 #, tcl-format msgid "Error writing commit to file: %s" msgstr "Fel vid skrivning av incheckning till fil: %s" -#: gitk:8545 +#: gitk:8567 #, tcl-format msgid "Error diffing commits: %s" msgstr "Fel vid jämförelse av incheckningar: %s" -#: gitk:8575 +#: gitk:8598 msgid "Top" msgstr "Topp" -#: gitk:8576 +#: gitk:8599 msgid "From" msgstr "Från" -#: gitk:8581 +#: gitk:8604 msgid "To" msgstr "Till" -#: gitk:8605 +#: gitk:8628 msgid "Generate patch" msgstr "Generera patch" -#: gitk:8607 +#: gitk:8630 msgid "From:" msgstr "Från:" -#: gitk:8616 +#: gitk:8639 msgid "To:" msgstr "Till:" -#: gitk:8625 +#: gitk:8648 msgid "Reverse" msgstr "Vänd" -#: gitk:8627 gitk:8822 +#: gitk:8650 gitk:8845 msgid "Output file:" msgstr "Utdatafil:" -#: gitk:8633 +#: gitk:8656 msgid "Generate" msgstr "Generera" -#: gitk:8671 +#: gitk:8694 msgid "Error creating patch:" msgstr "Fel vid generering av patch:" -#: gitk:8694 gitk:8810 gitk:8867 +#: gitk:8717 gitk:8833 gitk:8890 msgid "ID:" msgstr "Id:" -#: gitk:8703 +#: gitk:8726 msgid "Tag name:" msgstr "Taggnamn:" -#: gitk:8706 +#: gitk:8729 msgid "Tag message is optional" msgstr "Taggmeddelandet är valfritt" -#: gitk:8708 +#: gitk:8731 msgid "Tag message:" msgstr "Taggmeddelande:" -#: gitk:8712 gitk:8876 +#: gitk:8735 gitk:8899 msgid "Create" msgstr "Skapa" -#: gitk:8730 +#: gitk:8753 msgid "No tag name specified" msgstr "Inget taggnamn angavs" -#: gitk:8734 +#: gitk:8757 #, tcl-format msgid "Tag \"%s\" already exists" msgstr "Taggen \"%s\" finns redan" -#: gitk:8744 +#: gitk:8767 msgid "Error creating tag:" msgstr "Fel vid skapande av tagg:" -#: gitk:8819 +#: gitk:8842 msgid "Command:" msgstr "Kommando:" -#: gitk:8827 +#: gitk:8850 msgid "Write" msgstr "Skriv" -#: gitk:8845 +#: gitk:8868 msgid "Error writing commit:" msgstr "Fel vid skrivning av incheckning:" -#: gitk:8872 +#: gitk:8895 msgid "Name:" msgstr "Namn:" -#: gitk:8895 +#: gitk:8918 msgid "Please specify a name for the new branch" msgstr "Ange ett namn för den nya grenen" -#: gitk:8900 +#: gitk:8923 #, tcl-format msgid "Branch '%s' already exists. Overwrite?" msgstr "Grenen \"%s\" finns redan. Skriva över?" -#: gitk:8966 +#: gitk:8989 #, tcl-format msgid "Commit %s is already included in branch %s -- really re-apply it?" msgstr "" "Incheckningen %s finns redan på grenen %s -- skall den verkligen appliceras " "på nytt?" -#: gitk:8971 +#: gitk:8994 msgid "Cherry-picking" msgstr "Plockar" -#: gitk:8980 +#: gitk:9003 #, tcl-format msgid "" "Cherry-pick failed because of local changes to file '%s'.\n" @@ -995,7 +1000,7 @@ msgstr "" "Checka in, återställ eller spara undan (stash) dina ändringar och försök " "igen." -#: gitk:8986 +#: gitk:9009 msgid "" "Cherry-pick failed because of merge conflict.\n" "Do you wish to run git citool to resolve it?" @@ -1003,32 +1008,32 @@ msgstr "" "Cherry-pick misslyckades på grund av en sammanslagningskonflikt.\n" "Vill du köra git citool för att lösa den?" -#: gitk:9002 +#: gitk:9025 msgid "No changes committed" msgstr "Inga ändringar incheckade" -#: gitk:9028 +#: gitk:9051 msgid "Confirm reset" msgstr "Bekräfta återställning" -#: gitk:9030 +#: gitk:9053 #, tcl-format msgid "Reset branch %s to %s?" msgstr "Återställa grenen %s till %s?" -#: gitk:9032 +#: gitk:9055 msgid "Reset type:" msgstr "Typ av återställning:" -#: gitk:9035 +#: gitk:9058 msgid "Soft: Leave working tree and index untouched" msgstr "Mjuk: Rör inte utcheckning och index" -#: gitk:9038 +#: gitk:9061 msgid "Mixed: Leave working tree untouched, reset index" msgstr "Blandad: Rör inte utcheckning, återställ index" -#: gitk:9041 +#: gitk:9064 msgid "" "Hard: Reset working tree and index\n" "(discard ALL local changes)" @@ -1036,19 +1041,19 @@ msgstr "" "Hård: Återställ utcheckning och index\n" "(förkastar ALLA lokala ändringar)" -#: gitk:9058 +#: gitk:9081 msgid "Resetting" msgstr "Återställer" -#: gitk:9118 +#: gitk:9141 msgid "Checking out" msgstr "Checkar ut" -#: gitk:9171 +#: gitk:9194 msgid "Cannot delete the currently checked-out branch" msgstr "Kan inte ta bort den just nu utcheckade grenen" -#: gitk:9177 +#: gitk:9200 #, tcl-format msgid "" "The commits on branch %s aren't on any other branch.\n" @@ -1057,16 +1062,16 @@ msgstr "" "Incheckningarna på grenen %s existerar inte på någon annan gren.\n" "Vill du verkligen ta bort grenen %s?" -#: gitk:9208 +#: gitk:9231 #, tcl-format msgid "Tags and heads: %s" msgstr "Taggar och huvuden: %s" -#: gitk:9223 +#: gitk:9246 msgid "Filter" msgstr "Filter" -#: gitk:9518 +#: gitk:9541 msgid "" "Error reading commit topology information; branch and preceding/following " "tag information will be incomplete." @@ -1074,203 +1079,203 @@ msgstr "" "Fel vid läsning av information om incheckningstopologi; information om " "grenar och föregående/senare taggar kommer inte vara komplett." -#: gitk:10504 +#: gitk:10527 msgid "Tag" msgstr "Tagg" -#: gitk:10504 +#: gitk:10527 msgid "Id" msgstr "Id" -#: gitk:10554 +#: gitk:10576 msgid "Gitk font chooser" msgstr "Teckensnittsväljare för Gitk" -#: gitk:10571 +#: gitk:10593 msgid "B" msgstr "F" -#: gitk:10574 +#: gitk:10596 msgid "I" msgstr "K" -#: gitk:10692 +#: gitk:10714 msgid "Gitk preferences" msgstr "Inställningar för Gitk" -#: gitk:10694 +#: gitk:10716 msgid "Commit list display options" msgstr "Alternativ för incheckningslistvy" -#: gitk:10697 +#: gitk:10719 msgid "Maximum graph width (lines)" msgstr "Maximal grafbredd (rader)" -#: gitk:10700 +#: gitk:10722 #, tcl-format msgid "Maximum graph width (% of pane)" msgstr "Maximal grafbredd (% av ruta)" -#: gitk:10703 +#: gitk:10725 msgid "Show local changes" msgstr "Visa lokala ändringar" -#: gitk:10706 +#: gitk:10728 msgid "Auto-select SHA1" msgstr "Välj SHA1 automatiskt" -#: gitk:10709 +#: gitk:10731 msgid "Hide remote refs" msgstr "Dölj fjärr-referenser" -#: gitk:10713 +#: gitk:10735 msgid "Diff display options" msgstr "Alternativ för diffvy" -#: gitk:10715 +#: gitk:10737 msgid "Tab spacing" msgstr "Blanksteg för tabulatortecken" -#: gitk:10718 +#: gitk:10740 msgid "Display nearby tags" msgstr "Visa närliggande taggar" -#: gitk:10721 +#: gitk:10743 msgid "Limit diffs to listed paths" msgstr "Begränsa diff till listade sökvägar" -#: gitk:10724 +#: gitk:10746 msgid "Support per-file encodings" msgstr "Stöd för filspecifika teckenkodningar" -#: gitk:10730 gitk:10819 +#: gitk:10752 gitk:10832 msgid "External diff tool" msgstr "Externt diff-verktyg" -#: gitk:10731 +#: gitk:10753 msgid "Choose..." msgstr "Välj..." -#: gitk:10736 +#: gitk:10758 msgid "General options" msgstr "Allmänna inställningar" -#: gitk:10739 +#: gitk:10761 msgid "Use themed widgets" msgstr "Använd tema på fönsterelement" -#: gitk:10741 +#: gitk:10763 msgid "(change requires restart)" msgstr "(ändringen kräver omstart)" -#: gitk:10743 +#: gitk:10765 msgid "(currently unavailable)" msgstr "(för närvarande inte tillgängligt)" -#: gitk:10747 +#: gitk:10769 msgid "Colors: press to choose" msgstr "Färger: tryck för att välja" -#: gitk:10750 +#: gitk:10772 msgid "Interface" msgstr "Gränssnitt" -#: gitk:10751 +#: gitk:10773 msgid "interface" msgstr "gränssnitt" -#: gitk:10754 +#: gitk:10776 msgid "Background" msgstr "Bakgrund" -#: gitk:10755 gitk:10785 +#: gitk:10777 gitk:10807 msgid "background" msgstr "bakgrund" -#: gitk:10758 +#: gitk:10780 msgid "Foreground" msgstr "Förgrund" -#: gitk:10759 +#: gitk:10781 msgid "foreground" msgstr "förgrund" -#: gitk:10762 +#: gitk:10784 msgid "Diff: old lines" msgstr "Diff: gamla rader" -#: gitk:10763 +#: gitk:10785 msgid "diff old lines" msgstr "diff gamla rader" -#: gitk:10767 +#: gitk:10789 msgid "Diff: new lines" msgstr "Diff: nya rader" -#: gitk:10768 +#: gitk:10790 msgid "diff new lines" msgstr "diff nya rader" -#: gitk:10772 +#: gitk:10794 msgid "Diff: hunk header" msgstr "Diff: delhuvud" -#: gitk:10774 +#: gitk:10796 msgid "diff hunk header" msgstr "diff delhuvud" -#: gitk:10778 +#: gitk:10800 msgid "Marked line bg" msgstr "Markerad rad bakgrund" -#: gitk:10780 +#: gitk:10802 msgid "marked line background" msgstr "markerad rad bakgrund" -#: gitk:10784 +#: gitk:10806 msgid "Select bg" msgstr "Markerad bakgrund" -#: gitk:10788 +#: gitk:10810 msgid "Fonts: press to choose" msgstr "Teckensnitt: tryck för att välja" -#: gitk:10790 +#: gitk:10812 msgid "Main font" msgstr "Huvudteckensnitt" -#: gitk:10791 +#: gitk:10813 msgid "Diff display font" msgstr "Teckensnitt för diffvisning" -#: gitk:10792 +#: gitk:10814 msgid "User interface font" msgstr "Teckensnitt för användargränssnitt" -#: gitk:10829 +#: gitk:10842 #, tcl-format msgid "Gitk: choose color for %s" msgstr "Gitk: välj färg för %s" -#: gitk:11433 +#: gitk:11445 msgid "Cannot find a git repository here." -msgstr "Hittar inget gitk-arkiv här." +msgstr "Hittar inget git-arkiv här." -#: gitk:11437 +#: gitk:11449 #, tcl-format msgid "Cannot find the git directory \"%s\"." msgstr "Hittar inte git-katalogen \"%s\"." -#: gitk:11484 +#: gitk:11496 #, tcl-format msgid "Ambiguous argument '%s': both revision and filename" msgstr "Tvetydigt argument \"%s\": både revision och filnamn" -#: gitk:11496 +#: gitk:11508 msgid "Bad arguments to gitk:" msgstr "Felaktiga argument till gitk:" -#: gitk:11587 +#: gitk:11604 msgid "Command line" msgstr "Kommandorad" diff --git a/gitweb/README b/gitweb/README index bf3664f2b7..4a673933ac 100644 --- a/gitweb/README +++ b/gitweb/README @@ -177,13 +177,15 @@ not include variables usually directly set during build): * $my_url, $my_uri Full URL and absolute URL of gitweb script; in earlier versions of gitweb you might have need to set those - variables, now there should be no need to do it. + variables, now there should be no need to do it. See + $per_request_config if you need to set them still. * $base_url Base URL for relative URLs in pages generated by gitweb, (e.g. $logo, $favicon, @stylesheets if they are relative URLs), needed and used only for URLs with nonempty PATH_INFO via <base href="$base_url">. Usually gitweb sets its value correctly, and there is no need to set this variable, e.g. to $my_uri or "/". + See $per_request_config if you need to set it anyway. * $home_link Target of the home link on top of all pages (the first part of view "breadcrumbs"). By default set to absolute URI of a page ($my_uri). @@ -246,6 +248,16 @@ not include variables usually directly set during build): http://www.andre-simon.de due to assumptions about parameters and output). Useful if highlight is not installed on your webserver's PATH. [Default: highlight] + * $per_request_config + If set to code reference, it would be run once per each request. You can + set parts of configuration that change per session, e.g. by setting it to + sub { $ENV{GL_USER} = $cgi->remote_user || "gitweb"; } + Otherwise it is treated as boolean value: if true gitweb would process + config file once per request, if false it would process config file only + once. Note: $my_url, $my_uri, and $base_url are overwritten with + their default values before every request, so if you want to change + them, be sure to set this variable to true or a code reference effecting + the desired changes. The default is true. Projects list file format ~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 75306ca967..47796180d2 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -611,6 +611,14 @@ sub filter_snapshot_fmts { !$known_snapshot_formats{$_}{'disabled'}} @fmts; } +# If it is set to code reference, it is code that it is to be run once per +# request, allowing updating configurations that change with each request, +# while running other code in config file only once. +# +# Otherwise, if it is false then gitweb would process config file only once; +# if it is true then gitweb config would be run for each request. +our $per_request_config = 1; + our ($GITWEB_CONFIG, $GITWEB_CONFIG_SYSTEM); sub evaluate_gitweb_config { our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++"; @@ -1081,12 +1089,22 @@ sub reset_timer { our $number_of_git_cmds = 0; } +our $first_request = 1; sub run_request { reset_timer(); evaluate_uri(); - evaluate_gitweb_config(); - evaluate_git_version(); + if ($first_request) { + evaluate_gitweb_config(); + evaluate_git_version(); + } + if ($per_request_config) { + if (ref($per_request_config) eq 'CODE') { + $per_request_config->(); + } elsif (!$first_request) { + evaluate_gitweb_config(); + } + } check_loadavg(); # $projectroot and $projects_list might be set in gitweb config file @@ -1140,6 +1158,7 @@ sub evaluate_argv { sub run { evaluate_argv(); + $first_request = 1; $pre_listen_hook->() if $pre_listen_hook; @@ -1152,6 +1171,7 @@ sub run { $post_dispatch_hook->() if $post_dispatch_hook; + $first_request = 0; last REQUEST if ($is_last_request->()); } @@ -1210,7 +1230,7 @@ sub href { $href =~ s,/$,,; # Then add the project name, if present - $href .= "/".esc_url($params{'project'}); + $href .= "/".esc_path_info($params{'project'}); delete $params{'project'}; # since we destructively absorb parameters, we keep this @@ -1220,7 +1240,8 @@ sub href { # Summary just uses the project path URL, any other action is # added to the URL if (defined $params{'action'}) { - $href .= "/".esc_url($params{'action'}) unless $params{'action'} eq 'summary'; + $href .= "/".esc_path_info($params{'action'}) + unless $params{'action'} eq 'summary'; delete $params{'action'}; } @@ -1230,13 +1251,13 @@ sub href { || $params{'hash_parent'} || $params{'hash'}); if (defined $params{'hash_base'}) { if (defined $params{'hash_parent_base'}) { - $href .= esc_url($params{'hash_parent_base'}); + $href .= esc_path_info($params{'hash_parent_base'}); # skip the file_parent if it's the same as the file_name if (defined $params{'file_parent'}) { if (defined $params{'file_name'} && $params{'file_parent'} eq $params{'file_name'}) { delete $params{'file_parent'}; } elsif ($params{'file_parent'} !~ /\.\./) { - $href .= ":/".esc_url($params{'file_parent'}); + $href .= ":/".esc_path_info($params{'file_parent'}); delete $params{'file_parent'}; } } @@ -1244,19 +1265,19 @@ sub href { delete $params{'hash_parent'}; delete $params{'hash_parent_base'}; } elsif (defined $params{'hash_parent'}) { - $href .= esc_url($params{'hash_parent'}). ".."; + $href .= esc_path_info($params{'hash_parent'}). ".."; delete $params{'hash_parent'}; } - $href .= esc_url($params{'hash_base'}); + $href .= esc_path_info($params{'hash_base'}); if (defined $params{'file_name'} && $params{'file_name'} !~ /\.\./) { - $href .= ":/".esc_url($params{'file_name'}); + $href .= ":/".esc_path_info($params{'file_name'}); delete $params{'file_name'}; } delete $params{'hash'}; delete $params{'hash_base'}; } elsif (defined $params{'hash'}) { - $href .= esc_url($params{'hash'}); + $href .= esc_path_info($params{'hash'}); delete $params{'hash'}; } @@ -1289,6 +1310,9 @@ sub href { } $href .= "?" . join(';', @result) if scalar @result; + # final transformation: trailing spaces must be escaped (URI-encoded) + $href =~ s/(\s+)$/CGI::escape($1)/e; + return $href; } @@ -1371,6 +1395,17 @@ sub esc_param { return $str; } +# the quoting rules for path_info fragment are slightly different +sub esc_path_info { + my $str = shift; + return undef unless defined $str; + + # path_info doesn't treat '+' as space (specially), but '?' must be escaped + $str =~ s/([^A-Za-z0-9\-_.~();\/;:@&= +]+)/CGI::escape($1)/eg; + + return $str; +} + # quote unsafe chars in whole URL, so some characters cannot be quoted sub esc_url { my $str = shift; @@ -1380,6 +1415,13 @@ sub esc_url { return $str; } +# quote unsafe characters in HTML attributes +sub esc_attr { + + # for XHTML conformance escaping '"' to '"' is not enough + return esc_html(@_); +} + # replace invalid utf8 character with SUBSTITUTION sequence sub esc_html { my $str = shift; @@ -1785,7 +1827,7 @@ sub format_ref_marker { hash=>$dest )}, $name); - $markers .= " <span class=\"$class\" title=\"$ref\">" . + $markers .= " <span class=\"".esc_attr($class)."\" title=\"".esc_attr($ref)."\">" . $link . "</span>"; } } @@ -1869,7 +1911,7 @@ sub git_get_avatar { return $pre_white . "<img width=\"$size\" " . "class=\"avatar\" " . - "src=\"$url\" " . + "src=\"".esc_url($url)."\" " . "alt=\"\" " . "/>" . $post_white; } else { @@ -2580,7 +2622,7 @@ sub git_show_project_tagcloud { } else { my @tags = sort { $cloud->{$a}->{count} <=> $cloud->{$b}->{count} } keys %$cloud; return '<p align="center">' . join (', ', map { - "<a href=\"$home_link?by_tag=$_\">$cloud->{$_}->{topname}</a>" + $cgi->a({-href=>"$home_link?by_tag=$_"}, $cloud->{$_}->{topname}) } splice(@tags, 0, $count)) . '</p>'; } } @@ -3452,6 +3494,51 @@ sub get_page_title { return $title; } +sub print_feed_meta { + if (defined $project) { + my %href_params = get_feed_info(); + if (!exists $href_params{'-title'}) { + $href_params{'-title'} = 'log'; + } + + foreach my $format qw(RSS Atom) { + my $type = lc($format); + my %link_attr = ( + '-rel' => 'alternate', + '-title' => esc_attr("$project - $href_params{'-title'} - $format feed"), + '-type' => "application/$type+xml" + ); + + $href_params{'action'} = $type; + $link_attr{'-href'} = href(%href_params); + print "<link ". + "rel=\"$link_attr{'-rel'}\" ". + "title=\"$link_attr{'-title'}\" ". + "href=\"$link_attr{'-href'}\" ". + "type=\"$link_attr{'-type'}\" ". + "/>\n"; + + $href_params{'extra_options'} = '--no-merges'; + $link_attr{'-href'} = href(%href_params); + $link_attr{'-title'} .= ' (no merges)'; + print "<link ". + "rel=\"$link_attr{'-rel'}\" ". + "title=\"$link_attr{'-title'}\" ". + "href=\"$link_attr{'-href'}\" ". + "type=\"$link_attr{'-type'}\" ". + "/>\n"; + } + + } else { + printf('<link rel="alternate" title="%s projects list" '. + 'href="%s" type="text/plain; charset=utf-8" />'."\n", + esc_attr($site_name), href(project=>undef, action=>"project_index")); + printf('<link rel="alternate" title="%s projects feeds" '. + 'href="%s" type="text/x-opml" />'."\n", + esc_attr($site_name), href(project=>undef, action=>"opml")); + } +} + sub git_header_html { my $status = shift || "200 OK"; my $expires = shift; @@ -3494,57 +3581,17 @@ EOF # print out each stylesheet that exist, providing backwards capability # for those people who defined $stylesheet in a config file if (defined $stylesheet) { - print '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'"/>'."\n"; + print '<link rel="stylesheet" type="text/css" href="'.esc_url($stylesheet).'"/>'."\n"; } else { foreach my $stylesheet (@stylesheets) { next unless $stylesheet; - print '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'"/>'."\n"; - } - } - if (defined $project) { - my %href_params = get_feed_info(); - if (!exists $href_params{'-title'}) { - $href_params{'-title'} = 'log'; - } - - foreach my $format qw(RSS Atom) { - my $type = lc($format); - my %link_attr = ( - '-rel' => 'alternate', - '-title' => "$project - $href_params{'-title'} - $format feed", - '-type' => "application/$type+xml" - ); - - $href_params{'action'} = $type; - $link_attr{'-href'} = href(%href_params); - print "<link ". - "rel=\"$link_attr{'-rel'}\" ". - "title=\"$link_attr{'-title'}\" ". - "href=\"$link_attr{'-href'}\" ". - "type=\"$link_attr{'-type'}\" ". - "/>\n"; - - $href_params{'extra_options'} = '--no-merges'; - $link_attr{'-href'} = href(%href_params); - $link_attr{'-title'} .= ' (no merges)'; - print "<link ". - "rel=\"$link_attr{'-rel'}\" ". - "title=\"$link_attr{'-title'}\" ". - "href=\"$link_attr{'-href'}\" ". - "type=\"$link_attr{'-type'}\" ". - "/>\n"; + print '<link rel="stylesheet" type="text/css" href="'.esc_url($stylesheet).'"/>'."\n"; } - - } else { - printf('<link rel="alternate" title="%s projects list" '. - 'href="%s" type="text/plain; charset=utf-8" />'."\n", - $site_name, href(project=>undef, action=>"project_index")); - printf('<link rel="alternate" title="%s projects feeds" '. - 'href="%s" type="text/x-opml" />'."\n", - $site_name, href(project=>undef, action=>"opml")); } + print_feed_meta() + if ($status eq '200 OK'); if (defined $favicon) { - print qq(<link rel="shortcut icon" href="$favicon" type="image/png" />\n); + print qq(<link rel="shortcut icon" href=").esc_url($favicon).qq(" type="image/png" />\n); } print "</head>\n" . @@ -3557,7 +3604,7 @@ EOF print "<div class=\"page_header\">\n" . $cgi->a({-href => esc_url($logo_url), -title => $logo_label}, - qq(<img src="$logo" width="72" height="27" alt="git" class="logo"/>)); + qq(<img src=").esc_url($logo).qq(" width="72" height="27" alt="git" class="logo"/>)); print $cgi->a({-href => esc_url($home_link)}, $home_link_str) . " / "; if (defined $project) { print $cgi->a({-href => href(action=>"summary")}, esc_html($project)); @@ -3663,7 +3710,7 @@ sub git_footer_html { insert_file($site_footer); } - print qq!<script type="text/javascript" src="$javascript"></script>\n!; + print qq!<script type="text/javascript" src="!.esc_url($javascript).qq!"></script>\n!; if (defined $action && $action eq 'blame_incremental') { print qq!<script type="text/javascript">\n!. @@ -5874,14 +5921,14 @@ sub git_blob { } else { print "<div class=\"page_nav\">\n" . "<br/><br/></div>\n" . - "<div class=\"title\">$hash</div>\n"; + "<div class=\"title\">".esc_html($hash)."</div>\n"; } git_print_page_path($file_name, "blob", $hash_base); print "<div class=\"page_body\">\n"; if ($mimetype =~ m!^image/!) { - print qq!<img type="$mimetype"!; + print qq!<img type="!.esc_attr($mimetype).qq!"!; if ($file_name) { - print qq! alt="$file_name" title="$file_name"!; + print qq! alt="!.esc_attr($file_name).qq!" title="!.esc_attr($file_name).qq!"!; } print qq! src="! . href(action=>"blob_plain", hash=>$hash, @@ -5894,7 +5941,7 @@ sub git_blob { $nr++; $line = untabify($line); printf qq!<div class="pre"><a id="l%i" href="%s#l%i" class="linenr">%4i</a> %s</div>\n!, - $nr, href(-replay => 1), $nr, $nr, $syntax ? $line : esc_html($line, -nbsp=>1); + $nr, esc_attr(href(-replay => 1)), $nr, $nr, $syntax ? $line : esc_html($line, -nbsp=>1); } } close $fd @@ -5956,7 +6003,7 @@ sub git_tree { undef $hash_base; print "<div class=\"page_nav\">\n"; print "<br/><br/></div>\n"; - print "<div class=\"title\">$hash</div>\n"; + print "<div class=\"title\">".esc_html($hash)."</div>\n"; } if (defined $file_name) { $basedir = $file_name; @@ -6424,7 +6471,7 @@ sub git_blobdiff { git_print_header_div('commit', esc_html($co{'title'}), $hash_base); } else { print "<div class=\"page_nav\"><br/>$formats_nav<br/></div>\n"; - print "<div class=\"title\">$hash vs $hash_parent</div>\n"; + print "<div class=\"title\">".esc_html("$hash vs $hash_parent")."</div>\n"; } if (defined $file_name) { git_print_page_path($file_name, "blob", $hash_base); @@ -3,6 +3,7 @@ #include "exec_cmd.h" #include "levenshtein.h" #include "help.h" +#include "common-cmds.h" /* most GUI terminals set COLUMNS (although some don't export it) */ static int term_columns(void) @@ -298,7 +299,8 @@ static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old) } /* An empirically derived magic number */ -#define SIMILAR_ENOUGH(x) ((x) < 6) +#define SIMILARITY_FLOOR 7 +#define SIMILAR_ENOUGH(x) ((x) < SIMILARITY_FLOOR) const char *help_unknown_cmd(const char *cmd) { @@ -319,10 +321,28 @@ const char *help_unknown_cmd(const char *cmd) sizeof(main_cmds.names), cmdname_compare); uniq(&main_cmds); - /* This reuses cmdname->len for similarity index */ - for (i = 0; i < main_cmds.cnt; ++i) + /* This abuses cmdname->len for levenshtein distance */ + for (i = 0, n = 0; i < main_cmds.cnt; i++) { + int cmp = 0; /* avoid compiler stupidity */ + const char *candidate = main_cmds.names[i]->name; + + /* Does the candidate appear in common_cmds list? */ + while (n < ARRAY_SIZE(common_cmds) && + (cmp = strcmp(common_cmds[n].name, candidate)) < 0) + n++; + if ((n < ARRAY_SIZE(common_cmds)) && !cmp) { + /* Yes, this is one of the common commands */ + n++; /* use the entry from common_cmds[] */ + if (!prefixcmp(candidate, cmd)) { + /* Give prefix match a very good score */ + main_cmds.names[i]->len = 0; + continue; + } + } + main_cmds.names[i]->len = - levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4); + levenshtein(cmd, candidate, 0, 2, 1, 4) + 1; + } qsort(main_cmds.names, main_cmds.cnt, sizeof(*main_cmds.names), levenshtein_compare); @@ -330,10 +350,21 @@ const char *help_unknown_cmd(const char *cmd) if (!main_cmds.cnt) die ("Uh oh. Your system reports no Git commands at all."); - best_similarity = main_cmds.names[0]->len; - n = 1; - while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len) - ++n; + /* skip and count prefix matches */ + for (n = 0; n < main_cmds.cnt && !main_cmds.names[n]->len; n++) + ; /* still counting */ + + if (main_cmds.cnt <= n) { + /* prefix matches with everything? that is too ambiguous */ + best_similarity = SIMILARITY_FLOOR + 1; + } else { + /* count all the most similar ones */ + for (best_similarity = main_cmds.names[n++]->len; + (n < main_cmds.cnt && + best_similarity == main_cmds.names[n]->len); + n++) + ; /* still counting */ + } if (autocorrect && n == 1 && SIMILAR_ENOUGH(best_similarity)) { const char *assumed = main_cmds.names[0]->name; main_cmds.names[0] = NULL; diff --git a/http-backend.c b/http-backend.c index 14c90c2e84..85015048dd 100644 --- a/http-backend.c +++ b/http-backend.c @@ -510,9 +510,7 @@ static char* getdir(void) die("GIT_PROJECT_ROOT is set but PATH_INFO is not"); if (daemon_avoid_alias(pathinfo)) die("'%s': aliased", pathinfo); - strbuf_addstr(&buf, root); - if (buf.buf[buf.len - 1] != '/') - strbuf_addch(&buf, '/'); + end_url_with_slash(&buf, root); if (pathinfo[0] == '/') pathinfo++; strbuf_addstr(&buf, pathinfo); diff --git a/http-fetch.c b/http-fetch.c index 762c750d7a..923904f97f 100644 --- a/http-fetch.c +++ b/http-fetch.c @@ -14,8 +14,7 @@ int main(int argc, const char **argv) int commits; const char **write_ref = NULL; char **commit_id; - const char *url; - char *rewritten_url = NULL; + char *url = NULL; int arg = 1; int rc = 0; int get_tree = 0; @@ -57,19 +56,14 @@ int main(int argc, const char **argv) commit_id = (char **) &argv[arg++]; commits = 1; } - url = argv[arg]; + + if (argv[arg]) + str_end_url_with_slash(argv[arg], &url); prefix = setup_git_directory(); git_config(git_default_config, NULL); - if (url && url[strlen(url)-1] != '/') { - rewritten_url = xmalloc(strlen(url)+2); - strcpy(rewritten_url, url); - strcat(rewritten_url, "/"); - url = rewritten_url; - } - http_init(NULL); walker = get_http_walker(url); walker->get_tree = get_tree; @@ -93,7 +87,7 @@ int main(int argc, const char **argv) walker_free(walker); http_cleanup(); - free(rewritten_url); + free(url); return rc; } diff --git a/http-push.c b/http-push.c index c9bcd11697..ff41a0e183 100644 --- a/http-push.c +++ b/http-push.c @@ -1090,6 +1090,10 @@ static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed) if (tag_closed) { if (!strcmp(ctx->name, DAV_PROPFIND_RESP) && ls->dentry_name) { if (ls->dentry_flags & IS_DIR) { + + /* ensure collection names end with slash */ + str_end_url_with_slash(ls->dentry_name, &ls->dentry_name); + if (ls->flags & PROCESS_DIRS) { ls->userFunc(ls); } @@ -1112,8 +1116,16 @@ static void handle_remote_ls_ctx(struct xml_ctx *ctx, int tag_closed) } } if (path) { - path += repo->path_len; - ls->dentry_name = xstrdup(path); + const char *url = repo->url; + if (repo->path) + url = repo->path; + if (strncmp(path, url, repo->path_len)) + error("Parsed path '%s' does not match url: '%s'\n", + path, url); + else { + path += repo->path_len; + ls->dentry_name = xstrdup(path); + } } } else if (!strcmp(ctx->name, DAV_PROPFIND_COLLECTION)) { ls->dentry_flags |= IS_DIR; @@ -1789,7 +1801,6 @@ int main(int argc, char **argv) int new_refs; struct ref *ref, *local_refs; struct remote *remote; - char *rewritten_url = NULL; git_extract_argv0_path(argv[0]); @@ -1835,8 +1846,8 @@ int main(int argc, char **argv) } if (!repo->url) { char *path = strstr(arg, "//"); - repo->url = arg; - repo->path_len = strlen(arg); + str_end_url_with_slash(arg, &repo->url); + repo->path_len = strlen(repo->url); if (path) { repo->path = strchr(path+2, '/'); if (repo->path) @@ -1872,15 +1883,6 @@ int main(int argc, char **argv) remote->url[remote->url_nr++] = repo->url; http_init(remote); - if (repo->url && repo->url[strlen(repo->url)-1] != '/') { - rewritten_url = xmalloc(strlen(repo->url)+2); - strcpy(rewritten_url, repo->url); - strcat(rewritten_url, "/"); - repo->path = rewritten_url + (repo->path - repo->url); - repo->path_len++; - repo->url = rewritten_url; - } - #ifdef USE_CURL_MULTI is_running_queue = 0; #endif @@ -2088,7 +2090,6 @@ int main(int argc, char **argv) } cleanup: - free(rewritten_url); if (info_ref_lock) unlock_remote(info_ref_lock); free(repo); @@ -743,13 +743,6 @@ static inline int hex(int v) return 'A' + v - 10; } -void end_url_with_slash(struct strbuf *buf, const char *url) -{ - strbuf_addstr(buf, url); - if (buf->len && buf->buf[buf->len - 1] != '/') - strbuf_addstr(buf, "/"); -} - static char *quote_ref_url(const char *base, const char *ref) { struct strbuf buf = STRBUF_INIT; @@ -8,6 +8,7 @@ #include "strbuf.h" #include "remote.h" +#include "url.h" /* * We detect based on the cURL version if multi-transfer is @@ -117,7 +118,6 @@ extern void append_remote_object_url(struct strbuf *buf, const char *url, int only_two_digit_prefix); extern char *get_remote_object_url(const char *url, const char *hex, int only_two_digit_prefix); -extern void end_url_with_slash(struct strbuf *buf, const char *url); /* Options for http_request_*() */ #define HTTP_NO_CACHE 1 diff --git a/parse-options.c b/parse-options.c index 0fa79bc31d..42b51ef145 100644 --- a/parse-options.c +++ b/parse-options.c @@ -11,6 +11,13 @@ static int parse_options_usage(struct parse_opt_ctx_t *ctx, #define OPT_SHORT 1 #define OPT_UNSET 2 +static int optbug(const struct option *opt, const char *reason) +{ + if (opt->long_name) + return error("BUG: option '%s' %s", opt->long_name, reason); + return error("BUG: switch '%c' %s", opt->short_name, reason); +} + static int opterror(const struct option *opt, const char *reason, int flags) { if (flags & OPT_SHORT) @@ -55,25 +62,13 @@ static int get_value(struct parse_opt_ctx_t *p, return opterror(opt, "takes no value", flags); if (unset && (opt->flags & PARSE_OPT_NONEG)) return opterror(opt, "isn't available", flags); - - if (!(flags & OPT_SHORT) && p->opt) { - switch (opt->type) { - case OPTION_CALLBACK: - if (!(opt->flags & PARSE_OPT_NOARG)) - break; - /* FALLTHROUGH */ - case OPTION_BOOLEAN: - case OPTION_BIT: - case OPTION_NEGBIT: - case OPTION_SET_INT: - case OPTION_SET_PTR: - return opterror(opt, "takes no value", flags); - default: - break; - } - } + if (!(flags & OPT_SHORT) && p->opt && (opt->flags & PARSE_OPT_NOARG)) + return opterror(opt, "takes no value", flags); switch (opt->type) { + case OPTION_LOWLEVEL_CALLBACK: + return (*(parse_opt_ll_cb *)opt->callback)(p, opt, unset); + case OPTION_BIT: if (unset) *(int *)opt->value &= ~opt->defval; @@ -281,13 +276,6 @@ static int parse_nodash_opt(struct parse_opt_ctx_t *p, const char *arg, for (; options->type != OPTION_END; options++) { if (!(options->flags & PARSE_OPT_NODASH)) continue; - if ((options->flags & PARSE_OPT_OPTARG) || - !(options->flags & PARSE_OPT_NOARG)) - die("BUG: dashless options don't support arguments"); - if (!(options->flags & PARSE_OPT_NONEG)) - die("BUG: dashless options don't support negation"); - if (options->long_name) - die("BUG: dashless options can't be long"); if (options->short_name == arg[0] && arg[1] == '\0') return get_value(p, options, OPT_SHORT); } @@ -320,25 +308,37 @@ static void parse_options_check(const struct option *opts) for (; opts->type != OPTION_END; opts++) { if ((opts->flags & PARSE_OPT_LASTARG_DEFAULT) && - (opts->flags & PARSE_OPT_OPTARG)) { - if (opts->long_name) { - error("`--%s` uses incompatible flags " - "LASTARG_DEFAULT and OPTARG", opts->long_name); - } else { - error("`-%c` uses incompatible flags " - "LASTARG_DEFAULT and OPTARG", opts->short_name); - } - err |= 1; + (opts->flags & PARSE_OPT_OPTARG)) + err |= optbug(opts, "uses incompatible flags " + "LASTARG_DEFAULT and OPTARG"); + if (opts->flags & PARSE_OPT_NODASH && + ((opts->flags & PARSE_OPT_OPTARG) || + !(opts->flags & PARSE_OPT_NOARG) || + !(opts->flags & PARSE_OPT_NONEG) || + opts->long_name)) + err |= optbug(opts, "uses feature " + "not supported for dashless options"); + switch (opts->type) { + case OPTION_BOOLEAN: + case OPTION_BIT: + case OPTION_NEGBIT: + case OPTION_SET_INT: + case OPTION_SET_PTR: + case OPTION_NUMBER: + if ((opts->flags & PARSE_OPT_OPTARG) || + !(opts->flags & PARSE_OPT_NOARG)) + err |= optbug(opts, "should not accept an argument"); + default: + ; /* ok. (usually accepts an argument) */ } } - if (err) - exit(129); + exit(128); } void parse_options_start(struct parse_opt_ctx_t *ctx, int argc, const char **argv, const char *prefix, - int flags) + const struct option *options, int flags) { memset(ctx, 0, sizeof(*ctx)); ctx->argc = argc - 1; @@ -350,6 +350,7 @@ void parse_options_start(struct parse_opt_ctx_t *ctx, if ((flags & PARSE_OPT_KEEP_UNKNOWN) && (flags & PARSE_OPT_STOP_AT_NON_OPTION)) die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together"); + parse_options_check(options); } static int usage_with_options_internal(struct parse_opt_ctx_t *, @@ -362,8 +363,6 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, { int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP); - parse_options_check(options); - /* we must reset ->opt, unknown short option leave it dangling */ ctx->opt = NULL; @@ -374,7 +373,7 @@ int parse_options_step(struct parse_opt_ctx_t *ctx, if (parse_nodash_opt(ctx, arg, options) == 0) continue; if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION) - break; + return PARSE_OPT_NON_OPTION; ctx->out[ctx->cpidx++] = ctx->argv[0]; continue; } @@ -452,10 +451,11 @@ int parse_options(int argc, const char **argv, const char *prefix, { struct parse_opt_ctx_t ctx; - parse_options_start(&ctx, argc, argv, prefix, flags); + parse_options_start(&ctx, argc, argv, prefix, options, flags); switch (parse_options_step(&ctx, options, usagestr)) { case PARSE_OPT_HELP: exit(129); + case PARSE_OPT_NON_OPTION: case PARSE_OPT_DONE: break; default: /* PARSE_OPT_UNKNOWN */ @@ -541,7 +541,8 @@ static int usage_with_options_internal(struct parse_opt_ctx_t *ctx, if (opts->type == OPTION_NUMBER) pos += fprintf(outfile, "-NUM"); - if (!(opts->flags & PARSE_OPT_NOARG)) + if ((opts->flags & PARSE_OPT_LITERAL_ARGHELP) || + !(opts->flags & PARSE_OPT_NOARG)) pos += usage_argh(opts, outfile); if (pos <= USAGE_OPTS_WIDTH) diff --git a/parse-options.h b/parse-options.h index ae8647d893..31ec5d2476 100644 --- a/parse-options.h +++ b/parse-options.h @@ -17,6 +17,7 @@ enum parse_opt_type { OPTION_STRING, OPTION_INTEGER, OPTION_CALLBACK, + OPTION_LOWLEVEL_CALLBACK, OPTION_FILENAME }; @@ -43,6 +44,10 @@ enum parse_opt_option_flags { struct option; typedef int parse_opt_cb(const struct option *, const char *arg, int unset); +struct parse_opt_ctx_t; +typedef int parse_opt_ll_cb(struct parse_opt_ctx_t *ctx, + const struct option *opt, int unset); + /* * `type`:: * holds the type of the option, you must have an OPTION_END last in your @@ -87,7 +92,8 @@ typedef int parse_opt_cb(const struct option *, const char *arg, int unset); * useful for users of OPTION_NEGBIT. * * `callback`:: - * pointer to the callback to use for OPTION_CALLBACK. + * pointer to the callback to use for OPTION_CALLBACK or + * OPTION_LOWLEVEL_CALLBACK. * * `defval`:: * default value to fill (*->value) with for PARSE_OPT_OPTARG. @@ -161,6 +167,7 @@ extern NORETURN void usage_msg_opt(const char *msg, enum { PARSE_OPT_HELP = -1, PARSE_OPT_DONE, + PARSE_OPT_NON_OPTION, PARSE_OPT_UNKNOWN }; @@ -180,7 +187,7 @@ struct parse_opt_ctx_t { extern void parse_options_start(struct parse_opt_ctx_t *ctx, int argc, const char **argv, const char *prefix, - int flags); + const struct option *options, int flags); extern int parse_options_step(struct parse_opt_ctx_t *ctx, const struct option *options, diff --git a/reflog-walk.c b/reflog-walk.c index 4879615cad..5d81d39a52 100644 --- a/reflog-walk.c +++ b/reflog-walk.c @@ -239,7 +239,6 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit) commit->parents = xcalloc(sizeof(struct commit_list), 1); commit->parents->item = commit_info->commit; - commit->object.flags &= ~(ADDED | SEEN | SHOWN); } void get_reflog_selector(struct strbuf *sb, diff --git a/revision.c b/revision.c index b1c18906ba..ded881263b 100644 --- a/revision.c +++ b/revision.c @@ -2030,8 +2030,10 @@ static struct commit *get_revision_1(struct rev_info *revs) revs->commits = entry->next; free(entry); - if (revs->reflog_info) + if (revs->reflog_info) { fake_reflog_parent(revs->reflog_info, commit); + commit->object.flags &= ~(ADDED | SEEN | SHOWN); + } /* * If we haven't done the list limiting, we need to look at @@ -4,7 +4,7 @@ static int inside_git_dir = -1; static int inside_work_tree = -1; -const char *prefix_path(const char *prefix, int len, const char *path) +char *prefix_path(const char *prefix, int len, const char *path) { const char *orig = path; char *sanitized = xmalloc(len + strlen(path) + 1); @@ -512,8 +512,10 @@ const char *setup_git_directory_gently(int *nongit_ok) const char *prefix; prefix = setup_git_directory_gently_1(nongit_ok); - if (startup_info) + if (startup_info) { startup_info->have_repository = !nongit_ok || !*nongit_ok; + startup_info->prefix = prefix; + } return prefix; } diff --git a/sha1_name.c b/sha1_name.c index c5c59ced7f..ceb9cdd860 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -1091,6 +1091,23 @@ int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode, return ret; } +static char *resolve_relative_path(const char *rel) +{ + if (prefixcmp(rel, "./") && prefixcmp(rel, "../")) + return NULL; + + if (!startup_info) + die("BUG: startup_info struct is not initialized."); + + if (!is_inside_work_tree()) + die("relative path syntax can't be used outside working tree."); + + /* die() inside prefix_path() if resolved path is outside worktree */ + return prefix_path(startup_info->prefix, + startup_info->prefix ? strlen(startup_info->prefix) : 0, + rel); +} + int get_sha1_with_context_1(const char *name, unsigned char *sha1, struct object_context *oc, int gently, const char *prefix) @@ -1105,13 +1122,15 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1, if (!ret) return ret; /* sha1:path --> object name of path in ent sha1 - * :path -> object name of path in index + * :path -> object name of absolute path in index + * :./path -> object name of path relative to cwd in index * :[0-3]:path -> object name of path in index at stage * :/foo -> recent commit matching foo */ if (name[0] == ':') { int stage = 0; struct cache_entry *ce; + char *new_path = NULL; int pos; if (namelen > 2 && name[1] == '/') { struct commit_list *list = NULL; @@ -1126,7 +1145,13 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1, stage = name[1] - '0'; cp = name + 3; } - namelen = namelen - (cp - name); + new_path = resolve_relative_path(cp); + if (!new_path) { + namelen = namelen - (cp - name); + } else { + cp = new_path; + namelen = strlen(cp); + } strncpy(oc->path, cp, sizeof(oc->path)); @@ -1145,12 +1170,14 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1, if (ce_stage(ce) == stage) { hashcpy(sha1, ce->sha1); oc->mode = ce->ce_mode; + free(new_path); return 0; } pos++; } if (!gently) diagnose_invalid_index_path(stage, prefix, cp); + free(new_path); return -1; } for (cp = name, bracket_depth = 0; *cp; cp++) { @@ -1171,6 +1198,11 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1, } if (!get_sha1_1(name, cp-name, tree_sha1)) { const char *filename = cp+1; + char *new_filename = NULL; + + new_filename = resolve_relative_path(filename); + if (new_filename) + filename = new_filename; ret = get_tree_entry(tree_sha1, filename, sha1, &oc->mode); if (!gently) { diagnose_invalid_sha1_path(prefix, filename, @@ -1182,6 +1214,7 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1, sizeof(oc->path)); oc->path[sizeof(oc->path)-1] = '\0'; + free(new_filename); return ret; } else { if (!gently) diff --git a/submodule.c b/submodule.c index 91a4758747..6f1c10722f 100644 --- a/submodule.c +++ b/submodule.c @@ -10,7 +10,9 @@ #include "string-list.h" struct string_list config_name_for_path; +struct string_list config_fetch_recurse_submodules_for_name; struct string_list config_ignore_for_name; +static int config_fetch_recurse_submodules; static int add_submodule_odb(const char *path) { @@ -63,10 +65,14 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt, } } -static int submodule_config(const char *var, const char *value, void *cb) +int submodule_config(const char *var, const char *value, void *cb) { if (!prefixcmp(var, "submodule.")) return parse_submodule_config_option(var, value); + else if (!strcmp(var, "fetch.recursesubmodules")) { + config_fetch_recurse_submodules = git_config_bool(var, value); + return 0; + } return 0; } @@ -100,6 +106,14 @@ int parse_submodule_config_option(const char *var, const char *value) config = string_list_append(&config_name_for_path, xstrdup(value)); config->util = strbuf_detach(&submodname, NULL); strbuf_release(&submodname); + } else if ((len > 23) && !strcmp(var + len - 23, ".fetchrecursesubmodules")) { + strbuf_add(&submodname, var, len - 23); + config = unsorted_string_list_lookup(&config_fetch_recurse_submodules_for_name, submodname.buf); + if (!config) + config = string_list_append(&config_fetch_recurse_submodules_for_name, + strbuf_detach(&submodname, NULL)); + config->util = git_config_bool(var, value) ? (void *)1 : NULL; + strbuf_release(&submodname); } else if ((len > 7) && !strcmp(var + len - 7, ".ignore")) { if (strcmp(value, "untracked") && strcmp(value, "dirty") && strcmp(value, "all") && strcmp(value, "none")) { @@ -229,6 +243,89 @@ void show_submodule_summary(FILE *f, const char *path, strbuf_release(&sb); } +void set_config_fetch_recurse_submodules(int value) +{ + config_fetch_recurse_submodules = value; +} + +int fetch_populated_submodules(int num_options, const char **options, + const char *prefix, int ignore_config, + int quiet) +{ + int i, result = 0, argc = 0; + struct child_process cp; + const char **argv; + struct string_list_item *name_for_path; + const char *work_tree = get_git_work_tree(); + if (!work_tree) + return 0; + + if (!the_index.initialized) + if (read_cache() < 0) + die("index file corrupt"); + + /* 4: "fetch" (options) "--submodule-prefix" prefix NULL */ + argv = xcalloc(num_options + 4, sizeof(const char *)); + argv[argc++] = "fetch"; + for (i = 0; i < num_options; i++) + argv[argc++] = options[i]; + argv[argc++] = "--submodule-prefix"; + + memset(&cp, 0, sizeof(cp)); + cp.argv = argv; + cp.env = local_repo_env; + cp.git_cmd = 1; + cp.no_stdin = 1; + + for (i = 0; i < active_nr; i++) { + struct strbuf submodule_path = STRBUF_INIT; + struct strbuf submodule_git_dir = STRBUF_INIT; + struct strbuf submodule_prefix = STRBUF_INIT; + struct cache_entry *ce = active_cache[i]; + const char *git_dir, *name; + + if (!S_ISGITLINK(ce->ce_mode)) + continue; + + name = ce->name; + name_for_path = unsorted_string_list_lookup(&config_name_for_path, ce->name); + if (name_for_path) + name = name_for_path->util; + + if (!ignore_config) { + struct string_list_item *fetch_recurse_submodules_option; + fetch_recurse_submodules_option = unsorted_string_list_lookup(&config_fetch_recurse_submodules_for_name, name); + if (fetch_recurse_submodules_option) { + if (!fetch_recurse_submodules_option->util) + continue; + } else { + if (!config_fetch_recurse_submodules) + continue; + } + } + + strbuf_addf(&submodule_path, "%s/%s", work_tree, ce->name); + strbuf_addf(&submodule_git_dir, "%s/.git", submodule_path.buf); + strbuf_addf(&submodule_prefix, "%s%s/", prefix, ce->name); + git_dir = read_gitfile_gently(submodule_git_dir.buf); + if (!git_dir) + git_dir = submodule_git_dir.buf; + if (is_directory(git_dir)) { + if (!quiet) + printf("Fetching submodule %s%s\n", prefix, ce->name); + cp.dir = submodule_path.buf; + argv[argc] = submodule_prefix.buf; + if (run_command(&cp)) + result = 1; + } + strbuf_release(&submodule_path); + strbuf_release(&submodule_git_dir); + strbuf_release(&submodule_prefix); + } + free(argv); + return result; +} + unsigned is_submodule_modified(const char *path, int ignore_untracked) { ssize_t len; diff --git a/submodule.h b/submodule.h index 386f410a66..4729023aa5 100644 --- a/submodule.h +++ b/submodule.h @@ -5,6 +5,7 @@ struct diff_options; void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt, const char *path); +int submodule_config(const char *var, const char *value, void *cb); void gitmodules_config(); int parse_submodule_config_option(const char *var, const char *value); void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *); @@ -12,6 +13,10 @@ void show_submodule_summary(FILE *f, const char *path, unsigned char one[20], unsigned char two[20], unsigned dirty_submodule, const char *del, const char *add, const char *reset); +void set_config_fetch_recurse_submodules(int value); +int fetch_populated_submodules(int num_options, const char **options, + const char *prefix, int ignore_config, + int quiet); unsigned is_submodule_modified(const char *path, int ignore_untracked); int merge_submodule(unsigned char result[20], const char *path, const unsigned char base[20], const unsigned char a[20], const unsigned char b[20]); diff --git a/t/Makefile b/t/Makefile index 73c6ec473d..47cbeb6e68 100644 --- a/t/Makefile +++ b/t/Makefile @@ -23,10 +23,10 @@ TGITWEB = $(wildcard t95[0-9][0-9]-*.sh) all: $(DEFAULT_TEST_TARGET) -test: pre-clean +test: pre-clean $(TEST_LINT) $(MAKE) aggregate-results-and-cleanup -prove: pre-clean +prove: pre-clean $(TEST_LINT) @echo "*** prove ***"; GIT_CONFIG=.git/config $(PROVE) --exec '$(SHELL_PATH_SQ)' $(GIT_PROVE_OPTS) $(T) :: $(GIT_TEST_OPTS) $(MAKE) clean @@ -41,6 +41,18 @@ clean: $(RM) -r valgrind/bin $(RM) .prove +test-lint: test-lint-duplicates test-lint-executable + +test-lint-duplicates: + @dups=`echo $(T) | tr ' ' '\n' | sed 's/-.*//' | sort | uniq -d` && \ + test -z "$$dups" || { \ + echo >&2 "duplicate test numbers:" $$dups; exit 1; } + +test-lint-executable: + @bad=`for i in $(T); do test -x "$$i" || echo $$i; done` && \ + test -z "$$bad" || { \ + echo >&2 "non-executable tests:" $$bad; exit 1; } + aggregate-results-and-cleanup: $(T) $(MAKE) aggregate-results $(MAKE) clean diff --git a/t/t1412-reflog-loop.sh b/t/t1412-reflog-loop.sh new file mode 100755 index 0000000000..7f519e5ebe --- /dev/null +++ b/t/t1412-reflog-loop.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +test_description='reflog walk shows repeated commits again' +. ./test-lib.sh + +test_expect_success 'setup commits' ' + test_tick && + echo content >file && git add file && git commit -m one && + git tag one && + echo content >>file && git add file && git commit -m two && + git tag two +' + +test_expect_success 'setup reflog with alternating commits' ' + git checkout -b topic && + git reset one && + git reset two && + git reset one && + git reset two +' + +test_expect_success 'reflog shows all entries' ' + cat >expect <<-\EOF + topic@{0} two: updating HEAD + topic@{1} one: updating HEAD + topic@{2} two: updating HEAD + topic@{3} one: updating HEAD + topic@{4} branch: Created from HEAD + EOF + git log -g --format="%gd %gs" topic >actual && + test_cmp expect actual +' + +test_done diff --git a/t/t1506-rev-parse-diagnosis.sh b/t/t1506-rev-parse-diagnosis.sh index 0eeeb0e450..9f8adb1f82 100755 --- a/t/t1506-rev-parse-diagnosis.sh +++ b/t/t1506-rev-parse-diagnosis.sh @@ -31,6 +31,67 @@ test_expect_success 'correct file objects' ' test $HASH_file = $(git rev-parse :0:file.txt) ) ' +test_expect_success 'correct relative file objects (0)' ' + git rev-parse :file.txt >expected && + git rev-parse :./file.txt >result && + test_cmp expected result && + git rev-parse :0:./file.txt >result && + test_cmp expected result +' + +test_expect_success 'correct relative file objects (1)' ' + git rev-parse HEAD:file.txt >expected && + git rev-parse HEAD:./file.txt >result && + test_cmp expected result +' + +test_expect_success 'correct relative file objects (2)' ' + ( + cd subdir && + git rev-parse HEAD:../file.txt >result && + test_cmp ../expected result + ) +' + +test_expect_success 'correct relative file objects (3)' ' + ( + cd subdir && + git rev-parse HEAD:../subdir/../file.txt >result && + test_cmp ../expected result + ) +' + +test_expect_success 'correct relative file objects (4)' ' + git rev-parse HEAD:subdir/file.txt >expected && + ( + cd subdir && + git rev-parse HEAD:./file.txt >result && + test_cmp ../expected result + ) +' + +test_expect_success 'correct relative file objects (5)' ' + git rev-parse :subdir/file.txt >expected && + ( + cd subdir && + git rev-parse :./file.txt >result && + test_cmp ../expected result && + git rev-parse :0:./file.txt >result && + test_cmp ../expected result + ) +' + +test_expect_success 'correct relative file objects (6)' ' + git rev-parse :file.txt >expected && + ( + cd subdir && + git rev-parse :../file.txt >result && + test_cmp ../expected result && + git rev-parse :0:../file.txt >result && + test_cmp ../expected result + ) +' + test_expect_success 'incorrect revision id' ' test_must_fail git rev-parse foobar:file.txt 2>error && grep "Invalid object name '"'"'foobar'"'"'." error && @@ -75,4 +136,29 @@ test_expect_success 'invalid @{n} reference' ' grep "fatal: Log for [^ ]* only has [0-9][0-9]* entries." error ' +test_expect_success 'relative path not found' ' + ( + cd subdir && + test_must_fail git rev-parse HEAD:./nonexistent.txt 2>error && + grep subdir/nonexistent.txt error + ) +' + +test_expect_success 'relative path outside worktree' ' + test_must_fail git rev-parse HEAD:../file.txt >output 2>error && + test -z "$(cat output)" && + grep "outside repository" error +' + +test_expect_success 'relative path when cwd is outside worktree' ' + test_must_fail git --git-dir=.git --work-tree=subdir rev-parse HEAD:./file.txt >output 2>error && + test -z "$(cat output)" && + grep "relative path syntax can.t be used outside working tree." error +' + +test_expect_success 'relative path when startup_info is NULL' ' + test_must_fail test-match-trees HEAD:./file.txt HEAD:./file.txt 2>error && + grep "BUG: startup_info struct is not initialized." error +' + test_done diff --git a/t/t2006-checkout-index-basic.sh b/t/t2006-checkout-index-basic.sh new file mode 100755 index 0000000000..b8559838b1 --- /dev/null +++ b/t/t2006-checkout-index-basic.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +test_description='basic checkout-index tests +' + +. ./test-lib.sh + +test_expect_success 'checkout-index --gobbledegook' ' + test_expect_code 129 git checkout-index --gobbledegook 2>err && + grep "[Uu]sage" err +' + +test_expect_success 'checkout-index -h in broken repository' ' + mkdir broken && + ( + cd broken && + git init && + >.git/index && + test_expect_code 129 git checkout-index -h >usage 2>&1 + ) && + grep "[Uu]sage" broken/usage +' + +test_done diff --git a/t/t2107-update-index-basic.sh b/t/t2107-update-index-basic.sh new file mode 100755 index 0000000000..33f8be0cd7 --- /dev/null +++ b/t/t2107-update-index-basic.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +test_description='basic update-index tests + +Tests for command-line parsing and basic operation. +' + +. ./test-lib.sh + +test_expect_success 'update-index --nonsense fails' ' + test_must_fail git update-index --nonsense 2>msg && + cat msg && + test -s msg +' + +test_expect_failure 'update-index --nonsense dumps usage' ' + test_expect_code 129 git update-index --nonsense 2>err && + grep "[Uu]sage: git update-index" err +' + +test_expect_success 'update-index -h with corrupt index' ' + mkdir broken && + ( + cd broken && + git init && + >.git/index && + test_expect_code 129 git update-index -h >usage 2>&1 + ) && + grep "[Uu]sage: git update-index" broken/usage +' + +test_done diff --git a/t/t3004-ls-files-basic.sh b/t/t3004-ls-files-basic.sh new file mode 100755 index 0000000000..490e052875 --- /dev/null +++ b/t/t3004-ls-files-basic.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +test_description='basic ls-files tests + +This test runs git ls-files with various unusual or malformed +command-line arguments. +' + +. ./test-lib.sh + +>empty + +test_expect_success 'ls-files in empty repository' ' + git ls-files >actual && + test_cmp empty actual +' + +test_expect_success 'ls-files with nonexistent path' ' + git ls-files doesnotexist >actual && + test_cmp empty actual +' + +test_expect_success 'ls-files with nonsense option' ' + test_expect_code 129 git ls-files --nonsense 2>actual && + grep "[Uu]sage: git ls-files" actual +' + +test_expect_success 'ls-files -h in corrupt repository' ' + mkdir broken && + ( + cd broken && + git init && + >.git/index && + test_expect_code 129 git ls-files -h >usage 2>&1 + ) && + grep "[Uu]sage: git ls-files " broken/usage +' + +test_done diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index f54a533456..f308235f5d 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -26,6 +26,17 @@ test_expect_success \ ! test -f .git/refs/heads/--help ' +test_expect_success 'branch -h in broken repository' ' + mkdir broken && + ( + cd broken && + git init && + >.git/refs/heads/master && + test_expect_code 129 git branch -h >usage 2>&1 + ) && + grep "[Uu]sage" broken/usage +' + test_expect_success \ 'git branch abc should create a branch' \ 'git branch abc && test -f .git/refs/heads/abc' diff --git a/t/t3407-rebase-abort.sh b/t/t3407-rebase-abort.sh index fbb3f2e0df..e573dc845b 100755 --- a/t/t3407-rebase-abort.sh +++ b/t/t3407-rebase-abort.sh @@ -72,6 +72,18 @@ testrebase() { test $(git rev-parse to-rebase) = $(git rev-parse pre-rebase) && test ! -d "$dotest" ' + + test_expect_success "rebase$type --abort does not update reflog" ' + cd "$work_dir" && + # Clean up the state from the previous one + git reset --hard pre-rebase && + git reflog show to-rebase > reflog_before && + test_must_fail git rebase$type master && + git rebase --abort && + git reflog show to-rebase > reflog_after && + test_cmp reflog_before reflog_after && + rm reflog_before reflog_after + ' } testrebase "" .git/rebase-apply diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 07bf6eb49d..027c13d52c 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -6,6 +6,7 @@ test_description='various format-patch tests' . ./test-lib.sh +. "$TEST_DIRECTORY"/lib-terminal.sh test_expect_success setup ' @@ -686,4 +687,26 @@ test_expect_success 'format-patch --signature="" supresses signatures' ' ! grep "^-- \$" output ' +test_expect_success TTY 'format-patch --stdout paginates' ' + rm -f pager_used && + ( + GIT_PAGER="wc >pager_used" && + export GIT_PAGER && + test_terminal git format-patch --stdout --all + ) && + test_path_is_file pager_used +' + + test_expect_success TTY 'format-patch --stdout pagination can be disabled' ' + rm -f pager_used && + ( + GIT_PAGER="wc >pager_used" && + export GIT_PAGER && + test_terminal git --no-pager format-patch --stdout --all && + test_terminal git -c "pager.format-patch=false" format-patch --stdout --all + ) && + test_path_is_missing pager_used && + test_path_is_missing .git/pager_used +' + test_done diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index 8622eb51c7..9059bcd69e 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -344,6 +344,13 @@ test_expect_success 'check spaces as indentation (indent-with-non-tab: on)' ' ' +test_expect_success 'ditto, but tabwidth=9' ' + + git config core.whitespace "indent-with-non-tab,tabwidth=9" && + git diff --check + +' + test_expect_success 'check tabs and spaces as indentation (indent-with-non-tab: on)' ' git config core.whitespace "indent-with-non-tab" && @@ -352,6 +359,20 @@ test_expect_success 'check tabs and spaces as indentation (indent-with-non-tab: ' +test_expect_success 'ditto, but tabwidth=10' ' + + git config core.whitespace "indent-with-non-tab,tabwidth=10" && + test_must_fail git diff --check + +' + +test_expect_success 'ditto, but tabwidth=20' ' + + git config core.whitespace "indent-with-non-tab,tabwidth=20" && + git diff --check + +' + test_expect_success 'check tabs as indentation (tab-in-indent: off)' ' git config core.whitespace "-tab-in-indent" && @@ -376,6 +397,13 @@ test_expect_success 'check tabs and spaces as indentation (tab-in-indent: on)' ' ' +test_expect_success 'ditto, but tabwidth=1 (must be irrelevant)' ' + + git config core.whitespace "tab-in-indent,tabwidth=1" && + test_must_fail git diff --check + +' + test_expect_success 'check tab-in-indent and indent-with-non-tab conflict' ' git config core.whitespace "tab-in-indent,indent-with-non-tab" && diff --git a/t/t4019-diff-wserror.sh b/t/t4019-diff-wserror.sh index 3fa836f9d3..a5019759bc 100755 --- a/t/t4019-diff-wserror.sh +++ b/t/t4019-diff-wserror.sh @@ -51,8 +51,65 @@ test_expect_success default ' ' +test_expect_success 'default (attribute)' ' + + test_might_fail git config --unset core.whitespace && + echo "F whitespace" >.gitattributes && + prepare_output && + + grep Eight error >/dev/null && + grep HT error >/dev/null && + grep With error >/dev/null && + grep Return error >/dev/null && + grep No normal >/dev/null + +' + +test_expect_success 'default, tabwidth=10 (attribute)' ' + + git config core.whitespace "tabwidth=10" && + echo "F whitespace" >.gitattributes && + prepare_output && + + grep Eight normal >/dev/null && + grep HT error >/dev/null && + grep With error >/dev/null && + grep Return error >/dev/null && + grep No normal >/dev/null + +' + +test_expect_success 'no check (attribute)' ' + + test_might_fail git config --unset core.whitespace && + echo "F -whitespace" >.gitattributes && + prepare_output && + + grep Eight normal >/dev/null && + grep HT normal >/dev/null && + grep With normal >/dev/null && + grep Return normal >/dev/null && + grep No normal >/dev/null + +' + +test_expect_success 'no check, tabwidth=10 (attribute), must be irrelevant' ' + + git config core.whitespace "tabwidth=10" && + echo "F -whitespace" >.gitattributes && + prepare_output && + + grep Eight normal >/dev/null && + grep HT normal >/dev/null && + grep With normal >/dev/null && + grep Return normal >/dev/null && + grep No normal >/dev/null + +' + test_expect_success 'without -trail' ' + rm -f .gitattributes && git config core.whitespace -trail && prepare_output && @@ -134,6 +191,34 @@ test_expect_success 'with indent-non-tab only (attribute)' ' ' +test_expect_success 'with indent-non-tab only, tabwidth=10' ' + + rm -f .gitattributes && + git config core.whitespace indent,tabwidth=10,-trailing,-space && + prepare_output && + + grep Eight normal >/dev/null && + grep HT normal >/dev/null && + grep With normal >/dev/null && + grep Return normal >/dev/null && + grep No normal >/dev/null + +' + +test_expect_success 'with indent-non-tab only, tabwidth=10 (attribute)' ' + + test_might_fail git config --unset core.whitespace && + echo "F whitespace=indent,-trailing,-space,tabwidth=10" >.gitattributes && + prepare_output && + + grep Eight normal >/dev/null && + grep HT normal >/dev/null && + grep With normal >/dev/null && + grep Return normal >/dev/null && + grep No normal >/dev/null + +' + test_expect_success 'with cr-at-eol' ' rm -f .gitattributes && diff --git a/t/t4124-apply-ws-rule.sh b/t/t4124-apply-ws-rule.sh index 61bfc569c3..6f6ee88b28 100755 --- a/t/t4124-apply-ws-rule.sh +++ b/t/t4124-apply-ws-rule.sh @@ -10,7 +10,8 @@ prepare_test_file () { # X RULE # ! trailing-space # @ space-before-tab - # # indent-with-non-tab + # # indent-with-non-tab (default tab width 8) + # = indent-with-non-tab,tabwidth=16 # % tab-in-indent sed -e "s/_/ /g" -e "s/>/ /" <<-\EOF An_SP in an ordinary line>and a HT. @@ -25,8 +26,8 @@ prepare_test_file () { ________>_Eight SP, a HT and a SP (@#%). _______________Fifteen SP (#). _______________>Fifteen SP and a HT (@#%). - ________________Sixteen SP (#). - ________________>Sixteen SP and a HT (@#%). + ________________Sixteen SP (#=). + ________________>Sixteen SP and a HT (@#%=). _____a__Five SP, a non WS, two SP. A line with a (!) trailing SP_ A line with a (!) trailing HT> @@ -121,6 +122,34 @@ test_expect_success 'whitespace=error-all, no rule (attribute)' ' ' +test_expect_success 'spaces inserted by tab-in-indent' ' + + git config core.whitespace -trailing,-space,-indent,tab && + rm -f .gitattributes && + test_fix % && + sed -e "s/_/ /g" -e "s/>/ /" <<-\EOF >expect && + An_SP in an ordinary line>and a HT. + ________A HT (%). + ________A SP and a HT (@%). + _________A SP, a HT and a SP (@%). + _______Seven SP. + ________Eight SP (#). + ________Seven SP and a HT (@%). + ________________Eight SP and a HT (@#%). + _________Seven SP, a HT and a SP (@%). + _________________Eight SP, a HT and a SP (@#%). + _______________Fifteen SP (#). + ________________Fifteen SP and a HT (@#%). + ________________Sixteen SP (#=). + ________________________Sixteen SP and a HT (@#%=). + _____a__Five SP, a non WS, two SP. + A line with a (!) trailing SP_ + A line with a (!) trailing HT> + EOF + test_cmp expect target + +' + for t in - '' do case "$t" in '') tt='!' ;; *) tt= ;; esac @@ -129,7 +158,7 @@ do case "$s" in '') ts='@' ;; *) ts= ;; esac for i in - '' do - case "$i" in '') ti='#' ;; *) ti= ;; esac + case "$i" in '') ti='#' ti16='=';; *) ti= ti16= ;; esac for h in - '' do [ -z "$h$i" ] && continue @@ -142,12 +171,22 @@ do test_fix "$tt$ts$ti$th" ' + test_expect_success "rule=$rule,tabwidth=16" ' + git config core.whitespace "$rule,tabwidth=16" && + test_fix "$tt$ts$ti16$th" + ' + test_expect_success "rule=$rule (attributes)" ' git config --unset core.whitespace && echo "target whitespace=$rule" >.gitattributes && test_fix "$tt$ts$ti$th" ' + test_expect_success "rule=$rule,tabwidth=16 (attributes)" ' + echo "target whitespace=$rule,tabwidth=16" >.gitattributes && + test_fix "$tt$ts$ti16$th" + ' + done done done diff --git a/t/t5520-pull.sh b/t/t5520-pull.sh index 0b489f5b12..0470a81be0 100755 --- a/t/t5520-pull.sh +++ b/t/t5520-pull.sh @@ -222,4 +222,11 @@ test_expect_success 'git pull --rebase does not reapply old patches' ' ) ' +test_expect_success 'git pull --rebase against local branch' ' + git checkout -b copy2 to-rebase-orig && + git pull --rebase . to-rebase && + test "conflicting modification" = "$(cat file)" && + test file = "$(cat file2)" +' + test_done diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh new file mode 100755 index 0000000000..884a5e567c --- /dev/null +++ b/t/t5526-fetch-submodules.sh @@ -0,0 +1,195 @@ +#!/bin/sh +# Copyright (c) 2010, Jens Lehmann + +test_description='Recursive "git fetch" for submodules' + +. ./test-lib.sh + +pwd=$(pwd) + +add_upstream_commit() { + ( + cd submodule && + head1=$(git rev-parse --short HEAD) && + echo new >> subfile && + test_tick && + git add subfile && + git commit -m new subfile && + head2=$(git rev-parse --short HEAD) && + echo "From $pwd/submodule" > ../expect.err && + echo " $head1..$head2 master -> origin/master" >> ../expect.err + ) && + ( + cd deepsubmodule && + head1=$(git rev-parse --short HEAD) && + echo new >> deepsubfile && + test_tick && + git add deepsubfile && + git commit -m new deepsubfile && + head2=$(git rev-parse --short HEAD) && + echo "From $pwd/deepsubmodule" >> ../expect.err && + echo " $head1..$head2 master -> origin/master" >> ../expect.err + ) +} + +test_expect_success setup ' + mkdir deepsubmodule && + ( + cd deepsubmodule && + git init && + echo deepsubcontent > deepsubfile && + git add deepsubfile && + git commit -m new deepsubfile + ) && + mkdir submodule && + ( + cd submodule && + git init && + echo subcontent > subfile && + git add subfile && + git submodule add "$pwd/deepsubmodule" deepsubmodule && + git commit -a -m new + ) && + git submodule add "$pwd/submodule" submodule && + git commit -am initial && + git clone . downstream && + ( + cd downstream && + git submodule update --init --recursive + ) && + echo "Fetching submodule submodule" > expect.out && + echo "Fetching submodule submodule/deepsubmodule" >> expect.out +' + +test_expect_success "fetch --recurse-submodules recurses into submodules" ' + add_upstream_commit && + ( + cd downstream && + git fetch --recurse-submodules >../actual.out 2>../actual.err + ) && + test_cmp expect.out actual.out && + test_cmp expect.err actual.err +' + +test_expect_success "fetch alone only fetches superproject" ' + add_upstream_commit && + ( + cd downstream && + git fetch >../actual.out 2>../actual.err + ) && + ! test -s actual.out && + ! test -s actual.err +' + +test_expect_success "fetch --no-recurse-submodules only fetches superproject" ' + ( + cd downstream && + git fetch --no-recurse-submodules >../actual.out 2>../actual.err + ) && + ! test -s actual.out && + ! test -s actual.err +' + +test_expect_success "using fetchRecurseSubmodules=true in .gitmodules recurses into submodules" ' + ( + cd downstream && + git config -f .gitmodules submodule.submodule.fetchRecurseSubmodules true && + git fetch >../actual.out 2>../actual.err + ) && + test_cmp expect.out actual.out && + test_cmp expect.err actual.err +' + +test_expect_success "--no-recurse-submodules overrides .gitmodules config" ' + add_upstream_commit && + ( + cd downstream && + git fetch --no-recurse-submodules >../actual.out 2>../actual.err + ) && + ! test -s actual.out && + ! test -s actual.err +' + +test_expect_success "using fetchRecurseSubmodules=false in .git/config overrides setting in .gitmodules" ' + ( + cd downstream && + git config submodule.submodule.fetchRecurseSubmodules false && + git fetch >../actual.out 2>../actual.err + ) && + ! test -s actual.out && + ! test -s actual.err +' + +test_expect_success "--recurse-submodules overrides fetchRecurseSubmodules setting from .git/config" ' + ( + cd downstream && + git fetch --recurse-submodules >../actual.out 2>../actual.err && + git config -f --unset .gitmodules submodule.submodule.fetchRecurseSubmodules true && + git config --unset submodule.submodule.fetchRecurseSubmodules + ) && + test_cmp expect.out actual.out && + test_cmp expect.err actual.err +' + +test_expect_success "--quiet propagates to submodules" ' + ( + cd downstream && + git fetch --recurse-submodules --quiet >../actual.out 2>../actual.err + ) && + ! test -s actual.out && + ! test -s actual.err +' + +test_expect_success "--dry-run propagates to submodules" ' + add_upstream_commit && + ( + cd downstream && + git fetch --recurse-submodules --dry-run >../actual.out 2>../actual.err + ) && + test_cmp expect.out actual.out && + test_cmp expect.err actual.err && + ( + cd downstream && + git fetch --recurse-submodules >../actual.out 2>../actual.err + ) && + test_cmp expect.out actual.out && + test_cmp expect.err actual.err +' + +test_expect_success "recurseSubmodules=true propagates into submodules" ' + add_upstream_commit && + ( + cd downstream && + git config fetch.recurseSubmodules true + git fetch >../actual.out 2>../actual.err + ) && + test_cmp expect.out actual.out && + test_cmp expect.err actual.err +' + +test_expect_success "--recurse-submodules overrides config in submodule" ' + add_upstream_commit && + ( + cd downstream && + ( + cd submodule && + git config fetch.recurseSubmodules false + ) && + git fetch --recurse-submodules >../actual.out 2>../actual.err + ) && + test_cmp expect.out actual.out && + test_cmp expect.err actual.err +' + +test_expect_success "--no-recurse-submodules overrides config setting" ' + add_upstream_commit && + ( + cd downstream && + git config fetch.recurseSubmodules true + git fetch --no-recurse-submodules >../actual.out 2>../actual.err + ) && + ! test -s actual.out && + ! test -s actual.err +' + +test_done diff --git a/t/t5550-http-fetch.sh b/t/t5550-http-fetch.sh index 8c2ac353b7..a1883ca6b6 100755 --- a/t/t5550-http-fetch.sh +++ b/t/t5550-http-fetch.sh @@ -30,7 +30,8 @@ test_expect_success 'create http-accessible bare repository' ' ' test_expect_success 'clone http repository' ' - git clone $HTTPD_URL/dumb/repo.git clone && + git clone $HTTPD_URL/dumb/repo.git clone-tmpl && + cp -R clone-tmpl clone && test_cmp file clone/file ' @@ -44,11 +45,22 @@ test_expect_success 'clone http repository with authentication' ' test_expect_success 'fetch changes via http' ' echo content >>file && git commit -a -m two && - git push public + git push public && (cd clone && git pull) && test_cmp file clone/file ' +test_expect_success 'fetch changes via manual http-fetch' ' + cp -R clone-tmpl clone2 && + + HEAD=$(git rev-parse --verify HEAD) && + (cd clone2 && + git http-fetch -a -w heads/master-new $HEAD $(git config remote.origin.url) && + git checkout master-new && + test $HEAD = $(git rev-parse --verify HEAD)) && + test_cmp file clone2/file +' + test_expect_success 'http remote detects correct HEAD' ' git push public master:other && (cd clone && diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh new file mode 100755 index 0000000000..82f3639937 --- /dev/null +++ b/t/t6500-gc.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +test_description='basic git gc tests +' + +. ./test-lib.sh + +test_expect_success 'gc empty repository' ' + git gc +' + +test_expect_success 'gc --gobbledegook' ' + test_expect_code 129 git gc --nonsense 2>err && + grep "[Uu]sage: git gc" err +' + +test_expect_success 'gc -h with invalid configuration' ' + mkdir broken && + ( + cd broken && + git init && + echo "[gc] pruneexpire = CORRUPT" >>.git/config && + test_expect_code 129 git gc -h >usage 2>&1 + ) && + grep "[Uu]sage" broken/usage +' + +test_done diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index 782b0a3ece..2c49db9f62 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -421,11 +421,29 @@ test_expect_success 'add submodules without specifying an explicit path' ' git commit -m "repo commit 1" ) && git clone --bare repo/ bare.git && - cd addtest && - git submodule add "$submodurl/repo" && - git config -f .gitmodules submodule.repo.path repo && - git submodule add "$submodurl/bare.git" && - git config -f .gitmodules submodule.bare.path bare + ( + cd addtest && + git submodule add "$submodurl/repo" && + git config -f .gitmodules submodule.repo.path repo && + git submodule add "$submodurl/bare.git" && + git config -f .gitmodules submodule.bare.path bare + ) +' + +test_expect_success 'add should fail when path is used by a file' ' + ( + cd addtest && + touch file && + test_must_fail git submodule add "$submodurl/repo" file + ) +' + +test_expect_success 'add should fail when path is used by an existing directory' ' + ( + cd addtest && + mkdir empty-dir && + test_must_fail git submodule add "$submodurl/repo" empty-dir + ) ' test_done diff --git a/t/t7508-status.sh b/t/t7508-status.sh index 4de3e27950..f1dc5c3b6a 100755 --- a/t/t7508-status.sh +++ b/t/t7508-status.sh @@ -7,6 +7,30 @@ test_description='git status' . ./test-lib.sh +test_expect_success 'status -h in broken repository' ' + mkdir broken && + test_when_finished "rm -fr broken" && + ( + cd broken && + git init && + echo "[status] showuntrackedfiles = CORRUPT" >>.git/config && + test_expect_code 129 git status -h >usage 2>&1 + ) && + grep "[Uu]sage" broken/usage +' + +test_expect_success 'commit -h in broken repository' ' + mkdir broken && + test_when_finished "rm -fr broken" && + ( + cd broken && + git init && + echo "[status] showuntrackedfiles = CORRUPT" >>.git/config && + test_expect_code 129 git commit -h >usage 2>&1 + ) && + grep "[Uu]sage" broken/usage +' + test_expect_success 'setup' ' : >tracked && : >modified && @@ -381,12 +405,13 @@ test_expect_success 'status --porcelain ignores relative paths setting' ' test_expect_success 'setup unique colors' ' - git config status.color.untracked blue + git config status.color.untracked blue && + git config status.color.branch green ' cat >expect <<\EOF -# On branch master +# On branch <GREEN>master<RESET> # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh index b4f40e4c3a..b147a1bd69 100755 --- a/t/t7600-merge.sh +++ b/t/t7600-merge.sh @@ -144,6 +144,17 @@ test_expect_success 'test option parsing' ' test_must_fail git merge ' +test_expect_success 'merge -h with invalid index' ' + mkdir broken && + ( + cd broken && + git init && + >.git/index && + test_expect_code 129 git merge -h 2>usage + ) && + grep "[Uu]sage: git merge" broken/usage +' + test_expect_success 'reject non-strategy with a git-merge-foo name' ' test_must_fail git merge -s index c1 ' diff --git a/t/t7609-merge-abort.sh b/t/t7611-merge-abort.sh index 61890bc892..61890bc892 100755 --- a/t/t7609-merge-abort.sh +++ b/t/t7611-merge-abort.sh diff --git a/t/t8003-blame.sh b/t/t8003-blame-corner-cases.sh index 230143cf31..230143cf31 100755 --- a/t/t8003-blame.sh +++ b/t/t8003-blame-corner-cases.sh diff --git a/t/t8004-blame.sh b/t/t8004-blame-with-conflicts.sh index ba19ac127e..ba19ac127e 100755 --- a/t/t8004-blame.sh +++ b/t/t8004-blame-with-conflicts.sh diff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh index a713dfc50b..faf9092967 100755 --- a/t/t9010-svn-fe.sh +++ b/t/t9010-svn-fe.sh @@ -2,9 +2,25 @@ test_description='check svn dumpfile importer' -. ./lib-git-svn.sh +. ./test-lib.sh -test_dump() { +if ! svnadmin -h >/dev/null 2>&1 +then + skip_all='skipping svn-fe tests, svn not available' + test_done +fi + +svnconf=$PWD/svnconf +export svnconf + +svn_cmd () { + subcommand=$1 && + shift && + mkdir -p "$svnconf" && + svn "$subcommand" --config-dir "$svnconf" "$@" +} + +test_dump () { label=$1 dump=$2 test_expect_success "$dump" ' diff --git a/t/t9119-git-svn-info.sh b/t/t9119-git-svn-info.sh index f3f397cdda..ff19695e77 100755 --- a/t/t9119-git-svn-info.sh +++ b/t/t9119-git-svn-info.sh @@ -18,21 +18,14 @@ case $v in ;; esac -ptouch() { - perl -w -e ' - use strict; - use POSIX qw(mktime); - die "ptouch requires exactly 2 arguments" if @ARGV != 2; - my $text_last_updated = shift @ARGV; - my $git_file = shift @ARGV; - die "\"$git_file\" does not exist" if ! -e $git_file; - if ($text_last_updated - =~ /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/) { - my $mtime = mktime($6, $5, $4, $3, $2 - 1, $1 - 1900); - my $atime = $mtime; - utime $atime, $mtime, $git_file; - } - ' "`svn_cmd info $2 | grep '^Text Last Updated:'`" "$1" +# On the "Text Last Updated" line, "git svn info" does not return the +# same value as "svn info" (i.e. the commit timestamp that touched the +# path most recently); do not expect that field to match. +test_cmp_info () { + sed -e '/^Text Last Updated:/d' "$1" >tmp.expect + sed -e '/^Text Last Updated:/d' "$2" >tmp.actual + test_cmp tmp.expect tmp.actual && + rm -f tmp.expect tmp.actual } quoted_svnrepo="$(echo $svnrepo | sed 's/ /%20/')" @@ -62,17 +55,13 @@ test_expect_success 'setup repository and import' ' cd gitwc && git svn init "$svnrepo" && git svn fetch - ) && - ptouch gitwc/file svnwc/file && - ptouch gitwc/directory svnwc/directory && - ptouch gitwc/symlink-file svnwc/symlink-file && - ptouch gitwc/symlink-directory svnwc/symlink-directory + ) ' test_expect_success 'info' " (cd svnwc; svn info) > expected.info && (cd gitwc; git svn info) > actual.info && - test_cmp expected.info actual.info + test_cmp_info expected.info actual.info " test_expect_success 'info --url' ' @@ -82,7 +71,7 @@ test_expect_success 'info --url' ' test_expect_success 'info .' " (cd svnwc; svn info .) > expected.info-dot && (cd gitwc; git svn info .) > actual.info-dot && - test_cmp expected.info-dot actual.info-dot + test_cmp_info expected.info-dot actual.info-dot " test_expect_success 'info --url .' ' @@ -92,7 +81,7 @@ test_expect_success 'info --url .' ' test_expect_success 'info file' " (cd svnwc; svn info file) > expected.info-file && (cd gitwc; git svn info file) > actual.info-file && - test_cmp expected.info-file actual.info-file + test_cmp_info expected.info-file actual.info-file " test_expect_success 'info --url file' ' @@ -102,13 +91,13 @@ test_expect_success 'info --url file' ' test_expect_success 'info directory' " (cd svnwc; svn info directory) > expected.info-directory && (cd gitwc; git svn info directory) > actual.info-directory && - test_cmp expected.info-directory actual.info-directory + test_cmp_info expected.info-directory actual.info-directory " test_expect_success 'info inside directory' " (cd svnwc/directory; svn info) > expected.info-inside-directory && (cd gitwc/directory; git svn info) > actual.info-inside-directory && - test_cmp expected.info-inside-directory actual.info-inside-directory + test_cmp_info expected.info-inside-directory actual.info-inside-directory " test_expect_success 'info --url directory' ' @@ -118,7 +107,7 @@ test_expect_success 'info --url directory' ' test_expect_success 'info symlink-file' " (cd svnwc; svn info symlink-file) > expected.info-symlink-file && (cd gitwc; git svn info symlink-file) > actual.info-symlink-file && - test_cmp expected.info-symlink-file actual.info-symlink-file + test_cmp_info expected.info-symlink-file actual.info-symlink-file " test_expect_success 'info --url symlink-file' ' @@ -131,7 +120,7 @@ test_expect_success 'info symlink-directory' " > expected.info-symlink-directory && (cd gitwc; git svn info symlink-directory) \ > actual.info-symlink-directory && - test_cmp expected.info-symlink-directory actual.info-symlink-directory + test_cmp_info expected.info-symlink-directory actual.info-symlink-directory " test_expect_success 'info --url symlink-directory' ' @@ -146,14 +135,13 @@ test_expect_success 'info added-file' " git add added-file ) && cp gitwc/added-file svnwc/added-file && - ptouch gitwc/added-file svnwc/added-file && ( cd svnwc && svn_cmd add added-file > /dev/null ) && (cd svnwc; svn info added-file) > expected.info-added-file && (cd gitwc; git svn info added-file) > actual.info-added-file && - test_cmp expected.info-added-file actual.info-added-file + test_cmp_info expected.info-added-file actual.info-added-file " test_expect_success 'info --url added-file' ' @@ -163,7 +151,6 @@ test_expect_success 'info --url added-file' ' test_expect_success 'info added-directory' " mkdir gitwc/added-directory svnwc/added-directory && - ptouch gitwc/added-directory svnwc/added-directory && touch gitwc/added-directory/.placeholder && ( cd svnwc && @@ -177,7 +164,7 @@ test_expect_success 'info added-directory' " > expected.info-added-directory && (cd gitwc; git svn info added-directory) \ > actual.info-added-directory && - test_cmp expected.info-added-directory actual.info-added-directory + test_cmp_info expected.info-added-directory actual.info-added-directory " test_expect_success 'info --url added-directory' ' @@ -196,13 +183,12 @@ test_expect_success 'info added-symlink-file' " ln -s added-file added-symlink-file && svn_cmd add added-symlink-file > /dev/null ) && - ptouch gitwc/added-symlink-file svnwc/added-symlink-file && (cd svnwc; svn info added-symlink-file) \ > expected.info-added-symlink-file && (cd gitwc; git svn info added-symlink-file) \ > actual.info-added-symlink-file && - test_cmp expected.info-added-symlink-file \ - actual.info-added-symlink-file + test_cmp_info expected.info-added-symlink-file \ + actual.info-added-symlink-file " test_expect_success 'info --url added-symlink-file' ' @@ -221,13 +207,12 @@ test_expect_success 'info added-symlink-directory' " ln -s added-directory added-symlink-directory && svn_cmd add added-symlink-directory > /dev/null ) && - ptouch gitwc/added-symlink-directory svnwc/added-symlink-directory && (cd svnwc; svn info added-symlink-directory) \ > expected.info-added-symlink-directory && (cd gitwc; git svn info added-symlink-directory) \ > actual.info-added-symlink-directory && - test_cmp expected.info-added-symlink-directory \ - actual.info-added-symlink-directory + test_cmp_info expected.info-added-symlink-directory \ + actual.info-added-symlink-directory " test_expect_success 'info --url added-symlink-directory' ' @@ -235,11 +220,6 @@ test_expect_success 'info --url added-symlink-directory' ' = "$quoted_svnrepo/added-symlink-directory" ' -# The next few tests replace the "Text Last Updated" value with a -# placeholder since git doesn't have a way to know the date that a -# now-deleted file was last checked out locally. Internally it -# simply reuses the Last Changed Date. - test_expect_success 'info deleted-file' " ( cd gitwc && @@ -249,13 +229,9 @@ test_expect_success 'info deleted-file' " cd svnwc && svn_cmd rm --force file > /dev/null ) && - (cd svnwc; svn info file) | - sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \ - > expected.info-deleted-file && - (cd gitwc; git svn info file) | - sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \ - > actual.info-deleted-file && - test_cmp expected.info-deleted-file actual.info-deleted-file + (cd svnwc; svn info file) >expected.info-deleted-file && + (cd gitwc; git svn info file) >actual.info-deleted-file && + test_cmp_info expected.info-deleted-file actual.info-deleted-file " test_expect_success 'info --url file (deleted)' ' @@ -272,13 +248,9 @@ test_expect_success 'info deleted-directory' " cd svnwc && svn_cmd rm --force directory > /dev/null ) && - (cd svnwc; svn info directory) | - sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \ - > expected.info-deleted-directory && - (cd gitwc; git svn info directory) | - sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \ - > actual.info-deleted-directory && - test_cmp expected.info-deleted-directory actual.info-deleted-directory + (cd svnwc; svn info directory) >expected.info-deleted-directory && + (cd gitwc; git svn info directory) >actual.info-deleted-directory && + test_cmp_info expected.info-deleted-directory actual.info-deleted-directory " test_expect_success 'info --url directory (deleted)' ' @@ -295,14 +267,9 @@ test_expect_success 'info deleted-symlink-file' " cd svnwc && svn_cmd rm --force symlink-file > /dev/null ) && - (cd svnwc; svn info symlink-file) | - sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \ - > expected.info-deleted-symlink-file && - (cd gitwc; git svn info symlink-file) | - sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \ - > actual.info-deleted-symlink-file && - test_cmp expected.info-deleted-symlink-file \ - actual.info-deleted-symlink-file + (cd svnwc; svn info symlink-file) >expected.info-deleted-symlink-file && + (cd gitwc; git svn info symlink-file) >actual.info-deleted-symlink-file && + test_cmp_info expected.info-deleted-symlink-file actual.info-deleted-symlink-file " test_expect_success 'info --url symlink-file (deleted)' ' @@ -319,14 +286,9 @@ test_expect_success 'info deleted-symlink-directory' " cd svnwc && svn_cmd rm --force symlink-directory > /dev/null ) && - (cd svnwc; svn info symlink-directory) | - sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \ - > expected.info-deleted-symlink-directory && - (cd gitwc; git svn info symlink-directory) | - sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \ - > actual.info-deleted-symlink-directory && - test_cmp expected.info-deleted-symlink-directory \ - actual.info-deleted-symlink-directory + (cd svnwc; svn info symlink-directory) >expected.info-deleted-symlink-directory && + (cd gitwc; git svn info symlink-directory) >actual.info-deleted-symlink-directory && + test_cmp_info expected.info-deleted-symlink-directory actual.info-deleted-symlink-directory " test_expect_success 'info --url symlink-directory (deleted)' ' diff --git a/t/t9158-git-svn-mergeinfo.sh b/t/t9158-git-svn-mergeinfo.sh index 3ab43902b3..3ab43902b3 100644..100755 --- a/t/t9158-git-svn-mergeinfo.sh +++ b/t/t9158-git-svn-mergeinfo.sh diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index e8034d410f..222d1059ef 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -7,6 +7,23 @@ test_description='test git fast-import utility' . ./test-lib.sh . "$TEST_DIRECTORY"/diff-lib.sh ;# test-lib chdir's into trash +# Print $1 bytes from stdin to stdout. +# +# This could be written as "head -c $1", but IRIX "head" does not +# support the -c option. +head_c () { + perl -e ' + my $len = $ARGV[1]; + while ($len > 0) { + my $s; + my $nread = sysread(STDIN, $s, $len); + die "cannot read: $!" unless defined($nread); + print $s; + $len -= $nread; + } + ' - "$1" +} + file2_data='file2 second line of EOF' @@ -23,11 +40,18 @@ file5_data='an inline file. file6_data='#!/bin/sh echo "$@"' +>empty + ### ### series A ### test_tick + +test_expect_success 'empty stream succeeds' ' + git fast-import </dev/null +' + cat >input <<INPUT_END blob mark :2 @@ -1740,6 +1764,253 @@ test_expect_success 'R: feature no-relative-marks should be honoured' ' test_cmp marks.new non-relative.out ' +test_expect_success 'R: feature cat-blob supported' ' + echo "feature cat-blob" | + git fast-import +' + +test_expect_success 'R: cat-blob-fd must be a nonnegative integer' ' + test_must_fail git fast-import --cat-blob-fd=-1 </dev/null +' + +test_expect_success 'R: print old blob' ' + blob=$(echo "yes it can" | git hash-object -w --stdin) && + cat >expect <<-EOF && + ${blob} blob 11 + yes it can + + EOF + echo "cat-blob $blob" | + git fast-import --cat-blob-fd=6 6>actual && + test_cmp expect actual +' + +test_expect_success 'R: in-stream cat-blob-fd not respected' ' + echo hello >greeting && + blob=$(git hash-object -w greeting) && + cat >expect <<-EOF && + ${blob} blob 6 + hello + + EOF + git fast-import --cat-blob-fd=3 3>actual.3 >actual.1 <<-EOF && + cat-blob $blob + EOF + test_cmp expect actual.3 && + test_cmp empty actual.1 && + git fast-import 3>actual.3 >actual.1 <<-EOF && + option cat-blob-fd=3 + cat-blob $blob + EOF + test_cmp empty actual.3 && + test_cmp expect actual.1 +' + +test_expect_success 'R: print new blob' ' + blob=$(echo "yep yep yep" | git hash-object --stdin) && + cat >expect <<-EOF && + ${blob} blob 12 + yep yep yep + + EOF + git fast-import --cat-blob-fd=6 6>actual <<-\EOF && + blob + mark :1 + data <<BLOB_END + yep yep yep + BLOB_END + cat-blob :1 + EOF + test_cmp expect actual +' + +test_expect_success 'R: print new blob by sha1' ' + blob=$(echo "a new blob named by sha1" | git hash-object --stdin) && + cat >expect <<-EOF && + ${blob} blob 25 + a new blob named by sha1 + + EOF + git fast-import --cat-blob-fd=6 6>actual <<-EOF && + blob + data <<BLOB_END + a new blob named by sha1 + BLOB_END + cat-blob $blob + EOF + test_cmp expect actual +' + +test_expect_success 'setup: big file' ' + ( + echo "the quick brown fox jumps over the lazy dog" >big && + for i in 1 2 3 + do + cat big big big big >bigger && + cat bigger bigger bigger bigger >big || + exit + done + ) +' + +test_expect_success 'R: print two blobs to stdout' ' + blob1=$(git hash-object big) && + blob1_len=$(wc -c <big) && + blob2=$(echo hello | git hash-object --stdin) && + { + echo ${blob1} blob $blob1_len && + cat big && + cat <<-EOF + + ${blob2} blob 6 + hello + + EOF + } >expect && + { + cat <<-\END_PART1 && + blob + mark :1 + data <<data_end + END_PART1 + cat big && + cat <<-\EOF + data_end + blob + mark :2 + data <<data_end + hello + data_end + cat-blob :1 + cat-blob :2 + EOF + } | + git fast-import >actual && + test_cmp expect actual +' + +test_expect_success 'setup: have pipes?' ' + rm -f frob && + if mkfifo frob + then + test_set_prereq PIPE + fi +' + +test_expect_success PIPE 'R: copy using cat-file' ' + expect_id=$(git hash-object big) && + expect_len=$(wc -c <big) && + echo $expect_id blob $expect_len >expect.response && + + rm -f blobs && + cat >frontend <<-\FRONTEND_END && + #!/bin/sh + FRONTEND_END + + mkfifo blobs && + ( + export GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL GIT_COMMITTER_DATE && + cat <<-\EOF && + feature cat-blob + blob + mark :1 + data <<BLOB + EOF + cat big && + cat <<-\EOF && + BLOB + cat-blob :1 + EOF + + read blob_id type size <&3 && + echo "$blob_id $type $size" >response && + head_c $size >blob <&3 && + read newline <&3 && + + cat <<-EOF && + commit refs/heads/copied + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + copy big file as file3 + COMMIT + M 644 inline file3 + data <<BLOB + EOF + cat blob && + echo BLOB + ) 3<blobs | + git fast-import --cat-blob-fd=3 3>blobs && + git show copied:file3 >actual && + test_cmp expect.response response && + test_cmp big actual +' + +test_expect_success PIPE 'R: print blob mid-commit' ' + rm -f blobs && + echo "A blob from _before_ the commit." >expect && + mkfifo blobs && + ( + exec 3<blobs && + cat <<-EOF && + feature cat-blob + blob + mark :1 + data <<BLOB + A blob from _before_ the commit. + BLOB + commit refs/heads/temporary + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + Empty commit + COMMIT + cat-blob :1 + EOF + + read blob_id type size <&3 && + head_c $size >actual <&3 && + read newline <&3 && + + echo + ) | + git fast-import --cat-blob-fd=3 3>blobs && + test_cmp expect actual +' + +test_expect_success PIPE 'R: print staged blob within commit' ' + rm -f blobs && + echo "A blob from _within_ the commit." >expect && + mkfifo blobs && + ( + exec 3<blobs && + cat <<-EOF && + feature cat-blob + commit refs/heads/within + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + Empty commit + COMMIT + M 644 inline within + data <<BLOB + A blob from _within_ the commit. + BLOB + EOF + + to_get=$( + echo "A blob from _within_ the commit." | + git hash-object --stdin + ) && + echo "cat-blob $to_get" && + + read blob_id type size <&3 && + head_c $size >actual <&3 && + read newline <&3 && + + echo deleteall + ) | + git fast-import --cat-blob-fd=3 3>blobs && + test_cmp expect actual +' + cat >input << EOF option git quiet blob @@ -1748,8 +2019,6 @@ hi EOF -touch empty - test_expect_success 'R: quiet option results in no stats being output' ' cat input | git fast-import 2> output && test_cmp empty output @@ -1767,6 +2036,14 @@ test_expect_success 'R: unknown commandline options are rejected' '\ test_must_fail git fast-import --non-existing-option < /dev/null ' +test_expect_success 'R: die on invalid option argument' ' + echo "option git active-branches=-5" | + test_must_fail git fast-import && + echo "option git depth=" | + test_must_fail git fast-import && + test_must_fail git fast-import --depth="5 elephants" </dev/null +' + cat >input <<EOF option non-existing-vcs non-existing-option EOF diff --git a/test-treap.c b/test-treap.c index cdba5111e1..ab8c951c6e 100644 --- a/test-treap.c +++ b/test-treap.c @@ -38,9 +38,14 @@ int main(int argc, char *argv[]) usage("test-treap < ints"); while (strbuf_getline(&sb, stdin, '\n') != EOF) { - item = node_alloc(1); - strtonode(node_pointer(item), sb.buf); - treap_insert(&root, node_pointer(item)); + struct int_node *node = node_pointer(node_alloc(1)); + + item = node_offset(node); + strtonode(node, sb.buf); + node = treap_insert(&root, node_pointer(item)); + if (node_offset(node) != item) + die("inserted %"PRIu32" in place of %"PRIu32"", + node_offset(node), item); } item = node_offset(treap_first(&root)); @@ -25,10 +25,6 @@ #include "cache.h" #include "quote.h" -void do_nothing(size_t unused) -{ -} - /* Get a trace file descriptor from GIT_TRACE env variable. */ static int get_trace_fd(int *need_close) { @@ -76,7 +72,7 @@ void trace_printf(const char *fmt, ...) if (!fd) return; - set_try_to_free_routine(do_nothing); /* is never reset */ + set_try_to_free_routine(NULL); /* is never reset */ strbuf_init(&buf, 64); va_start(ap, fmt); len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap); @@ -108,7 +104,7 @@ void trace_argv_printf(const char **argv, const char *fmt, ...) if (!fd) return; - set_try_to_free_routine(do_nothing); /* is never reset */ + set_try_to_free_routine(NULL); /* is never reset */ strbuf_init(&buf, 64); va_start(ap, fmt); len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap); @@ -125,3 +125,17 @@ char *url_decode_parameter_value(const char **query) struct strbuf out = STRBUF_INIT; return url_decode_internal(query, "&", &out, 1); } + +void end_url_with_slash(struct strbuf *buf, const char *url) +{ + strbuf_addstr(buf, url); + if (buf->len && buf->buf[buf->len - 1] != '/') + strbuf_addstr(buf, "/"); +} + +void str_end_url_with_slash(const char *url, char **dest) { + struct strbuf buf = STRBUF_INIT; + end_url_with_slash(&buf, url); + free(*dest); + *dest = strbuf_detach(&buf, NULL); +} @@ -7,4 +7,7 @@ extern char *url_decode(const char *url); extern char *url_decode_parameter_name(const char **query); extern char *url_decode_parameter_value(const char **query); +extern void end_url_with_slash(struct strbuf *buf, const char *url); +extern void str_end_url_with_slash(const char *url, char **dest); + #endif /* URL_H */ diff --git a/userdiff.c b/userdiff.c index f9e05b548c..2d5453697a 100644 --- a/userdiff.c +++ b/userdiff.c @@ -74,14 +74,14 @@ PATTERNS("python", "^[ \t]*((class|def)[ \t].*)$", "[a-zA-Z_][a-zA-Z0-9_]*" "|[-+0-9.e]+[jJlL]?|0[xX]?[0-9a-fA-F]+[lL]?" "|[-+*/<>%&^|=!]=|//=?|<<=?|>>=?|\\*\\*=?" - "|[^[:space:]|[\x80-\xff]+"), + "|[^[:space:]]|[\x80-\xff]+"), /* -- */ PATTERNS("ruby", "^[ \t]*((class|module|def)[ \t].*)$", /* -- */ "(@|@@|\\$)?[a-zA-Z_][a-zA-Z0-9_]*" "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+|\\?(\\\\C-)?(\\\\M-)?." "|//=?|[-+*/<>%&^|=!]=|<<=?|>>=?|===|\\.{1,3}|::|[!=]~" - "|[^[:space:]|[\x80-\xff]+"), + "|[^[:space:]]|[\x80-\xff]+"), PATTERNS("bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$", "[={}\"]|[^={}\" \t]+"), PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$", diff --git a/vcs-svn/repo_tree.c b/vcs-svn/repo_tree.c index e94d91d129..e3d1fa3544 100644 --- a/vcs-svn/repo_tree.c +++ b/vcs-svn/repo_tree.c @@ -131,7 +131,7 @@ static void repo_write_dirent(uint32_t *path, uint32_t mode, if (dent == key) { dent->mode = REPO_MODE_DIR; dent->content_offset = 0; - dent_insert(&dir->entries, dent); + dent = dent_insert(&dir->entries, dent); } if (dent_offset(dent) < dent_pool.committed) { @@ -142,7 +142,7 @@ static void repo_write_dirent(uint32_t *path, uint32_t mode, dent->name_offset = name; dent->mode = REPO_MODE_DIR; dent->content_offset = dir_o; - dent_insert(&dir->entries, dent); + dent = dent_insert(&dir->entries, dent); } dir = repo_dir_from_dirent(dent); diff --git a/vcs-svn/trp.h b/vcs-svn/trp.h index ee35c688a0..c32b9184e9 100644 --- a/vcs-svn/trp.h +++ b/vcs-svn/trp.h @@ -188,11 +188,12 @@ a_attr uint32_t MAYBE_UNUSED a_pre##insert_recurse(uint32_t cur_node, uint32_t i return ret; \ } \ } \ -a_attr void MAYBE_UNUSED a_pre##insert(struct trp_root *treap, a_type *node) \ +a_attr a_type *MAYBE_UNUSED a_pre##insert(struct trp_root *treap, a_type *node) \ { \ uint32_t offset = trpn_offset(a_base, node); \ trp_node_new(a_base, a_field, offset); \ treap->trp_root = a_pre##insert_recurse(treap->trp_root, offset); \ + return trpn_pointer(a_base, offset); \ } \ a_attr uint32_t MAYBE_UNUSED a_pre##remove_recurse(uint32_t cur_node, uint32_t rem_node) \ { \ diff --git a/vcs-svn/trp.txt b/vcs-svn/trp.txt index eb4c191875..5ca6b42edb 100644 --- a/vcs-svn/trp.txt +++ b/vcs-svn/trp.txt @@ -21,7 +21,9 @@ The caller: . Allocates a `struct trp_root` variable and sets it to {~0}. -. Adds new nodes to the set using `foo_insert`. +. Adds new nodes to the set using `foo_insert`. Any pointers + to existing nodes cannot be relied upon any more, so the caller + might retrieve them anew with `foo_pointer`. . Can find a specific item in the set using `foo_search`. @@ -73,10 +75,14 @@ int (*cmp)(node_type \*a, node_type \*b) and returning a value less than, equal to, or greater than zero according to the result of comparison. -void foo_insert(struct trp_root *treap, node_type \*node):: +node_type {asterisk}foo_insert(struct trp_root *treap, node_type \*node):: Insert node into treap. If inserted multiple times, a node will appear in the treap multiple times. ++ +The return value is the address of the node within the treap, +which might differ from `node` if `pool_alloc` had to call +`realloc` to expand the pool. void foo_remove(struct trp_root *treap, node_type \*node):: @@ -12,6 +12,8 @@ static void (*try_to_free_routine)(size_t size) = do_nothing; try_to_free_t set_try_to_free_routine(try_to_free_t routine) { try_to_free_t old = try_to_free_routine; + if (!routine) + routine = do_nothing; try_to_free_routine = routine; return old; } @@ -56,6 +56,16 @@ unsigned parse_whitespace_rule(const char *string) rule |= whitespace_rule_names[i].rule_bits; break; } + if (strncmp(string, "tabwidth=", 9) == 0) { + unsigned tabwidth = atoi(string + 9); + if (0 < tabwidth && tabwidth < 0100) { + rule &= ~WS_TAB_WIDTH_MASK; + rule |= tabwidth; + } + else + warning("tabwidth %.*s out of range", + (int)(len - 9), string + 9); + } string = ep; } @@ -84,7 +94,7 @@ unsigned whitespace_rule(const char *pathname) value = attr_whitespace_rule.value; if (ATTR_TRUE(value)) { /* true (whitespace) */ - unsigned all_rule = 0; + unsigned all_rule = ws_tab_width(whitespace_rule_cfg); int i; for (i = 0; i < ARRAY_SIZE(whitespace_rule_names); i++) if (!whitespace_rule_names[i].loosens_error && @@ -93,7 +103,7 @@ unsigned whitespace_rule(const char *pathname) return all_rule; } else if (ATTR_FALSE(value)) { /* false (-whitespace) */ - return 0; + return ws_tab_width(whitespace_rule_cfg); } else if (ATTR_UNSET(value)) { /* reset to default (!whitespace) */ return whitespace_rule_cfg; @@ -206,7 +216,7 @@ static unsigned ws_check_emit_1(const char *line, int len, unsigned ws_rule, } /* Check for indent using non-tab. */ - if ((ws_rule & WS_INDENT_WITH_NON_TAB) && i - written >= 8) { + if ((ws_rule & WS_INDENT_WITH_NON_TAB) && i - written >= ws_tab_width(ws_rule)) { result |= WS_INDENT_WITH_NON_TAB; if (stream) { fputs(ws, stream); @@ -320,7 +330,7 @@ void ws_fix_copy(struct strbuf *dst, const char *src, int len, unsigned ws_rule, } else if (ch == ' ') { last_space_in_indent = i; if ((ws_rule & WS_INDENT_WITH_NON_TAB) && - 8 <= i - last_tab_in_indent) + ws_tab_width(ws_rule) <= i - last_tab_in_indent) need_fix_leading_space = 1; } else break; @@ -350,7 +360,7 @@ void ws_fix_copy(struct strbuf *dst, const char *src, int len, unsigned ws_rule, strbuf_addch(dst, ch); } else { consecutive_spaces++; - if (consecutive_spaces == 8) { + if (consecutive_spaces == ws_tab_width(ws_rule)) { strbuf_addch(dst, '\t'); consecutive_spaces = 0; } @@ -363,12 +373,13 @@ void ws_fix_copy(struct strbuf *dst, const char *src, int len, unsigned ws_rule, fixed = 1; } else if ((ws_rule & WS_TAB_IN_INDENT) && last_tab_in_indent >= 0) { /* Expand tabs into spaces */ + int start = dst->len; int last = last_tab_in_indent + 1; for (i = 0; i < last; i++) { if (src[i] == '\t') do { strbuf_addch(dst, ' '); - } while (dst->len % 8); + } while ((dst->len - start) % ws_tab_width(ws_rule)); else strbuf_addch(dst, src[i]); } diff --git a/wt-status.c b/wt-status.c index 06ae161c67..123582b6cb 100644 --- a/wt-status.c +++ b/wt-status.c @@ -21,11 +21,15 @@ static char default_wt_status_colors[][COLOR_MAXLEN] = { GIT_COLOR_RED, /* WT_STATUS_UNMERGED */ GIT_COLOR_GREEN, /* WT_STATUS_LOCAL_BRANCH */ GIT_COLOR_RED, /* WT_STATUS_REMOTE_BRANCH */ + GIT_COLOR_NIL, /* WT_STATUS_ONBRANCH */ }; static const char *color(int slot, struct wt_status *s) { - return s->use_color > 0 ? s->color_palette[slot] : ""; + const char *c = s->use_color > 0 ? s->color_palette[slot] : ""; + if (slot == WT_STATUS_ONBRANCH && color_is_nil(c)) + c = s->color_palette[WT_STATUS_HEADER]; + return c; } void wt_status_prepare(struct wt_status *s) @@ -625,7 +629,8 @@ static void wt_status_print_tracking(struct wt_status *s) void wt_status_print(struct wt_status *s) { - const char *branch_color = color(WT_STATUS_HEADER, s); + const char *branch_color = color(WT_STATUS_ONBRANCH, s); + const char *branch_status_color = color(WT_STATUS_HEADER, s); if (s->branch) { const char *on_what = "On branch "; @@ -634,11 +639,12 @@ void wt_status_print(struct wt_status *s) branch_name += 11; else if (!strcmp(branch_name, "HEAD")) { branch_name = ""; - branch_color = color(WT_STATUS_NOBRANCH, s); + branch_status_color = color(WT_STATUS_NOBRANCH, s); on_what = "Not currently on any branch."; } color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "# "); - color_fprintf_ln(s->fp, branch_color, "%s%s", on_what, branch_name); + color_fprintf(s->fp, branch_status_color, "%s", on_what); + color_fprintf_ln(s->fp, branch_color, "%s", branch_name); if (!s->is_initial) wt_status_print_tracking(s); } diff --git a/wt-status.h b/wt-status.h index 9df9c9fad2..20b17cf439 100644 --- a/wt-status.h +++ b/wt-status.h @@ -13,7 +13,9 @@ enum color_wt_status { WT_STATUS_NOBRANCH, WT_STATUS_UNMERGED, WT_STATUS_LOCAL_BRANCH, - WT_STATUS_REMOTE_BRANCH + WT_STATUS_REMOTE_BRANCH, + WT_STATUS_ONBRANCH, + WT_STATUS_MAXSLOT }; enum untracked_status_type { @@ -46,7 +48,7 @@ struct wt_status { int show_ignored_files; enum untracked_status_type show_untracked_files; const char *ignore_submodule_arg; - char color_palette[WT_STATUS_REMOTE_BRANCH+1][COLOR_MAXLEN]; + char color_palette[WT_STATUS_MAXSLOT][COLOR_MAXLEN]; /* These are computed during processing of the individual sections */ int commitable; |