diff options
333 files changed, 7017 insertions, 3684 deletions
diff --git a/.gitignore b/.gitignore index a213e8e25b..bbaf9de0bc 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,7 @@ git-gc git-get-tar-commit-id git-grep git-hash-object +git-help git-http-fetch git-http-push git-imap-send diff --git a/Documentation/Makefile b/Documentation/Makefile index 62269e39c4..ded0e40b97 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -44,6 +44,7 @@ MANPAGE_XSL = callouts.xsl INSTALL?=install RM ?= rm -f DOC_REF = origin/man +HTML_REF = origin/html infodir?=$(prefix)/share/info MAKEINFO=makeinfo @@ -222,4 +223,7 @@ install-webdoc : html quick-install: sh ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir) +quick-install-html: + sh ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir) + .PHONY: .FORCE-GIT-VERSION-FILE diff --git a/Documentation/RelNotes-1.6.0.1.txt b/Documentation/RelNotes-1.6.0.1.txt index bac117e89d..49d7a1cafa 100644 --- a/Documentation/RelNotes-1.6.0.1.txt +++ b/Documentation/RelNotes-1.6.0.1.txt @@ -4,6 +4,9 @@ GIT v1.6.0.1 Release Notes Fixes since v1.6.0 ------------------ +* "git diff --cc" did not honor content mangling specified by + gitattributes and core.autocrlf when reading from the work tree. + * "git diff --check" incorrectly detected new trailing blank lines when whitespace check was in effect. @@ -13,6 +16,8 @@ Fixes since v1.6.0 * "git format-patch" peeked before the beginning of a string when "format.headers" variable is empty (a misconfiguration). +* "git help help" did not work correctly. + * "git mailinfo" (hence "git am") was unhappy when MIME multipart message contained garbage after the finishing boundary. @@ -22,10 +27,10 @@ Fixes since v1.6.0 * "git merge" did not refresh the index correctly when a merge resulted in a fast-forward. -Contains other various documentation fixes. +* "git merge" did not resolve a truly trivial merges that can be done + without content level merges. --- -exec >/var/tmp/1 -O=v1.6.0-14-g3a634dc -echo O=$(git describe maint) -git shortlog --no-merges $O..maint +* "git svn dcommit" to a repository with URL that has embedded usernames + did not work correctly. + +Contains other various documentation fixes. diff --git a/Documentation/RelNotes-1.6.0.2.txt b/Documentation/RelNotes-1.6.0.2.txt new file mode 100644 index 0000000000..7a9646fc4f --- /dev/null +++ b/Documentation/RelNotes-1.6.0.2.txt @@ -0,0 +1,87 @@ +GIT v1.6.0.2 Release Notes +========================== + +Fixes since v1.6.0.1 +-------------------- + +* Installation on platforms that needs .exe suffix to git-* programs were + broken in 1.6.0.1. + +* Installation on filesystems without symbolic links support did nto + work well. + +* In-tree documentations and test scripts now use "git foo" form to set a + better example, instead of the "git-foo" form (which is an acceptable + form if you have "PATH=$(git --exec-path):$PATH" in your script) + +* Many commands did not use the correct working tree location when used + with GIT_WORK_TREE environment settings. + +* Some systems needs to use compatibility fnmach and regex libraries + independent from each other; the compat/ area has been reorganized to + allow this. + + +* "git apply --unidiff-zero" incorrectly applied a -U0 patch that inserts + a new line before the second line. + +* "git blame -c" did not exactly work like "git annotate" when range + boundaries are involved. + +* "git checkout file" when file is still unmerged checked out contents from + a random high order stage, which was confusing. + +* "git clone $there $here/" with extra trailing slashes after explicit + local directory name $here did not work as expected. + +* "git diff" on tracked contents with CRLF line endings did not drive "less" + intelligently when showing added or removed lines. + +* "git diff --dirstat -M" did not add changes in subdirectories up + correctly for renamed paths. + +* "git diff --cumulative" did not imply "--dirstat". + +* "git for-each-ref refs/heads/" did not work as expected. + +* "git gui" allowed users to feed patch without any context to be applied. + +* "git gui" botched parsing "diff" output when a line that begins with two + dashes and a space gets removed or a line that begins with two pluses + and a space gets added. + +* "git gui" translation updates and i18n fixes. + +* "git index-pack" is more careful against disk corruption while completing + a thin pack. + +* "git log -i --grep=pattern" did not ignore case; neither "git log -E + --grep=pattern" triggered extended regexp. + +* "git log --pretty="%ad" --date=short" did not use short format when + showing the timestamp. + +* "git log --author=author" match incorrectly matched with the + timestamp part of "author " line in commit objects. + +* "git log -F --author=author" did not work at all. + +* Build procedure for "git shell" that used stub versions of some + functions and globals was not understood by linkers on some platforms. + +* "git stash" was fooled by a stat-dirty but otherwise unmodified paths + and refused to work until the user refreshed the index. + +* "git svn" was broken on Perl before 5.8 with recent fixes to reduce + use of temporary files. + +* "git verify-pack -v" did not work correctly when given more than one + packfile. + +Also contains many documentation updates. + +-- +exec >/var/tmp/1 +O=v1.6.0.1-78-g3632cfc +echo O=$(git describe maint) +git shortlog --no-merges $O..maint diff --git a/Documentation/RelNotes-1.6.1.txt b/Documentation/RelNotes-1.6.1.txt new file mode 100644 index 0000000000..609d4ca562 --- /dev/null +++ b/Documentation/RelNotes-1.6.1.txt @@ -0,0 +1,120 @@ +GIT v1.6.1 Release Notes +======================== + +Updates since v1.6.0 +-------------------- + +When some commands (e.g. "git log", "git diff") spawn pager internally, we +used to make the pager the parent process of the git command that produces +output. This meant that the exit status of the whole thing comes from the +pager, not the underlying git command. We swapped the order of the +processes around and you will see the exit code from the command from now +on. + +(subsystems) + +* gitk can call out to git-gui to view "git blame" output; git-gui in turn + can run gitk from its blame view. + +(portability) + +* ... + +(documentation) + +* ... + +(performance) + +* The underlying diff machinery to produce textual output has been + optimized, which would result in faster "git blame" processing. + +* Most of the test scripts (but not the ones that try to run servers) + can be run in parallel. + +(usability, bells and whistles) + +* "git checkout --track origin/hack" used to be a syntax error. It now + DWIMs to create a corresponding local branch "hack", i.e. acts as if you + said "git checkout --track -b hack origin/hack". + +* "git cherry-pick" can also utilize rerere for conflict resolution. + +* "git commit --author=$name" can look up author name from existing + commits. + +* "git count-objects" reports the on-disk footprint for packfiles and + their corresponding idx files. + +* "git daemon" learned --max-connections=<count> option. + +* "git diff" learned to mimick --suppress-blank-empty from GNU diff via a + configuration option. + +* "git diff" learned to put more sensible hunk headers for Python and + HTML contents. + +* "git help" learned to use GIT_MAN_VIEWER environment variable before + using "man" program. + +* "git imap-send" can optionally talk SSL. + +* "git index-pack" is more careful against disk corruption while + completing a thin pack. + +* "git log --check" and "git log --exit-code" passes their underlying diff + status with their exit status code. + +* "git log" learned --simplify-merges, a milder variant of --full-history; + "gitk --simplify-merges" is easier to view than with --full-history. + +* "git merge --squash" and "git merge --no-ff" into an unborn branch are + noticed as user errors. + +* "git merge -s $strategy" can use a custom built strategy if you have a + command "git-merge-$strategy" on your $PATH. + +* "git reflog expire branch" can be used in place of "git reflog expire + refs/heads/branch". + +* "git submodule foreach" subcommand allows you to iterate over checked + out submodules. + +* "git submodule sync" subcommands allows you to update the origin URL + recorded in submodule directories from the toplevel .gitmodules file. + +(internal) + +* "git hash-object" learned to lie about the path being hashed, so that + correct gitattributes processing can be done while hashing contents + stored in a temporary file. + +Fixes since v1.6.0 +------------------ + +All of the fixes in v1.6.0.X maintenance series are included in this +release, unless otherwise noted. + +* "git add" and "git update-index" incorrectly allowed adding S/F when S + is a tracked symlink that points at a directory D that has a path F in + it (we still need to fix a similar nonsense when S is a submodule and F + is a path in it). + +* "git diff --stdin" used to take two trees on a line and compared them, + but we droppped support for such a use case long time ago. This has + been resurrected. + +* "git filter-branch" failed to rewrite a tag name with slashes in it. + +* "git push --tags --all $there" failed with generic usage message without + telling saying these two options are incompatible. + +* "git log --author/--committer" match used to potentially match the + timestamp part, exposing internal implementation detail. Also these did + not work with --fixed-strings match at all. + +-- +exec >/var/tmp/1 +O=v1.6.0.1-266-gaf9552f +echo O=$(git describe master) +git shortlog --no-merges $O..master ^maint diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches index 841bead9db..a1e9100f9e 100644 --- a/Documentation/SubmittingPatches +++ b/Documentation/SubmittingPatches @@ -71,7 +71,7 @@ run git diff --check on your changes before you commit. (1a) Try to be nice to older C compilers -We try to support wide range of C compilers to compile +We try to support a wide range of C compilers to compile git with. That means that you should not use C99 initializers, even if a lot of compilers grok it. diff --git a/Documentation/config.txt b/Documentation/config.txt index 676c39bb84..922ac7b44d 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -358,8 +358,13 @@ core.editor:: `EDITOR` environment variables and then finally `vi`. core.pager:: - The command that git will use to paginate output. Can be overridden - with the `GIT_PAGER` environment variable. + The command that git will use to paginate output. Can + be overridden with the `GIT_PAGER` environment + variable. Note that git sets the `LESS` environment + variable to `FRSX` if it is unset when it runs the + pager. One can change these settings by setting the + `LESS` variable to some other value or by giving the + `core.pager` option a value such as "`less -+FRSX`". core.whitespace:: A comma separated list of common whitespace problems to @@ -567,6 +572,10 @@ diff.autorefreshindex:: affects only 'git-diff' Porcelain, and not lower level 'diff' commands, such as 'git-diff-files'. +diff.suppress-blank-empty:: + A boolean to inhibit the standard behavior of printing a space + before each empty output line. Defaults to false. + diff.external:: If this config variable is set, diff generation is not performed using the internal diff machinery, but using the @@ -688,7 +697,7 @@ gitcvs.logfile:: Path to a log file where the CVS server interface well... logs various stuff. See linkgit:git-cvsserver[1]. -gitcvs.usecrlfattr +gitcvs.usecrlfattr:: If true, the server will look up the `crlf` attribute for files to determine the '-k' modes to use. If `crlf` is set, the '-k' mode will be left blank, so cvs clients will @@ -781,6 +790,15 @@ help.format:: Values 'man', 'info', 'web' and 'html' are supported. 'man' is the default. 'web' and 'html' are the same. +help.autocorrect:: + Automatically correct and execute mistyped commands after + waiting for the given number of deciseconds (0.1 sec). If more + than one command can be deduced from the entered text, nothing + will be executed. If the value of this option is negative, + the corrected command will be executed immediately. If the + value is 0 - the command will be just shown but not executed. + This is the default. + http.proxy:: Override the HTTP proxy, normally configured using the 'http_proxy' environment variable (see linkgit:curl[1]). This can be overridden @@ -979,9 +997,11 @@ pack.packSizeLimit:: linkgit:git-repack[1]. pager.<cmd>:: - Allows to set your own pager preferences for each command, overriding - the default. If `\--pager` or `\--no-pager` is specified on the command - line, it takes precedence over this option. + Allows turning on or off pagination of the output of a + particular git subcommand when writing to a tty. If + `\--paginate` or `\--no-pager` is specified on the command line, + it takes precedence over this option. To disable pagination for + all commands, set `core.pager` or 'GIT_PAGER' to "`cat`". pull.octopus:: The default merge strategy to use when pulling multiple branches diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index cba90fd27c..6e268326da 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -59,12 +59,11 @@ endif::git-format-patch[] lines. --dirstat[=limit]:: - Output only the sub-directories that are impacted by a diff, - and to what degree they are impacted. You can override the - default cut-off in percent (3) by "--dirstat=limit". If you - want to enable "cumulative" directory statistics, you can use - the "--cumulative" flag, which adds up percentages recursively - even when they have been already reported for a sub-directory. + Output the distribution of relative amount of changes (number of lines added or + removed) for each sub-directory. Directories with changes below + a cut-off percent (3% by default) are not shown. The cut-off percent + can be set with "--dirstat=limit". Changes in a child directory is not + counted for the parent directory, unless "--cumulative" is used. --summary:: Output a condensed summary of extended header information @@ -107,9 +106,9 @@ endif::git-format-patch[] --exit-code. --full-index:: - Instead of the first handful characters, show full - object name of pre- and post-image blob on the "index" - line when generating a patch format output. + Instead of the first handful of characters, show the full + pre- and post-image blob object names on the "index" + line when generating patch format output. --binary:: In addition to --full-index, output "binary diff" that diff --git a/Documentation/git-annotate.txt b/Documentation/git-annotate.txt index 8b6b56a544..0aba022ba6 100644 --- a/Documentation/git-annotate.txt +++ b/Documentation/git-annotate.txt @@ -14,6 +14,11 @@ DESCRIPTION Annotates each line in the given file with information from the commit which introduced the line. Optionally annotate from a given revision. +The only difference between this command and linkgit:git-blame[1] is that +they use slightly different output formats, and this command exists only +for backward compatibility to support existing scripts, and provide more +familiar command name for people coming from other SCM systems. + OPTIONS ------- include::blame-options.txt[] diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt index 5aa69c0e12..be54a0299f 100644 --- a/Documentation/git-checkout.txt +++ b/Documentation/git-checkout.txt @@ -8,7 +8,7 @@ git-checkout - Checkout a branch or paths to the working tree SYNOPSIS -------- [verse] -'git checkout' [-q] [-f] [[--track | --no-track] -b <new_branch> [-l]] [-m] [<branch>] +'git checkout' [-q] [-f] [--track | --no-track] [-b <new_branch> [-l]] [-m] [<branch>] 'git checkout' [<tree-ish>] [--] <paths>... DESCRIPTION @@ -21,6 +21,10 @@ specified, <new_branch>. Using -b will cause <new_branch> to be created; in this case you can use the --track or --no-track options, which will be passed to `git branch`. +As a convenience, --track will default to create a branch whose +name is constructed from the specified branch name by stripping +the first namespace level. + When <paths> are given, this command does *not* switch branches. It updates the named paths in the working tree from the index file (i.e. it runs `git checkout-index -f -u`), or @@ -59,6 +63,17 @@ OPTIONS 'git-checkout' and 'git-branch' to always behave as if '--no-track' were given. Set it to `always` if you want this behavior when the start-point is either a local or remote branch. ++ +If no '-b' option was given, the name of the new branch will be +derived from the remote branch, by attempting to guess the name +of the branch on remote system. If "remotes/" or "refs/remotes/" +are prefixed, it is stripped away, and then the part up to the +next slash (which would be the nickname of the remote) is removed. +This would tell us to use "hack" as the local branch when branching +off of "origin/hack" (or "remotes/origin/hack", or even +"refs/remotes/origin/hack"). If the given name has no slash, or the above +guessing results in an empty name, the guessing is aborted. You can +exlicitly give a name with '-b' in such a case. --no-track:: Ignore the branch.autosetupmerge configuration variable. diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt index 92ab3ab4a8..b8834baced 100644 --- a/Documentation/git-commit-tree.txt +++ b/Documentation/git-commit-tree.txt @@ -79,9 +79,9 @@ Diagnostics You don't exist. Go away!:: The passwd(5) gecos field couldn't be read Your parents must have hated you!:: - The password(5) gecos field is longer than a giant static buffer. + The passwd(5) gecos field is longer than a giant static buffer. Your sysadmin must hate you!:: - The password(5) name field is longer than a giant static buffer. + The passwd(5) name field is longer than a giant static buffer. Discussion ---------- diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt index 0e25bb8627..eb05b0f49b 100644 --- a/Documentation/git-commit.txt +++ b/Documentation/git-commit.txt @@ -75,8 +75,10 @@ OPTIONS read the message from the standard input. --author=<author>:: - Override the author name used in the commit. Use - `A U Thor <author@example.com>` format. + Override the author name used in the commit. You can use the + standard `A U Thor <author@example.com>` format. Otherwise, + an existing commit that matches the given string and its author + name is used. -m <msg>:: --message=<msg>:: diff --git a/Documentation/git-count-objects.txt b/Documentation/git-count-objects.txt index 75a8da1ca9..6bc1c21e62 100644 --- a/Documentation/git-count-objects.txt +++ b/Documentation/git-count-objects.txt @@ -21,8 +21,9 @@ OPTIONS --verbose:: In addition to the number of loose objects and disk space consumed, it reports the number of in-pack - objects, number of packs, and number of objects that can be - removed by running `git prune-packed`. + objects, number of packs, disk space consumed by those packs, + and number of objects that can be removed by running + `git prune-packed`. Author diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt index 4ba4b75c11..b08a08cd95 100644 --- a/Documentation/git-daemon.txt +++ b/Documentation/git-daemon.txt @@ -9,8 +9,9 @@ SYNOPSIS -------- [verse] 'git daemon' [--verbose] [--syslog] [--export-all] - [--timeout=n] [--init-timeout=n] [--strict-paths] - [--base-path=path] [--user-path | --user-path=path] + [--timeout=n] [--init-timeout=n] [--max-connections=n] + [--strict-paths] [--base-path=path] [--base-path-relaxed] + [--user-path | --user-path=path] [--interpolated-path=pathtemplate] [--reuseaddr] [--detach] [--pid-file=file] [--enable=service] [--disable=service] @@ -99,6 +100,10 @@ OPTIONS it takes for the server to process the sub-request and time spent waiting for next client's request. +--max-connections:: + Maximum number of concurrent clients, defaults to 32. Set it to + zero for no limit. + --syslog:: Log to syslog instead of stderr. Note that this option does not imply --verbose, thus by default only error conditions will be logged. diff --git a/Documentation/git-diff-tree.txt b/Documentation/git-diff-tree.txt index 1fdf20dcc9..5d48664e62 100644 --- a/Documentation/git-diff-tree.txt +++ b/Documentation/git-diff-tree.txt @@ -49,13 +49,22 @@ include::diff-options.txt[] --stdin:: When '--stdin' is specified, the command does not take <tree-ish> arguments from the command line. Instead, it - reads either one <commit> or a list of <commit> - separated with a single space from its standard input. + reads lines containing either two <tree>, one <commit>, or a + list of <commit> from its standard input. (Use a single space + as separator.) + -When a single commit is given on one line of such input, it compares -the commit with its parents. The following flags further affects its -behavior. The remaining commits, when given, are used as if they are +When two trees are given, it compares the first tree with the second. +When a single commit is given, it compares the commit with its +parents. The remaining commits, when given, are used as if they are parents of the first commit. ++ +When comparing two trees, the ID of both trees (separated by a space +and terminated by a newline) is printed before the difference. When +comparing commits, the ID of the first (or only) commit, followed by a +newline, is printed. ++ +The following flags further affects the behavior when comparing +commits (but not trees). -m:: By default, 'git-diff-tree --stdin' does not show diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt index eae6c0e7bc..ebd7c5fbb3 100644 --- a/Documentation/git-for-each-ref.txt +++ b/Documentation/git-for-each-ref.txt @@ -16,7 +16,7 @@ DESCRIPTION Iterate over all refs that match `<pattern>` and show them according to the given `<format>`, after sorting them according -to the given set of `<key>`. If `<max>` is given, stop after +to the given set of `<key>`. If `<count>` is given, stop after showing that many refs. The interpolated values in `<format>` can optionally be quoted as string literals in the specified host language allowing their direct evaluation in that language. diff --git a/Documentation/git-hash-object.txt b/Documentation/git-hash-object.txt index ac928e198e..0af40cfb85 100644 --- a/Documentation/git-hash-object.txt +++ b/Documentation/git-hash-object.txt @@ -8,7 +8,9 @@ git-hash-object - Compute object ID and optionally creates a blob from a file SYNOPSIS -------- -'git hash-object' [-t <type>] [-w] [--stdin | --stdin-paths] [--] <file>... +[verse] +'git hash-object' [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>... +'git hash-object' [-t <type>] [-w] --stdin-paths < <list-of-paths> DESCRIPTION ----------- @@ -35,6 +37,22 @@ OPTIONS --stdin-paths:: Read file names from stdin instead of from the command-line. +--path:: + Hash object as it were located at the given path. The location of + file does not directly influence on the hash value, but path is + used to determine what git filters should be applied to the object + before it can be placed to the object database, and, as result of + applying filters, the actual blob put into the object database may + differ from the given file. This option is mainly useful for hashing + temporary files located outside of the working directory or files + read from stdin. + +--no-filters:: + Hash the contents as is, ignoring any input filter that would + have been chosen by the attributes mechanism, including crlf + conversion. If the file is read from standard input then this + is always implied, unless the --path option is given. + Author ------ Written by Junio C Hamano <gitster@pobox.com> diff --git a/Documentation/git-help.txt b/Documentation/git-help.txt index f414583fc4..d9b9c34b3a 100644 --- a/Documentation/git-help.txt +++ b/Documentation/git-help.txt @@ -112,7 +112,9 @@ For example, this configuration: will try to use konqueror first. But this may fail (for example if DISPLAY is not set) and in that case emacs' woman mode will be tried. -If everything fails the 'man' program will be tried anyway. +If everything fails, or if no viewer is configured, the viewer specified +in the GIT_MAN_VIEWER environment variable will be tried. If that +fails too, the 'man' program will be tried anyway. man.<tool>.path ~~~~~~~~~~~~~~~ diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt index b3d8da33ee..bd49a0aee8 100644 --- a/Documentation/git-imap-send.txt +++ b/Documentation/git-imap-send.txt @@ -3,7 +3,7 @@ git-imap-send(1) NAME ---- -git-imap-send - Dump a mailbox from stdin into an imap folder +git-imap-send - Send a collection of patches from stdin to an IMAP folder SYNOPSIS @@ -13,9 +13,9 @@ SYNOPSIS DESCRIPTION ----------- -This command uploads a mailbox generated with git-format-patch -into an imap drafts folder. This allows patches to be sent as -other email is sent with mail clients that cannot read mailbox +This command uploads a mailbox generated with 'git-format-patch' +into an IMAP drafts folder. This allows patches to be sent as +other email is when using mail clients that cannot read mailbox files directly. Typical usage is something like: @@ -26,21 +26,75 @@ git format-patch --signoff --stdout --attach origin | git imap-send CONFIGURATION ------------- -'git-imap-send' requires the following values in the repository -configuration file (shown with examples): +To use the tool, imap.folder and either imap.tunnel or imap.host must be set +to appropriate values. + +Variables +~~~~~~~~~ + +imap.folder:: + The folder to drop the mails into, which is typically the Drafts + folder. For example: "INBOX.Drafts", "INBOX/Drafts" or + "[Gmail]/Drafts". Required to use imap-send. + +imap.tunnel:: + Command used to setup a tunnel to the IMAP server through which + commands will be piped instead of using a direct network connection + to the server. Required when imap.host is not set to use imap-send. + +imap.host:: + A URL identifying the server. Use a `imap://` prefix for non-secure + connections and a `imaps://` prefix for secure connections. + Ignored when imap.tunnel is set, but required to use imap-send + otherwise. + +imap.user:: + The username to use when logging in to the server. + +imap.password:: + The password to use when logging in to the server. + +imap.port:: + An integer port number to connect to on the server. + Defaults to 143 for imap:// hosts and 993 for imaps:// hosts. + Ignored when imap.tunnel is set. + +imap.sslverify:: + A boolean to enable/disable verification of the server certificate + used by the SSL/TLS connection. Default is `true`. Ignored when + imap.tunnel is set. + +Examples +~~~~~~~~ + +Using tunnel mode: .......................... [imap] - Folder = "INBOX.Drafts" + folder = "INBOX.Drafts" + tunnel = "ssh -q -C user@example.com /usr/bin/imapd ./Maildir 2> /dev/null" +.......................... +Using direct mode: + +......................... [imap] - Tunnel = "ssh -q user@server.com /usr/bin/imapd ./Maildir 2> /dev/null" + folder = "INBOX.Drafts" + host = imap://imap.example.com + user = bob + pass = p4ssw0rd +.......................... + +Using direct mode with SSL: +......................... [imap] - Host = imap.server.com - User = bob - Pass = pwd - Port = 143 + folder = "INBOX.Drafts" + host = imaps://imap.example.com + user = bob + pass = p4ssw0rd + port = 123 + sslverify = false .......................... diff --git a/Documentation/git-merge-base.txt b/Documentation/git-merge-base.txt index 1a7ecbf8f3..2f0c5259e0 100644 --- a/Documentation/git-merge-base.txt +++ b/Documentation/git-merge-base.txt @@ -8,26 +8,81 @@ git-merge-base - Find as good common ancestors as possible for a merge SYNOPSIS -------- -'git merge-base' [--all] <commit> <commit> +'git merge-base' [--all] <commit> <commit>... DESCRIPTION ----------- -'git-merge-base' finds as good a common ancestor as possible between -the two commits. That is, given two commits A and B, `git merge-base A -B` will output a commit which is reachable from both A and B through -the parent relationship. +'git-merge-base' finds best common ancestor(s) between two commits to use +in a three-way merge. One common ancestor is 'better' than another common +ancestor if the latter is an ancestor of the former. A common ancestor +that does not have any better common ancestor than it is a 'best common +ancestor', i.e. a 'merge base'. Note that there can be more than one +merge bases between two commits. -Given a selection of equally good common ancestors it should not be -relied on to decide in any particular way. - -The 'git-merge-base' algorithm is still in flux - use the source... +Among the two commits to compute their merge bases, one is specified by +the first commit argument on the command line; the other commit is a +(possibly hypothetical) commit that is a merge across all the remaining +commits on the command line. As the most common special case, giving only +two commits from the command line means computing the merge base between +the given two commits. OPTIONS ------- --all:: - Output all common ancestors for the two commits instead of - just one. + Output all merge bases for the commits, instead of just one. + +DISCUSSION +---------- + +Given two commits 'A' and 'B', `git merge-base A B` will output a commit +which is reachable from both 'A' and 'B' through the parent relationship. + +For example, with this topology: + + o---o---o---B + / + ---o---1---o---o---o---A + +the merge base between 'A' and 'B' is '1'. + +Given three commits 'A', 'B' and 'C', `git merge-base A B C` will compute the +merge base between 'A' and an hypothetical commit 'M', which is a merge +between 'B' and 'C'. For example, with this topology: + + o---o---o---o---C + / + / o---o---o---B + / / + ---2---1---o---o---o---A + +the result of `git merge-base A B C` is '1'. This is because the +equivalent topology with a merge commit 'M' between 'B' and 'C' is: + + + o---o---o---o---o + / \ + / o---o---o---o---M + / / + ---2---1---o---o---o---A + +and the result of `git merge-base A M` is '1'. Commit '2' is also a +common ancestor between 'A' and 'M', but '1' is a better common ancestor, +because '2' is an ancestor of '1'. Hence, '2' is not a merge base. + +When the history involves criss-cross merges, there can be more than one +'best' common ancestors between two commits. For example, with this +topology: + + ---1---o---A + \ / + X + / \ + ---2---o---o---B + +both '1' and '2' are merge-base of A and B. Neither one is better than +the other (both are 'best' merge base). When `--all` option is not given, +it is unspecified which best one is output. Author ------ diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt index 17a15acb07..685e1fed58 100644 --- a/Documentation/git-merge.txt +++ b/Documentation/git-merge.txt @@ -126,13 +126,25 @@ After seeing a conflict, you can do two things: up working tree changes made by 2. and 3.; 'git-reset --hard' can be used for this. - * Resolve the conflicts. `git diff` would report only the - conflicting paths because of the above 2. and 3. - Edit the working tree files into a desirable shape - ('git mergetool' can ease this task), 'git-add' or 'git-rm' - them, to make the index file contain what the merge result - should be, and run 'git-commit' to commit the result. + * Resolve the conflicts. Git will mark the conflicts in + the working tree. Edit the files into shape and + 'git-add' to the index. 'git-commit' to seal the deal. +You can work through the conflict with a number of tools: + + * Use a mergetool. 'git mergetool' to launch a graphical + mergetool which will work you through the merge. + + * Look at the diffs. 'git diff' will show a three-way diff, + highlighting changes from both the HEAD and remote versions. + + * Look at the diffs on their own. 'git log --merge -p <path>' + will show diffs first for the HEAD version and then the + remote version. + + * Look at the originals. 'git show :1:filename' shows the + common ancestor, 'git show :2:filename' shows the HEAD + version and 'git show :3:filename' shows the remote version. SEE ALSO -------- diff --git a/Documentation/git-name-rev.txt b/Documentation/git-name-rev.txt index abd2237e51..7ca8a7b48c 100644 --- a/Documentation/git-name-rev.txt +++ b/Documentation/git-name-rev.txt @@ -59,7 +59,7 @@ Enter 'git-name-rev': ------------ % git name-rev 33db5f4d9027a10e477ccf054b2c1ab94f74c85a -33db5f4d9027a10e477ccf054b2c1ab94f74c85a tags/v0.99^0~940 +33db5f4d9027a10e477ccf054b2c1ab94f74c85a tags/v0.99~940 ------------ Now you are wiser, because you know that it happened 940 revisions before v0.99. diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt index e2437f30ca..3c3e1b0e77 100644 --- a/Documentation/git-send-email.txt +++ b/Documentation/git-send-email.txt @@ -179,6 +179,9 @@ user is prompted for a password while the input is masked for privacy. This is useful if your default address is not the address that is subscribed to a list. If you use the sendmail binary, you must have suitable privileges for the -f parameter. + Default is the value of the 'sendemail.envelopesender' configuration + variable; if that is unspecified, choosing the envelope sender is left + to your MTA. --to:: Specify the primary recipient of the emails generated. diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt index 49e2296a24..051f94d26f 100644 --- a/Documentation/git-stash.txt +++ b/Documentation/git-stash.txt @@ -159,7 +159,7 @@ perform a pull, and then unstash, like this: + ---------------------------------------------------------------- $ git pull -... + ... file foobar not up to date, cannot merge. $ git stash $ git pull @@ -174,7 +174,7 @@ make a commit to a temporary branch to store your changes away, and return to your original branch to make the emergency fix, like this: + ---------------------------------------------------------------- -... hack hack hack ... +# ... hack hack hack ... $ git checkout -b my_wip $ git commit -a -m "WIP" $ git checkout master @@ -182,18 +182,18 @@ $ edit emergency fix $ git commit -a -m "Fix in a hurry" $ git checkout my_wip $ git reset --soft HEAD^ -... continue hacking ... +# ... continue hacking ... ---------------------------------------------------------------- + You can use 'git-stash' to simplify the above, like this: + ---------------------------------------------------------------- -... hack hack hack ... +# ... hack hack hack ... $ git stash $ edit emergency fix $ git commit -a -m "Fix in a hurry" $ git stash apply -... continue hacking ... +# ... continue hacking ... ---------------------------------------------------------------- Testing partial commits:: @@ -203,13 +203,13 @@ more commits out of the changes in the work tree, and you want to test each change before committing: + ---------------------------------------------------------------- -... hack hack hack ... +# ... hack hack hack ... $ git add --patch foo # add just first part to the index $ git stash save --keep-index # save all other changes to the stash $ edit/build/test first part -$ git commit foo -m 'First part' # commit fully tested change +$ git commit -m 'First part' # commit fully tested change $ git stash pop # prepare to work on all other changes -... repeat above five steps until one commit remains ... +# ... repeat above five steps until one commit remains ... $ edit/build/test remaining parts $ git commit foo -m 'Remaining parts' ---------------------------------------------------------------- diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index bf33b0cba0..babaa9bc46 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -14,6 +14,8 @@ SYNOPSIS 'git submodule' [--quiet] init [--] [<path>...] 'git submodule' [--quiet] update [--init] [--] [<path>...] 'git submodule' [--quiet] summary [--summary-limit <n>] [commit] [--] [<path>...] +'git submodule' [--quiet] foreach <command> +'git submodule' [--quiet] sync [--] [<path>...] DESCRIPTION @@ -123,6 +125,30 @@ summary:: in the submodule between the given super project commit and the index or working tree (switched by --cached) are shown. +foreach:: + Evaluates an arbitrary shell command in each checked out submodule. + The command has access to the variables $path and $sha1: + $path is the name of the submodule directory relative to the + superproject, and $sha1 is the commit as recorded in the superproject. + Any submodules defined in the superproject but not checked out are + ignored by this command. Unless given --quiet, foreach prints the name + of each submodule before evaluating the command. + A non-zero return from the command in any submodule causes + the processing to terminate. This can be overridden by adding '|| :' + to the end of the command. ++ +As an example, "git submodule foreach 'echo $path `git rev-parse HEAD`' will +show the path and currently checked out commit for each submodule. + +sync:: + Synchronizes submodules' remote URL configuration setting + to the value specified in .gitmodules. This is useful when + submodule URLs change upstream and you need to update your local + repositories accordingly. ++ +"git submodule sync" synchronizes all submodules while +"git submodule sync -- A" synchronizes submodule "A" only. + OPTIONS ------- -q:: diff --git a/Documentation/git-var.txt b/Documentation/git-var.txt index 3647dd6c8f..e2f4c0901b 100644 --- a/Documentation/git-var.txt +++ b/Documentation/git-var.txt @@ -20,7 +20,7 @@ OPTIONS Cause the logical variables to be listed. In addition, all the variables of the git configuration file .git/config are listed as well. (However, the configuration variables listing functionality - is deprecated in favor of 'git-config -l'.) + is deprecated in favor of 'git config -l'.) EXAMPLE -------- @@ -41,9 +41,9 @@ Diagnostics You don't exist. Go away!:: The passwd(5) gecos field couldn't be read Your parents must have hated you!:: - The password(5) gecos field is longer than a giant static buffer. + The passwd(5) gecos field is longer than a giant static buffer. Your sysadmin must hate you!:: - The password(5) name field is longer than a giant static buffer. + The passwd(5) name field is longer than a giant static buffer. SEE ALSO -------- diff --git a/Documentation/git-web--browse.txt b/Documentation/git-web--browse.txt index 36afad8d4e..7f7a45b2ea 100644 --- a/Documentation/git-web--browse.txt +++ b/Documentation/git-web--browse.txt @@ -77,7 +77,7 @@ the URLs passed as arguments. Note about konqueror -------------------- -When 'konqueror' is specified by the a command line option or a +When 'konqueror' is specified by a command line option or a configuration variable, we launch 'kfmclient' to try to open the HTML man page on an already opened konqueror in a new tab if possible. diff --git a/Documentation/git.txt b/Documentation/git.txt index 1bc295dd54..df420aeb33 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,9 +43,11 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.6.0/git.html[documentation for release 1.6.0] +* link:v1.6.0.2/git.html[documentation for release 1.6.0.2] * release notes for + link:RelNotes-1.6.0.2.txt[1.6.0.2], + link:RelNotes-1.6.0.1.txt[1.6.0.1], link:RelNotes-1.6.0.txt[1.6.0]. * link:v1.5.6.5/git.html[documentation for release 1.5.6.5] @@ -497,7 +499,8 @@ other 'GIT_PAGER':: This environment variable overrides `$PAGER`. If it is set to an empty string or to the value "cat", git will not launch - a pager. + a pager. See also the `core.pager` option in + linkgit:git-config[1]. 'GIT_SSH':: If this environment variable is set then 'git-fetch' diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt index db16b0ca5b..6f3551dc82 100644 --- a/Documentation/gitattributes.txt +++ b/Documentation/gitattributes.txt @@ -7,7 +7,7 @@ gitattributes - defining attributes per path SYNOPSIS -------- -$GIT_DIR/info/attributes, gitattributes +$GIT_DIR/info/attributes, .gitattributes DESCRIPTION @@ -105,9 +105,8 @@ Set:: Unset:: - Unsetting the `crlf` attribute on a path is meant to - mark the path as a "binary" file. The path never goes - through line endings conversion upon checkin/checkout. + Unsetting the `crlf` attribute on a path tells git not to + attempt any end-of-line conversion upon checkin or checkout. Unspecified:: @@ -312,10 +311,16 @@ patterns are available: - `bibtex` suitable for files with BibTeX coded references. -- `java` suitable for source code in the Java lanugage. +- `html` suitable for HTML/XHTML documents. + +- `java` suitable for source code in the Java language. - `pascal` suitable for source code in the Pascal/Delphi language. +- `php` suitable for source code in the PHP language. + +- `python` suitable for source code in the Python language. + - `ruby` suitable for source code in the Ruby language. - `tex` suitable for source code for LaTeX documents. @@ -482,6 +487,41 @@ in the file. E.g. the string `$Format:%H$` will be replaced by the commit hash. +USING ATTRIBUTE MACROS +---------------------- + +You do not want any end-of-line conversions applied to, nor textual diffs +produced for, any binary file you track. You would need to specify e.g. + +------------ +*.jpg -crlf -diff +------------ + +but that may become cumbersome, when you have many attributes. Using +attribute macros, you can specify groups of attributes set or unset at +the same time. The system knows a built-in attribute macro, `binary`: + +------------ +*.jpg binary +------------ + +which is equivalent to the above. Note that the attribute macros can only +be "Set" (see the above example that sets "binary" macro as if it were an +ordinary attribute --- setting it in turn unsets "crlf" and "diff"). + + +DEFINING ATTRIBUTE MACROS +------------------------- + +Custom attribute macros can be defined only in the `.gitattributes` file +at the toplevel (i.e. not in any subdirectory). The built-in attribute +macro "binary" is equivalent to: + +------------ +[attr]binary -diff -crlf +------------ + + EXAMPLE ------- diff --git a/Documentation/gitk.txt b/Documentation/gitk.txt index 6e827cd11c..ae29a00d59 100644 --- a/Documentation/gitk.txt +++ b/Documentation/gitk.txt @@ -49,6 +49,13 @@ frequently used options. the history between two branches (i.e. the HEAD and the MERGE_HEAD) that modify the conflicted files. +--argscmd=<command>:: + Command to be run each time gitk has to determine the list of + <revs> to show. The command is expected to print on its standard + output a list of additional revs to be shown, one per line. + Use this instead of explicitly specifying <revs> if the set of + commits to show may vary between refreshes. + <revs>:: Limit the revisions to show. This can be either a single revision diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt index f8d122a8b9..d1a17e2625 100644 --- a/Documentation/gitmodules.txt +++ b/Documentation/gitmodules.txt @@ -7,7 +7,7 @@ gitmodules - defining submodule properties SYNOPSIS -------- -gitmodules +$GIT_WORK_DIR/.gitmodules DESCRIPTION diff --git a/Documentation/gittutorial.txt b/Documentation/gittutorial.txt index 48d1454a90..384972cb9b 100644 --- a/Documentation/gittutorial.txt +++ b/Documentation/gittutorial.txt @@ -321,10 +321,37 @@ pulling, like this: ------------------------------------------------ alice$ git fetch /home/bob/myrepo master -alice$ git log -p ..FETCH_HEAD +alice$ git log -p HEAD..FETCH_HEAD ------------------------------------------------ This operation is safe even if Alice has uncommitted local changes. +The range notation HEAD..FETCH_HEAD" means "show everything that is reachable +from the FETCH_HEAD but exclude anything that is reachable from HEAD. +Alice already knows everything that leads to her current state (HEAD), +and reviewing what Bob has in his state (FETCH_HEAD) that she has not +seen with this command + +If Alice wants to visualize what Bob did since their histories forked +she can issue the following command: + +------------------------------------------------ +$ gitk HEAD..FETCH_HEAD +------------------------------------------------ + +This uses the same two-dot range notation we saw earlier with 'git log'. + +Alice may want to view what both of them did since they forked. +She can use three-dot form instead of the two-dot form: + +------------------------------------------------ +$ gitk HEAD...FETCH_HEAD +------------------------------------------------ + +This means "show everything that is reachable from either one, but +exclude anything that is reachable from both of them". + +Please note that these range notation can be used with both gitk +and "git log". After inspecting what Bob did, if there is nothing urgent, Alice may decide to continue working without pulling from Bob. If Bob's history diff --git a/Documentation/i18n.txt b/Documentation/i18n.txt index fb0d7da56b..d2970f8357 100644 --- a/Documentation/i18n.txt +++ b/Documentation/i18n.txt @@ -21,7 +21,7 @@ project find it more convenient to use legacy encodings, git does not forbid it. However, there are a few things to keep in mind. -. 'git-commit-tree' (hence, 'git-commit' which uses it) issues +. 'git-commit' and 'git-commit-tree' issues a warning if the commit log message given to it does not look like a valid UTF-8 string, unless you explicitly say your project uses a legacy encoding. The way to say this is to diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt index 00277e0613..c735788b0f 100644 --- a/Documentation/merge-config.txt +++ b/Documentation/merge-config.txt @@ -1,5 +1,5 @@ merge.stat:: - Whether to print the diffstat between ORIG_HEAD and merge result + Whether to print the diffstat between ORIG_HEAD and the merge result at the end of the merge. True by default. merge.log:: diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt index c11d495771..388d4925e6 100644 --- a/Documentation/pretty-formats.txt +++ b/Documentation/pretty-formats.txt @@ -103,7 +103,7 @@ The placeholders are: - '%an': author name - '%aN': author name (respecting .mailmap) - '%ae': author email -- '%ad': author date +- '%ad': author date (format respects --date= option) - '%aD': author date, RFC2822 style - '%ar': author date, relative - '%at': author date, UNIX timestamp diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index 735cf07b20..0ce916a188 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -409,6 +409,48 @@ Note that without '\--full-history', this still simplifies merges: if one of the parents is TREESAME, we follow only that one, so the other sides of the merge are never walked. +Finally, there is a fourth simplification mode available: + +--simplify-merges:: + + First, build a history graph in the same way that + '\--full-history' with parent rewriting does (see above). ++ +Then simplify each commit `C` to its replacement `C'` in the final +history according to the following rules: ++ +-- +* Set `C'` to `C`. ++ +* Replace each parent `P` of `C'` with its simplification `P'`. In + the process, drop parents that are ancestors of other parents, and + remove duplicates. ++ +* If after this parent rewriting, `C'` is a root or merge commit (has + zero or >1 parents), a boundary commit, or !TREESAME, it remains. + Otherwise, it is replaced with its only parent. +-- ++ +The effect of this is best shown by way of comparing to +'\--full-history' with parent rewriting. The example turns into: ++ +----------------------------------------------------------------------- + .-A---M---N---O + / / / + I B D + \ / / + `---------' +----------------------------------------------------------------------- ++ +Note the major differences in `N` and `P` over '\--full-history': ++ +-- +* `N`'s parent list had `I` removed, because it is an ancestor of the + other parent `M`. Still, `N` remained because it is !TREESAME. ++ +* `P`'s parent list similarly had `I` removed. `P` was then + removed completely, because it had one parent and is TREESAME. +-- ifdef::git-rev-list[] Bisection Helpers diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 156dc13733..6c7465c758 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v1.6.0.GIT +DEF_VER=v1.6.0.2.GIT LF=' ' @@ -6,7 +6,7 @@ will install the git programs in your own ~/bin/ directory. If you want to do a global install, you can do $ make prefix=/usr all doc info ;# as yourself - # make prefix=/usr install install-doc install-info ;# as root + # make prefix=/usr install install-doc install-html install-info ;# as root (or prefix=/usr/local, of course). Just like any program suite that uses $prefix, the built results have some paths encoded, @@ -19,7 +19,7 @@ set up install paths (via config.mak.autogen), so you can write instead $ make configure ;# as yourself $ ./configure --prefix=/usr ;# as yourself $ make all doc ;# as yourself - # make install install-doc ;# as root + # make install install-doc install-html;# as root Issues of note: @@ -89,13 +89,22 @@ Issues of note: inclined to install the tools, the default build target ("make all") does _not_ build them. + "make doc" builds documentation in man and html formats; there are + also "make man", "make html" and "make info". Note that "make html" + requires asciidoc, but not xmlto. "make man" (and thus make doc) + requires both. + + "make install-doc" installs documentation in man format only; there + are also "make install-man", "make install-html" and "make + install-info". + Building and installing the info file additionally requires makeinfo and docbook2X. Version 0.8.3 is known to work. The documentation is written for AsciiDoc 7, but "make ASCIIDOC8=YesPlease doc" will let you format with AsciiDoc 8. - Alternatively, pre-formatted documentation are available in + Alternatively, pre-formatted documentation is available in "html" and "man" branches of the git repository itself. For example, you could: @@ -117,6 +126,12 @@ Issues of note: http://www.kernel.org/pub/software/scm/git/docs/ + There are also "make quick-install-doc" and "make quick-install-html" + which install preformatted man pages and html documentation. + This does not require asciidoc/xmlto, but it only works from within + a cloned checkout of git.git with these two extra branches, and will + not work for the maintainer for obvious chicken-and-egg reasons. + It has been reported that docbook-xsl version 1.72 and 1.73 are buggy; 1.72 misformats manual pages for callouts, and 1.73 needs the patch in contrib/patches/docbook-xsl-manpages-charmap.patch @@ -124,6 +124,9 @@ all:: # Define USE_STDEV below if you want git to care about the underlying device # change being considered an inode change from the update-index perspective. # +# 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 DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72. @@ -293,6 +296,7 @@ PROGRAMS += git-pack-redundant$X PROGRAMS += git-patch-id$X PROGRAMS += git-receive-pack$X PROGRAMS += git-send-pack$X +PROGRAMS += git-shell$X PROGRAMS += git-show-index$X PROGRAMS += git-unpack-file$X PROGRAMS += git-update-server-info$X @@ -333,7 +337,6 @@ endif export PERL_PATH LIB_FILE=libgit.a -COMPAT_LIB = compat/lib.a XDIFF_LIB=xdiff/lib.a LIB_H += archive.h @@ -355,10 +358,13 @@ LIB_H += git-compat-util.h LIB_H += graph.h LIB_H += grep.h LIB_H += hash.h +LIB_H += help.h +LIB_H += levenshtein.h LIB_H += list-objects.h LIB_H += ll-merge.h LIB_H += log-tree.h LIB_H += mailmap.h +LIB_H += merge-recursive.h LIB_H += object.h LIB_H += pack.h LIB_H += pack-refs.h @@ -430,6 +436,7 @@ LIB_OBJS += hash.o LIB_OBJS += help.o LIB_OBJS += ident.o LIB_OBJS += interpolate.o +LIB_OBJS += levenshtein.o LIB_OBJS += list-objects.o LIB_OBJS += ll-merge.o LIB_OBJS += lockfile.o @@ -518,6 +525,7 @@ BUILTIN_OBJS += builtin-for-each-ref.o BUILTIN_OBJS += builtin-fsck.o BUILTIN_OBJS += builtin-gc.o BUILTIN_OBJS += builtin-grep.o +BUILTIN_OBJS += builtin-help.o BUILTIN_OBJS += builtin-init-db.o BUILTIN_OBJS += builtin-log.o BUILTIN_OBJS += builtin-ls-files.o @@ -575,9 +583,11 @@ EXTLIBS = ifeq ($(uname_S),Linux) NO_STRLCPY = YesPlease + THREADED_DELTA_SEARCH = YesPlease endif ifeq ($(uname_S),GNU/kFreeBSD) NO_STRLCPY = YesPlease + THREADED_DELTA_SEARCH = YesPlease endif ifeq ($(uname_S),UnixWare) CC = cc @@ -626,6 +636,8 @@ ifeq ($(uname_S),Darwin) endif NO_STRLCPY = YesPlease NO_MEMMEM = YesPlease + COMPAT_CFLAGS += -Icompat/regex + COMPAT_OBJS += compat/regex/regex.o endif ifeq ($(uname_S),SunOS) NEEDS_SOCKET = YesPlease @@ -675,6 +687,9 @@ ifeq ($(uname_S),FreeBSD) BASIC_CFLAGS += -I/usr/local/include BASIC_LDFLAGS += -L/usr/local/lib DIR_HAS_BSD_GROUP_SEMANTICS = YesPlease + THREADED_DELTA_SEARCH = YesPlease + COMPAT_CFLAGS += -Icompat/regex + COMPAT_OBJS += compat/regex/regex.o endif ifeq ($(uname_S),OpenBSD) NO_STRCASESTR = YesPlease @@ -682,14 +697,15 @@ ifeq ($(uname_S),OpenBSD) NEEDS_LIBICONV = YesPlease BASIC_CFLAGS += -I/usr/local/include BASIC_LDFLAGS += -L/usr/local/lib + THREADED_DELTA_SEARCH = YesPlease endif ifeq ($(uname_S),NetBSD) ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2) NEEDS_LIBICONV = YesPlease endif BASIC_CFLAGS += -I/usr/pkg/include - BASIC_LDFLAGS += -L/usr/pkg/lib - ALL_LDFLAGS += -Wl,-rpath,/usr/pkg/lib + BASIC_LDFLAGS += -L/usr/pkg/lib $(CC_LD_DYNPATH)/usr/pkg/lib + THREADED_DELTA_SEARCH = YesPlease endif ifeq ($(uname_S),AIX) NO_STRCASESTR=YesPlease @@ -700,6 +716,8 @@ ifeq ($(uname_S),AIX) INTERNAL_QSORT = UnfortunatelyYes NEEDS_LIBICONV=YesPlease BASIC_CFLAGS += -D_LARGE_FILES + COMPAT_CFLAGS += -Icompat/regex + COMPAT_OBJS += compat/regex/regex.o endif ifeq ($(uname_S),GNU) # GNU/Hurd @@ -727,6 +745,7 @@ ifeq ($(uname_S),HP-UX) NO_UNSETENV = YesPlease NO_HSTRERROR = YesPlease NO_SYS_SELECT_H = YesPlease + SNPRINTF_RETURNS_BOGUS = YesPlease endif ifneq (,$(findstring MINGW,$(uname_S))) NO_MMAP = YesPlease @@ -749,10 +768,11 @@ ifneq (,$(findstring MINGW,$(uname_S))) NO_SVN_TESTS = YesPlease NO_PERL_MAKEMAKER = YesPlease NO_POSIX_ONLY_PROGRAMS = YesPlease - COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat + NO_ST_BLOCKS_IN_STRUCT_STAT = YesPlease + COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/regex -Icompat/fnmatch COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" - COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o compat/winansi.o + COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/regex/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe gitexecdir = ../libexec/git-core @@ -781,12 +801,14 @@ ifeq ($(uname_S),Darwin) endif endif -ifdef NO_R_TO_GCC_LINKER - # Some gcc does not accept and pass -R to the linker to specify - # the runtime dynamic library path. - CC_LD_DYNPATH = -Wl,-rpath= -else - CC_LD_DYNPATH = -R +ifndef CC_LD_DYNPATH + ifdef NO_R_TO_GCC_LINKER + # Some gcc does not accept and pass -R to the linker to specify + # the runtime dynamic library path. + CC_LD_DYNPATH = -Wl,-rpath, + else + CC_LD_DYNPATH = -R + endif endif ifdef NO_CURL @@ -822,7 +844,6 @@ EXTLIBS += -lz ifndef NO_POSIX_ONLY_PROGRAMS PROGRAMS += git-daemon$X PROGRAMS += git-imap-send$X - PROGRAMS += git-shell$X endif ifndef NO_OPENSSL OPENSSL_LIBSSL = -lssl @@ -863,6 +884,9 @@ endif ifdef NO_D_INO_IN_DIRENT BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT endif +ifdef NO_ST_BLOCKS_IN_STRUCT_STAT + BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT +endif ifdef NO_C99_FORMAT BASIC_CFLAGS += -DNO_C99_FORMAT endif @@ -1091,14 +1115,17 @@ git$X: git.o $(BUILTIN_OBJS) $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ git.o \ $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS) -help.o: help.c common-cmds.h GIT-CFLAGS +builtin-help.o: builtin-help.c common-cmds.h GIT-CFLAGS $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) \ '-DGIT_HTML_PATH="$(htmldir_SQ)"' \ '-DGIT_MAN_PATH="$(mandir_SQ)"' \ '-DGIT_INFO_PATH="$(infodir_SQ)"' $< $(BUILT_INS): git$X - $(QUIET_BUILT_IN)$(RM) $@ && ln git$X $@ + $(QUIET_BUILT_IN)$(RM) $@ && \ + ln git$X $@ 2>/dev/null || \ + ln -s git$X $@ 2>/dev/null || \ + cp git$X $@ common-cmds.h: ./generate-cmdlist.sh command-list.txt @@ -1215,7 +1242,9 @@ endif git-%$X: %.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) -git-imap-send$X: imap-send.o $(LIB_FILE) +git-imap-send$X: imap-send.o $(GITLIBS) + $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ + $(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL) http.o http-walker.o http-push.o transport.o: http.h @@ -1223,12 +1252,6 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) -$(COMPAT_LIB): $(COMPAT_OBJS) - $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(COMPAT_OBJS) - -git-shell$X: abspath.o ctype.o exec_cmd.o quote.o strbuf.o usage.o wrapper.o shell.o $(COMPAT_LIB) - $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(COMPAT_LIB) - $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) $(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) builtin-revert.o wt-status.o: wt-status.h @@ -1248,6 +1271,12 @@ $(XDIFF_LIB): $(XDIFF_OBJS) doc: $(MAKE) -C Documentation all +man: + $(MAKE) -C Documentation man + +html: + $(MAKE) -C Documentation html + info: $(MAKE) -C Documentation info @@ -1351,7 +1380,7 @@ install: all $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' - $(INSTALL) git$X git-upload-pack$X git-receive-pack$X git-upload-archive$X '$(DESTDIR_SQ)$(bindir_SQ)' + $(INSTALL) git$X git-upload-pack$X git-receive-pack$X git-upload-archive$X git-shell$X git-cvsserver '$(DESTDIR_SQ)$(bindir_SQ)' $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install ifndef NO_TCLTK @@ -1363,16 +1392,13 @@ ifneq (,$X) endif bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \ execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \ - if test "z$$bindir" != "z$$execdir"; \ - then \ - ln -f "$$bindir/git$X" "$$execdir/git$X" || \ - cp "$$bindir/git$X" "$$execdir/git$X"; \ - fi && \ - { $(foreach p,$(BUILT_INS), $(RM) "$$execdir/$p" && ln "$$execdir/git$X" "$$execdir/$p" ;) } && \ - if test "z$$bindir" != "z$$execdir"; \ - then \ - $(RM) "$$execdir/git$X"; \ - fi && \ + { $(RM) "$$execdir/git-add$X" && \ + ln git-add$X "$$execdir/git-add$X" 2>/dev/null || \ + cp git-add$X "$$execdir/git-add$X"; } && \ + { $(foreach p,$(filter-out git-add$X,$(BUILT_INS)), $(RM) "$$execdir/$p" && \ + ln "$$execdir/git-add$X" "$$execdir/$p" 2>/dev/null || \ + ln -s "git-add$X" "$$execdir/$p" 2>/dev/null || \ + cp "$$execdir/git-add$X" "$$execdir/$p" || exit;) } && \ ./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X" install-doc: @@ -1387,6 +1413,9 @@ install-info: quick-install-doc: $(MAKE) -C Documentation quick-install +quick-install-html: + $(MAKE) -C Documentation quick-install-html + ### Maintainer's dist rules @@ -1441,7 +1470,7 @@ distclean: clean clean: $(RM) *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o xdiff/*.o \ - $(LIB_FILE) $(XDIFF_LIB) $(COMPAT_LIB) + $(LIB_FILE) $(XDIFF_LIB) $(RM) $(ALL_PROGRAMS) $(BUILT_INS) git$X $(RM) $(TEST_PROGRAMS) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope* @@ -1 +1 @@ -Documentation/RelNotes-1.6.0.1.txt
\ No newline at end of file +Documentation/RelNotes-1.6.1.txt
\ No newline at end of file @@ -48,7 +48,7 @@ static void format_subst(const struct commit *commit, strbuf_add(&fmt, b + 8, c - b - 8); strbuf_add(buf, src, b - src); - format_commit_message(commit, fmt.buf, buf); + format_commit_message(commit, fmt.buf, buf, DATE_NORMAL); len -= c + 1 - src; src = c + 1; } diff --git a/builtin-add.c b/builtin-add.c index fc3f96eaef..7c874e3115 100644 --- a/builtin-add.c +++ b/builtin-add.c @@ -8,10 +8,6 @@ #include "dir.h" #include "exec_cmd.h" #include "cache-tree.h" -#include "diff.h" -#include "diffcore.h" -#include "commit.h" -#include "revision.h" #include "run-command.h" #include "parse-options.h" @@ -22,6 +18,27 @@ static const char * const builtin_add_usage[] = { static int patch_interactive = 0, add_interactive = 0; static int take_worktree_changes; +static void fill_pathspec_matches(const char **pathspec, char *seen, int specs) +{ + int num_unmatched = 0, i; + + /* + * Since we are walking the index as if we are warlking the directory, + * we have to mark the matched pathspec as seen; otherwise we will + * mistakenly think that the user gave a pathspec that did not match + * anything. + */ + for (i = 0; i < specs; i++) + if (!seen[i]) + num_unmatched++; + if (!num_unmatched) + return; + for (i = 0; i < active_nr; i++) { + struct cache_entry *ce = active_cache[i]; + match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen); + } +} + static void prune_directory(struct dir_struct *dir, const char **pathspec, int prefix) { char *seen; @@ -41,6 +58,7 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p *dst++ = entry; } dir->nr = dst - dir->entries; + fill_pathspec_matches(pathspec, seen, specs); for (i = 0; i < specs; i++) { if (!seen[i] && !file_exists(pathspec[i])) @@ -79,59 +97,6 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec, prune_directory(dir, pathspec, baselen); } -struct update_callback_data -{ - int flags; - int add_errors; -}; - -static void update_callback(struct diff_queue_struct *q, - struct diff_options *opt, void *cbdata) -{ - int i; - struct update_callback_data *data = cbdata; - - for (i = 0; i < q->nr; i++) { - struct diff_filepair *p = q->queue[i]; - const char *path = p->one->path; - switch (p->status) { - default: - die("unexpected diff status %c", p->status); - case DIFF_STATUS_UNMERGED: - case DIFF_STATUS_MODIFIED: - case DIFF_STATUS_TYPE_CHANGED: - if (add_file_to_cache(path, data->flags)) { - if (!(data->flags & ADD_CACHE_IGNORE_ERRORS)) - die("updating files failed"); - data->add_errors++; - } - break; - case DIFF_STATUS_DELETED: - if (!(data->flags & ADD_CACHE_PRETEND)) - remove_file_from_cache(path); - if (data->flags & (ADD_CACHE_PRETEND|ADD_CACHE_VERBOSE)) - printf("remove '%s'\n", path); - break; - } - } -} - -int add_files_to_cache(const char *prefix, const char **pathspec, int flags) -{ - struct update_callback_data data; - struct rev_info rev; - init_revisions(&rev, prefix); - setup_revisions(0, NULL, &rev, NULL); - rev.prune_data = pathspec; - rev.diffopt.output_format = DIFF_FORMAT_CALLBACK; - rev.diffopt.format_callback = update_callback; - data.flags = flags; - data.add_errors = 0; - rev.diffopt.format_callback_data = &data; - run_diff_files(&rev, DIFF_RACY_IS_MODIFIED); - return !!data.add_errors; -} - static void refresh(int verbose, const char **pathspec) { char *seen; @@ -153,6 +118,16 @@ static const char **validate_pathspec(int argc, const char **argv, const char *p { const char **pathspec = get_pathspec(prefix, argv); + if (pathspec) { + const char **p; + for (p = pathspec; *p; p++) { + if (has_symlink_leading_path(strlen(*p), *p)) { + int len = prefix ? strlen(prefix) : 0; + die("'%s' is beyond a symbolic link", *p + len); + } + } + } + return pathspec; } @@ -258,7 +233,7 @@ int cmd_add(int argc, const char **argv, const char *prefix) if (addremove && take_worktree_changes) die("-A and -u are mutually incompatible"); - if (addremove && !argc) { + if ((addremove || take_worktree_changes) && !argc) { static const char *here[2] = { ".", NULL }; argc = 1; argv = here; @@ -271,33 +246,30 @@ int cmd_add(int argc, const char **argv, const char *prefix) flags = ((verbose ? ADD_CACHE_VERBOSE : 0) | (show_only ? ADD_CACHE_PRETEND : 0) | - (ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0)); + (ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) | + (!(addremove || take_worktree_changes) + ? ADD_CACHE_IGNORE_REMOVAL : 0)); if (require_pathspec && argc == 0) { fprintf(stderr, "Nothing specified, nothing added.\n"); fprintf(stderr, "Maybe you wanted to say 'git add .'?\n"); return 0; } - pathspec = get_pathspec(prefix, argv); - - /* - * If we are adding new files, we need to scan the working - * tree to find the ones that match pathspecs; this needs - * to be done before we read the index. - */ - if (add_new_files) - fill_directory(&dir, pathspec, ignored_too); + pathspec = validate_pathspec(argc, argv, prefix); if (read_cache() < 0) die("index file corrupt"); + if (add_new_files) + /* This picks up the paths that are not tracked */ + fill_directory(&dir, pathspec, ignored_too); + if (refresh_only) { refresh(verbose, pathspec); goto finish; } - if (take_worktree_changes || addremove) - exit_status |= add_files_to_cache(prefix, pathspec, flags); + exit_status |= add_files_to_cache(prefix, pathspec, flags); if (add_new_files) exit_status |= add_files(&dir, flags); diff --git a/builtin-apply.c b/builtin-apply.c index 2216a0bf7c..20bef1f21d 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -274,7 +274,7 @@ static void say_patch_name(FILE *output, const char *pre, static void read_patch_file(struct strbuf *sb, int fd) { if (strbuf_read(sb, fd, 0) < 0) - die("git-apply: read returned %s", strerror(errno)); + die("git apply: read returned %s", strerror(errno)); /* * Make sure that we have some slop in the buffer @@ -506,17 +506,17 @@ static char *gitdiff_verify_name(const char *line, int isnull, char *orig_name, name = orig_name; len = strlen(name); if (isnull) - die("git-apply: bad git-diff - expected /dev/null, got %s on line %d", name, linenr); + die("git apply: bad git-diff - expected /dev/null, got %s on line %d", name, linenr); another = find_name(line, NULL, p_value, TERM_TAB); if (!another || memcmp(another, name, len)) - die("git-apply: bad git-diff - inconsistent %s filename on line %d", oldnew, linenr); + die("git apply: bad git-diff - inconsistent %s filename on line %d", oldnew, linenr); free(another); return orig_name; } else { /* expect "/dev/null" */ if (memcmp("/dev/null", line, 9) || line[9] != '\n') - die("git-apply: bad git-diff - expected /dev/null on line %d", linenr); + die("git apply: bad git-diff - expected /dev/null on line %d", linenr); return NULL; } } @@ -1996,6 +1996,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag, /* * A hunk to change lines at the beginning would begin with * @@ -1,L +N,M @@ + * but we need to be careful. -U0 that inserts before the second + * line also has this pattern. * * And a hunk to add to an empty file would begin with * @@ -0,0 +N,M @@ @@ -2003,7 +2005,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag, * In other words, a hunk that is (frag->oldpos <= 1) with or * without leading context must match at the beginning. */ - match_beginning = frag->oldpos <= 1; + match_beginning = (!frag->oldpos || + (frag->oldpos == 1 && !unidiff_zero)); /* * A hunk without trailing lines must match at the end. diff --git a/builtin-archive.c b/builtin-archive.c index 22445acbfc..5ceec433fd 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -47,18 +47,18 @@ static int run_remote_archiver(const char *remote, int argc, len = packet_read_line(fd[0], buf, sizeof(buf)); if (!len) - die("git-archive: expected ACK/NAK, got EOF"); + die("git archive: expected ACK/NAK, got EOF"); if (buf[len-1] == '\n') buf[--len] = 0; if (strcmp(buf, "ACK")) { if (len > 5 && !prefixcmp(buf, "NACK ")) - die("git-archive: NACK %s", buf + 5); - die("git-archive: protocol error"); + die("git archive: NACK %s", buf + 5); + die("git archive: protocol error"); } len = packet_read_line(fd[0], buf, sizeof(buf)); if (len) - die("git-archive: expected a flush"); + die("git archive: expected a flush"); /* Now, start reading from fd[0] and spit it out to stdout */ rv = recv_sideband("archive", fd[0], 1, 2); diff --git a/builtin-blame.c b/builtin-blame.c index 4ea343189f..6b7b9f4466 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -38,7 +38,6 @@ static int show_root; static int reverse; static int blank_boundary; static int incremental; -static int cmd_is_annotate; static int xdl_opts = XDF_NEED_MINIMAL; static struct string_list mailmap; @@ -465,7 +464,6 @@ struct patch { }; struct blame_diff_state { - struct xdiff_emit_state xm; struct patch *ret; unsigned hunk_post_context; unsigned hunk_in_pre_context : 1; @@ -528,15 +526,12 @@ static struct patch *compare_buffer(mmfile_t *file_p, mmfile_t *file_o, xpp.flags = xdl_opts; memset(&xecfg, 0, sizeof(xecfg)); xecfg.ctxlen = context; - ecb.outf = xdiff_outf; - ecb.priv = &state; memset(&state, 0, sizeof(state)); - state.xm.consume = process_u_diff; state.ret = xmalloc(sizeof(struct patch)); state.ret->chunks = NULL; state.ret->num = 0; - xdi_diff(file_p, file_o, &xpp, &xecfg, &ecb); + xdi_diff_outf(file_p, file_o, process_u_diff, &state, &xpp, &xecfg, &ecb); if (state.ret->num) { struct chunk *chunk; @@ -1686,7 +1681,7 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt) if (suspect->commit->object.flags & UNINTERESTING) { if (blank_boundary) memset(hex, ' ', length); - else if (!cmd_is_annotate) { + else if (!(opt & OUTPUT_ANNOTATE_COMPAT)) { length--; putchar('^'); } @@ -1791,7 +1786,7 @@ static int prepare_lines(struct scoreboard *sb) /* * Add phony grafts for use with -S; this is primarily to - * support git-cvsserver that wants to give a linear history + * support git's cvsserver that wants to give a linear history * to its clients. */ static int read_ancestry(const char *graft_file) @@ -2317,8 +2312,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix) }; struct parse_opt_ctx_t ctx; - - cmd_is_annotate = !strcmp(argv[0], "annotate"); + int cmd_is_annotate = !strcmp(argv[0], "annotate"); git_config(git_blame_config, NULL); init_revisions(&revs, NULL); @@ -2346,6 +2340,9 @@ int cmd_blame(int argc, const char **argv, const char *prefix) parse_done: argc = parse_options_end(&ctx); + if (cmd_is_annotate) + output_option |= OUTPUT_ANNOTATE_COMPAT; + if (DIFF_OPT_TST(&revs.diffopt, FIND_COPIES_HARDER)) opt |= (PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE | PICKAXE_BLAME_COPY_HARDER); diff --git a/builtin-bundle.c b/builtin-bundle.c index ac476e7a4b..9b58152047 100644 --- a/builtin-bundle.c +++ b/builtin-bundle.c @@ -6,10 +6,10 @@ * Basic handler for bundle files to connect repositories via sneakernet. * Invocation must include action. * This function can create a bundle or provide information on an existing - * bundle supporting git-fetch, git-pull, and git-ls-remote + * bundle supporting "fetch", "pull", and "ls-remote". */ -static const char *bundle_usage="git-bundle (create <bundle> <git-rev-list args> | verify <bundle> | list-heads <bundle> [refname]... | unbundle <bundle> [refname]... )"; +static const char *bundle_usage="git bundle (create <bundle> <git rev-list args> | verify <bundle> | list-heads <bundle> [refname]... | unbundle <bundle> [refname]... )"; int cmd_bundle(int argc, const char **argv, const char *prefix) { diff --git a/builtin-cat-file.c b/builtin-cat-file.c index 7441a56acd..3fba6b9e74 100644 --- a/builtin-cat-file.c +++ b/builtin-cat-file.c @@ -137,11 +137,11 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name) break; default: - die("git-cat-file: unknown option: %s\n", exp_type); + die("git cat-file: unknown option: %s\n", exp_type); } if (!buf) - die("git-cat-file %s: bad file", obj_name); + die("git cat-file %s: bad file", obj_name); write_or_die(1, buf, size); return 0; diff --git a/builtin-check-ref-format.c b/builtin-check-ref-format.c index fe04be77a9..701de439ae 100644 --- a/builtin-check-ref-format.c +++ b/builtin-check-ref-format.c @@ -9,6 +9,6 @@ int cmd_check_ref_format(int argc, const char **argv, const char *prefix) { if (argc != 2) - usage("git-check-ref-format refname"); + usage("git check-ref-format refname"); return !!check_ref_format(argv[1]); } diff --git a/builtin-checkout-index.c b/builtin-checkout-index.c index 71ebabf990..55b7aafe06 100644 --- a/builtin-checkout-index.c +++ b/builtin-checkout-index.c @@ -5,26 +5,26 @@ * * Careful: order of argument flags does matter. For example, * - * git-checkout-index -a -f file.c + * git checkout-index -a -f file.c * * Will first check out all files listed in the cache (but not * overwrite any old ones), and then force-checkout "file.c" a * second time (ie that one _will_ overwrite any old contents * with the same filename). * - * Also, just doing "git-checkout-index" does nothing. You probably - * meant "git-checkout-index -a". And if you want to force it, you - * want "git-checkout-index -f -a". + * Also, just doing "git checkout-index" does nothing. You probably + * meant "git checkout-index -a". And if you want to force it, you + * want "git checkout-index -f -a". * * Intuitiveness is not the goal here. Repeatability is. The * reason for the "no arguments means no work" thing is that * from scripts you are supposed to be able to do things like * - * find . -name '*.h' -print0 | xargs -0 git-checkout-index -f -- + * find . -name '*.h' -print0 | xargs -0 git checkout-index -f -- * * or: * - * find . -name '*.h' -print0 | git-checkout-index -f -z --stdin + * find . -name '*.h' -print0 | git checkout-index -f -z --stdin * * which will force all existing *.h files to be replaced with * their cached copies. If an empty command line implied "all", @@ -107,7 +107,7 @@ static int checkout_file(const char *name, int prefix_length) } if (!state.quiet) { - fprintf(stderr, "git-checkout-index: %s ", name); + fprintf(stderr, "git checkout-index: %s ", name); if (!has_same_name) fprintf(stderr, "is not in the cache"); else if (checkout_stage) @@ -258,9 +258,9 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) const char *p; if (all) - die("git-checkout-index: don't mix '--all' and explicit filenames"); + die("git checkout-index: don't mix '--all' and explicit filenames"); if (read_from_stdin) - die("git-checkout-index: don't mix '--stdin' and explicit filenames"); + die("git checkout-index: don't mix '--stdin' and explicit filenames"); p = prefix_path(prefix, prefix_length, arg); checkout_file(p, prefix_length); if (p < arg || p > arg + strlen(arg)) @@ -271,7 +271,7 @@ int cmd_checkout_index(int argc, const char **argv, const char *prefix) struct strbuf buf, nbuf; if (all) - die("git-checkout-index: don't mix '--all' and '--stdin'"); + die("git checkout-index: don't mix '--all' and '--stdin'"); strbuf_init(&buf, 0); strbuf_init(&nbuf, 0); diff --git a/builtin-checkout.c b/builtin-checkout.c index 411cc513c6..d986ac7abb 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -76,6 +76,15 @@ static int read_tree_some(struct tree *tree, const char **pathspec) return 0; } +static int skip_same_name(struct cache_entry *ce, int pos) +{ + while (++pos < active_nr && + !strcmp(active_cache[pos]->name, ce->name)) + ; /* skip */ + return pos; +} + + static int checkout_paths(struct tree *source_tree, const char **pathspec) { int pos; @@ -107,6 +116,20 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec) if (report_path_error(ps_matched, pathspec, 0)) return 1; + /* Any unmerged paths? */ + for (pos = 0; pos < active_nr; pos++) { + struct cache_entry *ce = active_cache[pos]; + if (pathspec_match(pathspec, NULL, ce->name, 0)) { + if (!ce_stage(ce)) + continue; + errs = 1; + error("path '%s' is unmerged", ce->name); + pos = skip_same_name(ce, pos) - 1; + } + } + if (errs) + return 1; + /* Now we are committed to check them out */ memset(&state, 0, sizeof(state)); state.force = 1; @@ -114,7 +137,11 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec) for (pos = 0; pos < active_nr; pos++) { struct cache_entry *ce = active_cache[pos]; if (pathspec_match(pathspec, NULL, ce->name, 0)) { - errs |= checkout_entry(ce, &state, NULL); + if (!ce_stage(ce)) { + errs |= checkout_entry(ce, &state, NULL); + continue; + } + pos = skip_same_name(ce, pos) - 1; } } @@ -157,7 +184,7 @@ struct checkout_opts { int force; int writeout_error; - char *new_branch; + const char *new_branch; int new_branch_log; enum branch_track track; }; @@ -386,13 +413,11 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new) } /* - * If the new thing isn't a branch and isn't HEAD and we're - * not starting a new branch, and we want messages, and we - * weren't on a branch, and we're moving to a new commit, - * describe the old commit. + * If we were on a detached HEAD, but we are now moving to + * a new commit, we want to mention the old commit once more + * to remind the user that it might be lost. */ - if (!new->path && strcmp(new->name, "HEAD") && !opts->new_branch && - !opts->quiet && !old.path && new->commit != old.commit) + if (!opts->quiet && !old.path && new->commit != old.commit) describe_detached_head("Previous HEAD position was", old.commit); if (!old.commit) { @@ -437,13 +462,28 @@ int cmd_checkout(int argc, const char **argv, const char *prefix) git_config(git_default_config, NULL); - opts.track = git_branch_track; + opts.track = BRANCH_TRACK_UNSPECIFIED; argc = parse_options(argc, argv, options, checkout_usage, PARSE_OPT_KEEP_DASHDASH); - if (!opts.new_branch && (opts.track != git_branch_track)) - die("git checkout: --track and --no-track require -b"); + /* --track without -b should DWIM */ + if (0 < opts.track && !opts.new_branch) { + const char *argv0 = argv[0]; + if (!argc || !strcmp(argv0, "--")) + die ("--track needs a branch name"); + if (!prefixcmp(argv0, "refs/")) + argv0 += 5; + if (!prefixcmp(argv0, "remotes/")) + argv0 += 8; + argv0 = strchr(argv0, '/'); + if (!argv0 || !argv0[1]) + die ("Missing branch name; try -b"); + opts.new_branch = argv0 + 1; + } + + if (opts.track == BRANCH_TRACK_UNSPECIFIED) + opts.track = git_branch_track; if (opts.force && opts.merge) die("git checkout: -f and -m are incompatible"); diff --git a/builtin-clone.c b/builtin-clone.c index c0e3086437..c8435295ce 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -147,6 +147,15 @@ static int is_directory(const char *path) return !stat(path, &buf) && S_ISDIR(buf.st_mode); } +static void strip_trailing_slashes(char *dir) +{ + char *end = dir + strlen(dir); + + while (dir < end - 1 && is_dir_sep(end[-1])) + end--; + *end = '\0'; +} + static void setup_reference(const char *repo) { const char *ref_git; @@ -387,7 +396,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) path = get_repo_path(repo_name, &is_bundle); if (path) - repo = path; + repo = xstrdup(make_nonrelative_path(repo_name)); else if (!strchr(repo_name, ':')) repo = xstrdup(make_absolute_path(repo_name)); else @@ -397,6 +406,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) dir = xstrdup(argv[1]); else dir = guess_dir_name(repo_name, is_bundle, option_bare); + strip_trailing_slashes(dir); if (!stat(dir, &buf)) die("destination directory '%s' already exists.", dir); @@ -422,10 +432,11 @@ int cmd_clone(int argc, const char **argv, const char *prefix) if (!option_bare) { junk_work_tree = work_tree; if (safe_create_leading_directories_const(work_tree) < 0) - die("could not create leading directories of '%s'", - work_tree); + die("could not create leading directories of '%s': %s", + work_tree, strerror(errno)); if (mkdir(work_tree, 0755)) - die("could not create work tree dir '%s'.", work_tree); + die("could not create work tree dir '%s': %s.", + work_tree, strerror(errno)); set_git_work_tree(work_tree); } junk_git_dir = git_dir; diff --git a/builtin-commit-tree.c b/builtin-commit-tree.c index 7a9a309be0..f2684bb75e 100644 --- a/builtin-commit-tree.c +++ b/builtin-commit-tree.c @@ -24,7 +24,7 @@ static void check_valid(unsigned char *sha1, enum object_type expect) typename(expect)); } -static const char commit_tree_usage[] = "git-commit-tree <sha1> [-p <sha1>]* < changelog"; +static const char commit_tree_usage[] = "git commit-tree <sha1> [-p <sha1>]* < changelog"; static void new_parent(struct commit *parent, struct commit_list **parents_p) { @@ -48,6 +48,7 @@ static const char commit_utf8_warn[] = int commit_tree(const char *msg, unsigned char *tree, struct commit_list *parents, unsigned char *ret) { + int result; int encoding_is_utf8; struct strbuf buffer; @@ -86,7 +87,9 @@ int commit_tree(const char *msg, unsigned char *tree, if (encoding_is_utf8 && !is_utf8(buffer.buf)) fprintf(stderr, commit_utf8_warn); - return write_sha1_file(buffer.buf, buffer.len, commit_type, ret); + result = write_sha1_file(buffer.buf, buffer.len, commit_type, ret); + strbuf_release(&buffer); + return result; } int cmd_commit_tree(int argc, const char **argv, const char *prefix) @@ -118,7 +121,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix) } if (strbuf_read(&buffer, 0, 0) < 0) - die("git-commit-tree: read returned %s", strerror(errno)); + die("git commit-tree: read returned %s", strerror(errno)); if (!commit_tree(buffer.buf, tree_sha1, parents, commit_sha1)) { printf("%s\n", sha1_to_hex(commit_sha1)); diff --git a/builtin-commit.c b/builtin-commit.c index 649c8beb3e..8165bb3d31 100644 --- a/builtin-commit.c +++ b/builtin-commit.c @@ -320,7 +320,7 @@ static char *prepare_index(int argc, const char **argv, const char *prefix) die("unable to write new_index file"); fd = hold_lock_file_for_update(&false_lock, - git_path("next-index-%d", getpid()), 1); + git_path("next-index-%"PRIuMAX, (uintmax_t) getpid()), 1); create_base_index(); add_remove_files(&partial); @@ -710,6 +710,31 @@ static int message_is_empty(struct strbuf *sb, int start) return 1; } +static const char *find_author_by_nickname(const char *name) +{ + struct rev_info revs; + struct commit *commit; + struct strbuf buf = STRBUF_INIT; + const char *av[20]; + int ac = 0; + + init_revisions(&revs, NULL); + strbuf_addf(&buf, "--author=%s", name); + av[++ac] = "--all"; + av[++ac] = "-i"; + av[++ac] = buf.buf; + av[++ac] = NULL; + setup_revisions(ac, av, &revs, NULL); + prepare_revision_walk(&revs); + commit = get_revision(&revs); + if (commit) { + strbuf_release(&buf); + format_commit_message(commit, "%an <%ae>", &buf, DATE_NORMAL); + return strbuf_detach(&buf, NULL); + } + die("No existing author found with '%s'", name); +} + static int parse_and_validate_options(int argc, const char *argv[], const char * const usage[], const char *prefix) @@ -720,6 +745,9 @@ static int parse_and_validate_options(int argc, const char *argv[], logfile = parse_options_fix_filename(prefix, logfile); template_file = parse_options_fix_filename(prefix, template_file); + if (force_author && !strchr(force_author, '>')) + force_author = find_author_by_nickname(force_author); + if (logfile || message.len || use_message) use_editor = 0; if (edit_flag) @@ -882,7 +910,7 @@ static void print_summary(const char *prefix, const unsigned char *sha1) if (!log_tree_commit(&rev, commit)) { struct strbuf buf = STRBUF_INIT; - format_commit_message(commit, "%h: %s", &buf); + format_commit_message(commit, "%h: %s", &buf, DATE_NORMAL); printf("%s\n", buf.buf); strbuf_release(&buf); } diff --git a/builtin-count-objects.c b/builtin-count-objects.c index 91b5487478..ab35b65b07 100644 --- a/builtin-count-objects.c +++ b/builtin-count-objects.c @@ -43,7 +43,7 @@ static void count_objects(DIR *d, char *path, int len, int verbose, if (lstat(path, &st) || !S_ISREG(st.st_mode)) bad = 1; else - (*loose_size) += xsize_t(st.st_blocks); + (*loose_size) += xsize_t(on_disk_bytes(st)); } if (bad) { if (verbose) { @@ -104,6 +104,7 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix) if (verbose) { struct packed_git *p; unsigned long num_pack = 0; + unsigned long size_pack = 0; if (!packed_git) prepare_packed_git(); for (p = packed_git; p; p = p->next) { @@ -112,17 +113,19 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix) if (open_pack_index(p)) continue; packed += p->num_objects; + size_pack += p->pack_size + p->index_size; num_pack++; } printf("count: %lu\n", loose); - printf("size: %lu\n", loose_size / 2); + printf("size: %lu\n", loose_size / 1024); printf("in-pack: %lu\n", packed); printf("packs: %lu\n", num_pack); + printf("size-pack: %lu\n", size_pack / 1024); printf("prune-packable: %lu\n", packed_loose); printf("garbage: %lu\n", garbage); } else printf("%lu objects, %lu kilobytes\n", - loose, loose_size / 2); + loose, loose_size / 1024); return 0; } diff --git a/builtin-diff-index.c b/builtin-diff-index.c index 17d851b29e..04837494fe 100644 --- a/builtin-diff-index.c +++ b/builtin-diff-index.c @@ -39,6 +39,8 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix) if (rev.pending.nr != 1 || rev.max_count != -1 || rev.min_age != -1 || rev.max_age != -1) usage(diff_cache_usage); + if (!cached) + setup_work_tree(); if (read_cache() < 0) { perror("read_cache"); return -1; diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c index 415cb1612f..8ecefd4f0f 100644 --- a/builtin-diff-tree.c +++ b/builtin-diff-tree.c @@ -14,20 +14,10 @@ static int diff_tree_commit_sha1(const unsigned char *sha1) return log_tree_commit(&log_tree_opt, commit); } -static int diff_tree_stdin(char *line) +/* Diff one or more commits. */ +static int stdin_diff_commit(struct commit *commit, char *line, int len) { - int len = strlen(line); unsigned char sha1[20]; - struct commit *commit; - - if (!len || line[len-1] != '\n') - return -1; - line[len-1] = 0; - if (get_sha1_hex(line, sha1)) - return -1; - commit = lookup_commit(sha1); - if (!commit || parse_commit(commit)) - return -1; if (isspace(line[40]) && !get_sha1_hex(line+41, sha1)) { /* Graft the fake parents locally to the commit */ int pos = 41; @@ -52,6 +42,49 @@ static int diff_tree_stdin(char *line) return log_tree_commit(&log_tree_opt, commit); } +/* Diff two trees. */ +static int stdin_diff_trees(struct tree *tree1, char *line, int len) +{ + unsigned char sha1[20]; + struct tree *tree2; + if (len != 82 || !isspace(line[40]) || get_sha1_hex(line + 41, sha1)) + return error("Need exactly two trees, separated by a space"); + tree2 = lookup_tree(sha1); + if (!tree2 || parse_tree(tree2)) + return -1; + printf("%s %s\n", sha1_to_hex(tree1->object.sha1), + sha1_to_hex(tree2->object.sha1)); + diff_tree_sha1(tree1->object.sha1, tree2->object.sha1, + "", &log_tree_opt.diffopt); + log_tree_diff_flush(&log_tree_opt); + return 0; +} + +static int diff_tree_stdin(char *line) +{ + int len = strlen(line); + unsigned char sha1[20]; + struct object *obj; + + if (!len || line[len-1] != '\n') + return -1; + line[len-1] = 0; + if (get_sha1_hex(line, sha1)) + return -1; + obj = lookup_unknown_object(sha1); + if (!obj || !obj->parsed) + obj = parse_object(sha1); + if (!obj) + return -1; + if (obj->type == OBJ_COMMIT) + return stdin_diff_commit((struct commit *)obj, line, len); + if (obj->type == OBJ_TREE) + return stdin_diff_trees((struct tree *)obj, line, len); + error("Object %s is a %s, not a commit or tree", + sha1_to_hex(sha1), typename(obj->type)); + return -1; +} + static const char diff_tree_usage[] = "git diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] [--pretty] [-t] [-r] [--root] " "[<common diff options>] <tree-ish> [<tree-ish>] [<path>...]\n" diff --git a/builtin-diff.c b/builtin-diff.c index 7ffea97505..037c3039a4 100644 --- a/builtin-diff.c +++ b/builtin-diff.c @@ -122,6 +122,8 @@ static int builtin_diff_index(struct rev_info *revs, usage(builtin_diff_usage); argv++; argc--; } + if (!cached) + setup_work_tree(); /* * Make sure there is one revision (i.e. pending object), * and there is no revision filtering parameters. @@ -225,6 +227,7 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv (revs->diffopt.output_format & DIFF_FORMAT_PATCH)) revs->combine_merges = revs->dense_combined_merges = 1; + setup_work_tree(); if (read_cache() < 0) { perror("read_cache"); return -1; diff --git a/builtin-fast-export.c b/builtin-fast-export.c index 070971616d..7c93eb878d 100644 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -417,7 +417,8 @@ static void export_marks(char *file) for (i = 0; i < idnums.size; i++) { if (deco->base && deco->base->type == 1) { mark = ptr_to_mark(deco->decoration); - fprintf(f, ":%u %s\n", mark, sha1_to_hex(deco->base->sha1)); + fprintf(f, ":%"PRIu32" %s\n", mark, + sha1_to_hex(deco->base->sha1)); } deco++; } diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c index 273239af3b..4dfef29bcd 100644 --- a/builtin-fetch-pack.c +++ b/builtin-fetch-pack.c @@ -540,7 +540,7 @@ static int get_pack(int xd[2], char **pack_lockfile) *av++ = "--fix-thin"; if (args.lock_pack || unpack_limit) { int s = sprintf(keep_arg, - "--keep=fetch-pack %d on ", getpid()); + "--keep=fetch-pack %"PRIuMAX " on ", (uintmax_t) getpid()); if (gethostname(keep_arg + s, sizeof(keep_arg) - s)) strcpy(keep_arg + s, "localhost"); *av++ = keep_arg; @@ -609,7 +609,7 @@ static struct ref *do_fetch_pack(int fd[2], fprintf(stderr, "warning: no common commits\n"); if (get_pack(fd, pack_lockfile)) - die("git-fetch-pack: fetch failed."); + die("git fetch-pack: fetch failed."); all_done: return ref; @@ -750,7 +750,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix) if (!ret && nr_heads) { /* If the heads to pull were given, we should have * consumed all of them by matching the remote. - * Otherwise, 'git-fetch remote no-such-ref' would + * Otherwise, 'git fetch remote no-such-ref' would * silently succeed without issuing an error. */ for (i = 0; i < nr_heads; i++) diff --git a/builtin-fetch.c b/builtin-fetch.c index 7eec4a0e43..ee93d3a93d 100644 --- a/builtin-fetch.c +++ b/builtin-fetch.c @@ -86,10 +86,10 @@ static void add_merge_config(struct ref **head, /* * Not fetched to a tracking branch? We need to fetch * it anyway to allow this branch's "branch.$name.merge" - * to be honored by git-pull, but we do not have to + * to be honored by 'git pull', but we do not have to * fail if branch.$name.merge is misconfigured to point * at a nonexisting branch. If we were indeed called by - * git-pull, it will notice the misconfiguration because + * 'git pull', it will notice the misconfiguration because * there is no entry in the resulting FETCH_HEAD marked * for merging. */ @@ -396,7 +396,7 @@ static int store_updated_refs(const char *url, const char *remote_name, * The refs we are going to fetch are in to_fetch (nr_heads in * total). If running * - * $ git-rev-list --objects to_fetch[0] to_fetch[1] ... --not --all + * $ git rev-list --objects to_fetch[0] to_fetch[1] ... --not --all * * does not error out, that means everything reachable from the * refs we are going to fetch exists and is connected to some of diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c index 4d25ec51d0..21e92bbcb5 100644 --- a/builtin-for-each-ref.c +++ b/builtin-for-each-ref.c @@ -652,7 +652,8 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f if ((plen <= namelen) && !strncmp(refname, p, plen) && (refname[plen] == '\0' || - refname[plen] == '/')) + refname[plen] == '/' || + p[plen-1] == '/')) break; if (!fnmatch(p, refname, FNM_PATHNAME)) break; diff --git a/builtin-grep.c b/builtin-grep.c index 631129ddfd..3a51662a35 100644 --- a/builtin-grep.c +++ b/builtin-grep.c @@ -774,7 +774,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix) /* Make sure we do not get outside of paths */ for (i = 0; paths[i]; i++) if (strncmp(prefix, paths[i], opt.prefix_length)) - die("git-grep: cannot generate relative filenames containing '..'"); + die("git grep: cannot generate relative filenames containing '..'"); } } else if (prefix) { @@ -783,8 +783,11 @@ int cmd_grep(int argc, const char **argv, const char *prefix) paths[1] = NULL; } - if (!list.nr) + if (!list.nr) { + if (!cached) + setup_work_tree(); return !grep_cache(&opt, paths, cached); + } if (cached) die("both --cached and trees are given."); diff --git a/builtin-help.c b/builtin-help.c new file mode 100644 index 0000000000..64207cbfe9 --- /dev/null +++ b/builtin-help.c @@ -0,0 +1,465 @@ +/* + * builtin-help.c + * + * Builtin help command + */ +#include "cache.h" +#include "builtin.h" +#include "exec_cmd.h" +#include "common-cmds.h" +#include "parse-options.h" +#include "run-command.h" +#include "help.h" + +static struct man_viewer_list { + struct man_viewer_list *next; + char name[FLEX_ARRAY]; +} *man_viewer_list; + +static struct man_viewer_info_list { + struct man_viewer_info_list *next; + const char *info; + char name[FLEX_ARRAY]; +} *man_viewer_info_list; + +enum help_format { + HELP_FORMAT_MAN, + HELP_FORMAT_INFO, + HELP_FORMAT_WEB, +}; + +static int show_all = 0; +static enum help_format help_format = HELP_FORMAT_MAN; +static struct option builtin_help_options[] = { + OPT_BOOLEAN('a', "all", &show_all, "print all available commands"), + OPT_SET_INT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN), + OPT_SET_INT('w', "web", &help_format, "show manual in web browser", + HELP_FORMAT_WEB), + OPT_SET_INT('i', "info", &help_format, "show info page", + HELP_FORMAT_INFO), + OPT_END(), +}; + +static const char * const builtin_help_usage[] = { + "git help [--all] [--man|--web|--info] [command]", + NULL +}; + +static enum help_format parse_help_format(const char *format) +{ + if (!strcmp(format, "man")) + return HELP_FORMAT_MAN; + if (!strcmp(format, "info")) + return HELP_FORMAT_INFO; + if (!strcmp(format, "web") || !strcmp(format, "html")) + return HELP_FORMAT_WEB; + die("unrecognized help format '%s'", format); +} + +static const char *get_man_viewer_info(const char *name) +{ + struct man_viewer_info_list *viewer; + + for (viewer = man_viewer_info_list; viewer; viewer = viewer->next) + { + if (!strcasecmp(name, viewer->name)) + return viewer->info; + } + return NULL; +} + +static int check_emacsclient_version(void) +{ + struct strbuf buffer = STRBUF_INIT; + struct child_process ec_process; + const char *argv_ec[] = { "emacsclient", "--version", NULL }; + int version; + + /* emacsclient prints its version number on stderr */ + memset(&ec_process, 0, sizeof(ec_process)); + ec_process.argv = argv_ec; + ec_process.err = -1; + ec_process.stdout_to_stderr = 1; + if (start_command(&ec_process)) { + fprintf(stderr, "Failed to start emacsclient.\n"); + return -1; + } + strbuf_read(&buffer, ec_process.err, 20); + close(ec_process.err); + + /* + * Don't bother checking return value, because "emacsclient --version" + * seems to always exits with code 1. + */ + finish_command(&ec_process); + + if (prefixcmp(buffer.buf, "emacsclient")) { + fprintf(stderr, "Failed to parse emacsclient version.\n"); + strbuf_release(&buffer); + return -1; + } + + strbuf_remove(&buffer, 0, strlen("emacsclient")); + version = atoi(buffer.buf); + + if (version < 22) { + fprintf(stderr, + "emacsclient version '%d' too old (< 22).\n", + version); + strbuf_release(&buffer); + return -1; + } + + strbuf_release(&buffer); + return 0; +} + +static void exec_woman_emacs(const char* path, const char *page) +{ + if (!check_emacsclient_version()) { + /* This works only with emacsclient version >= 22. */ + struct strbuf man_page = STRBUF_INIT; + + if (!path) + path = "emacsclient"; + strbuf_addf(&man_page, "(woman \"%s\")", page); + execlp(path, "emacsclient", "-e", man_page.buf, NULL); + warning("failed to exec '%s': %s", path, strerror(errno)); + } +} + +static void exec_man_konqueror(const char* path, const char *page) +{ + const char *display = getenv("DISPLAY"); + if (display && *display) { + struct strbuf man_page = STRBUF_INIT; + const char *filename = "kfmclient"; + + /* It's simpler to launch konqueror using kfmclient. */ + if (path) { + const char *file = strrchr(path, '/'); + if (file && !strcmp(file + 1, "konqueror")) { + char *new = xstrdup(path); + char *dest = strrchr(new, '/'); + + /* strlen("konqueror") == strlen("kfmclient") */ + strcpy(dest + 1, "kfmclient"); + path = new; + } + if (file) + filename = file; + } else + path = "kfmclient"; + strbuf_addf(&man_page, "man:%s(1)", page); + execlp(path, filename, "newTab", man_page.buf, NULL); + warning("failed to exec '%s': %s", path, strerror(errno)); + } +} + +static void exec_man_man(const char* path, const char *page) +{ + if (!path) + path = "man"; + execlp(path, "man", page, NULL); + warning("failed to exec '%s': %s", path, strerror(errno)); +} + +static void exec_man_cmd(const char *cmd, const char *page) +{ + struct strbuf shell_cmd = STRBUF_INIT; + strbuf_addf(&shell_cmd, "%s %s", cmd, page); + execl("/bin/sh", "sh", "-c", shell_cmd.buf, NULL); + warning("failed to exec '%s': %s", cmd, strerror(errno)); +} + +static void add_man_viewer(const char *name) +{ + struct man_viewer_list **p = &man_viewer_list; + size_t len = strlen(name); + + while (*p) + p = &((*p)->next); + *p = xcalloc(1, (sizeof(**p) + len + 1)); + strncpy((*p)->name, name, len); +} + +static int supported_man_viewer(const char *name, size_t len) +{ + return (!strncasecmp("man", name, len) || + !strncasecmp("woman", name, len) || + !strncasecmp("konqueror", name, len)); +} + +static void do_add_man_viewer_info(const char *name, + size_t len, + const char *value) +{ + struct man_viewer_info_list *new = xcalloc(1, sizeof(*new) + len + 1); + + strncpy(new->name, name, len); + new->info = xstrdup(value); + new->next = man_viewer_info_list; + man_viewer_info_list = new; +} + +static int add_man_viewer_path(const char *name, + size_t len, + const char *value) +{ + if (supported_man_viewer(name, len)) + do_add_man_viewer_info(name, len, value); + else + warning("'%s': path for unsupported man viewer.\n" + "Please consider using 'man.<tool>.cmd' instead.", + name); + + return 0; +} + +static int add_man_viewer_cmd(const char *name, + size_t len, + const char *value) +{ + if (supported_man_viewer(name, len)) + warning("'%s': cmd for supported man viewer.\n" + "Please consider using 'man.<tool>.path' instead.", + name); + else + do_add_man_viewer_info(name, len, value); + + return 0; +} + +static int add_man_viewer_info(const char *var, const char *value) +{ + const char *name = var + 4; + const char *subkey = strrchr(name, '.'); + + if (!subkey) + return error("Config with no key for man viewer: %s", name); + + if (!strcmp(subkey, ".path")) { + if (!value) + return config_error_nonbool(var); + return add_man_viewer_path(name, subkey - name, value); + } + if (!strcmp(subkey, ".cmd")) { + if (!value) + return config_error_nonbool(var); + return add_man_viewer_cmd(name, subkey - name, value); + } + + warning("'%s': unsupported man viewer sub key.", subkey); + return 0; +} + +static int git_help_config(const char *var, const char *value, void *cb) +{ + if (!strcmp(var, "help.format")) { + if (!value) + return config_error_nonbool(var); + help_format = parse_help_format(value); + return 0; + } + if (!strcmp(var, "man.viewer")) { + if (!value) + return config_error_nonbool(var); + add_man_viewer(value); + return 0; + } + if (!prefixcmp(var, "man.")) + return add_man_viewer_info(var, value); + + return git_default_config(var, value, cb); +} + +static struct cmdnames main_cmds, other_cmds; + +void list_common_cmds_help(void) +{ + int i, longest = 0; + + for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { + if (longest < strlen(common_cmds[i].name)) + longest = strlen(common_cmds[i].name); + } + + puts("The most commonly used git commands are:"); + for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { + printf(" %s ", common_cmds[i].name); + mput_char(' ', longest - strlen(common_cmds[i].name)); + puts(common_cmds[i].help); + } +} + +static int is_git_command(const char *s) +{ + return is_in_cmdlist(&main_cmds, s) || + is_in_cmdlist(&other_cmds, s); +} + +static const char *prepend(const char *prefix, const char *cmd) +{ + size_t pre_len = strlen(prefix); + size_t cmd_len = strlen(cmd); + char *p = xmalloc(pre_len + cmd_len + 1); + memcpy(p, prefix, pre_len); + strcpy(p + pre_len, cmd); + return p; +} + +static const char *cmd_to_page(const char *git_cmd) +{ + if (!git_cmd) + return "git"; + else if (!prefixcmp(git_cmd, "git")) + return git_cmd; + else if (is_git_command(git_cmd)) + return prepend("git-", git_cmd); + else + return prepend("git", git_cmd); +} + +static void setup_man_path(void) +{ + struct strbuf new_path; + const char *old_path = getenv("MANPATH"); + + strbuf_init(&new_path, 0); + + /* We should always put ':' after our path. If there is no + * old_path, the ':' at the end will let 'man' to try + * system-wide paths after ours to find the manual page. If + * there is old_path, we need ':' as delimiter. */ + strbuf_addstr(&new_path, GIT_MAN_PATH); + strbuf_addch(&new_path, ':'); + if (old_path) + strbuf_addstr(&new_path, old_path); + + setenv("MANPATH", new_path.buf, 1); + + strbuf_release(&new_path); +} + +static void exec_viewer(const char *name, const char *page) +{ + const char *info = get_man_viewer_info(name); + + if (!strcasecmp(name, "man")) + exec_man_man(info, page); + else if (!strcasecmp(name, "woman")) + exec_woman_emacs(info, page); + else if (!strcasecmp(name, "konqueror")) + exec_man_konqueror(info, page); + else if (info) + exec_man_cmd(info, page); + else + warning("'%s': unknown man viewer.", name); +} + +static void show_man_page(const char *git_cmd) +{ + struct man_viewer_list *viewer; + const char *page = cmd_to_page(git_cmd); + const char *fallback = getenv("GIT_MAN_VIEWER"); + + setup_man_path(); + for (viewer = man_viewer_list; viewer; viewer = viewer->next) + { + exec_viewer(viewer->name, page); /* will return when unable */ + } + if (fallback) + exec_viewer(fallback, page); + exec_viewer("man", page); + die("no man viewer handled the request"); +} + +static void show_info_page(const char *git_cmd) +{ + const char *page = cmd_to_page(git_cmd); + setenv("INFOPATH", GIT_INFO_PATH, 1); + execlp("info", "info", "gitman", page, NULL); +} + +static void get_html_page_path(struct strbuf *page_path, const char *page) +{ + struct stat st; + const char *html_path = system_path(GIT_HTML_PATH); + + /* Check that we have a git documentation directory. */ + if (stat(mkpath("%s/git.html", html_path), &st) + || !S_ISREG(st.st_mode)) + die("'%s': not a documentation directory.", html_path); + + strbuf_init(page_path, 0); + strbuf_addf(page_path, "%s/%s.html", html_path, page); +} + +/* + * If open_html is not defined in a platform-specific way (see for + * example compat/mingw.h), we use the script web--browse to display + * HTML. + */ +#ifndef open_html +void open_html(const char *path) +{ + execl_git_cmd("web--browse", "-c", "help.browser", path, NULL); +} +#endif + +static void show_html_page(const char *git_cmd) +{ + const char *page = cmd_to_page(git_cmd); + struct strbuf page_path; /* it leaks but we exec bellow */ + + get_html_page_path(&page_path, page); + + open_html(page_path.buf); +} + +int cmd_help(int argc, const char **argv, const char *prefix) +{ + int nongit; + const char *alias; + load_command_list("git-", &main_cmds, &other_cmds); + + setup_git_directory_gently(&nongit); + git_config(git_help_config, NULL); + + argc = parse_options(argc, argv, builtin_help_options, + builtin_help_usage, 0); + + if (show_all) { + printf("usage: %s\n\n", git_usage_string); + list_commands("git commands", &main_cmds, &other_cmds); + printf("%s\n", git_more_info_string); + return 0; + } + + if (!argv[0]) { + printf("usage: %s\n\n", git_usage_string); + list_common_cmds_help(); + printf("\n%s\n", git_more_info_string); + return 0; + } + + alias = alias_lookup(argv[0]); + if (alias && !is_git_command(argv[0])) { + printf("`git %s' is aliased to `%s'\n", argv[0], alias); + return 0; + } + + switch (help_format) { + case HELP_FORMAT_MAN: + show_man_page(argv[0]); + break; + case HELP_FORMAT_INFO: + show_info_page(argv[0]); + break; + case HELP_FORMAT_WEB: + show_html_page(argv[0]); + break; + } + + return 0; +} diff --git a/builtin-http-fetch.c b/builtin-http-fetch.c index 3a062487a7..f3e63d7206 100644 --- a/builtin-http-fetch.c +++ b/builtin-http-fetch.c @@ -42,7 +42,7 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix) arg++; } if (argc < arg + 2 - commits_on_stdin) { - usage("git-http-fetch [-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin] commit-id url"); + usage("git http-fetch [-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin] commit-id url"); return 1; } if (commits_on_stdin) { @@ -53,7 +53,7 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix) } url = argv[arg]; if (url && url[strlen(url)-1] != '/') { - rewritten_url = malloc(strlen(url)+2); + rewritten_url = xmalloc(strlen(url)+2); strcpy(rewritten_url, url); strcat(rewritten_url, "/"); url = rewritten_url; @@ -75,7 +75,7 @@ int cmd_http_fetch(int argc, const char **argv, const char *prefix) fprintf(stderr, "Some loose object were found to be corrupt, but they might be just\n" "a false '404 Not Found' error message sent with incorrect HTTP\n" -"status code. Suggest running git-fsck.\n"); +"status code. Suggest running 'git fsck'.\n"); } walker_free(walker); diff --git a/builtin-log.c b/builtin-log.c index 911fd65990..1d3c5cbf58 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -217,6 +217,11 @@ static int cmd_log_walk(struct rev_info *rev) if (rev->early_output) finish_early_output(rev); + /* + * For --check and --exit-code, the exit code is based on CHECK_FAILED + * and HAS_CHANGES being accumulated in rev->diffopt, so be careful to + * retain that state information if replacing rev->diffopt in this loop + */ while ((commit = get_revision(rev)) != NULL) { log_tree_commit(rev, commit); if (!rev->reflog_info) { @@ -227,7 +232,11 @@ static int cmd_log_walk(struct rev_info *rev) free_commit_list(commit->parents); commit->parents = NULL; } - return 0; + if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF && + DIFF_OPT_TST(&rev->diffopt, CHECK_FAILED)) { + return 02; + } + return diff_result_code(&rev->diffopt, 0); } static int git_log_config(const char *var, const char *value, void *cb) @@ -923,7 +932,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) if (argc > 1) die ("unrecognized argument: %s", argv[1]); - if (!rev.diffopt.output_format) + if (!rev.diffopt.output_format + || rev.diffopt.output_format == DIFF_FORMAT_PATCH) rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_SUMMARY | DIFF_FORMAT_PATCH; if (!DIFF_OPT_TST(&rev.diffopt, TEXT) && !no_binary_diff) diff --git a/builtin-ls-files.c b/builtin-ls-files.c index e8d568eed7..068f424696 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -78,7 +78,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent) int offset = prefix_offset; if (len >= ent->len) - die("git-ls-files: internal error - directory entry not superset of prefix"); + die("git ls-files: internal error - directory entry not superset of prefix"); if (pathspec && !pathspec_match(pathspec, ps_matched, ent->name, len)) return; @@ -183,7 +183,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce) int offset = prefix_offset; if (len >= ce_namelen(ce)) - die("git-ls-files: internal error - cache entry not superset of prefix"); + die("git ls-files: internal error - cache entry not superset of prefix"); if (pathspec && !pathspec_match(pathspec, ps_matched, ce->name, len)) return; @@ -319,7 +319,7 @@ static const char *verify_pathspec(const char *prefix) } if (prefix_offset > max || memcmp(prev, prefix, prefix_offset)) - die("git-ls-files: cannot generate relative filenames containing '..'"); + die("git ls-files: cannot generate relative filenames containing '..'"); prefix_len = max; return max ? xmemdupz(prev, max) : NULL; diff --git a/builtin-merge-base.c b/builtin-merge-base.c index 3382b1382a..b08da516e4 100644 --- a/builtin-merge-base.c +++ b/builtin-merge-base.c @@ -2,9 +2,11 @@ #include "cache.h" #include "commit.h" -static int show_merge_base(struct commit *rev1, struct commit *rev2, int show_all) +static int show_merge_base(struct commit **rev, int rev_nr, int show_all) { - struct commit_list *result = get_merge_bases(rev1, rev2, 0); + struct commit_list *result; + + result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1, 0); if (!result) return 1; @@ -20,7 +22,7 @@ static int show_merge_base(struct commit *rev1, struct commit *rev2, int show_al } static const char merge_base_usage[] = -"git merge-base [--all] <commit-id> <commit-id>"; +"git merge-base [--all] <commit-id> <commit-id>..."; static struct commit *get_commit_reference(const char *arg) { @@ -38,7 +40,8 @@ static struct commit *get_commit_reference(const char *arg) int cmd_merge_base(int argc, const char **argv, const char *prefix) { - struct commit *rev1, *rev2; + struct commit **rev; + int rev_nr = 0; int show_all = 0; git_config(git_default_config, NULL); @@ -51,10 +54,15 @@ int cmd_merge_base(int argc, const char **argv, const char *prefix) usage(merge_base_usage); argc--; argv++; } - if (argc != 3) + if (argc < 3) usage(merge_base_usage); - rev1 = get_commit_reference(argv[1]); - rev2 = get_commit_reference(argv[2]); - return show_merge_base(rev1, rev2, show_all); + rev = xmalloc((argc - 1) * sizeof(*rev)); + + do { + rev[rev_nr++] = get_commit_reference(argv[1]); + argc--; argv++; + } while (argc > 1); + + return show_merge_base(rev, rev_nr, show_all); } diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c index 43e55bf901..dfb363ee2f 100644 --- a/builtin-merge-recursive.c +++ b/builtin-merge-recursive.c @@ -729,13 +729,13 @@ static void conflict_rename_rename(struct rename *ren1, const char *dst_name2 = ren2_dst; if (string_list_has_string(¤t_directory_set, ren1_dst)) { dst_name1 = del[delp++] = unique_path(ren1_dst, branch1); - output(1, "%s is a directory in %s added as %s instead", + output(1, "%s is a directory in %s adding as %s instead", ren1_dst, branch2, dst_name1); remove_file(0, ren1_dst, 0); } if (string_list_has_string(¤t_directory_set, ren2_dst)) { dst_name2 = del[delp++] = unique_path(ren2_dst, branch2); - output(1, "%s is a directory in %s added as %s instead", + output(1, "%s is a directory in %s adding as %s instead", ren2_dst, branch1, dst_name2); remove_file(0, ren2_dst, 0); } @@ -760,7 +760,7 @@ static void conflict_rename_dir(struct rename *ren1, const char *branch1) { char *new_path = unique_path(ren1->pair->two->path, branch1); - output(1, "Renamed %s to %s instead", ren1->pair->one->path, new_path); + output(1, "Renaming %s to %s instead", ren1->pair->one->path, new_path); remove_file(0, ren1->pair->two->path, 0); update_file(0, ren1->pair->two->sha1, ren1->pair->two->mode, new_path); free(new_path); @@ -773,7 +773,7 @@ static void conflict_rename_rename_2(struct rename *ren1, { char *new_path1 = unique_path(ren1->pair->two->path, branch1); char *new_path2 = unique_path(ren2->pair->two->path, branch2); - output(1, "Renamed %s to %s and %s to %s instead", + output(1, "Renaming %s to %s and %s to %s instead", ren1->pair->one->path, new_path1, ren2->pair->one->path, new_path2); remove_file(0, ren1->pair->two->path, 0); @@ -887,10 +887,10 @@ static int process_renames(struct string_list *a_renames, branch1, branch2); if (mfi.merge || !mfi.clean) - output(1, "Renamed %s->%s", src, ren1_dst); + output(1, "Renaming %s->%s", src, ren1_dst); if (mfi.merge) - output(2, "Auto-merged %s", ren1_dst); + output(2, "Auto-merging %s", ren1_dst); if (!mfi.clean) { output(1, "CONFLICT (content): merge conflict in %s", @@ -924,14 +924,14 @@ static int process_renames(struct string_list *a_renames, if (string_list_has_string(¤t_directory_set, ren1_dst)) { clean_merge = 0; - output(1, "CONFLICT (rename/directory): Renamed %s->%s in %s " + output(1, "CONFLICT (rename/directory): Rename %s->%s in %s " " directory %s added in %s", ren1_src, ren1_dst, branch1, ren1_dst, branch2); conflict_rename_dir(ren1, branch1); } else if (sha_eq(src_other.sha1, null_sha1)) { clean_merge = 0; - output(1, "CONFLICT (rename/delete): Renamed %s->%s in %s " + output(1, "CONFLICT (rename/delete): Rename %s->%s in %s " "and deleted in %s", ren1_src, ren1_dst, branch1, branch2); @@ -940,19 +940,19 @@ static int process_renames(struct string_list *a_renames, const char *new_path; clean_merge = 0; try_merge = 1; - output(1, "CONFLICT (rename/add): Renamed %s->%s in %s. " + output(1, "CONFLICT (rename/add): Rename %s->%s in %s. " "%s added in %s", ren1_src, ren1_dst, branch1, ren1_dst, branch2); new_path = unique_path(ren1_dst, branch2); - output(1, "Added as %s instead", new_path); + output(1, "Adding as %s instead", new_path); update_file(0, dst_other.sha1, dst_other.mode, new_path); } else if ((item = string_list_lookup(ren1_dst, renames2Dst))) { ren2 = item->util; clean_merge = 0; ren2->processed = 1; - output(1, "CONFLICT (rename/rename): Renamed %s->%s in %s. " - "Renamed %s->%s in %s", + output(1, "CONFLICT (rename/rename): Rename %s->%s in %s. " + "Rename %s->%s in %s", ren1_src, ren1_dst, branch1, ren2->pair->one->path, ren2->pair->two->path, branch2); conflict_rename_rename_2(ren1, branch1, ren2, branch2); @@ -986,9 +986,9 @@ static int process_renames(struct string_list *a_renames, output(3, "Skipped %s (merged same as existing)", ren1_dst); else { if (mfi.merge || !mfi.clean) - output(1, "Renamed %s => %s", ren1_src, ren1_dst); + output(1, "Renaming %s => %s", ren1_src, ren1_dst); if (mfi.merge) - output(2, "Auto-merged %s", ren1_dst); + output(2, "Auto-merging %s", ren1_dst); if (!mfi.clean) { output(1, "CONFLICT (rename/modify): Merge conflict in %s", ren1_dst); @@ -1039,7 +1039,7 @@ static int process_entry(const char *path, struct stage_data *entry, /* Deleted in both or deleted in one and * unchanged in the other */ if (a_sha) - output(2, "Removed %s", path); + output(2, "Removing %s", path); /* do not touch working file if it did not exist */ remove_file(1, path, !a_sha); } else { @@ -1086,12 +1086,12 @@ static int process_entry(const char *path, struct stage_data *entry, const char *new_path = unique_path(path, add_branch); clean_merge = 0; output(1, "CONFLICT (%s): There is a directory with name %s in %s. " - "Added %s as %s", + "Adding %s as %s", conf, path, other_branch, path, new_path); remove_file(0, path, 0); update_file(0, sha, mode, new_path); } else { - output(2, "Added %s", path); + output(2, "Adding %s", path); update_file(1, sha, mode, path); } } else if (a_sha && b_sha) { @@ -1105,7 +1105,7 @@ static int process_entry(const char *path, struct stage_data *entry, reason = "add/add"; o_sha = (unsigned char *)null_sha1; } - output(2, "Auto-merged %s", path); + output(2, "Auto-merging %s", path); o.path = a.path = b.path = (char *)path; hashcpy(o.sha1, o_sha); o.mode = o_mode; diff --git a/builtin-merge.c b/builtin-merge.c index a201c6628d..9ad9791068 100644 --- a/builtin-merge.c +++ b/builtin-merge.c @@ -22,6 +22,7 @@ #include "log-tree.h" #include "color.h" #include "rerere.h" +#include "help.h" #define DEFAULT_TWOHEAD (1<<0) #define DEFAULT_OCTOPUS (1<<1) @@ -77,7 +78,9 @@ static int option_parse_message(const struct option *opt, static struct strategy *get_strategy(const char *name) { int i; - struct strbuf err; + struct strategy *ret; + static struct cmdnames main_cmds, other_cmds; + static int loaded; if (!name) return NULL; @@ -86,12 +89,43 @@ static struct strategy *get_strategy(const char *name) if (!strcmp(name, all_strategy[i].name)) return &all_strategy[i]; - strbuf_init(&err, 0); - for (i = 0; i < ARRAY_SIZE(all_strategy); i++) - strbuf_addf(&err, " %s", all_strategy[i].name); - fprintf(stderr, "Could not find merge strategy '%s'.\n", name); - fprintf(stderr, "Available strategies are:%s.\n", err.buf); - exit(1); + if (!loaded) { + struct cmdnames not_strategies; + loaded = 1; + + memset(¬_strategies, 0, sizeof(struct cmdnames)); + load_command_list("git-merge-", &main_cmds, &other_cmds); + for (i = 0; i < main_cmds.cnt; i++) { + int j, found = 0; + struct cmdname *ent = main_cmds.names[i]; + for (j = 0; j < ARRAY_SIZE(all_strategy); j++) + if (!strncmp(ent->name, all_strategy[j].name, ent->len) + && !all_strategy[j].name[ent->len]) + found = 1; + if (!found) + add_cmdname(¬_strategies, ent->name, ent->len); + exclude_cmds(&main_cmds, ¬_strategies); + } + } + if (!is_in_cmdlist(&main_cmds, name) && !is_in_cmdlist(&other_cmds, name)) { + fprintf(stderr, "Could not find merge strategy '%s'.\n", name); + fprintf(stderr, "Available strategies are:"); + for (i = 0; i < main_cmds.cnt; i++) + fprintf(stderr, " %s", main_cmds.names[i]->name); + fprintf(stderr, ".\n"); + if (other_cmds.cnt) { + fprintf(stderr, "Available custom strategies are:"); + for (i = 0; i < other_cmds.cnt; i++) + fprintf(stderr, " %s", other_cmds.names[i]->name); + fprintf(stderr, ".\n"); + } + exit(1); + } + + ret = xmalloc(sizeof(struct strategy)); + memset(ret, 0, sizeof(struct strategy)); + ret->name = xstrdup(name); + return ret; } static void append_strategy(struct strategy *s) @@ -564,8 +598,6 @@ static int checkout_fast_forward(unsigned char *head, unsigned char *remote) struct dir_struct dir; struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file)); - if (read_cache_unmerged()) - die("you need to resolve your current index first"); refresh_cache(REFRESH_QUIET); fd = hold_locked_index(lock_file, 1); @@ -651,13 +683,15 @@ static void add_strategies(const char *string, unsigned attr) static int merge_trivial(void) { unsigned char result_tree[20], result_commit[20]; - struct commit_list parent; + struct commit_list *parent = xmalloc(sizeof(struct commit_list *)); write_tree_trivial(result_tree); printf("Wonderful.\n"); - parent.item = remoteheads->item; - parent.next = NULL; - commit_tree(merge_msg.buf, result_tree, &parent, result_commit); + parent->item = lookup_commit(head); + parent->next = xmalloc(sizeof(struct commit_list *)); + parent->next->item = remoteheads->item; + parent->next->next = NULL; + commit_tree(merge_msg.buf, result_tree, parent, result_commit); finish(result_commit, "In-index merge"); drop_save(); return 0; @@ -743,6 +777,7 @@ static int evaluate_result(void) int cnt = 0; struct rev_info rev; + discard_cache(); if (read_cache() < 0) die("failed to read the cache"); @@ -776,7 +811,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) struct commit_list **remotes = &remoteheads; setup_work_tree(); - if (unmerged_cache()) + if (read_cache_unmerged()) die("You are in the middle of a conflicted merge."); /* @@ -833,6 +868,11 @@ int cmd_merge(int argc, const char **argv, const char *prefix) if (argc != 1) die("Can merge only exactly one commit into " "empty head"); + if (squash) + die("Squash commit into empty head not supported yet"); + if (!allow_fast_forward) + die("Non-fast-forward commit does not make sense into " + "an empty head"); remote_head = peel_to_type(argv[0], 0, NULL, OBJ_COMMIT); if (!remote_head) die("%s - not something we can merge", argv[0]); @@ -1073,6 +1113,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) } /* Automerge succeeded. */ + discard_cache(); write_tree_trivial(result_tree); automerge_was_ok = 1; break; diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 2dadec1630..ba2cf00f5e 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -410,25 +410,22 @@ static unsigned long write_object(struct sha1file *f, return hdrlen + datalen; } -static off_t write_one(struct sha1file *f, +static int write_one(struct sha1file *f, struct object_entry *e, - off_t offset) + off_t *offset) { unsigned long size; /* offset is non zero if object is written already. */ if (e->idx.offset || e->preferred_base) - return offset; + return 1; /* if we are deltified, write out base object first. */ - if (e->delta) { - offset = write_one(f, e->delta, offset); - if (!offset) - return 0; - } + if (e->delta && !write_one(f, e->delta, offset)) + return 0; - e->idx.offset = offset; - size = write_object(f, e, offset); + e->idx.offset = *offset; + size = write_object(f, e, *offset); if (!size) { e->idx.offset = 0; return 0; @@ -436,9 +433,10 @@ static off_t write_one(struct sha1file *f, written_list[nr_written++] = &e->idx; /* make sure off_t is sufficiently large not to wrap */ - if (offset > offset + size) + if (*offset > *offset + size) die("pack too large for current definition of off_t"); - return offset + size; + *offset += size; + return 1; } /* forward declaration for write_pack_file */ @@ -448,7 +446,7 @@ static void write_pack_file(void) { uint32_t i = 0, j; struct sha1file *f; - off_t offset, offset_one, last_obj_offset = 0; + off_t offset; struct pack_header hdr; uint32_t nr_remaining = nr_result; time_t last_mtime = 0; @@ -480,11 +478,8 @@ static void write_pack_file(void) offset = sizeof(hdr); nr_written = 0; for (; i < nr_objects; i++) { - last_obj_offset = offset; - offset_one = write_one(f, objects + i, offset); - if (!offset_one) + if (!write_one(f, objects + i, &offset)) break; - offset = offset_one; display_progress(progress_state, written); } @@ -497,9 +492,9 @@ static void write_pack_file(void) } else if (nr_written == nr_remaining) { sha1close(f, sha1, CSUM_FSYNC); } else { - int fd = sha1close(f, NULL, 0); - fixup_pack_header_footer(fd, sha1, pack_tmp_name, nr_written); - fsync_or_die(fd, pack_tmp_name); + int fd = sha1close(f, sha1, 0); + fixup_pack_header_footer(fd, sha1, pack_tmp_name, + nr_written, sha1, offset); close(fd); } @@ -1096,9 +1091,12 @@ static void check_object(struct object_entry *entry) } entry->type = sha1_object_info(entry->idx.sha1, &entry->size); - if (entry->type < 0) - die("unable to get type of object %s", - sha1_to_hex(entry->idx.sha1)); + /* + * The error condition is checked in prepare_pack(). This is + * to permit a missing preferred base object to be ignored + * as a preferred base. Doing so can result in a larger + * pack file, but the transfer will still take place. + */ } static int pack_offset_sort(const void *_a, const void *_b) @@ -1722,8 +1720,12 @@ static void prepare_pack(int window, int depth) if (entry->no_try_delta) continue; - if (!entry->preferred_base) + if (!entry->preferred_base) { nr_deltas++; + if (entry->type < 0) + die("unable to get type of object %s", + sha1_to_hex(entry->idx.sha1)); + } delta_list[n++] = entry; } diff --git a/builtin-push.c b/builtin-push.c index c1ed68d938..cc6666f75e 100644 --- a/builtin-push.c +++ b/builtin-push.c @@ -59,8 +59,17 @@ static int do_push(const char *repo, int flags) if (remote->mirror) flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE); - if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) && refspec) - return -1; + if ((flags & TRANSPORT_PUSH_ALL) && refspec) { + if (!strcmp(*refspec, "refs/tags/*")) + return error("--all and --tags are incompatible"); + return error("--all can't be combined with refspecs"); + } + + if ((flags & TRANSPORT_PUSH_MIRROR) && refspec) { + if (!strcmp(*refspec, "refs/tags/*")) + return error("--mirror and --tags are incompatible"); + return error("--mirror can't be combined with refspecs"); + } if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) == (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) { diff --git a/builtin-read-tree.c b/builtin-read-tree.c index 72a6de302f..dddc3044b8 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -194,6 +194,8 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) usage(read_tree_usage); if ((opts.dir && !opts.update)) die("--exclude-per-directory is meaningless unless -u"); + if (opts.merge && !opts.index_only) + setup_work_tree(); if (opts.merge) { if (stage < 2) diff --git a/builtin-reflog.c b/builtin-reflog.c index 196fa03b7f..6b3667ef0e 100644 --- a/builtin-reflog.c +++ b/builtin-reflog.c @@ -540,11 +540,11 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix) free(collected.e); } - while (i < argc) { - const char *ref = argv[i++]; + for (; i < argc; i++) { + char *ref; unsigned char sha1[20]; - if (!resolve_ref(ref, sha1, 1, NULL)) { - status |= error("%s points nowhere!", ref); + if (!dwim_log(argv[i], strlen(argv[i]), sha1, &ref)) { + status |= error("%s points nowhere!", argv[i]); continue; } set_reflog_expiry_param(&cb, explicit_expiry, ref); diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 893762c80f..c023003b2b 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -645,7 +645,8 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) revs.diff) usage(rev_list_usage); - save_commit_buffer = revs.verbose_header || revs.grep_filter; + save_commit_buffer = revs.verbose_header || + revs.grep_filter.pattern_list; if (bisect_list) revs.limited = 1; diff --git a/builtin-revert.c b/builtin-revert.c index 27881e9493..36677053f8 100644 --- a/builtin-revert.c +++ b/builtin-revert.c @@ -11,6 +11,7 @@ #include "cache-tree.h" #include "diff.h" #include "revision.h" +#include "rerere.h" /* * This implements the builtins revert and cherry-pick. @@ -395,6 +396,7 @@ static int revert_or_cherry_pick(int argc, const char **argv) die ("Error wrapping up %s", defmsg); fprintf(stderr, "Automatic %s failed.%s\n", me, help_msg(commit->object.sha1)); + rerere(); exit(1); } if (commit_lock_file(&msg_file) < 0) diff --git a/builtin-rm.c b/builtin-rm.c index 0ed26bb8f1..6bd82111d2 100644 --- a/builtin-rm.c +++ b/builtin-rm.c @@ -221,7 +221,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix) printf("rm '%s'\n", path); if (remove_file_from_cache(path)) - die("git-rm: unable to remove %s", path); + die("git rm: unable to remove %s", path); } if (show_only) @@ -244,7 +244,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix) continue; } if (!removed) - die("git-rm: %s: %s", path, strerror(errno)); + die("git rm: %s: %s", path, strerror(errno)); } } diff --git a/builtin-show-ref.c b/builtin-show-ref.c index add16004f1..572b114119 100644 --- a/builtin-show-ref.c +++ b/builtin-show-ref.c @@ -62,7 +62,7 @@ match: * ref points at a nonexistent object. */ if (!has_sha1_file(sha1)) - die("git-show-ref: bad ref %s (%s)", refname, + die("git show-ref: bad ref %s (%s)", refname, sha1_to_hex(sha1)); if (quiet) @@ -82,12 +82,12 @@ match: else { obj = parse_object(sha1); if (!obj) - die("git-show-ref: bad ref %s (%s)", refname, + die("git show-ref: bad ref %s (%s)", refname, sha1_to_hex(sha1)); if (obj->type == OBJ_TAG) { obj = deref_tag(obj, refname, 0); if (!obj) - die("git-show-ref: bad tag at ref %s (%s)", refname, + die("git show-ref: bad tag at ref %s (%s)", refname, sha1_to_hex(sha1)); hex = find_unique_abbrev(obj->sha1, abbrev); printf("%s %s^{}\n", hex, refname); diff --git a/builtin-tar-tree.c b/builtin-tar-tree.c index f4bea4a322..cb7007e25f 100644 --- a/builtin-tar-tree.c +++ b/builtin-tar-tree.c @@ -76,7 +76,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix) n = read_in_full(0, buffer, HEADERSIZE); if (n < HEADERSIZE) - die("git-get-tar-commit-id: read error"); + die("git get-tar-commit-id: read error"); if (header->typeflag[0] != 'g') return 1; if (memcmp(content, "52 comment=", 11)) @@ -84,7 +84,7 @@ int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix) n = write_in_full(1, content + 11, 41); if (n < 41) - die("git-get-tar-commit-id: write error"); + die("git get-tar-commit-id: write error"); return 0; } diff --git a/builtin-update-index.c b/builtin-update-index.c index 38eb53ccba..ce83224756 100644 --- a/builtin-update-index.c +++ b/builtin-update-index.c @@ -194,6 +194,10 @@ static int process_path(const char *path) int len; struct stat st; + len = strlen(path); + if (has_symlink_leading_path(len, path)) + return error("'%s' is beyond a symbolic link", path); + /* * First things first: get the stat information, to decide * what to do about the pathname! @@ -201,7 +205,6 @@ static int process_path(const char *path) if (lstat(path, &st) < 0) return process_lstat_error(path, errno); - len = strlen(path); if (S_ISDIR(st.st_mode)) return process_directory(path, len, &st); @@ -262,7 +265,7 @@ static void chmod_path(int flip, const char *path) report("chmod %cx '%s'", flip, path); return; fail: - die("git-update-index: cannot chmod %cx '%s'", flip, path); + die("git update-index: cannot chmod %cx '%s'", flip, path); } static void update_one(const char *path, const char *prefix, int prefix_length) @@ -280,7 +283,7 @@ static void update_one(const char *path, const char *prefix, int prefix_length) if (force_remove) { if (remove_file_from_cache(p)) - die("git-update-index: unable to remove %s", path); + die("git update-index: unable to remove %s", path); report("remove '%s'", path); goto free_return; } @@ -351,7 +354,7 @@ static void read_index_info(int line_termination) if (line_termination && path_name[0] == '"') { strbuf_reset(&uq); if (unquote_c_style(&uq, path_name, NULL)) { - die("git-update-index: bad quoting of path name"); + die("git update-index: bad quoting of path name"); } path_name = uq.buf; } @@ -364,7 +367,7 @@ static void read_index_info(int line_termination) if (!mode) { /* mode == 0 means there is no such path -- remove */ if (remove_file_from_cache(path_name)) - die("git-update-index: unable to remove %s", + die("git update-index: unable to remove %s", ptr); } else { @@ -374,7 +377,7 @@ static void read_index_info(int line_termination) */ ptr[-42] = ptr[-1] = 0; if (add_cacheinfo(mode, sha1, path_name, stage)) - die("git-update-index: unable to update %s", + die("git update-index: unable to update %s", path_name); } continue; @@ -614,10 +617,12 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) 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; } @@ -626,12 +631,12 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) unsigned int mode; if (i+3 >= argc) - die("git-update-index: --cacheinfo <mode> <sha1> <path>"); + 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" + die("git update-index: --cacheinfo" " cannot add %s", argv[i+3]); i += 3; continue; @@ -639,7 +644,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) if (!strcmp(path, "--chmod=-x") || !strcmp(path, "--chmod=+x")) { if (argc <= i+1) - die("git-update-index: %s <path>", path); + die("git update-index: %s <path>", path); set_executable_bit = path[8]; continue; } @@ -684,6 +689,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) 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) @@ -702,6 +708,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) 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) @@ -714,6 +721,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix) strbuf_init(&buf, 0); strbuf_init(&nbuf, 0); + setup_work_tree(); while (strbuf_getline(&buf, stdin, line_termination) != EOF) { const char *p; if (line_termination && buf.buf[0] == '"') { diff --git a/builtin-verify-pack.c b/builtin-verify-pack.c index f4ac595695..25a29f11a4 100644 --- a/builtin-verify-pack.c +++ b/builtin-verify-pack.c @@ -1,7 +1,7 @@ #include "builtin.h" #include "cache.h" #include "pack.h" - +#include "pack-revindex.h" #define MAX_CHAIN 50 @@ -129,6 +129,7 @@ int cmd_verify_pack(int argc, const char **argv, const char *prefix) else { if (verify_one_pack(argv[1], verbose)) err = 1; + discard_revindex(); nothing_done = 0; } argc--; argv++; @@ -11,7 +11,7 @@ extern const char git_usage_string[]; extern const char git_more_info_string[]; extern void list_common_cmds_help(void); -extern void help_unknown_cmd(const char *cmd); +extern const char *help_unknown_cmd(const char *cmd); extern void prune_packed_objects(int); extern int read_line_with_nul(char *buf, int size, FILE *file); extern int fmt_merge_msg(int merge_summary, struct strbuf *in, @@ -126,6 +126,7 @@ struct cache_entry { #define CE_NAMEMASK (0x0fff) #define CE_STAGEMASK (0x3000) +#define CE_EXTENDED (0x4000) #define CE_VALID (0x8000) #define CE_STAGESHIFT 12 @@ -222,7 +223,8 @@ struct index_state { struct cache_tree *cache_tree; time_t timestamp; void *alloc; - unsigned name_hash_initialized : 1; + unsigned name_hash_initialized : 1, + initialized : 1; struct hash_table name_hash; }; @@ -377,6 +379,7 @@ extern int remove_file_from_index(struct index_state *, const char *path); #define ADD_CACHE_VERBOSE 1 #define ADD_CACHE_PRETEND 2 #define ADD_CACHE_IGNORE_ERRORS 4 +#define ADD_CACHE_IGNORE_REMOVAL 8 extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags); extern int add_file_to_index(struct index_state *, const char *path, int flags); extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh); @@ -391,7 +394,6 @@ extern int ie_modified(const struct index_state *, struct cache_entry *, struct extern int ce_path_match(const struct cache_entry *ce, const char **pathspec); extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path); -extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object); extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object); extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st); @@ -451,6 +453,7 @@ enum safe_crlf { extern enum safe_crlf safe_crlf; enum branch_track { + BRANCH_TRACK_UNSPECIFIED = -1, BRANCH_TRACK_NEVER = 0, BRANCH_TRACK_REMOTE, BRANCH_TRACK_ALWAYS, diff --git a/combine-diff.c b/combine-diff.c index 9f80a1c5e3..dcb90b1701 100644 --- a/combine-diff.c +++ b/combine-diff.c @@ -143,8 +143,6 @@ static void append_lost(struct sline *sline, int n, const char *line, int len) } struct combine_diff_state { - struct xdiff_emit_state xm; - unsigned int lno; int ob, on, nb, nn; unsigned long nmask; @@ -217,17 +215,15 @@ static void combine_diff(const unsigned char *parent, mmfile_t *result_file, parent_file.size = sz; xpp.flags = XDF_NEED_MINIMAL; memset(&xecfg, 0, sizeof(xecfg)); - ecb.outf = xdiff_outf; - ecb.priv = &state; memset(&state, 0, sizeof(state)); - state.xm.consume = consume_line; state.nmask = nmask; state.sline = sline; state.lno = 1; state.num_parent = num_parent; state.n = n; - xdi_diff(&parent_file, result_file, &xpp, &xecfg, &ecb); + xdi_diff_outf(&parent_file, result_file, consume_line, &state, + &xpp, &xecfg, &ecb); free(parent_file.ptr); /* Assign line numbers for this parent. @@ -500,6 +496,18 @@ static int hunk_comment_line(const char *bol) return (isalpha(ch) || ch == '_' || ch == '$'); } +static void show_line_to_eol(const char *line, int len, const char *reset) +{ + int saw_cr_at_eol = 0; + if (len < 0) + len = strlen(line); + saw_cr_at_eol = (len && line[len-1] == '\r'); + + printf("%.*s%s%s\n", len - saw_cr_at_eol, line, + reset, + saw_cr_at_eol ? "\r" : ""); +} + static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent, int use_color) { @@ -593,7 +601,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent, else putchar(' '); } - printf("%s%s\n", ll->line, c_reset); + show_line_to_eol(ll->line, -1, c_reset); ll = ll->next; } if (cnt < lno) @@ -617,7 +625,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent, putchar(' '); p_mask <<= 1; } - printf("%.*s%s\n", sl->len, sl->bol, c_reset); + show_line_to_eol(sl->bol, sl->len, c_reset); } } } @@ -727,6 +735,18 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent, die("early EOF '%s'", elem->path); result[len] = 0; + + /* If not a fake symlink, apply filters, e.g. autocrlf */ + if (is_file) { + struct strbuf buf; + + strbuf_init(&buf, 0); + if (convert_to_git(elem->path, result, len, &buf, safe_crlf)) { + free(result); + result = strbuf_detach(&buf, &len); + result_size = len; + } + } } else { deleted_file: @@ -67,7 +67,8 @@ extern int non_ascii(int); struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */ extern void get_commit_format(const char *arg, struct rev_info *); extern void format_commit_message(const struct commit *commit, - const void *format, struct strbuf *sb); + const void *format, struct strbuf *sb, + enum date_mode dmode); extern void pretty_print_commit(enum cmit_fmt fmt, const struct commit*, struct strbuf *, int abbrev, const char *subject, @@ -121,6 +122,7 @@ int read_graft_file(const char *graft_file); struct commit_graft *lookup_commit_graft(const unsigned char *sha1); extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup); +extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos, int cleanup); extern struct commit_list *get_octopus_merge_bases(struct commit_list *in); extern int register_shallow(const unsigned char *sha1); diff --git a/compat/fnmatch.c b/compat/fnmatch/fnmatch.c index 1f4ead5f98..1f4ead5f98 100644 --- a/compat/fnmatch.c +++ b/compat/fnmatch/fnmatch.c diff --git a/compat/fnmatch.h b/compat/fnmatch/fnmatch.h index cc3ec37940..cc3ec37940 100644 --- a/compat/fnmatch.h +++ b/compat/fnmatch/fnmatch.h diff --git a/compat/mingw.c b/compat/mingw.c index 772cad510d..ccfa2a0a3d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -31,11 +31,6 @@ static inline time_t filetime_to_time_t(const FILETIME *ft) return (time_t)winTime; } -static inline size_t size_to_blocks(size_t s) -{ - return (s+511)/512; -} - extern int _getdrive( void ); /* We keep the do_lstat code in a separate function to avoid recursion. * When a path ends with a slash, the stat will fail with ENOENT. In @@ -57,10 +52,10 @@ static int do_lstat(const char *file_name, struct stat *buf) buf->st_ino = 0; buf->st_gid = 0; buf->st_uid = 0; + buf->st_nlink = 1; buf->st_mode = fMode; buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ - buf->st_blocks = size_to_blocks(buf->st_size); - buf->st_dev = _getdrive() - 1; + buf->st_dev = buf->st_rdev = (_getdrive() - 1); buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); @@ -94,7 +89,7 @@ static int do_lstat(const char *file_name, struct stat *buf) * complete. Note that Git stat()s are redirected to mingw_lstat() * too, since Windows doesn't really handle symlinks that well. */ -int mingw_lstat(const char *file_name, struct mingw_stat *buf) +int mingw_lstat(const char *file_name, struct stat *buf) { int namelen; static char alt_name[PATH_MAX]; @@ -122,8 +117,7 @@ int mingw_lstat(const char *file_name, struct mingw_stat *buf) } #undef fstat -#undef stat -int mingw_fstat(int fd, struct mingw_stat *buf) +int mingw_fstat(int fd, struct stat *buf) { HANDLE fh = (HANDLE)_get_osfhandle(fd); BY_HANDLE_FILE_INFORMATION fdata; @@ -133,22 +127,8 @@ int mingw_fstat(int fd, struct mingw_stat *buf) return -1; } /* direct non-file handles to MS's fstat() */ - if (GetFileType(fh) != FILE_TYPE_DISK) { - struct stat st; - if (fstat(fd, &st)) - return -1; - buf->st_ino = st.st_ino; - buf->st_gid = st.st_gid; - buf->st_uid = st.st_uid; - buf->st_mode = st.st_mode; - buf->st_size = st.st_size; - buf->st_blocks = size_to_blocks(buf->st_size); - buf->st_dev = st.st_dev; - buf->st_atime = st.st_atime; - buf->st_mtime = st.st_mtime; - buf->st_ctime = st.st_ctime; - return 0; - } + if (GetFileType(fh) != FILE_TYPE_DISK) + return fstat(fd, buf); if (GetFileInformationByHandle(fh, &fdata)) { int fMode = S_IREAD; @@ -162,10 +142,10 @@ int mingw_fstat(int fd, struct mingw_stat *buf) buf->st_ino = 0; buf->st_gid = 0; buf->st_uid = 0; + buf->st_nlink = 1; buf->st_mode = fMode; buf->st_size = fdata.nFileSizeLow; /* Can't use nFileSizeHigh, since it's not a stat64 */ - buf->st_blocks = size_to_blocks(buf->st_size); - buf->st_dev = _getdrive() - 1; + buf->st_dev = buf->st_rdev = (_getdrive() - 1); buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime)); buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime)); buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime)); diff --git a/compat/mingw.h b/compat/mingw.h index a52e657c51..4f275cb8e6 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -162,22 +162,12 @@ int mingw_rename(const char*, const char*); /* Use mingw_lstat() instead of lstat()/stat() and * mingw_fstat() instead of fstat() on Windows. - * struct stat is redefined because it lacks the st_blocks member. */ -struct mingw_stat { - unsigned st_mode; - time_t st_mtime, st_atime, st_ctime; - unsigned st_dev, st_ino, st_uid, st_gid; - size_t st_size; - size_t st_blocks; -}; -int mingw_lstat(const char *file_name, struct mingw_stat *buf); -int mingw_fstat(int fd, struct mingw_stat *buf); +int mingw_lstat(const char *file_name, struct stat *buf); +int mingw_fstat(int fd, struct stat *buf); #define fstat mingw_fstat #define lstat mingw_lstat -#define stat mingw_stat -static inline int mingw_stat(const char *file_name, struct mingw_stat *buf) -{ return mingw_lstat(file_name, buf); } +#define stat(x,y) mingw_lstat(x,y) int mingw_utime(const char *file_name, const struct utimbuf *times); #define utime mingw_utime diff --git a/compat/regex.c b/compat/regex/regex.c index 87b33e4669..87b33e4669 100644 --- a/compat/regex.c +++ b/compat/regex/regex.c diff --git a/compat/regex.h b/compat/regex/regex.h index 6eb64f1402..6eb64f1402 100644 --- a/compat/regex.h +++ b/compat/regex/regex.h diff --git a/config.mak.in b/config.mak.in index b776149531..17e9861c06 100644 --- a/config.mak.in +++ b/config.mak.in @@ -3,6 +3,8 @@ CC = @CC@ CFLAGS = @CFLAGS@ +LDFLAGS = @LDFLAGS@ +CC_LD_DYNPATH = @CC_LD_DYNPATH@ AR = @AR@ TAR = @TAR@ #INSTALL = @INSTALL@ # needs install-sh or install.sh in sources diff --git a/configure.ac b/configure.ac index 7c2856efc9..27bab00a45 100644 --- a/configure.ac +++ b/configure.ac @@ -103,6 +103,38 @@ GIT_PARSE_WITH(tcltk)) AC_MSG_NOTICE([CHECKS for programs]) # AC_PROG_CC([cc gcc]) +# which switch to pass runtime path to dynamic libraries to the linker +AC_CACHE_CHECK([if linker supports -R], ld_dashr, [ + SAVE_LDFLAGS="${LDFLAGS}" + LDFLAGS="${SAVE_LDFLAGS} -R /" + AC_LINK_IFELSE(AC_LANG_PROGRAM([], []), [ld_dashr=yes], [ld_dashr=no]) + LDFLAGS="${SAVE_LDFLAGS}" +]) +if test "$ld_dashr" = "yes"; then + AC_SUBST(CC_LD_DYNPATH, [-R]) +else + AC_CACHE_CHECK([if linker supports -Wl,-rpath,], ld_wl_rpath, [ + SAVE_LDFLAGS="${LDFLAGS}" + LDFLAGS="${SAVE_LDFLAGS} -Wl,-rpath,/" + AC_LINK_IFELSE(AC_LANG_PROGRAM([], []), [ld_wl_rpath=yes], [ld_wl_rpath=no]) + LDFLAGS="${SAVE_LD_FLAGS}" + ]) + if test "$ld_wl_rpath" = "yes"; then + AC_SUBST(CC_LD_DYNPATH, [-Wl,-rpath,]) + else + AC_CACHE_CHECK([if linker supports -rpath], ld_rpath, [ + SAVE_LDFLAGS="${LDFLAGS}" + LDFLAGS="${SAVE_LDFLAGS} -rpath /" + AC_LINK_IFELSE(AC_LANG_PROGRAM([], []), [ld_rpath=yes], [ld_rpath=no]) + LDFLAGS="${SAVE_LD_FLAGS}" + ]) + if test "$ld_rpath" = "yes"; then + AC_SUBST(CC_LD_DYNPATH, [-rpath]) + else + AC_MSG_WARN([linker does not support runtime path to dynamic libraries]) + fi + fi +fi #AC_PROG_INSTALL # needs install-sh or install.sh in sources AC_CHECK_TOOLS(AR, [gar ar], :) AC_CHECK_PROGS(TAR, [gtar tar]) @@ -97,7 +97,7 @@ int get_ack(int fd, unsigned char *result_sha1) int len = packet_read_line(fd, line, sizeof(line)); if (!len) - die("git-fetch-pack: expected ACK/NAK, got EOF"); + die("git fetch-pack: expected ACK/NAK, got EOF"); if (line[len-1] == '\n') line[--len] = 0; if (!strcmp(line, "NAK")) @@ -109,7 +109,7 @@ int get_ack(int fd, unsigned char *result_sha1) return 1; } } - die("git-fetch_pack: expected ACK/NAK, got '%s'", line); + die("git fetch_pack: expected ACK/NAK, got '%s'", line); } int path_match(const char *path, int nr, char **match) diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index a31004088a..d3fb6ae507 100755 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -386,7 +386,9 @@ __git_porcelain_commands () cat-file) : plumbing;; check-attr) : plumbing;; check-ref-format) : plumbing;; + checkout-index) : plumbing;; commit-tree) : plumbing;; + count-objects) : infrequent;; cvsexportcommit) : export;; cvsimport) : import;; cvsserver) : daemon;; @@ -395,6 +397,7 @@ __git_porcelain_commands () diff-index) : plumbing;; diff-tree) : plumbing;; fast-import) : import;; + fast-export) : export;; fsck-objects) : plumbing;; fetch-pack) : plumbing;; fmt-merge-msg) : plumbing;; @@ -404,6 +407,10 @@ __git_porcelain_commands () index-pack) : plumbing;; init-db) : deprecated;; local-fetch) : plumbing;; + lost-found) : infrequent;; + ls-files) : plumbing;; + ls-remote) : plumbing;; + ls-tree) : plumbing;; mailinfo) : plumbing;; mailsplit) : plumbing;; merge-*) : plumbing;; @@ -428,6 +435,7 @@ __git_porcelain_commands () runstatus) : plumbing;; sh-setup) : internal;; shell) : daemon;; + show-ref) : plumbing;; send-pack) : plumbing;; show-index) : plumbing;; ssh-*) : transport;; @@ -442,6 +450,8 @@ __git_porcelain_commands () upload-archive) : plumbing;; upload-pack) : plumbing;; write-tree) : plumbing;; + var) : infrequent;; + verify-pack) : infrequent;; verify-tag) : plumbing;; *) echo $i;; esac @@ -771,7 +781,7 @@ _git_diff () __gitcomp "--cached --stat --numstat --shortstat --summary --patch-with-stat --name-only --name-status --color --no-color --color-words --no-renames --check - --full-index --binary --abbrev --diff-filter + --full-index --binary --abbrev --diff-filter= --find-copies-harder --pickaxe-all --pickaxe-regex --text --ignore-space-at-eol --ignore-space-change --ignore-all-space --exit-code --quiet --ext-diff @@ -1483,7 +1493,7 @@ _git_submodule () { __git_has_doubledash && return - local subcommands="add status init update" + local subcommands="add status init update summary foreach sync" if [ -z "$(__git_find_subcommand "$subcommands")" ]; then local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4 index f9865b444f..2216cacba7 100755 --- a/contrib/fast-import/git-p4 +++ b/contrib/fast-import/git-p4 @@ -76,7 +76,7 @@ def write_pipe(c, str): def p4_write_pipe(c, str): real_cmd = p4_build_cmd(c) - return write_pipe(c, str) + return write_pipe(real_cmd, str) def read_pipe(c, ignore_error=False): if verbose: @@ -708,6 +708,7 @@ class P4Submit(Command): newdiff = newdiff.replace("\n", "\r\n") tmpFile.write(submitTemplate + separatorLine + diff + newdiff) tmpFile.close() + mtime = os.stat(fileName).st_mtime defaultEditor = "vi" if platform.system() == "Windows": defaultEditor = "notepad" @@ -716,15 +717,29 @@ class P4Submit(Command): else: editor = os.environ.get("EDITOR", defaultEditor); system(editor + " " + fileName) - tmpFile = open(fileName, "rb") - message = tmpFile.read() - tmpFile.close() - os.remove(fileName) - submitTemplate = message[:message.index(separatorLine)] - if self.isWindows: - submitTemplate = submitTemplate.replace("\r\n", "\n") - p4_write_pipe("submit -i", submitTemplate) + response = "y" + if os.stat(fileName).st_mtime <= mtime: + response = "x" + while response != "y" and response != "n": + response = raw_input("Submit template unchanged. Submit anyway? [y]es, [n]o (skip this patch) ") + + if response == "y": + tmpFile = open(fileName, "rb") + message = tmpFile.read() + tmpFile.close() + submitTemplate = message[:message.index(separatorLine)] + if self.isWindows: + submitTemplate = submitTemplate.replace("\r\n", "\n") + p4_write_pipe("submit -i", submitTemplate) + else: + for f in editedFiles: + p4_system("revert \"%s\"" % f); + for f in filesToAdd: + p4_system("revert \"%s\"" % f); + system("rm %s" %f) + + os.remove(fileName) else: fileName = "submit.txt" file = open(fileName, "w+") @@ -1733,8 +1748,12 @@ class P4Clone(P4Sync): if not P4Sync.run(self, depotPaths): return False if self.branch != "master": - if gitBranchExists("refs/remotes/p4/master"): - system("git branch master refs/remotes/p4/master") + if self.importIntoRemotes: + masterbranch = "refs/remotes/p4/master" + else: + masterbranch = "refs/heads/p4/master" + if gitBranchExists(masterbranch): + system("git branch master %s" % masterbranch) system("git checkout -f") else: print "Could not detect main branch. No checkout/master branch created." diff --git a/contrib/fast-import/git-p4.txt b/contrib/fast-import/git-p4.txt index ac551d45f1..49b335921a 100644 --- a/contrib/fast-import/git-p4.txt +++ b/contrib/fast-import/git-p4.txt @@ -3,14 +3,16 @@ git-p4 - Perforce <-> Git converter using git-fast-import Usage ===== -git-p4 supports two main modes: Importing from Perforce to a Git repository is -done using "git-p4 sync" or "git-p4 rebase". Submitting changes from Git back -to Perforce is done using "git-p4 submit". +git-p4 can be used in two different ways: + +1) To import changes from Perforce to a Git repository, using "git-p4 sync". + +2) To submit changes from Git back to Perforce, using "git-p4 submit". Importing ========= -You can simply start with +Simply start with git-p4 clone //depot/path/project @@ -18,11 +20,18 @@ or git-p4 clone //depot/path/project myproject -This will create an empty git repository in a subdirectory called "project" (or -"myproject" with the second command), import the head revision from the -specified perforce path into a git "p4" branch (remotes/p4 actually), create a -master branch off it and check it out. If you want the entire history (not just -the head revision) then you can simply append a "@all" to the depot path: +This will: + +1) Create an empty git repository in a subdirectory called "project" (or +"myproject" with the second command) + +2) Import the head revision from the given Perforce path into a git branch +called "p4" (remotes/p4 actually) + +3) Create a master branch based on it and check it out. + +If you want the entire history (not just the head revision) then you can simply +append a "@all" to the depot path: git-p4 clone //depot/project/main@all myproject @@ -37,31 +46,40 @@ If you want more control you can also use the git-p4 sync command directly: This will import the current head revision of the specified depot path into a "remotes/p4/master" branch of your git repository. You can use the ---branch=mybranch option to use a different branch. +--branch=mybranch option to import into a different branch. -If you want to import the entire history of a given depot path just use +If you want to import the entire history of a given depot path simply use: git-p4 sync //path/in/depot@all + +Note: + To achieve optimal compression you may want to run 'git repack -a -d -f' after a big import. This may take a while. -Support for Perforce integrations is still work in progress. Don't bother -trying it unless you want to hack on it :) - Incremental Imports =================== -After an initial import you can easily synchronize your git repository with -newer changes from the Perforce depot by just calling +After an initial import you can continue to synchronize your git repository +with newer changes from the Perforce depot by just calling git-p4 sync in your git repository. By default the "remotes/p4/master" branch is updated. -It is recommended to run 'git repack -a -d -f' from time to time when using -incremental imports to optimally combine the individual git packs that each -incremental import creates through the use of git-fast-import. +Advanced Setup +============== + +Suppose you have a periodically updated git repository somewhere, containing a +complete import of a Perforce project. This repository can be cloned and used +with git-p4. When updating the cloned repository with the "sync" command, +git-p4 will try to fetch changes from the original repository first. The git +protocol used with this is usually faster than importing from Perforce +directly. + +This behaviour can be disabled by setting the "git-p4.syncFromOrigin" git +configuration variable to "false". Updating ======== @@ -79,7 +97,7 @@ Submitting ========== git-p4 has support for submitting changes from a git repository back to the -Perforce depot. This requires a Perforce checkout separate to your git +Perforce depot. This requires a Perforce checkout separate from your git repository. To submit all changes that are in the current git branch but not in the "p4" branch (or "origin" if "p4" doesn't exist) simply call @@ -97,17 +115,6 @@ continue importing the remaining changes with git-p4 submit --continue -After submitting you should sync your perforce import branch ("p4" or "origin") -from Perforce using git-p4's sync command. - -If you have changes in your working directory that you haven't committed into -git yet but that you want to commit to Perforce directly ("quick fixes") then -you do not have to go through the intermediate step of creating a git commit -first but you can just call - - git-p4 submit --direct - - Example ======= diff --git a/csum-file.c b/csum-file.c index ace64f165e..28389541a3 100644 --- a/csum-file.c +++ b/csum-file.c @@ -42,11 +42,11 @@ int sha1close(struct sha1file *f, unsigned char *result, unsigned int flags) sha1flush(f, offset); f->offset = 0; } + SHA1_Final(f->buffer, &f->ctx); + if (result) + hashcpy(result, f->buffer); if (flags & (CSUM_CLOSE | CSUM_FSYNC)) { /* write checksum and close fd */ - SHA1_Final(f->buffer, &f->ctx); - if (result) - hashcpy(result, f->buffer); sha1flush(f, 20); if (flags & CSUM_FSYNC) fsync_or_die(f->fd, f->name); @@ -5,17 +5,24 @@ */ #include "cache.h" +/* Just so that no insane platform contaminate namespace with these symbols */ +#undef SS +#undef AA +#undef DD +#undef GS + #define SS GIT_SPACE #define AA GIT_ALPHA #define DD GIT_DIGIT +#define GS GIT_SPECIAL /* \0, *, ?, [, \\ */ unsigned char sane_ctype[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, SS, SS, 0, 0, SS, 0, 0, /* 0-15 */ + GS, 0, 0, 0, 0, 0, 0, 0, 0, SS, SS, 0, 0, SS, 0, 0, /* 0-15 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16-15 */ - SS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 32-15 */ - DD, DD, DD, DD, DD, DD, DD, DD, DD, DD, 0, 0, 0, 0, 0, 0, /* 48-15 */ + SS, 0, 0, 0, 0, 0, 0, 0, 0, 0, GS, 0, 0, 0, 0, 0, /* 32-15 */ + DD, DD, DD, DD, DD, DD, DD, DD, DD, DD, 0, 0, 0, 0, 0, GS, /* 48-15 */ 0, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, /* 64-15 */ - AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, 0, 0, 0, 0, 0, /* 80-15 */ + AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, GS, GS, 0, 0, 0, /* 80-15 */ 0, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, /* 96-15 */ AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, 0, 0, 0, 0, 0, /* 112-15 */ /* Nothing in the 128.. range */ @@ -16,12 +16,11 @@ static int log_syslog; static int verbose; static int reuseaddr; -static int child_handler_pipe[2]; static const char daemon_usage[] = "git daemon [--verbose] [--syslog] [--export-all]\n" -" [--timeout=n] [--init-timeout=n] [--strict-paths]\n" -" [--base-path=path] [--base-path-relaxed]\n" +" [--timeout=n] [--init-timeout=n] [--max-connections=n]\n" +" [--strict-paths] [--base-path=path] [--base-path-relaxed]\n" " [--user-path | --user-path=path]\n" " [--interpolated-path=path]\n" " [--reuseaddr] [--detach] [--pid-file=file]\n" @@ -78,38 +77,19 @@ static struct interp interp_table[] = { static void logreport(int priority, const char *err, va_list params) { - /* We should do a single write so that it is atomic and output - * of several processes do not get intermingled. */ - char buf[1024]; - int buflen; - int maxlen, msglen; - - /* sizeof(buf) should be big enough for "[pid] \n" */ - buflen = snprintf(buf, sizeof(buf), "[%ld] ", (long) getpid()); - - maxlen = sizeof(buf) - buflen - 1; /* -1 for our own LF */ - msglen = vsnprintf(buf + buflen, maxlen, err, params); - if (log_syslog) { + char buf[1024]; + vsnprintf(buf, sizeof(buf), err, params); syslog(priority, "%s", buf); - return; + } else { + /* + * Since stderr is set to linebuffered mode, the + * logging of different processes will not overlap + */ + fprintf(stderr, "[%"PRIuMAX"] ", (uintmax_t)getpid()); + vfprintf(stderr, err, params); + fputc('\n', stderr); } - - /* maxlen counted our own LF but also counts space given to - * vsnprintf for the terminating NUL. We want to make sure that - * we have space for our own LF and NUL after the "meat" of the - * message, so truncate it at maxlen - 1. - */ - if (msglen > maxlen - 1) - msglen = maxlen - 1; - else if (msglen < 0) - msglen = 0; /* Protect against weird return values. */ - buflen += msglen; - - buf[buflen++] = '\n'; - buf[buflen] = '\0'; - - write_in_full(2, buf, buflen); } static void logerror(const char *err, ...) @@ -604,169 +584,107 @@ static int execute(struct sockaddr *addr) return -1; } +static int max_connections = 32; -/* - * We count spawned/reaped separately, just to avoid any - * races when updating them from signals. The SIGCHLD handler - * will only update children_reaped, and the fork logic will - * only update children_spawned. - * - * MAX_CHILDREN should be a power-of-two to make the modulus - * operation cheap. It should also be at least twice - * the maximum number of connections we will ever allow. - */ -#define MAX_CHILDREN 128 - -static int max_connections = 25; - -/* These are updated by the signal handler */ -static volatile unsigned int children_reaped; -static pid_t dead_child[MAX_CHILDREN]; - -/* These are updated by the main loop */ -static unsigned int children_spawned; -static unsigned int children_deleted; +static unsigned int live_children; static struct child { + struct child *next; pid_t pid; - int addrlen; struct sockaddr_storage address; -} live_child[MAX_CHILDREN]; +} *firstborn; -static void add_child(int idx, pid_t pid, struct sockaddr *addr, int addrlen) +static void add_child(pid_t pid, struct sockaddr *addr, int addrlen) { - live_child[idx].pid = pid; - live_child[idx].addrlen = addrlen; - memcpy(&live_child[idx].address, addr, addrlen); + struct child *newborn, **cradle; + + /* + * This must be xcalloc() -- we'll compare the whole sockaddr_storage + * but individual address may be shorter. + */ + newborn = xcalloc(1, sizeof(*newborn)); + live_children++; + newborn->pid = pid; + memcpy(&newborn->address, addr, addrlen); + for (cradle = &firstborn; *cradle; cradle = &(*cradle)->next) + if (!memcmp(&(*cradle)->address, &newborn->address, + sizeof(newborn->address))) + break; + newborn->next = *cradle; + *cradle = newborn; } -/* - * Walk from "deleted" to "spawned", and remove child "pid". - * - * We move everything up by one, since the new "deleted" will - * be one higher. - */ -static void remove_child(pid_t pid, unsigned deleted, unsigned spawned) +static void remove_child(pid_t pid) { - struct child n; + struct child **cradle, *blanket; - deleted %= MAX_CHILDREN; - spawned %= MAX_CHILDREN; - if (live_child[deleted].pid == pid) { - live_child[deleted].pid = -1; - return; - } - n = live_child[deleted]; - for (;;) { - struct child m; - deleted = (deleted + 1) % MAX_CHILDREN; - if (deleted == spawned) - die("could not find dead child %d\n", pid); - m = live_child[deleted]; - live_child[deleted] = n; - if (m.pid == pid) - return; - n = m; - } + for (cradle = &firstborn; (blanket = *cradle); cradle = &blanket->next) + if (blanket->pid == pid) { + *cradle = blanket->next; + live_children--; + free(blanket); + break; + } } /* * This gets called if the number of connections grows * past "max_connections". * - * We _should_ start off by searching for connections - * from the same IP, and if there is some address wth - * multiple connections, we should kill that first. - * - * As it is, we just "randomly" kill 25% of the connections, - * and our pseudo-random generator sucks too. I have no - * shame. - * - * Really, this is just a place-holder for a _real_ algorithm. + * We kill the newest connection from a duplicate IP. */ -static void kill_some_children(int signo, unsigned start, unsigned stop) +static void kill_some_child(void) { - start %= MAX_CHILDREN; - stop %= MAX_CHILDREN; - while (start != stop) { - if (!(start & 3)) - kill(live_child[start].pid, signo); - start = (start + 1) % MAX_CHILDREN; - } -} - -static void check_dead_children(void) -{ - unsigned spawned, reaped, deleted; - - spawned = children_spawned; - reaped = children_reaped; - deleted = children_deleted; + const struct child *blanket, *next; - while (deleted < reaped) { - pid_t pid = dead_child[deleted % MAX_CHILDREN]; - const char *dead = pid < 0 ? " (with error)" : ""; - - if (pid < 0) - pid = -pid; + if (!(blanket = firstborn)) + return; - /* XXX: Custom logging, since we don't wanna getpid() */ - if (verbose) { - if (log_syslog) - syslog(LOG_INFO, "[%d] Disconnected%s", - pid, dead); - else - fprintf(stderr, "[%d] Disconnected%s\n", - pid, dead); + for (; (next = blanket->next); blanket = next) + if (!memcmp(&blanket->address, &next->address, + sizeof(next->address))) { + kill(blanket->pid, SIGTERM); + break; } - remove_child(pid, deleted, spawned); - deleted++; - } - children_deleted = deleted; } -static void check_max_connections(void) +static void check_dead_children(void) { - for (;;) { - int active; - unsigned spawned, deleted; - - check_dead_children(); - - spawned = children_spawned; - deleted = children_deleted; - - active = spawned - deleted; - if (active <= max_connections) - break; - - /* Kill some unstarted connections with SIGTERM */ - kill_some_children(SIGTERM, deleted, spawned); - if (active <= max_connections << 1) - break; + int status; + pid_t pid; - /* If the SIGTERM thing isn't helping use SIGKILL */ - kill_some_children(SIGKILL, deleted, spawned); - sleep(1); + while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { + const char *dead = ""; + remove_child(pid); + if (!WIFEXITED(status) || (WEXITSTATUS(status) > 0)) + dead = " (with error)"; + loginfo("[%"PRIuMAX"] Disconnected%s", (uintmax_t)pid, dead); } } static void handle(int incoming, struct sockaddr *addr, int addrlen) { - pid_t pid = fork(); + pid_t pid; - if (pid) { - unsigned idx; + if (max_connections && live_children >= max_connections) { + kill_some_child(); + sleep(1); /* give it some time to die */ + check_dead_children(); + if (live_children >= max_connections) { + close(incoming); + logerror("Too many children, dropping connection"); + return; + } + } + if ((pid = fork())) { close(incoming); - if (pid < 0) + if (pid < 0) { + logerror("Couldn't fork %s", strerror(errno)); return; + } - idx = children_spawned % MAX_CHILDREN; - children_spawned++; - add_child(idx, pid, addr, addrlen); - - check_max_connections(); + add_child(pid, addr, addrlen); return; } @@ -779,21 +697,11 @@ static void handle(int incoming, struct sockaddr *addr, int addrlen) static void child_handler(int signo) { - for (;;) { - int status; - pid_t pid = waitpid(-1, &status, WNOHANG); - - if (pid > 0) { - unsigned reaped = children_reaped; - if (!WIFEXITED(status) || WEXITSTATUS(status) > 0) - pid = -pid; - dead_child[reaped % MAX_CHILDREN] = pid; - children_reaped = reaped + 1; - write(child_handler_pipe[1], &status, 1); - continue; - } - break; - } + /* + * Otherwise empty handler because systemcalls will get interrupted + * upon signal receipt + * SysV needs the handler to be rearmed + */ signal(SIGCHLD, child_handler); } @@ -836,7 +744,7 @@ static int socksetup(char *listen_addr, int listen_port, int **socklist_p) if (sockfd < 0) continue; if (sockfd >= FD_SETSIZE) { - error("too large socket descriptor."); + logerror("Socket descriptor too large"); close(sockfd); continue; } @@ -936,35 +844,28 @@ static int service_loop(int socknum, int *socklist) struct pollfd *pfd; int i; - if (pipe(child_handler_pipe) < 0) - die ("Could not set up pipe for child handler"); - - pfd = xcalloc(socknum + 1, sizeof(struct pollfd)); + pfd = xcalloc(socknum, sizeof(struct pollfd)); for (i = 0; i < socknum; i++) { pfd[i].fd = socklist[i]; pfd[i].events = POLLIN; } - pfd[socknum].fd = child_handler_pipe[0]; - pfd[socknum].events = POLLIN; signal(SIGCHLD, child_handler); for (;;) { int i; - if (poll(pfd, socknum + 1, -1) < 0) { + check_dead_children(); + + if (poll(pfd, socknum, -1) < 0) { if (errno != EINTR) { - error("poll failed, resuming: %s", + logerror("Poll failed, resuming: %s", strerror(errno)); sleep(1); } continue; } - if (pfd[socknum].revents & POLLIN) { - read(child_handler_pipe[0], &i, 1); - check_dead_children(); - } for (i = 0; i < socknum; i++) { if (pfd[i].revents & POLLIN) { @@ -1022,7 +923,7 @@ static void store_pid(const char *path) FILE *f = fopen(path, "w"); if (!f) die("cannot open pid file %s: %s", path, strerror(errno)); - if (fprintf(f, "%d\n", getpid()) < 0 || fclose(f) != 0) + if (fprintf(f, "%"PRIuMAX"\n", (uintmax_t) getpid()) < 0 || fclose(f) != 0) die("failed to write pid file %s: %s", path, strerror(errno)); } @@ -1055,11 +956,6 @@ int main(int argc, char **argv) gid_t gid = 0; int i; - /* Without this we cannot rely on waitpid() to tell - * what happened to our children. - */ - signal(SIGCHLD, SIG_DFL); - for (i = 1; i < argc; i++) { char *arg = argv[i]; @@ -1105,6 +1001,12 @@ int main(int argc, char **argv) init_timeout = atoi(arg+15); continue; } + if (!prefixcmp(arg, "--max-connections=")) { + max_connections = atoi(arg+18); + if (max_connections < 0) + max_connections = 0; /* unlimited */ + continue; + } if (!strcmp(arg, "--strict-paths")) { strict_paths = 1; continue; @@ -1178,9 +1080,10 @@ int main(int argc, char **argv) } if (log_syslog) { - openlog("git-daemon", 0, LOG_DAEMON); + openlog("git-daemon", LOG_PID, LOG_DAEMON); set_die_routine(daemon_die); - } + } else + setlinebuf(stderr); /* avoid splitting a message in the middle */ if (inetd_mode && (group_name || user_name)) die("--user and --group are incompatible with --inetd"); @@ -1233,8 +1136,10 @@ int main(int argc, char **argv) return execute(peer); } - if (detach) + if (detach) { daemonize(); + loginfo("Ready to rumble"); + } else sanitize_stdfds(); @@ -20,6 +20,7 @@ static int diff_detect_rename_default; static int diff_rename_limit_default = 200; +static int diff_suppress_blank_empty; int diff_use_color_default = -1; static const char *external_diff_cmd_cfg; int diff_auto_refresh_index = 1; @@ -176,6 +177,12 @@ int git_diff_basic_config(const char *var, const char *value, void *cb) return 0; } + /* like GNU diff's --suppress-blank-empty option */ + if (!strcmp(var, "diff.suppress-blank-empty")) { + diff_suppress_blank_empty = git_config_bool(var, value); + return 0; + } + if (!prefixcmp(var, "diff.")) { const char *ep = strrchr(var, '.'); if (ep != var + 4) { @@ -369,7 +376,6 @@ static void diff_words_append(char *line, unsigned long len, } struct diff_words_data { - struct xdiff_emit_state xm; struct diff_words_buffer minus, plus; FILE *file; }; @@ -459,11 +465,8 @@ static void diff_words_show(struct diff_words_data *diff_words) xpp.flags = XDF_NEED_MINIMAL; xecfg.ctxlen = diff_words->minus.alloc + diff_words->plus.alloc; - ecb.outf = xdiff_outf; - ecb.priv = diff_words; - diff_words->xm.consume = fn_out_diff_words_aux; - xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb); - + xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words, + &xpp, &xecfg, &ecb); free(minus.ptr); free(plus.ptr); diff_words->minus.text.size = diff_words->plus.text.size = 0; @@ -477,7 +480,6 @@ static void diff_words_show(struct diff_words_data *diff_words) typedef unsigned long (*sane_truncate_fn)(char *line, unsigned long len); struct emit_callback { - struct xdiff_emit_state xm; int nparents, color_diff; unsigned ws_rule; sane_truncate_fn truncate; @@ -511,13 +513,20 @@ const char *diff_get_color(int diff_use_color, enum color_diff ix) static void emit_line(FILE *file, const char *set, const char *reset, const char *line, int len) { - int has_trailing_newline = (len > 0 && line[len-1] == '\n'); + int has_trailing_newline, has_trailing_carriage_return; + + has_trailing_newline = (len > 0 && line[len-1] == '\n'); if (has_trailing_newline) len--; + has_trailing_carriage_return = (len > 0 && line[len-1] == '\r'); + if (has_trailing_carriage_return) + len--; fputs(set, file); fwrite(line, len, 1, file); fputs(reset, file); + if (has_trailing_carriage_return) + fputc('\r', file); if (has_trailing_newline) fputc('\n', file); } @@ -580,6 +589,12 @@ static void fn_out_consume(void *priv, char *line, unsigned long len) ecbdata->label_path[0] = ecbdata->label_path[1] = NULL; } + if (diff_suppress_blank_empty + && len == 2 && line[0] == ' ' && line[1] == '\n') { + line[0] = '\n'; + len = 1; + } + /* This is not really necessary for now because * this codepath only deals with two-way diffs. */ @@ -708,8 +723,6 @@ static char *pprint_rename(const char *a, const char *b) } struct diffstat_t { - struct xdiff_emit_state xm; - int nr; int alloc; struct diffstat_file { @@ -1054,6 +1067,13 @@ static long gather_dirstat(FILE *file, struct dirstat_dir *dir, unsigned long ch return this_dir; } +static int dirstat_compare(const void *_a, const void *_b) +{ + const struct dirstat_file *a = _a; + const struct dirstat_file *b = _b; + return strcmp(a->name, b->name); +} + static void show_dirstat(struct diff_options *options) { int i; @@ -1065,7 +1085,7 @@ static void show_dirstat(struct diff_options *options) dir.alloc = 0; dir.nr = 0; dir.percent = options->dirstat_percent; - dir.cumulative = options->output_format & DIFF_FORMAT_CUMULATIVE; + dir.cumulative = DIFF_OPT_TST(options, DIRSTAT_CUMULATIVE); changed = 0; for (i = 0; i < q->nr; i++) { @@ -1113,6 +1133,7 @@ static void show_dirstat(struct diff_options *options) return; /* Show all directories with more than x% of the changes */ + qsort(dir.files, dir.nr, sizeof(dir.files[0]), dirstat_compare); gather_dirstat(options->file, &dir, changed, "", 0); } @@ -1131,7 +1152,6 @@ static void free_diffstat_info(struct diffstat_t *diffstat) } struct checkdiff_t { - struct xdiff_emit_state xm; const char *filename; int lineno; struct diff_options *o; @@ -1376,6 +1396,8 @@ static struct builtin_funcname_pattern { const char *name; const char *pattern; } builtin_funcname_pattern[] = { + { "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$" }, + { "html", "^\\s*\\(<[Hh][1-6]\\s.*>.*\\)$" }, { "java", "!^[ ]*\\(catch\\|do\\|for\\|if\\|instanceof\\|" "new\\|return\\|switch\\|throw\\|while\\)\n" "^[ ]*\\(\\([ ]*" @@ -1387,9 +1409,10 @@ static struct builtin_funcname_pattern { "\\|" "^\\(.*=[ \t]*\\(class\\|record\\).*\\)$" }, - { "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$" }, - { "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$" }, + { "php", "^[\t ]*\\(\\(function\\|class\\).*\\)" }, + { "python", "^\\s*\\(\\(class\\|def\\)\\s.*\\)$" }, { "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$" }, + { "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$" }, }; static const char *diff_funcname_pattern(struct diff_filespec *one) @@ -1521,15 +1544,13 @@ static void builtin_diff(const char *name_a, xecfg.ctxlen = strtoul(diffopts + 10, NULL, 10); else if (!prefixcmp(diffopts, "-u")) xecfg.ctxlen = strtoul(diffopts + 2, NULL, 10); - ecb.outf = xdiff_outf; - ecb.priv = &ecbdata; - ecbdata.xm.consume = fn_out_consume; if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS)) { ecbdata.diff_words = xcalloc(1, sizeof(struct diff_words_data)); ecbdata.diff_words->file = o->file; } - xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); + xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata, + &xpp, &xecfg, &ecb); if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS)) free_diff_words_data(&ecbdata); } @@ -1580,9 +1601,8 @@ static void builtin_diffstat(const char *name_a, const char *name_b, memset(&xecfg, 0, sizeof(xecfg)); xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts; - ecb.outf = xdiff_outf; - ecb.priv = diffstat; - xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); + xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat, + &xpp, &xecfg, &ecb); } free_and_return: @@ -1603,7 +1623,6 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, return; memset(&data, 0, sizeof(data)); - data.xm.consume = checkdiff_consume; data.filename = name_b ? name_b : name_a; data.lineno = 0; data.o = o; @@ -1629,9 +1648,8 @@ static void builtin_checkdiff(const char *name_a, const char *name_b, memset(&xecfg, 0, sizeof(xecfg)); xecfg.ctxlen = 1; /* at least one context line */ xpp.flags = XDF_NEED_MINIMAL; - ecb.outf = xdiff_outf; - ecb.priv = &data; - xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); + xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data, + &xpp, &xecfg, &ecb); if ((data.ws_rule & WS_TRAILING_SPACE) && data.trailing_blanks_start) { @@ -2290,6 +2308,7 @@ void diff_setup(struct diff_options *options) options->break_opt = -1; options->rename_limit = -1; options->dirstat_percent = 3; + DIFF_OPT_CLR(options, DIRSTAT_CUMULATIVE); options->context = 3; options->change = diff_change; @@ -2462,8 +2481,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) options->output_format |= DIFF_FORMAT_SHORTSTAT; else if (opt_arg(arg, 'X', "dirstat", &options->dirstat_percent)) options->output_format |= DIFF_FORMAT_DIRSTAT; - else if (!strcmp(arg, "--cumulative")) - options->output_format |= DIFF_FORMAT_CUMULATIVE; + else if (!strcmp(arg, "--cumulative")) { + options->output_format |= DIFF_FORMAT_DIRSTAT; + DIFF_OPT_SET(options, DIRSTAT_CUMULATIVE); + } else if (!strcmp(arg, "--check")) options->output_format |= DIFF_FORMAT_CHECKDIFF; else if (!strcmp(arg, "--summary")) @@ -3019,7 +3040,6 @@ static void diff_summary(FILE *file, struct diff_filepair *p) } struct patch_id_t { - struct xdiff_emit_state xm; SHA_CTX *ctx; int patchlen; }; @@ -3064,7 +3084,6 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) SHA1_Init(&ctx); memset(&data, 0, sizeof(struct patch_id_t)); data.ctx = &ctx; - data.xm.consume = patch_id_consume; for (i = 0; i < q->nr; i++) { xpparam_t xpp; @@ -3129,9 +3148,8 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1) xpp.flags = XDF_NEED_MINIMAL; xecfg.ctxlen = 3; xecfg.flags = XDL_EMIT_FUNCNAMES; - ecb.outf = xdiff_outf; - ecb.priv = &data; - xdi_diff(&mf1, &mf2, &xpp, &xecfg, &ecb); + xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data, + &xpp, &xecfg, &ecb); } SHA1_Final(sha1, &ctx); @@ -3208,7 +3226,6 @@ void diff_flush(struct diff_options *options) struct diffstat_t diffstat; memset(&diffstat, 0, sizeof(struct diffstat_t)); - diffstat.xm.consume = diffstat_consume; for (i = 0; i < q->nr; i++) { struct diff_filepair *p = q->queue[i]; if (check_pair_status(p)) @@ -31,7 +31,6 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, #define DIFF_FORMAT_PATCH 0x0010 #define DIFF_FORMAT_SHORTSTAT 0x0020 #define DIFF_FORMAT_DIRSTAT 0x0040 -#define DIFF_FORMAT_CUMULATIVE 0x0080 /* These override all above */ #define DIFF_FORMAT_NAME 0x0100 @@ -64,6 +63,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q, #define DIFF_OPT_CHECK_FAILED (1 << 16) #define DIFF_OPT_RELATIVE_NAME (1 << 17) #define DIFF_OPT_IGNORE_SUBMODULES (1 << 18) +#define DIFF_OPT_DIRSTAT_CUMULATIVE (1 << 19) #define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag) #define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag) #define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag) @@ -52,11 +52,6 @@ int common_prefix(const char **pathspec) return prefix; } -static inline int special_char(unsigned char c1) -{ - return !c1 || c1 == '*' || c1 == '[' || c1 == '?' || c1 == '\\'; -} - /* * Does 'match' matches the given name? * A match is found if @@ -80,7 +75,7 @@ static int match_one(const char *match, const char *name, int namelen) for (;;) { unsigned char c1 = *match; unsigned char c2 = *name; - if (special_char(c1)) + if (isspecial(c1)) break; if (c1 != c2) return 0; @@ -680,17 +675,12 @@ static int cmp_name(const void *p1, const void *p2) */ static int simple_length(const char *match) { - const char special[256] = { - [0] = 1, ['?'] = 1, - ['\\'] = 1, ['*'] = 1, - ['['] = 1 - }; int len = -1; for (;;) { unsigned char c = *match++; len++; - if (special[c]) + if (isspecial(c)) return len; } } @@ -727,8 +717,12 @@ static void free_simplify(struct path_simplify *simplify) int read_directory(struct dir_struct *dir, const char *path, const char *base, int baselen, const char **pathspec) { - struct path_simplify *simplify = create_simplify(pathspec); + struct path_simplify *simplify; + + if (has_symlink_leading_path(strlen(path), path)) + return dir->nr; + simplify = create_simplify(pathspec); read_directory_recursive(dir, path, base, baselen, 0, simplify); free_simplify(simplify); qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name); @@ -111,7 +111,7 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout case S_IFREG: new = read_blob_entry(ce, path, &size); if (!new) - return error("git-checkout-index: unable to read sha1 file of %s (%s)", + return error("git checkout-index: unable to read sha1 file of %s (%s)", path, sha1_to_hex(ce->sha1)); /* @@ -132,7 +132,7 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout fd = create_file(path, ce->ce_mode); if (fd < 0) { free(new); - return error("git-checkout-index: unable to create file %s (%s)", + return error("git checkout-index: unable to create file %s (%s)", path, strerror(errno)); } @@ -140,12 +140,12 @@ 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("git checkout-index: unable to write file %s", path); break; case S_IFLNK: new = read_blob_entry(ce, path, &size); if (!new) - return error("git-checkout-index: unable to read sha1 file of %s (%s)", + return error("git checkout-index: unable to read sha1 file of %s (%s)", path, sha1_to_hex(ce->sha1)); if (to_tempfile || !has_symlinks) { if (to_tempfile) { @@ -155,31 +155,31 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout fd = create_file(path, 0666); if (fd < 0) { free(new); - return error("git-checkout-index: unable to create " + return error("git checkout-index: unable to create " "file %s (%s)", path, strerror(errno)); } wrote = write_in_full(fd, new, size); close(fd); free(new); if (wrote != size) - return error("git-checkout-index: unable to write file %s", + return error("git checkout-index: unable to write file %s", path); } else { wrote = symlink(new, path); free(new); if (wrote) - return error("git-checkout-index: unable to create " + return error("git checkout-index: unable to create " "symlink %s (%s)", path, strerror(errno)); } break; case S_IFGITLINK: if (to_tempfile) - return error("git-checkout-index: cannot create temporary subproject %s", path); + return error("git checkout-index: cannot create temporary subproject %s", path); if (mkdir(path, 0777) < 0) - return error("git-checkout-index: cannot create subproject directory %s", path); + return error("git checkout-index: cannot create subproject directory %s", path); break; default: - return error("git-checkout-index: unknown file mode for %s", path); + return error("git checkout-index: unknown file mode for %s", path); } if (state->refresh_cache) { diff --git a/fast-import.c b/fast-import.c index 7089e6f9e6..ccdf2e57b0 100644 --- a/fast-import.c +++ b/fast-import.c @@ -376,7 +376,7 @@ static void dump_marks_helper(FILE *, uintmax_t, struct mark_set *); static void write_crash_report(const char *err) { - char *loc = git_path("fast_import_crash_%d", getpid()); + char *loc = git_path("fast_import_crash_%"PRIuMAX, (uintmax_t) getpid()); FILE *rpt = fopen(loc, "w"); struct branch *b; unsigned long lu; @@ -390,8 +390,8 @@ static void write_crash_report(const char *err) fprintf(stderr, "fast-import: dumping crash report to %s\n", loc); fprintf(rpt, "fast-import crash report:\n"); - fprintf(rpt, " fast-import process: %d\n", getpid()); - fprintf(rpt, " parent process : %d\n", getppid()); + fprintf(rpt, " fast-import process: %"PRIuMAX"\n", (uintmax_t) getpid()); + fprintf(rpt, " parent process : %"PRIuMAX"\n", (uintmax_t) getppid()); fprintf(rpt, " at %s\n", show_date(time(NULL), 0, DATE_LOCAL)); fputc('\n', rpt); @@ -951,7 +951,8 @@ static void end_packfile(void) close_pack_windows(pack_data); fixup_pack_header_footer(pack_data->pack_fd, pack_data->sha1, - pack_data->pack_name, object_count); + pack_data->pack_name, object_count, + NULL, 0); close(pack_data->pack_fd); idx_name = keep_pack(create_index()); diff --git a/git-compat-util.h b/git-compat-util.h index cf89cdf459..db2836fbde 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -99,6 +99,11 @@ #include <iconv.h> #endif +#ifndef NO_OPENSSL +#include <openssl/ssl.h> +#include <openssl/err.h> +#endif + /* On most systems <limits.h> would have given us this, but * not on some systems (e.g. GNU/Hurd). */ @@ -192,6 +197,12 @@ extern int git_munmap(void *start, size_t length); #endif /* NO_MMAP */ +#ifdef NO_ST_BLOCKS_IN_STRUCT_STAT +#define on_disk_bytes(st) ((st).st_size) +#else +#define on_disk_bytes(st) ((st).st_blocks * 512) +#endif + #define DEFAULT_PACKED_GIT_LIMIT \ ((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256)) @@ -318,11 +329,13 @@ extern unsigned char sane_ctype[256]; #define GIT_SPACE 0x01 #define GIT_DIGIT 0x02 #define GIT_ALPHA 0x04 +#define GIT_SPECIAL 0x08 #define sane_istest(x,mask) ((sane_ctype[(unsigned char)(x)] & (mask)) != 0) #define isspace(x) sane_istest(x,GIT_SPACE) #define isdigit(x) sane_istest(x,GIT_DIGIT) #define isalpha(x) sane_istest(x,GIT_ALPHA) #define isalnum(x) sane_istest(x,GIT_ALPHA | GIT_DIGIT) +#define isspecial(x) sane_istest(x,GIT_SPECIAL) #define tolower(x) sane_case((unsigned char)(x), 0x20) #define toupper(x) sane_case((unsigned char)(x), 0) diff --git a/git-filter-branch.sh b/git-filter-branch.sh index a324cf0596..81392add0b 100755 --- a/git-filter-branch.sh +++ b/git-filter-branch.sh @@ -232,11 +232,11 @@ mkdir ../map || die "Could not create map/ directory" case "$filter_subdir" in "") git rev-list --reverse --topo-order --default HEAD \ - --parents "$@" + --parents --simplify-merges "$@" ;; *) git rev-list --reverse --topo-order --default HEAD \ - --parents "$@" -- "$filter_subdir" + --parents --simplify-merges "$@" -- "$filter_subdir" esac > ../revs || die "Could not get the commits" commits=$(wc -l <../revs | tr -d " ") @@ -317,24 +317,20 @@ done <../revs # In case of a subdirectory filter, it is possible that a specified head # is not in the set of rewritten commits, because it was pruned by the -# revision walker. Fix it by mapping these heads to the next rewritten -# ancestor(s), i.e. the boundaries in the set of rewritten commits. +# revision walker. Fix it by mapping these heads to the unique nearest +# ancestor that survived the pruning. -# NEEDSWORK: we should sort the unmapped refs topologically first -while read ref -do - sha1=$(git rev-parse "$ref"^0) - test -f "$workdir"/../map/$sha1 && continue - # Assign the boundarie(s) in the set of rewritten commits - # as the replacement commit(s). - # (This would look a bit nicer if --not --stdin worked.) - for p in $( (cd "$workdir"/../map; ls | sed "s/^/^/") | - git rev-list $ref --boundary --stdin | - sed -n "s/^-//p") +if test "$filter_subdir" +then + while read ref do - map $p >> "$workdir"/../map/$sha1 - done -done < "$tempdir"/heads + sha1=$(git rev-parse "$ref"^0) + test -f "$workdir"/../map/$sha1 && continue + ancestor=$(git rev-list --simplify-merges -1 \ + $ref -- "$filter_subdir") + test "$ancestor" && echo $(map $ancestor) >> "$workdir"/../map/$sha1 + done < "$tempdir"/heads +fi # Finally update the refs @@ -416,15 +412,17 @@ if [ "$filter_tag_name" ]; then echo "$ref -> $new_ref ($sha1 -> $new_sha1)" if [ "$type" = "tag" ]; then - new_sha1=$(git cat-file tag "$ref" | + new_sha1=$( ( printf 'object %s\ntype commit\ntag %s\n' \ + "$new_sha1" "$new_ref" + git cat-file tag "$ref" | sed -n \ -e "1,/^$/{ - s/^object .*/object $new_sha1/ - s/^type .*/type commit/ - s/^tag .*/tag $new_ref/ + /^object /d + /^type /d + /^tag /d }" \ -e '/^-----BEGIN PGP SIGNATURE-----/q' \ - -e 'p' | + -e 'p' ) | git mktag) || die "Could not create new tag object for $ref" if git cat-file tag "$ref" | \ diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index ad65aaad5a..10d8a4422f 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -657,6 +657,8 @@ proc apply_config {} { } set default_config(branch.autosetupmerge) true +set default_config(merge.tool) {} +set default_config(merge.keepbackup) true set default_config(merge.diffstat) true set default_config(merge.summary) false set default_config(merge.verbosity) 2 @@ -668,6 +670,7 @@ set default_config(gui.pruneduringfetch) false set default_config(gui.trustmtime) false set default_config(gui.fastcopyblame) false set default_config(gui.copyblamethreshold) 40 +set default_config(gui.blamehistoryctx) 7 set default_config(gui.diffcontext) 5 set default_config(gui.commitmsgwidth) 75 set default_config(gui.newbranchtemplate) {} @@ -1323,6 +1326,8 @@ proc rescan_done {fd buf after} { unlock_index display_all_files if {$current_diff_path ne {}} reshow_diff + if {$current_diff_path eq {}} select_first_diff + uplevel #0 $after } @@ -1619,6 +1624,15 @@ static unsigned char file_merge_bits[] = { 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f}; } -maskdata $filemask +image create bitmap file_statechange -background white -foreground green -data { +#define file_merge_width 14 +#define file_merge_height 15 +static unsigned char file_statechange_bits[] = { + 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x62, 0x10, + 0x62, 0x10, 0xba, 0x11, 0xba, 0x11, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10, + 0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + set ui_index .vpane.files.index.list set ui_workdir .vpane.files.workdir.list @@ -1627,12 +1641,14 @@ set all_icons(A$ui_index) file_fulltick set all_icons(M$ui_index) file_fulltick set all_icons(D$ui_index) file_removed set all_icons(U$ui_index) file_merge +set all_icons(T$ui_index) file_statechange set all_icons(_$ui_workdir) file_plain set all_icons(M$ui_workdir) file_mod set all_icons(D$ui_workdir) file_question set all_icons(U$ui_workdir) file_merge set all_icons(O$ui_workdir) file_plain +set all_icons(T$ui_workdir) file_statechange set max_status_desc 0 foreach i { @@ -1643,6 +1659,9 @@ foreach i { {MM {mc "Portions staged for commit"}} {MD {mc "Staged for commit, missing"}} + {_T {mc "File type changed, not staged"}} + {T_ {mc "File type changed, staged"}} + {_O {mc "Untracked, not staged"}} {A_ {mc "Staged for commit"}} {AM {mc "Portions staged for commit"}} @@ -1652,10 +1671,12 @@ foreach i { {D_ {mc "Staged for removal"}} {DO {mc "Staged for removal, still present"}} + {_U {mc "Requires merge resolution"}} {U_ {mc "Requires merge resolution"}} {UU {mc "Requires merge resolution"}} {UM {mc "Requires merge resolution"}} {UD {mc "Requires merge resolution"}} + {UT {mc "Requires merge resolution"}} } { set text [eval [lindex $i 1]] if {$max_status_desc < [string length $text]} { @@ -1796,13 +1817,120 @@ proc do_rescan {} { rescan ui_ready } +proc ui_do_rescan {} { + rescan {force_first_diff; ui_ready} +} + proc do_commit {} { commit_tree } proc next_diff {} { global next_diff_p next_diff_w next_diff_i - show_diff $next_diff_p $next_diff_w $next_diff_i + show_diff $next_diff_p $next_diff_w {} +} + +proc find_anchor_pos {lst name} { + set lid [lsearch -sorted -exact $lst $name] + + if {$lid == -1} { + set lid 0 + foreach lname $lst { + if {$lname >= $name} break + incr lid + } + } + + return $lid +} + +proc find_file_from {flist idx delta path mmask} { + global file_states + + set len [llength $flist] + while {$idx >= 0 && $idx < $len} { + set name [lindex $flist $idx] + + if {$name ne $path && [info exists file_states($name)]} { + set state [lindex $file_states($name) 0] + + if {$mmask eq {} || [regexp $mmask $state]} { + return $idx + } + } + + incr idx $delta + } + + return {} +} + +proc find_next_diff {w path {lno {}} {mmask {}}} { + global next_diff_p next_diff_w next_diff_i + global file_lists ui_index ui_workdir + + set flist $file_lists($w) + if {$lno eq {}} { + set lno [find_anchor_pos $flist $path] + } else { + incr lno -1 + } + + if {$mmask ne {} && ![regexp {(^\^)|(\$$)} $mmask]} { + if {$w eq $ui_index} { + set mmask "^$mmask" + } else { + set mmask "$mmask\$" + } + } + + set idx [find_file_from $flist $lno 1 $path $mmask] + if {$idx eq {}} { + incr lno -1 + set idx [find_file_from $flist $lno -1 $path $mmask] + } + + if {$idx ne {}} { + set next_diff_w $w + set next_diff_p [lindex $flist $idx] + set next_diff_i [expr {$idx+1}] + return 1 + } else { + return 0 + } +} + +proc next_diff_after_action {w path {lno {}} {mmask {}}} { + global current_diff_path + + if {$path ne $current_diff_path} { + return {} + } elseif {[find_next_diff $w $path $lno $mmask]} { + return {next_diff;} + } else { + return {reshow_diff;} + } +} + +proc select_first_diff {} { + global ui_workdir + + if {[find_next_diff $ui_workdir {} 1 {^_?U}] || + [find_next_diff $ui_workdir {} 1 {[^O]$}]} { + next_diff + } +} + +proc force_first_diff {} { + global current_diff_path + + if {[info exists file_states($current_diff_path)]} { + set state [lindex $file_states($current_diff_path) 0] + + if {[string index $state 1] ne {O}} return + } + + select_first_diff } proc toggle_or_diff {w x y} { @@ -1823,34 +1951,27 @@ proc toggle_or_diff {w x y} { $ui_index tag remove in_sel 0.0 end $ui_workdir tag remove in_sel 0.0 end - if {$col == 0 && $y > 1} { - set i [expr {$lno-1}] - set ll [expr {[llength $file_lists($w)]-1}] - - if {$i == $ll && $i == 0} { - set after {reshow_diff;} - } else { - global next_diff_p next_diff_w next_diff_i - - set next_diff_w $w - - if {$i < $ll} { - set i [expr {$i + 1}] - set next_diff_i $i - } else { - set next_diff_i $i - set i [expr {$i - 1}] - } + # Do not stage files with conflicts + if {[info exists file_states($path)]} { + set state [lindex $file_states($path) 0] + } else { + set state {__} + } - set next_diff_p [lindex $file_lists($w) $i] + if {[string first {U} $state] >= 0} { + set col 1 + } - if {$next_diff_p ne {} && $current_diff_path ne {}} { - set after {next_diff;} - } else { - set after {} - } + # Restage the file, or simply show the diff + if {$col == 0 && $y > 1} { + if {[string index $state 1] eq {O}} { + set mmask {} + } else { + set mmask {[^O]} } + set after [next_diff_after_action $w $path $lno $mmask] + if {$w eq $ui_index} { update_indexinfo \ "Unstaging [short_path $path] from commit" \ @@ -1932,7 +2053,7 @@ proc show_more_context {} { proc show_less_context {} { global repo_config - if {$repo_config(gui.diffcontext) >= 1} { + if {$repo_config(gui.diffcontext) > 1} { incr repo_config(gui.diffcontext) -1 reshow_diff } @@ -2113,7 +2234,7 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} { .mbar.commit add separator .mbar.commit add command -label [mc Rescan] \ - -command do_rescan \ + -command ui_do_rescan \ -accelerator F5 lappend disable_on_lock \ [list .mbar.commit entryconf [.mbar.commit index last] -state] @@ -2281,10 +2402,15 @@ proc usage {} { switch -- $subcommand { browser - blame { - set subcommand_args {rev? path} + if {$subcommand eq "blame"} { + set subcommand_args {[--line=<num>] rev? path} + } else { + set subcommand_args {rev? path} + } if {$argv eq {}} usage set head {} set path {} + set jump_spec {} set is_path 0 foreach a $argv { if {$is_path || [file exists $_prefix$a]} { @@ -2298,6 +2424,9 @@ blame { set path {} } set is_path 1 + } elseif {[regexp {^--line=(\d+)$} $a a lnum]} { + if {$jump_spec ne {} || $head ne {}} usage + set jump_spec [list $lnum] } elseif {$head eq {}} { if {$head ne {}} usage set head $a @@ -2329,6 +2458,7 @@ blame { switch -- $subcommand { browser { + if {$jump_spec ne {}} usage if {$head eq {}} { if {$path ne {} && [file isdirectory $path]} { set head $current_branch @@ -2344,7 +2474,7 @@ blame { puts stderr [mc "fatal: cannot stat path %s: No such file or directory" $path] exit 1 } - blame::new $head $path + blame::new $head $path $jump_spec } } return @@ -2460,7 +2590,7 @@ pack .vpane.lower.commarea.buttons.l -side top -fill x pack .vpane.lower.commarea.buttons -side left -fill y button .vpane.lower.commarea.buttons.rescan -text [mc Rescan] \ - -command do_rescan + -command ui_do_rescan pack .vpane.lower.commarea.buttons.rescan -side top -fill x lappend disable_on_lock \ {.vpane.lower.commarea.buttons.rescan conf -state} @@ -2689,6 +2819,51 @@ $ui_diff tag raise sel # -- Diff Body Context Menu # + +proc create_common_diff_popup {ctxm} { + $ctxm add command \ + -label [mc "Show Less Context"] \ + -command show_less_context + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add command \ + -label [mc "Show More Context"] \ + -command show_more_context + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add separator + $ctxm add command \ + -label [mc Refresh] \ + -command reshow_diff + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add command \ + -label [mc Copy] \ + -command {tk_textCopy $ui_diff} + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add command \ + -label [mc "Select All"] \ + -command {focus $ui_diff;$ui_diff tag add sel 0.0 end} + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add command \ + -label [mc "Copy All"] \ + -command { + $ui_diff tag add sel 0.0 end + tk_textCopy $ui_diff + $ui_diff tag remove sel 0.0 end + } + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add separator + $ctxm add command \ + -label [mc "Decrease Font Size"] \ + -command {incr_font_size font_diff -1} + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add command \ + -label [mc "Increase Font Size"] \ + -command {incr_font_size font_diff 1} + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add separator + $ctxm add command -label [mc "Options..."] \ + -command do_options +} + set ctxm .vpane.lower.diff.body.ctxm menu $ctxm -tearoff 0 $ctxm add command \ @@ -2702,71 +2877,65 @@ $ctxm add command \ set ui_diff_applyline [$ctxm index last] lappend diff_actions [list $ctxm entryconf $ui_diff_applyline -state] $ctxm add separator -$ctxm add command \ - -label [mc "Show Less Context"] \ - -command show_less_context -lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] -$ctxm add command \ - -label [mc "Show More Context"] \ - -command show_more_context -lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] -$ctxm add separator -$ctxm add command \ - -label [mc Refresh] \ - -command reshow_diff -lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] -$ctxm add command \ - -label [mc Copy] \ - -command {tk_textCopy $ui_diff} -lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] -$ctxm add command \ - -label [mc "Select All"] \ - -command {focus $ui_diff;$ui_diff tag add sel 0.0 end} -lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] -$ctxm add command \ - -label [mc "Copy All"] \ - -command { - $ui_diff tag add sel 0.0 end - tk_textCopy $ui_diff - $ui_diff tag remove sel 0.0 end - } -lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] -$ctxm add separator -$ctxm add command \ - -label [mc "Decrease Font Size"] \ - -command {incr_font_size font_diff -1} -lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] -$ctxm add command \ - -label [mc "Increase Font Size"] \ - -command {incr_font_size font_diff 1} -lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] -$ctxm add separator -$ctxm add command -label [mc "Options..."] \ - -command do_options -proc popup_diff_menu {ctxm x y X Y} { +create_common_diff_popup $ctxm + +set ctxmmg .vpane.lower.diff.body.ctxmmg +menu $ctxmmg -tearoff 0 +$ctxmmg add command \ + -label [mc "Run Merge Tool"] \ + -command {merge_resolve_tool} +lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state] +$ctxmmg add separator +$ctxmmg add command \ + -label [mc "Use Remote Version"] \ + -command {merge_resolve_one 3} +lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state] +$ctxmmg add command \ + -label [mc "Use Local Version"] \ + -command {merge_resolve_one 2} +lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state] +$ctxmmg add command \ + -label [mc "Revert To Base"] \ + -command {merge_resolve_one 1} +lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state] +$ctxmmg add separator +create_common_diff_popup $ctxmmg + +proc popup_diff_menu {ctxm ctxmmg x y X Y} { global current_diff_path file_states set ::cursorX $x set ::cursorY $y - if {$::ui_index eq $::current_diff_side} { - set l [mc "Unstage Hunk From Commit"] - set t [mc "Unstage Line From Commit"] + if {[info exists file_states($current_diff_path)]} { + set state [lindex $file_states($current_diff_path) 0] } else { - set l [mc "Stage Hunk For Commit"] - set t [mc "Stage Line For Commit"] - } - if {$::is_3way_diff - || $current_diff_path eq {} - || ![info exists file_states($current_diff_path)] - || {_O} eq [lindex $file_states($current_diff_path) 0]} { - set s disabled + set state {__} + } + if {[string first {U} $state] >= 0} { + tk_popup $ctxmmg $X $Y } else { - set s normal + if {$::ui_index eq $::current_diff_side} { + set l [mc "Unstage Hunk From Commit"] + set t [mc "Unstage Line From Commit"] + } else { + set l [mc "Stage Hunk For Commit"] + set t [mc "Stage Line For Commit"] + } + if {$::is_3way_diff + || $current_diff_path eq {} + || {__} eq $state + || {_O} eq $state + || {_T} eq $state + || {T_} eq $state} { + set s disabled + } else { + set s normal + } + $ctxm entryconf $::ui_diff_applyhunk -state $s -label $l + $ctxm entryconf $::ui_diff_applyline -state $s -label $t + tk_popup $ctxm $X $Y } - $ctxm entryconf $::ui_diff_applyhunk -state $s -label $l - $ctxm entryconf $::ui_diff_applyline -state $s -label $t - tk_popup $ctxm $X $Y } -bind_button3 $ui_diff [list popup_diff_menu $ctxm %x %y %X %Y] +bind_button3 $ui_diff [list popup_diff_menu $ctxm $ctxmmg %x %y %X %Y] # -- Status Bar # @@ -2842,9 +3011,9 @@ if {[is_enabled transport]} { bind . <$M1B-Key-P> do_push_anywhere } -bind . <Key-F5> do_rescan -bind . <$M1B-Key-r> do_rescan -bind . <$M1B-Key-R> do_rescan +bind . <Key-F5> ui_do_rescan +bind . <$M1B-Key-r> ui_do_rescan +bind . <$M1B-Key-R> ui_do_rescan bind . <$M1B-Key-s> do_signoff bind . <$M1B-Key-S> do_signoff bind . <$M1B-Key-t> do_add_selection diff --git a/git-gui/lib/blame.tcl b/git-gui/lib/blame.tcl index b6e42cbc8f..827c85d67f 100644 --- a/git-gui/lib/blame.tcl +++ b/git-gui/lib/blame.tcl @@ -58,7 +58,7 @@ field tooltip_t {} ; # Text widget in $tooltip_wm field tooltip_timer {} ; # Current timer event for our tooltip field tooltip_commit {} ; # Commit(s) in tooltip -constructor new {i_commit i_path} { +constructor new {i_commit i_path i_jump} { global cursor_ptr variable active_color variable group_colors @@ -259,6 +259,12 @@ constructor new {i_commit i_path} { $w.ctxm add command \ -label [mc "Do Full Copy Detection"] \ -command [cb _fullcopyblame] + $w.ctxm add command \ + -label [mc "Show History Context"] \ + -command [cb _gitkcommit] + $w.ctxm add command \ + -label [mc "Blame Parent Commit"] \ + -command [cb _blameparent] foreach i $w_columns { for {set g 0} {$g < [llength $group_colors]} {incr g} { @@ -332,7 +338,7 @@ constructor new {i_commit i_path} { wm protocol $top WM_DELETE_WINDOW "destroy $top" bind $top <Destroy> [cb _kill] - _load $this {} + _load $this $i_jump } method _kill {} { @@ -787,19 +793,27 @@ method _load_commit {cur_w cur_d pos} { set lno [lindex [split [$cur_w index $pos] .] 0] set dat [lindex $line_data $lno] if {$dat ne {}} { - lappend history [list \ - $commit $path \ - $highlight_column \ - $highlight_line \ - [lindex [$w_file xview] 0] \ - [lindex [$w_file yview] 0] \ - ] - set commit [lindex $dat 0] - set path [lindex $dat 1] - _load $this [list [lindex $dat 2]] + _load_new_commit $this \ + [lindex $dat 0] \ + [lindex $dat 1] \ + [list [lindex $dat 2]] } } +method _load_new_commit {new_commit new_path jump} { + lappend history [list \ + $commit $path \ + $highlight_column \ + $highlight_line \ + [lindex [$w_file xview] 0] \ + [lindex [$w_file yview] 0] \ + ] + + set commit $new_commit + set path $new_path + _load $this $jump +} + method _showcommit {cur_w lno} { global repo_config variable active_color @@ -905,10 +919,14 @@ method _showcommit {cur_w lno} { } } -method _copycommit {} { +method _get_click_amov_info {} { set pos @$::cursorX,$::cursorY set lno [lindex [split [$::cursorW index $pos] .] 0] - set dat [lindex $amov_data $lno] + return [lindex $amov_data $lno] +} + +method _copycommit {} { + set dat [_get_click_amov_info $this] if {$dat ne {}} { clipboard clear clipboard append \ @@ -918,6 +936,124 @@ method _copycommit {} { } } +method _format_offset_date {base offset} { + set exval [expr {$base + $offset*24*60*60}] + return [clock format $exval -format {%Y-%m-%d}] +} + +method _gitkcommit {} { + set dat [_get_click_amov_info $this] + if {$dat ne {}} { + set cmit [lindex $dat 0] + set radius [get_config gui.blamehistoryctx] + set cmdline [list --select-commit=$cmit] + + if {$radius > 0} { + set author_time {} + set committer_time {} + + catch {set author_time $header($cmit,author-time)} + catch {set committer_time $header($cmit,committer-time)} + + if {$committer_time eq {}} { + set committer_time $author_time + } + + set after_time [_format_offset_date $this $committer_time [expr {-$radius}]] + set before_time [_format_offset_date $this $committer_time $radius] + + lappend cmdline --after=$after_time --before=$before_time + } + + lappend cmdline $cmit + + set base_rev "HEAD" + if {$commit ne {}} { + set base_rev $commit + } + + if {$base_rev ne $cmit} { + lappend cmdline $base_rev + } + + do_gitk $cmdline + } +} + +method _blameparent {} { + set dat [_get_click_amov_info $this] + if {$dat ne {}} { + set cmit [lindex $dat 0] + set new_path [lindex $dat 1] + + if {[catch {set cparent [git rev-parse --verify "$cmit^"]}]} { + error_popup [strcat [mc "Cannot find parent commit:"] "\n\n$err"] + return; + } + + _kill $this + + # Generate a diff between the commit and its parent, + # and use the hunks to update the line number. + # Request zero context to simplify calculations. + if {[catch {set fd [eval git_read diff-tree \ + --unified=0 $cparent $cmit $new_path]} err]} { + $status stop [mc "Unable to display parent"] + error_popup [strcat [mc "Error loading diff:"] "\n\n$err"] + return + } + + set r_orig_line [lindex $dat 2] + + fconfigure $fd \ + -blocking 0 \ + -encoding binary \ + -translation binary + fileevent $fd readable [cb _read_diff_load_commit \ + $fd $cparent $new_path $r_orig_line] + set current_fd $fd + } +} + +method _read_diff_load_commit {fd cparent new_path tline} { + if {$fd ne $current_fd} { + catch {close $fd} + return + } + + while {[gets $fd line] >= 0} { + if {[regexp {^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@} $line line \ + old_line osz old_size new_line nsz new_size]} { + + if {$osz eq {}} { set old_size 1 } + if {$nsz eq {}} { set new_size 1 } + + if {$new_line <= $tline} { + if {[expr {$new_line + $new_size}] > $tline} { + # Target line within the hunk + set line_shift [expr { + ($new_size-$old_size)*($tline-$new_line)/$new_size + }] + } else { + set line_shift [expr {$new_size-$old_size}] + } + + set r_orig_line [expr {$r_orig_line - $line_shift}] + } + } + } + + if {[eof $fd]} { + close $fd; + set current_fd {} + + _load_new_commit $this \ + $cparent \ + $new_path \ + [list $r_orig_line] + } +} ifdeleted { catch {close $fd} } + method _show_tooltip {cur_w pos} { if {$tooltip_wm ne {}} { _open_tooltip $this $cur_w diff --git a/git-gui/lib/browser.tcl b/git-gui/lib/browser.tcl index ab470d1264..0410cc68df 100644 --- a/git-gui/lib/browser.tcl +++ b/git-gui/lib/browser.tcl @@ -151,7 +151,7 @@ method _enter {} { append p [lindex $n 1] } append p $name - blame::new $browser_commit $p + blame::new $browser_commit $p {} } } } diff --git a/git-gui/lib/commit.tcl b/git-gui/lib/commit.tcl index 40a7103557..2977315624 100644 --- a/git-gui/lib/commit.tcl +++ b/git-gui/lib/commit.tcl @@ -149,7 +149,9 @@ The rescan will be automatically started now. _? {continue} A? - D? - + T_ - M? {set files_ready 1} + _U - U? { error_popup [mc "Unmerged files cannot be committed. @@ -428,6 +430,7 @@ A rescan will be automatically started now. __ - A_ - M_ - + T_ - D_ { unset file_states($path) catch {unset selected_paths($path)} diff --git a/git-gui/lib/diff.tcl b/git-gui/lib/diff.tcl index 52b79e4a1f..a30c80a935 100644 --- a/git-gui/lib/diff.tcl +++ b/git-gui/lib/diff.tcl @@ -24,10 +24,16 @@ proc reshow_diff {} { set p $current_diff_path if {$p eq {}} { # No diff is being shown. - } elseif {$current_diff_side eq {} - || [catch {set s $file_states($p)}] - || [lsearch -sorted -exact $file_lists($current_diff_side) $p] == -1} { + } elseif {$current_diff_side eq {}} { clear_diff + } elseif {[catch {set s $file_states($p)}] + || [lsearch -sorted -exact $file_lists($current_diff_side) $p] == -1} { + + if {[find_next_diff $current_diff_side $p {} {[^O]}]} { + next_diff + } else { + clear_diff + } } else { set save_pos [lindex [$ui_diff yview] 0] show_diff $p $current_diff_side {} $save_pos @@ -59,6 +65,7 @@ proc show_diff {path w {lno {}} {scroll_pos {}}} { global is_3way_diff diff_active repo_config global ui_diff ui_index ui_workdir global current_diff_path current_diff_side current_diff_header + global current_diff_queue if {$diff_active || ![lock_index read]} return @@ -71,17 +78,74 @@ proc show_diff {path w {lno {}} {scroll_pos {}}} { } if {$lno >= 1} { $w tag add in_diff $lno.0 [expr {$lno + 1}].0 + $w see $lno.0 } set s $file_states($path) set m [lindex $s 0] - set is_3way_diff 0 - set diff_active 1 set current_diff_path $path set current_diff_side $w - set current_diff_header {} + set current_diff_queue {} ui_status [mc "Loading diff of %s..." [escape_path $path]] + if {[string first {U} $m] >= 0} { + merge_load_stages $path [list show_unmerged_diff $scroll_pos] + } elseif {$m eq {_O}} { + show_other_diff $path $w $m $scroll_pos + } else { + start_show_diff $scroll_pos + } +} + +proc show_unmerged_diff {scroll_pos} { + global current_diff_path current_diff_side + global merge_stages ui_diff + global current_diff_queue + + if {$merge_stages(2) eq {}} { + lappend current_diff_queue \ + [list "LOCAL: deleted\nREMOTE:\n" d======= \ + [list ":1:$current_diff_path" ":3:$current_diff_path"]] + } elseif {$merge_stages(3) eq {}} { + lappend current_diff_queue \ + [list "REMOTE: deleted\nLOCAL:\n" d======= \ + [list ":1:$current_diff_path" ":2:$current_diff_path"]] + } elseif {[lindex $merge_stages(1) 0] eq {120000} + || [lindex $merge_stages(2) 0] eq {120000} + || [lindex $merge_stages(3) 0] eq {120000}} { + lappend current_diff_queue \ + [list "LOCAL:\n" d======= \ + [list ":1:$current_diff_path" ":2:$current_diff_path"]] + lappend current_diff_queue \ + [list "REMOTE:\n" d======= \ + [list ":1:$current_diff_path" ":3:$current_diff_path"]] + } else { + start_show_diff $scroll_pos + return + } + + advance_diff_queue $scroll_pos +} + +proc advance_diff_queue {scroll_pos} { + global current_diff_queue ui_diff + + set item [lindex $current_diff_queue 0] + set current_diff_queue [lrange $current_diff_queue 1 end] + + $ui_diff conf -state normal + $ui_diff insert end [lindex $item 0] [lindex $item 1] + $ui_diff conf -state disabled + + start_show_diff $scroll_pos [lindex $item 2] +} + +proc show_other_diff {path w m scroll_pos} { + global file_states file_lists + global is_3way_diff diff_active repo_config + global ui_diff ui_index ui_workdir + global current_diff_path current_diff_side current_diff_header + # - Git won't give us the diff, there's nothing to compare to! # if {$m eq {_O}} { @@ -160,13 +224,29 @@ proc show_diff {path w {lno {}} {scroll_pos {}}} { ui_ready return } +} + +proc start_show_diff {scroll_pos {add_opts {}}} { + global file_states file_lists + global is_3way_diff diff_active repo_config + global ui_diff ui_index ui_workdir + global current_diff_path current_diff_side current_diff_header + + set path $current_diff_path + set w $current_diff_side + + set s $file_states($path) + set m [lindex $s 0] + set is_3way_diff 0 + set diff_active 1 + set current_diff_header {} set cmd [list] if {$w eq $ui_index} { lappend cmd diff-index lappend cmd --cached } elseif {$w eq $ui_workdir} { - if {[string index $m 0] eq {U}} { + if {[string first {U} $m] >= 0} { lappend cmd diff } else { lappend cmd diff-files @@ -175,14 +255,18 @@ proc show_diff {path w {lno {}} {scroll_pos {}}} { lappend cmd -p lappend cmd --no-color - if {$repo_config(gui.diffcontext) >= 0} { + if {$repo_config(gui.diffcontext) >= 1} { lappend cmd "-U$repo_config(gui.diffcontext)" } if {$w eq $ui_index} { lappend cmd [PARENT] } - lappend cmd -- - lappend cmd $path + if {$add_opts ne {}} { + eval lappend cmd $add_opts + } else { + lappend cmd -- + lappend cmd $path + } if {[catch {set fd [eval git_read --nice $cmd]} err]} { set diff_active 0 @@ -192,6 +276,7 @@ proc show_diff {path w {lno {}} {scroll_pos {}}} { return } + set ::current_diff_inheader 1 fconfigure $fd \ -blocking 0 \ -encoding binary \ @@ -202,23 +287,27 @@ proc show_diff {path w {lno {}} {scroll_pos {}}} { proc read_diff {fd scroll_pos} { global ui_diff diff_active global is_3way_diff current_diff_header + global current_diff_queue $ui_diff conf -state normal while {[gets $fd line] >= 0} { # -- Cleanup uninteresting diff header lines. # - if { [string match {diff --git *} $line] - || [string match {diff --cc *} $line] - || [string match {diff --combined *} $line] - || [string match {--- *} $line] - || [string match {+++ *} $line]} { - append current_diff_header $line "\n" - continue + if {$::current_diff_inheader} { + if { [string match {diff --git *} $line] + || [string match {diff --cc *} $line] + || [string match {diff --combined *} $line] + || [string match {--- *} $line] + || [string match {+++ *} $line]} { + append current_diff_header $line "\n" + continue + } } if {[string match {index *} $line]} continue if {$line eq {deleted file mode 120000}} { set line "deleted symlink" } + set ::current_diff_inheader 0 # -- Automatically detect if this is a 3 way diff. # @@ -286,6 +375,12 @@ proc read_diff {fd scroll_pos} { if {[eof $fd]} { close $fd + + if {$current_diff_queue ne {}} { + advance_diff_queue $scroll_pos + return + } + set diff_active 0 unlock_index if {$scroll_pos ne {}} { @@ -366,10 +461,9 @@ proc apply_hunk {x y} { } unlock_index display_file $current_diff_path $mi + # This should trigger shift to the next changed file if {$o eq {_}} { - clear_diff - } else { - set current_diff_path $current_diff_path + reshow_diff } } diff --git a/git-gui/lib/index.tcl b/git-gui/lib/index.tcl index 3c1fce7475..b045219a1c 100644 --- a/git-gui/lib/index.tcl +++ b/git-gui/lib/index.tcl @@ -99,6 +99,7 @@ proc write_update_indexinfo {fd pathList totalCnt batch after} { switch -glob -- [lindex $s 0] { A? {set new _O} M? {set new _M} + T_ {set new _T} D_ {set new _D} D? {set new _?} ?? {continue} @@ -162,6 +163,8 @@ proc write_update_index {fd pathList totalCnt batch after} { ?D {set new D_} _O - AM {set new A_} + _T {set new T_} + _U - U? { if {[file exists $path]} { set new M_ @@ -231,6 +234,7 @@ proc write_checkout_index {fd pathList totalCnt batch after} { switch -glob -- [lindex $file_states($path) 0] { U? {continue} ?M - + ?T - ?D { puts -nonewline $fd "[encoding convertto $path]\0" display_file $path ?_ @@ -252,6 +256,7 @@ proc unstage_helper {txt paths} { switch -glob -- [lindex $file_states($path) 0] { A? - M? - + T_ - D? { lappend pathList $path if {$path eq $current_diff_path} { @@ -296,6 +301,7 @@ proc add_helper {txt paths} { _O - ?M - ?D - + ?T - U? { lappend pathList $path if {$path eq $current_diff_path} { @@ -336,6 +342,7 @@ proc do_add_all {} { switch -glob -- [lindex $file_states($path) 0] { U? {continue} ?M - + ?T - ?D {lappend paths $path} } } @@ -353,6 +360,7 @@ proc revert_helper {txt paths} { switch -glob -- [lindex $file_states($path) 0] { U? {continue} ?M - + ?T - ?D { lappend pathList $path if {$path eq $current_diff_path} { @@ -409,11 +417,11 @@ proc do_revert_selection {} { if {[array size selected_paths] > 0} { revert_helper \ - {Reverting selected files} \ + [mc "Reverting selected files"] \ [array names selected_paths] } elseif {$current_diff_path ne {}} { revert_helper \ - "Reverting [short_path $current_diff_path]" \ + [mc "Reverting %s" [short_path $current_diff_path]] \ [list $current_diff_path] } } diff --git a/git-gui/lib/mergetool.tcl b/git-gui/lib/mergetool.tcl new file mode 100644 index 0000000000..79c58bc7bc --- /dev/null +++ b/git-gui/lib/mergetool.tcl @@ -0,0 +1,373 @@ +# git-gui merge conflict resolution +# parts based on git-mergetool (c) 2006 Theodore Y. Ts'o + +proc merge_resolve_one {stage} { + global current_diff_path + + switch -- $stage { + 1 { set target [mc "the base version"] } + 2 { set target [mc "this branch"] } + 3 { set target [mc "the other branch"] } + } + + set op_question [mc "Force resolution to %s? +Note that the diff shows only conflicting changes. + +%s will be overwritten. + +This operation can be undone only by restarting the merge." \ + $target [short_path $current_diff_path]] + + if {[ask_popup $op_question] eq {yes}} { + merge_load_stages $current_diff_path [list merge_force_stage $stage] + } +} + +proc merge_add_resolution {path} { + global current_diff_path ui_workdir + + set after [next_diff_after_action $ui_workdir $path {} {^_?U}] + + update_index \ + [mc "Adding resolution for %s" [short_path $path]] \ + [list $path] \ + [concat $after [list ui_ready]] +} + +proc merge_force_stage {stage} { + global current_diff_path merge_stages + + if {$merge_stages($stage) ne {}} { + git checkout-index -f --stage=$stage -- $current_diff_path + } else { + file delete -- $current_diff_path + } + + merge_add_resolution $current_diff_path +} + +proc merge_load_stages {path cont} { + global merge_stages_fd merge_stages merge_stages_buf + + if {[info exists merge_stages_fd]} { + catch { kill_file_process $merge_stages_fd } + catch { close $merge_stages_fd } + } + + set merge_stages(0) {} + set merge_stages(1) {} + set merge_stages(2) {} + set merge_stages(3) {} + set merge_stages_buf {} + + set merge_stages_fd [eval git_read ls-files -u -z -- $path] + + fconfigure $merge_stages_fd -blocking 0 -translation binary -encoding binary + fileevent $merge_stages_fd readable [list read_merge_stages $merge_stages_fd $cont] +} + +proc read_merge_stages {fd cont} { + global merge_stages_buf merge_stages_fd merge_stages + + append merge_stages_buf [read $fd] + set pck [split $merge_stages_buf "\0"] + set merge_stages_buf [lindex $pck end] + + if {[eof $fd] && $merge_stages_buf ne {}} { + lappend pck {} + set merge_stages_buf {} + } + + foreach p [lrange $pck 0 end-1] { + set fcols [split $p "\t"] + set cols [split [lindex $fcols 0] " "] + set stage [lindex $cols 2] + + set merge_stages($stage) [lrange $cols 0 1] + } + + if {[eof $fd]} { + close $fd + unset merge_stages_fd + eval $cont + } +} + +proc merge_resolve_tool {} { + global current_diff_path + + merge_load_stages $current_diff_path [list merge_resolve_tool2] +} + +proc merge_resolve_tool2 {} { + global current_diff_path merge_stages + + # Validate the stages + if {$merge_stages(2) eq {} || + [lindex $merge_stages(2) 0] eq {120000} || + [lindex $merge_stages(2) 0] eq {160000} || + $merge_stages(3) eq {} || + [lindex $merge_stages(3) 0] eq {120000} || + [lindex $merge_stages(3) 0] eq {160000} + } { + error_popup [mc "Cannot resolve deletion or link conflicts using a tool"] + return + } + + if {![file exists $current_diff_path]} { + error_popup [mc "Conflict file does not exist"] + return + } + + # Determine the tool to use + set tool [get_config merge.tool] + if {$tool eq {}} { set tool meld } + + set merge_tool_path [get_config "mergetool.$tool.path"] + if {$merge_tool_path eq {}} { + switch -- $tool { + emerge { set merge_tool_path "emacs" } + araxis { set merge_tool_path "compare" } + default { set merge_tool_path $tool } + } + } + + # Make file names + set filebase [file rootname $current_diff_path] + set fileext [file extension $current_diff_path] + set basename [lindex [file split $current_diff_path] end] + + set MERGED $current_diff_path + set BASE "./$MERGED.BASE$fileext" + set LOCAL "./$MERGED.LOCAL$fileext" + set REMOTE "./$MERGED.REMOTE$fileext" + set BACKUP "./$MERGED.BACKUP$fileext" + + set base_stage $merge_stages(1) + + # Build the command line + switch -- $tool { + kdiff3 { + if {$base_stage ne {}} { + set cmdline [list "$merge_tool_path" --auto --L1 "$MERGED (Base)" \ + --L2 "$MERGED (Local)" --L3 "$MERGED (Remote)" -o "$MERGED" "$BASE" "$LOCAL" "$REMOTE"] + } else { + set cmdline [list "$merge_tool_path" --auto --L1 "$MERGED (Local)" \ + --L2 "$MERGED (Remote)" -o "$MERGED" "$LOCAL" "$REMOTE"] + } + } + tkdiff { + if {$base_stage ne {}} { + set cmdline [list "$merge_tool_path" -a "$BASE" -o "$MERGED" "$LOCAL" "$REMOTE"] + } else { + set cmdline [list "$merge_tool_path" -o "$MERGED" "$LOCAL" "$REMOTE"] + } + } + meld { + set cmdline [list "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"] + } + gvimdiff { + set cmdline [list "$merge_tool_path" -f "$LOCAL" "$MERGED" "$REMOTE"] + } + xxdiff { + if {$base_stage ne {}} { + set cmdline [list "$merge_tool_path" -X --show-merged-pane \ + -R {Accel.SaveAsMerged: "Ctrl-S"} \ + -R {Accel.Search: "Ctrl+F"} \ + -R {Accel.SearchForward: "Ctrl-G"} \ + --merged-file "$MERGED" "$LOCAL" "$BASE" "$REMOTE"] + } else { + set cmdline [list "$merge_tool_path" -X --show-merged-pane \ + -R {Accel.SaveAsMerged: "Ctrl-S"} \ + -R {Accel.Search: "Ctrl+F"} \ + -R {Accel.SearchForward: "Ctrl-G"} \ + --merged-file "$MERGED" "$LOCAL" "$REMOTE"] + } + } + opendiff { + if {$base_stage ne {}} { + set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" -ancestor "$BASE" -merge "$MERGED"] + } else { + set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" -merge "$MERGED"] + } + } + ecmerge { + if {$base_stage ne {}} { + set cmdline [list "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" --default --mode=merge3 --to="$MERGED"] + } else { + set cmdline [list "$merge_tool_path" "$LOCAL" "$REMOTE" --default --mode=merge2 --to="$MERGED"] + } + } + emerge { + if {$base_stage ne {}} { + set cmdline [list "$merge_tool_path" -f emerge-files-with-ancestor-command \ + "$LOCAL" "$REMOTE" "$BASE" "$basename"] + } else { + set cmdline [list "$merge_tool_path" -f emerge-files-command \ + "$LOCAL" "$REMOTE" "$basename"] + } + } + winmerge { + if {$base_stage ne {}} { + # This tool does not support 3-way merges. + # Use the 'conflict file' resolution feature instead. + set cmdline [list "$merge_tool_path" -e -ub "$MERGED"] + } else { + set cmdline [list "$merge_tool_path" -e -ub -wl \ + -dl "Theirs File" -dr "Mine File" "$REMOTE" "$LOCAL" "$MERGED"] + } + } + araxis { + if {$base_stage ne {}} { + set cmdline [list "$merge_tool_path" -wait -merge -3 -a1 \ + -title1:"'$MERGED (Base)'" -title2:"'$MERGED (Local)'" \ + -title3:"'$MERGED (Remote)'" \ + "$BASE" "$LOCAL" "$REMOTE" "$MERGED"] + } else { + set cmdline [list "$merge_tool_path" -wait -2 \ + -title1:"'$MERGED (Local)'" -title2:"'$MERGED (Remote)'" \ + "$LOCAL" "$REMOTE" "$MERGED"] + } + } + p4merge { + set cmdline [list "$merge_tool_path" "$BASE" "$REMOTE" "$LOCAL" "$MERGED"] + } + vimdiff { + error_popup [mc "Not a GUI merge tool: '%s'" $tool] + return + } + default { + error_popup [mc "Unsupported merge tool '%s'" $tool] + return + } + } + + merge_tool_start $cmdline $MERGED $BACKUP [list $BASE $LOCAL $REMOTE] +} + +proc delete_temp_files {files} { + foreach fname $files { + file delete $fname + } +} + +proc merge_tool_get_stages {target stages} { + global merge_stages + + set i 1 + foreach fname $stages { + if {$merge_stages($i) eq {}} { + file delete $fname + catch { close [open $fname w] } + } else { + # A hack to support autocrlf properly + git checkout-index -f --stage=$i -- $target + file rename -force -- $target $fname + } + incr i + } +} + +proc merge_tool_start {cmdline target backup stages} { + global merge_stages mtool_target mtool_tmpfiles mtool_fd mtool_mtime + + if {[info exists mtool_fd]} { + if {[ask_popup [mc "Merge tool is already running, terminate it?"]] eq {yes}} { + catch { kill_file_process $mtool_fd } + catch { close $mtool_fd } + unset mtool_fd + + set old_backup [lindex $mtool_tmpfiles end] + file rename -force -- $old_backup $mtool_target + delete_temp_files $mtool_tmpfiles + } else { + return + } + } + + # Save the original file + file rename -force -- $target $backup + + # Get the blobs; it destroys $target + if {[catch {merge_tool_get_stages $target $stages} err]} { + file rename -force -- $backup $target + delete_temp_files $stages + error_popup [mc "Error retrieving versions:\n%s" $err] + return + } + + # Restore the conflict file + file copy -force -- $backup $target + + # Initialize global state + set mtool_target $target + set mtool_mtime [file mtime $target] + set mtool_tmpfiles $stages + + lappend mtool_tmpfiles $backup + + # Force redirection to avoid interpreting output on stderr + # as an error, and launch the tool + lappend cmdline {2>@1} + + if {[catch { set mtool_fd [_open_stdout_stderr $cmdline] } err]} { + delete_temp_files $mtool_tmpfiles + error_popup [mc "Could not start the merge tool:\n\n%s" $err] + return + } + + ui_status [mc "Running merge tool..."] + + fconfigure $mtool_fd -blocking 0 -translation binary -encoding binary + fileevent $mtool_fd readable [list read_mtool_output $mtool_fd] +} + +proc read_mtool_output {fd} { + global mtool_fd mtool_tmpfiles + + read $fd + if {[eof $fd]} { + unset mtool_fd + + fconfigure $fd -blocking 1 + merge_tool_finish $fd + } +} + +proc merge_tool_finish {fd} { + global mtool_tmpfiles mtool_target mtool_mtime + + set backup [lindex $mtool_tmpfiles end] + set failed 0 + + # Check the return code + if {[catch {close $fd} err]} { + set failed 1 + if {$err ne {child process exited abnormally}} { + error_popup [strcat [mc "Merge tool failed."] "\n\n$err"] + } + } + + # Check the modification time of the target file + if {!$failed && [file mtime $mtool_target] eq $mtool_mtime} { + if {[ask_popup [mc "File %s unchanged, still accept as resolved?" \ + [short_path $mtool_target]]] ne {yes}} { + set failed 1 + } + } + + # Finish + if {$failed} { + file rename -force -- $backup $mtool_target + delete_temp_files $mtool_tmpfiles + ui_status [mc "Merge tool failed."] + } else { + if {[is_config_true merge.keepbackup]} { + file rename -force -- $backup "$mtool_target.orig" + } + + delete_temp_files $mtool_tmpfiles + + merge_add_resolution $mtool_target + } +} diff --git a/git-gui/lib/option.tcl b/git-gui/lib/option.tcl index ffb3f00ff0..9b865f6a75 100644 --- a/git-gui/lib/option.tcl +++ b/git-gui/lib/option.tcl @@ -119,13 +119,15 @@ proc do_options {} { {b merge.summary {mc "Summarize Merge Commits"}} {i-1..5 merge.verbosity {mc "Merge Verbosity"}} {b merge.diffstat {mc "Show Diffstat After Merge"}} + {t merge.tool {mc "Use Merge Tool"}} {b gui.trustmtime {mc "Trust File Modification Timestamps"}} {b gui.pruneduringfetch {mc "Prune Tracking Branches During Fetch"}} {b gui.matchtrackingbranch {mc "Match Tracking Branches"}} {b gui.fastcopyblame {mc "Blame Copy Only On Changed Files"}} {i-20..200 gui.copyblamethreshold {mc "Minimum Letters To Blame Copy On"}} - {i-0..99 gui.diffcontext {mc "Number of Diff Context Lines"}} + {i-0..300 gui.blamehistoryctx {mc "Blame History Context Radius (days)"}} + {i-1..99 gui.diffcontext {mc "Number of Diff Context Lines"}} {i-0..99 gui.commitmsgwidth {mc "Commit Message Text Width"}} {t gui.newbranchtemplate {mc "New Branch Name Template"}} } { diff --git a/git-gui/po/fr.po b/git-gui/po/fr.po index 89b6d51ea0..26b866f551 100644 --- a/git-gui/po/fr.po +++ b/git-gui/po/fr.po @@ -1,50 +1,51 @@ -# translation of fr.po to French +# translation of fr.po to Français # Translation of git-gui to French. # Copyright (C) 2008 Shawn Pearce, et al. # This file is distributed under the same license as the git package. # # Christian Couder <chriscool@tuxfamily.org>, 2008. +# Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>, 2008. msgid "" msgstr "" "Project-Id-Version: fr\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2008-03-14 07:18+0100\n" -"PO-Revision-Date: 2008-04-04 22:05+0200\n" -"Last-Translator: Christian Couder <chriscool@tuxfamily.org>\n" -"Language-Team: French\n" +"POT-Creation-Date: 2008-08-02 14:45-0700\n" +"PO-Revision-Date: 2008-08-11 17:12-0400\n" +"Last-Translator: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>\n" +"Language-Team: Français <fr@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: KBabel 1.11.4\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: git-gui.sh:41 git-gui.sh:634 git-gui.sh:648 git-gui.sh:661 git-gui.sh:744 -#: git-gui.sh:763 +#: git-gui.sh:41 git-gui.sh:688 git-gui.sh:702 git-gui.sh:715 git-gui.sh:798 +#: git-gui.sh:817 msgid "git-gui: fatal error" msgstr "git-gui: erreur fatale" -#: git-gui.sh:593 +#: git-gui.sh:644 #, tcl-format msgid "Invalid font specified in %s:" -msgstr "Invalide fonte spécifiée dans %s :" +msgstr "Police invalide spécifiée dans %s :" -#: git-gui.sh:620 +#: git-gui.sh:674 msgid "Main Font" -msgstr "Fonte principale" +msgstr "Police principale" -#: git-gui.sh:621 +#: git-gui.sh:675 msgid "Diff/Console Font" -msgstr "Fonte diff/console" +msgstr "Police diff/console" -#: git-gui.sh:635 +#: git-gui.sh:689 msgid "Cannot find git in PATH." msgstr "Impossible de trouver git dans PATH." -#: git-gui.sh:662 +#: git-gui.sh:716 msgid "Cannot parse Git version string:" msgstr "Impossible de parser la version de Git :" -#: git-gui.sh:680 +#: git-gui.sh:734 #, tcl-format msgid "" "Git version cannot be determined.\n" @@ -63,378 +64,381 @@ msgstr "" "\n" "Peut'on considérer que '%s' est en version 1.5.0 ?\n" -#: git-gui.sh:918 +#: git-gui.sh:972 msgid "Git directory not found:" -msgstr "Impossible de trouver le répertoire de Git :" +msgstr "Impossible de trouver le répertoire git :" -#: git-gui.sh:925 +#: git-gui.sh:979 msgid "Cannot move to top of working directory:" msgstr "Impossible d'aller à la racine du répertoire de travail :" -#: git-gui.sh:932 +#: git-gui.sh:986 msgid "Cannot use funny .git directory:" -msgstr "Impossible d'utiliser un drôle de répertoire git :" +msgstr "Impossible d'utiliser le répertoire .git:" -#: git-gui.sh:937 +#: git-gui.sh:991 msgid "No working directory" -msgstr "Pas de répertoire de travail" +msgstr "Aucun répertoire de travail" -#: git-gui.sh:1084 lib/checkout_op.tcl:283 +#: git-gui.sh:1138 lib/checkout_op.tcl:305 msgid "Refreshing file status..." msgstr "Rafraichissement du status des fichiers..." -#: git-gui.sh:1149 +#: git-gui.sh:1194 msgid "Scanning for modified files ..." msgstr "Recherche de fichiers modifiés..." -#: git-gui.sh:1324 lib/browser.tcl:246 +#: git-gui.sh:1369 lib/browser.tcl:246 msgid "Ready." msgstr "Prêt." -#: git-gui.sh:1590 +#: git-gui.sh:1635 msgid "Unmodified" msgstr "Non modifié" -#: git-gui.sh:1592 +#: git-gui.sh:1637 msgid "Modified, not staged" -msgstr "Modifié, non pré-commité" +msgstr "Modifié, pas indexé" -#: git-gui.sh:1593 git-gui.sh:1598 +#: git-gui.sh:1638 git-gui.sh:1643 msgid "Staged for commit" -msgstr "Pré-commité" +msgstr "Indexé" -#: git-gui.sh:1594 git-gui.sh:1599 +#: git-gui.sh:1639 git-gui.sh:1644 msgid "Portions staged for commit" -msgstr "En partie pré-commité" +msgstr "Portions indexées" -#: git-gui.sh:1595 git-gui.sh:1600 +#: git-gui.sh:1640 git-gui.sh:1645 msgid "Staged for commit, missing" -msgstr "Pré-commité, manquant" +msgstr "Indexés, manquant" -#: git-gui.sh:1597 +#: git-gui.sh:1642 msgid "Untracked, not staged" -msgstr "Non suivi, non pré-commité" +msgstr "Non versionné, non indexé" -#: git-gui.sh:1602 +#: git-gui.sh:1647 msgid "Missing" msgstr "Manquant" -#: git-gui.sh:1603 +#: git-gui.sh:1648 msgid "Staged for removal" -msgstr "Pré-commité pour suppression" +msgstr "Indexé pour suppression" -#: git-gui.sh:1604 +#: git-gui.sh:1649 msgid "Staged for removal, still present" -msgstr "Pré-commité pour suppression, toujours présent" +msgstr "Indexé pour suppression, toujours présent" -#: git-gui.sh:1606 git-gui.sh:1607 git-gui.sh:1608 git-gui.sh:1609 +#: git-gui.sh:1651 git-gui.sh:1652 git-gui.sh:1653 git-gui.sh:1654 msgid "Requires merge resolution" msgstr "Nécessite la résolution d'une fusion" -#: git-gui.sh:1644 +#: git-gui.sh:1689 msgid "Starting gitk... please wait..." -msgstr "Lancement de gitk... merci de patienter..." +msgstr "Lancement de gitk... un instant..." -#: git-gui.sh:1653 -#, tcl-format -msgid "" -"Unable to start gitk:\n" -"\n" -"%s does not exist" -msgstr "" -"Impossible de lancer gitk :\n" -"\n" -"%s inexistant" +#: git-gui.sh:1698 +msgid "Couldn't find gitk in PATH" +msgstr "Impossible de trouver gitk dans PATH." -#: git-gui.sh:1860 lib/choose_repository.tcl:36 +#: git-gui.sh:1948 lib/choose_repository.tcl:36 msgid "Repository" -msgstr "Référentiel" +msgstr "Dépôt" -#: git-gui.sh:1861 +#: git-gui.sh:1949 msgid "Edit" -msgstr "Editer" +msgstr "Edition" -#: git-gui.sh:1863 lib/choose_rev.tcl:561 +#: git-gui.sh:1951 lib/choose_rev.tcl:561 msgid "Branch" msgstr "Branche" -#: git-gui.sh:1866 lib/choose_rev.tcl:548 +#: git-gui.sh:1954 lib/choose_rev.tcl:548 msgid "Commit@@noun" msgstr "Commit" -#: git-gui.sh:1869 lib/merge.tcl:120 lib/merge.tcl:149 lib/merge.tcl:167 +#: git-gui.sh:1957 lib/merge.tcl:120 lib/merge.tcl:149 lib/merge.tcl:167 msgid "Merge" msgstr "Fusionner" -#: git-gui.sh:1870 lib/choose_rev.tcl:557 +#: git-gui.sh:1958 lib/choose_rev.tcl:557 msgid "Remote" -msgstr "Référentiel distant" +msgstr "Dépôt distant" -#: git-gui.sh:1879 +#: git-gui.sh:1967 msgid "Browse Current Branch's Files" -msgstr "Visionner fichiers dans branche courante" +msgstr "Naviguer dans la branche courante" -#: git-gui.sh:1883 +#: git-gui.sh:1971 msgid "Browse Branch Files..." -msgstr "Visionner fichiers de branche" +msgstr "Naviguer dans la branche..." -#: git-gui.sh:1888 +#: git-gui.sh:1976 msgid "Visualize Current Branch's History" msgstr "Visualiser historique branche courante" -#: git-gui.sh:1892 +#: git-gui.sh:1980 msgid "Visualize All Branch History" -msgstr "Visualiser historique toutes branches" +msgstr "Voir l'historique de toutes les branches" -#: git-gui.sh:1899 +#: git-gui.sh:1987 #, tcl-format msgid "Browse %s's Files" -msgstr "Visionner fichiers de %s" +msgstr "Naviguer l'arborescence de %s" -#: git-gui.sh:1901 +#: git-gui.sh:1989 #, tcl-format msgid "Visualize %s's History" -msgstr "Visualiser historique de %s" +msgstr "Voir l'historique de la branche: %s" -#: git-gui.sh:1906 lib/database.tcl:27 lib/database.tcl:67 +#: git-gui.sh:1994 lib/database.tcl:27 lib/database.tcl:67 msgid "Database Statistics" -msgstr "Statistiques base de donnée" +msgstr "Statistiques du dépôt" -#: git-gui.sh:1909 lib/database.tcl:34 +#: git-gui.sh:1997 lib/database.tcl:34 msgid "Compress Database" -msgstr "Comprimer base de donnée" +msgstr "Comprimer le dépôt" -#: git-gui.sh:1912 +#: git-gui.sh:2000 msgid "Verify Database" -msgstr "Vérifier base de donnée" +msgstr "Vérifier le dépôt" -#: git-gui.sh:1919 git-gui.sh:1923 git-gui.sh:1927 lib/shortcut.tcl:7 +#: git-gui.sh:2007 git-gui.sh:2011 git-gui.sh:2015 lib/shortcut.tcl:7 #: lib/shortcut.tcl:39 lib/shortcut.tcl:71 msgid "Create Desktop Icon" msgstr "Créer icône sur bureau" -#: git-gui.sh:1932 lib/choose_repository.tcl:177 lib/choose_repository.tcl:185 +#: git-gui.sh:2023 lib/choose_repository.tcl:177 lib/choose_repository.tcl:185 msgid "Quit" msgstr "Quitter" -#: git-gui.sh:1939 +#: git-gui.sh:2031 msgid "Undo" msgstr "Défaire" -#: git-gui.sh:1942 +#: git-gui.sh:2034 msgid "Redo" msgstr "Refaire" -#: git-gui.sh:1946 git-gui.sh:2443 +#: git-gui.sh:2038 git-gui.sh:2545 msgid "Cut" msgstr "Couper" -#: git-gui.sh:1949 git-gui.sh:2446 git-gui.sh:2520 git-gui.sh:2614 +#: git-gui.sh:2041 git-gui.sh:2548 git-gui.sh:2622 git-gui.sh:2715 #: lib/console.tcl:69 msgid "Copy" msgstr "Copier" -#: git-gui.sh:1952 git-gui.sh:2449 +#: git-gui.sh:2044 git-gui.sh:2551 msgid "Paste" msgstr "Coller" -#: git-gui.sh:1955 git-gui.sh:2452 lib/branch_delete.tcl:26 +#: git-gui.sh:2047 git-gui.sh:2554 lib/branch_delete.tcl:26 #: lib/remote_branch_delete.tcl:38 msgid "Delete" msgstr "Supprimer" -#: git-gui.sh:1959 git-gui.sh:2456 git-gui.sh:2618 lib/console.tcl:71 +#: git-gui.sh:2051 git-gui.sh:2558 git-gui.sh:2719 lib/console.tcl:71 msgid "Select All" msgstr "Tout sélectionner" -#: git-gui.sh:1968 +#: git-gui.sh:2060 msgid "Create..." msgstr "Créer..." -#: git-gui.sh:1974 +#: git-gui.sh:2066 msgid "Checkout..." -msgstr "Emprunter... " +msgstr "Charger (checkout)..." -#: git-gui.sh:1980 +#: git-gui.sh:2072 msgid "Rename..." msgstr "Renommer..." -#: git-gui.sh:1985 git-gui.sh:2085 +#: git-gui.sh:2077 git-gui.sh:2187 msgid "Delete..." msgstr "Supprimer..." -#: git-gui.sh:1990 +#: git-gui.sh:2082 msgid "Reset..." msgstr "Réinitialiser..." -#: git-gui.sh:2002 git-gui.sh:2389 +#: git-gui.sh:2094 git-gui.sh:2491 msgid "New Commit" msgstr "Nouveau commit" -#: git-gui.sh:2010 git-gui.sh:2396 +#: git-gui.sh:2102 git-gui.sh:2498 msgid "Amend Last Commit" msgstr "Corriger dernier commit" -#: git-gui.sh:2019 git-gui.sh:2356 lib/remote_branch_delete.tcl:99 +#: git-gui.sh:2111 git-gui.sh:2458 lib/remote_branch_delete.tcl:99 msgid "Rescan" -msgstr "Resynchroniser" +msgstr "Recharger modifs." -#: git-gui.sh:2025 +#: git-gui.sh:2117 msgid "Stage To Commit" -msgstr "Commiter un pré-commit" +msgstr "Indexer" -#: git-gui.sh:2031 +#: git-gui.sh:2123 msgid "Stage Changed Files To Commit" -msgstr "Commiter fichiers modifiés dans pré-commit" +msgstr "Indexer toutes modifications" -#: git-gui.sh:2037 +#: git-gui.sh:2129 msgid "Unstage From Commit" -msgstr "Commit vers pré-commit" +msgstr "Désindexer" -#: git-gui.sh:2042 lib/index.tcl:395 +#: git-gui.sh:2134 lib/index.tcl:395 msgid "Revert Changes" -msgstr "Inverser modification" +msgstr "Annuler les modifications (revert)" -#: git-gui.sh:2049 git-gui.sh:2368 git-gui.sh:2467 +#: git-gui.sh:2141 git-gui.sh:2702 +msgid "Show Less Context" +msgstr "Montrer moins de contexte" + +#: git-gui.sh:2145 git-gui.sh:2706 +msgid "Show More Context" +msgstr "Montrer plus de contexte" + +#: git-gui.sh:2151 git-gui.sh:2470 git-gui.sh:2569 msgid "Sign Off" -msgstr "Se désinscrire" +msgstr "Signer" -#: git-gui.sh:2053 git-gui.sh:2372 +#: git-gui.sh:2155 git-gui.sh:2474 msgid "Commit@@verb" msgstr "Commiter" -#: git-gui.sh:2064 +#: git-gui.sh:2166 msgid "Local Merge..." msgstr "Fusion locale..." -#: git-gui.sh:2069 +#: git-gui.sh:2171 msgid "Abort Merge..." msgstr "Abandonner fusion..." -#: git-gui.sh:2081 +#: git-gui.sh:2183 msgid "Push..." msgstr "Pousser..." -#: git-gui.sh:2092 lib/choose_repository.tcl:41 -msgid "Apple" -msgstr "Pomme" - -#: git-gui.sh:2095 git-gui.sh:2117 lib/about.tcl:14 +#: git-gui.sh:2197 git-gui.sh:2219 lib/about.tcl:14 #: lib/choose_repository.tcl:44 lib/choose_repository.tcl:50 #, tcl-format msgid "About %s" -msgstr "A propos de %s" +msgstr "À propos de %s" -#: git-gui.sh:2099 +#: git-gui.sh:2201 msgid "Preferences..." msgstr "Préférences..." -#: git-gui.sh:2107 git-gui.sh:2639 +#: git-gui.sh:2209 git-gui.sh:2740 msgid "Options..." msgstr "Options..." -#: git-gui.sh:2113 lib/choose_repository.tcl:47 +#: git-gui.sh:2215 lib/choose_repository.tcl:47 msgid "Help" msgstr "Aide" -#: git-gui.sh:2154 +#: git-gui.sh:2256 msgid "Online Documentation" msgstr "Documentation en ligne" -#: git-gui.sh:2238 +#: git-gui.sh:2340 #, tcl-format msgid "fatal: cannot stat path %s: No such file or directory" -msgstr "erreur fatale : pas d'infos sur le chemin %s : Fichier ou répertoire inexistant" +msgstr "" +"erreur fatale : pas d'infos sur le chemin %s : Fichier ou répertoire " +"inexistant" -#: git-gui.sh:2271 +#: git-gui.sh:2373 msgid "Current Branch:" msgstr "Branche courante :" -#: git-gui.sh:2292 +#: git-gui.sh:2394 msgid "Staged Changes (Will Commit)" -msgstr "Modifications pré-commitées" +msgstr "Modifs. indexées (pour commit)" -#: git-gui.sh:2312 +#: git-gui.sh:2414 msgid "Unstaged Changes" -msgstr "Modifications non pré-commitées" +msgstr "Modifs. non indexées" -#: git-gui.sh:2362 +#: git-gui.sh:2464 msgid "Stage Changed" -msgstr "Pré-commit modifié" +msgstr "Indexer modifs." -#: git-gui.sh:2378 lib/transport.tcl:93 lib/transport.tcl:182 +#: git-gui.sh:2480 lib/transport.tcl:93 lib/transport.tcl:182 msgid "Push" msgstr "Pousser" -#: git-gui.sh:2408 +#: git-gui.sh:2510 msgid "Initial Commit Message:" msgstr "Message de commit initial :" -#: git-gui.sh:2409 +#: git-gui.sh:2511 msgid "Amended Commit Message:" msgstr "Message de commit corrigé :" -#: git-gui.sh:2410 +#: git-gui.sh:2512 msgid "Amended Initial Commit Message:" msgstr "Message de commit initial corrigé :" -#: git-gui.sh:2411 +#: git-gui.sh:2513 msgid "Amended Merge Commit Message:" msgstr "Message de commit de fusion corrigé :" -#: git-gui.sh:2412 +#: git-gui.sh:2514 msgid "Merge Commit Message:" msgstr "Message de commit de fusion :" -#: git-gui.sh:2413 +#: git-gui.sh:2515 msgid "Commit Message:" msgstr "Message de commit :" -#: git-gui.sh:2459 git-gui.sh:2622 lib/console.tcl:73 +#: git-gui.sh:2561 git-gui.sh:2723 lib/console.tcl:73 msgid "Copy All" msgstr "Copier tout" -#: git-gui.sh:2483 lib/blame.tcl:107 +#: git-gui.sh:2585 lib/blame.tcl:100 msgid "File:" msgstr "Fichier :" -#: git-gui.sh:2589 +#: git-gui.sh:2691 msgid "Apply/Reverse Hunk" msgstr "Appliquer/Inverser section" -#: git-gui.sh:2595 -msgid "Show Less Context" -msgstr "Montrer moins de contexte" - -#: git-gui.sh:2602 -msgid "Show More Context" -msgstr "Montrer plus de contexte" +#: git-gui.sh:2696 +msgid "Apply/Reverse Line" +msgstr "Appliquer/Inverser la ligne" -#: git-gui.sh:2610 +#: git-gui.sh:2711 msgid "Refresh" msgstr "Rafraichir" -#: git-gui.sh:2631 +#: git-gui.sh:2732 msgid "Decrease Font Size" -msgstr "Réduire fonte" +msgstr "Diminuer la police" -#: git-gui.sh:2635 +#: git-gui.sh:2736 msgid "Increase Font Size" -msgstr "Agrandir fonte" +msgstr "Agrandir la police" -#: git-gui.sh:2646 +#: git-gui.sh:2747 msgid "Unstage Hunk From Commit" -msgstr "Enlever section pré-commitée" +msgstr "Désindexer la section" + +#: git-gui.sh:2748 +msgid "Unstage Line From Commit" +msgstr "Désindexer la ligne" -#: git-gui.sh:2648 +#: git-gui.sh:2750 msgid "Stage Hunk For Commit" -msgstr "Pré-commiter section" +msgstr "Indexer la section" -#: git-gui.sh:2667 +#: git-gui.sh:2751 +msgid "Stage Line For Commit" +msgstr "Indexer la ligne" + +#: git-gui.sh:2771 msgid "Initializing..." msgstr "Initialisation..." -#: git-gui.sh:2762 +#: git-gui.sh:2876 #, tcl-format msgid "" "Possible environment issues exist.\n" @@ -451,7 +455,7 @@ msgstr "" "sous-processus de Git lancés par %s\n" "\n" -#: git-gui.sh:2792 +#: git-gui.sh:2906 msgid "" "\n" "This is due to a known issue with the\n" @@ -461,7 +465,7 @@ msgstr "" "Ceci est du à un problème connu avec\n" "le binaire Tcl distribué par Cygwin." -#: git-gui.sh:2797 +#: git-gui.sh:2911 #, tcl-format msgid "" "\n" @@ -482,78 +486,94 @@ msgstr "" msgid "git-gui - a graphical user interface for Git." msgstr "git-gui - une interface graphique utilisateur pour Git" -#: lib/blame.tcl:77 +#: lib/blame.tcl:70 msgid "File Viewer" msgstr "Visionneur de fichier" -#: lib/blame.tcl:81 +#: lib/blame.tcl:74 msgid "Commit:" msgstr "Commit :" -#: lib/blame.tcl:264 +#: lib/blame.tcl:257 msgid "Copy Commit" msgstr "Copier commit" -#: lib/blame.tcl:384 +#: lib/blame.tcl:260 +msgid "Do Full Copy Detection" +msgstr "Lancer la détection approfondie des copies" + +#: lib/blame.tcl:388 #, tcl-format msgid "Reading %s..." msgstr "Lecture de %s..." -#: lib/blame.tcl:488 +#: lib/blame.tcl:492 msgid "Loading copy/move tracking annotations..." msgstr "Chargement des annotations de suivi des copies/déplacements..." -#: lib/blame.tcl:508 +#: lib/blame.tcl:512 msgid "lines annotated" msgstr "lignes annotées" -#: lib/blame.tcl:689 +#: lib/blame.tcl:704 msgid "Loading original location annotations..." msgstr "Chargement des annotations d'emplacement original" -#: lib/blame.tcl:692 +#: lib/blame.tcl:707 msgid "Annotation complete." msgstr "Annotation terminée." -#: lib/blame.tcl:746 +#: lib/blame.tcl:737 +msgid "Busy" +msgstr "Occupé" + +#: lib/blame.tcl:738 +msgid "Annotation process is already running." +msgstr "Annotation en cours d'exécution." + +#: lib/blame.tcl:777 +msgid "Running thorough copy detection..." +msgstr "Recherche de copie approfondie en cours..." + +#: lib/blame.tcl:827 msgid "Loading annotation..." msgstr "Chargement des annotations..." -#: lib/blame.tcl:802 +#: lib/blame.tcl:883 msgid "Author:" msgstr "Auteur :" -#: lib/blame.tcl:806 +#: lib/blame.tcl:887 msgid "Committer:" msgstr "Commiteur :" -#: lib/blame.tcl:811 +#: lib/blame.tcl:892 msgid "Original File:" msgstr "Fichier original :" -#: lib/blame.tcl:925 +#: lib/blame.tcl:1006 msgid "Originally By:" msgstr "A l'origine par :" -#: lib/blame.tcl:931 +#: lib/blame.tcl:1012 msgid "In File:" msgstr "Dans le fichier :" -#: lib/blame.tcl:936 +#: lib/blame.tcl:1017 msgid "Copied Or Moved Here By:" msgstr "Copié ou déplacé ici par :" #: lib/branch_checkout.tcl:14 lib/branch_checkout.tcl:19 msgid "Checkout Branch" -msgstr "Emprunter branche" +msgstr "Charger la branche (checkout)" #: lib/branch_checkout.tcl:23 msgid "Checkout" -msgstr "Emprunter" +msgstr "Charger (checkout)" #: lib/branch_checkout.tcl:27 lib/branch_create.tcl:35 #: lib/branch_delete.tcl:32 lib/branch_rename.tcl:30 lib/browser.tcl:282 -#: lib/checkout_op.tcl:522 lib/choose_font.tcl:43 lib/merge.tcl:171 +#: lib/checkout_op.tcl:544 lib/choose_font.tcl:43 lib/merge.tcl:171 #: lib/option.tcl:103 lib/remote_branch_delete.tcl:42 lib/transport.tcl:97 msgid "Cancel" msgstr "Annuler" @@ -562,17 +582,17 @@ msgstr "Annuler" msgid "Revision" msgstr "Révision" -#: lib/branch_checkout.tcl:36 lib/branch_create.tcl:69 lib/option.tcl:242 +#: lib/branch_checkout.tcl:36 lib/branch_create.tcl:69 lib/option.tcl:244 msgid "Options" msgstr "Options" #: lib/branch_checkout.tcl:39 lib/branch_create.tcl:92 msgid "Fetch Tracking Branch" -msgstr "Branche suivant récupération" +msgstr "Récupérer la branche de suivi" #: lib/branch_checkout.tcl:44 msgid "Detach From Local Branch" -msgstr "Détacher de branche locale" +msgstr "Détacher de la branche locale" #: lib/branch_create.tcl:22 msgid "Create Branch" @@ -600,7 +620,7 @@ msgstr "Trouver nom de branche de suivi" #: lib/branch_create.tcl:66 msgid "Starting Revision" -msgstr "Début de révision" +msgstr "Révision initiale" #: lib/branch_create.tcl:72 msgid "Update Existing Branch:" @@ -612,28 +632,28 @@ msgstr "Non" #: lib/branch_create.tcl:80 msgid "Fast Forward Only" -msgstr "Avance rapide seulement" +msgstr "Mise-à-jour rectiligne seulement (fast-forward)" -#: lib/branch_create.tcl:85 lib/checkout_op.tcl:514 +#: lib/branch_create.tcl:85 lib/checkout_op.tcl:536 msgid "Reset" msgstr "Réinitialiser" #: lib/branch_create.tcl:97 msgid "Checkout After Creation" -msgstr "Emprunt après création" +msgstr "Charger (checkout) après création" #: lib/branch_create.tcl:131 msgid "Please select a tracking branch." -msgstr "Merci de choisir une branche de suivi" +msgstr "Choisissez une branche de suivi" #: lib/branch_create.tcl:140 #, tcl-format msgid "Tracking branch %s is not a branch in the remote repository." -msgstr "La branche de suivi %s n'est pas une branche dans le référentiel distant." +msgstr "La branche de suivi %s n'est pas une branche dans le dépôt distant." #: lib/branch_create.tcl:153 lib/branch_rename.tcl:86 msgid "Please supply a branch name." -msgstr "Merci de fournir un nom de branche." +msgstr "Fournissez un nom de branche." #: lib/branch_create.tcl:164 lib/branch_rename.tcl:106 #, tcl-format @@ -654,7 +674,7 @@ msgstr "Branches locales" #: lib/branch_delete.tcl:52 msgid "Delete Only If Merged Into" -msgstr "Supprimer ssi fusion dedans" +msgstr "Supprimer seulement si fusionnée dans:" #: lib/branch_delete.tcl:54 msgid "Always (Do not perform merge test.)" @@ -704,7 +724,7 @@ msgstr "Nouveau nom :" msgid "Please select a branch to rename." msgstr "Merci de sélectionner une branche à renommer." -#: lib/branch_rename.tcl:96 lib/checkout_op.tcl:179 +#: lib/branch_rename.tcl:96 lib/checkout_op.tcl:201 #, tcl-format msgid "Branch '%s' already exists." msgstr "La branche '%s' existe déjà." @@ -712,7 +732,7 @@ msgstr "La branche '%s' existe déjà." #: lib/branch_rename.tcl:117 #, tcl-format msgid "Failed to rename '%s'." -msgstr "Le renommage de '%s' a échoué." +msgstr "Échec pour renommer '%s'." #: lib/browser.tcl:17 msgid "Starting..." @@ -733,34 +753,39 @@ msgstr "[Jusqu'au parent]" #: lib/browser.tcl:267 lib/browser.tcl:273 msgid "Browse Branch Files" -msgstr "Visionner fichiers de branches" +msgstr "Naviguer dans les fichiers de le branche" #: lib/browser.tcl:278 lib/choose_repository.tcl:387 -#: lib/choose_repository.tcl:474 lib/choose_repository.tcl:484 -#: lib/choose_repository.tcl:987 +#: lib/choose_repository.tcl:472 lib/choose_repository.tcl:482 +#: lib/choose_repository.tcl:985 msgid "Browse" -msgstr "Visionner" +msgstr "Naviguer" -#: lib/checkout_op.tcl:79 +#: lib/checkout_op.tcl:84 #, tcl-format msgid "Fetching %s from %s" msgstr "Récupération de %s à partir de %s" -#: lib/checkout_op.tcl:127 +#: lib/checkout_op.tcl:132 #, tcl-format msgid "fatal: Cannot resolve %s" msgstr "erreur fatale : Impossible de résoudre %s" -#: lib/checkout_op.tcl:140 lib/console.tcl:81 lib/database.tcl:31 +#: lib/checkout_op.tcl:145 lib/console.tcl:81 lib/database.tcl:31 msgid "Close" msgstr "Fermer" -#: lib/checkout_op.tcl:169 +#: lib/checkout_op.tcl:174 #, tcl-format msgid "Branch '%s' does not exist." msgstr "La branche '%s' n'existe pas." -#: lib/checkout_op.tcl:206 +#: lib/checkout_op.tcl:193 +#, tcl-format +msgid "Failed to configure simplified git-pull for '%s'." +msgstr "Échec de la configuration simplifiée de git-pull pour '%s'." + +#: lib/checkout_op.tcl:228 #, tcl-format msgid "" "Branch '%s' already exists.\n" @@ -770,24 +795,24 @@ msgid "" msgstr "" "La branche '%s' existe déjà.\n" "\n" -"Impossible d'avancer rapidement à %s.\n" +"Impossible de faire une avance rapide (fast forward) vers %s.\n" "Une fusion est nécessaire." -#: lib/checkout_op.tcl:220 +#: lib/checkout_op.tcl:242 #, tcl-format msgid "Merge strategy '%s' not supported." msgstr "La stratégie de fusion '%s' n'est pas supportée." -#: lib/checkout_op.tcl:239 +#: lib/checkout_op.tcl:261 #, tcl-format msgid "Failed to update '%s'." msgstr "La mise à jour de '%s' a échouée." -#: lib/checkout_op.tcl:251 +#: lib/checkout_op.tcl:273 msgid "Staging area (index) is already locked." -msgstr "L'espace de pré-commit ('index' ou 'staging') est déjà vérouillé." +msgstr "L'index (staging area) est déjà vérouillé" -#: lib/checkout_op.tcl:266 +#: lib/checkout_op.tcl:288 msgid "" "Last scanned state does not match repository state.\n" "\n" @@ -796,36 +821,39 @@ msgid "" "\n" "The rescan will be automatically started now.\n" msgstr "" -"L'état lors de la dernière synchronisation ne correspond plus à l'état du référentiel.\n" +"L'état lors de la dernière synchronisation ne correspond plus à l'état du " +"dépôt\n" "\n" -"Un autre programme Git a modifié ce référentiel depuis la dernière synchronisation. Une resynchronisation doit être effectuée avant de pouvoir modifier la branche courante.\n" +"Un autre programme Git a modifié ce dépôt depuis la dernière " +"synchronisation. Une resynchronisation doit être effectuée avant de pouvoir " +"modifier la branche courante.\n" "\n" "Cela va être fait tout de suite automatiquement.\n" -#: lib/checkout_op.tcl:322 +#: lib/checkout_op.tcl:344 #, tcl-format msgid "Updating working directory to '%s'..." msgstr "Mise à jour du répertoire courant avec '%s'..." -#: lib/checkout_op.tcl:323 +#: lib/checkout_op.tcl:345 msgid "files checked out" -msgstr "fichiers empruntés" +msgstr "fichiers chargés" -#: lib/checkout_op.tcl:353 +#: lib/checkout_op.tcl:375 #, tcl-format msgid "Aborted checkout of '%s' (file level merging is required)." -msgstr "Emprunt de '%s' abandonné. (Il est nécessaire de fusionner des fichiers.)" +msgstr "Chargement de '%s' abandonné (il est nécessaire de fusionner des fichiers)." -#: lib/checkout_op.tcl:354 +#: lib/checkout_op.tcl:376 msgid "File level merge required." msgstr "Il est nécessaire de fusionner des fichiers." -#: lib/checkout_op.tcl:358 +#: lib/checkout_op.tcl:380 #, tcl-format msgid "Staying on branch '%s'." msgstr "Le répertoire de travail reste sur la branche '%s'." -#: lib/checkout_op.tcl:429 +#: lib/checkout_op.tcl:451 msgid "" "You are no longer on a local branch.\n" "\n" @@ -837,30 +865,30 @@ msgstr "" "Si vous vouliez être sur une branche, créez en une maintenant en partant de " "'Cet emprunt détaché'." -#: lib/checkout_op.tcl:446 lib/checkout_op.tcl:450 +#: lib/checkout_op.tcl:468 lib/checkout_op.tcl:472 #, tcl-format msgid "Checked out '%s'." -msgstr "'%s' emprunté." +msgstr "'%s' chargé." -#: lib/checkout_op.tcl:478 +#: lib/checkout_op.tcl:500 #, tcl-format msgid "Resetting '%s' to '%s' will lose the following commits:" msgstr "Réinitialiser '%s' à '%s' va faire perdre les commits suivants :" -#: lib/checkout_op.tcl:500 +#: lib/checkout_op.tcl:522 msgid "Recovering lost commits may not be easy." msgstr "Récupérer les commits perdus ne sera peut être pas facile." -#: lib/checkout_op.tcl:505 +#: lib/checkout_op.tcl:527 #, tcl-format msgid "Reset '%s'?" msgstr "Réinitialiser '%s' ?" -#: lib/checkout_op.tcl:510 lib/merge.tcl:163 +#: lib/checkout_op.tcl:532 lib/merge.tcl:163 msgid "Visualize" msgstr "Visualiser" -#: lib/checkout_op.tcl:578 +#: lib/checkout_op.tcl:600 #, tcl-format msgid "" "Failed to set current branch.\n" @@ -884,15 +912,15 @@ msgstr "Sélectionner" #: lib/choose_font.tcl:53 msgid "Font Family" -msgstr "Famille de fonte" +msgstr "Familles de polices" #: lib/choose_font.tcl:74 msgid "Font Size" -msgstr "Taille de fonte" +msgstr "Taille de police" #: lib/choose_font.tcl:91 msgid "Font Example" -msgstr "Exemple de fonte" +msgstr "Exemple de police" #: lib/choose_font.tcl:103 msgid "" @@ -900,7 +928,7 @@ msgid "" "If you like this text, it can be your font." msgstr "" "C'est un texte d'exemple.\n" -"Si vous aimez ce texte, vous pouvez choisir cette fonte." +"Si vous aimez ce texte, vous pouvez choisir cette police" #: lib/choose_repository.tcl:28 msgid "Git Gui" @@ -908,23 +936,23 @@ msgstr "Git Gui" #: lib/choose_repository.tcl:81 lib/choose_repository.tcl:376 msgid "Create New Repository" -msgstr "Créer nouveau référentiel" +msgstr "Créer nouveau dépôt" #: lib/choose_repository.tcl:87 msgid "New..." msgstr "Nouveau..." -#: lib/choose_repository.tcl:94 lib/choose_repository.tcl:460 +#: lib/choose_repository.tcl:94 lib/choose_repository.tcl:458 msgid "Clone Existing Repository" -msgstr "Cloner référentiel existant" +msgstr "Cloner dépôt existant" #: lib/choose_repository.tcl:100 msgid "Clone..." msgstr "Cloner..." -#: lib/choose_repository.tcl:107 lib/choose_repository.tcl:976 +#: lib/choose_repository.tcl:107 lib/choose_repository.tcl:974 msgid "Open Existing Repository" -msgstr "Ouvrir référentiel existant" +msgstr "Ouvrir dépôt existant" #: lib/choose_repository.tcl:113 msgid "Open..." @@ -932,202 +960,202 @@ msgstr "Ouvrir..." #: lib/choose_repository.tcl:126 msgid "Recent Repositories" -msgstr "Référentiels récents" +msgstr "Dépôt récemment utilisés" #: lib/choose_repository.tcl:132 msgid "Open Recent Repository:" -msgstr "Ouvrir référentiel récent :" +msgstr "Ouvrir dépôt récent :" #: lib/choose_repository.tcl:296 lib/choose_repository.tcl:303 #: lib/choose_repository.tcl:310 #, tcl-format msgid "Failed to create repository %s:" -msgstr "La création du référentiel %s a échouée :" +msgstr "La création du dépôt %s a échouée :" -#: lib/choose_repository.tcl:381 lib/choose_repository.tcl:478 +#: lib/choose_repository.tcl:381 lib/choose_repository.tcl:476 msgid "Directory:" msgstr "Répertoire :" -#: lib/choose_repository.tcl:412 lib/choose_repository.tcl:537 -#: lib/choose_repository.tcl:1011 +#: lib/choose_repository.tcl:410 lib/choose_repository.tcl:535 +#: lib/choose_repository.tcl:1007 msgid "Git Repository" -msgstr "Référentiel Git" +msgstr "Dépôt Git" -#: lib/choose_repository.tcl:437 +#: lib/choose_repository.tcl:435 #, tcl-format msgid "Directory %s already exists." msgstr "Le répertoire %s existe déjà." -#: lib/choose_repository.tcl:441 +#: lib/choose_repository.tcl:439 #, tcl-format msgid "File %s already exists." msgstr "Le fichier %s existe déjà." -#: lib/choose_repository.tcl:455 +#: lib/choose_repository.tcl:453 msgid "Clone" msgstr "Cloner" -#: lib/choose_repository.tcl:468 +#: lib/choose_repository.tcl:466 msgid "URL:" msgstr "URL :" -#: lib/choose_repository.tcl:489 +#: lib/choose_repository.tcl:487 msgid "Clone Type:" msgstr "Type de clonage :" -#: lib/choose_repository.tcl:495 +#: lib/choose_repository.tcl:493 msgid "Standard (Fast, Semi-Redundant, Hardlinks)" msgstr "Standard (rapide, semi-redondant, liens durs)" -#: lib/choose_repository.tcl:501 +#: lib/choose_repository.tcl:499 msgid "Full Copy (Slower, Redundant Backup)" msgstr "Copy complète (plus lent, sauvegarde redondante)" -#: lib/choose_repository.tcl:507 +#: lib/choose_repository.tcl:505 msgid "Shared (Fastest, Not Recommended, No Backup)" msgstr "Partagé (le plus rapide, non recommandé, pas de sauvegarde)" -#: lib/choose_repository.tcl:543 lib/choose_repository.tcl:590 -#: lib/choose_repository.tcl:736 lib/choose_repository.tcl:806 -#: lib/choose_repository.tcl:1017 lib/choose_repository.tcl:1025 +#: lib/choose_repository.tcl:541 lib/choose_repository.tcl:588 +#: lib/choose_repository.tcl:734 lib/choose_repository.tcl:804 +#: lib/choose_repository.tcl:1013 lib/choose_repository.tcl:1021 #, tcl-format msgid "Not a Git repository: %s" -msgstr "'%s' n'est pas un référentiel Git." +msgstr "'%s' n'est pas un dépôt Git." -#: lib/choose_repository.tcl:579 +#: lib/choose_repository.tcl:577 msgid "Standard only available for local repository." -msgstr "Standard n'est disponible que pour un référentiel local." +msgstr "Standard n'est disponible que pour un dépôt local." -#: lib/choose_repository.tcl:583 +#: lib/choose_repository.tcl:581 msgid "Shared only available for local repository." -msgstr "Partagé n'est disponible que pour un référentiel local." +msgstr "Partagé n'est disponible que pour un dépôt local." -#: lib/choose_repository.tcl:604 +#: lib/choose_repository.tcl:602 #, tcl-format msgid "Location %s already exists." msgstr "L'emplacement %s existe déjà." -#: lib/choose_repository.tcl:615 +#: lib/choose_repository.tcl:613 msgid "Failed to configure origin" msgstr "La configuration de l'origine a échouée." -#: lib/choose_repository.tcl:627 +#: lib/choose_repository.tcl:625 msgid "Counting objects" -msgstr "Comptage des objets" +msgstr "Décompte des objets" -#: lib/choose_repository.tcl:628 +#: lib/choose_repository.tcl:626 msgid "buckets" msgstr "paniers" -#: lib/choose_repository.tcl:652 +#: lib/choose_repository.tcl:650 #, tcl-format msgid "Unable to copy objects/info/alternates: %s" msgstr "Impossible de copier 'objects/info/alternates' : %s" -#: lib/choose_repository.tcl:688 +#: lib/choose_repository.tcl:686 #, tcl-format msgid "Nothing to clone from %s." msgstr "Il n'y a rien à cloner depuis %s." -#: lib/choose_repository.tcl:690 lib/choose_repository.tcl:904 -#: lib/choose_repository.tcl:916 +#: lib/choose_repository.tcl:688 lib/choose_repository.tcl:902 +#: lib/choose_repository.tcl:914 msgid "The 'master' branch has not been initialized." -msgstr "Cette branche 'master' n'a pas été initialisée." +msgstr "La branche 'master' n'a pas été initialisée." -#: lib/choose_repository.tcl:703 +#: lib/choose_repository.tcl:701 msgid "Hardlinks are unavailable. Falling back to copying." -msgstr "Les liens durs ne sont pas disponibles. On se résoud à copier." +msgstr "Les liens durs ne sont pas supportés. Une copie sera effectuée à la place." -#: lib/choose_repository.tcl:715 +#: lib/choose_repository.tcl:713 #, tcl-format msgid "Cloning from %s" msgstr "Clonage depuis %s" -#: lib/choose_repository.tcl:746 +#: lib/choose_repository.tcl:744 msgid "Copying objects" msgstr "Copie des objets" -#: lib/choose_repository.tcl:747 +#: lib/choose_repository.tcl:745 msgid "KiB" msgstr "KiB" -#: lib/choose_repository.tcl:771 +#: lib/choose_repository.tcl:769 #, tcl-format msgid "Unable to copy object: %s" msgstr "Impossible de copier l'objet : %s" -#: lib/choose_repository.tcl:781 +#: lib/choose_repository.tcl:779 msgid "Linking objects" msgstr "Liaison des objets" -#: lib/choose_repository.tcl:782 +#: lib/choose_repository.tcl:780 msgid "objects" msgstr "objets" -#: lib/choose_repository.tcl:790 +#: lib/choose_repository.tcl:788 #, tcl-format msgid "Unable to hardlink object: %s" msgstr "Impossible créer un lien dur pour l'objet : %s" -#: lib/choose_repository.tcl:845 +#: lib/choose_repository.tcl:843 msgid "Cannot fetch branches and objects. See console output for details." msgstr "" "Impossible de récupérer les branches et objets. Voir la sortie console pour " "plus de détails." -#: lib/choose_repository.tcl:856 +#: lib/choose_repository.tcl:854 msgid "Cannot fetch tags. See console output for details." msgstr "" -"Impossible de récupérer les marques. Voir la sortie console pour plus de " -"détails." +"Impossible de récupérer les marques (tags). Voir la sortie console pour plus " +"de détails." -#: lib/choose_repository.tcl:880 +#: lib/choose_repository.tcl:878 msgid "Cannot determine HEAD. See console output for details." msgstr "Impossible de déterminer HEAD. Voir la sortie console pour plus de détails." -#: lib/choose_repository.tcl:889 +#: lib/choose_repository.tcl:887 #, tcl-format msgid "Unable to cleanup %s" msgstr "Impossible de nettoyer %s" -#: lib/choose_repository.tcl:895 +#: lib/choose_repository.tcl:893 msgid "Clone failed." msgstr "Le clonage a échoué." -#: lib/choose_repository.tcl:902 +#: lib/choose_repository.tcl:900 msgid "No default branch obtained." msgstr "Aucune branche par défaut n'a été obtenue." -#: lib/choose_repository.tcl:913 +#: lib/choose_repository.tcl:911 #, tcl-format msgid "Cannot resolve %s as a commit." msgstr "Impossible de résoudre %s comme commit." -#: lib/choose_repository.tcl:925 +#: lib/choose_repository.tcl:923 msgid "Creating working directory" msgstr "Création du répertoire de travail" -#: lib/choose_repository.tcl:926 lib/index.tcl:65 lib/index.tcl:127 +#: lib/choose_repository.tcl:924 lib/index.tcl:65 lib/index.tcl:127 #: lib/index.tcl:193 msgid "files" msgstr "fichiers" -#: lib/choose_repository.tcl:955 +#: lib/choose_repository.tcl:953 msgid "Initial file checkout failed." -msgstr "L'emprunt initial de fichier a échoué." +msgstr "Chargement initial du fichier échoué." -#: lib/choose_repository.tcl:971 +#: lib/choose_repository.tcl:969 msgid "Open" msgstr "Ouvrir" -#: lib/choose_repository.tcl:981 +#: lib/choose_repository.tcl:979 msgid "Repository:" -msgstr "Référentiel :" +msgstr "Dépôt :" -#: lib/choose_repository.tcl:1031 +#: lib/choose_repository.tcl:1027 #, tcl-format msgid "Failed to open repository %s:" -msgstr "Impossible d'ouvrir le référentiel %s :" +msgstr "Impossible d'ouvrir le dépôt %s :" #: lib/choose_rev.tcl:53 msgid "This Detached Checkout" @@ -1143,11 +1171,11 @@ msgstr "Branche locale" #: lib/choose_rev.tcl:79 msgid "Tracking Branch" -msgstr "Suivi de branche" +msgstr "Branche de suivi" #: lib/choose_rev.tcl:84 lib/choose_rev.tcl:538 msgid "Tag" -msgstr "Marque" +msgstr "Marque (tag)" #: lib/choose_rev.tcl:317 #, tcl-format @@ -1164,7 +1192,7 @@ msgstr "L'expression de révision est vide." #: lib/choose_rev.tcl:531 msgid "Updated" -msgstr "Misa à jour" +msgstr "Mise-à-jour:" #: lib/choose_rev.tcl:559 msgid "URL" @@ -1218,9 +1246,9 @@ msgid "" "The rescan will be automatically started now.\n" msgstr "" "L'état lors de la dernière synchronisation ne correspond plus à l'état du " -"référentiel.\n" +"dépôt.\n" "\n" -"Un autre programme Git a modifié ce référentiel depuis la dernière " +"Un autre programme Git a modifié ce dépôt depuis la dernière " "synchronisation. Une resynshronisation doit être effectuée avant de pouvoir " "créer un nouveau commit.\n" "\n" @@ -1258,7 +1286,7 @@ msgid "" msgstr "" "Pas de modification à commiter.\n" "\n" -"Vous devez pré-commiter au moins 1 fichier avant de pouvoir commiter.\n" +"Vous devez indexer au moins 1 fichier avant de pouvoir commiter.\n" #: lib/commit.tcl:183 msgid "" @@ -1285,19 +1313,19 @@ msgstr "attention : Tcl ne supporte pas l'encodage '%s'." #: lib/commit.tcl:221 msgid "Calling pre-commit hook..." -msgstr "Appel du programme externe d'avant commit..." +msgstr "Lancement de l'action d'avant-commit..." #: lib/commit.tcl:236 msgid "Commit declined by pre-commit hook." -msgstr "Commit refusé par le programme externe d'avant commit." +msgstr "Commit refusé par l'action d'avant-commit." #: lib/commit.tcl:259 msgid "Calling commit-msg hook..." -msgstr "Appel du programme externe de message de commit..." +msgstr "Lancement de l'action \"message de commit\"..." #: lib/commit.tcl:274 msgid "Commit declined by commit-msg hook." -msgstr "Commit refusé par le programme externe de message de commit." +msgstr "Commit refusé par l'action \"message de commit\"." #: lib/commit.tcl:287 msgid "Committing changes..." @@ -1406,7 +1434,7 @@ msgid "" "\n" "Compress the database now?" msgstr "" -"Ce référentiel comprend actuellement environ %i objets ayant leur fichier " +"Ce dépôt comprend actuellement environ %i objets ayant leur fichier " "particulier.\n" "\n" "Pour conserver une performance optimale, il est fortement recommandé de " @@ -1420,7 +1448,7 @@ msgstr "" msgid "Invalid date from Git: %s" msgstr "Date invalide de Git : %s" -#: lib/diff.tcl:42 +#: lib/diff.tcl:44 #, tcl-format msgid "" "No differences detected.\n" @@ -1443,39 +1471,47 @@ msgstr "" "Une resynchronisation va être lancée automatiquement pour trouver d'autres " "fichiers qui pourraient se trouver dans le même état." -#: lib/diff.tcl:81 +#: lib/diff.tcl:83 #, tcl-format msgid "Loading diff of %s..." msgstr "Chargement des différences de %s..." -#: lib/diff.tcl:114 lib/diff.tcl:184 +#: lib/diff.tcl:116 lib/diff.tcl:190 #, tcl-format msgid "Unable to display %s" msgstr "Impossible d'afficher %s" -#: lib/diff.tcl:115 +#: lib/diff.tcl:117 msgid "Error loading file:" msgstr "Erreur lors du chargement du fichier :" -#: lib/diff.tcl:122 +#: lib/diff.tcl:124 msgid "Git Repository (subproject)" -msgstr "Référentiel Git (sous projet)" +msgstr "Dépôt Git (sous projet)" -#: lib/diff.tcl:134 +#: lib/diff.tcl:136 msgid "* Binary file (not showing content)." msgstr "* Fichier binaire (pas d'apperçu du contenu)." -#: lib/diff.tcl:185 +#: lib/diff.tcl:191 msgid "Error loading diff:" msgstr "Erreur lors du chargement des différences :" -#: lib/diff.tcl:303 +#: lib/diff.tcl:313 msgid "Failed to unstage selected hunk." -msgstr "La suppression dans le pré-commit de la section sélectionnée a échouée." +msgstr "Échec lors de la désindexation de la section sélectionnée." -#: lib/diff.tcl:310 +#: lib/diff.tcl:320 msgid "Failed to stage selected hunk." -msgstr "Le pré-commit de la section sélectionnée a échoué." +msgstr "Échec lors de l'indexation de la section." + +#: lib/diff.tcl:386 +msgid "Failed to unstage selected line." +msgstr "Échec lors de la désindexation de la ligne sélectionnée." + +#: lib/diff.tcl:394 +msgid "Failed to stage selected line." +msgstr "Échec lors de l'indexation de la ligne." #: lib/error.tcl:20 lib/error.tcl:114 msgid "error" @@ -1491,17 +1527,19 @@ msgstr "Vous devez corriger les erreurs suivantes avant de pouvoir commiter." #: lib/index.tcl:6 msgid "Unable to unlock the index." -msgstr "Impossible de dévérouiller le pré-commit." +msgstr "Impossible de dévérouiller l'index." #: lib/index.tcl:15 msgid "Index Error" -msgstr "Erreur de pré-commit" +msgstr "Erreur de l'index" #: lib/index.tcl:21 msgid "" "Updating the Git index failed. A rescan will be automatically started to " "resynchronize git-gui." -msgstr "Le pré-commit a échoué. Une resynchronisation va être lancée automatiquement." +msgstr "" +"Échec de la mise à jour de l'index. Une resynchronisation va être lancée " +"automatiquement." #: lib/index.tcl:27 msgid "Continue" @@ -1509,12 +1547,12 @@ msgstr "Continuer" #: lib/index.tcl:31 msgid "Unlock Index" -msgstr "Dévérouiller le pré-commit" +msgstr "Déverouiller l'index" #: lib/index.tcl:282 #, tcl-format msgid "Unstaging %s from commit" -msgstr "Supprimer %s du commit" +msgstr "Désindexation de: %s" #: lib/index.tcl:313 msgid "Ready to commit." @@ -1523,23 +1561,23 @@ msgstr "Prêt à être commité." #: lib/index.tcl:326 #, tcl-format msgid "Adding %s" -msgstr "Ajouter %s" +msgstr "Ajout de %s" #: lib/index.tcl:381 #, tcl-format msgid "Revert changes in file %s?" -msgstr "Inverser les modifications dans le fichier %s ? " +msgstr "Annuler les modifications dans le fichier %s ? " #: lib/index.tcl:383 #, tcl-format msgid "Revert changes in these %i files?" -msgstr "Inverser les modifications dans ces %i fichiers ?" +msgstr "Annuler les modifications dans ces %i fichiers ?" #: lib/index.tcl:391 msgid "Any unstaged changes will be permanently lost by the revert." msgstr "" -"Toutes les modifications non pré-commitées seront définitivement perdues " -"lors de l'inversion." +"Toutes les modifications non-indexées seront définitivement perdues par " +"l'annulation." #: lib/index.tcl:394 msgid "Do Nothing" @@ -1551,7 +1589,7 @@ msgid "" "\n" "You must finish amending this commit before starting any type of merge.\n" msgstr "" -"Impossible de fucionner pendant une correction.\n" +"Impossible de fusionner pendant une correction.\n" "\n" "Vous devez finir de corriger ce commit avant de lancer une quelconque " "fusion.\n" @@ -1566,9 +1604,9 @@ msgid "" "The rescan will be automatically started now.\n" msgstr "" "L'état lors de la dernière synchronisation ne correspond plus à l'état du " -"référentiel.\n" +"dépôt.\n" "\n" -"Un autre programme Git a modifié ce référentiel depuis la dernière " +"Un autre programme Git a modifié ce dépôt depuis la dernière " "synchronisation. Une resynchronisation doit être effectuée avant de pouvoir " "fusionner de nouveau.\n" "\n" @@ -1588,8 +1626,8 @@ msgstr "" "\n" "Le fichier %s a des conflicts de fusion.\n" "\n" -"Vous devez les résoudre, puis pré-commiter le fichier, et enfin commiter " -"pour terminer la fusion courante. Seulementà ce moment là, il sera possible " +"Vous devez les résoudre, puis indexer le fichier, et enfin commiter pour " +"terminer la fusion courante. Seulement à ce moment là sera-t-il possible " "d'effectuer une nouvelle fusion.\n" #: lib/merge.tcl:54 @@ -1685,11 +1723,11 @@ msgstr "Abandon" msgid "files reset" msgstr "fichiers réinitialisés" -#: lib/merge.tcl:265 +#: lib/merge.tcl:266 msgid "Abort failed." msgstr "L'abandon a échoué." -#: lib/merge.tcl:267 +#: lib/merge.tcl:268 msgid "Abort completed. Ready." msgstr "Abandon teminé. Prêt." @@ -1704,11 +1742,11 @@ msgstr "Sauvegarder" #: lib/option.tcl:109 #, tcl-format msgid "%s Repository" -msgstr "Référentiel de %s" +msgstr "Dépôt: %s" #: lib/option.tcl:110 msgid "Global (All Repositories)" -msgstr "Globales (tous les référentiels)" +msgstr "Globales (tous les dépôts)" #: lib/option.tcl:116 msgid "User Name" @@ -1736,56 +1774,76 @@ msgstr "Faire confiance aux dates de modification de fichiers " #: lib/option.tcl:124 msgid "Prune Tracking Branches During Fetch" -msgstr "Nettoyer les branches de suivi pendant la récupération" +msgstr "Purger les branches de suivi pendant la récupération" #: lib/option.tcl:125 msgid "Match Tracking Branches" msgstr "Faire correspondre les branches de suivi" #: lib/option.tcl:126 +msgid "Blame Copy Only On Changed Files" +msgstr "Annoter les copies seulement sur fichiers modifiés" + +#: lib/option.tcl:127 +msgid "Minimum Letters To Blame Copy On" +msgstr "Minimum de caratères pour annoter une copie" + +#: lib/option.tcl:128 msgid "Number of Diff Context Lines" msgstr "Nombre de lignes de contexte dans les diffs" -#: lib/option.tcl:127 +#: lib/option.tcl:129 msgid "Commit Message Text Width" msgstr "Largeur du texte de message de commit" -#: lib/option.tcl:128 +#: lib/option.tcl:130 msgid "New Branch Name Template" msgstr "Nouveau modèle de nom de branche" -#: lib/option.tcl:192 +#: lib/option.tcl:194 msgid "Spelling Dictionary:" msgstr "Dictionnaire d'orthographe :" -#: lib/option.tcl:216 +#: lib/option.tcl:218 msgid "Change Font" -msgstr "Modifier les fontes" +msgstr "Modifier les polices" -#: lib/option.tcl:220 +#: lib/option.tcl:222 #, tcl-format msgid "Choose %s" msgstr "Choisir %s" -#: lib/option.tcl:226 +#: lib/option.tcl:228 msgid "pt." msgstr "pt." -#: lib/option.tcl:240 +#: lib/option.tcl:242 msgid "Preferences" msgstr "Préférences" -#: lib/option.tcl:275 +#: lib/option.tcl:277 msgid "Failed to completely save options:" msgstr "La sauvegarde complète des options a échouée :" +#: lib/remote.tcl:165 +msgid "Prune from" +msgstr "Purger de" + +#: lib/remote.tcl:170 +msgid "Fetch from" +msgstr "Récupérer de" + +#: lib/remote.tcl:213 +msgid "Push to" +msgstr "Pousser vers" + #: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34 msgid "Delete Remote Branch" msgstr "Supprimer branche distante" #: lib/remote_branch_delete.tcl:47 msgid "From Repository" -msgstr "Référentiel" +msgstr "Dépôt source" #: lib/remote_branch_delete.tcl:50 lib/transport.tcl:123 msgid "Remote:" @@ -1856,25 +1914,13 @@ msgstr "Supprimer les branches de %s" #: lib/remote_branch_delete.tcl:286 msgid "No repository selected." -msgstr "Aucun référentiel n'est sélectionné." +msgstr "Aucun dépôt n'est sélectionné." #: lib/remote_branch_delete.tcl:291 #, tcl-format msgid "Scanning %s..." msgstr "Synchronisation de %s..." -#: lib/remote.tcl:165 -msgid "Prune from" -msgstr "Nettoyer de" - -#: lib/remote.tcl:170 -msgid "Fetch from" -msgstr "Récupérer de" - -#: lib/remote.tcl:213 -msgid "Push to" -msgstr "Pousser vers" - #: lib/shortcut.tcl:20 lib/shortcut.tcl:61 msgid "Cannot write shortcut:" msgstr "Impossible d'écrire le raccourcis :" @@ -1908,15 +1954,15 @@ msgstr "La vérification d'orthographe a échouée silentieusement au démarrage msgid "Unrecognized spell checker" msgstr "Vérificateur d'orthographe non reconnu" -#: lib/spellcheck.tcl:180 +#: lib/spellcheck.tcl:186 msgid "No Suggestions" msgstr "Aucune suggestion" -#: lib/spellcheck.tcl:381 +#: lib/spellcheck.tcl:387 msgid "Unexpected EOF from spell checker" -msgstr "Fin de fichier innatendue envoyée par le vérificateur d'orthographe" +msgstr "EOF inattendue envoyée par le vérificateur d'orthographe" -#: lib/spellcheck.tcl:385 +#: lib/spellcheck.tcl:391 msgid "Spell Checker Failed" msgstr "Le vérificateur d'orthographe a échoué" @@ -1938,7 +1984,7 @@ msgstr "Récupération des dernières modifications de %s" #: lib/transport.tcl:18 #, tcl-format msgid "remote prune %s" -msgstr "nettoyer à distance %s" +msgstr "purger à distance %s" #: lib/transport.tcl:19 #, tcl-format @@ -1970,11 +2016,11 @@ msgstr "Branches source" #: lib/transport.tcl:120 msgid "Destination Repository" -msgstr "Référentiel de destination" +msgstr "Dépôt de destination" #: lib/transport.tcl:158 msgid "Transfer Options" -msgstr "Transférer options" +msgstr "Options de transfert" #: lib/transport.tcl:160 msgid "Force overwrite existing branch (may discard changes)" @@ -1988,5 +2034,5 @@ msgstr "Utiliser des petits paquets (pour les connexions lentes)" #: lib/transport.tcl:168 msgid "Include tags" -msgstr "Inclure les marques" +msgstr "Inclure les marques (tags)" diff --git a/git-gui/po/po2msg.sh b/git-gui/po/po2msg.sh index b7c4bf3fdf..1e9f992528 100644 --- a/git-gui/po/po2msg.sh +++ b/git-gui/po/po2msg.sh @@ -11,8 +11,8 @@ proc u2a {s} { foreach i [split $s ""] { scan $i %c c if {$c<128} { - # escape '[', '\' and ']' - if {$c == 0x5b || $c == 0x5d} { + # escape '[', '\', '$' and ']' + if {$c == 0x5b || $c == 0x5d || $c == 0x24} { append res "\\" } append res $i diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh index 645e1147dc..1dadbb4966 100755 --- a/git-merge-octopus.sh +++ b/git-merge-octopus.sh @@ -61,7 +61,7 @@ do exit 2 esac - common=$(git merge-base --all $MRC $SHA1) || + common=$(git merge-base --all $SHA1 $MRC) || die "Unable to find common commit with $SHA1" case "$LF$common$LF" in @@ -100,14 +100,7 @@ do next=$(git write-tree 2>/dev/null) fi - # We have merged the other branch successfully. Ideally - # we could implement OR'ed heads in merge-base, and keep - # a list of commits we have merged so far in MRC to feed - # them to merge-base, but we approximate it by keep using - # the current MRC. We used to update it to $common, which - # was incorrectly doing AND'ed merge-base here, which was - # unneeded. - + MRC="$MRC $SHA1" MRT=$next done diff --git a/git-stash.sh b/git-stash.sh index e15c12abc3..d799c76378 100755 --- a/git-stash.sh +++ b/git-stash.sh @@ -39,6 +39,7 @@ clear_stash () { create_stash () { stash_msg="$1" + git update-index -q --refresh if no_changes then exit 0 @@ -101,6 +102,7 @@ save_stash () { stash_msg="$*" + git update-index -q --refresh if no_changes then echo 'No local changes to save' @@ -150,6 +152,7 @@ show_stash () { } apply_stash () { + git update-index -q --refresh && git diff-files --quiet --ignore-submodules || die 'Cannot restore on top of a dirty state' diff --git a/git-submodule.sh b/git-submodule.sh index b40f876a2c..1c39b593a6 100755 --- a/git-submodule.sh +++ b/git-submodule.sh @@ -6,9 +6,10 @@ USAGE="[--quiet] [--cached] \ [add <repo> [-b branch] <path>]|[status|init|update [-i|--init]|summary [-n|--summary-limit <n>] [<commit>]] \ -[--] [<path>...]" +[--] [<path>...]|[foreach <command>]|[sync [--] [<path>...]]" OPTIONS_SPEC= . git-sh-setup +. git-parse-remote require_work_tree command= @@ -30,12 +31,11 @@ say() # Resolve relative url by appending to parent's url resolve_relative_url () { - branch="$(git symbolic-ref HEAD 2>/dev/null)" - remote="$(git config branch.${branch#refs/heads/}.remote)" - remote="${remote:-origin}" + remote=$(get_default_remote) remoteurl=$(git config "remote.$remote.url") || die "remote ($remote) does not have a url defined in .git/config" url="$1" + remoteurl=${remoteurl%/} while test -n "$url" do case "$url" in @@ -50,7 +50,16 @@ resolve_relative_url () break;; esac done - echo "$remoteurl/$url" + echo "$remoteurl/${url%/}" +} + +# +# Get submodule info for registered submodules +# $@ = path to limit submodule list +# +module_list() +{ + git ls-files --stage -- "$@" | grep '^160000 ' } # @@ -199,6 +208,26 @@ cmd_add() } # +# Execute an arbitrary command sequence in each checked out +# submodule +# +# $@ = command to execute +# +cmd_foreach() +{ + module_list | + while read mode sha1 stage path + do + if test -e "$path"/.git + then + say "Entering '$path'" + (cd "$path" && eval "$@") || + die "Stopping at '$path'; script returned non-zero status." + fi + done +} + +# # Register submodules in .git/config # # $@ = requested paths (default to all) @@ -226,7 +255,7 @@ cmd_init() shift done - git ls-files --stage -- "$@" | grep '^160000 ' | + module_list "$@" | while read mode sha1 stage path do # Skip already registered paths @@ -284,7 +313,7 @@ cmd_update() esac done - git ls-files --stage -- "$@" | grep '^160000 ' | + module_list "$@" | while read mode sha1 stage path do name=$(module_name "$path") || exit @@ -549,7 +578,7 @@ cmd_status() shift done - git ls-files --stage -- "$@" | grep '^160000 ' | + module_list "$@" | while read mode sha1 stage path do name=$(module_name "$path") || exit @@ -573,6 +602,50 @@ cmd_status() fi done } +# +# Sync remote urls for submodules +# This makes the value for remote.$remote.url match the value +# specified in .gitmodules. +# +cmd_sync() +{ + while test $# -ne 0 + do + case "$1" in + -q|--quiet) + quiet=1 + shift + ;; + --) + shift + break + ;; + -*) + usage + ;; + *) + break + ;; + esac + done + cd_to_toplevel + module_list "$@" | + while read mode sha1 stage path + do + name=$(module_name "$path") + url=$(git config -f .gitmodules --get submodule."$name".url) + if test -e "$path"/.git + then + ( + unset GIT_DIR + cd "$path" + remote=$(get_default_remote) + say "Synchronizing submodule url for '$name'" + git config remote."$remote".url "$url" + ) + fi + done +} # This loop parses the command line arguments to find the # subcommand name to dispatch. Parsing of the subcommand specific @@ -583,7 +656,7 @@ cmd_status() while test $# != 0 && test -z "$command" do case "$1" in - add | init | update | status | summary) + add | foreach | init | update | status | summary | sync) command=$1 ;; -q|--quiet) diff --git a/git-svn.perl b/git-svn.perl index 7a1d26db8b..88066c9a75 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -421,15 +421,15 @@ sub cmd_dcommit { $head ||= 'HEAD'; my @refs; my ($url, $rev, $uuid, $gs) = working_head_info($head, \@refs); + unless ($gs) { + die "Unable to determine upstream SVN information from ", + "$head history.\nPerhaps the repository is empty."; + } $url = defined $_commit_url ? $_commit_url : $gs->full_url; my $last_rev = $_revision if defined $_revision; if ($url) { print "Committing to $url ...\n"; } - unless ($gs) { - die "Unable to determine upstream SVN information from ", - "$head history.\nPerhaps the repository is empty."; - } my ($linear_refs, $parents) = linearize_history($gs, \@refs); if ($_no_rebase && scalar(@$linear_refs) > 1) { warn "Attempting to commit more than one change while ", @@ -803,8 +803,28 @@ sub cmd_commit_diff { } } +sub escape_uri_only { + my ($uri) = @_; + my @tmp; + foreach (split m{/}, $uri) { + s/([^\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg; + push @tmp, $_; + } + join('/', @tmp); +} + +sub escape_url { + my ($url) = @_; + if ($url =~ m#^([^:]+)://([^/]*)(.*)$#) { + my ($scheme, $domain, $uri) = ($1, $2, escape_uri_only($3)); + $url = "$scheme://$domain$uri"; + } + $url; +} + sub cmd_info { my $path = canonicalize_path(defined($_[0]) ? $_[0] : "."); + my $fullpath = canonicalize_path($cmd_dir_prefix . $path); if (exists $_[1]) { die "Too many arguments specified\n"; } @@ -812,8 +832,8 @@ sub cmd_info { my ($file_type, $diff_status) = find_file_type_and_diff_status($path); if (!$file_type && !$diff_status) { - print STDERR "$path: (Not a versioned resource)\n\n"; - return; + print STDERR "svn: '$path' is not under version control\n"; + exit 1; } my ($url, $rev, $uuid, $gs) = working_head_info('HEAD'); @@ -825,21 +845,21 @@ sub cmd_info { # canonicalize_path() will return "" to make libsvn 1.5.x happy, $path = "." if $path eq ""; - my $full_url = $url . ($path eq "." ? "" : "/$path"); + my $full_url = $url . ($fullpath eq "" ? "" : "/$fullpath"); if ($_url) { - print $full_url, "\n"; + print escape_url($full_url), "\n"; return; } my $result = "Path: $path\n"; $result .= "Name: " . basename($path) . "\n" if $file_type ne "dir"; - $result .= "URL: " . $full_url . "\n"; + $result .= "URL: " . escape_url($full_url) . "\n"; eval { my $repos_root = $gs->repos_root; Git::SVN::remove_username($repos_root); - $result .= "Repository Root: $repos_root\n"; + $result .= "Repository Root: " . escape_url($repos_root) . "\n"; }; if ($@) { $result .= "Repository Root: (offline)\n"; @@ -861,7 +881,7 @@ sub cmd_info { } my ($lc_author, $lc_rev, $lc_date_utc); - my @args = Git::SVN::Log::git_svn_log_cmd($rev, $rev, "--", $path); + my @args = Git::SVN::Log::git_svn_log_cmd($rev, $rev, "--", $fullpath); my $log = command_output_pipe(@args); my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/; while (<$log>) { @@ -3284,7 +3304,7 @@ sub close_file { my $out = syswrite($tmp_fh, $str, $res); defined($out) && $out == $res or croak("write ", - $tmp_fh->filename, + Git::temp_path($tmp_fh), ": $!\n"); } defined $res or croak $!; @@ -3295,7 +3315,7 @@ sub close_file { } $hash = $::_repository->hash_and_insert_object( - $fh->filename); + Git::temp_path($fh)); $hash =~ /^[a-f\d]{40}$/ or die "not a sha1: $hash\n"; Git::temp_release($fb->{base}, 1); @@ -3380,11 +3400,12 @@ sub generate_diff { while (<$diff_fh>) { chomp $_; # this gets rid of the trailing "\0" if ($state eq 'meta' && /^:(\d{6})\s(\d{6})\s - $::sha1\s($::sha1)\s + ($::sha1)\s($::sha1)\s ([MTCRAD])\d*$/xo) { push @mods, { mode_a => $1, mode_b => $2, - sha1_b => $3, chg => $4 }; - if ($4 =~ /^(?:C|R)$/) { + sha1_a => $3, sha1_b => $4, + chg => $5 }; + if ($5 =~ /^(?:C|R)$/) { $state = 'file_a'; } else { $state = 'file_b'; @@ -3636,6 +3657,7 @@ sub R { my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat, $self->url_path($m->{file_a}), $self->{r}); print "\tR\t$m->{file_a} => $m->{file_b}\n" unless $::_q; + $self->apply_autoprops($file, $fbat); $self->chg_file($fbat, $m); $self->close_file($fbat,undef,$self->{pool}); @@ -3662,33 +3684,52 @@ sub change_file_prop { $self->SUPER::change_file_prop($fbat, $pname, $pval, $self->{pool}); } -sub chg_file { - my ($self, $fbat, $m) = @_; - if ($m->{mode_b} =~ /755$/ && $m->{mode_a} !~ /755$/) { - $self->change_file_prop($fbat,'svn:executable','*'); - } elsif ($m->{mode_b} !~ /755$/ && $m->{mode_a} =~ /755$/) { - $self->change_file_prop($fbat,'svn:executable',undef); - } - my $fh = Git::temp_acquire('git_blob'); - if ($m->{mode_b} =~ /^120/) { +sub _chg_file_get_blob ($$$$) { + my ($self, $fbat, $m, $which) = @_; + my $fh = Git::temp_acquire("git_blob_$which"); + if ($m->{"mode_$which"} =~ /^120/) { print $fh 'link ' or croak $!; $self->change_file_prop($fbat,'svn:special','*'); - } elsif ($m->{mode_a} =~ /^120/ && $m->{mode_b} !~ /^120/) { + } elsif ($m->{mode_a} =~ /^120/ && $m->{"mode_$which"} !~ /^120/) { $self->change_file_prop($fbat,'svn:special',undef); } - my $size = $::_repository->cat_blob($m->{sha1_b}, $fh); - croak "Failed to read object $m->{sha1_b}" if ($size < 0); + my $blob = $m->{"sha1_$which"}; + return ($fh,) if ($blob =~ /^0{40}$/); + my $size = $::_repository->cat_blob($blob, $fh); + croak "Failed to read object $blob" if ($size < 0); $fh->flush == 0 or croak $!; seek $fh, 0, 0 or croak $!; my $exp = ::md5sum($fh); seek $fh, 0, 0 or croak $!; + return ($fh, $exp); +} +sub chg_file { + my ($self, $fbat, $m) = @_; + if ($m->{mode_b} =~ /755$/ && $m->{mode_a} !~ /755$/) { + $self->change_file_prop($fbat,'svn:executable','*'); + } elsif ($m->{mode_b} !~ /755$/ && $m->{mode_a} =~ /755$/) { + $self->change_file_prop($fbat,'svn:executable',undef); + } + my ($fh_a, $exp_a) = _chg_file_get_blob $self, $fbat, $m, 'a'; + my ($fh_b, $exp_b) = _chg_file_get_blob $self, $fbat, $m, 'b'; my $pool = SVN::Pool->new; - my $atd = $self->apply_textdelta($fbat, undef, $pool); - my $got = SVN::TxDelta::send_stream($fh, @$atd, $pool); - die "Checksum mismatch\nexpected: $exp\ngot: $got\n" if ($got ne $exp); - Git::temp_release($fh, 1); + my $atd = $self->apply_textdelta($fbat, $exp_a, $pool); + if (-s $fh_a) { + my $txstream = SVN::TxDelta::new ($fh_a, $fh_b, $pool); + my $res = SVN::TxDelta::send_txstream($txstream, @$atd, $pool); + if (defined $res) { + die "Unexpected result from send_txstream: $res\n", + "(SVN::Core::VERSION: $SVN::Core::VERSION)\n"; + } + } else { + my $got = SVN::TxDelta::send_stream($fh_b, @$atd, $pool); + die "Checksum mismatch\nexpected: $exp_b\ngot: $got\n" + if ($got ne $exp_b); + } + Git::temp_release($fh_b, 1); + Git::temp_release($fh_a, 1); $pool->clear; } @@ -3984,6 +4025,7 @@ sub gs_do_switch { } } $ra ||= $self; + $url_b = escape_url($url_b); my $reporter = $ra->do_switch($rev_b, '', 1, $url_b, $editor, $pool); my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef) : (); $reporter->set_path('', $rev_a, 0, @lock, $pool); @@ -4383,7 +4425,7 @@ sub config_pager { sub run_pager { return unless -t *STDOUT && defined $pager; - pipe my $rfd, my $wfd or return; + pipe my ($rfd, $wfd) or return; defined(my $pid = fork) or ::fatal "Can't fork: $!"; if (!$pid) { open STDOUT, '>&', $wfd or @@ -286,7 +286,7 @@ static void handle_internal_command(int argc, const char **argv) { "count-objects", cmd_count_objects, RUN_SETUP }, { "describe", cmd_describe, RUN_SETUP }, { "diff", cmd_diff }, - { "diff-files", cmd_diff_files, RUN_SETUP }, + { "diff-files", cmd_diff_files, RUN_SETUP | NEED_WORK_TREE }, { "diff-index", cmd_diff_index, RUN_SETUP }, { "diff-tree", cmd_diff_tree, RUN_SETUP }, { "fast-export", cmd_fast_export, RUN_SETUP }, @@ -364,7 +364,7 @@ static void handle_internal_command(int argc, const char **argv) if (sizeof(ext) > 1) { i = strlen(argv[0]) - strlen(ext); if (i > 0 && !strcmp(argv[0] + i, ext)) { - char *argv0 = strdup(argv[0]); + char *argv0 = xstrdup(argv[0]); argv[0] = cmd = argv0; argv0[i] = '\0'; } @@ -499,7 +499,9 @@ int main(int argc, const char **argv) cmd, argv[0]); exit(1); } - help_unknown_cmd(cmd); + argv[0] = help_unknown_cmd(cmd); + handle_internal_command(argc, argv); + execv_dashed_external(argv); } fprintf(stderr, "Failed to run command '%s': %s\n", diff --git a/git.spec.in b/git.spec.in index c6492e5be2..6733b6f555 100644 --- a/git.spec.in +++ b/git.spec.in @@ -145,6 +145,7 @@ rm -rf $RPM_BUILD_ROOT %files cvs %defattr(-,root,root) %doc Documentation/*git-cvs*.txt +%{_bindir}/git-cvsserver %{_libexecdir}/git-core/*cvs* %{!?_without_docs: %{_mandir}/man1/*cvs*.1*} %{!?_without_docs: %doc Documentation/*git-cvs*.html } @@ -188,6 +189,9 @@ rm -rf $RPM_BUILD_ROOT # No files for you! %changelog +* Fri Sep 12 2008 Quy Tonthat <qtonthat@gmail.com> +- move git-cvsserver to bindir. + * Sun Jun 15 2008 Junio C Hamano <gitster@pobox.com> - Remove curl from Requires list. diff --git a/gitk-git/gitk b/gitk-git/gitk index 087c4ac733..2eaa2ae7d6 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -418,10 +418,12 @@ proc stop_rev_list {view} { } proc reset_pending_select {selid} { - global pending_select mainheadid + global pending_select mainheadid selectheadid if {$selid ne {}} { set pending_select $selid + } elseif {$selectheadid ne {}} { + set pending_select $selectheadid } else { set pending_select $mainheadid } @@ -1609,6 +1611,7 @@ proc getcommit {id} { proc readrefs {} { global tagids idtags headids idheads tagobjid global otherrefids idotherrefs mainhead mainheadid + global selecthead selectheadid foreach v {tagids idtags headids idheads otherrefids idotherrefs} { catch {unset $v} @@ -1655,6 +1658,12 @@ proc readrefs {} { set mainhead [string range $thehead 11 end] } } + set selectheadid {} + if {$selecthead ne {}} { + catch { + set selectheadid [exec git rev-parse --verify $selecthead] + } + } } # skip over fake commits @@ -2205,6 +2214,8 @@ proc makewindow {} { -command {flist_hl 1} $flist_menu add command -label [mc "External diff"] \ -command {external_diff} + $flist_menu add command -label [mc "Blame parent commit"] \ + -command {external_blame 1} } # Windows sends all mouse wheel events to the current focused window, not @@ -3012,6 +3023,27 @@ proc external_diff {} { } } +proc external_blame {parent_idx} { + global flist_menu_file + global nullid nullid2 + global parentlist selectedline currentid + + if {$parent_idx > 0} { + set base_commit [lindex $parentlist $selectedline [expr {$parent_idx-1}]] + } else { + set base_commit $currentid + } + + if {$base_commit eq {} || $base_commit eq $nullid || $base_commit eq $nullid2} { + error_popup [mc "No such commit"] + return + } + + if {[catch {exec git gui blame $base_commit $flist_menu_file &} err]} { + error_popup [mc "git gui blame: command failed: $err"] + } +} + # delete $dir when we see eof on $f (presumably because the child has exited) proc delete_at_eof {f dir} { while {[gets $f line] >= 0} {} @@ -9865,6 +9897,9 @@ if {![file isdirectory $gitdir]} { exit 1 } +set selecthead {} +set selectheadid {} + set revtreeargs {} set cmdline_files {} set i 0 @@ -9876,6 +9911,9 @@ foreach arg $argv { set cmdline_files [lrange $argv [expr {$i + 1}] end] break } + "--select-commit=*" { + set selecthead [string range $arg 16 end] + } "--argscmd=*" { set revtreeargscmd [string range $arg 10 end] } @@ -9886,6 +9924,10 @@ foreach arg $argv { incr i } +if {$selecthead eq "HEAD"} { + set selecthead {} +} + if {$i >= [llength $argv] && $revtreeargs ne {}} { # no -- on command line, but some arguments (other than --argscmd) if {[catch { diff --git a/gitweb/gitweb.css b/gitweb/gitweb.css index aa0eeca247..07f5b53788 100644 --- a/gitweb/gitweb.css +++ b/gitweb/gitweb.css @@ -481,6 +481,19 @@ span.refs span { border-color: #ffccff #ff00ee #ff00ee #ffccff; } +span.refs span a { + text-decoration: none; + color: inherit; +} + +span.refs span a:hover { + text-decoration: underline; +} + +span.refs span.indirect { + font-style: italic; +} + span.refs span.ref { background-color: #aaaaff; border-color: #ccccff #0033cc #0033cc #ccccff; diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl index 90cd99bf91..29e21564c8 100755 --- a/gitweb/gitweb.perl +++ b/gitweb/gitweb.perl @@ -1090,13 +1090,23 @@ sub format_log_line_html { } # format marker of refs pointing to given object + +# the destination action is chosen based on object type and current context: +# - for annotated tags, we choose the tag view unless it's the current view +# already, in which case we go to shortlog view +# - for other refs, we keep the current view if we're in history, shortlog or +# log view, and select shortlog otherwise sub format_ref_marker { my ($refs, $id) = @_; my $markers = ''; if (defined $refs->{$id}) { foreach my $ref (@{$refs->{$id}}) { + # this code exploits the fact that non-lightweight tags are the + # only indirect objects, and that they are the only objects for which + # we want to use tag instead of shortlog as action my ($type, $name) = qw(); + my $indirect = ($ref =~ s/\^\{\}$//); # e.g. tags/v2.6.11 or heads/next if ($ref =~ m!^(.*?)s?/(.*)$!) { $type = $1; @@ -1106,8 +1116,29 @@ sub format_ref_marker { $name = $ref; } - $markers .= " <span class=\"$type\" title=\"$ref\">" . - esc_html($name) . "</span>"; + my $class = $type; + $class .= " indirect" if $indirect; + + my $dest_action = "shortlog"; + + if ($indirect) { + $dest_action = "tag" unless $action eq "tag"; + } elsif ($action =~ /^(history|(short)?log)$/) { + $dest_action = $action; + } + + my $dest = ""; + $dest .= "refs/" unless $ref =~ m!^refs/!; + $dest .= $ref; + + my $link = $cgi->a({ + -href => href( + action=>$dest_action, + hash=>$dest + )}, $name); + + $markers .= " <span class=\"$class\" title=\"$ref\">" . + $link . "</span>"; } } @@ -1918,7 +1949,7 @@ sub git_get_references { while (my $line = <$fd>) { chomp $line; - if ($line =~ m!^([0-9a-fA-F]{40})\srefs/($type/?[^^]+)!) { + if ($line =~ m!^([0-9a-fA-F]{40})\srefs/($type.*)$!) { if (defined $refs{$1}) { push @{$refs{$1}}, $2; } else { @@ -2,6 +2,19 @@ #include "grep.h" #include "xdiff-interface.h" +void append_header_grep_pattern(struct grep_opt *opt, enum grep_header_field field, const char *pat) +{ + struct grep_pat *p = xcalloc(1, sizeof(*p)); + p->pattern = pat; + p->origin = "header"; + p->no = 0; + p->token = GREP_PATTERN_HEAD; + p->field = field; + *opt->pattern_tail = p; + opt->pattern_tail = &p->next; + p->next = NULL; +} + void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t) { @@ -247,16 +260,53 @@ static int fixmatch(const char *pattern, char *line, regmatch_t *match) } } +static int strip_timestamp(char *bol, char **eol_p) +{ + char *eol = *eol_p; + int ch; + + while (bol < --eol) { + if (*eol != '>') + continue; + *eol_p = ++eol; + ch = *eol; + *eol = '\0'; + return ch; + } + return 0; +} + +static struct { + const char *field; + size_t len; +} header_field[] = { + { "author ", 7 }, + { "committer ", 10 }, +}; + static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol, char *eol, enum grep_context ctx) { int hit = 0; int at_true_bol = 1; + int saved_ch = 0; regmatch_t pmatch[10]; if ((p->token != GREP_PATTERN) && ((p->token == GREP_PATTERN_HEAD) != (ctx == GREP_CONTEXT_HEAD))) return 0; + if (p->token == GREP_PATTERN_HEAD) { + const char *field; + size_t len; + assert(p->field < ARRAY_SIZE(header_field)); + field = header_field[p->field].field; + len = header_field[p->field].len; + if (strncmp(bol, field, len)) + return 0; + bol += len; + saved_ch = strip_timestamp(bol, &eol); + } + again: if (!opt->fixed) { regex_t *exp = &p->regexp; @@ -298,6 +348,8 @@ static int match_one_pattern(struct grep_opt *opt, struct grep_pat *p, char *bol goto again; } } + if (p->token == GREP_PATTERN_HEAD && saved_ch) + *eol = saved_ch; return hit; } @@ -17,12 +17,18 @@ enum grep_context { GREP_CONTEXT_BODY, }; +enum grep_header_field { + GREP_HEADER_AUTHOR = 0, + GREP_HEADER_COMMITTER, +}; + struct grep_pat { struct grep_pat *next; const char *origin; int no; enum grep_pat_token token; const char *pattern; + enum grep_header_field field; regex_t regexp; }; @@ -74,6 +80,7 @@ struct grep_opt { }; extern void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t); +extern void append_header_grep_pattern(struct grep_opt *, enum grep_header_field, const char *); extern void compile_grep_patterns(struct grep_opt *opt); extern void free_grep_patterns(struct grep_opt *opt); extern int grep_buffer(struct grep_opt *opt, const char *name, char *buf, unsigned long size); diff --git a/hash-object.c b/hash-object.c index 46c06a9552..a4d127cf78 100644 --- a/hash-object.c +++ b/hash-object.c @@ -7,16 +7,14 @@ #include "cache.h" #include "blob.h" #include "quote.h" +#include "parse-options.h" -static void hash_object(const char *path, enum object_type type, int write_object) +static void hash_fd(int fd, const char *type, int write_object, const char *path) { - int fd; struct stat st; unsigned char sha1[20]; - fd = open(path, O_RDONLY); - if (fd < 0 || - fstat(fd, &st) < 0 || - index_fd(sha1, fd, &st, write_object, type, path)) + if (fstat(fd, &st) < 0 || + index_fd(sha1, fd, &st, write_object, type_from_string(type), path)) die(write_object ? "Unable to add %s to database" : "Unable to hash %s", path); @@ -24,12 +22,14 @@ static void hash_object(const char *path, enum object_type type, int write_objec maybe_flush_or_die(stdout, "hash to stdout"); } -static void hash_stdin(const char *type, int write_object) +static void hash_object(const char *path, const char *type, int write_object, + const char *vpath) { - unsigned char sha1[20]; - if (index_pipe(sha1, 0, type, write_object)) - die("Unable to add stdin to database"); - printf("%s\n", sha1_to_hex(sha1)); + int fd; + fd = open(path, O_RDONLY); + if (fd < 0) + die("Cannot open %s", path); + hash_fd(fd, type, write_object, vpath); } static void hash_stdin_paths(const char *type, int write_objects) @@ -45,92 +45,91 @@ static void hash_stdin_paths(const char *type, int write_objects) die("line is badly quoted"); strbuf_swap(&buf, &nbuf); } - hash_object(buf.buf, type_from_string(type), write_objects); + hash_object(buf.buf, type, write_objects, buf.buf); } strbuf_release(&buf); strbuf_release(&nbuf); } -static const char hash_object_usage[] = -"git hash-object [ [-t <type>] [-w] [--stdin] <file>... | --stdin-paths < <list-of-paths> ]"; +static const char * const hash_object_usage[] = { + "git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>...", + "git hash-object --stdin-paths < <list-of-paths>", + NULL +}; -int main(int argc, char **argv) +static const char *type; +static int write_object; +static int hashstdin; +static int stdin_paths; +static int no_filters; +static const char *vpath; + +static const struct option hash_object_options[] = { + OPT_STRING('t', NULL, &type, "type", "object type"), + OPT_BOOLEAN('w', NULL, &write_object, "write the object into the object database"), + OPT_BOOLEAN( 0 , "stdin", &hashstdin, "read the object from stdin"), + OPT_BOOLEAN( 0 , "stdin-paths", &stdin_paths, "read file names from stdin"), + OPT_BOOLEAN( 0 , "no-filters", &no_filters, "store file as is without filters"), + OPT_STRING( 0 , "path", &vpath, "file", "process file as it were from this path"), + OPT_END() +}; + +int main(int argc, const char **argv) { int i; - const char *type = blob_type; - int write_object = 0; const char *prefix = NULL; int prefix_length = -1; - int no_more_flags = 0; - int hashstdin = 0; - int stdin_paths = 0; + const char *errstr = NULL; + + type = blob_type; git_config(git_default_config, NULL); - for (i = 1 ; i < argc; i++) { - if (!no_more_flags && argv[i][0] == '-') { - if (!strcmp(argv[i], "-t")) { - if (argc <= ++i) - usage(hash_object_usage); - type = argv[i]; - } - else if (!strcmp(argv[i], "-w")) { - if (prefix_length < 0) { - prefix = setup_git_directory(); - prefix_length = - prefix ? strlen(prefix) : 0; - } - write_object = 1; - } - else if (!strcmp(argv[i], "--")) { - no_more_flags = 1; - } - else if (!strcmp(argv[i], "--help")) - usage(hash_object_usage); - else if (!strcmp(argv[i], "--stdin-paths")) { - if (hashstdin) { - error("Can't use --stdin-paths with --stdin"); - usage(hash_object_usage); - } - stdin_paths = 1; - - } - else if (!strcmp(argv[i], "--stdin")) { - if (stdin_paths) { - error("Can't use %s with --stdin-paths", argv[i]); - usage(hash_object_usage); - } - if (hashstdin) - die("Multiple --stdin arguments are not supported"); - hashstdin = 1; - } - else - usage(hash_object_usage); - } - else { - const char *arg = argv[i]; - - if (stdin_paths) { - error("Can't specify files (such as \"%s\") with --stdin-paths", arg); - usage(hash_object_usage); - } - - if (hashstdin) { - hash_stdin(type, write_object); - hashstdin = 0; - } - if (0 <= prefix_length) - arg = prefix_filename(prefix, prefix_length, - arg); - hash_object(arg, type_from_string(type), write_object); - no_more_flags = 1; - } + argc = parse_options(argc, argv, hash_object_options, hash_object_usage, 0); + + if (write_object) { + prefix = setup_git_directory(); + prefix_length = prefix ? strlen(prefix) : 0; + if (vpath && prefix) + vpath = prefix_filename(prefix, prefix_length, vpath); + } + + if (stdin_paths) { + if (hashstdin) + errstr = "Can't use --stdin-paths with --stdin"; + else if (argc) + errstr = "Can't specify files with --stdin-paths"; + else if (vpath) + errstr = "Can't use --stdin-paths with --path"; + else if (no_filters) + errstr = "Can't use --stdin-paths with --no-filters"; + } + else { + if (hashstdin > 1) + errstr = "Multiple --stdin arguments are not supported"; + if (vpath && no_filters) + errstr = "Can't use --path with --no-filters"; + } + + if (errstr) { + error (errstr); + usage_with_options(hash_object_usage, hash_object_options); + } + + if (hashstdin) + hash_fd(0, type, write_object, vpath); + + for (i = 0 ; i < argc; i++) { + const char *arg = argv[i]; + + if (0 <= prefix_length) + arg = prefix_filename(prefix, prefix_length, arg); + hash_object(arg, type, write_object, + no_filters ? NULL : vpath ? vpath : arg); } if (stdin_paths) hash_stdin_paths(type, write_object); - if (hashstdin) - hash_stdin(type, write_object); return 0; } @@ -1,276 +1,8 @@ -/* - * builtin-help.c - * - * Builtin help-related commands (help, usage, version) - */ #include "cache.h" #include "builtin.h" #include "exec_cmd.h" -#include "common-cmds.h" -#include "parse-options.h" -#include "run-command.h" - -static struct man_viewer_list { - struct man_viewer_list *next; - char name[FLEX_ARRAY]; -} *man_viewer_list; - -static struct man_viewer_info_list { - struct man_viewer_info_list *next; - const char *info; - char name[FLEX_ARRAY]; -} *man_viewer_info_list; - -enum help_format { - HELP_FORMAT_MAN, - HELP_FORMAT_INFO, - HELP_FORMAT_WEB, -}; - -static int show_all = 0; -static enum help_format help_format = HELP_FORMAT_MAN; -static struct option builtin_help_options[] = { - OPT_BOOLEAN('a', "all", &show_all, "print all available commands"), - OPT_SET_INT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN), - OPT_SET_INT('w', "web", &help_format, "show manual in web browser", - HELP_FORMAT_WEB), - OPT_SET_INT('i', "info", &help_format, "show info page", - HELP_FORMAT_INFO), - OPT_END(), -}; - -static const char * const builtin_help_usage[] = { - "git help [--all] [--man|--web|--info] [command]", - NULL -}; - -static enum help_format parse_help_format(const char *format) -{ - if (!strcmp(format, "man")) - return HELP_FORMAT_MAN; - if (!strcmp(format, "info")) - return HELP_FORMAT_INFO; - if (!strcmp(format, "web") || !strcmp(format, "html")) - return HELP_FORMAT_WEB; - die("unrecognized help format '%s'", format); -} - -static const char *get_man_viewer_info(const char *name) -{ - struct man_viewer_info_list *viewer; - - for (viewer = man_viewer_info_list; viewer; viewer = viewer->next) - { - if (!strcasecmp(name, viewer->name)) - return viewer->info; - } - return NULL; -} - -static int check_emacsclient_version(void) -{ - struct strbuf buffer = STRBUF_INIT; - struct child_process ec_process; - const char *argv_ec[] = { "emacsclient", "--version", NULL }; - int version; - - /* emacsclient prints its version number on stderr */ - memset(&ec_process, 0, sizeof(ec_process)); - ec_process.argv = argv_ec; - ec_process.err = -1; - ec_process.stdout_to_stderr = 1; - if (start_command(&ec_process)) { - fprintf(stderr, "Failed to start emacsclient.\n"); - return -1; - } - strbuf_read(&buffer, ec_process.err, 20); - close(ec_process.err); - - /* - * Don't bother checking return value, because "emacsclient --version" - * seems to always exits with code 1. - */ - finish_command(&ec_process); - - if (prefixcmp(buffer.buf, "emacsclient")) { - fprintf(stderr, "Failed to parse emacsclient version.\n"); - strbuf_release(&buffer); - return -1; - } - - strbuf_remove(&buffer, 0, strlen("emacsclient")); - version = atoi(buffer.buf); - - if (version < 22) { - fprintf(stderr, - "emacsclient version '%d' too old (< 22).\n", - version); - strbuf_release(&buffer); - return -1; - } - - strbuf_release(&buffer); - return 0; -} - -static void exec_woman_emacs(const char* path, const char *page) -{ - if (!check_emacsclient_version()) { - /* This works only with emacsclient version >= 22. */ - struct strbuf man_page = STRBUF_INIT; - - if (!path) - path = "emacsclient"; - strbuf_addf(&man_page, "(woman \"%s\")", page); - execlp(path, "emacsclient", "-e", man_page.buf, NULL); - warning("failed to exec '%s': %s", path, strerror(errno)); - } -} - -static void exec_man_konqueror(const char* path, const char *page) -{ - const char *display = getenv("DISPLAY"); - if (display && *display) { - struct strbuf man_page = STRBUF_INIT; - const char *filename = "kfmclient"; - - /* It's simpler to launch konqueror using kfmclient. */ - if (path) { - const char *file = strrchr(path, '/'); - if (file && !strcmp(file + 1, "konqueror")) { - char *new = xstrdup(path); - char *dest = strrchr(new, '/'); - - /* strlen("konqueror") == strlen("kfmclient") */ - strcpy(dest + 1, "kfmclient"); - path = new; - } - if (file) - filename = file; - } else - path = "kfmclient"; - strbuf_addf(&man_page, "man:%s(1)", page); - execlp(path, filename, "newTab", man_page.buf, NULL); - warning("failed to exec '%s': %s", path, strerror(errno)); - } -} - -static void exec_man_man(const char* path, const char *page) -{ - if (!path) - path = "man"; - execlp(path, "man", page, NULL); - warning("failed to exec '%s': %s", path, strerror(errno)); -} - -static void exec_man_cmd(const char *cmd, const char *page) -{ - struct strbuf shell_cmd = STRBUF_INIT; - strbuf_addf(&shell_cmd, "%s %s", cmd, page); - execl("/bin/sh", "sh", "-c", shell_cmd.buf, NULL); - warning("failed to exec '%s': %s", cmd, strerror(errno)); -} - -static void add_man_viewer(const char *name) -{ - struct man_viewer_list **p = &man_viewer_list; - size_t len = strlen(name); - - while (*p) - p = &((*p)->next); - *p = xcalloc(1, (sizeof(**p) + len + 1)); - strncpy((*p)->name, name, len); -} - -static int supported_man_viewer(const char *name, size_t len) -{ - return (!strncasecmp("man", name, len) || - !strncasecmp("woman", name, len) || - !strncasecmp("konqueror", name, len)); -} - -static void do_add_man_viewer_info(const char *name, - size_t len, - const char *value) -{ - struct man_viewer_info_list *new = xcalloc(1, sizeof(*new) + len + 1); - - strncpy(new->name, name, len); - new->info = xstrdup(value); - new->next = man_viewer_info_list; - man_viewer_info_list = new; -} - -static int add_man_viewer_path(const char *name, - size_t len, - const char *value) -{ - if (supported_man_viewer(name, len)) - do_add_man_viewer_info(name, len, value); - else - warning("'%s': path for unsupported man viewer.\n" - "Please consider using 'man.<tool>.cmd' instead.", - name); - - return 0; -} - -static int add_man_viewer_cmd(const char *name, - size_t len, - const char *value) -{ - if (supported_man_viewer(name, len)) - warning("'%s': cmd for supported man viewer.\n" - "Please consider using 'man.<tool>.path' instead.", - name); - else - do_add_man_viewer_info(name, len, value); - - return 0; -} - -static int add_man_viewer_info(const char *var, const char *value) -{ - const char *name = var + 4; - const char *subkey = strrchr(name, '.'); - - if (!subkey) - return error("Config with no key for man viewer: %s", name); - - if (!strcmp(subkey, ".path")) { - if (!value) - return config_error_nonbool(var); - return add_man_viewer_path(name, subkey - name, value); - } - if (!strcmp(subkey, ".cmd")) { - if (!value) - return config_error_nonbool(var); - return add_man_viewer_cmd(name, subkey - name, value); - } - - warning("'%s': unsupported man viewer sub key.", subkey); - return 0; -} - -static int git_help_config(const char *var, const char *value, void *cb) -{ - if (!strcmp(var, "help.format")) { - if (!value) - return config_error_nonbool(var); - help_format = parse_help_format(value); - return 0; - } - if (!strcmp(var, "man.viewer")) { - if (!value) - return config_error_nonbool(var); - add_man_viewer(value); - return 0; - } - if (!prefixcmp(var, "man.")) - return add_man_viewer_info(var, value); - - return git_default_config(var, value, cb); -} +#include "levenshtein.h" +#include "help.h" /* most GUI terminals set COLUMNS (although some don't export it) */ static int term_columns(void) @@ -294,24 +26,9 @@ static int term_columns(void) return 80; } -static inline void mput_char(char c, unsigned int num) +void add_cmdname(struct cmdnames *cmds, const char *name, int len) { - while(num--) - putchar(c); -} - -static struct cmdnames { - int alloc; - int cnt; - struct cmdname { - size_t len; - char name[1]; - } **names; -} main_cmds, other_cmds; - -static void add_cmdname(struct cmdnames *cmds, const char *name, int len) -{ - struct cmdname *ent = xmalloc(sizeof(*ent) + len); + struct cmdname *ent = xmalloc(sizeof(*ent) + len + 1); ent->len = len; memcpy(ent->name, name, len); @@ -321,6 +38,16 @@ static void add_cmdname(struct cmdnames *cmds, const char *name, int len) cmds->names[cmds->cnt++] = ent; } +static void clean_cmdnames(struct cmdnames *cmds) +{ + int i; + for (i = 0; i < cmds->cnt; ++i) + free(cmds->names[i]); + free(cmds->names); + cmds->cnt = 0; + cmds->alloc = 0; +} + static int cmdname_compare(const void *a_, const void *b_) { struct cmdname *a = *(struct cmdname **)a_; @@ -342,7 +69,7 @@ static void uniq(struct cmdnames *cmds) cmds->cnt = j; } -static void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes) +void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes) { int ci, cj, ei; int cmp; @@ -417,19 +144,21 @@ static int is_executable(const char *name) return st.st_mode & S_IXUSR; } -static unsigned int list_commands_in_dir(struct cmdnames *cmds, - const char *path) +static void list_commands_in_dir(struct cmdnames *cmds, + const char *path, + const char *prefix) { - unsigned int longest = 0; - const char *prefix = "git-"; - int prefix_len = strlen(prefix); + int prefix_len; DIR *dir = opendir(path); struct dirent *de; struct strbuf buf = STRBUF_INIT; int len; if (!dir) - return 0; + return; + if (!prefix) + prefix = "git-"; + prefix_len = strlen(prefix); strbuf_addf(&buf, "%s/", path); len = buf.len; @@ -449,100 +178,81 @@ static unsigned int list_commands_in_dir(struct cmdnames *cmds, if (has_extension(de->d_name, ".exe")) entlen -= 4; - if (longest < entlen) - longest = entlen; - add_cmdname(cmds, de->d_name + prefix_len, entlen); } closedir(dir); strbuf_release(&buf); - - return longest; } -static unsigned int load_command_list(void) +void load_command_list(const char *prefix, + struct cmdnames *main_cmds, + struct cmdnames *other_cmds) { - unsigned int longest = 0; - unsigned int len; const char *env_path = getenv("PATH"); - char *paths, *path, *colon; const char *exec_path = git_exec_path(); - if (exec_path) - longest = list_commands_in_dir(&main_cmds, exec_path); - - if (!env_path) { - fprintf(stderr, "PATH not set\n"); - exit(1); + if (exec_path) { + list_commands_in_dir(main_cmds, exec_path, prefix); + qsort(main_cmds->names, main_cmds->cnt, + sizeof(*main_cmds->names), cmdname_compare); + uniq(main_cmds); } - path = paths = xstrdup(env_path); - while (1) { - if ((colon = strchr(path, PATH_SEP))) - *colon = 0; + if (env_path) { + char *paths, *path, *colon; + path = paths = xstrdup(env_path); + while (1) { + if ((colon = strchr(path, PATH_SEP))) + *colon = 0; - len = list_commands_in_dir(&other_cmds, path); - if (len > longest) - longest = len; - - if (!colon) - break; - path = colon + 1; - } - free(paths); + list_commands_in_dir(other_cmds, path, prefix); - qsort(main_cmds.names, main_cmds.cnt, - sizeof(*main_cmds.names), cmdname_compare); - uniq(&main_cmds); - - qsort(other_cmds.names, other_cmds.cnt, - sizeof(*other_cmds.names), cmdname_compare); - uniq(&other_cmds); - exclude_cmds(&other_cmds, &main_cmds); + if (!colon) + break; + path = colon + 1; + } + free(paths); - return longest; + qsort(other_cmds->names, other_cmds->cnt, + sizeof(*other_cmds->names), cmdname_compare); + uniq(other_cmds); + } + exclude_cmds(other_cmds, main_cmds); } -static void list_commands(void) +void list_commands(const char *title, struct cmdnames *main_cmds, + struct cmdnames *other_cmds) { - unsigned int longest = load_command_list(); - const char *exec_path = git_exec_path(); + int i, longest = 0; - if (main_cmds.cnt) { - printf("available git commands in '%s'\n", exec_path); - printf("----------------------------"); - mput_char('-', strlen(exec_path)); + for (i = 0; i < main_cmds->cnt; i++) + if (longest < main_cmds->names[i]->len) + longest = main_cmds->names[i]->len; + for (i = 0; i < other_cmds->cnt; i++) + if (longest < other_cmds->names[i]->len) + longest = other_cmds->names[i]->len; + + if (main_cmds->cnt) { + const char *exec_path = git_exec_path(); + printf("available %s in '%s'\n", title, exec_path); + printf("----------------"); + mput_char('-', strlen(title) + strlen(exec_path)); putchar('\n'); - pretty_print_string_list(&main_cmds, longest); + pretty_print_string_list(main_cmds, longest); putchar('\n'); } - if (other_cmds.cnt) { - printf("git commands available from elsewhere on your $PATH\n"); - printf("---------------------------------------------------\n"); - pretty_print_string_list(&other_cmds, longest); + if (other_cmds->cnt) { + printf("%s available from elsewhere on your $PATH\n", title); + printf("---------------------------------------"); + mput_char('-', strlen(title)); + putchar('\n'); + pretty_print_string_list(other_cmds, longest); putchar('\n'); } } -void list_common_cmds_help(void) -{ - int i, longest = 0; - - for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { - if (longest < strlen(common_cmds[i].name)) - longest = strlen(common_cmds[i].name); - } - - puts("The most commonly used git commands are:"); - for (i = 0; i < ARRAY_SIZE(common_cmds); i++) { - printf(" %s ", common_cmds[i].name); - mput_char(' ', longest - strlen(common_cmds[i].name)); - puts(common_cmds[i].help); - } -} - -static int is_in_cmdlist(struct cmdnames *c, const char *s) +int is_in_cmdlist(struct cmdnames *c, const char *s) { int i; for (i = 0; i < c->cnt; i++) @@ -551,132 +261,85 @@ static int is_in_cmdlist(struct cmdnames *c, const char *s) return 0; } -static int is_git_command(const char *s) -{ - load_command_list(); - return is_in_cmdlist(&main_cmds, s) || - is_in_cmdlist(&other_cmds, s); -} +static int autocorrect; -static const char *prepend(const char *prefix, const char *cmd) +static int git_unknown_cmd_config(const char *var, const char *value, void *cb) { - size_t pre_len = strlen(prefix); - size_t cmd_len = strlen(cmd); - char *p = xmalloc(pre_len + cmd_len + 1); - memcpy(p, prefix, pre_len); - strcpy(p + pre_len, cmd); - return p; -} + if (!strcmp(var, "help.autocorrect")) + autocorrect = git_config_int(var,value); -static const char *cmd_to_page(const char *git_cmd) -{ - if (!git_cmd) - return "git"; - else if (!prefixcmp(git_cmd, "git")) - return git_cmd; - else if (is_git_command(git_cmd)) - return prepend("git-", git_cmd); - else - return prepend("git", git_cmd); -} - -static void setup_man_path(void) -{ - struct strbuf new_path; - const char *old_path = getenv("MANPATH"); - - strbuf_init(&new_path, 0); - - /* We should always put ':' after our path. If there is no - * old_path, the ':' at the end will let 'man' to try - * system-wide paths after ours to find the manual page. If - * there is old_path, we need ':' as delimiter. */ - strbuf_addstr(&new_path, GIT_MAN_PATH); - strbuf_addch(&new_path, ':'); - if (old_path) - strbuf_addstr(&new_path, old_path); - - setenv("MANPATH", new_path.buf, 1); - - strbuf_release(&new_path); + return git_default_config(var, value, cb); } -static void exec_viewer(const char *name, const char *page) +static int levenshtein_compare(const void *p1, const void *p2) { - const char *info = get_man_viewer_info(name); - - if (!strcasecmp(name, "man")) - exec_man_man(info, page); - else if (!strcasecmp(name, "woman")) - exec_woman_emacs(info, page); - else if (!strcasecmp(name, "konqueror")) - exec_man_konqueror(info, page); - else if (info) - exec_man_cmd(info, page); - else - warning("'%s': unknown man viewer.", name); + const struct cmdname *const *c1 = p1, *const *c2 = p2; + const char *s1 = (*c1)->name, *s2 = (*c2)->name; + int l1 = (*c1)->len; + int l2 = (*c2)->len; + return l1 != l2 ? l1 - l2 : strcmp(s1, s2); } -static void show_man_page(const char *git_cmd) +const char *help_unknown_cmd(const char *cmd) { - struct man_viewer_list *viewer; - const char *page = cmd_to_page(git_cmd); + int i, n, best_similarity = 0; + struct cmdnames main_cmds, other_cmds; - setup_man_path(); - for (viewer = man_viewer_list; viewer; viewer = viewer->next) - { - exec_viewer(viewer->name, page); /* will return when unable */ - } - exec_viewer("man", page); - die("no man viewer handled the request"); -} + memset(&main_cmds, 0, sizeof(main_cmds)); + memset(&other_cmds, 0, sizeof(main_cmds)); -static void show_info_page(const char *git_cmd) -{ - const char *page = cmd_to_page(git_cmd); - setenv("INFOPATH", GIT_INFO_PATH, 1); - execlp("info", "info", "gitman", page, NULL); -} + git_config(git_unknown_cmd_config, NULL); -static void get_html_page_path(struct strbuf *page_path, const char *page) -{ - struct stat st; - const char *html_path = system_path(GIT_HTML_PATH); + load_command_list("git-", &main_cmds, &other_cmds); - /* Check that we have a git documentation directory. */ - if (stat(mkpath("%s/git.html", html_path), &st) - || !S_ISREG(st.st_mode)) - die("'%s': not a documentation directory.", html_path); + ALLOC_GROW(main_cmds.names, main_cmds.cnt + other_cmds.cnt, + main_cmds.alloc); + memcpy(main_cmds.names + main_cmds.cnt, other_cmds.names, + other_cmds.cnt * sizeof(other_cmds.names[0])); + main_cmds.cnt += other_cmds.cnt; + free(other_cmds.names); - strbuf_init(page_path, 0); - strbuf_addf(page_path, "%s/%s.html", html_path, page); -} + /* This reuses cmdname->len for similarity index */ + for (i = 0; i < main_cmds.cnt; ++i) + main_cmds.names[i]->len = + levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4); -/* - * If open_html is not defined in a platform-specific way (see for - * example compat/mingw.h), we use the script web--browse to display - * HTML. - */ -#ifndef open_html -void open_html(const char *path) -{ - execl_git_cmd("web--browse", "-c", "help.browser", path, NULL); -} -#endif + qsort(main_cmds.names, main_cmds.cnt, + sizeof(*main_cmds.names), levenshtein_compare); + + 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; + if (autocorrect && n == 1) { + const char *assumed = main_cmds.names[0]->name; + main_cmds.names[0] = NULL; + clean_cmdnames(&main_cmds); + fprintf(stderr, "WARNING: You called a Git program named '%s', " + "which does not exist.\n" + "Continuing under the assumption that you meant '%s'\n", + cmd, assumed); + if (autocorrect > 0) { + fprintf(stderr, "in %0.1f seconds automatically...\n", + (float)autocorrect/10.0); + poll(NULL, 0, autocorrect * 100); + } + return assumed; + } -static void show_html_page(const char *git_cmd) -{ - const char *page = cmd_to_page(git_cmd); - struct strbuf page_path; /* it leaks but we exec bellow */ + fprintf(stderr, "git: '%s' is not a git-command. See 'git --help'.\n", cmd); - get_html_page_path(&page_path, page); + if (best_similarity < 6) { + fprintf(stderr, "\nDid you mean %s?\n", + n < 2 ? "this": "one of these"); - open_html(page_path.buf); -} + for (i = 0; i < n; i++) + fprintf(stderr, "\t%s\n", main_cmds.names[i]->name); + } -void help_unknown_cmd(const char *cmd) -{ - fprintf(stderr, "git: '%s' is not a git-command. See 'git --help'.\n", cmd); exit(1); } @@ -685,49 +348,3 @@ int cmd_version(int argc, const char **argv, const char *prefix) printf("git version %s\n", git_version_string); return 0; } - -int cmd_help(int argc, const char **argv, const char *prefix) -{ - int nongit; - const char *alias; - - setup_git_directory_gently(&nongit); - git_config(git_help_config, NULL); - - argc = parse_options(argc, argv, builtin_help_options, - builtin_help_usage, 0); - - if (show_all) { - printf("usage: %s\n\n", git_usage_string); - list_commands(); - printf("%s\n", git_more_info_string); - return 0; - } - - if (!argv[0]) { - printf("usage: %s\n\n", git_usage_string); - list_common_cmds_help(); - printf("\n%s\n", git_more_info_string); - return 0; - } - - alias = alias_lookup(argv[0]); - if (alias && !is_git_command(argv[0])) { - printf("`git %s' is aliased to `%s'\n", argv[0], alias); - return 0; - } - - switch (help_format) { - case HELP_FORMAT_MAN: - show_man_page(argv[0]); - break; - case HELP_FORMAT_INFO: - show_info_page(argv[0]); - break; - case HELP_FORMAT_WEB: - show_html_page(argv[0]); - break; - } - - return 0; -} diff --git a/help.h b/help.h new file mode 100644 index 0000000000..56bc15406f --- /dev/null +++ b/help.h @@ -0,0 +1,29 @@ +#ifndef HELP_H +#define HELP_H + +struct cmdnames { + int alloc; + int cnt; + struct cmdname { + size_t len; /* also used for similarity index in help.c */ + char name[FLEX_ARRAY]; + } **names; +}; + +static inline void mput_char(char c, unsigned int num) +{ + while(num--) + putchar(c); +} + +void load_command_list(const char *prefix, + struct cmdnames *main_cmds, + struct cmdnames *other_cmds); +void add_cmdname(struct cmdnames *cmds, const char *name, int len); +/* Here we require that excludes is a sorted list. */ +void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes); +int is_in_cmdlist(struct cmdnames *c, const char *s); +void list_commands(const char *title, struct cmdnames *main_cmds, + struct cmdnames *other_cmds); + +#endif /* HELP_H */ diff --git a/http-push.c b/http-push.c index 6805288857..c9dd9a1f64 100644 --- a/http-push.c +++ b/http-push.c @@ -2237,7 +2237,7 @@ int main(int argc, char **argv) no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:"); if (remote->url && remote->url[strlen(remote->url)-1] != '/') { - rewritten_url = malloc(strlen(remote->url)+2); + rewritten_url = xmalloc(strlen(remote->url)+2); strcpy(rewritten_url, remote->url); strcat(rewritten_url, "/"); remote->url = rewritten_url; @@ -165,7 +165,16 @@ static CURL* get_curl_handle(void) { CURL* result = curl_easy_init(); - curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, curl_ssl_verify); + if (!curl_ssl_verify) { + curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 0); + } else { + /* Verify authenticity of the peer's certificate */ + curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 1); + /* The name in the cert must match whom we tried to connect */ + curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 2); + } + #if LIBCURL_VERSION_NUM >= 0x070907 curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); #endif @@ -402,7 +411,7 @@ static struct fill_chain *fill_cfg = NULL; void add_fill_function(void *data, int (*fill)(void *)) { - struct fill_chain *new = malloc(sizeof(*new)); + struct fill_chain *new = xmalloc(sizeof(*new)); struct fill_chain **linkp = &fill_cfg; new->data = data; new->fill = fill; diff --git a/imap-send.c b/imap-send.c index 1ec1310921..af7e08c094 100644 --- a/imap-send.c +++ b/imap-send.c @@ -23,71 +23,74 @@ */ #include "cache.h" +#ifdef NO_OPENSSL +typedef void *SSL; +#endif -typedef struct store_conf { +struct store_conf { char *name; const char *path; /* should this be here? its interpretation is driver-specific */ char *map_inbox; char *trash; unsigned max_size; /* off_t is overkill */ unsigned trash_remote_new:1, trash_only_new:1; -} store_conf_t; +}; -typedef struct string_list { +struct string_list { struct string_list *next; char string[1]; -} string_list_t; +}; -typedef struct channel_conf { +struct channel_conf { struct channel_conf *next; char *name; - store_conf_t *master, *slave; + struct store_conf *master, *slave; char *master_name, *slave_name; char *sync_state; - string_list_t *patterns; + struct string_list *patterns; int mops, sops; unsigned max_messages; /* for slave only */ -} channel_conf_t; +}; -typedef struct group_conf { +struct group_conf { struct group_conf *next; char *name; - string_list_t *channels; -} group_conf_t; + struct string_list *channels; +}; /* For message->status */ #define M_RECENT (1<<0) /* unsyncable flag; maildir_* depend on this being 1<<0 */ #define M_DEAD (1<<1) /* expunged */ #define M_FLAGS (1<<2) /* flags fetched */ -typedef struct message { +struct message { struct message *next; - /* string_list_t *keywords; */ + /* struct string_list *keywords; */ size_t size; /* zero implies "not fetched" */ int uid; unsigned char flags, status; -} message_t; +}; -typedef struct store { - store_conf_t *conf; /* foreign */ +struct store { + struct store_conf *conf; /* foreign */ /* currently open mailbox */ const char *name; /* foreign! maybe preset? */ char *path; /* own */ - message_t *msgs; /* own */ + struct message *msgs; /* own */ int uidvalidity; unsigned char opts; /* maybe preset? */ /* note that the following do _not_ reflect stats from msgs, but mailbox totals */ int count; /* # of messages */ int recent; /* # of recent messages - don't trust this beyond the initial read */ -} store_t; +}; -typedef struct { +struct msg_data { char *data; int len; unsigned char flags; unsigned int crlf:1; -} msg_data_t; +}; #define DRV_OK 0 #define DRV_MSG_BAD -1 @@ -96,14 +99,14 @@ typedef struct { static int Verbose, Quiet; -static void imap_info( const char *, ... ); -static void imap_warn( const char *, ... ); +static void imap_info(const char *, ...); +static void imap_warn(const char *, ...); -static char *next_arg( char ** ); +static char *next_arg(char **); -static void free_generic_messages( message_t * ); +static void free_generic_messages(struct message *); -static int nfsnprintf( char *buf, int blen, const char *fmt, ... ); +static int nfsnprintf(char *buf, int blen, const char *fmt, ...); static int nfvasprintf(char **strp, const char *fmt, va_list ap) { @@ -119,67 +122,70 @@ static int nfvasprintf(char **strp, const char *fmt, va_list ap) return len; } -static void arc4_init( void ); -static unsigned char arc4_getbyte( void ); +static void arc4_init(void); +static unsigned char arc4_getbyte(void); -typedef struct imap_server_conf { +struct imap_server_conf { char *name; char *tunnel; char *host; int port; char *user; char *pass; -} imap_server_conf_t; + int use_ssl; + int ssl_verify; +}; -typedef struct imap_store_conf { - store_conf_t gen; - imap_server_conf_t *server; +struct imap_store_conf { + struct store_conf gen; + struct imap_server_conf *server; unsigned use_namespace:1; -} imap_store_conf_t; +}; -#define NIL (void*)0x1 -#define LIST (void*)0x2 +#define NIL (void *)0x1 +#define LIST (void *)0x2 -typedef struct _list { - struct _list *next, *child; +struct imap_list { + struct imap_list *next, *child; char *val; int len; -} list_t; +}; -typedef struct { +struct imap_socket { int fd; -} Socket_t; + SSL *ssl; +}; -typedef struct { - Socket_t sock; +struct imap_buffer { + struct imap_socket sock; int bytes; int offset; char buf[1024]; -} buffer_t; +}; struct imap_cmd; -typedef struct imap { +struct imap { int uidnext; /* from SELECT responses */ - list_t *ns_personal, *ns_other, *ns_shared; /* NAMESPACE info */ + struct imap_list *ns_personal, *ns_other, *ns_shared; /* NAMESPACE info */ unsigned caps, rcaps; /* CAPABILITY results */ /* command queue */ int nexttag, num_in_progress, literal_pending; struct imap_cmd *in_progress, **in_progress_append; - buffer_t buf; /* this is BIG, so put it last */ -} imap_t; + struct imap_buffer buf; /* this is BIG, so put it last */ +}; -typedef struct imap_store { - store_t gen; +struct imap_store { + struct store gen; int uidvalidity; - imap_t *imap; + struct imap *imap; const char *prefix; unsigned /*currentnc:1,*/ trashnc:1; -} imap_store_t; +}; struct imap_cmd_cb { - int (*cont)( imap_store_t *ctx, struct imap_cmd *cmd, const char *prompt ); - void (*done)( imap_store_t *ctx, struct imap_cmd *cmd, int response); + int (*cont)(struct imap_store *ctx, struct imap_cmd *cmd, const char *prompt); + void (*done)(struct imap_store *ctx, struct imap_cmd *cmd, int response); void *ctx; char *data; int dlen; @@ -201,6 +207,7 @@ enum CAPABILITY { UIDPLUS, LITERALPLUS, NAMESPACE, + STARTTLS, }; static const char *cap_list[] = { @@ -208,13 +215,14 @@ static const char *cap_list[] = { "UIDPLUS", "LITERAL+", "NAMESPACE", + "STARTTLS", }; #define RESP_OK 0 #define RESP_NO 1 #define RESP_BAD 2 -static int get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ); +static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd); static const char *Flags[] = { @@ -225,42 +233,137 @@ static const char *Flags[] = { "Deleted", }; -static void -socket_perror( const char *func, Socket_t *sock, int ret ) +#ifndef NO_OPENSSL +static void ssl_socket_perror(const char *func) +{ + fprintf(stderr, "%s: %s\n", func, ERR_error_string(ERR_get_error(), 0)); +} +#endif + +static void socket_perror(const char *func, struct imap_socket *sock, int ret) +{ +#ifndef NO_OPENSSL + if (sock->ssl) { + int sslerr = SSL_get_error(sock->ssl, ret); + switch (sslerr) { + case SSL_ERROR_NONE: + break; + case SSL_ERROR_SYSCALL: + perror("SSL_connect"); + break; + default: + ssl_socket_perror("SSL_connect"); + break; + } + } else +#endif + { + if (ret < 0) + perror(func); + else + fprintf(stderr, "%s: unexpected EOF\n", func); + } +} + +static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int verify) { - if (ret < 0) - perror( func ); +#ifdef NO_OPENSSL + fprintf(stderr, "SSL requested but SSL support not compiled in\n"); + return -1; +#else + SSL_METHOD *meth; + SSL_CTX *ctx; + int ret; + + SSL_library_init(); + SSL_load_error_strings(); + + if (use_tls_only) + meth = TLSv1_method(); else - fprintf( stderr, "%s: unexpected EOF\n", func ); + meth = SSLv23_method(); + + if (!meth) { + ssl_socket_perror("SSLv23_method"); + return -1; + } + + ctx = SSL_CTX_new(meth); + + if (verify) + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); + + if (!SSL_CTX_set_default_verify_paths(ctx)) { + ssl_socket_perror("SSL_CTX_set_default_verify_paths"); + return -1; + } + sock->ssl = SSL_new(ctx); + if (!sock->ssl) { + ssl_socket_perror("SSL_new"); + return -1; + } + if (!SSL_set_fd(sock->ssl, sock->fd)) { + ssl_socket_perror("SSL_set_fd"); + return -1; + } + + ret = SSL_connect(sock->ssl); + if (ret <= 0) { + socket_perror("SSL_connect", sock, ret); + return -1; + } + + return 0; +#endif } -static int -socket_read( Socket_t *sock, char *buf, int len ) +static int socket_read(struct imap_socket *sock, char *buf, int len) { - ssize_t n = xread( sock->fd, buf, len ); + ssize_t n; +#ifndef NO_OPENSSL + if (sock->ssl) + n = SSL_read(sock->ssl, buf, len); + else +#endif + n = xread(sock->fd, buf, len); if (n <= 0) { - socket_perror( "read", sock, n ); - close( sock->fd ); + socket_perror("read", sock, n); + close(sock->fd); sock->fd = -1; } return n; } -static int -socket_write( Socket_t *sock, const char *buf, int len ) +static int socket_write(struct imap_socket *sock, const char *buf, int len) { - int n = write_in_full( sock->fd, buf, len ); + int n; +#ifndef NO_OPENSSL + if (sock->ssl) + n = SSL_write(sock->ssl, buf, len); + else +#endif + n = write_in_full(sock->fd, buf, len); if (n != len) { - socket_perror( "write", sock, n ); - close( sock->fd ); + socket_perror("write", sock, n); + close(sock->fd); sock->fd = -1; } return n; } +static void socket_shutdown(struct imap_socket *sock) +{ +#ifndef NO_OPENSSL + if (sock->ssl) { + SSL_shutdown(sock->ssl); + SSL_free(sock->ssl); + } +#endif + close(sock->fd); +} + /* simple line buffering */ -static int -buffer_gets( buffer_t * b, char **s ) +static int buffer_gets(struct imap_buffer *b, char **s) { int n; int start = b->offset; @@ -274,7 +377,7 @@ buffer_gets( buffer_t * b, char **s ) /* shift down used bytes */ *s = b->buf; - assert( start <= b->bytes ); + assert(start <= b->bytes); n = b->bytes - start; if (n) @@ -284,8 +387,8 @@ buffer_gets( buffer_t * b, char **s ) start = 0; } - n = socket_read( &b->sock, b->buf + b->bytes, - sizeof(b->buf) - b->bytes ); + n = socket_read(&b->sock, b->buf + b->bytes, + sizeof(b->buf) - b->bytes); if (n <= 0) return -1; @@ -294,12 +397,12 @@ buffer_gets( buffer_t * b, char **s ) } if (b->buf[b->offset] == '\r') { - assert( b->offset + 1 < b->bytes ); + assert(b->offset + 1 < b->bytes); if (b->buf[b->offset + 1] == '\n') { b->buf[b->offset] = 0; /* terminate the string */ b->offset += 2; /* next line */ if (Verbose) - puts( *s ); + puts(*s); return 0; } } @@ -309,39 +412,36 @@ buffer_gets( buffer_t * b, char **s ) /* not reached */ } -static void -imap_info( const char *msg, ... ) +static void imap_info(const char *msg, ...) { va_list va; if (!Quiet) { - va_start( va, msg ); - vprintf( msg, va ); - va_end( va ); - fflush( stdout ); + va_start(va, msg); + vprintf(msg, va); + va_end(va); + fflush(stdout); } } -static void -imap_warn( const char *msg, ... ) +static void imap_warn(const char *msg, ...) { va_list va; if (Quiet < 2) { - va_start( va, msg ); - vfprintf( stderr, msg, va ); - va_end( va ); + va_start(va, msg); + vfprintf(stderr, msg, va); + va_end(va); } } -static char * -next_arg( char **s ) +static char *next_arg(char **s) { char *ret; if (!s || !*s) return NULL; - while (isspace( (unsigned char) **s )) + while (isspace((unsigned char) **s)) (*s)++; if (!**s) { *s = NULL; @@ -350,10 +450,10 @@ next_arg( char **s ) if (**s == '"') { ++*s; ret = *s; - *s = strchr( *s, '"' ); + *s = strchr(*s, '"'); } else { ret = *s; - while (**s && !isspace( (unsigned char) **s )) + while (**s && !isspace((unsigned char) **s)) (*s)++; } if (*s) { @@ -365,27 +465,25 @@ next_arg( char **s ) return ret; } -static void -free_generic_messages( message_t *msgs ) +static void free_generic_messages(struct message *msgs) { - message_t *tmsg; + struct message *tmsg; for (; msgs; msgs = tmsg) { tmsg = msgs->next; - free( msgs ); + free(msgs); } } -static int -nfsnprintf( char *buf, int blen, const char *fmt, ... ) +static int nfsnprintf(char *buf, int blen, const char *fmt, ...) { int ret; va_list va; - va_start( va, fmt ); - if (blen <= 0 || (unsigned)(ret = vsnprintf( buf, blen, fmt, va )) >= (unsigned)blen) - die( "Fatal: buffer too small. Please report a bug.\n"); - va_end( va ); + va_start(va, fmt); + if (blen <= 0 || (unsigned)(ret = vsnprintf(buf, blen, fmt, va)) >= (unsigned)blen) + die("Fatal: buffer too small. Please report a bug.\n"); + va_end(va); return ret; } @@ -393,21 +491,20 @@ static struct { unsigned char i, j, s[256]; } rs; -static void -arc4_init( void ) +static void arc4_init(void) { int i, fd; unsigned char j, si, dat[128]; - if ((fd = open( "/dev/urandom", O_RDONLY )) < 0 && (fd = open( "/dev/random", O_RDONLY )) < 0) { - fprintf( stderr, "Fatal: no random number source available.\n" ); - exit( 3 ); + if ((fd = open("/dev/urandom", O_RDONLY)) < 0 && (fd = open("/dev/random", O_RDONLY)) < 0) { + fprintf(stderr, "Fatal: no random number source available.\n"); + exit(3); } - if (read_in_full( fd, dat, 128 ) != 128) { - fprintf( stderr, "Fatal: cannot read random number source.\n" ); - exit( 3 ); + if (read_in_full(fd, dat, 128) != 128) { + fprintf(stderr, "Fatal: cannot read random number source.\n"); + exit(3); } - close( fd ); + close(fd); for (i = 0; i < 256; i++) rs.s[i] = i; @@ -423,8 +520,7 @@ arc4_init( void ) arc4_getbyte(); } -static unsigned char -arc4_getbyte( void ) +static unsigned char arc4_getbyte(void) { unsigned char si, sj; @@ -437,54 +533,53 @@ arc4_getbyte( void ) return rs.s[(si + sj) & 0xff]; } -static struct imap_cmd * -v_issue_imap_cmd( imap_store_t *ctx, struct imap_cmd_cb *cb, - const char *fmt, va_list ap ) +static struct imap_cmd *v_issue_imap_cmd(struct imap_store *ctx, + struct imap_cmd_cb *cb, + const char *fmt, va_list ap) { - imap_t *imap = ctx->imap; + struct imap *imap = ctx->imap; struct imap_cmd *cmd; int n, bufl; char buf[1024]; - cmd = xmalloc( sizeof(struct imap_cmd) ); - nfvasprintf( &cmd->cmd, fmt, ap ); + cmd = xmalloc(sizeof(struct imap_cmd)); + nfvasprintf(&cmd->cmd, fmt, ap); cmd->tag = ++imap->nexttag; if (cb) cmd->cb = *cb; else - memset( &cmd->cb, 0, sizeof(cmd->cb) ); + memset(&cmd->cb, 0, sizeof(cmd->cb)); while (imap->literal_pending) - get_cmd_result( ctx, NULL ); + get_cmd_result(ctx, NULL); - bufl = nfsnprintf( buf, sizeof(buf), cmd->cb.data ? CAP(LITERALPLUS) ? + bufl = nfsnprintf(buf, sizeof(buf), cmd->cb.data ? CAP(LITERALPLUS) ? "%d %s{%d+}\r\n" : "%d %s{%d}\r\n" : "%d %s\r\n", - cmd->tag, cmd->cmd, cmd->cb.dlen ); + cmd->tag, cmd->cmd, cmd->cb.dlen); if (Verbose) { if (imap->num_in_progress) - printf( "(%d in progress) ", imap->num_in_progress ); - if (memcmp( cmd->cmd, "LOGIN", 5 )) - printf( ">>> %s", buf ); + printf("(%d in progress) ", imap->num_in_progress); + if (memcmp(cmd->cmd, "LOGIN", 5)) + printf(">>> %s", buf); else - printf( ">>> %d LOGIN <user> <pass>\n", cmd->tag ); + printf(">>> %d LOGIN <user> <pass>\n", cmd->tag); } - if (socket_write( &imap->buf.sock, buf, bufl ) != bufl) { - free( cmd->cmd ); - free( cmd ); + if (socket_write(&imap->buf.sock, buf, bufl) != bufl) { + free(cmd->cmd); + free(cmd); if (cb) - free( cb->data ); + free(cb->data); return NULL; } if (cmd->cb.data) { if (CAP(LITERALPLUS)) { - n = socket_write( &imap->buf.sock, cmd->cb.data, cmd->cb.dlen ); - free( cmd->cb.data ); + n = socket_write(&imap->buf.sock, cmd->cb.data, cmd->cb.dlen); + free(cmd->cb.data); if (n != cmd->cb.dlen || - (n = socket_write( &imap->buf.sock, "\r\n", 2 )) != 2) - { - free( cmd->cmd ); - free( cmd ); + (n = socket_write(&imap->buf.sock, "\r\n", 2)) != 2) { + free(cmd->cmd); + free(cmd); return NULL; } cmd->cb.data = NULL; @@ -499,109 +594,106 @@ v_issue_imap_cmd( imap_store_t *ctx, struct imap_cmd_cb *cb, return cmd; } -static struct imap_cmd * -issue_imap_cmd( imap_store_t *ctx, struct imap_cmd_cb *cb, const char *fmt, ... ) +static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx, + struct imap_cmd_cb *cb, + const char *fmt, ...) { struct imap_cmd *ret; va_list ap; - va_start( ap, fmt ); - ret = v_issue_imap_cmd( ctx, cb, fmt, ap ); - va_end( ap ); + va_start(ap, fmt); + ret = v_issue_imap_cmd(ctx, cb, fmt, ap); + va_end(ap); return ret; } -static int -imap_exec( imap_store_t *ctx, struct imap_cmd_cb *cb, const char *fmt, ... ) +static int imap_exec(struct imap_store *ctx, struct imap_cmd_cb *cb, + const char *fmt, ...) { va_list ap; struct imap_cmd *cmdp; - va_start( ap, fmt ); - cmdp = v_issue_imap_cmd( ctx, cb, fmt, ap ); - va_end( ap ); + va_start(ap, fmt); + cmdp = v_issue_imap_cmd(ctx, cb, fmt, ap); + va_end(ap); if (!cmdp) return RESP_BAD; - return get_cmd_result( ctx, cmdp ); + return get_cmd_result(ctx, cmdp); } -static int -imap_exec_m( imap_store_t *ctx, struct imap_cmd_cb *cb, const char *fmt, ... ) +static int imap_exec_m(struct imap_store *ctx, struct imap_cmd_cb *cb, + const char *fmt, ...) { va_list ap; struct imap_cmd *cmdp; - va_start( ap, fmt ); - cmdp = v_issue_imap_cmd( ctx, cb, fmt, ap ); - va_end( ap ); + va_start(ap, fmt); + cmdp = v_issue_imap_cmd(ctx, cb, fmt, ap); + va_end(ap); if (!cmdp) return DRV_STORE_BAD; - switch (get_cmd_result( ctx, cmdp )) { + switch (get_cmd_result(ctx, cmdp)) { case RESP_BAD: return DRV_STORE_BAD; case RESP_NO: return DRV_MSG_BAD; default: return DRV_OK; } } -static int -is_atom( list_t *list ) +static int is_atom(struct imap_list *list) { return list && list->val && list->val != NIL && list->val != LIST; } -static int -is_list( list_t *list ) +static int is_list(struct imap_list *list) { return list && list->val == LIST; } -static void -free_list( list_t *list ) +static void free_list(struct imap_list *list) { - list_t *tmp; + struct imap_list *tmp; for (; list; list = tmp) { tmp = list->next; - if (is_list( list )) - free_list( list->child ); - else if (is_atom( list )) - free( list->val ); - free( list ); + if (is_list(list)) + free_list(list->child); + else if (is_atom(list)) + free(list->val); + free(list); } } -static int -parse_imap_list_l( imap_t *imap, char **sp, list_t **curp, int level ) +static int parse_imap_list_l(struct imap *imap, char **sp, struct imap_list **curp, int level) { - list_t *cur; + struct imap_list *cur; char *s = *sp, *p; int n, bytes; for (;;) { - while (isspace( (unsigned char)*s )) + while (isspace((unsigned char)*s)) s++; if (level && *s == ')') { s++; break; } - *curp = cur = xmalloc( sizeof(*cur) ); + *curp = cur = xmalloc(sizeof(*cur)); curp = &cur->next; cur->val = NULL; /* for clean bail */ if (*s == '(') { /* sublist */ s++; cur->val = LIST; - if (parse_imap_list_l( imap, &s, &cur->child, level + 1 )) + if (parse_imap_list_l(imap, &s, &cur->child, level + 1)) goto bail; } else if (imap && *s == '{') { /* literal */ - bytes = cur->len = strtol( s + 1, &s, 10 ); + bytes = cur->len = strtol(s + 1, &s, 10); if (*s != '}') goto bail; - s = cur->val = xmalloc( cur->len ); + s = cur->val = xmalloc(cur->len); /* dump whats left over in the input buffer */ n = imap->buf.bytes - imap->buf.offset; @@ -610,7 +702,7 @@ parse_imap_list_l( imap_t *imap, char **sp, list_t **curp, int level ) /* the entire message fit in the buffer */ n = bytes; - memcpy( s, imap->buf.buf + imap->buf.offset, n ); + memcpy(s, imap->buf.buf + imap->buf.offset, n); s += n; bytes -= n; @@ -619,13 +711,13 @@ parse_imap_list_l( imap_t *imap, char **sp, list_t **curp, int level ) /* now read the rest of the message */ while (bytes > 0) { - if ((n = socket_read (&imap->buf.sock, s, bytes)) <= 0) + if ((n = socket_read(&imap->buf.sock, s, bytes)) <= 0) goto bail; s += n; bytes -= n; } - if (buffer_gets( &imap->buf, &s )) + if (buffer_gets(&imap->buf, &s)) goto bail; } else if (*s == '"') { /* quoted string */ @@ -640,15 +732,14 @@ parse_imap_list_l( imap_t *imap, char **sp, list_t **curp, int level ) } else { /* atom */ p = s; - for (; *s && !isspace( (unsigned char)*s ); s++) + for (; *s && !isspace((unsigned char)*s); s++) if (level && *s == ')') break; cur->len = s - p; - if (cur->len == 3 && !memcmp ("NIL", p, 3)) { + if (cur->len == 3 && !memcmp("NIL", p, 3)) cur->val = NIL; - } else { + else cur->val = xmemdupz(p, cur->len); - } } if (!level) @@ -660,127 +751,122 @@ parse_imap_list_l( imap_t *imap, char **sp, list_t **curp, int level ) *curp = NULL; return 0; - bail: +bail: *curp = NULL; return -1; } -static list_t * -parse_imap_list( imap_t *imap, char **sp ) +static struct imap_list *parse_imap_list(struct imap *imap, char **sp) { - list_t *head; + struct imap_list *head; - if (!parse_imap_list_l( imap, sp, &head, 0 )) + if (!parse_imap_list_l(imap, sp, &head, 0)) return head; - free_list( head ); + free_list(head); return NULL; } -static list_t * -parse_list( char **sp ) +static struct imap_list *parse_list(char **sp) { - return parse_imap_list( NULL, sp ); + return parse_imap_list(NULL, sp); } -static void -parse_capability( imap_t *imap, char *cmd ) +static void parse_capability(struct imap *imap, char *cmd) { char *arg; unsigned i; imap->caps = 0x80000000; - while ((arg = next_arg( &cmd ))) + while ((arg = next_arg(&cmd))) for (i = 0; i < ARRAY_SIZE(cap_list); i++) - if (!strcmp( cap_list[i], arg )) + if (!strcmp(cap_list[i], arg)) imap->caps |= 1 << i; imap->rcaps = imap->caps; } -static int -parse_response_code( imap_store_t *ctx, struct imap_cmd_cb *cb, char *s ) +static int parse_response_code(struct imap_store *ctx, struct imap_cmd_cb *cb, + char *s) { - imap_t *imap = ctx->imap; + struct imap *imap = ctx->imap; char *arg, *p; if (*s != '[') return RESP_OK; /* no response code */ s++; - if (!(p = strchr( s, ']' ))) { - fprintf( stderr, "IMAP error: malformed response code\n" ); + if (!(p = strchr(s, ']'))) { + fprintf(stderr, "IMAP error: malformed response code\n"); return RESP_BAD; } *p++ = 0; - arg = next_arg( &s ); - if (!strcmp( "UIDVALIDITY", arg )) { - if (!(arg = next_arg( &s )) || !(ctx->gen.uidvalidity = atoi( arg ))) { - fprintf( stderr, "IMAP error: malformed UIDVALIDITY status\n" ); + arg = next_arg(&s); + if (!strcmp("UIDVALIDITY", arg)) { + if (!(arg = next_arg(&s)) || !(ctx->gen.uidvalidity = atoi(arg))) { + fprintf(stderr, "IMAP error: malformed UIDVALIDITY status\n"); return RESP_BAD; } - } else if (!strcmp( "UIDNEXT", arg )) { - if (!(arg = next_arg( &s )) || !(imap->uidnext = atoi( arg ))) { - fprintf( stderr, "IMAP error: malformed NEXTUID status\n" ); + } else if (!strcmp("UIDNEXT", arg)) { + if (!(arg = next_arg(&s)) || !(imap->uidnext = atoi(arg))) { + fprintf(stderr, "IMAP error: malformed NEXTUID status\n"); return RESP_BAD; } - } else if (!strcmp( "CAPABILITY", arg )) { - parse_capability( imap, s ); - } else if (!strcmp( "ALERT", arg )) { + } else if (!strcmp("CAPABILITY", arg)) { + parse_capability(imap, s); + } else if (!strcmp("ALERT", arg)) { /* RFC2060 says that these messages MUST be displayed * to the user */ - for (; isspace( (unsigned char)*p ); p++); - fprintf( stderr, "*** IMAP ALERT *** %s\n", p ); - } else if (cb && cb->ctx && !strcmp( "APPENDUID", arg )) { - if (!(arg = next_arg( &s )) || !(ctx->gen.uidvalidity = atoi( arg )) || - !(arg = next_arg( &s )) || !(*(int *)cb->ctx = atoi( arg ))) - { - fprintf( stderr, "IMAP error: malformed APPENDUID status\n" ); + for (; isspace((unsigned char)*p); p++); + fprintf(stderr, "*** IMAP ALERT *** %s\n", p); + } else if (cb && cb->ctx && !strcmp("APPENDUID", arg)) { + if (!(arg = next_arg(&s)) || !(ctx->gen.uidvalidity = atoi(arg)) || + !(arg = next_arg(&s)) || !(*(int *)cb->ctx = atoi(arg))) { + fprintf(stderr, "IMAP error: malformed APPENDUID status\n"); return RESP_BAD; } } return RESP_OK; } -static int -get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) +static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd) { - imap_t *imap = ctx->imap; + struct imap *imap = ctx->imap; struct imap_cmd *cmdp, **pcmdp, *ncmdp; char *cmd, *arg, *arg1, *p; int n, resp, resp2, tag; for (;;) { - if (buffer_gets( &imap->buf, &cmd )) + if (buffer_gets(&imap->buf, &cmd)) return RESP_BAD; - arg = next_arg( &cmd ); + arg = next_arg(&cmd); if (*arg == '*') { - arg = next_arg( &cmd ); + arg = next_arg(&cmd); if (!arg) { - fprintf( stderr, "IMAP error: unable to parse untagged response\n" ); + fprintf(stderr, "IMAP error: unable to parse untagged response\n"); return RESP_BAD; } - if (!strcmp( "NAMESPACE", arg )) { - imap->ns_personal = parse_list( &cmd ); - imap->ns_other = parse_list( &cmd ); - imap->ns_shared = parse_list( &cmd ); - } else if (!strcmp( "OK", arg ) || !strcmp( "BAD", arg ) || - !strcmp( "NO", arg ) || !strcmp( "BYE", arg )) { - if ((resp = parse_response_code( ctx, NULL, cmd )) != RESP_OK) + if (!strcmp("NAMESPACE", arg)) { + imap->ns_personal = parse_list(&cmd); + imap->ns_other = parse_list(&cmd); + imap->ns_shared = parse_list(&cmd); + } else if (!strcmp("OK", arg) || !strcmp("BAD", arg) || + !strcmp("NO", arg) || !strcmp("BYE", arg)) { + if ((resp = parse_response_code(ctx, NULL, cmd)) != RESP_OK) return resp; - } else if (!strcmp( "CAPABILITY", arg )) - parse_capability( imap, cmd ); - else if ((arg1 = next_arg( &cmd ))) { - if (!strcmp( "EXISTS", arg1 )) - ctx->gen.count = atoi( arg ); - else if (!strcmp( "RECENT", arg1 )) - ctx->gen.recent = atoi( arg ); + } else if (!strcmp("CAPABILITY", arg)) + parse_capability(imap, cmd); + else if ((arg1 = next_arg(&cmd))) { + if (!strcmp("EXISTS", arg1)) + ctx->gen.count = atoi(arg); + else if (!strcmp("RECENT", arg1)) + ctx->gen.recent = atoi(arg); } else { - fprintf( stderr, "IMAP error: unable to parse untagged response\n" ); + fprintf(stderr, "IMAP error: unable to parse untagged response\n"); return RESP_BAD; } } else if (!imap->in_progress) { - fprintf( stderr, "IMAP error: unexpected reply: %s %s\n", arg, cmd ? cmd : "" ); + fprintf(stderr, "IMAP error: unexpected reply: %s %s\n", arg, cmd ? cmd : ""); return RESP_BAD; } else if (*arg == '+') { /* This can happen only with the last command underway, as @@ -788,57 +874,57 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) cmdp = (struct imap_cmd *)((char *)imap->in_progress_append - offsetof(struct imap_cmd, next)); if (cmdp->cb.data) { - n = socket_write( &imap->buf.sock, cmdp->cb.data, cmdp->cb.dlen ); - free( cmdp->cb.data ); + n = socket_write(&imap->buf.sock, cmdp->cb.data, cmdp->cb.dlen); + free(cmdp->cb.data); cmdp->cb.data = NULL; if (n != (int)cmdp->cb.dlen) return RESP_BAD; } else if (cmdp->cb.cont) { - if (cmdp->cb.cont( ctx, cmdp, cmd )) + if (cmdp->cb.cont(ctx, cmdp, cmd)) return RESP_BAD; } else { - fprintf( stderr, "IMAP error: unexpected command continuation request\n" ); + fprintf(stderr, "IMAP error: unexpected command continuation request\n"); return RESP_BAD; } - if (socket_write( &imap->buf.sock, "\r\n", 2 ) != 2) + if (socket_write(&imap->buf.sock, "\r\n", 2) != 2) return RESP_BAD; if (!cmdp->cb.cont) imap->literal_pending = 0; if (!tcmd) return DRV_OK; } else { - tag = atoi( arg ); + tag = atoi(arg); for (pcmdp = &imap->in_progress; (cmdp = *pcmdp); pcmdp = &cmdp->next) if (cmdp->tag == tag) goto gottag; - fprintf( stderr, "IMAP error: unexpected tag %s\n", arg ); + fprintf(stderr, "IMAP error: unexpected tag %s\n", arg); return RESP_BAD; - gottag: + gottag: if (!(*pcmdp = cmdp->next)) imap->in_progress_append = pcmdp; imap->num_in_progress--; if (cmdp->cb.cont || cmdp->cb.data) imap->literal_pending = 0; - arg = next_arg( &cmd ); - if (!strcmp( "OK", arg )) + arg = next_arg(&cmd); + if (!strcmp("OK", arg)) resp = DRV_OK; else { - if (!strcmp( "NO", arg )) { - if (cmdp->cb.create && cmd && (cmdp->cb.trycreate || !memcmp( cmd, "[TRYCREATE]", 11 ))) { /* SELECT, APPEND or UID COPY */ - p = strchr( cmdp->cmd, '"' ); - if (!issue_imap_cmd( ctx, NULL, "CREATE \"%.*s\"", strchr( p + 1, '"' ) - p + 1, p )) { + if (!strcmp("NO", arg)) { + if (cmdp->cb.create && cmd && (cmdp->cb.trycreate || !memcmp(cmd, "[TRYCREATE]", 11))) { /* SELECT, APPEND or UID COPY */ + p = strchr(cmdp->cmd, '"'); + if (!issue_imap_cmd(ctx, NULL, "CREATE \"%.*s\"", strchr(p + 1, '"') - p + 1, p)) { resp = RESP_BAD; goto normal; } /* not waiting here violates the spec, but a server that does not grok this nonetheless violates it too. */ cmdp->cb.create = 0; - if (!(ncmdp = issue_imap_cmd( ctx, &cmdp->cb, "%s", cmdp->cmd ))) { + if (!(ncmdp = issue_imap_cmd(ctx, &cmdp->cb, "%s", cmdp->cmd))) { resp = RESP_BAD; goto normal; } - free( cmdp->cmd ); - free( cmdp ); + free(cmdp->cmd); + free(cmdp); if (!tcmd) return 0; /* ignored */ if (cmdp == tcmd) @@ -846,21 +932,21 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) continue; } resp = RESP_NO; - } else /*if (!strcmp( "BAD", arg ))*/ + } else /*if (!strcmp("BAD", arg))*/ resp = RESP_BAD; - fprintf( stderr, "IMAP command '%s' returned response (%s) - %s\n", - memcmp (cmdp->cmd, "LOGIN", 5) ? + fprintf(stderr, "IMAP command '%s' returned response (%s) - %s\n", + memcmp(cmdp->cmd, "LOGIN", 5) ? cmdp->cmd : "LOGIN <user> <pass>", arg, cmd ? cmd : ""); } - if ((resp2 = parse_response_code( ctx, &cmdp->cb, cmd )) > resp) + if ((resp2 = parse_response_code(ctx, &cmdp->cb, cmd)) > resp) resp = resp2; - normal: + normal: if (cmdp->cb.done) - cmdp->cb.done( ctx, cmdp, resp ); - free( cmdp->cb.data ); - free( cmdp->cmd ); - free( cmdp ); + cmdp->cb.done(ctx, cmdp, resp); + free(cmdp->cb.data); + free(cmdp->cmd); + free(cmdp); if (!tcmd || tcmd == cmdp) return resp; } @@ -868,170 +954,184 @@ get_cmd_result( imap_store_t *ctx, struct imap_cmd *tcmd ) /* not reached */ } -static void -imap_close_server( imap_store_t *ictx ) +static void imap_close_server(struct imap_store *ictx) { - imap_t *imap = ictx->imap; + struct imap *imap = ictx->imap; if (imap->buf.sock.fd != -1) { - imap_exec( ictx, NULL, "LOGOUT" ); - close( imap->buf.sock.fd ); + imap_exec(ictx, NULL, "LOGOUT"); + socket_shutdown(&imap->buf.sock); } - free_list( imap->ns_personal ); - free_list( imap->ns_other ); - free_list( imap->ns_shared ); - free( imap ); + free_list(imap->ns_personal); + free_list(imap->ns_other); + free_list(imap->ns_shared); + free(imap); } -static void -imap_close_store( store_t *ctx ) +static void imap_close_store(struct store *ctx) { - imap_close_server( (imap_store_t *)ctx ); - free_generic_messages( ctx->msgs ); - free( ctx ); + imap_close_server((struct imap_store *)ctx); + free_generic_messages(ctx->msgs); + free(ctx); } -static store_t * -imap_open_store( imap_server_conf_t *srvc ) +static struct store *imap_open_store(struct imap_server_conf *srvc) { - imap_store_t *ctx; - imap_t *imap; + struct imap_store *ctx; + struct imap *imap; char *arg, *rsp; struct hostent *he; struct sockaddr_in addr; int s, a[2], preauth; pid_t pid; - ctx = xcalloc( sizeof(*ctx), 1 ); + ctx = xcalloc(sizeof(*ctx), 1); - ctx->imap = imap = xcalloc( sizeof(*imap), 1 ); + ctx->imap = imap = xcalloc(sizeof(*imap), 1); imap->buf.sock.fd = -1; imap->in_progress_append = &imap->in_progress; /* open connection to IMAP server */ if (srvc->tunnel) { - imap_info( "Starting tunnel '%s'... ", srvc->tunnel ); + imap_info("Starting tunnel '%s'... ", srvc->tunnel); - if (socketpair( PF_UNIX, SOCK_STREAM, 0, a )) { - perror( "socketpair" ); - exit( 1 ); + if (socketpair(PF_UNIX, SOCK_STREAM, 0, a)) { + perror("socketpair"); + exit(1); } pid = fork(); if (pid < 0) - _exit( 127 ); + _exit(127); if (!pid) { - if (dup2( a[0], 0 ) == -1 || dup2( a[0], 1 ) == -1) - _exit( 127 ); - close( a[0] ); - close( a[1] ); - execl( "/bin/sh", "sh", "-c", srvc->tunnel, NULL ); - _exit( 127 ); + if (dup2(a[0], 0) == -1 || dup2(a[0], 1) == -1) + _exit(127); + close(a[0]); + close(a[1]); + execl("/bin/sh", "sh", "-c", srvc->tunnel, NULL); + _exit(127); } - close (a[0]); + close(a[0]); imap->buf.sock.fd = a[1]; - imap_info( "ok\n" ); + imap_info("ok\n"); } else { - memset( &addr, 0, sizeof(addr) ); - addr.sin_port = htons( srvc->port ); + memset(&addr, 0, sizeof(addr)); + addr.sin_port = htons(srvc->port); addr.sin_family = AF_INET; - imap_info( "Resolving %s... ", srvc->host ); - he = gethostbyname( srvc->host ); + imap_info("Resolving %s... ", srvc->host); + he = gethostbyname(srvc->host); if (!he) { - perror( "gethostbyname" ); + perror("gethostbyname"); goto bail; } - imap_info( "ok\n" ); + imap_info("ok\n"); addr.sin_addr.s_addr = *((int *) he->h_addr_list[0]); - s = socket( PF_INET, SOCK_STREAM, 0 ); + s = socket(PF_INET, SOCK_STREAM, 0); - imap_info( "Connecting to %s:%hu... ", inet_ntoa( addr.sin_addr ), ntohs( addr.sin_port ) ); - if (connect( s, (struct sockaddr *)&addr, sizeof(addr) )) { - close( s ); - perror( "connect" ); + imap_info("Connecting to %s:%hu... ", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + if (connect(s, (struct sockaddr *)&addr, sizeof(addr))) { + close(s); + perror("connect"); goto bail; } - imap_info( "ok\n" ); imap->buf.sock.fd = s; + if (srvc->use_ssl && + ssl_socket_connect(&imap->buf.sock, 0, srvc->ssl_verify)) { + close(s); + goto bail; + } + imap_info("ok\n"); } /* read the greeting string */ - if (buffer_gets( &imap->buf, &rsp )) { - fprintf( stderr, "IMAP error: no greeting response\n" ); + if (buffer_gets(&imap->buf, &rsp)) { + fprintf(stderr, "IMAP error: no greeting response\n"); goto bail; } - arg = next_arg( &rsp ); - if (!arg || *arg != '*' || (arg = next_arg( &rsp )) == NULL) { - fprintf( stderr, "IMAP error: invalid greeting response\n" ); + arg = next_arg(&rsp); + if (!arg || *arg != '*' || (arg = next_arg(&rsp)) == NULL) { + fprintf(stderr, "IMAP error: invalid greeting response\n"); goto bail; } preauth = 0; - if (!strcmp( "PREAUTH", arg )) + if (!strcmp("PREAUTH", arg)) preauth = 1; - else if (strcmp( "OK", arg ) != 0) { - fprintf( stderr, "IMAP error: unknown greeting response\n" ); + else if (strcmp("OK", arg) != 0) { + fprintf(stderr, "IMAP error: unknown greeting response\n"); goto bail; } - parse_response_code( ctx, NULL, rsp ); - if (!imap->caps && imap_exec( ctx, NULL, "CAPABILITY" ) != RESP_OK) + parse_response_code(ctx, NULL, rsp); + if (!imap->caps && imap_exec(ctx, NULL, "CAPABILITY") != RESP_OK) goto bail; if (!preauth) { - - imap_info ("Logging in...\n"); +#ifndef NO_OPENSSL + if (!srvc->use_ssl && CAP(STARTTLS)) { + if (imap_exec(ctx, 0, "STARTTLS") != RESP_OK) + goto bail; + if (ssl_socket_connect(&imap->buf.sock, 1, + srvc->ssl_verify)) + goto bail; + /* capabilities may have changed, so get the new capabilities */ + if (imap_exec(ctx, 0, "CAPABILITY") != RESP_OK) + goto bail; + } +#endif + imap_info("Logging in...\n"); if (!srvc->user) { - fprintf( stderr, "Skipping server %s, no user\n", srvc->host ); + fprintf(stderr, "Skipping server %s, no user\n", srvc->host); goto bail; } if (!srvc->pass) { char prompt[80]; - sprintf( prompt, "Password (%s@%s): ", srvc->user, srvc->host ); - arg = getpass( prompt ); + sprintf(prompt, "Password (%s@%s): ", srvc->user, srvc->host); + arg = getpass(prompt); if (!arg) { - perror( "getpass" ); - exit( 1 ); + perror("getpass"); + exit(1); } if (!*arg) { - fprintf( stderr, "Skipping account %s@%s, no password\n", srvc->user, srvc->host ); + fprintf(stderr, "Skipping account %s@%s, no password\n", srvc->user, srvc->host); goto bail; } /* * getpass() returns a pointer to a static buffer. make a copy * for long term storage. */ - srvc->pass = xstrdup( arg ); + srvc->pass = xstrdup(arg); } if (CAP(NOLOGIN)) { - fprintf( stderr, "Skipping account %s@%s, server forbids LOGIN\n", srvc->user, srvc->host ); + fprintf(stderr, "Skipping account %s@%s, server forbids LOGIN\n", srvc->user, srvc->host); goto bail; } - imap_warn( "*** IMAP Warning *** Password is being sent in the clear\n" ); - if (imap_exec( ctx, NULL, "LOGIN \"%s\" \"%s\"", srvc->user, srvc->pass ) != RESP_OK) { - fprintf( stderr, "IMAP error: LOGIN failed\n" ); + if (!imap->buf.sock.ssl) + imap_warn("*** IMAP Warning *** Password is being " + "sent in the clear\n"); + if (imap_exec(ctx, NULL, "LOGIN \"%s\" \"%s\"", srvc->user, srvc->pass) != RESP_OK) { + fprintf(stderr, "IMAP error: LOGIN failed\n"); goto bail; } } /* !preauth */ ctx->prefix = ""; ctx->trashnc = 1; - return (store_t *)ctx; + return (struct store *)ctx; - bail: - imap_close_store( &ctx->gen ); +bail: + imap_close_store(&ctx->gen); return NULL; } -static int -imap_make_flags( int flags, char *buf ) +static int imap_make_flags(int flags, char *buf) { const char *s; unsigned i, d; @@ -1050,11 +1150,10 @@ imap_make_flags( int flags, char *buf ) #define TUIDL 8 -static int -imap_store_msg( store_t *gctx, msg_data_t *data, int *uid ) +static int imap_store_msg(struct store *gctx, struct msg_data *data, int *uid) { - imap_store_t *ctx = (imap_store_t *)gctx; - imap_t *imap = ctx->imap; + struct imap_store *ctx = (struct imap_store *)gctx; + struct imap *imap = ctx->imap; struct imap_cmd_cb cb; char *fmap, *buf; const char *prefix, *box; @@ -1062,14 +1161,14 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid ) int start, sbreak = 0, ebreak = 0; char flagstr[128], tuid[TUIDL * 2 + 1]; - memset( &cb, 0, sizeof(cb) ); + memset(&cb, 0, sizeof(cb)); fmap = data->data; len = data->len; nocr = !data->crlf; extra = 0, i = 0; if (!CAP(UIDPLUS) && uid) { - nloop: + nloop: start = i; while (i < len) if (fmap[i++] == '\n') { @@ -1078,18 +1177,18 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid ) sbreak = ebreak = i - 2 + nocr; goto mktid; } - if (!memcmp( fmap + start, "X-TUID: ", 8 )) { + if (!memcmp(fmap + start, "X-TUID: ", 8)) { extra -= (ebreak = i) - (sbreak = start) + nocr; goto mktid; } goto nloop; } /* invalid message */ - free( fmap ); + free(fmap); return DRV_MSG_BAD; - mktid: + mktid: for (j = 0; j < TUIDL; j++) - sprintf( tuid + j * 2, "%02x", arc4_getbyte() ); + sprintf(tuid + j * 2, "%02x", arc4_getbyte()); extra += 8 + TUIDL * 2 + 2; } if (nocr) @@ -1098,7 +1197,7 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid ) extra++; cb.dlen = len + extra; - buf = cb.data = xmalloc( cb.dlen ); + buf = cb.data = xmalloc(cb.dlen); i = 0; if (!CAP(UIDPLUS) && uid) { if (nocr) { @@ -1109,12 +1208,12 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid ) } else *buf++ = fmap[i]; } else { - memcpy( buf, fmap, sbreak ); + memcpy(buf, fmap, sbreak); buf += sbreak; } - memcpy( buf, "X-TUID: ", 8 ); + memcpy(buf, "X-TUID: ", 8); buf += 8; - memcpy( buf, tuid, TUIDL * 2 ); + memcpy(buf, tuid, TUIDL * 2); buf += TUIDL * 2; *buf++ = '\r'; *buf++ = '\n'; @@ -1128,13 +1227,13 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid ) } else *buf++ = fmap[i]; } else - memcpy( buf, fmap + i, len - i ); + memcpy(buf, fmap + i, len - i); - free( fmap ); + free(fmap); d = 0; if (data->flags) { - d = imap_make_flags( data->flags, flagstr ); + d = imap_make_flags(data->flags, flagstr); flagstr[d++] = ' '; } flagstr[d] = 0; @@ -1147,11 +1246,11 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid ) imap->caps = imap->rcaps & ~(1 << LITERALPLUS); } else { box = gctx->name; - prefix = !strcmp( box, "INBOX" ) ? "" : ctx->prefix; + prefix = !strcmp(box, "INBOX") ? "" : ctx->prefix; cb.create = 0; } cb.ctx = uid; - ret = imap_exec_m( ctx, &cb, "APPEND \"%s%s\" %s", prefix, box, flagstr ); + ret = imap_exec_m(ctx, &cb, "APPEND \"%s%s\" %s", prefix, box, flagstr); imap->caps = imap->rcaps; if (ret != DRV_OK) return ret; @@ -1165,8 +1264,7 @@ imap_store_msg( store_t *gctx, msg_data_t *data, int *uid ) #define CHUNKSIZE 0x1000 -static int -read_message( FILE *f, msg_data_t *msg ) +static int read_message(FILE *f, struct msg_data *msg) { struct strbuf buf; @@ -1183,8 +1281,7 @@ read_message( FILE *f, msg_data_t *msg ) return msg->len; } -static int -count_messages( msg_data_t *msg ) +static int count_messages(struct msg_data *msg) { int count = 0; char *p = msg->data; @@ -1194,7 +1291,7 @@ count_messages( msg_data_t *msg ) count++; p += 5; } - p = strstr( p+5, "\nFrom "); + p = strstr(p+5, "\nFrom "); if (!p) break; p++; @@ -1202,22 +1299,21 @@ count_messages( msg_data_t *msg ) return count; } -static int -split_msg( msg_data_t *all_msgs, msg_data_t *msg, int *ofs ) +static int split_msg(struct msg_data *all_msgs, struct msg_data *msg, int *ofs) { char *p, *data; - memset( msg, 0, sizeof *msg ); + memset(msg, 0, sizeof *msg); if (*ofs >= all_msgs->len) return 0; - data = &all_msgs->data[ *ofs ]; + data = &all_msgs->data[*ofs]; msg->len = all_msgs->len - *ofs; if (msg->len < 5 || prefixcmp(data, "From ")) return 0; - p = strchr( data, '\n' ); + p = strchr(data, '\n'); if (p) { p = &p[1]; msg->len -= p-data; @@ -1225,7 +1321,7 @@ split_msg( msg_data_t *all_msgs, msg_data_t *msg, int *ofs ) data = p; } - p = strstr( data, "\nFrom " ); + p = strstr(data, "\nFrom "); if (p) msg->len = &p[1] - data; @@ -1234,24 +1330,24 @@ split_msg( msg_data_t *all_msgs, msg_data_t *msg, int *ofs ) return 1; } -static imap_server_conf_t server = -{ +static struct imap_server_conf server = { NULL, /* name */ NULL, /* tunnel */ NULL, /* host */ 0, /* port */ NULL, /* user */ NULL, /* pass */ + 0, /* use_ssl */ + 1, /* ssl_verify */ }; static char *imap_folder; -static int -git_imap_config(const char *key, const char *val, void *cb) +static int git_imap_config(const char *key, const char *val, void *cb) { char imap_key[] = "imap."; - if (strncmp( key, imap_key, sizeof imap_key - 1 )) + if (strncmp(key, imap_key, sizeof imap_key - 1)) return 0; if (!val) @@ -1259,90 +1355,96 @@ git_imap_config(const char *key, const char *val, void *cb) key += sizeof imap_key - 1; - if (!strcmp( "folder", key )) { - imap_folder = xstrdup( val ); - } else if (!strcmp( "host", key )) { - { - if (!prefixcmp(val, "imap:")) - val += 5; - if (!server.port) - server.port = 143; + if (!strcmp("folder", key)) { + imap_folder = xstrdup(val); + } else if (!strcmp("host", key)) { + if (!prefixcmp(val, "imap:")) + val += 5; + else if (!prefixcmp(val, "imaps:")) { + val += 6; + server.use_ssl = 1; } if (!prefixcmp(val, "//")) val += 2; - server.host = xstrdup( val ); - } - else if (!strcmp( "user", key )) - server.user = xstrdup( val ); - else if (!strcmp( "pass", key )) - server.pass = xstrdup( val ); - else if (!strcmp( "port", key )) - server.port = git_config_int( key, val ); - else if (!strcmp( "tunnel", key )) - server.tunnel = xstrdup( val ); + server.host = xstrdup(val); + } else if (!strcmp("user", key)) + server.user = xstrdup(val); + else if (!strcmp("pass", key)) + server.pass = xstrdup(val); + else if (!strcmp("port", key)) + server.port = git_config_int(key, val); + else if (!strcmp("tunnel", key)) + server.tunnel = xstrdup(val); + else if (!strcmp("sslverify", key)) + server.ssl_verify = git_config_bool(key, val); return 0; } -int -main(int argc, char **argv) +int main(int argc, char **argv) { - msg_data_t all_msgs, msg; - store_t *ctx = NULL; + struct msg_data all_msgs, msg; + struct store *ctx = NULL; int uid = 0; int ofs = 0; int r; int total, n = 0; + int nongit_ok; /* init the random number generator */ arc4_init(); + setup_git_directory_gently(&nongit_ok); git_config(git_imap_config, NULL); + if (!server.port) + server.port = server.use_ssl ? 993 : 143; + if (!imap_folder) { - fprintf( stderr, "no imap store specified\n" ); + fprintf(stderr, "no imap store specified\n"); return 1; } if (!server.host) { if (!server.tunnel) { - fprintf( stderr, "no imap host specified\n" ); + fprintf(stderr, "no imap host specified\n"); return 1; } server.host = "tunnel"; } /* read the messages */ - if (!read_message( stdin, &all_msgs )) { - fprintf(stderr,"nothing to send\n"); + if (!read_message(stdin, &all_msgs)) { + fprintf(stderr, "nothing to send\n"); return 1; } - total = count_messages( &all_msgs ); + total = count_messages(&all_msgs); if (!total) { - fprintf(stderr,"no messages to send\n"); + fprintf(stderr, "no messages to send\n"); return 1; } /* write it to the imap server */ - ctx = imap_open_store( &server ); + ctx = imap_open_store(&server); if (!ctx) { - fprintf( stderr,"failed to open store\n"); + fprintf(stderr, "failed to open store\n"); return 1; } - fprintf( stderr, "sending %d message%s\n", total, (total!=1)?"s":"" ); + fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : ""); ctx->name = imap_folder; while (1) { unsigned percent = n * 100 / total; - fprintf( stderr, "%4u%% (%d/%d) done\r", percent, n, total ); - if (!split_msg( &all_msgs, &msg, &ofs )) + fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total); + if (!split_msg(&all_msgs, &msg, &ofs)) + break; + r = imap_store_msg(ctx, &msg, &uid); + if (r != DRV_OK) break; - r = imap_store_msg( ctx, &msg, &uid ); - if (r != DRV_OK) break; n++; } - fprintf( stderr,"\n" ); + fprintf(stderr, "\n"); - imap_close_store( ctx ); + imap_close_store(ctx); return 0; } diff --git a/index-pack.c b/index-pack.c index 52064befdb..a6e91fe3ba 100644 --- a/index-pack.c +++ b/index-pack.c @@ -654,7 +654,7 @@ static void parse_pack_objects(unsigned char *sha1) } } -static int write_compressed(int fd, void *in, unsigned int size, uint32_t *obj_crc) +static int write_compressed(struct sha1file *f, void *in, unsigned int size) { z_stream stream; unsigned long maxsize; @@ -674,13 +674,12 @@ static int write_compressed(int fd, void *in, unsigned int size, uint32_t *obj_c deflateEnd(&stream); size = stream.total_out; - write_or_die(fd, out, size); - *obj_crc = crc32(*obj_crc, out, size); + sha1write(f, out, size); free(out); return size; } -static struct object_entry *append_obj_to_pack( +static struct object_entry *append_obj_to_pack(struct sha1file *f, const unsigned char *sha1, void *buf, unsigned long size, enum object_type type) { @@ -696,15 +695,15 @@ static struct object_entry *append_obj_to_pack( s >>= 7; } header[n++] = c; - write_or_die(output_fd, header, n); - obj[0].idx.crc32 = crc32(0, Z_NULL, 0); - obj[0].idx.crc32 = crc32(obj[0].idx.crc32, header, n); + crc32_begin(f); + sha1write(f, header, n); obj[0].size = size; obj[0].hdr_size = n; obj[0].type = type; obj[0].real_type = type; obj[1].idx.offset = obj[0].idx.offset + n; - obj[1].idx.offset += write_compressed(output_fd, buf, size, &obj[0].idx.crc32); + obj[1].idx.offset += write_compressed(f, buf, size); + obj[0].idx.crc32 = crc32_end(f); hashcpy(obj->idx.sha1, sha1); return obj; } @@ -716,7 +715,7 @@ static int delta_pos_compare(const void *_a, const void *_b) return a->obj_no - b->obj_no; } -static void fix_unresolved_deltas(int nr_unresolved) +static void fix_unresolved_deltas(struct sha1file *f, int nr_unresolved) { struct delta_entry **sorted_by_pos; int i, n = 0; @@ -754,8 +753,8 @@ static void fix_unresolved_deltas(int nr_unresolved) if (check_sha1_signature(d->base.sha1, base_obj.data, base_obj.size, typename(type))) die("local object %s is corrupt", sha1_to_hex(d->base.sha1)); - base_obj.obj = append_obj_to_pack(d->base.sha1, base_obj.data, - base_obj.size, type); + base_obj.obj = append_obj_to_pack(f, d->base.sha1, + base_obj.data, base_obj.size, type); link_base_data(NULL, &base_obj); find_delta_children(&d->base, &first, &last); @@ -875,8 +874,10 @@ int main(int argc, char **argv) const char *keep_name = NULL, *keep_msg = NULL; char *index_name_buf = NULL, *keep_name_buf = NULL; struct pack_idx_entry **idx_objects; - unsigned char sha1[20]; + unsigned char pack_sha1[20]; + int nongit = 0; + setup_git_directory_gently(&nongit); git_config(git_index_pack_config, NULL); for (i = 1; i < argc; i++) { @@ -960,13 +961,15 @@ int main(int argc, char **argv) parse_pack_header(); objects = xmalloc((nr_objects + 1) * sizeof(struct object_entry)); deltas = xmalloc(nr_objects * sizeof(struct delta_entry)); - parse_pack_objects(sha1); + parse_pack_objects(pack_sha1); if (nr_deltas == nr_resolved_deltas) { stop_progress(&progress); /* Flush remaining pack final 20-byte SHA1. */ flush(); } else { if (fix_thin_pack) { + struct sha1file *f; + unsigned char read_sha1[20], tail_sha1[20]; char msg[48]; int nr_unresolved = nr_deltas - nr_resolved_deltas; int nr_objects_initial = nr_objects; @@ -975,12 +978,19 @@ int main(int argc, char **argv) objects = xrealloc(objects, (nr_objects + nr_unresolved + 1) * sizeof(*objects)); - fix_unresolved_deltas(nr_unresolved); + f = sha1fd(output_fd, curr_pack); + fix_unresolved_deltas(f, nr_unresolved); sprintf(msg, "completed with %d local objects", nr_objects - nr_objects_initial); stop_progress_msg(&progress, msg); - fixup_pack_header_footer(output_fd, sha1, - curr_pack, nr_objects); + sha1close(f, tail_sha1, 0); + hashcpy(read_sha1, pack_sha1); + fixup_pack_header_footer(output_fd, pack_sha1, + curr_pack, nr_objects, + read_sha1, consumed_bytes-20); + if (hashcmp(read_sha1, tail_sha1) != 0) + die("Unexpected tail checksum for %s " + "(disk corruption?)", curr_pack); } if (nr_deltas != nr_resolved_deltas) die("pack has %d unresolved deltas", @@ -993,13 +1003,13 @@ int main(int argc, char **argv) idx_objects = xmalloc((nr_objects) * sizeof(struct pack_idx_entry *)); for (i = 0; i < nr_objects; i++) idx_objects[i] = &objects[i].idx; - curr_index = write_idx_file(index_name, idx_objects, nr_objects, sha1); + curr_index = write_idx_file(index_name, idx_objects, nr_objects, pack_sha1); free(idx_objects); final(pack_name, curr_pack, index_name, curr_index, keep_name, keep_msg, - sha1); + pack_sha1); free(objects); free(index_name_buf); free(keep_name_buf); diff --git a/levenshtein.c b/levenshtein.c new file mode 100644 index 0000000000..db52f2c205 --- /dev/null +++ b/levenshtein.c @@ -0,0 +1,47 @@ +#include "cache.h" +#include "levenshtein.h" + +int levenshtein(const char *string1, const char *string2, + int w, int s, int a, int d) +{ + int len1 = strlen(string1), len2 = strlen(string2); + int *row0 = xmalloc(sizeof(int) * (len2 + 1)); + int *row1 = xmalloc(sizeof(int) * (len2 + 1)); + int *row2 = xmalloc(sizeof(int) * (len2 + 1)); + int i, j; + + for (j = 0; j <= len2; j++) + row1[j] = j * a; + for (i = 0; i < len1; i++) { + int *dummy; + + row2[0] = (i + 1) * d; + for (j = 0; j < len2; j++) { + /* substitution */ + row2[j + 1] = row1[j] + s * (string1[i] != string2[j]); + /* swap */ + if (i > 0 && j > 0 && string1[i - 1] == string2[j] && + string1[i] == string2[j - 1] && + row2[j + 1] > row0[j - 1] + w) + row2[j + 1] = row0[j - 1] + w; + /* deletion */ + if (j + 1 < len2 && row2[j + 1] > row1[j + 1] + d) + row2[j + 1] = row1[j + 1] + d; + /* insertion */ + if (row2[j + 1] > row2[j] + a) + row2[j + 1] = row2[j] + a; + } + + dummy = row0; + row0 = row1; + row1 = row2; + row2 = dummy; + } + + i = row1[len2]; + free(row0); + free(row1); + free(row2); + + return i; +} diff --git a/levenshtein.h b/levenshtein.h new file mode 100644 index 0000000000..0173abeef5 --- /dev/null +++ b/levenshtein.h @@ -0,0 +1,8 @@ +#ifndef LEVENSHTEIN_H +#define LEVENSHTEIN_H + +int levenshtein(const char *string1, const char *string2, + int swap_penalty, int substition_penalty, + int insertion_penalty, int deletion_penalty); + +#endif diff --git a/log-tree.c b/log-tree.c index bd8b9e45ab..30cd5bb228 100644 --- a/log-tree.c +++ b/log-tree.c @@ -432,7 +432,7 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log struct commit_list *parents; unsigned const char *sha1 = commit->object.sha1; - if (!opt->diff) + if (!opt->diff && !DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS)) return 0; /* Root commit? */ diff --git a/merge-index.c b/merge-index.c index 7491c56ad2..7827e87a92 100644 --- a/merge-index.c +++ b/merge-index.c @@ -27,7 +27,7 @@ static int merge_entry(int pos, const char *path) int found; if (pos >= active_nr) - die("git-merge-index: %s not in the cache", path); + die("git merge-index: %s not in the cache", path); arguments[0] = pgm; arguments[1] = ""; arguments[2] = ""; @@ -53,7 +53,7 @@ static int merge_entry(int pos, const char *path) arguments[stage + 4] = ownbuf[stage]; } while (++pos < active_nr); if (!found) - die("git-merge-index: %s not in the cache", path); + die("git merge-index: %s not in the cache", path); run_program(); return found; } @@ -117,7 +117,7 @@ int main(int argc, char **argv) merge_all(); continue; } - die("git-merge-index: unknown option %s", arg); + die("git merge-index: unknown option %s", arg); } merge_file(arg); } @@ -41,7 +41,18 @@ extern int type_from_string(const char *str); extern unsigned int get_max_object_index(void); extern struct object *get_indexed_object(unsigned int); -/** Internal only **/ +/* + * This can be used to see if we have heard of the object before, but + * it can return "yes we have, and here is a half-initialised object" + * for an object that we haven't loaded/parsed yet. + * + * When parsing a commit to create an in-core commit object, its + * parents list holds commit objects that represent its parents, but + * they are expected to be lazily initialized and do not know what + * their trees or parents are yet. When this function returns such a + * half-initialised objects, the caller is expected to initialize them + * by calling parse_object() on them. + */ struct object *lookup_object(const unsigned char *sha1); extern void *create_object(const unsigned char *sha1, int type, void *obj); diff --git a/pack-revindex.c b/pack-revindex.c index cd300bdff5..6096b6224a 100644 --- a/pack-revindex.c +++ b/pack-revindex.c @@ -142,3 +142,15 @@ struct revindex_entry *find_pack_revindex(struct packed_git *p, off_t ofs) } while (lo < hi); die("internal error: pack revindex corrupt"); } + +void discard_revindex(void) +{ + if (pack_revindex_hashsz) { + int i; + for (i = 0; i < pack_revindex_hashsz; i++) + if (pack_revindex[i].revindex) + free(pack_revindex[i].revindex); + free(pack_revindex); + pack_revindex_hashsz = 0; + } +} diff --git a/pack-revindex.h b/pack-revindex.h index 36a514a6cf..8d5027ad91 100644 --- a/pack-revindex.h +++ b/pack-revindex.h @@ -7,5 +7,6 @@ struct revindex_entry { }; struct revindex_entry *find_pack_revindex(struct packed_git *p, off_t ofs); +void discard_revindex(void); #endif diff --git a/pack-write.c b/pack-write.c index a8f0269936..939ed56362 100644 --- a/pack-write.c +++ b/pack-write.c @@ -144,41 +144,94 @@ char *write_idx_file(char *index_name, struct pack_idx_entry **objects, return index_name; } +/* + * Update pack header with object_count and compute new SHA1 for pack data + * associated to pack_fd, and write that SHA1 at the end. That new SHA1 + * is also returned in new_pack_sha1. + * + * If partial_pack_sha1 is non null, then the SHA1 of the existing pack + * (without the header update) is computed and validated against the + * one provided in partial_pack_sha1. The validation is performed at + * partial_pack_offset bytes in the pack file. The SHA1 of the remaining + * data (i.e. from partial_pack_offset to the end) is then computed and + * returned in partial_pack_sha1. + * + * Note that new_pack_sha1 is updated last, so both new_pack_sha1 and + * partial_pack_sha1 can refer to the same buffer if the caller is not + * interested in the resulting SHA1 of pack data above partial_pack_offset. + */ void fixup_pack_header_footer(int pack_fd, - unsigned char *pack_file_sha1, + unsigned char *new_pack_sha1, const char *pack_name, - uint32_t object_count) + uint32_t object_count, + unsigned char *partial_pack_sha1, + off_t partial_pack_offset) { - static const int buf_sz = 128 * 1024; - SHA_CTX c; + int aligned_sz, buf_sz = 8 * 1024; + SHA_CTX old_sha1_ctx, new_sha1_ctx; struct pack_header hdr; char *buf; + SHA1_Init(&old_sha1_ctx); + SHA1_Init(&new_sha1_ctx); + if (lseek(pack_fd, 0, SEEK_SET) != 0) - die("Failed seeking to start: %s", strerror(errno)); + die("Failed seeking to start of %s: %s", pack_name, strerror(errno)); if (read_in_full(pack_fd, &hdr, sizeof(hdr)) != sizeof(hdr)) die("Unable to reread header of %s: %s", pack_name, strerror(errno)); if (lseek(pack_fd, 0, SEEK_SET) != 0) - die("Failed seeking to start: %s", strerror(errno)); + die("Failed seeking to start of %s: %s", pack_name, strerror(errno)); + SHA1_Update(&old_sha1_ctx, &hdr, sizeof(hdr)); hdr.hdr_entries = htonl(object_count); + SHA1_Update(&new_sha1_ctx, &hdr, sizeof(hdr)); write_or_die(pack_fd, &hdr, sizeof(hdr)); - - SHA1_Init(&c); - SHA1_Update(&c, &hdr, sizeof(hdr)); + partial_pack_offset -= sizeof(hdr); buf = xmalloc(buf_sz); + aligned_sz = buf_sz - sizeof(hdr); for (;;) { - ssize_t n = xread(pack_fd, buf, buf_sz); + ssize_t m, n; + m = (partial_pack_sha1 && partial_pack_offset < aligned_sz) ? + partial_pack_offset : aligned_sz; + n = xread(pack_fd, buf, m); if (!n) break; if (n < 0) die("Failed to checksum %s: %s", pack_name, strerror(errno)); - SHA1_Update(&c, buf, n); + SHA1_Update(&new_sha1_ctx, buf, n); + + aligned_sz -= n; + if (!aligned_sz) + aligned_sz = buf_sz; + + if (!partial_pack_sha1) + continue; + + SHA1_Update(&old_sha1_ctx, buf, n); + partial_pack_offset -= n; + if (partial_pack_offset == 0) { + unsigned char sha1[20]; + SHA1_Final(sha1, &old_sha1_ctx); + if (hashcmp(sha1, partial_pack_sha1) != 0) + die("Unexpected checksum for %s " + "(disk corruption?)", pack_name); + /* + * Now let's compute the SHA1 of the remainder of the + * pack, which also means making partial_pack_offset + * big enough not to matter anymore. + */ + SHA1_Init(&old_sha1_ctx); + partial_pack_offset = ~partial_pack_offset; + partial_pack_offset -= MSB(partial_pack_offset, 1); + } } free(buf); - SHA1_Final(pack_file_sha1, &c); - write_or_die(pack_fd, pack_file_sha1, 20); + if (partial_pack_sha1) + SHA1_Final(partial_pack_sha1, &old_sha1_ctx); + SHA1_Final(new_pack_sha1, &new_sha1_ctx); + write_or_die(pack_fd, new_pack_sha1, 20); + fsync_or_die(pack_fd, pack_name); } char *index_pack_lockfile(int ip_out) @@ -58,7 +58,7 @@ struct pack_idx_entry { extern char *write_idx_file(char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1); extern int check_pack_crc(struct packed_git *p, struct pack_window **w_curs, off_t offset, off_t len, unsigned int nr); extern int verify_pack(struct packed_git *); -extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t); +extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t, unsigned char *, off_t); extern char *index_pack_lockfile(int fd); #define PH_ERROR_EOF (-1) @@ -1,4 +1,5 @@ #include "cache.h" +#include "run-command.h" /* * This is split up from the rest of git so that we can do @@ -8,7 +9,7 @@ static int spawned_pager; #ifndef __MINGW32__ -static void run_pager(const char *pager) +static void pager_preexec(void) { /* * Work around bug in "less" by not starting it until we @@ -20,17 +21,13 @@ static void run_pager(const char *pager) FD_SET(0, &in); select(1, &in, NULL, &in, NULL); - execlp(pager, pager, NULL); - execl("/bin/sh", "sh", "-c", pager, NULL); + setenv("LESS", "FRSX", 0); } -#else -#include "run-command.h" +#endif static const char *pager_argv[] = { "sh", "-c", NULL, NULL }; -static struct child_process pager_process = { - .argv = pager_argv, - .in = -1 -}; +static struct child_process pager_process; + static void wait_for_pager(void) { fflush(stdout); @@ -40,14 +37,9 @@ static void wait_for_pager(void) close(2); finish_command(&pager_process); } -#endif void setup_pager(void) { -#ifndef __MINGW32__ - pid_t pid; - int fd[2]; -#endif const char *pager = getenv("GIT_PAGER"); if (!isatty(1)) @@ -66,37 +58,13 @@ void setup_pager(void) spawned_pager = 1; /* means we are emitting to terminal */ -#ifndef __MINGW32__ - if (pipe(fd) < 0) - return; - pid = fork(); - if (pid < 0) { - close(fd[0]); - close(fd[1]); - return; - } - - /* return in the child */ - if (!pid) { - dup2(fd[1], 1); - dup2(fd[1], 2); - close(fd[0]); - close(fd[1]); - return; - } - - /* The original process turns into the PAGER */ - dup2(fd[0], 0); - close(fd[0]); - close(fd[1]); - - setenv("LESS", "FRSX", 0); - run_pager(pager); - die("unable to execute pager '%s'", pager); - exit(255); -#else /* spawn the pager */ pager_argv[2] = pager; + pager_process.argv = pager_argv; + pager_process.in = -1; +#ifndef __MINGW32__ + pager_process.preexec_cb = pager_preexec; +#endif if (start_command(&pager_process)) return; @@ -107,7 +75,6 @@ void setup_pager(void) /* this makes sure that the parent terminates after the pager */ atexit(wait_for_pager); -#endif } int pager_in_use(void) diff --git a/perl/Git.pm b/perl/Git.pm index 102e6a4ce3..6aab712e6a 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -58,7 +58,7 @@ require Exporter; command_bidi_pipe command_close_bidi_pipe version exec_path hash_object git_cmd_try remote_refs - temp_acquire temp_release temp_reset); + temp_acquire temp_release temp_reset temp_path); =head1 DESCRIPTION @@ -937,7 +937,7 @@ sub _close_cat_blob { { # %TEMP_* Lexical Context -my (%TEMP_LOCKS, %TEMP_FILES); +my (%TEMP_FILEMAP, %TEMP_FILES); =item temp_acquire ( NAME ) @@ -965,7 +965,7 @@ sub temp_acquire { my $temp_fd = _temp_cache($name); - $TEMP_LOCKS{$temp_fd} = 1; + $TEMP_FILES{$temp_fd}{locked} = 1; $temp_fd; } @@ -991,16 +991,16 @@ the same string. sub temp_release { my ($self, $temp_fd, $trunc) = _maybe_self(@_); - if (ref($temp_fd) ne 'File::Temp') { + if (exists $TEMP_FILEMAP{$temp_fd}) { $temp_fd = $TEMP_FILES{$temp_fd}; } - unless ($TEMP_LOCKS{$temp_fd}) { + unless ($TEMP_FILES{$temp_fd}{locked}) { carp "Attempt to release temp file '", $temp_fd, "' that has not been locked"; } temp_reset($temp_fd) if $trunc and $temp_fd->opened; - $TEMP_LOCKS{$temp_fd} = 0; + $TEMP_FILES{$temp_fd}{locked} = 0; undef; } @@ -1009,9 +1009,9 @@ sub _temp_cache { _verify_require(); - my $temp_fd = \$TEMP_FILES{$name}; + my $temp_fd = \$TEMP_FILEMAP{$name}; if (defined $$temp_fd and $$temp_fd->opened) { - if ($TEMP_LOCKS{$$temp_fd}) { + if ($TEMP_FILES{$$temp_fd}{locked}) { throw Error::Simple("Temp file with moniker '", $name, "' already in use"); } @@ -1021,12 +1021,13 @@ sub _temp_cache { carp "Temp file '", $name, "' was closed. Opening replacement."; } - $$temp_fd = File::Temp->new( - TEMPLATE => 'Git_XXXXXX', - DIR => File::Spec->tmpdir + my $fname; + ($$temp_fd, $fname) = File::Temp->tempfile( + 'Git_XXXXXX', UNLINK => 1 ) or throw Error::Simple("couldn't open new temp file"); $$temp_fd->autoflush; binmode $$temp_fd; + $TEMP_FILES{$$temp_fd}{fname} = $fname; } $$temp_fd; } @@ -1053,8 +1054,25 @@ sub temp_reset { or throw Error::Simple("expected file position to be reset"); } +=item temp_path ( NAME ) + +=item temp_path ( FILEHANDLE ) + +Returns the filename associated with the given tempfile. + +=cut + +sub temp_path { + my ($self, $temp_fd) = _maybe_self(@_); + + if (exists $TEMP_FILEMAP{$temp_fd}) { + $temp_fd = $TEMP_FILEMAP{$temp_fd}; + } + $TEMP_FILES{$temp_fd}{fname}; +} + sub END { - unlink values %TEMP_FILES if %TEMP_FILES; + unlink values %TEMP_FILEMAP if %TEMP_FILEMAP; } } # %TEMP_* Lexical Context @@ -310,7 +310,7 @@ static int mailmap_name(struct strbuf *sb, const char *email) } static size_t format_person_part(struct strbuf *sb, char part, - const char *msg, int len) + const char *msg, int len, enum date_mode dmode) { /* currently all placeholders have same length */ const int placeholder_len = 2; @@ -377,7 +377,7 @@ static size_t format_person_part(struct strbuf *sb, char part, switch (part) { case 'd': /* date */ - strbuf_addstr(sb, show_date(date, tz, DATE_NORMAL)); + strbuf_addstr(sb, show_date(date, tz, dmode)); return placeholder_len; case 'D': /* date, RFC2822 style */ strbuf_addstr(sb, show_date(date, tz, DATE_RFC2822)); @@ -409,6 +409,7 @@ struct chunk { struct format_commit_context { const struct commit *commit; + enum date_mode dmode; /* These offsets are relative to the start of the commit message. */ int commit_header_parsed; @@ -584,10 +585,12 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder, return 1; case 'a': /* author ... */ return format_person_part(sb, placeholder[1], - msg + c->author.off, c->author.len); + msg + c->author.off, c->author.len, + c->dmode); case 'c': /* committer ... */ return format_person_part(sb, placeholder[1], - msg + c->committer.off, c->committer.len); + msg + c->committer.off, c->committer.len, + c->dmode); case 'e': /* encoding */ strbuf_add(sb, msg + c->encoding.off, c->encoding.len); return 1; @@ -599,12 +602,14 @@ static size_t format_commit_item(struct strbuf *sb, const char *placeholder, } void format_commit_message(const struct commit *commit, - const void *format, struct strbuf *sb) + const void *format, struct strbuf *sb, + enum date_mode dmode) { struct format_commit_context context; memset(&context, 0, sizeof(context)); context.commit = commit; + context.dmode = dmode; strbuf_expand(sb, format, format_commit_item, &context); } @@ -770,7 +775,7 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit, const char *encoding; if (fmt == CMIT_FMT_USERFORMAT) { - format_commit_message(commit, user_format, sb); + format_commit_message(commit, user_format, sb, dmode); return; } diff --git a/read-cache.c b/read-cache.c index 6c57095f73..5b1b3ad03b 100644 --- a/read-cache.c +++ b/read-cache.c @@ -8,6 +8,11 @@ #include "cache-tree.h" #include "refs.h" #include "dir.h" +#include "tree.h" +#include "commit.h" +#include "diff.h" +#include "diffcore.h" +#include "revision.h" /* Index extensions. * @@ -1118,6 +1123,10 @@ static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_en ce->ce_size = ntohl(ondisk->size); /* On-disk flags are just 16 bits */ ce->ce_flags = ntohs(ondisk->flags); + + /* For future extension: we do not understand this entry yet */ + if (ce->ce_flags & CE_EXTENDED) + die("Unknown index entry format"); hashcpy(ce->sha1, ondisk->sha1); len = ce->ce_flags & CE_NAMEMASK; @@ -1155,7 +1164,7 @@ int read_index_from(struct index_state *istate, const char *path) size_t mmap_size; errno = EBUSY; - if (istate->alloc) + if (istate->initialized) return istate->cache_nr; errno = ENOENT; @@ -1195,6 +1204,7 @@ int read_index_from(struct index_state *istate, const char *path) * index size */ istate->alloc = xmalloc(estimate_cache_size(mmap_size, istate->cache_nr)); + istate->initialized = 1; src_offset = sizeof(*hdr); dst_offset = 0; @@ -1248,6 +1258,7 @@ int discard_index(struct index_state *istate) cache_tree_free(&(istate->cache_tree)); free(istate->alloc); istate->alloc = NULL; + istate->initialized = 0; /* no need to throw away allocated active_cache */ return 0; @@ -1478,3 +1489,59 @@ int read_index_unmerged(struct index_state *istate) istate->cache_nr = dst - istate->cache; return !!last; } + +struct update_callback_data +{ + int flags; + int add_errors; +}; + +static void update_callback(struct diff_queue_struct *q, + struct diff_options *opt, void *cbdata) +{ + int i; + struct update_callback_data *data = cbdata; + + for (i = 0; i < q->nr; i++) { + struct diff_filepair *p = q->queue[i]; + const char *path = p->one->path; + switch (p->status) { + default: + die("unexpected diff status %c", p->status); + case DIFF_STATUS_UNMERGED: + case DIFF_STATUS_MODIFIED: + case DIFF_STATUS_TYPE_CHANGED: + if (add_file_to_index(&the_index, path, data->flags)) { + if (!(data->flags & ADD_CACHE_IGNORE_ERRORS)) + die("updating files failed"); + data->add_errors++; + } + break; + case DIFF_STATUS_DELETED: + if (data->flags & ADD_CACHE_IGNORE_REMOVAL) + break; + if (!(data->flags & ADD_CACHE_PRETEND)) + remove_file_from_index(&the_index, path); + if (data->flags & (ADD_CACHE_PRETEND|ADD_CACHE_VERBOSE)) + printf("remove '%s'\n", path); + break; + } + } +} + +int add_files_to_cache(const char *prefix, const char **pathspec, int flags) +{ + struct update_callback_data data; + struct rev_info rev; + init_revisions(&rev, prefix); + setup_revisions(0, NULL, &rev, NULL); + rev.prune_data = pathspec; + rev.diffopt.output_format = DIFF_FORMAT_CALLBACK; + rev.diffopt.format_callback = update_callback; + data.flags = flags; + data.add_errors = 0; + rev.diffopt.format_callback_data = &data; + run_diff_files(&rev, DIFF_RACY_IS_MODIFIED); + return !!data.add_errors; +} + diff --git a/receive-pack.c b/receive-pack.c index d44c19e6b5..b81678a970 100644 --- a/receive-pack.c +++ b/receive-pack.c @@ -407,7 +407,7 @@ static const char *unpack(void) char keep_arg[256]; struct child_process ip; - s = sprintf(keep_arg, "--keep=receive-pack %i on ", getpid()); + s = sprintf(keep_arg, "--keep=receive-pack %"PRIuMAX" on ", (uintmax_t) getpid()); if (gethostname(keep_arg + s, sizeof(keep_arg) - s)) strcpy(keep_arg + s, "localhost"); @@ -390,6 +390,18 @@ int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *re return retval; } +/* + * If the "reading" argument is set, this function finds out what _object_ + * the ref points at by "reading" the ref. The ref, if it is not symbolic, + * has to exist, and if it is symbolic, it has to point at an existing ref, + * because the "read" goes through the symref to the ref it points at. + * + * The access that is not "reading" may often be "writing", but does not + * have to; it can be merely checking _where it leads to_. If it is a + * prelude to "writing" to the ref, a write to a symref that points at + * yet-to-be-born ref will create the real ref pointed by the symref. + * reading=0 allows the caller to check where such a symref leads to. + */ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag) { int depth = MAXDEPTH; @@ -409,13 +421,7 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int * if (--depth < 0) return NULL; - /* Special case: non-existing file. - * Not having the refs/heads/new-branch is OK - * if we are writing into it, so is .git/HEAD - * that points at refs/heads/master still to be - * born. It is NOT OK if we are resolving for - * reading. - */ + /* Special case: non-existing file. */ if (lstat(path, &st) < 0) { struct ref_list *list = get_packed_refs(); while (list) { @@ -69,7 +69,7 @@ static const char *alias_url(const char *url) if (!longest) return url; - ret = malloc(rewrite[longest_i]->baselen + + ret = xmalloc(rewrite[longest_i]->baselen + (strlen(url) - longest->len) + 1); strcpy(ret, rewrite[longest_i]->base); strcpy(ret + rewrite[longest_i]->baselen, url + longest->len); @@ -152,7 +152,7 @@ static struct branch *make_branch(const char *name, int len) ret->name = xstrndup(name, len); else ret->name = xstrdup(name); - refname = malloc(strlen(name) + strlen("refs/heads/") + 1); + refname = xmalloc(strlen(name) + strlen("refs/heads/") + 1); strcpy(refname, "refs/heads/"); strcpy(refname + strlen("refs/heads/"), ret->name); ret->refname = refname; @@ -449,6 +449,26 @@ static int verify_refname(char *name, int is_glob) return result; } +/* + * This function frees a refspec array. + * Warning: code paths should be checked to ensure that the src + * and dst pointers are always freeable pointers as well + * as the refspec pointer itself. + */ +void free_refspecs(struct refspec *refspec, int nr_refspec) +{ + int i; + + if (!refspec) + return; + + for (i = 0; i < nr_refspec; i++) { + free(refspec[i].src); + free(refspec[i].dst); + } + free(refspec); +} + static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify) { int i; @@ -567,7 +587,12 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp invalid: if (verify) { - free(rs); + /* + * nr_refspec must be greater than zero and i must be valid + * since it is only possible to reach this point from within + * the for loop above. + */ + free_refspecs(rs, i+1); return NULL; } die("Invalid refspec '%s'", refspec[i]); @@ -579,7 +604,7 @@ int valid_fetch_refspec(const char *fetch_refspec_str) struct refspec *refspec; refspec = parse_refspec_internal(1, fetch_refspec, 1, 1); - free(refspec); + free_refspecs(refspec, 1); return !!refspec; } @@ -78,6 +78,7 @@ void ref_remove_duplicates(struct ref *ref_map); int valid_fetch_refspec(const char *refspec); struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec); struct refspec *parse_push_refspec(int nr_refspec, const char **refspec); +void free_refspecs(struct refspec *refspec, int nr_refspec); int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, int nr_refspec, const char **refspec, int all); diff --git a/revision.c b/revision.c index e75079a6e1..499f0e0225 100644 --- a/revision.c +++ b/revision.c @@ -489,7 +489,7 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit, p->object.flags |= SEEN; insert_by_date_cached(p, list, cached_base, cache_ptr); } - if(revs->first_parent_only) + if (revs->first_parent_only) break; } return 0; @@ -782,6 +782,10 @@ void init_revisions(struct rev_info *revs, const char *prefix) revs->commit_format = CMIT_FMT_DEFAULT; + revs->grep_filter.status_only = 1; + revs->grep_filter.pattern_tail = &(revs->grep_filter.pattern_list); + revs->grep_filter.regflags = REG_NEWLINE; + diff_setup(&revs->diffopt); if (prefix && !revs->diffopt.prefix) { revs->diffopt.prefix = prefix; @@ -946,33 +950,12 @@ void read_revisions_from_stdin(struct rev_info *revs) static void add_grep(struct rev_info *revs, const char *ptn, enum grep_pat_token what) { - if (!revs->grep_filter) { - struct grep_opt *opt = xcalloc(1, sizeof(*opt)); - opt->status_only = 1; - opt->pattern_tail = &(opt->pattern_list); - opt->regflags = REG_NEWLINE; - revs->grep_filter = opt; - } - append_grep_pattern(revs->grep_filter, ptn, - "command line", 0, what); + append_grep_pattern(&revs->grep_filter, ptn, "command line", 0, what); } -static void add_header_grep(struct rev_info *revs, const char *field, const char *pattern) +static void add_header_grep(struct rev_info *revs, enum grep_header_field field, const char *pattern) { - char *pat; - const char *prefix; - int patlen, fldlen; - - fldlen = strlen(field); - patlen = strlen(pattern); - pat = xmalloc(patlen + fldlen + 10); - prefix = ".*"; - if (*pattern == '^') { - prefix = ""; - pattern++; - } - sprintf(pat, "^%s %s%s", field, prefix, pattern); - add_grep(revs, pat, GREP_PATTERN_HEAD); + append_header_grep_pattern(&revs->grep_filter, field, pattern); } static void add_message_grep(struct rev_info *revs, const char *pattern) @@ -1045,6 +1028,11 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg } else if (!strcmp(arg, "--topo-order")) { revs->lifo = 1; revs->topo_order = 1; + } else if (!strcmp(arg, "--simplify-merges")) { + revs->simplify_merges = 1; + revs->rewrite_parents = 1; + revs->simplify_history = 0; + revs->limited = 1; } else if (!strcmp(arg, "--date-order")) { revs->lifo = 0; revs->topo_order = 1; @@ -1158,23 +1146,19 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg * Grepping the commit log */ else if (!prefixcmp(arg, "--author=")) { - add_header_grep(revs, "author", arg+9); + add_header_grep(revs, GREP_HEADER_AUTHOR, arg+9); } else if (!prefixcmp(arg, "--committer=")) { - add_header_grep(revs, "committer", arg+12); + add_header_grep(revs, GREP_HEADER_COMMITTER, arg+12); } else if (!prefixcmp(arg, "--grep=")) { add_message_grep(revs, arg+7); } else if (!strcmp(arg, "--extended-regexp") || !strcmp(arg, "-E")) { - if (revs->grep_filter) - revs->grep_filter->regflags |= REG_EXTENDED; + revs->grep_filter.regflags |= REG_EXTENDED; } else if (!strcmp(arg, "--regexp-ignore-case") || !strcmp(arg, "-i")) { - if (revs->grep_filter) - revs->grep_filter->regflags |= REG_ICASE; + revs->grep_filter.regflags |= REG_ICASE; } else if (!strcmp(arg, "--fixed-strings") || !strcmp(arg, "-F")) { - if (revs->grep_filter) - revs->grep_filter->fixed = 1; + revs->grep_filter.fixed = 1; } else if (!strcmp(arg, "--all-match")) { - if (revs->grep_filter) - revs->grep_filter->all_match = 1; + revs->grep_filter.all_match = 1; } else if (!prefixcmp(arg, "--encoding=")) { arg += 11; if (strcmp(arg, "none")) @@ -1349,9 +1333,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch if (diff_setup_done(&revs->diffopt) < 0) die("diff_setup_done failed"); - if (revs->grep_filter) { - compile_grep_patterns(revs->grep_filter); - } + compile_grep_patterns(&revs->grep_filter); if (revs->reverse && revs->reflog_info) die("cannot combine --reverse with --walk-reflogs"); @@ -1378,6 +1360,179 @@ static void add_child(struct rev_info *revs, struct commit *parent, struct commi l->next = add_decoration(&revs->children, &parent->object, l); } +static int remove_duplicate_parents(struct commit *commit) +{ + struct commit_list **pp, *p; + int surviving_parents; + + /* Examine existing parents while marking ones we have seen... */ + pp = &commit->parents; + while ((p = *pp) != NULL) { + struct commit *parent = p->item; + if (parent->object.flags & TMP_MARK) { + *pp = p->next; + continue; + } + parent->object.flags |= TMP_MARK; + pp = &p->next; + } + /* count them while clearing the temporary mark */ + surviving_parents = 0; + for (p = commit->parents; p; p = p->next) { + p->item->object.flags &= ~TMP_MARK; + surviving_parents++; + } + return surviving_parents; +} + +struct merge_simplify_state { + struct commit *simplified; +}; + +static struct merge_simplify_state *locate_simplify_state(struct rev_info *revs, struct commit *commit) +{ + struct merge_simplify_state *st; + + st = lookup_decoration(&revs->merge_simplification, &commit->object); + if (!st) { + st = xcalloc(1, sizeof(*st)); + add_decoration(&revs->merge_simplification, &commit->object, st); + } + return st; +} + +static struct commit_list **simplify_one(struct rev_info *revs, struct commit *commit, struct commit_list **tail) +{ + struct commit_list *p; + struct merge_simplify_state *st, *pst; + int cnt; + + st = locate_simplify_state(revs, commit); + + /* + * Have we handled this one? + */ + if (st->simplified) + return tail; + + /* + * An UNINTERESTING commit simplifies to itself, so does a + * root commit. We do not rewrite parents of such commit + * anyway. + */ + if ((commit->object.flags & UNINTERESTING) || !commit->parents) { + st->simplified = commit; + return tail; + } + + /* + * Do we know what commit all of our parents should be rewritten to? + * Otherwise we are not ready to rewrite this one yet. + */ + for (cnt = 0, p = commit->parents; p; p = p->next) { + pst = locate_simplify_state(revs, p->item); + if (!pst->simplified) { + tail = &commit_list_insert(p->item, tail)->next; + cnt++; + } + } + if (cnt) { + tail = &commit_list_insert(commit, tail)->next; + return tail; + } + + /* + * Rewrite our list of parents. + */ + for (p = commit->parents; p; p = p->next) { + pst = locate_simplify_state(revs, p->item); + p->item = pst->simplified; + } + cnt = remove_duplicate_parents(commit); + + /* + * It is possible that we are a merge and one side branch + * does not have any commit that touches the given paths; + * in such a case, the immediate parents will be rewritten + * to different commits. + * + * o----X X: the commit we are looking at; + * / / o: a commit that touches the paths; + * ---o----' + * + * Further reduce the parents by removing redundant parents. + */ + if (1 < cnt) { + struct commit_list *h = reduce_heads(commit->parents); + cnt = commit_list_count(h); + free_commit_list(commit->parents); + commit->parents = h; + } + + /* + * A commit simplifies to itself if it is a root, if it is + * UNINTERESTING, if it touches the given paths, or if it is a + * merge and its parents simplifies to more than one commits + * (the first two cases are already handled at the beginning of + * this function). + * + * Otherwise, it simplifies to what its sole parent simplifies to. + */ + if (!cnt || + (commit->object.flags & UNINTERESTING) || + !(commit->object.flags & TREESAME) || + (1 < cnt)) + st->simplified = commit; + else { + pst = locate_simplify_state(revs, commit->parents->item); + st->simplified = pst->simplified; + } + return tail; +} + +static void simplify_merges(struct rev_info *revs) +{ + struct commit_list *list; + struct commit_list *yet_to_do, **tail; + + if (!revs->topo_order) + sort_in_topological_order(&revs->commits, revs->lifo); + if (!revs->prune) + return; + + /* feed the list reversed */ + yet_to_do = NULL; + for (list = revs->commits; list; list = list->next) + commit_list_insert(list->item, &yet_to_do); + while (yet_to_do) { + list = yet_to_do; + yet_to_do = NULL; + tail = &yet_to_do; + while (list) { + struct commit *commit = list->item; + struct commit_list *next = list->next; + free(list); + list = next; + tail = simplify_one(revs, commit, tail); + } + } + + /* clean up the result, removing the simplified ones */ + list = revs->commits; + revs->commits = NULL; + tail = &revs->commits; + while (list) { + struct commit *commit = list->item; + struct commit_list *next = list->next; + struct merge_simplify_state *st; + free(list); + list = next; + st = locate_simplify_state(revs, commit); + if (st->simplified == commit) + tail = &commit_list_insert(commit, tail)->next; + } +} + static void set_children(struct rev_info *revs) { struct commit_list *l; @@ -1418,6 +1573,8 @@ int prepare_revision_walk(struct rev_info *revs) return -1; if (revs->topo_order) sort_in_topological_order(&revs->commits, revs->lifo); + if (revs->simplify_merges) + simplify_merges(revs); if (revs->children.name) set_children(revs); return 0; @@ -1450,26 +1607,6 @@ static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp } } -static void remove_duplicate_parents(struct commit *commit) -{ - struct commit_list **pp, *p; - - /* Examine existing parents while marking ones we have seen... */ - pp = &commit->parents; - while ((p = *pp) != NULL) { - struct commit *parent = p->item; - if (parent->object.flags & TMP_MARK) { - *pp = p->next; - continue; - } - parent->object.flags |= TMP_MARK; - pp = &p->next; - } - /* ... and clear the temporary mark */ - for (p = commit->parents; p; p = p->next) - p->item->object.flags &= ~TMP_MARK; -} - static int rewrite_parents(struct rev_info *revs, struct commit *commit) { struct commit_list **pp = &commit->parents; @@ -1492,9 +1629,9 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit) static int commit_match(struct commit *commit, struct rev_info *opt) { - if (!opt->grep_filter) + if (!opt->grep_filter.pattern_list) return 1; - return grep_buffer(opt->grep_filter, + return grep_buffer(&opt->grep_filter, NULL, /* we say nothing, not even filename */ commit->buffer, strlen(commit->buffer)); } diff --git a/revision.h b/revision.h index 1b045669ae..fc23522b38 100644 --- a/revision.h +++ b/revision.h @@ -2,6 +2,7 @@ #define REVISION_H #include "parse-options.h" +#include "grep.h" #define SEEN (1u<<0) #define UNINTERESTING (1u<<1) @@ -41,6 +42,7 @@ struct rev_info { simplify_history:1, lifo:1, topo_order:1, + simplify_merges:1, tag_objects:1, tree_objects:1, blob_objects:1, @@ -92,7 +94,7 @@ struct rev_info { int show_log_size; /* Filter by commit log message */ - struct grep_opt *grep_filter; + struct grep_opt grep_filter; /* Display history graph */ struct git_graph *graph; @@ -109,6 +111,7 @@ struct rev_info { struct reflog_walk_info *reflog_info; struct decoration children; + struct decoration merge_simplification; }; #define REV_TREE_SAME 0 diff --git a/run-command.c b/run-command.c index bbb9c777e5..caab374577 100644 --- a/run-command.c +++ b/run-command.c @@ -111,6 +111,8 @@ int start_command(struct child_process *cmd) unsetenv(*cmd->env); } } + if (cmd->preexec_cb) + cmd->preexec_cb(); if (cmd->git_cmd) { execv_git_cmd(cmd->argv); } else { diff --git a/run-command.h b/run-command.h index 5203a9ebb1..4f2b7d7d40 100644 --- a/run-command.h +++ b/run-command.h @@ -42,6 +42,7 @@ struct child_process { unsigned no_stderr:1; unsigned git_cmd:1; /* if this is to be git sub-command */ unsigned stdout_to_stderr:1; + void (*preexec_cb)(void); }; int start_command(struct child_process *); @@ -581,6 +581,8 @@ const char *setup_git_directory(void) if (retval && chdir(retval)) die ("Could not jump back into original cwd"); rel = get_relative_cwd(buffer, PATH_MAX, get_git_work_tree()); + if (rel && *rel && chdir(get_git_work_tree())) + die ("Could not jump to working directory"); return rel && *rel ? strcat(rel, "/") : NULL; } diff --git a/sha1_file.c b/sha1_file.c index 32e4664b1b..9ee1ed16ad 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -990,6 +990,7 @@ void prepare_packed_git(void) void reprepare_packed_git(void) { + discard_revindex(); prepare_packed_git_run_once = 0; prepare_packed_git(); } @@ -2360,51 +2361,22 @@ int has_sha1_file(const unsigned char *sha1) return has_loose_object(sha1); } -int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object) +static int index_mem(unsigned char *sha1, void *buf, size_t size, + int write_object, enum object_type type, const char *path) { - struct strbuf buf; - int ret; - - strbuf_init(&buf, 0); - if (strbuf_read(&buf, fd, 4096) < 0) { - strbuf_release(&buf); - return -1; - } - - if (!type) - type = blob_type; - if (write_object) - ret = write_sha1_file(buf.buf, buf.len, type, sha1); - else - ret = hash_sha1_file(buf.buf, buf.len, type, sha1); - strbuf_release(&buf); - - return ret; -} - -int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, - enum object_type type, const char *path) -{ - size_t size = xsize_t(st->st_size); - void *buf = NULL; int ret, re_allocated = 0; - if (size) - buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); - close(fd); - if (!type) type = OBJ_BLOB; /* * Convert blobs to git internal format */ - if ((type == OBJ_BLOB) && S_ISREG(st->st_mode)) { + if ((type == OBJ_BLOB) && path) { struct strbuf nbuf; strbuf_init(&nbuf, 0); if (convert_to_git(path, buf, size, &nbuf, write_object ? safe_crlf : 0)) { - munmap(buf, size); buf = strbuf_detach(&nbuf, &size); re_allocated = 1; } @@ -2414,12 +2386,33 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, ret = write_sha1_file(buf, size, typename(type), sha1); else ret = hash_sha1_file(buf, size, typename(type), sha1); - if (re_allocated) { + if (re_allocated) free(buf); - return ret; - } - if (size) + return ret; +} + +int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, + enum object_type type, const char *path) +{ + int ret; + size_t size = xsize_t(st->st_size); + + if (!S_ISREG(st->st_mode)) { + struct strbuf sbuf; + strbuf_init(&sbuf, 0); + if (strbuf_read(&sbuf, fd, 4096) >= 0) + ret = index_mem(sha1, sbuf.buf, sbuf.len, write_object, + type, path); + else + ret = -1; + strbuf_release(&sbuf); + } else if (size) { + void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + ret = index_mem(sha1, buf, size, write_object, type, path); munmap(buf, size); + } else + ret = index_mem(sha1, NULL, size, write_object, type, path); + close(fd); return ret; } diff --git a/sha1_name.c b/sha1_name.c index 4fb77f8863..41b680915d 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -349,7 +349,10 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1) else nth = -1; } - if (0 <= nth) + if (100000000 <= nth) { + at_time = nth; + nth = -1; + } else if (0 <= nth) at_time = 0; else { char *tmp = xstrndup(str + at + 2, reflog_len); @@ -3,14 +3,6 @@ #include "exec_cmd.h" #include "strbuf.h" -/* Stubs for functions that make no sense for git-shell. These stubs - * are provided here to avoid linking in external redundant modules. - */ -void release_pack_memory(size_t need, int fd){} -void trace_argv_printf(const char **argv, const char *fmt, ...){} -void trace_printf(const char *fmt, ...){} - - static int do_generic_cmd(const char *me, char *arg) { const char *my_argv[4]; @@ -56,6 +48,19 @@ int main(int argc, char **argv) { char *prog; struct commands *cmd; + int devnull_fd; + + /* + * Always open file descriptors 0/1/2 to avoid clobbering files + * in die(). It also avoids not messing up when the pipes are + * dup'ed onto stdin/stdout/stderr in the child processes we spawn. + */ + devnull_fd = open("/dev/null", O_RDWR); + while (devnull_fd >= 0 && devnull_fd <= 2) + devnull_fd = dup(devnull_fd); + if (devnull_fd == -1) + die("opening /dev/null failed (%s)", strerror(errno)); + close (devnull_fd); /* * Special hack to pretend to be a CVS server diff --git a/sideband.c b/sideband.c index b6777812cb..cca3360546 100644 --- a/sideband.c +++ b/sideband.c @@ -25,6 +25,7 @@ int recv_sideband(const char *me, int in_stream, int out, int err) unsigned sf; char buf[LARGE_PACKET_MAX + 2*FIX_SIZE]; char *suffix, *term; + int skip_pf = 0; memcpy(buf, PREFIX, pf); term = getenv("TERM"); @@ -54,39 +55,58 @@ int recv_sideband(const char *me, int in_stream, int out, int err) return SIDEBAND_REMOTE_ERROR; case 2: buf[pf] = ' '; - len += pf+1; - while (1) { - int brk = pf+1; + do { + char *b = buf; + int brk = 0; - /* Break the buffer into separate lines. */ - while (brk < len) { + /* + * If the last buffer didn't end with a line + * break then we should not print a prefix + * this time around. + */ + if (skip_pf) { + b += pf+1; + } else { + len += pf+1; + brk += pf+1; + } + + /* Look for a line break. */ + for (;;) { brk++; - if (buf[brk-1] == '\n' || - buf[brk-1] == '\r') + if (brk > len) { + brk = 0; + break; + } + if (b[brk-1] == '\n' || + b[brk-1] == '\r') break; } /* * Let's insert a suffix to clear the end - * of the screen line, but only if current - * line data actually contains something. + * of the screen line if a line break was + * found. Also, if we don't skip the + * prefix, then a non-empty string must be + * present too. */ - if (brk > pf+1 + 1) { + if (brk > (skip_pf ? 0 : (pf+1 + 1))) { char save[FIX_SIZE]; - memcpy(save, buf + brk, sf); - buf[brk + sf - 1] = buf[brk - 1]; - memcpy(buf + brk - 1, suffix, sf); - safe_write(err, buf, brk + sf); - memcpy(buf + brk, save, sf); - } else - safe_write(err, buf, brk); + memcpy(save, b + brk, sf); + b[brk + sf - 1] = b[brk - 1]; + memcpy(b + brk - 1, suffix, sf); + safe_write(err, b, brk + sf); + memcpy(b + brk, save, sf); + len -= brk; + } else { + int l = brk ? brk : len; + safe_write(err, b, l); + len -= l; + } - if (brk < len) { - memmove(buf + pf+1, buf + brk, len - brk); - len = len - brk + pf+1; - } else - break; - } + skip_pf = !brk; + memmove(buf + pf+1, b + brk, len); + } while (len); continue; case 1: safe_write(out, buf + pf+1, len); diff --git a/t/.gitignore b/t/.gitignore index b27e280083..7dcbb232cd 100644 --- a/t/.gitignore +++ b/t/.gitignore @@ -1,2 +1,2 @@ -/trash directory +/trash directory* /test-results diff --git a/t/Makefile b/t/Makefile index 0d65cedaa6..ed49c20b16 100644 --- a/t/Makefile +++ b/t/Makefile @@ -14,7 +14,8 @@ SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh) TSVN = $(wildcard t91[0-9][0-9]-*.sh) -all: pre-clean $(T) aggregate-results clean +all: pre-clean + $(MAKE) aggregate-results-and-cleanup $(T): @echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS) @@ -25,6 +26,10 @@ pre-clean: clean: $(RM) -r 'trash directory' test-results +aggregate-results-and-cleanup: $(T) + $(MAKE) aggregate-results + $(MAKE) clean + aggregate-results: '$(SHELL_PATH_SQ)' ./aggregate-results.sh test-results/t*-* @@ -34,4 +39,3 @@ full-svn-test: $(MAKE) $(TSVN) GIT_SVN_NO_OPTIMIZE_COMMITS=0 LC_ALL=en_US.UTF-8 .PHONY: pre-clean $(T) aggregate-results clean -.NOTPARALLEL: diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh index a841df2a9e..c526eedd62 100644 --- a/t/lib-git-svn.sh +++ b/t/lib-git-svn.sh @@ -1,8 +1,11 @@ . ./test-lib.sh +remotes_git_svn=remotes/git""-svn +git_svn_id=git""-svn-id + if test -n "$NO_SVN_TESTS" then - test_expect_success 'skipping git-svn tests, NO_SVN_TESTS defined' : + test_expect_success 'skipping git svn tests, NO_SVN_TESTS defined' : test_done exit fi @@ -14,7 +17,7 @@ SVN_TREE=$GIT_SVN_DIR/svn-tree svn >/dev/null 2>&1 if test $? -ne 1 then - test_expect_success 'skipping git-svn tests, svn not found' : + test_expect_success 'skipping git svn tests, svn not found' : test_done exit fi @@ -88,7 +91,7 @@ start_httpd () { mkdir "$GIT_DIR"/logs cat > "$GIT_DIR/httpd.conf" <<EOF -ServerName "git-svn test" +ServerName "git svn test" ServerRoot "$GIT_DIR" DocumentRoot "$GIT_DIR" PidFile "$GIT_DIR/httpd.pid" diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh index dc473dfb53..6ac312b905 100644 --- a/t/lib-httpd.sh +++ b/t/lib-httpd.sh @@ -14,7 +14,7 @@ fi LIB_HTTPD_PATH=${LIB_HTTPD_PATH-'/usr/sbin/apache2'} LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'8111'} -TEST_PATH="$PWD"/../lib-httpd +TEST_PATH="$TEST_DIRECTORY"/lib-httpd HTTPD_ROOT_PATH="$PWD"/httpd HTTPD_DOCUMENT_ROOT_PATH=$HTTPD_ROOT_PATH/www diff --git a/t/t0022-crlf-rename.sh b/t/t0022-crlf-rename.sh index 7d1ce2d056..f1e1d48869 100755 --- a/t/t0022-crlf-rename.sh +++ b/t/t0022-crlf-rename.sh @@ -6,13 +6,13 @@ test_description='ignore CR in CRLF sequence while computing similiarity' test_expect_success setup ' - cat ../t0022-crlf-rename.sh >sample && + cat "$TEST_DIRECTORY"/t0022-crlf-rename.sh >sample && git add sample && test_tick && git commit -m Initial && - sed -e "s/\$/
/" ../t0022-crlf-rename.sh >elpmas && + sed -e "s/\$/
/" "$TEST_DIRECTORY"/t0022-crlf-rename.sh >elpmas && git add elpmas && rm -f sample && diff --git a/t/t0050-filesystem.sh b/t/t0050-filesystem.sh index b177174ef5..7edf49db3c 100755 --- a/t/t0050-filesystem.sh +++ b/t/t0050-filesystem.sh @@ -85,7 +85,7 @@ $test_case 'add (with different case)' ' rm camelcase && echo 1 >CamelCase && git add CamelCase && - test $(git-ls-files | grep -i camelcase | wc -l) = 1 + test $(git ls-files | grep -i camelcase | wc -l) = 1 ' diff --git a/t/t0055-beyond-symlinks.sh b/t/t0055-beyond-symlinks.sh new file mode 100755 index 0000000000..b29c37a5a4 --- /dev/null +++ b/t/t0055-beyond-symlinks.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +test_description='update-index and add refuse to add beyond symlinks' + +. ./test-lib.sh + +test_expect_success setup ' + >a && + mkdir b && + ln -s b c && + >c/d && + git update-index --add a b/d +' + +test_expect_success 'update-index --add beyond symlinks' ' + test_must_fail git update-index --add c/d && + ! ( git ls-files | grep c/d ) +' + +test_expect_success 'add beyond symlinks' ' + test_must_fail git add c/d && + ! ( git ls-files | grep c/d ) +' + +test_done diff --git a/t/t1000-read-tree-m-3way.sh b/t/t1000-read-tree-m-3way.sh index 807fb83af8..22ba7a5442 100755 --- a/t/t1000-read-tree-m-3way.sh +++ b/t/t1000-read-tree-m-3way.sh @@ -72,7 +72,7 @@ In addition: ' . ./test-lib.sh -. ../lib-read-tree-m-3way.sh +. "$TEST_DIRECTORY"/lib-read-tree-m-3way.sh ################################################################ # Trivial "majority when 3 stages exist" merge plus #2ALT, #3ALT diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh index 1ec0535138..fd98e445bf 100755 --- a/t/t1007-hash-object.sh +++ b/t/t1007-hash-object.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description="git-hash-object" +test_description="git hash-object" . ./test-lib.sh @@ -49,16 +49,28 @@ setup_repo # Argument checking test_expect_success "multiple '--stdin's are rejected" ' - test_must_fail git hash-object --stdin --stdin < example + echo example | test_must_fail git hash-object --stdin --stdin ' test_expect_success "Can't use --stdin and --stdin-paths together" ' - test_must_fail git hash-object --stdin --stdin-paths && - test_must_fail git hash-object --stdin-paths --stdin + echo example | test_must_fail git hash-object --stdin --stdin-paths && + echo example | test_must_fail git hash-object --stdin-paths --stdin ' test_expect_success "Can't pass filenames as arguments with --stdin-paths" ' - test_must_fail git hash-object --stdin-paths hello < example + echo example | test_must_fail git hash-object --stdin-paths hello +' + +test_expect_success "Can't use --path with --stdin-paths" ' + echo example | test_must_fail git hash-object --stdin-paths --path=foo +' + +test_expect_success "Can't use --stdin-paths with --no-filters" ' + echo example | test_must_fail git hash-object --stdin-paths --no-filters +' + +test_expect_success "Can't use --path with --no-filters" ' + test_must_fail git hash-object --no-filters --path=foo ' # Behavior @@ -93,6 +105,42 @@ test_expect_success 'git hash-object --stdin file1 <file0 first operates on file test "$obname1" = "$obname1new" ' +test_expect_success 'check that appropriate filter is invoke when --path is used' ' + echo fooQ | tr Q "\\015" >file0 && + cp file0 file1 && + echo "file0 -crlf" >.gitattributes && + echo "file1 crlf" >>.gitattributes && + git config core.autocrlf true && + file0_sha=$(git hash-object file0) && + file1_sha=$(git hash-object file1) && + test "$file0_sha" != "$file1_sha" && + path1_sha=$(git hash-object --path=file1 file0) && + path0_sha=$(git hash-object --path=file0 file1) && + test "$file0_sha" = "$path0_sha" && + test "$file1_sha" = "$path1_sha" && + path1_sha=$(cat file0 | git hash-object --path=file1 --stdin) && + path0_sha=$(cat file1 | git hash-object --path=file0 --stdin) && + test "$file0_sha" = "$path0_sha" && + test "$file1_sha" = "$path1_sha" && + git config --unset core.autocrlf +' + +test_expect_success 'check that --no-filters option works' ' + echo fooQ | tr Q "\\015" >file0 && + cp file0 file1 && + echo "file0 -crlf" >.gitattributes && + echo "file1 crlf" >>.gitattributes && + git config core.autocrlf true && + file0_sha=$(git hash-object file0) && + file1_sha=$(git hash-object file1) && + test "$file0_sha" != "$file1_sha" && + nofilters_file1=$(git hash-object --no-filters file1) && + test "$file0_sha" = "$nofilters_file1" && + nofilters_file1=$(cat file1 | git hash-object --stdin) && + test "$file0_sha" = "$nofilters_file1" && + git config --unset core.autocrlf +' + pop_repo for args in "-w --stdin" "--stdin -w"; do diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh index 09a8199335..67e637b781 100755 --- a/t/t1200-tutorial.sh +++ b/t/t1200-tutorial.sh @@ -78,7 +78,7 @@ test_expect_success 'git whatchanged -p --root' 'cmp whatchanged.expect whatchan git tag my-first-tag test_expect_success 'git tag my-first-tag' 'cmp .git/refs/heads/master .git/refs/tags/my-first-tag' -# TODO: test git-clone +# TODO: test git clone git checkout -b mybranch test_expect_success 'git checkout -b mybranch' 'cmp .git/refs/heads/master .git/refs/heads/mybranch' diff --git a/t/t1303-wacky-config.sh b/t/t1303-wacky-config.sh index f98f4c5179..1983076c75 100755 --- a/t/t1303-wacky-config.sh +++ b/t/t1303-wacky-config.sh @@ -35,7 +35,7 @@ test_expect_success 'add key in different section' ' ' SECTION="test.q\"s\\sq'sp e.key" -test_expect_success 'make sure git-config escapes section names properly' ' +test_expect_success 'make sure git config escapes section names properly' ' git config "$SECTION" bar && check "$SECTION" bar ' diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh index b31e4b1ac6..04c2b164bc 100755 --- a/t/t1400-update-ref.sh +++ b/t/t1400-update-ref.sh @@ -228,21 +228,21 @@ test_expect_success \ 'echo TEST >F && git add F && GIT_AUTHOR_DATE="2005-05-26 23:30" \ - GIT_COMMITTER_DATE="2005-05-26 23:30" git-commit -m add -a && + GIT_COMMITTER_DATE="2005-05-26 23:30" git commit -m add -a && h_TEST=$(git rev-parse --verify HEAD) echo The other day this did not work. >M && echo And then Bob told me how to fix it. >>M && echo OTHER >F && GIT_AUTHOR_DATE="2005-05-26 23:41" \ - GIT_COMMITTER_DATE="2005-05-26 23:41" git-commit -F M -a && + GIT_COMMITTER_DATE="2005-05-26 23:41" git commit -F M -a && h_OTHER=$(git rev-parse --verify HEAD) && GIT_AUTHOR_DATE="2005-05-26 23:44" \ - GIT_COMMITTER_DATE="2005-05-26 23:44" git-commit --amend && + GIT_COMMITTER_DATE="2005-05-26 23:44" git commit --amend && h_FIXED=$(git rev-parse --verify HEAD) && echo Merged initial commit and a later commit. >M && echo $h_TEST >.git/MERGE_HEAD && GIT_AUTHOR_DATE="2005-05-26 23:45" \ - GIT_COMMITTER_DATE="2005-05-26 23:45" git-commit -F M && + GIT_COMMITTER_DATE="2005-05-26 23:45" git commit -F M && h_MERGED=$(git rev-parse --verify HEAD) && rm -f M' @@ -253,7 +253,7 @@ $h_OTHER $h_FIXED $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117151040 +0000 co $h_FIXED $h_MERGED $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117151100 +0000 commit (merge): Merged initial commit and a later commit. EOF test_expect_success \ - 'git-commit logged updates' \ + 'git commit logged updates' \ "diff expect .git/logs/$m" unset h_TEST h_OTHER h_FIXED h_MERGED diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh index 2ee88d8a06..c039ee3fd8 100755 --- a/t/t1501-worktree.sh +++ b/t/t1501-worktree.sh @@ -28,6 +28,7 @@ test_rev_parse() { [ $# -eq 0 ] && return } +EMPTY_TREE=$(git write-tree) mkdir -p work/sub/dir || exit 1 mv .git repo.git || exit 1 @@ -106,12 +107,71 @@ test_expect_success 'repo finds its work tree from work tree, too' ' ' test_expect_success '_gently() groks relative GIT_DIR & GIT_WORK_TREE' ' - cd repo.git/work/sub/dir && + (cd repo.git/work/sub/dir && GIT_DIR=../../.. GIT_WORK_TREE=../.. GIT_PAGER= \ git diff --exit-code tracked && echo changed > tracked && ! GIT_DIR=../../.. GIT_WORK_TREE=../.. GIT_PAGER= \ - git diff --exit-code tracked + git diff --exit-code tracked) +' +cat > diff-index-cached.expected <<\EOF +:000000 100644 0000000000000000000000000000000000000000 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 A sub/dir/tracked +EOF +cat > diff-index.expected <<\EOF +:000000 100644 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 A sub/dir/tracked +EOF + + +test_expect_success 'git diff-index' ' + GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work git diff-index $EMPTY_TREE > result && + test_cmp diff-index.expected result && + GIT_DIR=repo.git git diff-index --cached $EMPTY_TREE > result && + test_cmp diff-index-cached.expected result +' +cat >diff-files.expected <<\EOF +:100644 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0000000000000000000000000000000000000000 M sub/dir/tracked +EOF + +test_expect_success 'git diff-files' ' + GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work git diff-files > result && + test_cmp diff-files.expected result +' + +cat >diff-TREE.expected <<\EOF +diff --git a/sub/dir/tracked b/sub/dir/tracked +new file mode 100644 +index 0000000..5ea2ed4 +--- /dev/null ++++ b/sub/dir/tracked +@@ -0,0 +1 @@ ++changed +EOF +cat >diff-TREE-cached.expected <<\EOF +diff --git a/sub/dir/tracked b/sub/dir/tracked +new file mode 100644 +index 0000000..e69de29 +EOF +cat >diff-FILES.expected <<\EOF +diff --git a/sub/dir/tracked b/sub/dir/tracked +index e69de29..5ea2ed4 100644 +--- a/sub/dir/tracked ++++ b/sub/dir/tracked +@@ -0,0 +1 @@ ++changed +EOF + +test_expect_success 'git diff' ' + GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work git diff $EMPTY_TREE > result && + test_cmp diff-TREE.expected result && + GIT_DIR=repo.git git diff --cached $EMPTY_TREE > result && + test_cmp diff-TREE-cached.expected result && + GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work git diff > result && + test_cmp diff-FILES.expected result +' + +test_expect_success 'git grep' ' + (cd repo.git/work/sub && + GIT_DIR=../.. GIT_WORK_TREE=.. git grep -l changed | grep -q dir/tracked) ' test_done diff --git a/t/t1503-rev-parse-verify.sh b/t/t1503-rev-parse-verify.sh index 95244c9bcf..cc65394947 100755 --- a/t/t1503-rev-parse-verify.sh +++ b/t/t1503-rev-parse-verify.sh @@ -23,7 +23,7 @@ add_line_into_file() fi test_tick - git-commit --quiet -m "$MSG" $_file + git commit --quiet -m "$MSG" $_file } HASH1= diff --git a/t/t2005-checkout-index-symlinks.sh b/t/t2005-checkout-index-symlinks.sh index a84c5a6af9..ed12c4d782 100755 --- a/t/t2005-checkout-index-symlinks.sh +++ b/t/t2005-checkout-index-symlinks.sh @@ -13,7 +13,7 @@ file if core.symlinks is false.' test_expect_success \ 'preparation' ' git config core.symlinks false && -l=$(echo -n file | git-hash-object -t blob -w --stdin) && +l=$(echo -n file | git hash-object -t blob -w --stdin) && echo "120000 $l symlink" | git update-index --index-info' test_expect_success \ @@ -23,6 +23,6 @@ test -f symlink' test_expect_success \ 'the file must be the blob we added during the setup' ' -test "$(git-hash-object -t blob symlink)" = $l' +test "$(git hash-object -t blob symlink)" = $l' test_done diff --git a/t/t2050-git-dir-relative.sh b/t/t2050-git-dir-relative.sh index 88f268b9d7..b7131d8c08 100755 --- a/t/t2050-git-dir-relative.sh +++ b/t/t2050-git-dir-relative.sh @@ -26,8 +26,8 @@ chmod +x .git/hooks/post-commit' test_expect_success 'post-commit hook used ordinarily' ' echo initial >top && -git-add top -git-commit -m initial && +git add top +git commit -m initial && test -r "${COMMIT_FILE}" ' diff --git a/t/t2101-update-index-reupdate.sh b/t/t2101-update-index-reupdate.sh index 59b560bfdf..648184fd98 100755 --- a/t/t2101-update-index-reupdate.sh +++ b/t/t2101-update-index-reupdate.sh @@ -40,7 +40,7 @@ test_expect_success 'update-index --remove --again' \ git ls-files -s >current && cmp current expected' -test_expect_success 'first commit' 'git-commit -m initial' +test_expect_success 'first commit' 'git commit -m initial' cat > expected <<\EOF 100644 53ab446c3f4e42ce9bb728a0ccb283a101be4979 0 dir1/file3 diff --git a/t/t2102-update-index-symlinks.sh b/t/t2102-update-index-symlinks.sh index 19d0894d26..f195aefe3a 100755 --- a/t/t2102-update-index-symlinks.sh +++ b/t/t2102-update-index-symlinks.sh @@ -13,7 +13,7 @@ even if a plain file is in the working tree if core.symlinks is false.' test_expect_success \ 'preparation' ' git config core.symlinks false && -l=$(echo -n file | git-hash-object -t blob -w --stdin) && +l=$(echo -n file | git hash-object -t blob -w --stdin) && echo "120000 $l symlink" | git update-index --index-info' test_expect_success \ diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh index f57a6e077c..cd9231cf61 100755 --- a/t/t2200-add-update.sh +++ b/t/t2200-add-update.sh @@ -26,7 +26,7 @@ test_expect_success setup ' echo initial >dir2/sub3 && git add check dir1 dir2 top foo && test_tick - git-commit -m initial && + git commit -m initial && echo changed >check && echo changed >top && @@ -40,20 +40,20 @@ test_expect_success update ' ' test_expect_success 'update noticed a removal' ' - test "$(git-ls-files dir1/sub1)" = "" + test "$(git ls-files dir1/sub1)" = "" ' test_expect_success 'update touched correct path' ' - test "$(git-diff-files --name-status dir2/sub3)" = "" + test "$(git diff-files --name-status dir2/sub3)" = "" ' test_expect_success 'update did not touch other tracked files' ' - test "$(git-diff-files --name-status check)" = "M check" && - test "$(git-diff-files --name-status top)" = "M top" + test "$(git diff-files --name-status check)" = "M check" && + test "$(git diff-files --name-status top)" = "M top" ' test_expect_success 'update did not touch untracked files' ' - test "$(git-ls-files dir2/other)" = "" + test "$(git ls-files dir2/other)" = "" ' test_expect_success 'cache tree has not been corrupted' ' diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh index 1caeacafa7..8666946b02 100755 --- a/t/t3001-ls-files-others-exclude.sh +++ b/t/t3001-ls-files-others-exclude.sh @@ -96,7 +96,7 @@ cat > expect << EOF # three/ EOF -test_expect_success 'git-status honours core.excludesfile' \ +test_expect_success 'git status honors core.excludesfile' \ 'test_cmp expect output' test_expect_success 'trailing slash in exclude allows directory match(1)' ' diff --git a/t/t3020-ls-files-error-unmatch.sh b/t/t3020-ls-files-error-unmatch.sh index af8c4121ab..f4066cbc09 100755 --- a/t/t3020-ls-files-error-unmatch.sh +++ b/t/t3020-ls-files-error-unmatch.sh @@ -13,7 +13,7 @@ line. touch foo bar git update-index --add foo bar -git-commit -m "add foo bar" +git commit -m "add foo bar" test_expect_success \ 'git ls-files --error-unmatch should fail with unmatched path.' \ diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh index aff360303a..de0cdb1cf4 100755 --- a/t/t3030-merge-recursive.sh +++ b/t/t3030-merge-recursive.sh @@ -241,7 +241,7 @@ test_expect_success 'merge-recursive simple' ' rm -fr [abcd] && git checkout -f "$c2" && - git-merge-recursive "$c0" -- "$c2" "$c1" + git merge-recursive "$c0" -- "$c2" "$c1" status=$? case "$status" in 1) @@ -269,12 +269,23 @@ test_expect_success 'merge-recursive result' ' ' +test_expect_success 'fail if the index has unresolved entries' ' + + rm -fr [abcd] && + git checkout -f "$c1" && + + test_must_fail git merge "$c5" && + test_must_fail git merge "$c5" 2> out && + grep "You are in the middle of a conflicted merge" out + +' + test_expect_success 'merge-recursive remove conflict' ' rm -fr [abcd] && git checkout -f "$c1" && - git-merge-recursive "$c0" -- "$c1" "$c5" + git merge-recursive "$c0" -- "$c1" "$c5" status=$? case "$status" in 1) @@ -306,7 +317,7 @@ test_expect_success 'merge-recursive d/f simple' ' git reset --hard && git checkout -f "$c1" && - git-merge-recursive "$c0" -- "$c1" "$c3" + git merge-recursive "$c0" -- "$c1" "$c3" ' test_expect_success 'merge-recursive result' ' @@ -328,7 +339,7 @@ test_expect_success 'merge-recursive d/f conflict' ' git reset --hard && git checkout -f "$c1" && - git-merge-recursive "$c0" -- "$c1" "$c4" + git merge-recursive "$c0" -- "$c1" "$c4" status=$? case "$status" in 1) @@ -362,7 +373,7 @@ test_expect_success 'merge-recursive d/f conflict the other way' ' git reset --hard && git checkout -f "$c4" && - git-merge-recursive "$c0" -- "$c4" "$c1" + git merge-recursive "$c0" -- "$c4" "$c1" status=$? case "$status" in 1) @@ -396,7 +407,7 @@ test_expect_success 'merge-recursive d/f conflict' ' git reset --hard && git checkout -f "$c1" && - git-merge-recursive "$c0" -- "$c1" "$c6" + git merge-recursive "$c0" -- "$c1" "$c6" status=$? case "$status" in 1) @@ -430,7 +441,7 @@ test_expect_success 'merge-recursive d/f conflict' ' git reset --hard && git checkout -f "$c6" && - git-merge-recursive "$c0" -- "$c6" "$c1" + git merge-recursive "$c0" -- "$c6" "$c1" status=$? case "$status" in 1) diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 7a83fbfe4f..2147eacc50 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -14,10 +14,10 @@ test_expect_success \ 'prepare a trivial repository' \ 'echo Hello > A && git update-index --add A && - git-commit -m "Initial commit." && + git commit -m "Initial commit." && echo World >> A && git update-index --add A && - git-commit -m "Second commit." && + git commit -m "Second commit." && HEAD=$(git rev-parse --verify HEAD)' test_expect_success \ @@ -123,7 +123,7 @@ test_expect_success \ test_expect_success 'test tracking setup via --track' \ 'git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch --track my1 local/master && test $(git config branch.my1.remote) = local && test $(git config branch.my1.merge) = refs/heads/master' @@ -131,7 +131,7 @@ test_expect_success 'test tracking setup via --track' \ test_expect_success 'test tracking setup (non-wildcard, matching)' \ 'git config remote.local.url . && git config remote.local.fetch refs/heads/master:refs/remotes/local/master && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch --track my4 local/master && test $(git config branch.my4.remote) = local && test $(git config branch.my4.merge) = refs/heads/master' @@ -139,7 +139,7 @@ test_expect_success 'test tracking setup (non-wildcard, matching)' \ test_expect_success 'test tracking setup (non-wildcard, not matching)' \ 'git config remote.local.url . && git config remote.local.fetch refs/heads/s:refs/remotes/local/s && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch --track my5 local/master && ! test "$(git config branch.my5.remote)" = local && ! test "$(git config branch.my5.merge)" = refs/heads/master' @@ -148,7 +148,7 @@ test_expect_success 'test tracking setup via config' \ 'git config branch.autosetupmerge true && git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch my3 local/master && test $(git config branch.my3.remote) = local && test $(git config branch.my3.merge) = refs/heads/master' @@ -157,7 +157,7 @@ test_expect_success 'test overriding tracking setup via --no-track' \ 'git config branch.autosetupmerge true && git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch --no-track my2 local/master && git config branch.autosetupmerge false && ! test "$(git config branch.my2.remote)" = local && @@ -173,7 +173,7 @@ test_expect_success 'no tracking without .fetch entries' \ test_expect_success 'test tracking setup via --track but deeper' \ 'git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/o/o || git-fetch local) && + (git show-ref -q refs/remotes/local/o/o || git fetch local) && git branch --track my7 local/o/o && test "$(git config branch.my7.remote)" = local && test "$(git config branch.my7.merge)" = refs/heads/o/o' @@ -209,7 +209,7 @@ EOF test_expect_success \ 'git checkout -b g/h/i -l should create a branch and a log' \ 'GIT_COMMITTER_DATE="2005-05-26 23:30" \ - git-checkout -b g/h/i -l master && + git checkout -b g/h/i -l master && test -f .git/refs/heads/g/h/i && test -f .git/logs/refs/heads/g/h/i && diff expect .git/logs/refs/heads/g/h/i' @@ -228,7 +228,7 @@ test_expect_success 'autosetuprebase local on a tracked local branch' ' git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && git config branch.autosetuprebase local && - (git show-ref -q refs/remotes/local/o || git-fetch local) && + (git show-ref -q refs/remotes/local/o || git fetch local) && git branch mybase && git branch --track myr1 mybase && test "$(git config branch.myr1.remote)" = . && @@ -240,7 +240,7 @@ test_expect_success 'autosetuprebase always on a tracked local branch' ' git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && git config branch.autosetuprebase always && - (git show-ref -q refs/remotes/local/o || git-fetch local) && + (git show-ref -q refs/remotes/local/o || git fetch local) && git branch mybase2 && git branch --track myr2 mybase && test "$(git config branch.myr2.remote)" = . && @@ -252,7 +252,7 @@ test_expect_success 'autosetuprebase remote on a tracked local branch' ' git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && git config branch.autosetuprebase remote && - (git show-ref -q refs/remotes/local/o || git-fetch local) && + (git show-ref -q refs/remotes/local/o || git fetch local) && git branch mybase3 && git branch --track myr3 mybase2 && test "$(git config branch.myr3.remote)" = . && @@ -264,7 +264,7 @@ test_expect_success 'autosetuprebase never on a tracked local branch' ' git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && git config branch.autosetuprebase never && - (git show-ref -q refs/remotes/local/o || git-fetch local) && + (git show-ref -q refs/remotes/local/o || git fetch local) && git branch mybase4 && git branch --track myr4 mybase2 && test "$(git config branch.myr4.remote)" = . && @@ -276,7 +276,7 @@ test_expect_success 'autosetuprebase local on a tracked remote branch' ' git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && git config branch.autosetuprebase local && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch --track myr5 local/master && test "$(git config branch.myr5.remote)" = local && test "$(git config branch.myr5.merge)" = refs/heads/master && @@ -287,7 +287,7 @@ test_expect_success 'autosetuprebase never on a tracked remote branch' ' git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && git config branch.autosetuprebase never && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch --track myr6 local/master && test "$(git config branch.myr6.remote)" = local && test "$(git config branch.myr6.merge)" = refs/heads/master && @@ -298,7 +298,7 @@ test_expect_success 'autosetuprebase remote on a tracked remote branch' ' git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && git config branch.autosetuprebase remote && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch --track myr7 local/master && test "$(git config branch.myr7.remote)" = local && test "$(git config branch.myr7.merge)" = refs/heads/master && @@ -309,7 +309,7 @@ test_expect_success 'autosetuprebase always on a tracked remote branch' ' git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && git config branch.autosetuprebase remote && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch --track myr8 local/master && test "$(git config branch.myr8.remote)" = local && test "$(git config branch.myr8.merge)" = refs/heads/master && @@ -320,7 +320,7 @@ test_expect_success 'autosetuprebase unconfigured on a tracked remote branch' ' git config --unset branch.autosetuprebase && git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch --track myr9 local/master && test "$(git config branch.myr9.remote)" = local && test "$(git config branch.myr9.merge)" = refs/heads/master && @@ -330,7 +330,7 @@ test_expect_success 'autosetuprebase unconfigured on a tracked remote branch' ' test_expect_success 'autosetuprebase unconfigured on a tracked local branch' ' git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/o || git-fetch local) && + (git show-ref -q refs/remotes/local/o || git fetch local) && git branch mybase10 && git branch --track myr10 mybase2 && test "$(git config branch.myr10.remote)" = . && @@ -341,7 +341,7 @@ test_expect_success 'autosetuprebase unconfigured on a tracked local branch' ' test_expect_success 'autosetuprebase unconfigured on untracked local branch' ' git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch --no-track myr11 mybase2 && test "z$(git config branch.myr11.remote)" = z && test "z$(git config branch.myr11.merge)" = z && @@ -351,7 +351,7 @@ test_expect_success 'autosetuprebase unconfigured on untracked local branch' ' test_expect_success 'autosetuprebase unconfigured on untracked remote branch' ' git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch --no-track myr12 local/master && test "z$(git config branch.myr12.remote)" = z && test "z$(git config branch.myr12.merge)" = z && @@ -362,7 +362,7 @@ test_expect_success 'autosetuprebase never on an untracked local branch' ' git config branch.autosetuprebase never && git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch --no-track myr13 mybase2 && test "z$(git config branch.myr13.remote)" = z && test "z$(git config branch.myr13.merge)" = z && @@ -373,7 +373,7 @@ test_expect_success 'autosetuprebase local on an untracked local branch' ' git config branch.autosetuprebase local && git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch --no-track myr14 mybase2 && test "z$(git config branch.myr14.remote)" = z && test "z$(git config branch.myr14.merge)" = z && @@ -384,7 +384,7 @@ test_expect_success 'autosetuprebase remote on an untracked local branch' ' git config branch.autosetuprebase remote && git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch --no-track myr15 mybase2 && test "z$(git config branch.myr15.remote)" = z && test "z$(git config branch.myr15.merge)" = z && @@ -395,7 +395,7 @@ test_expect_success 'autosetuprebase always on an untracked local branch' ' git config branch.autosetuprebase always && git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch --no-track myr16 mybase2 && test "z$(git config branch.myr16.remote)" = z && test "z$(git config branch.myr16.merge)" = z && @@ -406,7 +406,7 @@ test_expect_success 'autosetuprebase never on an untracked remote branch' ' git config branch.autosetuprebase never && git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch --no-track myr17 local/master && test "z$(git config branch.myr17.remote)" = z && test "z$(git config branch.myr17.merge)" = z && @@ -417,7 +417,7 @@ test_expect_success 'autosetuprebase local on an untracked remote branch' ' git config branch.autosetuprebase local && git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch --no-track myr18 local/master && test "z$(git config branch.myr18.remote)" = z && test "z$(git config branch.myr18.merge)" = z && @@ -428,7 +428,7 @@ test_expect_success 'autosetuprebase remote on an untracked remote branch' ' git config branch.autosetuprebase remote && git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch --no-track myr19 local/master && test "z$(git config branch.myr19.remote)" = z && test "z$(git config branch.myr19.merge)" = z && @@ -439,7 +439,7 @@ test_expect_success 'autosetuprebase always on an untracked remote branch' ' git config branch.autosetuprebase always && git config remote.local.url . && git config remote.local.fetch refs/heads/*:refs/remotes/local/* && - (git show-ref -q refs/remotes/local/master || git-fetch local) && + (git show-ref -q refs/remotes/local/master || git fetch local) && git branch --no-track myr20 local/master && test "z$(git config branch.myr20.remote)" = z && test "z$(git config branch.myr20.merge)" = z && diff --git a/t/t3210-pack-refs.sh b/t/t3210-pack-refs.sh index c2dec1c632..087ef75061 100755 --- a/t/t3210-pack-refs.sh +++ b/t/t3210-pack-refs.sh @@ -17,7 +17,7 @@ test_expect_success \ 'prepare a trivial repository' \ 'echo Hello > A && git update-index --add A && - git-commit -m "Initial commit." && + git commit -m "Initial commit." && HEAD=$(git rev-parse --verify HEAD)' SHA1= @@ -97,7 +97,7 @@ test_expect_success \ git branch n' test_expect_success 'pack, prune and repack' ' - git-tag foo && + git tag foo && git pack-refs --all --prune && git show-ref >all-of-them && git pack-refs && diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh index 0574ef1f10..db46d53e82 100755 --- a/t/t3300-funny-names.sh +++ b/t/t3300-funny-names.sh @@ -21,7 +21,7 @@ cat >"$p0" <<\EOF 3. A quick brown fox jumps over the lazy cat, oops dog. EOF -cat >"$p1" "$p0" +cat 2>/dev/null >"$p1" "$p0" echo 'Foo Bar Baz' >"$p2" test -f "$p1" && cmp "$p0" "$p1" || { diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index 91bb5e1d9e..b7a670ef40 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -16,15 +16,15 @@ test_expect_success \ 'prepare repository with topic branches' \ 'echo First > A && git update-index --add A && - git-commit -m "Add A." && + git commit -m "Add A." && git checkout -b my-topic-branch && echo Second > B && git update-index --add B && - git-commit -m "Add B." && + git commit -m "Add B." && git checkout -f master && echo Third >> A && git update-index A && - git-commit -m "Modify A." && + git commit -m "Modify A." && git checkout -b side my-topic-branch && echo Side >> C && git add C && diff --git a/t/t3401-rebase-partial.sh b/t/t3401-rebase-partial.sh index 166ddb1447..aea6685984 100755 --- a/t/t3401-rebase-partial.sh +++ b/t/t3401-rebase-partial.sh @@ -15,29 +15,29 @@ test_expect_success \ 'prepare repository with topic branch' \ 'echo First > A && git update-index --add A && - git-commit -m "Add A." && + git commit -m "Add A." && - git-checkout -b my-topic-branch && + git checkout -b my-topic-branch && echo Second > B && git update-index --add B && - git-commit -m "Add B." && + git commit -m "Add B." && echo AnotherSecond > C && git update-index --add C && - git-commit -m "Add C." && + git commit -m "Add C." && - git-checkout -f master && + git checkout -f master && echo Third >> A && git update-index A && - git-commit -m "Modify A." + git commit -m "Modify A." ' test_expect_success \ 'pick top patch from topic branch into master' \ 'git cherry-pick my-topic-branch^0 && - git-checkout -f my-topic-branch && + git checkout -f my-topic-branch && git branch master-merge master && git branch my-topic-branch-merge my-topic-branch ' @@ -49,13 +49,13 @@ test_debug \ ' test_expect_success \ - 'rebase topic branch against new master and check git-am did not get halted' \ - 'git-rebase master && test ! -d .git/rebase-apply' + 'rebase topic branch against new master and check git am did not get halted' \ + 'git rebase master && test ! -d .git/rebase-apply' test_expect_success \ 'rebase --merge topic branch that was partially merged upstream' \ - 'git-checkout -f my-topic-branch-merge && - git-rebase --merge master-merge && + 'git checkout -f my-topic-branch-merge && + git rebase --merge master-merge && test ! -d .git/rebase-merge' test_done diff --git a/t/t3403-rebase-skip.sh b/t/t3403-rebase-skip.sh index 0d33c71daa..64446e3db3 100755 --- a/t/t3403-rebase-skip.sh +++ b/t/t3403-rebase-skip.sh @@ -7,7 +7,7 @@ test_description='git rebase --merge --skip tests' . ./test-lib.sh -# we assume the default git-am -3 --skip strategy is tested independently +# we assume the default git am -3 --skip strategy is tested independently # and always works :) test_expect_success setup ' diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 5aa487ac02..e0ded197ec 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -161,7 +161,7 @@ test_expect_success 'stop on conflicting pick' ' test "$(git rev-parse HEAD~3)" = "$(git rev-parse master)" && test_cmp expect .git/rebase-merge/patch && test_cmp expect2 file1 && - test "$(git-diff --name-status | + test "$(git diff --name-status | sed -n -e "/^U/s/^U[^a-z]*//p")" = file1 && test 4 = $(grep -v "^#" < .git/rebase-merge/done | wc -l) && test 0 = $(grep -c "^[^#]" < .git/rebase-merge/git-rebase-todo) diff --git a/t/t3407-rebase-abort.sh b/t/t3407-rebase-abort.sh index 4de550a632..2999e78937 100755 --- a/t/t3407-rebase-abort.sh +++ b/t/t3407-rebase-abort.sh @@ -52,7 +52,7 @@ testrebase() { test -d "$dotest" && test_must_fail git rebase --skip && test $(git rev-parse HEAD) = $(git rev-parse master) && - git-rebase --abort && + git rebase --abort && test $(git rev-parse to-rebase) = $(git rev-parse pre-rebase) && test ! -d "$dotest" ' diff --git a/t/t3500-cherry.sh b/t/t3500-cherry.sh index 4911c48378..dadbbc2a9f 100755 --- a/t/t3500-cherry.sh +++ b/t/t3500-cherry.sh @@ -17,25 +17,25 @@ test_expect_success \ 'prepare repository with topic branch, and check cherry finds the 2 patches from there' \ 'echo First > A && git update-index --add A && - git-commit -m "Add A." && + git commit -m "Add A." && - git-checkout -b my-topic-branch && + git checkout -b my-topic-branch && echo Second > B && git update-index --add B && - git-commit -m "Add B." && + git commit -m "Add B." && sleep 2 && echo AnotherSecond > C && git update-index --add C && - git-commit -m "Add C." && + git commit -m "Add C." && - git-checkout -f master && + git checkout -f master && rm -f B C && echo Third >> A && git update-index A && - git-commit -m "Modify A." && + git commit -m "Modify A." && expr "$(echo $(git cherry master my-topic-branch) )" : "+ [^ ]* + .*" ' diff --git a/t/t3504-cherry-pick-rerere.sh b/t/t3504-cherry-pick-rerere.sh new file mode 100755 index 0000000000..f7b3518a32 --- /dev/null +++ b/t/t3504-cherry-pick-rerere.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +test_description='cherry-pick should rerere for conflicts' + +. ./test-lib.sh + +test_expect_success setup ' + echo foo >foo && + git add foo && test_tick && git commit -q -m 1 && + echo foo-master >foo && + git add foo && test_tick && git commit -q -m 2 && + + git checkout -b dev HEAD^ && + echo foo-dev >foo && + git add foo && test_tick && git commit -q -m 3 && + git config rerere.enabled true +' + +test_expect_success 'conflicting merge' ' + test_must_fail git merge master +' + +test_expect_success 'fixup' ' + echo foo-dev >foo && + git add foo && test_tick && git commit -q -m 4 && + git reset --hard HEAD^ + echo foo-dev >expect +' + +test_expect_success 'cherry-pick conflict' ' + test_must_fail git cherry-pick master && + test_cmp expect foo +' + +test_expect_success 'reconfigure' ' + git config rerere.enabled false + git reset --hard +' + +test_expect_success 'cherry-pick conflict without rerere' ' + test_must_fail git cherry-pick master && + test_must_fail test_cmp expect foo +' + +test_done diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index 79c06adf1f..558c80edbf 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -12,14 +12,14 @@ test_expect_success \ 'Initialize test directory' \ "touch -- foo bar baz 'space embedded' -q && git add -- foo bar baz 'space embedded' -q && - git-commit -m 'add normal files' && + git commit -m 'add normal files' && test_tabs=y && if touch -- 'tab embedded' 'newline embedded' then git add -- 'tab embedded' 'newline embedded' && - git-commit -m 'add files with tabs and newlines' + git commit -m 'add files with tabs and newlines' else say 'Your filesystem does not allow tabs in filenames.' test_tabs=n diff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh index c851db8ca9..6fb027ba57 100755 --- a/t/t3800-mktag.sh +++ b/t/t3800-mktag.sh @@ -2,7 +2,7 @@ # # -test_description='git-mktag: tag object verify test' +test_description='git mktag: tag object verify test' . ./test-lib.sh @@ -14,7 +14,7 @@ test_description='git-mktag: tag object verify test' check_verify_failure () { expect="$2" test_expect_success "$1" ' - ( test_must_fail git-mktag <tag.sig 2>message ) && + ( test_must_fail git mktag <tag.sig 2>message ) && grep "$expect" message ' } @@ -24,7 +24,7 @@ check_verify_failure () { # for the tag. echo Hello >A git update-index --add A -git-commit -m "Initial commit" +git commit -m "Initial commit" head=$(git rev-parse --verify HEAD) ############################################################ @@ -222,7 +222,7 @@ EOF test_expect_success \ 'allow empty tag email' \ - 'git-mktag <tag.sig >.git/refs/tags/mytag 2>message' + 'git mktag <tag.sig >.git/refs/tags/mytag 2>message' ############################################################ # 16. disallow spaces in tag email @@ -350,14 +350,14 @@ EOF test_expect_success \ 'create valid tag' \ - 'git-mktag <tag.sig >.git/refs/tags/mytag 2>message' + 'git mktag <tag.sig >.git/refs/tags/mytag 2>message' ############################################################ # 25. check mytag test_expect_success \ 'check mytag' \ - 'git-tag -l | grep mytag' + 'git tag -l | grep mytag' test_done diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh index 883281dbd6..784c31aec9 100755 --- a/t/t3900-i18n-commit.sh +++ b/t/t3900-i18n-commit.sh @@ -16,9 +16,9 @@ test_expect_success setup ' : >F && git add F && T=$(git write-tree) && - C=$(git commit-tree $T <../t3900/1-UTF-8.txt) && + C=$(git commit-tree $T <"$TEST_DIRECTORY"/t3900/1-UTF-8.txt) && git update-ref HEAD $C && - git-tag C0 + git tag C0 ' test_expect_success 'no encoding header for base case' ' @@ -30,9 +30,9 @@ for H in ISO-8859-1 EUCJP ISO-2022-JP do test_expect_success "$H setup" ' git config i18n.commitencoding $H && - git-checkout -b $H C0 && + git checkout -b $H C0 && echo $H >F && - git-commit -a -F ../t3900/$H.txt + git commit -a -F "$TEST_DIRECTORY"/t3900/$H.txt ' done @@ -57,13 +57,13 @@ test_expect_success 'config to remove customization' ' ' test_expect_success 'ISO-8859-1 should be shown in UTF-8 now' ' - compare_with ISO-8859-1 ../t3900/1-UTF-8.txt + compare_with ISO-8859-1 "$TEST_DIRECTORY"/t3900/1-UTF-8.txt ' for H in EUCJP ISO-2022-JP do test_expect_success "$H should be shown in UTF-8 now" ' - compare_with '$H' ../t3900/2-UTF-8.txt + compare_with '$H' "$TEST_DIRECTORY"/t3900/2-UTF-8.txt ' done @@ -82,7 +82,7 @@ for H in ISO-8859-1 EUCJP ISO-2022-JP do test_expect_success "$H should be shown in itself now" ' git config i18n.commitencoding '$H' && - compare_with '$H' ../t3900/'$H'.txt + compare_with '$H' "$TEST_DIRECTORY"/t3900/'$H'.txt ' done @@ -91,13 +91,13 @@ test_expect_success 'config to tweak customization' ' ' test_expect_success 'ISO-8859-1 should be shown in UTF-8 now' ' - compare_with ISO-8859-1 ../t3900/1-UTF-8.txt + compare_with ISO-8859-1 "$TEST_DIRECTORY"/t3900/1-UTF-8.txt ' for H in EUCJP ISO-2022-JP do test_expect_success "$H should be shown in UTF-8 now" ' - compare_with '$H' ../t3900/2-UTF-8.txt + compare_with '$H' "$TEST_DIRECTORY"/t3900/2-UTF-8.txt ' done @@ -107,7 +107,7 @@ do for H in EUCJP ISO-2022-JP do test_expect_success "$H should be shown in $J now" ' - compare_with '$H' ../t3900/'$J'.txt + compare_with '$H' "$TEST_DIRECTORY"/t3900/'$J'.txt ' done done @@ -115,7 +115,7 @@ done for H in ISO-8859-1 EUCJP ISO-2022-JP do test_expect_success "No conversion with $H" ' - compare_with "--encoding=none '$H'" ../t3900/'$H'.txt + compare_with "--encoding=none '$H'" "$TEST_DIRECTORY"/t3900/'$H'.txt ' done diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh index 235f372832..7655da3f8d 100755 --- a/t/t3901-i18n-patch.sh +++ b/t/t3901-i18n-patch.sh @@ -35,7 +35,7 @@ test_expect_success setup ' # use UTF-8 in author and committer name to match the # i18n.commitencoding settings - . ../t3901-utf8.txt && + . "$TEST_DIRECTORY"/t3901-utf8.txt && test_tick && echo "$GIT_AUTHOR_NAME" >mine && @@ -57,7 +57,7 @@ test_expect_success setup ' # the second one on the side branch is ISO-8859-1 git config i18n.commitencoding ISO-8859-1 && # use author and committer name in ISO-8859-1 to match it. - . ../t3901-8859-1.txt && + . "$TEST_DIRECTORY"/t3901-8859-1.txt && test_tick && echo Yet another >theirs && git add theirs && @@ -101,9 +101,9 @@ test_expect_success 'rebase (U/U)' ' # The result will be committed by GIT_COMMITTER_NAME -- # we want UTF-8 encoded name. - . ../t3901-utf8.txt && + . "$TEST_DIRECTORY"/t3901-utf8.txt && git checkout -b test && - git-rebase master && + git rebase master && check_encoding 2 ' @@ -111,10 +111,10 @@ test_expect_success 'rebase (U/U)' ' test_expect_success 'rebase (U/L)' ' git config i18n.commitencoding UTF-8 && git config i18n.logoutputencoding ISO-8859-1 && - . ../t3901-utf8.txt && + . "$TEST_DIRECTORY"/t3901-utf8.txt && git reset --hard side && - git-rebase master && + git rebase master && check_encoding 2 ' @@ -123,10 +123,10 @@ test_expect_success 'rebase (L/L)' ' # In this test we want ISO-8859-1 encoded commits as the result git config i18n.commitencoding ISO-8859-1 && git config i18n.logoutputencoding ISO-8859-1 && - . ../t3901-8859-1.txt && + . "$TEST_DIRECTORY"/t3901-8859-1.txt && git reset --hard side && - git-rebase master && + git rebase master && check_encoding 2 8859 ' @@ -136,10 +136,10 @@ test_expect_success 'rebase (L/U)' ' # to get ISO-8859-1 results. git config i18n.commitencoding ISO-8859-1 && git config i18n.logoutputencoding UTF-8 && - . ../t3901-8859-1.txt && + . "$TEST_DIRECTORY"/t3901-8859-1.txt && git reset --hard side && - git-rebase master && + git rebase master && check_encoding 2 8859 ' @@ -149,7 +149,7 @@ test_expect_success 'cherry-pick(U/U)' ' git config i18n.commitencoding UTF-8 && git config i18n.logoutputencoding UTF-8 && - . ../t3901-utf8.txt && + . "$TEST_DIRECTORY"/t3901-utf8.txt && git reset --hard master && git cherry-pick side^ && @@ -164,7 +164,7 @@ test_expect_success 'cherry-pick(L/L)' ' git config i18n.commitencoding ISO-8859-1 && git config i18n.logoutputencoding ISO-8859-1 && - . ../t3901-8859-1.txt && + . "$TEST_DIRECTORY"/t3901-8859-1.txt && git reset --hard master && git cherry-pick side^ && @@ -179,7 +179,7 @@ test_expect_success 'cherry-pick(U/L)' ' git config i18n.commitencoding UTF-8 && git config i18n.logoutputencoding ISO-8859-1 && - . ../t3901-utf8.txt && + . "$TEST_DIRECTORY"/t3901-utf8.txt && git reset --hard master && git cherry-pick side^ && @@ -195,7 +195,7 @@ test_expect_success 'cherry-pick(L/U)' ' git config i18n.commitencoding ISO-8859-1 && git config i18n.logoutputencoding UTF-8 && - . ../t3901-8859-1.txt && + . "$TEST_DIRECTORY"/t3901-8859-1.txt && git reset --hard master && git cherry-pick side^ && @@ -208,10 +208,10 @@ test_expect_success 'cherry-pick(L/U)' ' test_expect_success 'rebase --merge (U/U)' ' git config i18n.commitencoding UTF-8 && git config i18n.logoutputencoding UTF-8 && - . ../t3901-utf8.txt && + . "$TEST_DIRECTORY"/t3901-utf8.txt && git reset --hard side && - git-rebase --merge master && + git rebase --merge master && check_encoding 2 ' @@ -219,10 +219,10 @@ test_expect_success 'rebase --merge (U/U)' ' test_expect_success 'rebase --merge (U/L)' ' git config i18n.commitencoding UTF-8 && git config i18n.logoutputencoding ISO-8859-1 && - . ../t3901-utf8.txt && + . "$TEST_DIRECTORY"/t3901-utf8.txt && git reset --hard side && - git-rebase --merge master && + git rebase --merge master && check_encoding 2 ' @@ -231,10 +231,10 @@ test_expect_success 'rebase --merge (L/L)' ' # In this test we want ISO-8859-1 encoded commits as the result git config i18n.commitencoding ISO-8859-1 && git config i18n.logoutputencoding ISO-8859-1 && - . ../t3901-8859-1.txt && + . "$TEST_DIRECTORY"/t3901-8859-1.txt && git reset --hard side && - git-rebase --merge master && + git rebase --merge master && check_encoding 2 8859 ' @@ -244,10 +244,10 @@ test_expect_success 'rebase --merge (L/U)' ' # to get ISO-8859-1 results. git config i18n.commitencoding ISO-8859-1 && git config i18n.logoutputencoding UTF-8 && - . ../t3901-8859-1.txt && + . "$TEST_DIRECTORY"/t3901-8859-1.txt && git reset --hard side && - git-rebase --merge master && + git rebase --merge master && check_encoding 2 8859 ' diff --git a/t/t3902-quoted.sh b/t/t3902-quoted.sh index fe4fb5116a..5868052425 100755 --- a/t/t3902-quoted.sh +++ b/t/t3902-quoted.sh @@ -7,12 +7,6 @@ test_description='quoted output' . ./test-lib.sh -P1='pathname with HT' -: >"$P1" 2>&1 && test -f "$P1" && rm -f "$P1" || { - echo >&2 'Filesystem does not support HT in names' - test_done -} - FN='濱野' GN='純' HT=' ' @@ -20,7 +14,7 @@ LF=' ' DQ='"' -echo foo > "Name and an${HT}HT" +echo foo 2>/dev/null > "Name and an${HT}HT" test -f "Name and an${HT}HT" || { # since FAT/NTFS does not allow tabs in filenames, skip this test say 'Your filesystem does not allow tabs in filenames, test skipped.' diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh index 8d4804b658..7484cbede6 100755 --- a/t/t3903-stash.sh +++ b/t/t3903-stash.sh @@ -3,7 +3,7 @@ # Copyright (c) 2007 Johannes E Schindelin # -test_description='Test git-stash' +test_description='Test git stash' . ./test-lib.sh diff --git a/t/t4000-diff-format.sh b/t/t4000-diff-format.sh index c44b27aeb2..6ddd46915d 100755 --- a/t/t4000-diff-format.sh +++ b/t/t4000-diff-format.sh @@ -7,7 +7,7 @@ test_description='Test built-in diff output engine. ' . ./test-lib.sh -. ../diff-lib.sh +. "$TEST_DIRECTORY"/diff-lib.sh echo >path0 'Line 1 Line 2 diff --git a/t/t4001-diff-rename.sh b/t/t4001-diff-rename.sh index a32692417d..71bac83dd5 100755 --- a/t/t4001-diff-rename.sh +++ b/t/t4001-diff-rename.sh @@ -7,7 +7,7 @@ test_description='Test rename detection in diff engine. ' . ./test-lib.sh -. ../diff-lib.sh +. "$TEST_DIRECTORY"/diff-lib.sh echo >path0 'Line 1 Line 2 diff --git a/t/t4002-diff-basic.sh b/t/t4002-diff-basic.sh index a4cfde6b29..cc3681f161 100755 --- a/t/t4002-diff-basic.sh +++ b/t/t4002-diff-basic.sh @@ -7,7 +7,7 @@ test_description='Test diff raw-output. ' . ./test-lib.sh -. ../lib-read-tree-m-3way.sh +. "$TEST_DIRECTORY"/lib-read-tree-m-3way.sh cat >.test-plain-OA <<\EOF :000000 100644 0000000000000000000000000000000000000000 ccba72ad3888a3520b39efcf780b9ee64167535d A AA @@ -169,6 +169,20 @@ test_expect_success \ cmp -s .test-a .test-recursive-AB' test_expect_success \ + 'diff-tree --stdin of known trees.' \ + 'echo $tree_A $tree_B | git diff-tree --stdin > .test-a && + echo $tree_A $tree_B > .test-plain-ABx && + cat .test-plain-AB >> .test-plain-ABx && + cmp -s .test-a .test-plain-ABx' + +test_expect_success \ + 'diff-tree --stdin of known trees.' \ + 'echo $tree_A $tree_B | git diff-tree -r --stdin > .test-a && + echo $tree_A $tree_B > .test-recursive-ABx && + cat .test-recursive-AB >> .test-recursive-ABx && + cmp -s .test-a .test-recursive-ABx' + +test_expect_success \ 'diff-cache O with A in cache' \ 'git read-tree $tree_A && git diff-index --cached $tree_O >.test-a && diff --git a/t/t4003-diff-rename-1.sh b/t/t4003-diff-rename-1.sh index 8b1f875286..c6130c4019 100755 --- a/t/t4003-diff-rename-1.sh +++ b/t/t4003-diff-rename-1.sh @@ -7,11 +7,11 @@ test_description='More rename detection ' . ./test-lib.sh -. ../diff-lib.sh ;# test-lib chdir's into trash +. "$TEST_DIRECTORY"/diff-lib.sh ;# test-lib chdir's into trash test_expect_success \ 'prepare reference tree' \ - 'cat ../../COPYING >COPYING && + 'cat "$TEST_DIRECTORY"/../COPYING >COPYING && echo frotz >rezrov && git update-index --add COPYING rezrov && tree=$(git write-tree) && @@ -99,7 +99,7 @@ test_expect_success \ test_expect_success \ 'prepare work tree once again' \ - 'cat ../../COPYING >COPYING && + 'cat "$TEST_DIRECTORY"/../COPYING >COPYING && git update-index --add --remove COPYING COPYING.1' # tree has COPYING and rezrov. work tree has COPYING and COPYING.1, diff --git a/t/t4004-diff-rename-symlink.sh b/t/t4004-diff-rename-symlink.sh index 3d25be7a67..b35af9b42d 100755 --- a/t/t4004-diff-rename-symlink.sh +++ b/t/t4004-diff-rename-symlink.sh @@ -10,7 +10,7 @@ copy of symbolic links, but should not produce rename/copy followed by an edit for them. ' . ./test-lib.sh -. ../diff-lib.sh +. "$TEST_DIRECTORY"/diff-lib.sh test_expect_success \ 'prepare reference tree' \ diff --git a/t/t4005-diff-rename-2.sh b/t/t4005-diff-rename-2.sh index 6630017312..1ba359d478 100755 --- a/t/t4005-diff-rename-2.sh +++ b/t/t4005-diff-rename-2.sh @@ -7,11 +7,11 @@ test_description='Same rename detection as t4003 but testing diff-raw. ' . ./test-lib.sh -. ../diff-lib.sh ;# test-lib chdir's into trash +. "$TEST_DIRECTORY"/diff-lib.sh ;# test-lib chdir's into trash test_expect_success \ 'prepare reference tree' \ - 'cat ../../COPYING >COPYING && + 'cat "$TEST_DIRECTORY"/../COPYING >COPYING && echo frotz >rezrov && git update-index --add COPYING rezrov && tree=$(git write-tree) && @@ -71,7 +71,7 @@ test_expect_success \ test_expect_success \ 'prepare work tree once again' \ - 'cat ../../COPYING >COPYING && + 'cat "$TEST_DIRECTORY"/../COPYING >COPYING && git update-index --add --remove COPYING COPYING.1' git diff-index -C --find-copies-harder $tree >current diff --git a/t/t4007-rename-3.sh b/t/t4007-rename-3.sh index 104a4e1492..42072d724e 100755 --- a/t/t4007-rename-3.sh +++ b/t/t4007-rename-3.sh @@ -7,12 +7,12 @@ test_description='Rename interaction with pathspec. ' . ./test-lib.sh -. ../diff-lib.sh ;# test-lib chdir's into trash +. "$TEST_DIRECTORY"/diff-lib.sh ;# test-lib chdir's into trash test_expect_success \ 'prepare reference tree' \ 'mkdir path0 path1 && - cp ../../COPYING path0/COPYING && + cp "$TEST_DIRECTORY"/../COPYING path0/COPYING && git update-index --add path0/COPYING && tree=$(git write-tree) && echo $tree' diff --git a/t/t4008-diff-break-rewrite.sh b/t/t4008-diff-break-rewrite.sh index 26c2e4aa65..7e343a9cd1 100755 --- a/t/t4008-diff-break-rewrite.sh +++ b/t/t4008-diff-break-rewrite.sh @@ -22,12 +22,12 @@ four changes in total. Further, with -B and -M together, these should turn into two renames. ' . ./test-lib.sh -. ../diff-lib.sh ;# test-lib chdir's into trash +. "$TEST_DIRECTORY"/diff-lib.sh ;# test-lib chdir's into trash test_expect_success \ setup \ - 'cat ../../README >file0 && - cat ../../COPYING >file1 && + 'cat "$TEST_DIRECTORY"/../README >file0 && + cat "$TEST_DIRECTORY"/../COPYING >file1 && git update-index --add file0 file1 && tree=$(git write-tree) && echo "$tree"' diff --git a/t/t4009-diff-rename-4.sh b/t/t4009-diff-rename-4.sh index d2b45e7b8f..de3f17478e 100755 --- a/t/t4009-diff-rename-4.sh +++ b/t/t4009-diff-rename-4.sh @@ -7,11 +7,11 @@ test_description='Same rename detection as t4003 but testing diff-raw -z. ' . ./test-lib.sh -. ../diff-lib.sh ;# test-lib chdir's into trash +. "$TEST_DIRECTORY"/diff-lib.sh ;# test-lib chdir's into trash test_expect_success \ 'prepare reference tree' \ - 'cat ../../COPYING >COPYING && + 'cat "$TEST_DIRECTORY"/../COPYING >COPYING && echo frotz >rezrov && git update-index --add COPYING rezrov && tree=$(git write-tree) && @@ -78,7 +78,7 @@ test_expect_success \ test_expect_success \ 'prepare work tree once again' \ - 'cat ../../COPYING >COPYING && + 'cat "$TEST_DIRECTORY"/../COPYING >COPYING && git update-index --add --remove COPYING COPYING.1' git diff-index -z -C --find-copies-harder $tree >current diff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh index ad3d9e4845..9322298ecc 100755 --- a/t/t4010-diff-pathspec.sh +++ b/t/t4010-diff-pathspec.sh @@ -10,7 +10,7 @@ Prepare: path1/file1 ' . ./test-lib.sh -. ../diff-lib.sh ;# test-lib chdir's into trash +. "$TEST_DIRECTORY"/diff-lib.sh ;# test-lib chdir's into trash test_expect_success \ setup \ diff --git a/t/t4011-diff-symlink.sh b/t/t4011-diff-symlink.sh index c6d13693ba..02efecae3a 100755 --- a/t/t4011-diff-symlink.sh +++ b/t/t4011-diff-symlink.sh @@ -7,7 +7,7 @@ test_description='Test diff of symlinks. ' . ./test-lib.sh -. ../diff-lib.sh +. "$TEST_DIRECTORY"/diff-lib.sh cat > expected << EOF diff --git a/frotz b/frotz diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh index eced1f30fb..b8ec6e90af 100755 --- a/t/t4012-diff-binary.sh +++ b/t/t4012-diff-binary.sh @@ -12,7 +12,7 @@ test_expect_success 'prepare repository' \ 'echo AIT >a && echo BIT >b && echo CIT >c && echo DIT >d && git update-index --add a b c d && echo git >a && - cat ../test4012.png >b && + cat "$TEST_DIRECTORY"/test4012.png >b && echo git >c && cat b b >d' @@ -61,7 +61,7 @@ test_expect_success 'apply detecting corrupt patch correctly' \ detected=`sed -ne "${detected}p" broken` && test "$detected" = xCIT' -test_expect_success 'initial commit' 'git-commit -a -m initial' +test_expect_success 'initial commit' 'git commit -a -m initial' # Try removal (b), modification (d), and creation (e). test_expect_success 'diff-index with --binary' \ @@ -72,7 +72,7 @@ test_expect_success 'diff-index with --binary' \ git apply --stat --summary current' test_expect_success 'apply binary patch' \ - 'git-reset --hard && + 'git reset --hard && git apply --binary --index <current && tree1=`git write-tree` && test "$tree1" = "$tree0"' diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index 9337b81064..1a6b52234d 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -99,7 +99,7 @@ do test=`echo "$cmd" | sed -e 's|[/ ][/ ]*|_|g'` cnt=`expr $test_count + 1` pfx=`printf "%04d" $cnt` - expect="../t4013/diff.$test" + expect="$TEST_DIRECTORY/t4013/diff.$test" actual="$pfx-diff.$test" test_expect_success "git $cmd" ' diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 7fe853c20d..9d99dc2887 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -230,4 +230,29 @@ test_expect_success 'shortlog of cover-letter wraps overly-long onelines' ' ' +cat > expect << EOF +--- + file | 16 ++++++++++++++++ + 1 files changed, 16 insertions(+), 0 deletions(-) + +diff --git a/file b/file +index 40f36c6..2dc5c23 100644 +--- a/file ++++ b/file +@@ -13,4 +13,20 @@ C + 10 + D + E + F ++5 +EOF + +test_expect_success 'format-patch respects -U' ' + + git format-patch -U4 -2 && + sed -e "1,/^$/d" -e "/^+5/q" < 0001-This-is-an-excessively-long-subject-line-for-a-messa.patch > output && + test_cmp expect output + +' + test_done diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index ec98509fd2..fc2307eaa3 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -7,7 +7,7 @@ test_description='Test special whitespace in diff engine. ' . ./test-lib.sh -. ../diff-lib.sh +. "$TEST_DIRECTORY"/diff-lib.sh # Ray Lehtiniemi's example @@ -352,4 +352,20 @@ test_expect_success 'checkdiff allows new blank lines' ' git diff --check ' +test_expect_success 'combined diff with autocrlf conversion' ' + + git reset --hard && + echo >x hello && + git commit -m "one side" x && + git checkout HEAD^ && + echo >x goodbye && + git commit -m "the other side" x && + git config core.autocrlf true && + test_must_fail git merge master && + + git diff | sed -e "1,/^@@@/d" >actual && + ! grep "^-" actual + +' + test_done diff --git a/t/t4016-diff-quote.sh b/t/t4016-diff-quote.sh index f07035ab7e..55eb5f83f1 100755 --- a/t/t4016-diff-quote.sh +++ b/t/t4016-diff-quote.sh @@ -13,8 +13,8 @@ P1='pathname with HT' P2='pathname with SP' P3='pathname with LF' -: >"$P1" 2>&1 && test -f "$P1" && rm -f "$P1" || { - echo >&2 'Filesystem does not support tabs in names' +: 2>/dev/null >"$P1" && test -f "$P1" && rm -f "$P1" || { + say 'Your filesystem does not allow tabs in filenames, test skipped.' test_done } diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh index 833d6cbcfc..18bcd9713d 100755 --- a/t/t4018-diff-funcname.sh +++ b/t/t4018-diff-funcname.sh @@ -57,4 +57,10 @@ test_expect_success 'last regexp must not be negated' ' test_must_fail git diff --no-index Beer.java Beer-correct.java ' +test_expect_success 'alternation in pattern' ' + git config diff.java.funcname "^[ ]*\\(\\(public\\|static\\).*\\)$" + git diff --no-index Beer.java Beer-correct.java | + grep "^@@.*@@ public static void main(" +' + test_done diff --git a/t/t4019-diff-wserror.sh b/t/t4019-diff-wserror.sh index 7eae1f4500..84a1fe3115 100755 --- a/t/t4019-diff-wserror.sh +++ b/t/t4019-diff-wserror.sh @@ -178,4 +178,16 @@ test_expect_success 'trailing empty lines (2)' ' ' +test_expect_success 'do not color trailing cr in context' ' + git config --unset core.whitespace + rm -f .gitattributes && + echo AAAQ | tr Q "\015" >G && + git add G && + echo BBBQ | tr Q "\015" >>G + git diff --color G | tr "\015" Q >output && + grep "BBB.*${blue_grep}Q" output && + grep "AAA.*\[mQ" output + +' + test_done diff --git a/t/t4020-diff-external.sh b/t/t4020-diff-external.sh index 637b4e19d5..dfe3fbc74b 100755 --- a/t/t4020-diff-external.sh +++ b/t/t4020-diff-external.sh @@ -104,7 +104,7 @@ echo NULZbetweenZwords | perl -pe 'y/Z/\000/' > file test_expect_success 'force diff with "diff"' ' echo >.gitattributes "file diff" && git diff >actual && - test_cmp ../t4020/diff.NUL actual + test_cmp "$TEST_DIRECTORY"/t4020/diff.NUL actual ' test_done diff --git a/t/t4022-diff-rewrite.sh b/t/t4022-diff-rewrite.sh index bf996fc414..2a537a21e8 100755 --- a/t/t4022-diff-rewrite.sh +++ b/t/t4022-diff-rewrite.sh @@ -6,12 +6,12 @@ test_description='rewrite diff' test_expect_success setup ' - cat ../../COPYING >test && + cat "$TEST_DIRECTORY"/../COPYING >test && git add test && tr \ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" \ "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM" \ - <../../COPYING >test + <"$TEST_DIRECTORY"/../COPYING >test ' diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh index 4dbfc6e8b7..297ddb5a25 100755 --- a/t/t4023-diff-rename-typechange.sh +++ b/t/t4023-diff-rename-typechange.sh @@ -7,21 +7,21 @@ test_description='typechange rename detection' test_expect_success setup ' rm -f foo bar && - cat ../../COPYING >foo && + cat "$TEST_DIRECTORY"/../COPYING >foo && ln -s linklink bar && git add foo bar && git commit -a -m Initial && git tag one && rm -f foo bar && - cat ../../COPYING >bar && + cat "$TEST_DIRECTORY"/../COPYING >bar && ln -s linklink foo && git add foo bar && git commit -a -m Second && git tag two && rm -f foo bar && - cat ../../COPYING >foo && + cat "$TEST_DIRECTORY"/../COPYING >foo && git add foo && git commit -a -m Third && git tag three && @@ -35,15 +35,15 @@ test_expect_success setup ' # This is purely for sanity check rm -f foo bar && - cat ../../COPYING >foo && - cat ../../Makefile >bar && + cat "$TEST_DIRECTORY"/../COPYING >foo && + cat "$TEST_DIRECTORY"/../Makefile >bar && git add foo bar && git commit -a -m Fifth && git tag five && rm -f foo bar && - cat ../../Makefile >foo && - cat ../../COPYING >bar && + cat "$TEST_DIRECTORY"/../Makefile >foo && + cat "$TEST_DIRECTORY"/../COPYING >bar && git add foo bar && git commit -a -m Sixth && git tag six diff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh index ba6679c6e4..1c2edebb09 100755 --- a/t/t4027-diff-submodule.sh +++ b/t/t4027-diff-submodule.sh @@ -3,7 +3,7 @@ test_description='difference in submodules' . ./test-lib.sh -. ../diff-lib.sh +. "$TEST_DIRECTORY"/diff-lib.sh _z40=0000000000000000000000000000000000000000 test_expect_success setup ' diff --git a/t/t4029-diff-trailing-space.sh b/t/t4029-diff-trailing-space.sh new file mode 100755 index 0000000000..4ca65e0332 --- /dev/null +++ b/t/t4029-diff-trailing-space.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# +# Copyright (c) Jim Meyering +# +test_description='diff honors config option, diff.suppress-blank-empty' + +. ./test-lib.sh + +cat <<\EOF > exp || +diff --git a/f b/f +index 5f6a263..8cb8bae 100644 +--- a/f ++++ b/f +@@ -1,2 +1,2 @@ + +-x ++y +EOF +exit 1 + +test_expect_success \ + "$test_description" \ + 'printf "\nx\n" > f && + git add f && + git commit -q -m. f && + printf "\ny\n" > f && + git config --bool diff.suppress-blank-empty true && + git diff f > actual && + test_cmp exp actual && + perl -i.bak -p -e "s/^\$/ /" exp && + git config --bool diff.suppress-blank-empty false && + git diff f > actual && + test_cmp exp actual && + git config --bool --unset diff.suppress-blank-empty && + git diff f > actual && + test_cmp exp actual + ' + +test_done diff --git a/t/t4100-apply-stat.sh b/t/t4100-apply-stat.sh index e0c67740a5..9b433de836 100755 --- a/t/t4100-apply-stat.sh +++ b/t/t4100-apply-stat.sh @@ -17,13 +17,13 @@ do test_expect_success "$title" ' git apply --stat --summary \ <"$TEST_DIRECTORY/t4100/t-apply-$num.patch" >current && - test_cmp ../t4100/t-apply-$num.expect current + test_cmp "$TEST_DIRECTORY"/t4100/t-apply-$num.expect current ' test_expect_success "$title with recount" ' sed -e "$UNC" <"$TEST_DIRECTORY/t4100/t-apply-$num.patch" | git apply --recount --stat --summary >current && - test_cmp ../t4100/t-apply-$num.expect current + test_cmp "$TEST_DIRECTORY"/t4100/t-apply-$num.expect current ' done <<\EOF rename diff --git a/t/t4101-apply-nonl.sh b/t/t4101-apply-nonl.sh index da8abcf364..e3443d004d 100755 --- a/t/t4101-apply-nonl.sh +++ b/t/t4101-apply-nonl.sh @@ -21,9 +21,10 @@ do do test $i -eq $j && continue cat frotz.$i >frotz - test_expect_success \ - "apply diff between $i and $j" \ - "git apply <../t4101/diff.$i-$j && diff frotz.$j frotz" + test_expect_success "apply diff between $i and $j" ' + git apply <"$TEST_DIRECTORY"/t4101/diff.$i-$j && + test_cmp frotz.$j frotz + ' done done diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh index 7da0b4bb8b..ad4cc1a757 100755 --- a/t/t4103-apply-binary.sh +++ b/t/t4103-apply-binary.sh @@ -21,16 +21,16 @@ cat file1 >file2 cat file1 >file4 git update-index --add --remove file1 file2 file4 -git-commit -m 'Initial Version' 2>/dev/null +git commit -m 'Initial Version' 2>/dev/null -git-checkout -b binary +git checkout -b binary perl -pe 'y/x/\000/' <file1 >file3 cat file3 >file4 git add file2 perl -pe 'y/\000/v/' <file3 >file1 rm -f file2 git update-index --add --remove file1 file2 file3 file4 -git-commit -m 'Second Version' +git commit -m 'Second Version' git diff-tree -p master binary >B.diff git diff-tree -p -C master binary >C.diff @@ -39,47 +39,47 @@ git diff-tree -p --binary master binary >BF.diff git diff-tree -p --binary -C master binary >CF.diff test_expect_success 'stat binary diff -- should not fail.' \ - 'git-checkout master + 'git checkout master git apply --stat --summary B.diff' test_expect_success 'stat binary diff (copy) -- should not fail.' \ - 'git-checkout master + 'git checkout master git apply --stat --summary C.diff' test_expect_success 'check binary diff -- should fail.' \ - 'git-checkout master && + 'git checkout master && test_must_fail git apply --check B.diff' test_expect_success 'check binary diff (copy) -- should fail.' \ - 'git-checkout master && + 'git checkout master && test_must_fail git apply --check C.diff' test_expect_success \ 'check incomplete binary diff with replacement -- should fail.' ' - git-checkout master && + git checkout master && test_must_fail git apply --check --allow-binary-replacement B.diff ' test_expect_success \ 'check incomplete binary diff with replacement (copy) -- should fail.' ' - git-checkout master && + git checkout master && test_must_fail git apply --check --allow-binary-replacement C.diff ' test_expect_success 'check binary diff with replacement.' \ - 'git-checkout master + 'git checkout master git apply --check --allow-binary-replacement BF.diff' test_expect_success 'check binary diff with replacement (copy).' \ - 'git-checkout master + 'git checkout master git apply --check --allow-binary-replacement CF.diff' # Now we start applying them. do_reset () { rm -f file? && - git-reset --hard && - git-checkout -f master + git reset --hard && + git checkout -f master } test_expect_success 'apply binary diff -- should fail.' \ diff --git a/t/t4104-apply-boundary.sh b/t/t4104-apply-boundary.sh index e7e2913de7..0e3ce3611d 100755 --- a/t/t4104-apply-boundary.sh +++ b/t/t4104-apply-boundary.sh @@ -27,6 +27,15 @@ test_expect_success setup ' git diff victim >add-a-patch.with && git diff --unified=0 >add-a-patch.without && + : insert at line two + for i in b a '"$L"' y + do + echo $i + done >victim && + cat victim >insert-a-expect && + git diff victim >insert-a-patch.with && + git diff --unified=0 >insert-a-patch.without && + : modify at the head for i in a '"$L"' y do @@ -55,7 +64,7 @@ test_expect_success setup ' git diff --unified=0 >add-z-patch.without && : modify at the tail - for i in a '"$L"' y + for i in b '"$L"' z do echo $i done >victim && @@ -81,7 +90,7 @@ do with) u= ;; without) u='--unidiff-zero ' ;; esac - for kind in add-a add-z mod-a mod-z del-a del-z + for kind in add-a add-z insert-a mod-a mod-z del-a del-z do test_expect_success "apply $kind-patch $with context" ' cat original >victim && @@ -95,7 +104,7 @@ do done done -for kind in add-a add-z mod-a mod-z del-a del-z +for kind in add-a add-z insert-a mod-a mod-z del-a del-z do rm -f $kind-ng.without sed -e "s/^diff --git /diff /" \ diff --git a/t/t4124-apply-ws-rule.sh b/t/t4124-apply-ws-rule.sh index 85f3da2b98..f83322e513 100755 --- a/t/t4124-apply-ws-rule.sh +++ b/t/t4124-apply-ws-rule.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='core.whitespace rules and git-apply' +test_description='core.whitespace rules and git apply' . ./test-lib.sh diff --git a/t/t4127-apply-same-fn.sh b/t/t4127-apply-same-fn.sh index 1f859dd908..3a8202ea93 100755 --- a/t/t4127-apply-same-fn.sh +++ b/t/t4127-apply-same-fn.sh @@ -26,7 +26,7 @@ test_expect_success 'apply same filename with independent changes' ' git diff >> patch0 && cp same_fn same_fn2 && git reset --hard && - git-apply patch0 && + git apply patch0 && diff same_fn same_fn2 ' @@ -39,7 +39,7 @@ test_expect_success 'apply same filename with overlapping changes' ' git diff >> patch0 && cp same_fn same_fn2 && git reset --hard && - git-apply patch0 && + git apply patch0 && diff same_fn same_fn2 ' diff --git a/t/t4150-am.sh b/t/t4150-am.sh index 6e6aaf5936..1be5fb3f9d 100755 --- a/t/t4150-am.sh +++ b/t/t4150-am.sh @@ -164,7 +164,7 @@ test_expect_success 'am --keep really keeps the subject' ' git checkout HEAD^ && git am --keep patch4 && ! test -d .git/rebase-apply && - git-cat-file commit HEAD | + git cat-file commit HEAD | grep -q -F "Re: Re: Re: [PATCH 1/5 v2] third" ' diff --git a/t/t4151-am-abort.sh b/t/t4151-am-abort.sh index 7d86cdff64..4448aba7e0 100755 --- a/t/t4151-am-abort.sh +++ b/t/t4151-am-abort.sh @@ -44,14 +44,14 @@ do ' test_expect_success "am$with3 --skip continue after failed am$with3" ' - test_must_fail git-am$with3 --skip >output && + test_must_fail git am$with3 --skip >output && test "$(grep "^Applying" output)" = "Applying: 6" && test_cmp file-2-expect file-2 && test ! -f .git/rr-cache/MERGE_RR ' test_expect_success "am --abort goes back after failed am$with3" ' - git-am --abort && + git am --abort && git rev-parse HEAD >actual && git rev-parse initial >expect && test_cmp expect actual && diff --git a/t/t4202-log.sh b/t/t4202-log.sh index 4c8af45f83..0ab925c4e4 100755 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@ -69,7 +69,29 @@ test_expect_success 'diff-filter=D' ' ' +test_expect_success 'setup case sensitivity tests' ' + echo case >one && + test_tick && + git commit -a -m Second +' + +test_expect_success 'log --grep' ' + echo second >expect && + git log -1 --pretty="tformat:%s" --grep=sec >actual && + test_cmp expect actual +' +test_expect_success 'log -i --grep' ' + echo Second >expect && + git log -1 --pretty="tformat:%s" -i --grep=sec >actual && + test_cmp expect actual +' + +test_expect_success 'log --grep -i' ' + echo Second >expect && + git log -1 --pretty="tformat:%s" --grep=sec -i >actual && + test_cmp expect actual +' test_done diff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh index 198e3503d5..fe14589427 100755 --- a/t/t5100-mailinfo.sh +++ b/t/t5100-mailinfo.sh @@ -8,27 +8,28 @@ test_description='git mailinfo and git mailsplit test' . ./test-lib.sh test_expect_success 'split sample box' \ - 'git mailsplit -o. ../t5100/sample.mbox >last && + 'git mailsplit -o. "$TEST_DIRECTORY"/t5100/sample.mbox >last && last=`cat last` && echo total is $last && test `cat last` = 11' for mail in `echo 00*` do - test_expect_success "mailinfo $mail" \ - "git mailinfo -u msg$mail patch$mail <$mail >info$mail && + test_expect_success "mailinfo $mail" ' + git mailinfo -u msg$mail patch$mail <$mail >info$mail && echo msg && - diff ../t5100/msg$mail msg$mail && + test_cmp "$TEST_DIRECTORY"/t5100/msg$mail msg$mail && echo patch && - diff ../t5100/patch$mail patch$mail && + test_cmp "$TEST_DIRECTORY"/t5100/patch$mail patch$mail && echo info && - diff ../t5100/info$mail info$mail" + test_cmp "$TEST_DIRECTORY"/t5100/info$mail info$mail + ' done test_expect_success 'respect NULs' ' - git mailsplit -d3 -o. ../t5100/nul-plain && - cmp ../t5100/nul-plain 001 && + git mailsplit -d3 -o. "$TEST_DIRECTORY"/t5100/nul-plain && + test_cmp "$TEST_DIRECTORY"/t5100/nul-plain 001 && (cat 001 | git mailinfo msg patch) && test 4 = $(wc -l < patch) @@ -36,10 +37,10 @@ test_expect_success 'respect NULs' ' test_expect_success 'Preserve NULs out of MIME encoded message' ' - git mailsplit -d5 -o. ../t5100/nul-b64.in && - cmp ../t5100/nul-b64.in 00001 && + git mailsplit -d5 -o. "$TEST_DIRECTORY"/t5100/nul-b64.in && + test_cmp "$TEST_DIRECTORY"/t5100/nul-b64.in 00001 && git mailinfo msg patch <00001 && - cmp ../t5100/nul-b64.expect patch + test_cmp "$TEST_DIRECTORY"/t5100/nul-b64.expect patch ' diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index 645583f9d7..3a0ef8759c 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -3,7 +3,7 @@ # Copyright (c) 2005 Junio C Hamano # -test_description='git-pack-object +test_description='git pack-object ' . ./test-lib.sh @@ -187,6 +187,12 @@ test_expect_success \ test-3-${packname_3}.idx' test_expect_success \ + 'verify pack -v' \ + 'git verify-pack -v test-1-${packname_1}.idx \ + test-2-${packname_2}.idx \ + test-3-${packname_3}.idx' + +test_expect_success \ 'verify-pack catches mismatched .idx and .pack files' \ 'cat test-1-${packname_1}.idx >test-3.idx && cat test-2-${packname_2}.pack >test-3.pack && @@ -236,24 +242,24 @@ test_expect_success \ test_expect_success \ 'build pack index for an existing pack' \ 'cat test-1-${packname_1}.pack >test-3.pack && - git-index-pack -o tmp.idx test-3.pack && + git index-pack -o tmp.idx test-3.pack && cmp tmp.idx test-1-${packname_1}.idx && - git-index-pack test-3.pack && + git index-pack test-3.pack && cmp test-3.idx test-1-${packname_1}.idx && cat test-2-${packname_2}.pack >test-3.pack && - git-index-pack -o tmp.idx test-2-${packname_2}.pack && + git index-pack -o tmp.idx test-2-${packname_2}.pack && cmp tmp.idx test-2-${packname_2}.idx && - git-index-pack test-3.pack && + git index-pack test-3.pack && cmp test-3.idx test-2-${packname_2}.idx && cat test-3-${packname_3}.pack >test-3.pack && - git-index-pack -o tmp.idx test-3-${packname_3}.pack && + git index-pack -o tmp.idx test-3-${packname_3}.pack && cmp tmp.idx test-3-${packname_3}.idx && - git-index-pack test-3.pack && + git index-pack test-3.pack && cmp test-3.idx test-3-${packname_3}.idx && :' @@ -266,7 +272,7 @@ test_expect_success \ test_expect_success \ 'make sure index-pack detects the SHA1 collision' \ - 'test_must_fail git-index-pack -o bad.idx test-3.pack' + 'test_must_fail git index-pack -o bad.idx test-3.pack' test_expect_success \ 'honor pack.packSizeLimit' \ diff --git a/t/t5301-sliding-window.sh b/t/t5301-sliding-window.sh index 073ac0c6f9..0a24e61ff9 100755 --- a/t/t5301-sliding-window.sh +++ b/t/t5301-sliding-window.sh @@ -19,7 +19,7 @@ test_expect_success \ tree=`git write-tree` && commit1=`git commit-tree $tree </dev/null` && git update-ref HEAD $commit1 && - git-repack -a -d && + git repack -a -d && test "`git count-objects`" = "0 objects, 0 kilobytes" && pack1=`ls .git/objects/pack/*.pack` && test -f "$pack1"' @@ -45,7 +45,7 @@ test_expect_success \ git config core.packedGitLimit 512 && commit2=`git commit-tree $tree -p $commit1 </dev/null` && git update-ref HEAD $commit2 && - git-repack -a -d && + git repack -a -d && test "`git count-objects`" = "0 objects, 0 kilobytes" && pack2=`ls .git/objects/pack/*.pack` && test -f "$pack2" diff --git a/t/t5302-pack-index.sh b/t/t5302-pack-index.sh index 0639772ac4..6424db1f28 100755 --- a/t/t5302-pack-index.sh +++ b/t/t5302-pack-index.sh @@ -48,11 +48,11 @@ test_expect_success \ test_expect_success \ 'index-pack with index version 1' \ - 'git-index-pack --index-version=1 -o 1.idx "test-1-${pack1}.pack"' + 'git index-pack --index-version=1 -o 1.idx "test-1-${pack1}.pack"' test_expect_success \ 'index-pack with index version 2' \ - 'git-index-pack --index-version=2 -o 2.idx "test-1-${pack1}.pack"' + 'git index-pack --index-version=2 -o 2.idx "test-1-${pack1}.pack"' test_expect_success \ 'index-pack results should match pack-objects ones' \ @@ -85,7 +85,7 @@ test_expect_success \ test "$have_64bits" && test_expect_success \ 'index v2: force some 64-bit offsets with index-pack' \ - 'git-index-pack --index-version=2,0x40000 -o 3.idx "test-1-${pack1}.pack"' + 'git index-pack --index-version=2,0x40000 -o 3.idx "test-1-${pack1}.pack"' test "$have_64bits" && test_expect_success \ @@ -94,7 +94,7 @@ test_expect_success \ test_expect_success \ '[index v1] 1) stream pack to repository' \ - 'git-index-pack --index-version=1 --stdin < "test-1-${pack1}.pack" && + 'git index-pack --index-version=1 --stdin < "test-1-${pack1}.pack" && git prune-packed && git count-objects | ( read nr rest && test "$nr" -eq 1 ) && cmp "test-1-${pack1}.pack" ".git/objects/pack/pack-${pack1}.pack" && @@ -132,7 +132,7 @@ test_expect_success \ test_expect_success \ '[index v2] 1) stream pack to repository' \ 'rm -f .git/objects/pack/* && - git-index-pack --index-version=2 --stdin < "test-1-${pack1}.pack" && + git index-pack --index-version=2 --stdin < "test-1-${pack1}.pack" && git prune-packed && git count-objects | ( read nr rest && test "$nr" -eq 1 ) && cmp "test-1-${pack1}.pack" ".git/objects/pack/pack-${pack1}.pack" && @@ -165,7 +165,7 @@ test_expect_success \ test_expect_success \ '[index v2] 6) verify-pack detects CRC mismatch' \ 'rm -f .git/objects/pack/* && - git-index-pack --index-version=2 --stdin < "test-1-${pack1}.pack" && + git index-pack --index-version=2 --stdin < "test-1-${pack1}.pack" && git verify-pack ".git/objects/pack/pack-${pack1}.pack" && chmod +w ".git/objects/pack/pack-${pack1}.idx" && dd if=/dev/zero of=".git/objects/pack/pack-${pack1}.idx" conv=notrunc \ diff --git a/t/t5305-include-tag.sh b/t/t5305-include-tag.sh index fb471a08c6..b061864a87 100755 --- a/t/t5305-include-tag.sh +++ b/t/t5305-include-tag.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-pack-object --include-tag' +test_description='git pack-object --include-tag' . ./test-lib.sh TRASH=`pwd` diff --git a/t/t5306-pack-nobase.sh b/t/t5306-pack-nobase.sh new file mode 100755 index 0000000000..f4931c0c2a --- /dev/null +++ b/t/t5306-pack-nobase.sh @@ -0,0 +1,80 @@ +#!/bin/sh +# +# Copyright (c) 2008 Google Inc. +# + +test_description='git-pack-object with missing base + +' +. ./test-lib.sh + +# Create A-B chain +# +test_expect_success \ + 'setup base' \ + 'for a in a b c d e f g h i; do echo $a >>text; done && + echo side >side && + git update-index --add text side && + A=$(echo A | git commit-tree $(git write-tree)) && + + echo m >>text && + git update-index text && + B=$(echo B | git commit-tree $(git write-tree) -p $A) && + git update-ref HEAD $B + ' + +# Create repository with C whose parent is B. +# Repository contains C, C^{tree}, C:text, B, B^{tree}. +# Repository is missing B:text (best delta base for C:text). +# Repository is missing A (parent of B). +# Repository is missing A:side. +# +test_expect_success \ + 'setup patch_clone' \ + 'base_objects=$(pwd)/.git/objects && + (mkdir patch_clone && + cd patch_clone && + git init && + echo "$base_objects" >.git/objects/info/alternates && + echo q >>text && + git read-tree $B && + git update-index text && + git update-ref HEAD $(echo C | git commit-tree $(git write-tree) -p $B) && + rm .git/objects/info/alternates && + + git --git-dir=../.git cat-file commit $B | + git hash-object -t commit -w --stdin && + + git --git-dir=../.git cat-file tree "$B^{tree}" | + git hash-object -t tree -w --stdin + ) && + C=$(git --git-dir=patch_clone/.git rev-parse HEAD) + ' + +# Clone patch_clone indirectly by cloning base and fetching. +# +test_expect_success \ + 'indirectly clone patch_clone' \ + '(mkdir user_clone && + cd user_clone && + git init && + git pull ../.git && + test $(git rev-parse HEAD) = $B && + + git pull ../patch_clone/.git && + test $(git rev-parse HEAD) = $C + ) + ' + +# Cloning the patch_clone directly should fail. +# +test_expect_success \ + 'clone of patch_clone is incomplete' \ + '(mkdir user_direct && + cd user_direct && + git init && + test_must_fail git fetch ../patch_clone/.git + ) + ' + +test_done diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh index 68c2ae688c..544771d8fa 100755 --- a/t/t5400-send-pack.sh +++ b/t/t5400-send-pack.sh @@ -31,7 +31,7 @@ test_expect_success setup ' parent=$commit || return 1 done && git update-ref HEAD "$commit" && - git-clone ./. victim && + git clone ./. victim && cd victim && git log && cd .. && @@ -68,7 +68,7 @@ test_expect_success 'pack the destination repository' ' test_expect_success \ 'pushing rewound head should not barf but require --force' ' # should not fail but refuse to update. - if git-send-pack ./victim/.git/ master + if git send-pack ./victim/.git/ master then # now it should fail with Pasky patch echo >&2 Gaah, it should have failed. @@ -85,7 +85,7 @@ test_expect_success \ true fi && # this should update - git-send-pack --force ./victim/.git/ master && + git send-pack --force ./victim/.git/ master && cmp victim/.git/refs/heads/master .git/refs/heads/master ' @@ -95,7 +95,7 @@ test_expect_success \ git branch extra master && cd .. && test -f victim/.git/refs/heads/extra && - git-send-pack ./victim/.git/ :extra master && + git send-pack ./victim/.git/ :extra master && ! test -f victim/.git/refs/heads/extra ' @@ -109,27 +109,27 @@ test_expect_success \ git config receive.denyNonFastforwards true && cd .. && git update-ref refs/heads/master master^ || return 1 - git-send-pack --force ./victim/.git/ master && return 1 + git send-pack --force ./victim/.git/ master && return 1 ! test_cmp .git/refs/heads/master victim/.git/refs/heads/master ' test_expect_success \ 'pushing does not include non-head refs' ' mkdir parent && cd parent && - git-init && touch file && git-add file && git-commit -m add && + git init && touch file && git add file && git commit -m add && cd .. && - git-clone parent child && cd child && git-push --all && + git clone parent child && cd child && git push --all && cd ../parent && - git-branch -a >branches && ! grep origin/master branches + git branch -a >branches && ! grep origin/master branches ' rewound_push_setup() { rm -rf parent child && mkdir parent && cd parent && - git-init && echo one >file && git-add file && git-commit -m one && - echo two >file && git-commit -a -m two && + git init && echo one >file && git add file && git commit -m one && + echo two >file && git commit -a -m two && cd .. && - git-clone parent child && cd child && git-reset --hard HEAD^ + git clone parent child && cd child && git reset --hard HEAD^ } rewound_push_succeeded() { @@ -148,26 +148,26 @@ rewound_push_failed() { test_expect_success \ 'pushing explicit refspecs respects forcing' ' rewound_push_setup && - if git-send-pack ../parent/.git refs/heads/master:refs/heads/master + if git send-pack ../parent/.git refs/heads/master:refs/heads/master then false else true fi && rewound_push_failed && - git-send-pack ../parent/.git +refs/heads/master:refs/heads/master && + git send-pack ../parent/.git +refs/heads/master:refs/heads/master && rewound_push_succeeded ' test_expect_success \ 'pushing wildcard refspecs respects forcing' ' rewound_push_setup && - if git-send-pack ../parent/.git refs/heads/*:refs/heads/* + if git send-pack ../parent/.git refs/heads/*:refs/heads/* then false else true fi && rewound_push_failed && - git-send-pack ../parent/.git +refs/heads/*:refs/heads/* && + git send-pack ../parent/.git +refs/heads/*:refs/heads/* && rewound_push_succeeded ' diff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh index ee769d6695..64f66c94f3 100755 --- a/t/t5401-update-hooks.sh +++ b/t/t5401-update-hooks.sh @@ -17,7 +17,7 @@ test_expect_success setup ' commit1=$(echo modify | git commit-tree $tree1 -p $commit0) && git update-ref refs/heads/master $commit0 && git update-ref refs/heads/tofail $commit1 && - git-clone ./. victim && + git clone ./. victim && GIT_DIR=victim/.git git update-ref refs/heads/tofail $commit1 && git update-ref refs/heads/master $commit1 && git update-ref refs/heads/tofail $commit0 @@ -61,7 +61,7 @@ EOF chmod u+x victim/.git/hooks/post-update test_expect_success push ' - test_must_fail git-send-pack --force ./victim/.git \ + test_must_fail git send-pack --force ./victim/.git \ master tofail >send.out 2>send.err ' diff --git a/t/t5402-post-merge-hook.sh b/t/t5402-post-merge-hook.sh index 1394047a8d..6eb2ffd6ec 100755 --- a/t/t5402-post-merge-hook.sh +++ b/t/t5402-post-merge-hook.sh @@ -16,9 +16,9 @@ test_expect_success setup ' tree1=$(git write-tree) && commit1=$(echo modify | git commit-tree $tree1 -p $commit0) && git update-ref refs/heads/master $commit0 && - git-clone ./. clone1 && + git clone ./. clone1 && GIT_DIR=clone1/.git git update-index --add a && - git-clone ./. clone2 && + git clone ./. clone2 && GIT_DIR=clone2/.git git update-index --add a ' diff --git a/t/t5403-post-checkout-hook.sh b/t/t5403-post-checkout-hook.sh index 823239a251..9b2e1a94c5 100755 --- a/t/t5403-post-checkout-hook.sh +++ b/t/t5403-post-checkout-hook.sh @@ -14,8 +14,8 @@ test_expect_success setup ' tree0=$(git write-tree) && commit0=$(echo setup | git commit-tree $tree0) && git update-ref refs/heads/master $commit0 && - git-clone ./. clone1 && - git-clone ./. clone2 && + git clone ./. clone1 && + git clone ./. clone2 && GIT_DIR=clone2/.git git branch -a new2 && echo Data for commit1. >clone2/b && GIT_DIR=clone2/.git git add clone2/b && diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh index 362cf7e928..c450f33f33 100755 --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@ -58,7 +58,7 @@ pull_to_client () { cd client test_expect_success "$number pull" \ - "git-fetch-pack -k -v .. $heads" + "git fetch-pack -k -v .. $heads" case "$heads" in *A*) echo $ATIP > .git/refs/heads/A;; esac case "$heads" in *B*) echo $BTIP > .git/refs/heads/B;; esac git symbolic-ref HEAD refs/heads/`echo $heads | sed -e 's/^\(.\).*$/\1/'` @@ -129,7 +129,7 @@ pull_to_client 2nd "B" $((64*3)) pull_to_client 3rd "A" $((1*3)) # old fails -test_expect_success "clone shallow" 'git-clone --depth 2 "file://$(pwd)/." shallow' +test_expect_success "clone shallow" 'git clone --depth 2 "file://$(pwd)/." shallow' (cd shallow; git count-objects -v) > count.shallow @@ -137,7 +137,7 @@ test_expect_success "clone shallow object count" \ "test \"in-pack: 18\" = \"$(grep in-pack count.shallow)\"" count_output () { - sed -e '/^in-pack:/d' -e '/^packs:/d' -e '/: 0$/d' "$1" + sed -e '/^in-pack:/d' -e '/^packs:/d' -e '/^size-pack:/d' -e '/: 0$/d' "$1" } test_expect_success "clone shallow object count (part 2)" ' diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index be9ee9326f..c4496635df 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -109,7 +109,7 @@ test_expect_success 'remove remote' ' cat > test/expect << EOF * remote origin - URL: $(pwd)/one/.git + URL: $(pwd)/one Remote branch merged with 'git pull' while on branch master master New remote branch (next fetch will store in remotes/origin) @@ -140,7 +140,7 @@ test_expect_success 'show' ' cat > test/expect << EOF * remote origin - URL: $(pwd)/one/.git + URL: $(pwd)/one Remote branch merged with 'git pull' while on branch master master Tracked remote branches @@ -169,7 +169,7 @@ test_expect_success 'prune' ' cat > test/expect << EOF Pruning origin -URL: $(pwd)/one/.git +URL: $(pwd)/one * [would prune] origin/side2 EOF diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 13d1d826c2..de26c20327 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -111,7 +111,7 @@ test_expect_success 'fetch must not resolve short tag name' ' test_expect_success 'fetch must not resolve short remote name' ' cd "$D" && - git-update-ref refs/remotes/six/HEAD HEAD + git update-ref refs/remotes/six/HEAD HEAD mkdir six && cd six && diff --git a/t/t5515-fetch-merge-logic.sh b/t/t5515-fetch-merge-logic.sh index 8becbc3f38..1f4608d8ba 100755 --- a/t/t5515-fetch-merge-logic.sh +++ b/t/t5515-fetch-merge-logic.sh @@ -131,9 +131,9 @@ do test=`echo "$cmd" | sed -e 's|[/ ][/ ]*|_|g'` cnt=`expr $test_count + 1` pfx=`printf "%04d" $cnt` - expect_f="../../t5515/fetch.$test" + expect_f="$TEST_DIRECTORY/t5515/fetch.$test" actual_f="$pfx-fetch.$test" - expect_r="../../t5515/refs.$test" + expect_r="$TEST_DIRECTORY/t5515/refs.$test" actual_r="$pfx-refs.$test" test_expect_success "$cmd" ' diff --git a/t/t5530-upload-pack-error.sh b/t/t5530-upload-pack-error.sh index 1a15817cd5..f5102b902a 100755 --- a/t/t5530-upload-pack-error.sh +++ b/t/t5530-upload-pack-error.sh @@ -34,7 +34,7 @@ test_expect_success 'upload-pack fails due to error in pack-objects' ' ! echo "0032want $(git rev-parse HEAD) 00000009done -0000" | git-upload-pack . > /dev/null 2> output.err && +0000" | git upload-pack . > /dev/null 2> output.err && grep "pack-objects died" output.err ' @@ -52,7 +52,7 @@ test_expect_success 'upload-pack fails due to error in rev-list' ' ! echo "0032want $(git rev-parse HEAD) 00000009done -0000" | git-upload-pack . > /dev/null 2> output.err && +0000" | git upload-pack . > /dev/null 2> output.err && grep "waitpid (async) failed" output.err ' diff --git a/t/t5540-http-push.sh b/t/t5540-http-push.sh index b0d242e3ed..da9588645c 100755 --- a/t/t5540-http-push.sh +++ b/t/t5540-http-push.sh @@ -19,7 +19,7 @@ then exit fi -. ../lib-httpd.sh +. "$TEST_DIRECTORY"/lib-httpd.sh if ! start_httpd >&3 2>&4 then diff --git a/t/t5600-clone-fail-cleanup.sh b/t/t5600-clone-fail-cleanup.sh index 3c013e2b6a..ee06d28649 100755 --- a/t/t5600-clone-fail-cleanup.sh +++ b/t/t5600-clone-fail-cleanup.sh @@ -3,9 +3,9 @@ # Copyright (C) 2006 Carl D. Worth <cworth@cworth.org> # -test_description='test git-clone to cleanup after failure +test_description='test git clone to cleanup after failure -This test covers the fact that if git-clone fails, it should remove +This test covers the fact that if git clone fails, it should remove the directory it created, to avoid the user having to manually remove the directory before attempting a clone again.' @@ -13,7 +13,7 @@ remove the directory before attempting a clone again.' test_expect_success \ 'clone of non-existent source should fail' \ - 'test_must_fail git-clone foo bar' + 'test_must_fail git clone foo bar' test_expect_success \ 'failed clone should not leave a directory' \ @@ -25,15 +25,15 @@ test_create_repo foo # clone doesn't like it if there is no HEAD. Is that a bug? (cd foo && touch file && git add file && git commit -m 'add file' >/dev/null 2>&1) -# source repository given to git-clone should be relative to the +# source repository given to git clone should be relative to the # current path not to the target dir test_expect_success \ 'clone of non-existent (relative to $PWD) source should fail' \ - 'test_must_fail git-clone ../foo baz' + 'test_must_fail git clone ../foo baz' test_expect_success \ 'clone should work now that source exists' \ - 'git-clone foo bar' + 'git clone foo bar' test_expect_success \ 'successful clone must leave the directory' \ diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh index 59c65fef28..78a3fa639c 100755 --- a/t/t5601-clone.sh +++ b/t/t5601-clone.sh @@ -107,4 +107,22 @@ test_expect_success 'clone --mirror does not repeat tags' ' ' +test_expect_success 'clone to destination with trailing /' ' + + git clone src target-1/ && + T=$( cd target-1 && git rev-parse HEAD ) && + S=$( cd src && git rev-parse HEAD ) && + test "$T" = "$S" + +' + +test_expect_success 'clone to destination with extra trailing /' ' + + git clone src target-2/// && + T=$( cd target-2 && git rev-parse HEAD ) && + S=$( cd src && git rev-parse HEAD ) && + test "$T" = "$S" + +' + test_done diff --git a/t/t5602-clone-remote-exec.sh b/t/t5602-clone-remote-exec.sh index 8367a6845f..82b1d1e2b3 100755 --- a/t/t5602-clone-remote-exec.sh +++ b/t/t5602-clone-remote-exec.sh @@ -11,13 +11,13 @@ test_expect_success setup ' chmod +x not_ssh ' -test_expect_success 'clone calls git-upload-pack unqualified with no -u option' ' +test_expect_success 'clone calls git upload-pack unqualified with no -u option' ' GIT_SSH=./not_ssh git clone localhost:/path/to/repo junk echo "localhost git-upload-pack '\''/path/to/repo'\''" >expected test_cmp expected not_ssh_output ' -test_expect_success 'clone calls specified git-upload-pack with -u option' ' +test_expect_success 'clone calls specified git upload-pack with -u option' ' GIT_SSH=./not_ssh git clone -u /something/bin/git-upload-pack localhost:/path/to/repo junk echo "localhost /something/bin/git-upload-pack '\''/path/to/repo'\''" >expected test_cmp expected not_ssh_output diff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh index 8f5de097ec..b4e8fbaa5e 100755 --- a/t/t6002-rev-list-bisect.sh +++ b/t/t6002-rev-list-bisect.sh @@ -5,7 +5,7 @@ test_description='Tests git rev-list --bisect functionality' . ./test-lib.sh -. ../t6000lib.sh # t6xxx specific functions +. "$TEST_DIRECTORY"/t6000lib.sh # t6xxx specific functions # usage: test_bisection max-diff bisect-option head ^prune... # diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh index 5daa0be8cc..2c73f2da7b 100755 --- a/t/t6003-rev-list-topo-order.sh +++ b/t/t6003-rev-list-topo-order.sh @@ -6,7 +6,7 @@ test_description='Tests git rev-list --topo-order functionality' . ./test-lib.sh -. ../t6000lib.sh # t6xxx specific functions +. "$TEST_DIRECTORY"/t6000lib.sh # t6xxx specific functions list_duplicates() { diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh index 9176484db2..86bf7e14ba 100755 --- a/t/t6006-rev-list-format.sh +++ b/t/t6006-rev-list-format.sh @@ -6,8 +6,8 @@ test_description='git rev-list --pretty=format test' test_tick test_expect_success 'setup' ' -touch foo && git add foo && git-commit -m "added foo" && - echo changed >foo && git-commit -a -m "changed foo" +touch foo && git add foo && git commit -m "added foo" && + echo changed >foo && git commit -a -m "changed foo" ' # usage: test_format name format_string <expected_output @@ -110,7 +110,7 @@ include an iso8859 character: ¡bueno! EOF test_expect_success 'setup complex body' ' git config i18n.commitencoding iso8859-1 && - echo change2 >foo && git-commit -a -F commit-msg + echo change2 >foo && git commit -a -F commit-msg ' test_format complex-encoding %e <<'EOF' @@ -139,6 +139,12 @@ commit 131a310eb913d107dd3c09a65d1651175898735d commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873 EOF +test_expect_success '%ad respects --date=' ' + echo 2005-04-07 >expect.ad-short && + git log -1 --date=short --pretty=tformat:%ad >output.ad-short master && + test_cmp expect.ad-short output.ad-short +' + test_expect_success 'empty email' ' test_tick && C=$(GIT_AUTHOR_EMAIL= git commit-tree HEAD^{tree} </dev/null) && diff --git a/t/t6010-merge-base.sh b/t/t6010-merge-base.sh index b6e57b2426..04e4b7c5c2 100755 --- a/t/t6010-merge-base.sh +++ b/t/t6010-merge-base.sh @@ -108,4 +108,52 @@ test_expect_success 'compute merge-base (all)' \ 'MB=$(git merge-base --all PL PR) && expr "$(git name-rev "$MB")" : "[0-9a-f]* tags/C2"' +# Another set to demonstrate base between one commit and a merge +# in the documentation. + +test_expect_success 'merge-base for octopus-step (setup)' ' + test_tick && git commit --allow-empty -m root && git tag MMR && + test_tick && git commit --allow-empty -m 1 && git tag MM1 && + test_tick && git commit --allow-empty -m o && + test_tick && git commit --allow-empty -m o && + test_tick && git commit --allow-empty -m o && + test_tick && git commit --allow-empty -m A && git tag MMA && + git checkout MM1 && + test_tick && git commit --allow-empty -m o && + test_tick && git commit --allow-empty -m o && + test_tick && git commit --allow-empty -m o && + test_tick && git commit --allow-empty -m B && git tag MMB && + git checkout MMR && + test_tick && git commit --allow-empty -m o && + test_tick && git commit --allow-empty -m o && + test_tick && git commit --allow-empty -m o && + test_tick && git commit --allow-empty -m o && + test_tick && git commit --allow-empty -m C && git tag MMC +' + +test_expect_success 'merge-base A B C' ' + MB=$(git merge-base --all MMA MMB MMC) && + MM1=$(git rev-parse --verify MM1) && + test "$MM1" = "$MB" +' + +test_expect_success 'criss-cross merge-base for octopus-step (setup)' ' + git reset --hard MMR && + test_tick && git commit --allow-empty -m 1 && git tag CC1 && + git reset --hard E && + test_tick && git commit --allow-empty -m 2 && git tag CC2 && + test_tick && git merge -s ours CC1 && + test_tick && git commit --allow-empty -m o && + test_tick && git commit --allow-empty -m B && git tag CCB && + git reset --hard CC1 && + test_tick && git merge -s ours CC2 && + test_tick && git commit --allow-empty -m A && git tag CCA +' + +test_expect_success 'merge-base B A^^ A^^2' ' + MB0=$(git merge-base --all CCB CCA^^ CCA^^2 | sort) && + MB1=$(git rev-parse CC1 CC2 | sort) && + test "$MB0" = "$MB1" +' + test_done diff --git a/t/t6012-rev-list-simplify.sh b/t/t6012-rev-list-simplify.sh new file mode 100755 index 0000000000..510bb9679f --- /dev/null +++ b/t/t6012-rev-list-simplify.sh @@ -0,0 +1,93 @@ +#!/bin/sh + +test_description='merge simplification' + +. ./test-lib.sh + +note () { + git tag "$1" +} + +_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' +_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" + +unnote () { + git name-rev --tags --stdin | sed -e "s|$_x40 (tags/\([^)]*\)) |\1 |g" +} + +test_expect_success setup ' + echo "Hi there" >file && + git add file && + test_tick && git commit -m "Initial file" && + note A && + + git branch other-branch && + + echo "Hello" >file && + git add file && + test_tick && git commit -m "Modified file" && + note B && + + git checkout other-branch && + + echo "Hello" >file && + git add file && + test_tick && git commit -m "Modified the file identically" && + note C && + + echo "This is a stupid example" >another-file && + git add another-file && + test_tick && git commit -m "Add another file" && + note D && + + test_tick && git merge -m "merge" master && + note E && + + echo "Yet another" >elif && + git add elif && + test_tick && git commit -m "Irrelevant change" && + note F && + + git checkout master && + echo "Yet another" >elif && + git add elif && + test_tick && git commit -m "Another irrelevant change" && + note G && + + test_tick && git merge -m "merge" other-branch && + note H && + + echo "Final change" >file && + test_tick && git commit -a -m "Final change" && + note I +' + +FMT='tformat:%P %H | %s' + +check_result () { + for c in $1 + do + echo "$c" + done >expect && + shift && + param="$*" && + test_expect_success "log $param" ' + git log --pretty="$FMT" --parents $param | + unnote >actual && + sed -e "s/^.* \([^ ]*\) .*/\1/" >check <actual && + test_cmp expect check || { + cat actual + false + } + ' +} + +check_result 'I H G F E D C B A' --full-history +check_result 'I H E C B A' --full-history -- file +check_result 'I H E C B A' --full-history --topo-order -- file +check_result 'I H E C B A' --full-history --date-order -- file +check_result 'I E C B A' --simplify-merges -- file +check_result 'I B A' -- file +check_result 'I B A' --topo-order -- file + +test_done diff --git a/t/t6023-merge-file.sh b/t/t6023-merge-file.sh index f674c48cab..5e18d68c97 100755 --- a/t/t6023-merge-file.sh +++ b/t/t6023-merge-file.sh @@ -136,7 +136,7 @@ test_expect_success "expected conflict markers" "test_cmp expect out" test_expect_success 'binary files cannot be merged' ' test_must_fail git merge-file -p \ - orig.txt ../test4012.png new1.txt 2> merge.err && + orig.txt "$TEST_DIRECTORY"/test4012.png new1.txt 2> merge.err && grep "Cannot merge binary files" merge.err ' @@ -150,8 +150,8 @@ test_expect_success 'MERGE_ZEALOUS simplifies non-conflicts' ' ' -sed -e 's/deerit./&\n\n\n\n/' -e "s/locavit,/locavit;/" < new6.txt > new8.txt -sed -e 's/deerit./&\n\n\n\n/' -e "s/locavit,/locavit --/" < new7.txt > new9.txt +sed -e 's/deerit./&%%%%/' -e "s/locavit,/locavit;/"< new6.txt | tr '%' '\012' > new8.txt +sed -e 's/deerit./&%%%%/' -e "s/locavit,/locavit --/" < new7.txt | tr '%' '\012' > new9.txt test_expect_success 'ZEALOUS_ALNUM' ' diff --git a/t/t6025-merge-symlinks.sh b/t/t6025-merge-symlinks.sh index fc58456a11..53892a555c 100755 --- a/t/t6025-merge-symlinks.sh +++ b/t/t6025-merge-symlinks.sh @@ -5,7 +5,7 @@ test_description='merging symlinks on filesystem w/o symlink support. -This tests that git-merge-recursive writes merge results as plain files +This tests that git merge-recursive writes merge results as plain files if core.symlinks is false.' . ./test-lib.sh @@ -15,25 +15,25 @@ test_expect_success \ git config core.symlinks false && > file && git add file && -git-commit -m initial && +git commit -m initial && git branch b-symlink && git branch b-file && -l=$(echo -n file | git-hash-object -t blob -w --stdin) && +l=$(echo -n file | git hash-object -t blob -w --stdin) && echo "120000 $l symlink" | git update-index --index-info && -git-commit -m master && -git-checkout b-symlink && -l=$(echo -n file-different | git-hash-object -t blob -w --stdin) && +git commit -m master && +git checkout b-symlink && +l=$(echo -n file-different | git hash-object -t blob -w --stdin) && echo "120000 $l symlink" | git update-index --index-info && -git-commit -m b-symlink && -git-checkout b-file && +git commit -m b-symlink && +git checkout b-file && echo plain-file > symlink && git add symlink && -git-commit -m b-file' +git commit -m b-file' test_expect_success \ 'merge master into b-symlink, which has a different symbolic link' ' -git-checkout b-symlink && -test_must_fail git-merge master' +git checkout b-symlink && +test_must_fail git merge master' test_expect_success \ 'the merge result must be a file' ' @@ -41,8 +41,8 @@ test -f symlink' test_expect_success \ 'merge master into b-file, which has a file instead of a symbolic link' ' -git-reset --hard && git-checkout b-file && -test_must_fail git-merge master' +git reset --hard && git checkout b-file && +test_must_fail git merge master' test_expect_success \ 'the merge result must be a file' ' @@ -50,9 +50,9 @@ test -f symlink' test_expect_success \ 'merge b-file, which has a file instead of a symbolic link, into master' ' -git-reset --hard && -git-checkout master && -test_must_fail git-merge b-file' +git reset --hard && +git checkout master && +test_must_fail git merge b-file' test_expect_success \ 'the merge result must be a file' ' diff --git a/t/t6026-merge-attr.sh b/t/t6026-merge-attr.sh index 56fc341768..4b423e937d 100755 --- a/t/t6026-merge-attr.sh +++ b/t/t6026-merge-attr.sh @@ -106,9 +106,9 @@ test_expect_success 'custom merge backend' ' cmp binary union && sed -e 1,3d text >check-1 && - o=$(git-unpack-file master^:text) && - a=$(git-unpack-file side^:text) && - b=$(git-unpack-file master:text) && + o=$(git unpack-file master^:text) && + a=$(git unpack-file side^:text) && + b=$(git unpack-file master:text) && sh -c "./custom-merge $o $a $b 0" && sed -e 1,3d $a >check-2 && cmp check-1 check-2 && @@ -133,9 +133,9 @@ test_expect_success 'custom merge backend' ' cmp binary union && sed -e 1,3d text >check-1 && - o=$(git-unpack-file master^:text) && - a=$(git-unpack-file anchor:text) && - b=$(git-unpack-file master:text) && + o=$(git unpack-file master^:text) && + a=$(git unpack-file anchor:text) && + b=$(git unpack-file master:text) && sh -c "./custom-merge $o $a $b 0" && sed -e 1,3d $a >check-2 && cmp check-1 check-2 && diff --git a/t/t6027-merge-binary.sh b/t/t6027-merge-binary.sh index 92ca1f0f8c..b519626ca0 100755 --- a/t/t6027-merge-binary.sh +++ b/t/t6027-merge-binary.sh @@ -6,7 +6,7 @@ test_description='ask merge-recursive to merge binary files' test_expect_success setup ' - cat ../test4012.png >m && + cat "$TEST_DIRECTORY"/test4012.png >m && git add m && git ls-files -s | sed -e "s/ 0 / 1 /" >E1 && test_tick && diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh index 244fda62a5..36c9a6965f 100755 --- a/t/t6030-bisect-porcelain.sh +++ b/t/t6030-bisect-porcelain.sh @@ -2,7 +2,7 @@ # # Copyright (c) 2007 Christian Couder # -test_description='Tests git-bisect functionality' +test_description='Tests git bisect functionality' exec </dev/null @@ -23,7 +23,7 @@ add_line_into_file() fi test_tick - git-commit --quiet -m "$MSG" $_file + git commit --quiet -m "$MSG" $_file } HASH1= diff --git a/t/t6101-rev-parse-parents.sh b/t/t6101-rev-parse-parents.sh index 919552a2fc..f105fab98e 100755 --- a/t/t6101-rev-parse-parents.sh +++ b/t/t6101-rev-parse-parents.sh @@ -6,7 +6,7 @@ test_description='Test git rev-parse with different parent options' . ./test-lib.sh -. ../t6000lib.sh # t6xxx specific functions +. "$TEST_DIRECTORY"/t6000lib.sh # t6xxx specific functions date >path0 git update-index --add path0 diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh index 2fb672c3b4..16cc635813 100755 --- a/t/t6120-describe.sh +++ b/t/t6120-describe.sh @@ -31,57 +31,57 @@ check_describe () { test_expect_success setup ' test_tick && - echo one >file && git add file && git-commit -m initial && + echo one >file && git add file && git commit -m initial && one=$(git rev-parse HEAD) && test_tick && - echo two >file && git add file && git-commit -m second && + echo two >file && git add file && git commit -m second && two=$(git rev-parse HEAD) && test_tick && - echo three >file && git add file && git-commit -m third && + echo three >file && git add file && git commit -m third && test_tick && - echo A >file && git add file && git-commit -m A && + echo A >file && git add file && git commit -m A && test_tick && - git-tag -a -m A A && + git tag -a -m A A && test_tick && - echo c >file && git add file && git-commit -m c && + echo c >file && git add file && git commit -m c && test_tick && - git-tag c && + git tag c && git reset --hard $two && test_tick && - echo B >side && git add side && git-commit -m B && + echo B >side && git add side && git commit -m B && test_tick && - git-tag -a -m B B && + git tag -a -m B B && test_tick && - git-merge -m Merged c && + git merge -m Merged c && merged=$(git rev-parse HEAD) && git reset --hard $two && test_tick && - echo D >another && git add another && git-commit -m D && + echo D >another && git add another && git commit -m D && test_tick && - git-tag -a -m D D && + git tag -a -m D D && test_tick && echo DD >another && git commit -a -m another && test_tick && - git-tag e && + git tag e && test_tick && echo DDD >another && git commit -a -m "yet another" && test_tick && - git-merge -m Merged $merged && + git merge -m Merged $merged && test_tick && echo X >file && echo X >side && git add file side && - git-commit -m x + git commit -m x ' diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh index bc74349416..8f5a06f7dd 100755 --- a/t/t6200-fmt-merge-msg.sh +++ b/t/t6200-fmt-merge-msg.sh @@ -83,13 +83,13 @@ test_expect_success 'merge-msg test #1' ' ' cat >expected <<EOF -Merge branch 'left' of ../$test +Merge branch 'left' of $TEST_DIRECTORY/$test EOF test_expect_success 'merge-msg test #2' ' git checkout master && - git fetch ../"$test" left && + git fetch "$TEST_DIRECTORY/$test" left && git fmt-merge-msg <.git/FETCH_HEAD >actual && test_cmp expected actual diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh index 8ced59321e..26995b3cdd 100755 --- a/t/t6300-for-each-ref.sh +++ b/t/t6300-for-each-ref.sh @@ -97,27 +97,27 @@ test_atom tag contents 'Tagging at 1151939927 ' test_expect_success 'Check invalid atoms names are errors' ' - test_must_fail git-for-each-ref --format="%(INVALID)" refs/heads + test_must_fail git for-each-ref --format="%(INVALID)" refs/heads ' test_expect_success 'Check format specifiers are ignored in naming date atoms' ' - git-for-each-ref --format="%(authordate)" refs/heads && - git-for-each-ref --format="%(authordate:default) %(authordate)" refs/heads && - git-for-each-ref --format="%(authordate) %(authordate:default)" refs/heads && - git-for-each-ref --format="%(authordate:default) %(authordate:default)" refs/heads + git for-each-ref --format="%(authordate)" refs/heads && + git for-each-ref --format="%(authordate:default) %(authordate)" refs/heads && + git for-each-ref --format="%(authordate) %(authordate:default)" refs/heads && + git for-each-ref --format="%(authordate:default) %(authordate:default)" refs/heads ' test_expect_success 'Check valid format specifiers for date fields' ' - git-for-each-ref --format="%(authordate:default)" refs/heads && - git-for-each-ref --format="%(authordate:relative)" refs/heads && - git-for-each-ref --format="%(authordate:short)" refs/heads && - git-for-each-ref --format="%(authordate:local)" refs/heads && - git-for-each-ref --format="%(authordate:iso8601)" refs/heads && - git-for-each-ref --format="%(authordate:rfc2822)" refs/heads + git for-each-ref --format="%(authordate:default)" refs/heads && + git for-each-ref --format="%(authordate:relative)" refs/heads && + git for-each-ref --format="%(authordate:short)" refs/heads && + git for-each-ref --format="%(authordate:local)" refs/heads && + git for-each-ref --format="%(authordate:iso8601)" refs/heads && + git for-each-ref --format="%(authordate:rfc2822)" refs/heads ' test_expect_success 'Check invalid format specifiers are errors' ' - test_must_fail git-for-each-ref --format="%(authordate:INVALID)" refs/heads + test_must_fail git for-each-ref --format="%(authordate:INVALID)" refs/heads ' cat >expected <<\EOF @@ -207,7 +207,7 @@ refs/tags/testtag EOF test_expect_success 'Verify ascending sort' ' - git-for-each-ref --format="%(refname)" --sort=refname >actual && + git for-each-ref --format="%(refname)" --sort=refname >actual && test_cmp expected actual ' @@ -218,7 +218,7 @@ refs/heads/master EOF test_expect_success 'Verify descending sort' ' - git-for-each-ref --format="%(refname)" --sort=-refname >actual && + git for-each-ref --format="%(refname)" --sort=-refname >actual && test_cmp expected actual ' diff --git a/t/t7001-mv.sh b/t/t7001-mv.sh index 910a28c7e2..575ef5beb2 100755 --- a/t/t7001-mv.sh +++ b/t/t7001-mv.sh @@ -6,9 +6,9 @@ test_description='git mv in subdirs' test_expect_success \ 'prepare reference tree' \ 'mkdir path0 path1 && - cp ../../COPYING path0/COPYING && + cp "$TEST_DIRECTORY"/../COPYING path0/COPYING && git add path0/COPYING && - git-commit -m add -a' + git commit -m add -a' test_expect_success \ 'moving the file out of subdirectory' \ @@ -17,7 +17,7 @@ test_expect_success \ # in path0 currently test_expect_success \ 'commiting the change' \ - 'cd .. && git-commit -m move-out -a' + 'cd .. && git commit -m move-out -a' test_expect_success \ 'checking the commit' \ @@ -31,7 +31,7 @@ test_expect_success \ # in path0 currently test_expect_success \ 'commiting the change' \ - 'cd .. && git-commit -m move-in -a' + 'cd .. && git commit -m move-in -a' test_expect_success \ 'checking the commit' \ @@ -40,9 +40,9 @@ test_expect_success \ test_expect_success \ 'adding another file' \ - 'cp ../../README path0/README && + 'cp "$TEST_DIRECTORY"/../README path0/README && git add path0/README && - git-commit -m add2 -a' + git commit -m add2 -a' test_expect_success \ 'moving whole subdirectory' \ @@ -50,7 +50,7 @@ test_expect_success \ test_expect_success \ 'commiting the change' \ - 'git-commit -m dir-move -a' + 'git commit -m dir-move -a' test_expect_success \ 'checking the commit' \ @@ -69,7 +69,7 @@ test_expect_success \ test_expect_success \ 'commiting the change' \ - 'git-commit -m dir-move -a' + 'git commit -m dir-move -a' test_expect_success \ 'checking the commit' \ diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh index c8b4f65f38..5e359cb561 100755 --- a/t/t7002-grep.sh +++ b/t/t7002-grep.sh @@ -22,6 +22,7 @@ test_expect_success setup ' mkdir t && echo test >t/t && git add file x y z t/t && + test_tick && git commit -m initial ' @@ -113,4 +114,54 @@ do done +test_expect_success 'log grep setup' ' + echo a >>file && + test_tick && + GIT_AUTHOR_NAME="With * Asterisk" \ + GIT_AUTHOR_EMAIL="xyzzy@frotz.com" \ + git commit -a -m "second" && + + echo a >>file && + test_tick && + git commit -a -m "third" + +' + +test_expect_success 'log grep (1)' ' + git log --author=author --pretty=tformat:%s >actual && + ( echo third ; echo initial ) >expect && + test_cmp expect actual +' + +test_expect_success 'log grep (2)' ' + git log --author=" * " -F --pretty=tformat:%s >actual && + ( echo second ) >expect && + test_cmp expect actual +' + +test_expect_success 'log grep (3)' ' + git log --author="^A U" --pretty=tformat:%s >actual && + ( echo third ; echo initial ) >expect && + test_cmp expect actual +' + +test_expect_success 'log grep (4)' ' + git log --author="frotz\.com>$" --pretty=tformat:%s >actual && + ( echo second ) >expect && + test_cmp expect actual +' + +test_expect_success 'log grep (5)' ' + git log --author=Thor -F --grep=Thu --pretty=tformat:%s >actual && + ( echo third ; echo initial ) >expect && + test_cmp expect actual +' + +test_expect_success 'log grep (6)' ' + git log --author=-0700 --pretty=tformat:%s >actual && + >expect && + test_cmp expect actual + +' + test_done diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh index a0ab096c8f..b0a9d7d536 100755 --- a/t/t7003-filter-branch.sh +++ b/t/t7003-filter-branch.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-filter-branch' +test_description='git filter-branch' . ./test-lib.sh make_commit () { @@ -32,14 +32,14 @@ test_expect_success 'setup' ' H=$(git rev-parse H) test_expect_success 'rewrite identically' ' - git-filter-branch branch + git filter-branch branch ' test_expect_success 'result is really identical' ' test $H = $(git rev-parse HEAD) ' test_expect_success 'rewrite bare repository identically' ' - (git config core.bare true && cd .git && git-filter-branch branch) + (git config core.bare true && cd .git && git filter-branch branch) ' git config core.bare false test_expect_success 'result is really identical' ' @@ -47,7 +47,7 @@ test_expect_success 'result is really identical' ' ' test_expect_success 'rewrite, renaming a specific file' ' - git-filter-branch -f --tree-filter "mv d doh || :" HEAD + git filter-branch -f --tree-filter "mv d doh || :" HEAD ' test_expect_success 'test that the file was renamed' ' @@ -58,7 +58,7 @@ test_expect_success 'test that the file was renamed' ' ' test_expect_success 'rewrite, renaming a specific directory' ' - git-filter-branch -f --tree-filter "mv dir diroh || :" HEAD + git filter-branch -f --tree-filter "mv dir diroh || :" HEAD ' test_expect_success 'test that the directory was renamed' ' @@ -73,7 +73,7 @@ test_expect_success 'test that the directory was renamed' ' git tag oldD HEAD~4 test_expect_success 'rewrite one branch, keeping a side branch' ' git branch modD oldD && - git-filter-branch -f --tree-filter "mv b boh || :" D..modD + git filter-branch -f --tree-filter "mv b boh || :" D..modD ' test_expect_success 'common ancestor is still common (unchanged)' ' @@ -96,13 +96,17 @@ test_expect_success 'filter subdirectory only' ' test_tick && git commit -m "again not subdir" && git branch sub && - git-filter-branch -f --subdirectory-filter subdir refs/heads/sub + git branch sub-earlier HEAD~2 && + git filter-branch -f --subdirectory-filter subdir \ + refs/heads/sub refs/heads/sub-earlier ' test_expect_success 'subdirectory filter result looks okay' ' test 2 = $(git rev-list sub | wc -l) && git show sub:new && - test_must_fail git show sub:subdir + test_must_fail git show sub:subdir && + git show sub-earlier:new && + test_must_fail git show sub-earlier:subdir ' test_expect_success 'more setup' ' @@ -120,7 +124,7 @@ test_expect_success 'more setup' ' test_expect_success 'use index-filter to move into a subdirectory' ' git branch directorymoved && - git-filter-branch -f --index-filter \ + git filter-branch -f --index-filter \ "git ls-files -s | sed \"s-\\t-&newsubdir/-\" | GIT_INDEX_FILE=\$GIT_INDEX_FILE.new \ git update-index --index-info && @@ -129,7 +133,7 @@ test_expect_success 'use index-filter to move into a subdirectory' ' test_expect_success 'stops when msg filter fails' ' old=$(git rev-parse HEAD) && - test_must_fail git-filter-branch -f --msg-filter false HEAD && + test_must_fail git filter-branch -f --msg-filter false HEAD && test $old = $(git rev-parse HEAD) && rm -rf .git-rewrite ' @@ -140,7 +144,7 @@ test_expect_success 'author information is preserved' ' test_tick && GIT_AUTHOR_NAME="B V Uips" git commit -m bvuips && git branch preserved-author && - git-filter-branch -f --msg-filter "cat; \ + git filter-branch -f --msg-filter "cat; \ test \$GIT_COMMIT != $(git rev-parse master) || \ echo Hallo" \ preserved-author && @@ -152,7 +156,7 @@ test_expect_success "remove a certain author's commits" ' test_tick && git commit -m i i && git branch removed-author && - git-filter-branch -f --commit-filter "\ + git filter-branch -f --commit-filter "\ if [ \"\$GIT_AUTHOR_NAME\" = \"B V Uips\" ];\ then\ skip_commit \"\$@\"; @@ -250,4 +254,12 @@ test_expect_success 'Tag name filtering strips gpg signature' ' test_cmp expect actual ' +test_expect_success 'Tag name filtering allows slashes in tag names' ' + git tag -m tag-with-slash X/1 && + git cat-file tag X/1 | sed -e s,X/1,X/2, > expect && + git filter-branch -f --tag-name-filter "echo X/2" && + git cat-file tag X/2 > actual && + test_cmp expect actual +' + test_done diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh index 8d44c2ed1f..f0edbf1a76 100755 --- a/t/t7004-tag.sh +++ b/t/t7004-tag.sh @@ -3,7 +3,7 @@ # Copyright (c) 2007 Carlos Rica # -test_description='git-tag +test_description='git tag Tests for operations with tags.' @@ -22,25 +22,25 @@ test_expect_success 'listing all tags in an empty tree should succeed' ' ' test_expect_success 'listing all tags in an empty tree should output nothing' ' - test `git-tag -l | wc -l` -eq 0 && - test `git-tag | wc -l` -eq 0 + test `git tag -l | wc -l` -eq 0 && + test `git tag | wc -l` -eq 0 ' test_expect_success 'looking for a tag in an empty tree should fail' \ '! (tag_exists mytag)' test_expect_success 'creating a tag in an empty tree should fail' ' - test_must_fail git-tag mynotag && + test_must_fail git tag mynotag && ! tag_exists mynotag ' test_expect_success 'creating a tag for HEAD in an empty tree should fail' ' - test_must_fail git-tag mytaghead HEAD && + test_must_fail git tag mytaghead HEAD && ! tag_exists mytaghead ' test_expect_success 'creating a tag for an unknown revision should fail' ' - test_must_fail git-tag mytagnorev aaaaaaaaaaa && + test_must_fail git tag mytagnorev aaaaaaaaaaa && ! tag_exists mytagnorev ' @@ -54,32 +54,32 @@ test_expect_success 'creating a tag using default HEAD should succeed' ' ' test_expect_success 'listing all tags if one exists should succeed' ' - git-tag -l && - git-tag + git tag -l && + git tag ' test_expect_success 'listing all tags if one exists should output that tag' ' - test `git-tag -l` = mytag && - test `git-tag` = mytag + test `git tag -l` = mytag && + test `git tag` = mytag ' # pattern matching: test_expect_success 'listing a tag using a matching pattern should succeed' \ - 'git-tag -l mytag' + 'git tag -l mytag' test_expect_success \ 'listing a tag using a matching pattern should output that tag' \ - 'test `git-tag -l mytag` = mytag' + 'test `git tag -l mytag` = mytag' # todo: git tag -l now returns always zero, when fixed, change this test test_expect_success \ 'listing tags using a non-matching pattern should suceed' \ - 'git-tag -l xxx' + 'git tag -l xxx' test_expect_success \ 'listing tags using a non-matching pattern should output nothing' \ - 'test `git-tag -l xxx | wc -l` -eq 0' + 'test `git tag -l xxx | wc -l` -eq 0' # special cases for creating tags: @@ -89,13 +89,13 @@ test_expect_success \ test_expect_success \ 'trying to create a tag with a non-valid name should fail' ' - test `git-tag -l | wc -l` -eq 1 && + test `git tag -l | wc -l` -eq 1 && test_must_fail git tag "" && test_must_fail git tag .othertag && test_must_fail git tag "other tag" && test_must_fail git tag "othertag^" && test_must_fail git tag "other~tag" && - test `git-tag -l | wc -l` -eq 1 + test `git tag -l | wc -l` -eq 1 ' test_expect_success 'creating a tag using HEAD directly should succeed' ' @@ -107,7 +107,7 @@ test_expect_success 'creating a tag using HEAD directly should succeed' ' test_expect_success 'trying to delete an unknown tag should fail' ' ! tag_exists unknown-tag && - test_must_fail git-tag -d unknown-tag + test_must_fail git tag -d unknown-tag ' cat >expect <<EOF @@ -117,7 +117,7 @@ EOF test_expect_success \ 'trying to delete tags without params should succeed and do nothing' ' git tag -l > actual && test_cmp expect actual && - git-tag -d && + git tag -d && git tag -l > actual && test_cmp expect actual ' @@ -125,7 +125,7 @@ test_expect_success \ 'deleting two existing tags in one command should succeed' ' tag_exists mytag && tag_exists myhead && - git-tag -d mytag myhead && + git tag -d mytag myhead && ! tag_exists mytag && ! tag_exists myhead ' @@ -133,7 +133,7 @@ test_expect_success \ test_expect_success \ 'creating a tag with the name of another deleted one should succeed' ' ! tag_exists mytag && - git-tag mytag && + git tag mytag && tag_exists mytag ' @@ -141,13 +141,13 @@ test_expect_success \ 'trying to delete two tags, existing and not, should fail in the 2nd' ' tag_exists mytag && ! tag_exists myhead && - test_must_fail git-tag -d mytag anothertag && + test_must_fail git tag -d mytag anothertag && ! tag_exists mytag && ! tag_exists myhead ' test_expect_success 'trying to delete an already deleted tag should fail' \ - 'test_must_fail git-tag -d mytag' + 'test_must_fail git tag -d mytag' # listing various tags with pattern matching: @@ -185,7 +185,7 @@ cba EOF test_expect_success \ 'listing tags with substring as pattern must print those matching' ' - git-tag -l "*a*" > actual && + git tag -l "*a*" > actual && test_cmp expect actual ' @@ -195,7 +195,7 @@ v1.0.1 EOF test_expect_success \ 'listing tags with a suffix as pattern must print those matching' ' - git-tag -l "*.1" > actual && + git tag -l "*.1" > actual && test_cmp expect actual ' @@ -205,7 +205,7 @@ t211 EOF test_expect_success \ 'listing tags with a prefix as pattern must print those matching' ' - git-tag -l "t21*" > actual && + git tag -l "t21*" > actual && test_cmp expect actual ' @@ -214,7 +214,7 @@ a1 EOF test_expect_success \ 'listing tags using a name as pattern must print that one matching' ' - git-tag -l a1 > actual && + git tag -l a1 > actual && test_cmp expect actual ' @@ -223,7 +223,7 @@ v1.0 EOF test_expect_success \ 'listing tags using a name as pattern must print that one matching' ' - git-tag -l v1.0 > actual && + git tag -l v1.0 > actual && test_cmp expect actual ' @@ -233,14 +233,14 @@ v1.1.3 EOF test_expect_success \ 'listing tags with ? in the pattern should print those matching' ' - git-tag -l "v1.?.?" > actual && + git tag -l "v1.?.?" > actual && test_cmp expect actual ' >expect test_expect_success \ 'listing tags using v.* should print nothing because none have v.' ' - git-tag -l "v.*" > actual && + git tag -l "v.*" > actual && test_cmp expect actual ' @@ -252,7 +252,7 @@ v1.1.3 EOF test_expect_success \ 'listing tags using v* should print only those having v' ' - git-tag -l "v*" > actual && + git tag -l "v*" > actual && test_cmp expect actual ' @@ -260,21 +260,21 @@ test_expect_success \ test_expect_success \ 'a non-annotated tag created without parameters should point to HEAD' ' - git-tag non-annotated-tag && + git tag non-annotated-tag && test $(git cat-file -t non-annotated-tag) = commit && test $(git rev-parse non-annotated-tag) = $(git rev-parse HEAD) ' test_expect_success 'trying to verify an unknown tag should fail' \ - 'test_must_fail git-tag -v unknown-tag' + 'test_must_fail git tag -v unknown-tag' test_expect_success \ 'trying to verify a non-annotated and non-signed tag should fail' \ - 'test_must_fail git-tag -v non-annotated-tag' + 'test_must_fail git tag -v non-annotated-tag' test_expect_success \ 'trying to verify many non-annotated or unknown tags, should fail' \ - 'test_must_fail git-tag -v unknown-tag1 non-annotated-tag unknown-tag2' + 'test_must_fail git tag -v unknown-tag1 non-annotated-tag unknown-tag2' # creating annotated tags: @@ -300,7 +300,7 @@ get_tag_header annotated-tag $commit commit $time >expect echo "A message" >>expect test_expect_success \ 'creating an annotated tag with -m message should succeed' ' - git-tag -m "A message" annotated-tag && + git tag -m "A message" annotated-tag && get_tag_msg annotated-tag >actual && test_cmp expect actual ' @@ -313,7 +313,7 @@ get_tag_header file-annotated-tag $commit commit $time >expect cat msgfile >>expect test_expect_success \ 'creating an annotated tag with -F messagefile should succeed' ' - git-tag -F msgfile file-annotated-tag && + git tag -F msgfile file-annotated-tag && get_tag_msg file-annotated-tag >actual && test_cmp expect actual ' @@ -325,7 +325,7 @@ EOF get_tag_header stdin-annotated-tag $commit commit $time >expect cat inputmsg >>expect test_expect_success 'creating an annotated tag with -F - should succeed' ' - git-tag -F - stdin-annotated-tag <inputmsg && + git tag -F - stdin-annotated-tag <inputmsg && get_tag_msg stdin-annotated-tag >actual && test_cmp expect actual ' @@ -334,7 +334,7 @@ test_expect_success \ 'trying to create a tag with a non-existing -F file should fail' ' ! test -f nonexistingfile && ! tag_exists notag && - test_must_fail git-tag -F nonexistingfile notag && + test_must_fail git tag -F nonexistingfile notag && ! tag_exists notag ' @@ -343,11 +343,11 @@ test_expect_success \ echo "message file 1" >msgfile1 && echo "message file 2" >msgfile2 && ! tag_exists msgtag && - test_must_fail git-tag -m "message 1" -F msgfile1 msgtag && + test_must_fail git tag -m "message 1" -F msgfile1 msgtag && ! tag_exists msgtag && - test_must_fail git-tag -F msgfile1 -m "message 1" msgtag && + test_must_fail git tag -F msgfile1 -m "message 1" msgtag && ! tag_exists msgtag && - test_must_fail git-tag -m "message 1" -F msgfile1 \ + test_must_fail git tag -m "message 1" -F msgfile1 \ -m "message 2" msgtag && ! tag_exists msgtag ' @@ -357,7 +357,7 @@ test_expect_success \ get_tag_header empty-annotated-tag $commit commit $time >expect test_expect_success \ 'creating a tag with an empty -m message should succeed' ' - git-tag -m "" empty-annotated-tag && + git tag -m "" empty-annotated-tag && get_tag_msg empty-annotated-tag >actual && test_cmp expect actual ' @@ -366,7 +366,7 @@ test_expect_success \ get_tag_header emptyfile-annotated-tag $commit commit $time >expect test_expect_success \ 'creating a tag with an empty -F messagefile should succeed' ' - git-tag -F emptyfile emptyfile-annotated-tag && + git tag -F emptyfile emptyfile-annotated-tag && get_tag_msg emptyfile-annotated-tag >actual && test_cmp expect actual ' @@ -387,7 +387,7 @@ Trailing blank lines EOF test_expect_success \ 'extra blanks in the message for an annotated tag should be removed' ' - git-tag -F blanksfile blanks-annotated-tag && + git tag -F blanksfile blanks-annotated-tag && get_tag_msg blanks-annotated-tag >actual && test_cmp expect actual ' @@ -395,7 +395,7 @@ test_expect_success \ get_tag_header blank-annotated-tag $commit commit $time >expect test_expect_success \ 'creating a tag with blank -m message with spaces should succeed' ' - git-tag -m " " blank-annotated-tag && + git tag -m " " blank-annotated-tag && get_tag_msg blank-annotated-tag >actual && test_cmp expect actual ' @@ -406,7 +406,7 @@ echo ' ' >>blankfile get_tag_header blankfile-annotated-tag $commit commit $time >expect test_expect_success \ 'creating a tag with blank -F messagefile with spaces should succeed' ' - git-tag -F blankfile blankfile-annotated-tag && + git tag -F blankfile blankfile-annotated-tag && get_tag_msg blankfile-annotated-tag >actual && test_cmp expect actual ' @@ -415,7 +415,7 @@ printf ' ' >blanknonlfile get_tag_header blanknonlfile-annotated-tag $commit commit $time >expect test_expect_success \ 'creating a tag with -F file of spaces and no newline should succeed' ' - git-tag -F blanknonlfile blanknonlfile-annotated-tag && + git tag -F blanknonlfile blanknonlfile-annotated-tag && get_tag_msg blanknonlfile-annotated-tag >actual && test_cmp expect actual ' @@ -450,7 +450,7 @@ Last line. EOF test_expect_success \ 'creating a tag using a -F messagefile with #comments should succeed' ' - git-tag -F commentsfile comments-annotated-tag && + git tag -F commentsfile comments-annotated-tag && get_tag_msg comments-annotated-tag >actual && test_cmp expect actual ' @@ -458,7 +458,7 @@ test_expect_success \ get_tag_header comment-annotated-tag $commit commit $time >expect test_expect_success \ 'creating a tag with a #comment in the -m message should succeed' ' - git-tag -m "#comment" comment-annotated-tag && + git tag -m "#comment" comment-annotated-tag && get_tag_msg comment-annotated-tag >actual && test_cmp expect actual ' @@ -469,7 +469,7 @@ echo '####' >>commentfile get_tag_header commentfile-annotated-tag $commit commit $time >expect test_expect_success \ 'creating a tag with #comments in the -F messagefile should succeed' ' - git-tag -F commentfile commentfile-annotated-tag && + git tag -F commentfile commentfile-annotated-tag && get_tag_msg commentfile-annotated-tag >actual && test_cmp expect actual ' @@ -478,7 +478,7 @@ printf '#comment' >commentnonlfile get_tag_header commentnonlfile-annotated-tag $commit commit $time >expect test_expect_success \ 'creating a tag with a file of #comment and no newline should succeed' ' - git-tag -F commentnonlfile commentnonlfile-annotated-tag && + git tag -F commentnonlfile commentnonlfile-annotated-tag && get_tag_msg commentnonlfile-annotated-tag >actual && test_cmp expect actual ' @@ -487,51 +487,51 @@ test_expect_success \ test_expect_success \ 'listing the one-line message of a non-signed tag should succeed' ' - git-tag -m "A msg" tag-one-line && + git tag -m "A msg" tag-one-line && echo "tag-one-line" >expect && - git-tag -l | grep "^tag-one-line" >actual && + git tag -l | grep "^tag-one-line" >actual && test_cmp expect actual && - git-tag -n0 -l | grep "^tag-one-line" >actual && + git tag -n0 -l | grep "^tag-one-line" >actual && test_cmp expect actual && - git-tag -n0 -l tag-one-line >actual && + git tag -n0 -l tag-one-line >actual && test_cmp expect actual && echo "tag-one-line A msg" >expect && - git-tag -n1 -l | grep "^tag-one-line" >actual && + git tag -n1 -l | grep "^tag-one-line" >actual && test_cmp expect actual && - git-tag -n -l | grep "^tag-one-line" >actual && + git tag -n -l | grep "^tag-one-line" >actual && test_cmp expect actual && - git-tag -n1 -l tag-one-line >actual && + git tag -n1 -l tag-one-line >actual && test_cmp expect actual && - git-tag -n2 -l tag-one-line >actual && + git tag -n2 -l tag-one-line >actual && test_cmp expect actual && - git-tag -n999 -l tag-one-line >actual && + git tag -n999 -l tag-one-line >actual && test_cmp expect actual ' test_expect_success \ 'listing the zero-lines message of a non-signed tag should succeed' ' - git-tag -m "" tag-zero-lines && + git tag -m "" tag-zero-lines && echo "tag-zero-lines" >expect && - git-tag -l | grep "^tag-zero-lines" >actual && + git tag -l | grep "^tag-zero-lines" >actual && test_cmp expect actual && - git-tag -n0 -l | grep "^tag-zero-lines" >actual && + git tag -n0 -l | grep "^tag-zero-lines" >actual && test_cmp expect actual && - git-tag -n0 -l tag-zero-lines >actual && + git tag -n0 -l tag-zero-lines >actual && test_cmp expect actual && echo "tag-zero-lines " >expect && - git-tag -n1 -l | grep "^tag-zero-lines" >actual && + git tag -n1 -l | grep "^tag-zero-lines" >actual && test_cmp expect actual && - git-tag -n -l | grep "^tag-zero-lines" >actual && + git tag -n -l | grep "^tag-zero-lines" >actual && test_cmp expect actual && - git-tag -n1 -l tag-zero-lines >actual && + git tag -n1 -l tag-zero-lines >actual && test_cmp expect actual && - git-tag -n2 -l tag-zero-lines >actual && + git tag -n2 -l tag-zero-lines >actual && test_cmp expect actual && - git-tag -n999 -l tag-zero-lines >actual && + git tag -n999 -l tag-zero-lines >actual && test_cmp expect actual ' @@ -540,42 +540,42 @@ echo 'tag line two' >>annotagmsg echo 'tag line three' >>annotagmsg test_expect_success \ 'listing many message lines of a non-signed tag should succeed' ' - git-tag -F annotagmsg tag-lines && + git tag -F annotagmsg tag-lines && echo "tag-lines" >expect && - git-tag -l | grep "^tag-lines" >actual && + git tag -l | grep "^tag-lines" >actual && test_cmp expect actual && - git-tag -n0 -l | grep "^tag-lines" >actual && + git tag -n0 -l | grep "^tag-lines" >actual && test_cmp expect actual && - git-tag -n0 -l tag-lines >actual && + git tag -n0 -l tag-lines >actual && test_cmp expect actual && echo "tag-lines tag line one" >expect && - git-tag -n1 -l | grep "^tag-lines" >actual && + git tag -n1 -l | grep "^tag-lines" >actual && test_cmp expect actual && - git-tag -n -l | grep "^tag-lines" >actual && + git tag -n -l | grep "^tag-lines" >actual && test_cmp expect actual && - git-tag -n1 -l tag-lines >actual && + git tag -n1 -l tag-lines >actual && test_cmp expect actual && echo " tag line two" >>expect && - git-tag -n2 -l | grep "^ *tag.line" >actual && + git tag -n2 -l | grep "^ *tag.line" >actual && test_cmp expect actual && - git-tag -n2 -l tag-lines >actual && + git tag -n2 -l tag-lines >actual && test_cmp expect actual && echo " tag line three" >>expect && - git-tag -n3 -l | grep "^ *tag.line" >actual && + git tag -n3 -l | grep "^ *tag.line" >actual && test_cmp expect actual && - git-tag -n3 -l tag-lines >actual && + git tag -n3 -l tag-lines >actual && test_cmp expect actual && - git-tag -n4 -l | grep "^ *tag.line" >actual && + git tag -n4 -l | grep "^ *tag.line" >actual && test_cmp expect actual && - git-tag -n4 -l tag-lines >actual && + git tag -n4 -l tag-lines >actual && test_cmp expect actual && - git-tag -n99 -l | grep "^ *tag.line" >actual && + git tag -n99 -l | grep "^ *tag.line" >actual && test_cmp expect actual && - git-tag -n99 -l tag-lines >actual && + git tag -n99 -l tag-lines >actual && test_cmp expect actual ' @@ -592,19 +592,19 @@ fi test_expect_success \ 'trying to verify an annotated non-signed tag should fail' ' tag_exists annotated-tag && - test_must_fail git-tag -v annotated-tag + test_must_fail git tag -v annotated-tag ' test_expect_success \ 'trying to verify a file-annotated non-signed tag should fail' ' tag_exists file-annotated-tag && - test_must_fail git-tag -v file-annotated-tag + test_must_fail git tag -v file-annotated-tag ' test_expect_success \ 'trying to verify two annotated non-signed tags should fail' ' tag_exists annotated-tag file-annotated-tag && - test_must_fail git-tag -v annotated-tag file-annotated-tag + test_must_fail git tag -v annotated-tag file-annotated-tag ' # creating and verifying signed tags: @@ -625,7 +625,7 @@ esac # Name and email: C O Mitter <committer@example.com> # No password given, to enable non-interactive operation. -cp -R ../t7004 ./gpghome +cp -R "$TEST_DIRECTORY"/t7004 ./gpghome chmod 0700 gpghome GNUPGHOME="$(pwd)/gpghome" export GNUPGHOME @@ -634,7 +634,7 @@ get_tag_header signed-tag $commit commit $time >expect echo 'A signed tag message' >>expect echo '-----BEGIN PGP SIGNATURE-----' >>expect test_expect_success 'creating a signed tag with -m message should succeed' ' - git-tag -s -m "A signed tag message" signed-tag && + git tag -s -m "A signed tag message" signed-tag && get_tag_msg signed-tag >actual && test_cmp expect actual ' @@ -675,7 +675,7 @@ get_tag_header implied-sign $commit commit $time >expect ./fakeeditor >>expect echo '-----BEGIN PGP SIGNATURE-----' >>expect test_expect_success '-u implies signed tag' ' - GIT_EDITOR=./fakeeditor git-tag -u CDDE430D implied-sign && + GIT_EDITOR=./fakeeditor git tag -u CDDE430D implied-sign && get_tag_msg implied-sign >actual && test_cmp expect actual ' @@ -689,7 +689,7 @@ cat sigmsgfile >>expect echo '-----BEGIN PGP SIGNATURE-----' >>expect test_expect_success \ 'creating a signed tag with -F messagefile should succeed' ' - git-tag -s -F sigmsgfile file-signed-tag && + git tag -s -F sigmsgfile file-signed-tag && get_tag_msg file-signed-tag >actual && test_cmp expect actual ' @@ -702,7 +702,7 @@ get_tag_header stdin-signed-tag $commit commit $time >expect cat siginputmsg >>expect echo '-----BEGIN PGP SIGNATURE-----' >>expect test_expect_success 'creating a signed tag with -F - should succeed' ' - git-tag -s -F - stdin-signed-tag <siginputmsg && + git tag -s -F - stdin-signed-tag <siginputmsg && get_tag_msg stdin-signed-tag >actual && test_cmp expect actual ' @@ -711,7 +711,7 @@ get_tag_header implied-annotate $commit commit $time >expect ./fakeeditor >>expect echo '-----BEGIN PGP SIGNATURE-----' >>expect test_expect_success '-s implies annotated tag' ' - GIT_EDITOR=./fakeeditor git-tag -s implied-annotate && + GIT_EDITOR=./fakeeditor git tag -s implied-annotate && get_tag_msg implied-annotate >actual && test_cmp expect actual ' @@ -720,23 +720,23 @@ test_expect_success \ 'trying to create a signed tag with non-existing -F file should fail' ' ! test -f nonexistingfile && ! tag_exists nosigtag && - test_must_fail git-tag -s -F nonexistingfile nosigtag && + test_must_fail git tag -s -F nonexistingfile nosigtag && ! tag_exists nosigtag ' test_expect_success 'verifying a signed tag should succeed' \ - 'git-tag -v signed-tag' + 'git tag -v signed-tag' test_expect_success 'verifying two signed tags in one command should succeed' \ - 'git-tag -v signed-tag file-signed-tag' + 'git tag -v signed-tag file-signed-tag' test_expect_success \ 'verifying many signed and non-signed tags should fail' ' - test_must_fail git-tag -v signed-tag annotated-tag && - test_must_fail git-tag -v file-annotated-tag file-signed-tag && - test_must_fail git-tag -v annotated-tag \ + test_must_fail git tag -v signed-tag annotated-tag && + test_must_fail git tag -v file-annotated-tag file-signed-tag && + test_must_fail git tag -v annotated-tag \ file-signed-tag file-annotated-tag && - test_must_fail git-tag -v signed-tag annotated-tag file-signed-tag + test_must_fail git tag -v signed-tag annotated-tag file-signed-tag ' test_expect_success 'verifying a forged tag should fail' ' @@ -744,7 +744,7 @@ test_expect_success 'verifying a forged tag should fail' ' sed -e "s/signed-tag/forged-tag/" | git mktag) && git tag forged-tag $forged && - test_must_fail git-tag -v forged-tag + test_must_fail git tag -v forged-tag ' # blank and empty messages for signed tags: @@ -753,10 +753,10 @@ get_tag_header empty-signed-tag $commit commit $time >expect echo '-----BEGIN PGP SIGNATURE-----' >>expect test_expect_success \ 'creating a signed tag with an empty -m message should succeed' ' - git-tag -s -m "" empty-signed-tag && + git tag -s -m "" empty-signed-tag && get_tag_msg empty-signed-tag >actual && test_cmp expect actual && - git-tag -v empty-signed-tag + git tag -v empty-signed-tag ' >sigemptyfile @@ -764,10 +764,10 @@ get_tag_header emptyfile-signed-tag $commit commit $time >expect echo '-----BEGIN PGP SIGNATURE-----' >>expect test_expect_success \ 'creating a signed tag with an empty -F messagefile should succeed' ' - git-tag -s -F sigemptyfile emptyfile-signed-tag && + git tag -s -F sigemptyfile emptyfile-signed-tag && get_tag_msg emptyfile-signed-tag >actual && test_cmp expect actual && - git-tag -v emptyfile-signed-tag + git tag -v emptyfile-signed-tag ' printf '\n\n \n\t\nLeading blank lines\n' > sigblanksfile @@ -787,20 +787,20 @@ EOF echo '-----BEGIN PGP SIGNATURE-----' >>expect test_expect_success \ 'extra blanks in the message for a signed tag should be removed' ' - git-tag -s -F sigblanksfile blanks-signed-tag && + git tag -s -F sigblanksfile blanks-signed-tag && get_tag_msg blanks-signed-tag >actual && test_cmp expect actual && - git-tag -v blanks-signed-tag + git tag -v blanks-signed-tag ' get_tag_header blank-signed-tag $commit commit $time >expect echo '-----BEGIN PGP SIGNATURE-----' >>expect test_expect_success \ 'creating a signed tag with a blank -m message should succeed' ' - git-tag -s -m " " blank-signed-tag && + git tag -s -m " " blank-signed-tag && get_tag_msg blank-signed-tag >actual && test_cmp expect actual && - git-tag -v blank-signed-tag + git tag -v blank-signed-tag ' echo ' ' >sigblankfile @@ -810,10 +810,10 @@ get_tag_header blankfile-signed-tag $commit commit $time >expect echo '-----BEGIN PGP SIGNATURE-----' >>expect test_expect_success \ 'creating a signed tag with blank -F file with spaces should succeed' ' - git-tag -s -F sigblankfile blankfile-signed-tag && + git tag -s -F sigblankfile blankfile-signed-tag && get_tag_msg blankfile-signed-tag >actual && test_cmp expect actual && - git-tag -v blankfile-signed-tag + git tag -v blankfile-signed-tag ' printf ' ' >sigblanknonlfile @@ -821,10 +821,10 @@ get_tag_header blanknonlfile-signed-tag $commit commit $time >expect echo '-----BEGIN PGP SIGNATURE-----' >>expect test_expect_success \ 'creating a signed tag with spaces and no newline should succeed' ' - git-tag -s -F sigblanknonlfile blanknonlfile-signed-tag && + git tag -s -F sigblanknonlfile blanknonlfile-signed-tag && get_tag_msg blanknonlfile-signed-tag >actual && test_cmp expect actual && - git-tag -v signed-tag + git tag -v signed-tag ' # messages with commented lines for signed tags: @@ -858,20 +858,20 @@ EOF echo '-----BEGIN PGP SIGNATURE-----' >>expect test_expect_success \ 'creating a signed tag with a -F file with #comments should succeed' ' - git-tag -s -F sigcommentsfile comments-signed-tag && + git tag -s -F sigcommentsfile comments-signed-tag && get_tag_msg comments-signed-tag >actual && test_cmp expect actual && - git-tag -v comments-signed-tag + git tag -v comments-signed-tag ' get_tag_header comment-signed-tag $commit commit $time >expect echo '-----BEGIN PGP SIGNATURE-----' >>expect test_expect_success \ 'creating a signed tag with #commented -m message should succeed' ' - git-tag -s -m "#comment" comment-signed-tag && + git tag -s -m "#comment" comment-signed-tag && get_tag_msg comment-signed-tag >actual && test_cmp expect actual && - git-tag -v comment-signed-tag + git tag -v comment-signed-tag ' echo '#comment' >sigcommentfile @@ -881,10 +881,10 @@ get_tag_header commentfile-signed-tag $commit commit $time >expect echo '-----BEGIN PGP SIGNATURE-----' >>expect test_expect_success \ 'creating a signed tag with #commented -F messagefile should succeed' ' - git-tag -s -F sigcommentfile commentfile-signed-tag && + git tag -s -F sigcommentfile commentfile-signed-tag && get_tag_msg commentfile-signed-tag >actual && test_cmp expect actual && - git-tag -v commentfile-signed-tag + git tag -v commentfile-signed-tag ' printf '#comment' >sigcommentnonlfile @@ -892,61 +892,61 @@ get_tag_header commentnonlfile-signed-tag $commit commit $time >expect echo '-----BEGIN PGP SIGNATURE-----' >>expect test_expect_success \ 'creating a signed tag with a #comment and no newline should succeed' ' - git-tag -s -F sigcommentnonlfile commentnonlfile-signed-tag && + git tag -s -F sigcommentnonlfile commentnonlfile-signed-tag && get_tag_msg commentnonlfile-signed-tag >actual && test_cmp expect actual && - git-tag -v commentnonlfile-signed-tag + git tag -v commentnonlfile-signed-tag ' # listing messages for signed tags: test_expect_success \ 'listing the one-line message of a signed tag should succeed' ' - git-tag -s -m "A message line signed" stag-one-line && + git tag -s -m "A message line signed" stag-one-line && echo "stag-one-line" >expect && - git-tag -l | grep "^stag-one-line" >actual && + git tag -l | grep "^stag-one-line" >actual && test_cmp expect actual && - git-tag -n0 -l | grep "^stag-one-line" >actual && + git tag -n0 -l | grep "^stag-one-line" >actual && test_cmp expect actual && - git-tag -n0 -l stag-one-line >actual && + git tag -n0 -l stag-one-line >actual && test_cmp expect actual && echo "stag-one-line A message line signed" >expect && - git-tag -n1 -l | grep "^stag-one-line" >actual && + git tag -n1 -l | grep "^stag-one-line" >actual && test_cmp expect actual && - git-tag -n -l | grep "^stag-one-line" >actual && + git tag -n -l | grep "^stag-one-line" >actual && test_cmp expect actual && - git-tag -n1 -l stag-one-line >actual && + git tag -n1 -l stag-one-line >actual && test_cmp expect actual && - git-tag -n2 -l stag-one-line >actual && + git tag -n2 -l stag-one-line >actual && test_cmp expect actual && - git-tag -n999 -l stag-one-line >actual && + git tag -n999 -l stag-one-line >actual && test_cmp expect actual ' test_expect_success \ 'listing the zero-lines message of a signed tag should succeed' ' - git-tag -s -m "" stag-zero-lines && + git tag -s -m "" stag-zero-lines && echo "stag-zero-lines" >expect && - git-tag -l | grep "^stag-zero-lines" >actual && + git tag -l | grep "^stag-zero-lines" >actual && test_cmp expect actual && - git-tag -n0 -l | grep "^stag-zero-lines" >actual && + git tag -n0 -l | grep "^stag-zero-lines" >actual && test_cmp expect actual && - git-tag -n0 -l stag-zero-lines >actual && + git tag -n0 -l stag-zero-lines >actual && test_cmp expect actual && echo "stag-zero-lines " >expect && - git-tag -n1 -l | grep "^stag-zero-lines" >actual && + git tag -n1 -l | grep "^stag-zero-lines" >actual && test_cmp expect actual && - git-tag -n -l | grep "^stag-zero-lines" >actual && + git tag -n -l | grep "^stag-zero-lines" >actual && test_cmp expect actual && - git-tag -n1 -l stag-zero-lines >actual && + git tag -n1 -l stag-zero-lines >actual && test_cmp expect actual && - git-tag -n2 -l stag-zero-lines >actual && + git tag -n2 -l stag-zero-lines >actual && test_cmp expect actual && - git-tag -n999 -l stag-zero-lines >actual && + git tag -n999 -l stag-zero-lines >actual && test_cmp expect actual ' @@ -955,42 +955,42 @@ echo 'stag line two' >>sigtagmsg echo 'stag line three' >>sigtagmsg test_expect_success \ 'listing many message lines of a signed tag should succeed' ' - git-tag -s -F sigtagmsg stag-lines && + git tag -s -F sigtagmsg stag-lines && echo "stag-lines" >expect && - git-tag -l | grep "^stag-lines" >actual && + git tag -l | grep "^stag-lines" >actual && test_cmp expect actual && - git-tag -n0 -l | grep "^stag-lines" >actual && + git tag -n0 -l | grep "^stag-lines" >actual && test_cmp expect actual && - git-tag -n0 -l stag-lines >actual && + git tag -n0 -l stag-lines >actual && test_cmp expect actual && echo "stag-lines stag line one" >expect && - git-tag -n1 -l | grep "^stag-lines" >actual && + git tag -n1 -l | grep "^stag-lines" >actual && test_cmp expect actual && - git-tag -n -l | grep "^stag-lines" >actual && + git tag -n -l | grep "^stag-lines" >actual && test_cmp expect actual && - git-tag -n1 -l stag-lines >actual && + git tag -n1 -l stag-lines >actual && test_cmp expect actual && echo " stag line two" >>expect && - git-tag -n2 -l | grep "^ *stag.line" >actual && + git tag -n2 -l | grep "^ *stag.line" >actual && test_cmp expect actual && - git-tag -n2 -l stag-lines >actual && + git tag -n2 -l stag-lines >actual && test_cmp expect actual && echo " stag line three" >>expect && - git-tag -n3 -l | grep "^ *stag.line" >actual && + git tag -n3 -l | grep "^ *stag.line" >actual && test_cmp expect actual && - git-tag -n3 -l stag-lines >actual && + git tag -n3 -l stag-lines >actual && test_cmp expect actual && - git-tag -n4 -l | grep "^ *stag.line" >actual && + git tag -n4 -l | grep "^ *stag.line" >actual && test_cmp expect actual && - git-tag -n4 -l stag-lines >actual && + git tag -n4 -l stag-lines >actual && test_cmp expect actual && - git-tag -n99 -l | grep "^ *stag.line" >actual && + git tag -n99 -l | grep "^ *stag.line" >actual && test_cmp expect actual && - git-tag -n99 -l stag-lines >actual && + git tag -n99 -l stag-lines >actual && test_cmp expect actual ' @@ -1005,7 +1005,7 @@ echo "A message for a tree" >>expect echo '-----BEGIN PGP SIGNATURE-----' >>expect test_expect_success \ 'creating a signed tag pointing to a tree should succeed' ' - git-tag -s -m "A message for a tree" tree-signed-tag HEAD^{tree} && + git tag -s -m "A message for a tree" tree-signed-tag HEAD^{tree} && get_tag_msg tree-signed-tag >actual && test_cmp expect actual ' @@ -1015,7 +1015,7 @@ echo "A message for a blob" >>expect echo '-----BEGIN PGP SIGNATURE-----' >>expect test_expect_success \ 'creating a signed tag pointing to a blob should succeed' ' - git-tag -s -m "A message for a blob" blob-signed-tag HEAD:foo && + git tag -s -m "A message for a blob" blob-signed-tag HEAD:foo && get_tag_msg blob-signed-tag >actual && test_cmp expect actual ' @@ -1025,7 +1025,7 @@ echo "A message for another tag" >>expect echo '-----BEGIN PGP SIGNATURE-----' >>expect test_expect_success \ 'creating a signed tag pointing to another tag should succeed' ' - git-tag -s -m "A message for another tag" tag-signed-tag signed-tag && + git tag -s -m "A message for another tag" tag-signed-tag signed-tag && get_tag_msg tag-signed-tag >actual && test_cmp expect actual ' @@ -1033,7 +1033,7 @@ test_expect_success \ # try to sign with bad user.signingkey git config user.signingkey BobTheMouse test_expect_success \ - 'git-tag -s fails if gpg is misconfigured' \ + 'git tag -s fails if gpg is misconfigured' \ 'test_must_fail git tag -s -m tail tag-gpg-failure' git config --unset user.signingkey @@ -1042,10 +1042,10 @@ git config --unset user.signingkey rm -rf gpghome test_expect_success \ 'verify signed tag fails when public key is not present' \ - 'test_must_fail git-tag -v signed-tag' + 'test_must_fail git tag -v signed-tag' test_expect_success \ - 'git-tag -a fails if tag annotation is empty' ' + 'git tag -a fails if tag annotation is empty' ' ! (GIT_EDITOR=cat git tag -a initial-comment) ' diff --git a/t/t7101-reset.sh b/t/t7101-reset.sh index 0d9874bfd7..96e163f084 100755 --- a/t/t7101-reset.sh +++ b/t/t7101-reset.sh @@ -3,33 +3,33 @@ # Copyright (c) 2006 Shawn Pearce # -test_description='git-reset should cull empty subdirs' +test_description='git reset should cull empty subdirs' . ./test-lib.sh test_expect_success \ 'creating initial files' \ 'mkdir path0 && - cp ../../COPYING path0/COPYING && + cp "$TEST_DIRECTORY"/../COPYING path0/COPYING && git add path0/COPYING && - git-commit -m add -a' + git commit -m add -a' test_expect_success \ 'creating second files' \ 'mkdir path1 && mkdir path1/path2 && - cp ../../COPYING path1/path2/COPYING && - cp ../../COPYING path1/COPYING && - cp ../../COPYING COPYING && - cp ../../COPYING path0/COPYING-TOO && + cp "$TEST_DIRECTORY"/../COPYING path1/path2/COPYING && + cp "$TEST_DIRECTORY"/../COPYING path1/COPYING && + cp "$TEST_DIRECTORY"/../COPYING COPYING && + cp "$TEST_DIRECTORY"/../COPYING path0/COPYING-TOO && git add path1/path2/COPYING && git add path1/COPYING && git add COPYING && git add path0/COPYING-TOO && - git-commit -m change -a' + git commit -m change -a' test_expect_success \ 'resetting tree HEAD^' \ - 'git-reset --hard HEAD^' + 'git reset --hard HEAD^' test_expect_success \ 'checking initial files exist after rewind' \ diff --git a/t/t7102-reset.sh b/t/t7102-reset.sh index 29f5678b4c..e637c7d4db 100755 --- a/t/t7102-reset.sh +++ b/t/t7102-reset.sh @@ -3,9 +3,9 @@ # Copyright (c) 2007 Carlos Rica # -test_description='git-reset +test_description='git reset -Documented tests for git-reset' +Documented tests for git reset' . ./test-lib.sh diff --git a/t/t7103-reset-bare.sh b/t/t7103-reset-bare.sh index cdecebe456..42bf518c68 100755 --- a/t/t7103-reset-bare.sh +++ b/t/t7103-reset-bare.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-reset in a bare repository' +test_description='git reset in a bare repository' . ./test-lib.sh test_expect_success 'setup non-bare' ' diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 9ad5d635a2..25181388f8 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -3,7 +3,7 @@ # Copyright (c) 2006 Junio C Hamano # -test_description='git-checkout tests. +test_description='git checkout tests. Creates master, forks renamer and side branches from it. Test switching across them. @@ -337,4 +337,58 @@ test_expect_success \ test refs/heads/delete-me = "$(git symbolic-ref HEAD)" && test_must_fail git checkout --track -b track' +test_expect_success \ + 'checkout with --track fakes a sensible -b <name>' ' + git update-ref refs/remotes/origin/koala/bear renamer && + git update-ref refs/new/koala/bear renamer && + + git checkout --track origin/koala/bear && + test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" && + test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" && + + git checkout master && git branch -D koala/bear && + + git checkout --track refs/remotes/origin/koala/bear && + test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" && + test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" && + + git checkout master && git branch -D koala/bear && + + git checkout --track remotes/origin/koala/bear && + test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" && + test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" && + + git checkout master && git branch -D koala/bear && + + git checkout --track refs/new/koala/bear && + test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" && + test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" +' + +test_expect_success \ + 'checkout with --track, but without -b, fails with too short tracked name' ' + test_must_fail git checkout --track renamer' + +test_expect_success 'checkout an unmerged path should fail' ' + rm -f .git/index && + O=$(echo original | git hash-object -w --stdin) && + A=$(echo ourside | git hash-object -w --stdin) && + B=$(echo theirside | git hash-object -w --stdin) && + ( + echo "100644 $A 0 fild" && + echo "100644 $O 1 file" && + echo "100644 $A 2 file" && + echo "100644 $B 3 file" && + echo "100644 $A 0 filf" + ) | git update-index --index-info && + echo "none of the above" >sample && + cat sample >fild && + cat sample >file && + cat sample >filf && + test_must_fail git checkout fild file filf && + test_cmp sample fild && + test_cmp sample filf && + test_cmp sample file +' + test_done diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index 2b51c0d7d8..1636fac2a4 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -3,7 +3,7 @@ # Copyright (c) 2007 Michael Spang # -test_description='git-clean basic tests' +test_description='git clean basic tests' . ./test-lib.sh @@ -16,17 +16,17 @@ test_expect_success 'setup' ' echo build >.gitignore && echo \*.o >>.gitignore && git add . && - git-commit -m setup && + git commit -m setup && touch src/part2.c README && git add . ' -test_expect_success 'git-clean' ' +test_expect_success 'git clean' ' mkdir -p build docs && touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && - git-clean && + git clean && test -f Makefile && test -f README && test -f src/part1.c && @@ -39,11 +39,11 @@ test_expect_success 'git-clean' ' ' -test_expect_success 'git-clean src/' ' +test_expect_success 'git clean src/' ' mkdir -p build docs && touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && - git-clean src/ && + git clean src/ && test -f Makefile && test -f README && test -f src/part1.c && @@ -56,11 +56,11 @@ test_expect_success 'git-clean src/' ' ' -test_expect_success 'git-clean src/ src/' ' +test_expect_success 'git clean src/ src/' ' mkdir -p build docs && touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && - git-clean src/ src/ && + git clean src/ src/ && test -f Makefile && test -f README && test -f src/part1.c && @@ -73,11 +73,11 @@ test_expect_success 'git-clean src/ src/' ' ' -test_expect_success 'git-clean with prefix' ' +test_expect_success 'git clean with prefix' ' mkdir -p build docs src/test && touch a.out src/part3.c docs/manual.txt obj.o build/lib.so src/test/1.c && - (cd src/ && git-clean) && + (cd src/ && git clean) && test -f Makefile && test -f README && test -f src/part1.c && @@ -91,7 +91,7 @@ test_expect_success 'git-clean with prefix' ' ' -test_expect_success 'git-clean with relative prefix' ' +test_expect_success 'git clean with relative prefix' ' mkdir -p build docs && touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && @@ -106,7 +106,7 @@ test_expect_success 'git-clean with relative prefix' ' } ' -test_expect_success 'git-clean with absolute path' ' +test_expect_success 'git clean with absolute path' ' mkdir -p build docs && touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && @@ -121,7 +121,7 @@ test_expect_success 'git-clean with absolute path' ' } ' -test_expect_success 'git-clean with out of work tree relative path' ' +test_expect_success 'git clean with out of work tree relative path' ' mkdir -p build docs && touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && @@ -131,7 +131,7 @@ test_expect_success 'git-clean with out of work tree relative path' ' ) ' -test_expect_success 'git-clean with out of work tree absolute path' ' +test_expect_success 'git clean with out of work tree absolute path' ' mkdir -p build docs && touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && @@ -142,11 +142,11 @@ test_expect_success 'git-clean with out of work tree absolute path' ' ) ' -test_expect_success 'git-clean -d with prefix and path' ' +test_expect_success 'git clean -d with prefix and path' ' mkdir -p build docs src/feature && touch a.out src/part3.c src/feature/file.c docs/manual.txt obj.o build/lib.so && - (cd src/ && git-clean -d feature/) && + (cd src/ && git clean -d feature/) && test -f Makefile && test -f README && test -f src/part1.c && @@ -160,12 +160,12 @@ test_expect_success 'git-clean -d with prefix and path' ' ' -test_expect_success 'git-clean symbolic link' ' +test_expect_success 'git clean symbolic link' ' mkdir -p build docs && touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && ln -s docs/manual.txt src/part4.c - git-clean && + git clean && test -f Makefile && test -f README && test -f src/part1.c && @@ -179,10 +179,10 @@ test_expect_success 'git-clean symbolic link' ' ' -test_expect_success 'git-clean with wildcard' ' +test_expect_success 'git clean with wildcard' ' touch a.clean b.clean other.c && - git-clean "*.clean" && + git clean "*.clean" && test -f Makefile && test -f README && test -f src/part1.c && @@ -193,11 +193,11 @@ test_expect_success 'git-clean with wildcard' ' ' -test_expect_success 'git-clean -n' ' +test_expect_success 'git clean -n' ' mkdir -p build docs && touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && - git-clean -n && + git clean -n && test -f Makefile && test -f README && test -f src/part1.c && @@ -210,11 +210,11 @@ test_expect_success 'git-clean -n' ' ' -test_expect_success 'git-clean -d' ' +test_expect_success 'git clean -d' ' mkdir -p build docs && touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && - git-clean -d && + git clean -d && test -f Makefile && test -f README && test -f src/part1.c && @@ -227,11 +227,11 @@ test_expect_success 'git-clean -d' ' ' -test_expect_success 'git-clean -d src/ examples/' ' +test_expect_success 'git clean -d src/ examples/' ' mkdir -p build docs examples && touch a.out src/part3.c docs/manual.txt obj.o build/lib.so examples/1.c && - git-clean -d src/ examples/ && + git clean -d src/ examples/ && test -f Makefile && test -f README && test -f src/part1.c && @@ -245,11 +245,11 @@ test_expect_success 'git-clean -d src/ examples/' ' ' -test_expect_success 'git-clean -x' ' +test_expect_success 'git clean -x' ' mkdir -p build docs && touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && - git-clean -x && + git clean -x && test -f Makefile && test -f README && test -f src/part1.c && @@ -262,11 +262,11 @@ test_expect_success 'git-clean -x' ' ' -test_expect_success 'git-clean -d -x' ' +test_expect_success 'git clean -d -x' ' mkdir -p build docs && touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && - git-clean -d -x && + git clean -d -x && test -f Makefile && test -f README && test -f src/part1.c && @@ -279,11 +279,11 @@ test_expect_success 'git-clean -d -x' ' ' -test_expect_success 'git-clean -X' ' +test_expect_success 'git clean -X' ' mkdir -p build docs && touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && - git-clean -X && + git clean -X && test -f Makefile && test -f README && test -f src/part1.c && @@ -296,11 +296,11 @@ test_expect_success 'git-clean -X' ' ' -test_expect_success 'git-clean -d -X' ' +test_expect_success 'git clean -d -X' ' mkdir -p build docs && touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && - git-clean -d -X && + git clean -d -X && test -f Makefile && test -f README && test -f src/part1.c && @@ -331,7 +331,7 @@ test_expect_success 'clean.requireForce and -n' ' mkdir -p build docs && touch a.out src/part3.c docs/manual.txt obj.o build/lib.so && - git-clean -n && + git clean -n && test -f Makefile && test -f README && test -f src/part1.c && @@ -346,7 +346,7 @@ test_expect_success 'clean.requireForce and -n' ' test_expect_success 'clean.requireForce and -f' ' - git-clean -f && + git clean -f && test -f README && test -f src/part1.c && test -f src/part2.c && diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh index cbc0c34ce2..be73f7b60a 100755 --- a/t/t7400-submodule-basic.sh +++ b/t/t7400-submodule-basic.sh @@ -6,7 +6,7 @@ test_description='Basic porcelain support for submodules This test tries to verify basic sanity of the init, update and status -subcommands of git-submodule. +subcommands of git submodule. ' . ./test-lib.sh @@ -22,16 +22,16 @@ subcommands of git-submodule. # test_expect_success 'Prepare submodule testing' ' : > t && - git-add t && - git-commit -m "initial commit" && + git add t && + git commit -m "initial commit" && git branch initial HEAD && mkdir init && cd init && git init && echo a >a && git add a && - git-commit -m "submodule commit 1" && - git-tag -a -m "rev-1" rev-1 && + git commit -m "submodule commit 1" && + git tag -a -m "rev-1" rev-1 && rev1=$(git rev-parse HEAD) && if test -z "$rev1" then @@ -42,13 +42,13 @@ test_expect_success 'Prepare submodule testing' ' echo a >a && echo z >z && git add a init z && - git-commit -m "super commit 1" && + git commit -m "super commit 1" && mv init .subrepo && GIT_CONFIG=.gitmodules git config submodule.example.url git://example.com/init.git ' test_expect_success 'status should fail for unmapped paths' ' - if git-submodule status + if git submodule status then echo "[OOPS] submodule status succeeded" false @@ -60,16 +60,16 @@ test_expect_success 'status should fail for unmapped paths' ' ' test_expect_success 'status should only print one line' ' - lines=$(git-submodule status | wc -l) && + lines=$(git submodule status | wc -l) && test $lines = 1 ' test_expect_success 'status should initially be "missing"' ' - git-submodule status | grep "^-$rev1" + git submodule status | grep "^-$rev1" ' test_expect_success 'init should register submodule url in .git/config' ' - git-submodule init && + git submodule init && url=$(git config submodule.example.url) && if test "$url" != "git://example.com/init.git" then @@ -84,7 +84,7 @@ test_expect_success 'init should register submodule url in .git/config' ' test_expect_success 'update should fail when path is used by a file' ' echo "hello" >init && - if git-submodule update + if git submodule update then echo "[OOPS] update should have failed" false @@ -100,7 +100,7 @@ test_expect_success 'update should fail when path is used by a file' ' test_expect_success 'update should fail when path is used by a nonempty directory' ' mkdir init && echo "hello" >init/a && - if git-submodule update + if git submodule update then echo "[OOPS] update should have failed" false @@ -116,7 +116,7 @@ test_expect_success 'update should fail when path is used by a nonempty director test_expect_success 'update should work when path is an empty dir' ' rm -rf init && mkdir init && - git-submodule update && + git submodule update && head=$(cd init && git rev-parse HEAD) && if test -z "$head" then @@ -130,14 +130,14 @@ test_expect_success 'update should work when path is an empty dir' ' ' test_expect_success 'status should be "up-to-date" after update' ' - git-submodule status | grep "^ $rev1" + git submodule status | grep "^ $rev1" ' test_expect_success 'status should be "modified" after submodule commit' ' cd init && echo b >b && git add b && - git-commit -m "submodule commit 2" && + git commit -m "submodule commit 2" && rev2=$(git rev-parse HEAD) && cd .. && if test -z "$rev2" @@ -145,19 +145,19 @@ test_expect_success 'status should be "modified" after submodule commit' ' echo "[OOPS] submodule git rev-parse returned nothing" false fi && - git-submodule status | grep "^+$rev2" + git submodule status | grep "^+$rev2" ' test_expect_success 'the --cached sha1 should be rev1' ' - git-submodule --cached status | grep "^+$rev1" + git submodule --cached status | grep "^+$rev1" ' test_expect_success 'git diff should report the SHA1 of the new submodule commit' ' - git-diff | grep "^+Subproject commit $rev2" + git diff | grep "^+Subproject commit $rev2" ' test_expect_success 'update should checkout rev1' ' - git-submodule update init && + git submodule update init && head=$(cd init && git rev-parse HEAD) && if test -z "$head" then @@ -171,12 +171,12 @@ test_expect_success 'update should checkout rev1' ' ' test_expect_success 'status should be "up-to-date" after update' ' - git-submodule status | grep "^ $rev1" + git submodule status | grep "^ $rev1" ' test_expect_success 'checkout superproject with subproject already present' ' - git-checkout initial && - git-checkout master + git checkout initial && + git checkout master ' test_expect_success 'apply submodule diff' ' @@ -188,8 +188,8 @@ test_expect_success 'apply submodule diff' ' git commit -m "change subproject" ) && git update-index --add init && - git-commit -m "change init" && - git-format-patch -1 --stdout >P.diff && + git commit -m "change init" && + git format-patch -1 --stdout >P.diff && git checkout second && git apply --index P.diff && D=$(git diff --cached master) && diff --git a/t/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh index bf12dbdeef..61498293b9 100755 --- a/t/t7401-submodule-summary.sh +++ b/t/t7401-submodule-summary.sh @@ -5,7 +5,7 @@ test_description='Summary support for submodules -This test tries to verify the sanity of summary subcommand of git-submodule. +This test tries to verify the sanity of summary subcommand of git submodule. ' . ./test-lib.sh diff --git a/t/t7500-commit.sh b/t/t7500-commit.sh index 809bdba630..6e18a96319 100755 --- a/t/t7500-commit.sh +++ b/t/t7500-commit.sh @@ -3,7 +3,7 @@ # Copyright (c) 2007 Steven Grimm # -test_description='git-commit +test_description='git commit Tests for selected commit options.' @@ -46,15 +46,24 @@ test_expect_success 'unedited template with comments should not commit' ' ' test_expect_success 'a Signed-off-by line by itself should not commit' ' - ! GIT_EDITOR=../t7500/add-signed-off git commit --template "$TEMPLATE" + ( + test_set_editor "$TEST_DIRECTORY"/t7500/add-signed-off && + test_must_fail git commit --template "$TEMPLATE" + ) ' test_expect_success 'adding comments to a template should not commit' ' - ! GIT_EDITOR=../t7500/add-comments git commit --template "$TEMPLATE" + ( + test_set_editor "$TEST_DIRECTORY"/t7500/add-comments && + test_must_fail git commit --template "$TEMPLATE" + ) ' test_expect_success 'adding real content to a template should commit' ' - GIT_EDITOR=../t7500/add-content git commit --template "$TEMPLATE" && + ( + test_set_editor "$TEST_DIRECTORY"/t7500/add-content && + git commit --template "$TEMPLATE" + ) && commit_msg_is "template linecommit message" ' @@ -62,7 +71,10 @@ test_expect_success '-t option should be short for --template' ' echo "short template" > "$TEMPLATE" && echo "new content" >> foo && git add foo && - GIT_EDITOR=../t7500/add-content git commit -t "$TEMPLATE" && + ( + test_set_editor "$TEST_DIRECTORY"/t7500/add-content && + git commit -t "$TEMPLATE" + ) && commit_msg_is "short templatecommit message" ' @@ -71,7 +83,10 @@ test_expect_success 'config-specified template should commit' ' git config commit.template "$TEMPLATE" && echo "more content" >> foo && git add foo && - GIT_EDITOR=../t7500/add-content git commit && + ( + test_set_editor "$TEST_DIRECTORY"/t7500/add-content && + git commit + ) && git config --unset commit.template && commit_msg_is "new templatecommit message" ' @@ -79,7 +94,7 @@ test_expect_success 'config-specified template should commit' ' test_expect_success 'explicit commit message should override template' ' echo "still more content" >> foo && git add foo && - GIT_EDITOR=../t7500/add-content git commit --template "$TEMPLATE" \ + GIT_EDITOR="$TEST_DIRECTORY"/t7500/add-content git commit --template "$TEMPLATE" \ -m "command line msg" && commit_msg_is "command line msg" ' @@ -88,8 +103,10 @@ test_expect_success 'commit message from file should override template' ' echo "content galore" >> foo && git add foo && echo "standard input msg" | - GIT_EDITOR=../t7500/add-content git commit \ - --template "$TEMPLATE" --file - && + ( + test_set_editor "$TEST_DIRECTORY"/t7500/add-content && + git commit --template "$TEMPLATE" --file - + ) && commit_msg_is "standard input msg" ' @@ -132,10 +149,12 @@ EOF test_expect_success '--signoff' ' echo "yet another content *narf*" >> foo && - echo "zort" | - GIT_EDITOR=../t7500/add-content git commit -s -F - foo && + echo "zort" | ( + test_set_editor "$TEST_DIRECTORY"/t7500/add-content && + git commit -s -F - foo + ) && git cat-file commit HEAD | sed "1,/^$/d" > output && - diff expect output + test_cmp expect output ' test_expect_success 'commit message from file (1)' ' diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index 0edd9ddf73..63bfc6d8b3 100755 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -6,7 +6,7 @@ # FIXME: Test the various index usages, -i and -o, test reflog, # signoff -test_description='git-commit' +test_description='git commit' . ./test-lib.sh test_tick @@ -14,52 +14,52 @@ test_tick test_expect_success \ "initial status" \ "echo 'bongo bongo' >file && - git-add file && \ - git-status | grep 'Initial commit'" + git add file && \ + git status | grep 'Initial commit'" test_expect_success \ "fail initial amend" \ - "test_must_fail git-commit --amend" + "test_must_fail git commit --amend" test_expect_success \ "initial commit" \ - "git-commit -m initial" + "git commit -m initial" test_expect_success \ "invalid options 1" \ - "test_must_fail git-commit -m foo -m bar -F file" + "test_must_fail git commit -m foo -m bar -F file" test_expect_success \ "invalid options 2" \ - "test_must_fail git-commit -C HEAD -m illegal" + "test_must_fail git commit -C HEAD -m illegal" test_expect_success \ "using paths with -a" \ "echo King of the bongo >file && - test_must_fail git-commit -m foo -a file" + test_must_fail git commit -m foo -a file" test_expect_success \ "using paths with --interactive" \ "echo bong-o-bong >file && - ! (echo 7 | git-commit -m foo --interactive file)" + ! (echo 7 | git commit -m foo --interactive file)" test_expect_success \ "using invalid commit with -C" \ - "test_must_fail git-commit -C bogus" + "test_must_fail git commit -C bogus" test_expect_success \ "testing nothing to commit" \ - "test_must_fail git-commit -m initial" + "test_must_fail git commit -m initial" test_expect_success \ "next commit" \ "echo 'bongo bongo bongo' >file \ - git-commit -m next -a" + git commit -m next -a" test_expect_success \ "commit message from non-existing file" \ "echo 'more bongo: bongo bongo bongo bongo' >file && \ - test_must_fail git-commit -F gah -a" + test_must_fail git commit -F gah -a" # Empty except stray tabs and spaces on a few lines. sed -e 's/@$//' >msg <<EOF @@ -70,12 +70,12 @@ Signed-off-by: hula EOF test_expect_success \ "empty commit message" \ - "test_must_fail git-commit -F msg -a" + "test_must_fail git commit -F msg -a" test_expect_success \ "commit message from file" \ "echo 'this is the commit message, coming from a file' >msg && \ - git-commit -F msg -a" + git commit -F msg -a" cat >editor <<\EOF #!/bin/sh @@ -86,16 +86,16 @@ chmod 755 editor test_expect_success \ "amend commit" \ - "VISUAL=./editor git-commit --amend" + "VISUAL=./editor git commit --amend" test_expect_success \ "passing -m and -F" \ "echo 'enough with the bongos' >file && \ - test_must_fail git-commit -F msg -m amending ." + test_must_fail git commit -F msg -m amending ." test_expect_success \ "using message from other commit" \ - "git-commit -C HEAD^ ." + "git commit -C HEAD^ ." cat >editor <<\EOF #!/bin/sh @@ -107,25 +107,25 @@ chmod 755 editor test_expect_success \ "editing message from other commit" \ "echo 'hula hula' >file && \ - VISUAL=./editor git-commit -c HEAD^ -a" + VISUAL=./editor git commit -c HEAD^ -a" test_expect_success \ "message from stdin" \ "echo 'silly new contents' >file && \ - echo commit message from stdin | git-commit -F - -a" + echo commit message from stdin | git commit -F - -a" test_expect_success \ "overriding author from command line" \ "echo 'gak' >file && \ - git-commit -m 'author' --author 'Rubber Duck <rduck@convoy.org>' -a" + git commit -m 'author' --author 'Rubber Duck <rduck@convoy.org>' -a" test_expect_success \ "interactive add" \ - "echo 7 | git-commit --interactive | grep 'What now'" + "echo 7 | git commit --interactive | grep 'What now'" test_expect_success \ "showing committed revisions" \ - "git-rev-list HEAD >current" + "git rev-list HEAD >current" # We could just check the head sha1, but checking each commit makes it # easier to isolate bugs. @@ -140,8 +140,8 @@ d381ac431806e53f3dd7ac2f1ae0534f36d738b9 EOF test_expect_success \ - 'validate git-rev-list output.' \ - 'diff current expected' + 'validate git rev-list output.' \ + 'test_cmp expected current' test_expect_success 'partial commit that involves removal (1)' ' @@ -151,7 +151,7 @@ test_expect_success 'partial commit that involves removal (1)' ' git commit -m "Partial: add elif" elif && git diff-tree --name-status HEAD^ HEAD >current && echo "A elif" >expected && - diff expected current + test_cmp expected current ' @@ -160,7 +160,7 @@ test_expect_success 'partial commit that involves removal (2)' ' git commit -m "Partial: remove file" file && git diff-tree --name-status HEAD^ HEAD >current && echo "D file" >expected && - diff expected current + test_cmp expected current ' @@ -171,7 +171,7 @@ test_expect_success 'partial commit that involves removal (3)' ' git commit -m "Partial: modify elif" elif && git diff-tree --name-status HEAD^ HEAD >current && echo "M elif" >expected && - diff expected current + test_cmp expected current ' @@ -187,7 +187,7 @@ test_expect_success 'amend commit to fix author' ' expected && git commit --amend --author="$author" && git cat-file -p HEAD > current && - diff expected current + test_cmp expected current ' @@ -256,7 +256,7 @@ test_expect_success 'amend commit to fix author' ' expected && git commit --amend --author="$author" && git cat-file -p HEAD > current && - diff expected current + test_cmp expected current ' diff --git a/t/t7502-status.sh b/t/t7502-status.sh index 38a48b57c7..c8e4c2e7b4 100755 --- a/t/t7502-status.sh +++ b/t/t7502-status.sh @@ -3,7 +3,7 @@ # Copyright (c) 2007 Johannes E. Schindelin # -test_description='git-status' +test_description='git status' . ./test-lib.sh diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh index cd6c7c8342..ff189624d4 100755 --- a/t/t7505-prepare-commit-msg-hook.sh +++ b/t/t7505-prepare-commit-msg-hook.sh @@ -32,7 +32,7 @@ echo "#!$SHELL_PATH" > "$HOOK" cat >> "$HOOK" <<'EOF' if test "$2" = commit; then - source=$(git-rev-parse "$3") + source=$(git rev-parse "$3") else source=${2-default} fi diff --git a/t/t7506-status-submodule.sh b/t/t7506-status-submodule.sh index a75130cdbb..d9a08aac56 100755 --- a/t/t7506-status-submodule.sh +++ b/t/t7506-status-submodule.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-status for submodule' +test_description='git status for submodule' . ./test-lib.sh diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh index fee8fb77d4..9516f541e9 100755 --- a/t/t7600-merge.sh +++ b/t/t7600-merge.sh @@ -3,7 +3,7 @@ # Copyright (c) 2007 Lars Hjemli # -test_description='git-merge +test_description='git merge Testing basic merge operations/option parsing.' @@ -230,6 +230,10 @@ test_expect_success 'test option parsing' ' test_must_fail git merge ' +test_expect_success 'reject non-strategy with a git-merge-foo name' ' + test_must_fail git merge -s index c1 +' + test_expect_success 'merge c0 with c1' ' git reset --hard c0 && git merge c1 && @@ -498,4 +502,13 @@ test_expect_success 'merge fast-forward in a dirty tree' ' test_debug 'gitk --all' +test_expect_success 'in-index merge' ' + git reset --hard c0 && + git merge --no-ff -s resolve c1 > out && + grep "Wonderful." out && + verify_parents $c0 $c1 +' + +test_debug 'gitk --all' + test_done diff --git a/t/t7601-merge-pull-config.sh b/t/t7601-merge-pull-config.sh index 55aa6b5f27..7ba94ea99b 100755 --- a/t/t7601-merge-pull-config.sh +++ b/t/t7601-merge-pull-config.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-merge +test_description='git merge Testing pull.* configuration parsing.' diff --git a/t/t7602-merge-octopus-many.sh b/t/t7602-merge-octopus-many.sh index fcb8285746..01e5415e94 100755 --- a/t/t7602-merge-octopus-many.sh +++ b/t/t7602-merge-octopus-many.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-merge +test_description='git merge Testing octopus merge with more than 25 refs.' diff --git a/t/t7603-merge-reduce-heads.sh b/t/t7603-merge-reduce-heads.sh index 17b19dc11f..b47b7b9757 100755 --- a/t/t7603-merge-reduce-heads.sh +++ b/t/t7603-merge-reduce-heads.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-merge +test_description='git merge Testing octopus merge when reducing parents to independent branches.' diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh index 6081677d23..de977c5e2f 100755 --- a/t/t7604-merge-custom-message.sh +++ b/t/t7604-merge-custom-message.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-merge +test_description='git merge Testing merge when using a custom message for the merge commit.' diff --git a/t/t7605-merge-resolve.sh b/t/t7605-merge-resolve.sh index ee21a107fd..0cb9d11f21 100755 --- a/t/t7605-merge-resolve.sh +++ b/t/t7605-merge-resolve.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-merge +test_description='git merge Testing the resolve strategy.' @@ -36,7 +36,9 @@ test_expect_success 'merge c1 to c2' ' git diff --exit-code && test -f c0.c && test -f c1.c && - test -f c2.c + test -f c2.c && + test 3 = $(git ls-tree -r HEAD | wc -l) && + test 3 = $(git ls-files | wc -l) ' test_expect_success 'merge c2 to c3 (fails)' ' diff --git a/t/t7606-merge-custom.sh b/t/t7606-merge-custom.sh new file mode 100755 index 0000000000..52a451dd57 --- /dev/null +++ b/t/t7606-merge-custom.sh @@ -0,0 +1,49 @@ +#!/bin/sh + +test_description='git merge + +Testing a custom strategy.' + +. ./test-lib.sh + +cat >git-merge-theirs <<EOF +#!$SHELL_PATH +eval git read-tree --reset -u \\\$\$# +EOF +chmod +x git-merge-theirs +PATH=.:$PATH +export PATH + +test_expect_success 'setup' ' + echo c0 >c0.c && + git add c0.c && + git commit -m c0 && + git tag c0 && + echo c1 >c1.c && + git add c1.c && + git commit -m c1 && + git tag c1 && + git reset --hard c0 && + echo c1c1 >c1.c && + echo c2 >c2.c && + git add c1.c c2.c && + git commit -m c2 && + git tag c2 +' + +test_expect_success 'merge c2 with a custom strategy' ' + git reset --hard c1 && + git merge -s theirs c2 && + test "$(git rev-parse c1)" != "$(git rev-parse HEAD)" && + test "$(git rev-parse c1)" = "$(git rev-parse HEAD^1)" && + test "$(git rev-parse c2)" = "$(git rev-parse HEAD^2)" && + test "$(git rev-parse c2^{tree})" = "$(git rev-parse HEAD^{tree})" && + git diff --exit-code && + git diff --exit-code c2 HEAD && + git diff --exit-code c2 && + test -f c0.c && + grep c1c1 c1.c && + test -f c2.c +' + +test_done diff --git a/t/t7610-mergetool.sh b/t/t7610-mergetool.sh index 9285071c47..09fa5f115c 100755 --- a/t/t7610-mergetool.sh +++ b/t/t7610-mergetool.sh @@ -3,7 +3,7 @@ # Copyright (c) 2008 Charles Bailey # -test_description='git-mergetool +test_description='git mergetool Testing basic merge tool invocation' diff --git a/t/t7701-repack-unpack-unreachable.sh b/t/t7701-repack-unpack-unreachable.sh index 31c340fd38..531dac060a 100755 --- a/t/t7701-repack-unpack-unreachable.sh +++ b/t/t7701-repack-unpack-unreachable.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-repack works correctly' +test_description='git repack works correctly' . ./test-lib.sh diff --git a/t/t8001-annotate.sh b/t/t8001-annotate.sh index eabec2e06e..45cb60ea4b 100755 --- a/t/t8001-annotate.sh +++ b/t/t8001-annotate.sh @@ -4,7 +4,7 @@ test_description='git annotate' . ./test-lib.sh PROG='git annotate' -. ../annotate-tests.sh +. "$TEST_DIRECTORY"/annotate-tests.sh test_expect_success \ 'Annotating an old revision works' \ diff --git a/t/t8002-blame.sh b/t/t8002-blame.sh index 92ece30fa9..597cf0486f 100755 --- a/t/t8002-blame.sh +++ b/t/t8002-blame.sh @@ -4,6 +4,6 @@ test_description='git blame' . ./test-lib.sh PROG='git blame -c' -. ../annotate-tests.sh +. "$TEST_DIRECTORY"/annotate-tests.sh test_done diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 1c857cf4ab..d098a01ba3 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-send-email' +test_description='git send-email' . ./test-lib.sh PROG='git send-email' diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh index 843a5013b9..9b238c329b 100755 --- a/t/t9100-git-svn-basic.sh +++ b/t/t9100-git-svn-basic.sh @@ -3,7 +3,7 @@ # Copyright (c) 2006 Eric Wong # -test_description='git-svn basic tests' +test_description='git svn basic tests' GIT_SVN_LC_ALL=${LC_ALL:-$LANG} case "$GIT_SVN_LC_ALL" in @@ -17,10 +17,10 @@ esac . ./lib-git-svn.sh -say 'define NO_SVN_TESTS to skip git-svn tests' +say 'define NO_SVN_TESTS to skip git svn tests' test_expect_success \ - 'initialize git-svn' ' + 'initialize git svn' ' mkdir import && cd import && echo foo > foo && @@ -31,26 +31,26 @@ test_expect_success \ echo "zzz" > bar/zzz && echo "#!/bin/sh" > exec.sh && chmod +x exec.sh && - svn import -m "import for git-svn" . "$svnrepo" >/dev/null && + svn import -m "import for git svn" . "$svnrepo" >/dev/null && cd .. && rm -rf import && - git-svn init "$svnrepo"' + git svn init "$svnrepo"' test_expect_success \ 'import an SVN revision into git' \ - 'git-svn fetch' + 'git svn fetch' test_expect_success "checkout from svn" 'svn co "$svnrepo" "$SVN_TREE"' name='try a deep --rmdir with a commit' test_expect_success "$name" ' - git checkout -f -b mybranch remotes/git-svn && + git checkout -f -b mybranch ${remotes_git_svn} && mv dir/a/b/c/d/e/file dir/file && cp dir/file file && git update-index --add --remove dir/a/b/c/d/e/file dir/file file && git commit -m "$name" && - git-svn set-tree --find-copies-harder --rmdir \ - remotes/git-svn..mybranch && + git svn set-tree --find-copies-harder --rmdir \ + ${remotes_git_svn}..mybranch && svn up "$SVN_TREE" && test -d "$SVN_TREE"/dir && test ! -d "$SVN_TREE"/dir/a' @@ -63,61 +63,61 @@ test_expect_success "$name" " git update-index --remove dir/file && git update-index --add dir/file/file && git commit -m '$name' && - test_must_fail git-svn set-tree --find-copies-harder --rmdir \ - remotes/git-svn..mybranch" || true + test_must_fail git svn set-tree --find-copies-harder --rmdir \ + ${remotes_git_svn}..mybranch" || true name='detect node change from directory to file #1' test_expect_success "$name" ' rm -rf dir "$GIT_DIR"/index && - git checkout -f -b mybranch2 remotes/git-svn && + git checkout -f -b mybranch2 ${remotes_git_svn} && mv bar/zzz zzz && rm -rf bar && mv zzz bar && git update-index --remove -- bar/zzz && git update-index --add -- bar && git commit -m "$name" && - test_must_fail git-svn set-tree --find-copies-harder --rmdir \ - remotes/git-svn..mybranch2' || true + test_must_fail git svn set-tree --find-copies-harder --rmdir \ + ${remotes_git_svn}..mybranch2' || true name='detect node change from file to directory #2' test_expect_success "$name" ' rm -f "$GIT_DIR"/index && - git checkout -f -b mybranch3 remotes/git-svn && + git checkout -f -b mybranch3 ${remotes_git_svn} && rm bar/zzz && git update-index --remove bar/zzz && mkdir bar/zzz && echo yyy > bar/zzz/yyy && git update-index --add bar/zzz/yyy && git commit -m "$name" && - test_must_fail git-svn set-tree --find-copies-harder --rmdir \ - remotes/git-svn..mybranch3' || true + test_must_fail git svn set-tree --find-copies-harder --rmdir \ + ${remotes_git_svn}..mybranch3' || true name='detect node change from directory to file #2' test_expect_success "$name" ' rm -f "$GIT_DIR"/index && - git checkout -f -b mybranch4 remotes/git-svn && + git checkout -f -b mybranch4 ${remotes_git_svn} && rm -rf dir && git update-index --remove -- dir/file && touch dir && echo asdf > dir && git update-index --add -- dir && git commit -m "$name" && - test_must_fail git-svn set-tree --find-copies-harder --rmdir \ - remotes/git-svn..mybranch4' || true + test_must_fail git svn set-tree --find-copies-harder --rmdir \ + ${remotes_git_svn}..mybranch4' || true name='remove executable bit from a file' test_expect_success "$name" ' rm -f "$GIT_DIR"/index && - git checkout -f -b mybranch5 remotes/git-svn && + git checkout -f -b mybranch5 ${remotes_git_svn} && chmod -x exec.sh && git update-index exec.sh && git commit -m "$name" && - git-svn set-tree --find-copies-harder --rmdir \ - remotes/git-svn..mybranch5 && + git svn set-tree --find-copies-harder --rmdir \ + ${remotes_git_svn}..mybranch5 && svn up "$SVN_TREE" && test ! -x "$SVN_TREE"/exec.sh' @@ -127,8 +127,8 @@ test_expect_success "$name" ' chmod +x exec.sh && git update-index exec.sh && git commit -m "$name" && - git-svn set-tree --find-copies-harder --rmdir \ - remotes/git-svn..mybranch5 && + git svn set-tree --find-copies-harder --rmdir \ + ${remotes_git_svn}..mybranch5 && svn up "$SVN_TREE" && test -x "$SVN_TREE"/exec.sh' @@ -139,8 +139,8 @@ test_expect_success "$name" ' ln -s bar/zzz exec.sh && git update-index exec.sh && git commit -m "$name" && - git-svn set-tree --find-copies-harder --rmdir \ - remotes/git-svn..mybranch5 && + git svn set-tree --find-copies-harder --rmdir \ + ${remotes_git_svn}..mybranch5 && svn up "$SVN_TREE" && test -L "$SVN_TREE"/exec.sh' @@ -151,8 +151,8 @@ test_expect_success "$name" ' ln -s bar/zzz exec-2.sh && git update-index --add bar/zzz exec-2.sh && git commit -m "$name" && - git-svn set-tree --find-copies-harder --rmdir \ - remotes/git-svn..mybranch5 && + git svn set-tree --find-copies-harder --rmdir \ + ${remotes_git_svn}..mybranch5 && svn up "$SVN_TREE" && test -x "$SVN_TREE"/bar/zzz && test -L "$SVN_TREE"/exec-2.sh' @@ -164,8 +164,8 @@ test_expect_success "$name" ' cp help exec-2.sh && git update-index exec-2.sh && git commit -m "$name" && - git-svn set-tree --find-copies-harder --rmdir \ - remotes/git-svn..mybranch5 && + git svn set-tree --find-copies-harder --rmdir \ + ${remotes_git_svn}..mybranch5 && svn up "$SVN_TREE" && test -f "$SVN_TREE"/exec-2.sh && test ! -L "$SVN_TREE"/exec-2.sh && @@ -180,7 +180,7 @@ then echo '# hello' >> exec-2.sh && git update-index exec-2.sh && git commit -m 'éï∏' && - git-svn set-tree HEAD" + git svn set-tree HEAD" unset LC_ALL else say "UTF-8 locale not set, test skipped ($GIT_SVN_LC_ALL)" @@ -190,8 +190,8 @@ name='test fetch functionality (svn => git) with alternate GIT_SVN_ID' GIT_SVN_ID=alt export GIT_SVN_ID test_expect_success "$name" \ - 'git-svn init "$svnrepo" && git-svn fetch && - git rev-list --pretty=raw remotes/git-svn | grep ^tree | uniq > a && + 'git svn init "$svnrepo" && git svn fetch && + git rev-list --pretty=raw ${remotes_git_svn} | grep ^tree | uniq > a && git rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b && test_cmp a b' @@ -215,45 +215,45 @@ test_expect_success "$name" "test_cmp a expected" test_expect_success 'exit if remote refs are ambigious' " git config --add svn-remote.svn.fetch \ - bar:refs/remotes/git-svn && - test_must_fail git-svn migrate + bar:refs/${remotes_git_svn} && + test_must_fail git svn migrate " test_expect_success 'exit if init-ing a would clobber a URL' ' svnadmin create "${PWD}/svnrepo2" && svn mkdir -m "mkdir bar" "${svnrepo}2/bar" && git config --unset svn-remote.svn.fetch \ - "^bar:refs/remotes/git-svn$" && - test_must_fail git-svn init "${svnrepo}2/bar" + "^bar:refs/${remotes_git_svn}$" && + test_must_fail git svn init "${svnrepo}2/bar" ' test_expect_success \ 'init allows us to connect to another directory in the same repo' ' - git-svn init --minimize-url -i bar "$svnrepo/bar" && + git svn init --minimize-url -i bar "$svnrepo/bar" && git config --get svn-remote.svn.fetch \ "^bar:refs/remotes/bar$" && git config --get svn-remote.svn.fetch \ - "^:refs/remotes/git-svn$" + "^:refs/${remotes_git_svn}$" ' test_expect_success 'able to dcommit to a subdirectory' " - git-svn fetch -i bar && + git svn fetch -i bar && git checkout -b my-bar refs/remotes/bar && echo abc > d && git update-index --add d && git commit -m '/bar/d should be in the log' && - git-svn dcommit -i bar && + git svn dcommit -i bar && test -z \"\`git diff refs/heads/my-bar refs/remotes/bar\`\" && mkdir newdir && echo new > newdir/dir && git update-index --add newdir/dir && git commit -m 'add a new directory' && - git-svn dcommit -i bar && + git svn dcommit -i bar && test -z \"\`git diff refs/heads/my-bar refs/remotes/bar\`\" && echo foo >> newdir/dir && git update-index newdir/dir && git commit -m 'modify a file in new directory' && - git-svn dcommit -i bar && + git svn dcommit -i bar && test -z \"\`git diff refs/heads/my-bar refs/remotes/bar\`\" " @@ -261,7 +261,7 @@ test_expect_success 'able to set-tree to a subdirectory' " echo cba > d && git update-index d && git commit -m 'update /bar/d' && - git-svn set-tree -i bar HEAD && + git svn set-tree -i bar HEAD && test -z \"\`git diff refs/heads/my-bar refs/remotes/bar\`\" " diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh index f420796c31..1e31d6ea72 100755 --- a/t/t9101-git-svn-props.sh +++ b/t/t9101-git-svn-props.sh @@ -3,7 +3,7 @@ # Copyright (c) 2006 Eric Wong # -test_description='git-svn property tests' +test_description='git svn property tests' . ./lib-git-svn.sh mkdir import @@ -26,29 +26,29 @@ cd import EOF printf "Hello\r\nWorld\r\n" > crlf - a_crlf=`git-hash-object -w crlf` + a_crlf=`git hash-object -w crlf` printf "Hello\rWorld\r" > cr - a_cr=`git-hash-object -w cr` + a_cr=`git hash-object -w cr` printf "Hello\nWorld\n" > lf - a_lf=`git-hash-object -w lf` + a_lf=`git hash-object -w lf` printf "Hello\r\nWorld" > ne_crlf - a_ne_crlf=`git-hash-object -w ne_crlf` + a_ne_crlf=`git hash-object -w ne_crlf` printf "Hello\nWorld" > ne_lf - a_ne_lf=`git-hash-object -w ne_lf` + a_ne_lf=`git hash-object -w ne_lf` printf "Hello\rWorld" > ne_cr - a_ne_cr=`git-hash-object -w ne_cr` + a_ne_cr=`git hash-object -w ne_cr` touch empty - a_empty=`git-hash-object -w empty` + a_empty=`git hash-object -w empty` printf "\n" > empty_lf - a_empty_lf=`git-hash-object -w empty_lf` + a_empty_lf=`git hash-object -w empty_lf` printf "\r" > empty_cr - a_empty_cr=`git-hash-object -w empty_cr` + a_empty_cr=`git hash-object -w empty_cr` printf "\r\n" > empty_crlf - a_empty_crlf=`git-hash-object -w empty_crlf` + a_empty_crlf=`git hash-object -w empty_crlf` - svn import --no-auto-props -m 'import for git-svn' . "$svnrepo" >/dev/null + svn import --no-auto-props -m 'import for git svn' . "$svnrepo" >/dev/null cd .. rm -rf import @@ -66,16 +66,16 @@ test_expect_success 'setup some commits to svn' \ svn commit -m "Propset Id" && cd ..' -test_expect_success 'initialize git-svn' 'git-svn init "$svnrepo"' -test_expect_success 'fetch revisions from svn' 'git-svn fetch' +test_expect_success 'initialize git svn' 'git svn init "$svnrepo"' +test_expect_success 'fetch revisions from svn' 'git svn fetch' name='test svn:keywords ignoring' test_expect_success "$name" \ - 'git checkout -b mybranch remotes/git-svn && + 'git checkout -b mybranch ${remotes_git_svn} && echo Hi again >> kw.c && git commit -a -m "test keywords ignoring" && - git-svn set-tree remotes/git-svn..mybranch && - git pull . remotes/git-svn' + git svn set-tree ${remotes_git_svn}..mybranch && + git pull . ${remotes_git_svn}' expect='/* $Id$ */' got="`sed -ne 2p kw.c`" @@ -90,8 +90,8 @@ test_expect_success "propset CR on crlf files" \ cd ..' test_expect_success 'fetch and pull latest from svn and checkout a new wc' \ - 'git-svn fetch && - git pull . remotes/git-svn && + 'git svn fetch && + git pull . ${remotes_git_svn} && svn co "$svnrepo" new_wc' for i in crlf ne_crlf lf ne_lf cr ne_cr empty_cr empty_lf empty empty_crlf @@ -103,8 +103,8 @@ done cd test_wc printf '$Id$\rHello\rWorld\r' > cr printf '$Id$\rHello\rWorld' > ne_cr - a_cr=`printf '$Id$\r\nHello\r\nWorld\r\n' | git-hash-object --stdin` - a_ne_cr=`printf '$Id$\r\nHello\r\nWorld' | git-hash-object --stdin` + a_cr=`printf '$Id$\r\nHello\r\nWorld\r\n' | git hash-object --stdin` + a_ne_cr=`printf '$Id$\r\nHello\r\nWorld' | git hash-object --stdin` test_expect_success 'Set CRLF on cr files' \ 'svn propset svn:eol-style CRLF cr && svn propset svn:eol-style CRLF ne_cr && @@ -113,10 +113,10 @@ cd test_wc svn commit -m "propset CRLF on cr files"' cd .. test_expect_success 'fetch and pull latest from svn' \ - 'git-svn fetch && git pull . remotes/git-svn' + 'git svn fetch && git pull . ${remotes_git_svn}' -b_cr="`git-hash-object cr`" -b_ne_cr="`git-hash-object ne_cr`" +b_cr="`git hash-object cr`" +b_ne_cr="`git hash-object ne_cr`" test_expect_success 'CRLF + $Id$' "test '$a_cr' = '$b_cr'" test_expect_success 'CRLF + $Id$ (no newline)' "test '$a_ne_cr' = '$b_ne_cr'" @@ -145,7 +145,7 @@ test_expect_success 'test show-ignore' " svn propset -R svn:ignore 'no-such-file*' . svn commit -m 'propset svn:ignore' cd .. && - git-svn show-ignore > show-ignore.got && + git svn show-ignore > show-ignore.got && cmp show-ignore.expect show-ignore.got " @@ -161,8 +161,8 @@ cat >create-ignore-index.expect <<\EOF EOF test_expect_success 'test create-ignore' " - git-svn fetch && git pull . remotes/git-svn && - git-svn create-ignore && + git svn fetch && git pull . ${remotes_git_svn} && + git svn create-ignore && cmp ./.gitignore create-ignore.expect && cmp ./deeply/.gitignore create-ignore.expect && cmp ./deeply/nested/.gitignore create-ignore.expect && @@ -182,15 +182,15 @@ EOF # pattern, it can pass even though the propget did not execute on the # right directory. test_expect_success 'test propget' " - git-svn propget svn:ignore . | cmp - prop.expect && + git svn propget svn:ignore . | cmp - prop.expect && cd deeply && - git-svn propget svn:ignore . | cmp - ../prop.expect && - git-svn propget svn:entry:committed-rev nested/directory/.keep \ + git svn propget svn:ignore . | cmp - ../prop.expect && + git svn propget svn:entry:committed-rev nested/directory/.keep \ | cmp - ../prop2.expect && - git-svn propget svn:ignore .. | cmp - ../prop.expect && - git-svn propget svn:ignore nested/ | cmp - ../prop.expect && - git-svn propget svn:ignore ./nested | cmp - ../prop.expect && - git-svn propget svn:ignore .././deeply/nested | cmp - ../prop.expect + git svn propget svn:ignore .. | cmp - ../prop.expect && + git svn propget svn:ignore nested/ | cmp - ../prop.expect && + git svn propget svn:ignore ./nested | cmp - ../prop.expect && + git svn propget svn:ignore .././deeply/nested | cmp - ../prop.expect " cat >prop.expect <<\EOF @@ -210,8 +210,8 @@ Properties on 'nested/directory/.keep': EOF test_expect_success 'test proplist' " - git-svn proplist . | cmp - prop.expect && - git-svn proplist nested/directory/.keep | cmp - prop2.expect + git svn proplist . | cmp - prop.expect && + git svn proplist nested/directory/.keep | cmp - prop2.expect " test_done diff --git a/t/t9102-git-svn-deep-rmdir.sh b/t/t9102-git-svn-deep-rmdir.sh index 0e7ce34b9b..e223218015 100755 --- a/t/t9102-git-svn-deep-rmdir.sh +++ b/t/t9102-git-svn-deep-rmdir.sh @@ -1,5 +1,5 @@ #!/bin/sh -test_description='git-svn rmdir' +test_description='git svn rmdir' . ./lib-git-svn.sh test_expect_success 'initialize repo' ' @@ -9,20 +9,20 @@ test_expect_success 'initialize repo' ' mkdir -p deeply/nested/directory/number/2 && echo foo > deeply/nested/directory/number/1/file && echo foo > deeply/nested/directory/number/2/another && - svn import -m "import for git-svn" . "$svnrepo" && + svn import -m "import for git svn" . "$svnrepo" && cd .. ' -test_expect_success 'mirror via git-svn' ' - git-svn init "$svnrepo" && - git-svn fetch && - git checkout -f -b test-rmdir remotes/git-svn +test_expect_success 'mirror via git svn' ' + git svn init "$svnrepo" && + git svn fetch && + git checkout -f -b test-rmdir ${remotes_git_svn} ' test_expect_success 'Try a commit on rmdir' ' git rm -f deeply/nested/directory/number/2/another && git commit -a -m "remove another" && - git-svn set-tree --rmdir HEAD && + git svn set-tree --rmdir HEAD && svn ls -R "$svnrepo" | grep ^deeply/nested/directory/number/1 ' diff --git a/t/t9103-git-svn-tracked-directory-removed.sh b/t/t9103-git-svn-tracked-directory-removed.sh index 9ffd8458ef..963dd95e4a 100755 --- a/t/t9103-git-svn-tracked-directory-removed.sh +++ b/t/t9103-git-svn-tracked-directory-removed.sh @@ -3,7 +3,7 @@ # Copyright (c) 2007 Eric Wong # -test_description='git-svn tracking removed top-level path' +test_description='git svn tracking removed top-level path' . ./lib-git-svn.sh test_expect_success 'make history for tracking' ' diff --git a/t/t9104-git-svn-follow-parent.sh b/t/t9104-git-svn-follow-parent.sh index 4d964e2db7..0a091e048e 100755 --- a/t/t9104-git-svn-follow-parent.sh +++ b/t/t9104-git-svn-follow-parent.sh @@ -3,7 +3,7 @@ # Copyright (c) 2006 Eric Wong # -test_description='git-svn fetching' +test_description='git svn fetching' . ./lib-git-svn.sh test_expect_success 'initialize repo' ' @@ -27,8 +27,8 @@ test_expect_success 'initialize repo' ' ' test_expect_success 'init and fetch a moved directory' ' - git-svn init --minimize-url -i thunk "$svnrepo"/thunk && - git-svn fetch -i thunk && + git svn init --minimize-url -i thunk "$svnrepo"/thunk && + git svn fetch -i thunk && test "`git rev-parse --verify refs/remotes/thunk@2`" \ = "`git rev-parse --verify refs/remotes/thunk~1`" && test "`git cat-file blob refs/remotes/thunk:readme |\ @@ -43,7 +43,7 @@ test_expect_success 'init and fetch from one svn-remote' ' trunk:refs/remotes/svn/trunk && git config --add svn-remote.svn.fetch \ thunk:refs/remotes/svn/thunk && - git-svn fetch -i svn/thunk && + git svn fetch -i svn/thunk && test "`git rev-parse --verify refs/remotes/svn/trunk`" \ = "`git rev-parse --verify refs/remotes/svn/thunk~1`" && test "`git cat-file blob refs/remotes/svn/thunk:readme |\ @@ -57,8 +57,8 @@ test_expect_success 'follow deleted parent' ' -r2 "$svnrepo"/trunk "$svnrepo"/junk) && git config --add svn-remote.svn.fetch \ junk:refs/remotes/svn/junk && - git-svn fetch -i svn/thunk && - git-svn fetch -i svn/junk && + git svn fetch -i svn/thunk && + git svn fetch -i svn/junk && test -z "`git diff svn/junk svn/trunk`" && test "`git merge-base svn/junk svn/trunk`" \ = "`git rev-parse svn/trunk`" @@ -69,9 +69,9 @@ test_expect_success 'follow larger parent' ' echo hi > import/trunk/thunk/bump/thud/file && svn import -m "import a larger parent" import "$svnrepo"/larger-parent && svn cp -m "hi" "$svnrepo"/larger-parent "$svnrepo"/another-larger && - git-svn init --minimize-url -i larger \ + git svn init --minimize-url -i larger \ "$svnrepo"/another-larger/trunk/thunk/bump/thud && - git-svn fetch -i larger && + git svn fetch -i larger && git rev-parse --verify refs/remotes/larger && git rev-parse --verify \ refs/remotes/larger-parent/trunk/thunk/bump/thud && @@ -92,15 +92,15 @@ test_expect_success 'follow higher-level parent' ' cd .. svn mkdir -m "new glob at top level" "$svnrepo"/glob && svn mv -m "move blob down a level" "$svnrepo"/blob "$svnrepo"/glob/blob && - git-svn init --minimize-url -i blob "$svnrepo"/glob/blob && - git-svn fetch -i blob + git svn init --minimize-url -i blob "$svnrepo"/glob/blob && + git svn fetch -i blob ' test_expect_success 'follow deleted directory' ' svn mv -m "bye!" "$svnrepo"/glob/blob/hi "$svnrepo"/glob/blob/bye && svn rm -m "remove glob" "$svnrepo"/glob && - git-svn init --minimize-url -i glob "$svnrepo"/glob && - git-svn fetch -i glob && + git svn init --minimize-url -i glob "$svnrepo"/glob && + git svn fetch -i glob && test "`git cat-file blob refs/remotes/glob:blob/bye`" = hi && test "`git ls-tree refs/remotes/glob | wc -l `" -eq 1 ' @@ -129,9 +129,9 @@ test_expect_success 'follow-parent avoids deleting relevant info' ' poke native/t/c.t && svn commit -m "reorg test" && cd .. && - git-svn init --minimize-url -i r9270-t \ + git svn init --minimize-url -i r9270-t \ "$svnrepo"/r9270/trunk/subversion/bindings/swig/perl/native/t && - git-svn fetch -i r9270-t && + git svn fetch -i r9270-t && test `git rev-list r9270-t | wc -l` -eq 2 && test "`git ls-tree --name-only r9270-t~1`" = \ "`git ls-tree --name-only r9270-t`" @@ -139,9 +139,9 @@ test_expect_success 'follow-parent avoids deleting relevant info' ' test_expect_success "track initial change if it was only made to parent" ' svn cp -m "wheee!" "$svnrepo"/r9270/trunk "$svnrepo"/r9270/drunk && - git-svn init --minimize-url -i r9270-d \ + git svn init --minimize-url -i r9270-d \ "$svnrepo"/r9270/drunk/subversion/bindings/swig/perl/native/t && - git-svn fetch -i r9270-d && + git svn fetch -i r9270-d && test `git rev-list r9270-d | wc -l` -eq 3 && test "`git ls-tree --name-only r9270-t`" = \ "`git ls-tree --name-only r9270-d`" && @@ -151,19 +151,19 @@ test_expect_success "track initial change if it was only made to parent" ' test_expect_success "track multi-parent paths" ' svn cp -m "resurrect /glob" "$svnrepo"/r9270 "$svnrepo"/glob && - git-svn multi-fetch && + git svn multi-fetch && test `git cat-file commit refs/remotes/glob | \ grep "^parent " | wc -l` -eq 2 ' test_expect_success "multi-fetch continues to work" " - git-svn multi-fetch + git svn multi-fetch " test_expect_success "multi-fetch works off a 'clean' repository" ' rm -r "$GIT_DIR/svn" "$GIT_DIR/refs/remotes" "$GIT_DIR/logs" && mkdir "$GIT_DIR/svn" && - git-svn multi-fetch + git svn multi-fetch ' test_debug 'gitk --all &' diff --git a/t/t9105-git-svn-commit-diff.sh b/t/t9105-git-svn-commit-diff.sh index 63230367bb..ba99abb6d9 100755 --- a/t/t9105-git-svn-commit-diff.sh +++ b/t/t9105-git-svn-commit-diff.sh @@ -1,7 +1,7 @@ #!/bin/sh # # Copyright (c) 2006 Eric Wong -test_description='git-svn commit-diff' +test_description='git svn commit-diff' . ./lib-git-svn.sh test_expect_success 'initialize repo' ' @@ -26,16 +26,16 @@ prev=`git rev-parse --verify HEAD^1` test_expect_success 'test the commit-diff command' ' test -n "$prev" && test -n "$head" && - git-svn commit-diff -r1 "$prev" "$head" "$svnrepo" && + git svn commit-diff -r1 "$prev" "$head" "$svnrepo" && svn co "$svnrepo" wc && cmp readme wc/readme ' -test_expect_success 'commit-diff to a sub-directory (with git-svn config)' ' +test_expect_success 'commit-diff to a sub-directory (with git svn config)' ' svn import -m "sub-directory" import "$svnrepo"/subdir && - git-svn init --minimize-url "$svnrepo"/subdir && - git-svn fetch && - git-svn commit-diff -r3 "$prev" "$head" && + git svn init --minimize-url "$svnrepo"/subdir && + git svn fetch && + git svn commit-diff -r3 "$prev" "$head" && svn cat "$svnrepo"/subdir/readme > readme.2 && cmp readme readme.2 ' diff --git a/t/t9106-git-svn-commit-diff-clobber.sh b/t/t9106-git-svn-commit-diff-clobber.sh index 83896e9687..6eb0fd85c8 100755 --- a/t/t9106-git-svn-commit-diff-clobber.sh +++ b/t/t9106-git-svn-commit-diff-clobber.sh @@ -1,7 +1,7 @@ #!/bin/sh # # Copyright (c) 2006 Eric Wong -test_description='git-svn commit-diff clobber' +test_description='git svn commit-diff clobber' . ./lib-git-svn.sh test_expect_success 'initialize repo' ' @@ -27,7 +27,7 @@ test_expect_success 'commit change from svn side' ' test_expect_success 'commit conflicting change from git' ' echo second line from git >> file && git commit -a -m "second line from git" && - test_must_fail git-svn commit-diff -r1 HEAD~1 HEAD "$svnrepo" + test_must_fail git svn commit-diff -r1 HEAD~1 HEAD "$svnrepo" ' test_expect_success 'commit complementing change from git' ' @@ -36,13 +36,13 @@ test_expect_success 'commit complementing change from git' ' git commit -a -m "second line from svn" && echo third line from git >> file && git commit -a -m "third line from git" && - git-svn commit-diff -r2 HEAD~1 HEAD "$svnrepo" + git svn commit-diff -r2 HEAD~1 HEAD "$svnrepo" ' test_expect_success 'dcommit fails to commit because of conflict' ' - git-svn init "$svnrepo" && - git-svn fetch && - git reset --hard refs/remotes/git-svn && + git svn init "$svnrepo" && + git svn fetch && + git reset --hard refs/${remotes_git_svn} && svn co "$svnrepo" t.svn && cd t.svn && echo fourth line from svn >> file && @@ -52,18 +52,18 @@ test_expect_success 'dcommit fails to commit because of conflict' ' rm -rf t.svn && echo "fourth line from git" >> file && git commit -a -m "fourth line from git" && - test_must_fail git-svn dcommit + test_must_fail git svn dcommit ' test_expect_success 'dcommit does the svn equivalent of an index merge' " - git reset --hard refs/remotes/git-svn && + git reset --hard refs/${remotes_git_svn} && echo 'index merge' > file2 && git update-index --add file2 && git commit -a -m 'index merge' && echo 'more changes' >> file2 && git update-index file2 && git commit -a -m 'more changes' && - git-svn dcommit + git svn dcommit " test_expect_success 'commit another change from svn side' ' @@ -76,8 +76,8 @@ test_expect_success 'commit another change from svn side' ' rm -rf t.svn ' -test_expect_success 'multiple dcommit from git-svn will not clobber svn' " - git reset --hard refs/remotes/git-svn && +test_expect_success 'multiple dcommit from git svn will not clobber svn' " + git reset --hard refs/${remotes_git_svn} && echo new file >> new-file && git update-index --add new-file && git commit -a -m 'new file' && diff --git a/t/t9106-git-svn-dcommit-clobber-series.sh b/t/t9106-git-svn-dcommit-clobber-series.sh index bc37db9d62..fd185011b7 100755 --- a/t/t9106-git-svn-dcommit-clobber-series.sh +++ b/t/t9106-git-svn-dcommit-clobber-series.sh @@ -1,7 +1,7 @@ #!/bin/sh # # Copyright (c) 2007 Eric Wong -test_description='git-svn dcommit clobber series' +test_description='git svn dcommit clobber series' . ./lib-git-svn.sh test_expect_success 'initialize repo' ' diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh index d9b553ad55..acad16a6f0 100755 --- a/t/t9107-git-svn-migrate.sh +++ b/t/t9107-git-svn-migrate.sh @@ -1,6 +1,6 @@ #!/bin/sh # Copyright (c) 2006 Eric Wong -test_description='git-svn metadata migrations from previous versions' +test_description='git svn metadata migrations from previous versions' . ./lib-git-svn.sh test_expect_success 'setup old-looking metadata' ' @@ -14,34 +14,34 @@ test_expect_success 'setup old-looking metadata' ' done && \ svn import -m test . "$svnrepo" cd .. && - git-svn init "$svnrepo" && - git-svn fetch && + git svn init "$svnrepo" && + git svn fetch && mv "$GIT_DIR"/svn/* "$GIT_DIR"/ && mv "$GIT_DIR"/svn/.metadata "$GIT_DIR"/ && rmdir "$GIT_DIR"/svn && - git update-ref refs/heads/git-svn-HEAD refs/remotes/git-svn && - git update-ref refs/heads/svn-HEAD refs/remotes/git-svn && - git update-ref -d refs/remotes/git-svn refs/remotes/git-svn + git update-ref refs/heads/git-svn-HEAD refs/${remotes_git_svn} && + git update-ref refs/heads/svn-HEAD refs/${remotes_git_svn} && + git update-ref -d refs/${remotes_git_svn} refs/${remotes_git_svn} ' head=`git rev-parse --verify refs/heads/git-svn-HEAD^0` test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'" -test_expect_success 'initialize old-style (v0) git-svn layout' ' +test_expect_success 'initialize old-style (v0) git svn layout' ' mkdir -p "$GIT_DIR"/git-svn/info "$GIT_DIR"/svn/info && echo "$svnrepo" > "$GIT_DIR"/git-svn/info/url && echo "$svnrepo" > "$GIT_DIR"/svn/info/url && - git-svn migrate && - ! test -d "$GIT_DIR"/git-svn && - git rev-parse --verify refs/remotes/git-svn^0 && + git svn migrate && + ! test -d "$GIT_DIR"/git svn && + git rev-parse --verify refs/${remotes_git_svn}^0 && git rev-parse --verify refs/remotes/svn^0 && test "$(git config --get svn-remote.svn.url)" = "$svnrepo" && test `git config --get svn-remote.svn.fetch` = \ - ":refs/remotes/git-svn" + ":refs/${remotes_git_svn}" ' test_expect_success 'initialize a multi-repository repo' ' - git-svn init "$svnrepo" -T trunk -t tags -b branches && + git svn init "$svnrepo" -T trunk -t tags -b branches && git config --get-all svn-remote.svn.fetch > fetch.out && grep "^trunk:refs/remotes/trunk$" fetch.out && test -n "`git config --get svn-remote.svn.branches \ @@ -61,7 +61,7 @@ test_expect_success 'initialize a multi-repository repo' ' # refs should all be different, but the trees should all be the same: test_expect_success 'multi-fetch works on partial urls + paths' " - git-svn multi-fetch && + git svn multi-fetch && for i in trunk a b tags/0.1 tags/0.2 tags/0.3; do git rev-parse --verify refs/remotes/\$i^0 >> refs.out || exit 1; done && @@ -85,7 +85,7 @@ test_expect_success 'migrate --minimize on old inited layout' ' ( mkdir -p "$GIT_DIR"/svn/$ref/info/ && echo "$svnrepo"$path > "$GIT_DIR"/svn/$ref/info/url ) || exit 1; done && - git-svn migrate --minimize && + git svn migrate --minimize && test -z "`git config -l |grep -v "^svn-remote\.git-svn\."`" && git config --get-all svn-remote.svn.fetch > fetch.out && grep "^trunk:refs/remotes/trunk$" fetch.out && @@ -94,11 +94,11 @@ test_expect_success 'migrate --minimize on old inited layout' ' grep "^tags/0\.1:refs/remotes/tags/0\.1$" fetch.out && grep "^tags/0\.2:refs/remotes/tags/0\.2$" fetch.out && grep "^tags/0\.3:refs/remotes/tags/0\.3$" fetch.out - grep "^:refs/remotes/git-svn" fetch.out + grep "^:refs/${remotes_git_svn}" fetch.out ' test_expect_success ".rev_db auto-converted to .rev_map.UUID" ' - git-svn fetch -i trunk && + git svn fetch -i trunk && test -z "$(ls "$GIT_DIR"/svn/trunk/.rev_db.* 2>/dev/null)" && expect="$(ls "$GIT_DIR"/svn/trunk/.rev_map.*)" && test -n "$expect" && @@ -106,7 +106,7 @@ test_expect_success ".rev_db auto-converted to .rev_map.UUID" ' convert_to_rev_db "$expect" "$rev_db" && rm -f "$expect" && test -f "$rev_db" && - git-svn fetch -i trunk && + git svn fetch -i trunk && test -z "$(ls "$GIT_DIR"/svn/trunk/.rev_db.* 2>/dev/null)" && test ! -e "$GIT_DIR"/svn/trunk/.rev_db && test -f "$expect" diff --git a/t/t9108-git-svn-glob.sh b/t/t9108-git-svn-glob.sh index 8b792a1370..d8582b1aa5 100755 --- a/t/t9108-git-svn-glob.sh +++ b/t/t9108-git-svn-glob.sh @@ -1,6 +1,6 @@ #!/bin/sh # Copyright (c) 2007 Eric Wong -test_description='git-svn globbing refspecs' +test_description='git svn globbing refspecs' . ./lib-git-svn.sh cat > expect.end <<EOF @@ -46,7 +46,7 @@ test_expect_success 'test refspec globbing' ' "branches/*/src/a:refs/remotes/branches/*" && git config --add svn-remote.svn.tags\ "tags/*/src/a:refs/remotes/tags/*" && - git-svn multi-fetch && + git svn multi-fetch && git log --pretty=oneline refs/remotes/tags/end | \ sed -e "s/^.\{41\}//" > output.end && test_cmp expect.end output.end && @@ -74,7 +74,7 @@ test_expect_success 'test left-hand-side only globbing' ' poke tags/end/src/b/readme && svn commit -m "try to try" ) && - git-svn fetch two && + git svn fetch two && test `git rev-list refs/remotes/two/tags/end | wc -l` -eq 6 && test `git rev-list refs/remotes/two/branches/start | wc -l` -eq 3 && test `git rev-parse refs/remotes/two/branches/start~2` = \ @@ -104,7 +104,7 @@ test_expect_success 'test disallow multi-globs' ' poke tags/end/src/b/readme && svn commit -m "try to try" ) && - test_must_fail git-svn fetch three 2> stderr.three && + test_must_fail git svn fetch three 2> stderr.three && test_cmp expect.three stderr.three ' diff --git a/t/t9108-git-svn-multi-glob.sh b/t/t9108-git-svn-multi-glob.sh index 3583721652..8f79c3f251 100755 --- a/t/t9108-git-svn-multi-glob.sh +++ b/t/t9108-git-svn-multi-glob.sh @@ -1,6 +1,6 @@ #!/bin/sh # Copyright (c) 2007 Eric Wong -test_description='git-svn globbing refspecs' +test_description='git svn globbing refspecs' . ./lib-git-svn.sh cat > expect.end <<EOF @@ -46,7 +46,7 @@ test_expect_success 'test refspec globbing' ' "branches/*/*/src/a:refs/remotes/branches/*/*" && git config --add svn-remote.svn.tags\ "tags/*/src/a:refs/remotes/tags/*" && - git-svn multi-fetch && + git svn multi-fetch && git log --pretty=oneline refs/remotes/tags/end | \ sed -e "s/^.\{41\}//" > output.end && test_cmp expect.end output.end && @@ -74,7 +74,7 @@ test_expect_success 'test left-hand-side only globbing' ' poke tags/end/src/b/readme && svn commit -m "try to try" ) && - git-svn fetch two && + git svn fetch two && test `git rev-list refs/remotes/two/tags/end | wc -l` -eq 6 && test `git rev-list refs/remotes/two/branches/v1/start | wc -l` -eq 3 && test `git rev-parse refs/remotes/two/branches/v1/start~2` = \ @@ -123,7 +123,7 @@ test_expect_success 'test another branch' ' "branches/*/*:refs/remotes/four/branches/*/*" && git config --add svn-remote.four.tags \ "tags/*:refs/remotes/four/tags/*" && - git-svn fetch four && + git svn fetch four && test `git rev-list refs/remotes/four/tags/next | wc -l` -eq 5 && test `git rev-list refs/remotes/four/branches/v2/start | wc -l` -eq 3 && test `git rev-parse refs/remotes/four/branches/v2/start~2` = \ @@ -153,7 +153,7 @@ test_expect_success 'test disallow multiple globs' ' poke tags/end/src/b/readme && svn commit -m "try to try" ) && - test_must_fail git-svn fetch three 2> stderr.three && + test_must_fail git svn fetch three 2> stderr.three && test_cmp expect.three stderr.three ' diff --git a/t/t9110-git-svn-use-svm-props.sh b/t/t9110-git-svn-use-svm-props.sh index 04d2a65c08..a06e4c5b8e 100755 --- a/t/t9110-git-svn-use-svm-props.sh +++ b/t/t9110-git-svn-use-svm-props.sh @@ -3,18 +3,18 @@ # Copyright (c) 2007 Eric Wong # -test_description='git-svn useSvmProps test' +test_description='git svn useSvmProps test' . ./lib-git-svn.sh test_expect_success 'load svm repo' ' - svnadmin load -q "$rawsvnrepo" < ../t9110/svm.dump && - git-svn init --minimize-url -R arr -i bar "$svnrepo"/mirror/arr && - git-svn init --minimize-url -R argh -i dir "$svnrepo"/mirror/argh && - git-svn init --minimize-url -R argh -i e \ + svnadmin load -q "$rawsvnrepo" < "$TEST_DIRECTORY"/t9110/svm.dump && + git svn init --minimize-url -R arr -i bar "$svnrepo"/mirror/arr && + git svn init --minimize-url -R argh -i dir "$svnrepo"/mirror/argh && + git svn init --minimize-url -R argh -i e \ "$svnrepo"/mirror/argh/a/b/c/d/e && git config svn.useSvmProps true && - git-svn fetch --all + git svn fetch --all ' uuid=161ce429-a9dd-4828-af4a-52023f968c89 @@ -22,40 +22,40 @@ uuid=161ce429-a9dd-4828-af4a-52023f968c89 bar_url=http://mayonaise/svnrepo/bar test_expect_success 'verify metadata for /bar' " git cat-file commit refs/remotes/bar | \ - grep '^git-svn-id: $bar_url@12 $uuid$' && + grep '^${git_svn_id}: $bar_url@12 $uuid$' && git cat-file commit refs/remotes/bar~1 | \ - grep '^git-svn-id: $bar_url@11 $uuid$' && + grep '^${git_svn_id}: $bar_url@11 $uuid$' && git cat-file commit refs/remotes/bar~2 | \ - grep '^git-svn-id: $bar_url@10 $uuid$' && + grep '^${git_svn_id}: $bar_url@10 $uuid$' && git cat-file commit refs/remotes/bar~3 | \ - grep '^git-svn-id: $bar_url@9 $uuid$' && + grep '^${git_svn_id}: $bar_url@9 $uuid$' && git cat-file commit refs/remotes/bar~4 | \ - grep '^git-svn-id: $bar_url@6 $uuid$' && + grep '^${git_svn_id}: $bar_url@6 $uuid$' && git cat-file commit refs/remotes/bar~5 | \ - grep '^git-svn-id: $bar_url@1 $uuid$' + grep '^${git_svn_id}: $bar_url@1 $uuid$' " e_url=http://mayonaise/svnrepo/dir/a/b/c/d/e test_expect_success 'verify metadata for /dir/a/b/c/d/e' " git cat-file commit refs/remotes/e | \ - grep '^git-svn-id: $e_url@1 $uuid$' + grep '^${git_svn_id}: $e_url@1 $uuid$' " dir_url=http://mayonaise/svnrepo/dir test_expect_success 'verify metadata for /dir' " git cat-file commit refs/remotes/dir | \ - grep '^git-svn-id: $dir_url@2 $uuid$' && + grep '^${git_svn_id}: $dir_url@2 $uuid$' && git cat-file commit refs/remotes/dir~1 | \ - grep '^git-svn-id: $dir_url@1 $uuid$' + grep '^${git_svn_id}: $dir_url@1 $uuid$' " test_expect_success 'find commit based on SVN revision number' " - git-svn find-rev r12 | + git svn find-rev r12 | grep `git rev-parse HEAD` " test_expect_success 'empty rebase' " - git-svn rebase + git svn rebase " test_done diff --git a/t/t9111-git-svn-use-svnsync-props.sh b/t/t9111-git-svn-use-svnsync-props.sh index a8d74dcd3a..bd081c2ec3 100755 --- a/t/t9111-git-svn-use-svnsync-props.sh +++ b/t/t9111-git-svn-use-svnsync-props.sh @@ -3,17 +3,17 @@ # Copyright (c) 2007 Eric Wong # -test_description='git-svn useSvnsyncProps test' +test_description='git svn useSvnsyncProps test' . ./lib-git-svn.sh test_expect_success 'load svnsync repo' ' - svnadmin load -q "$rawsvnrepo" < ../t9111/svnsync.dump && - git-svn init --minimize-url -R arr -i bar "$svnrepo"/bar && - git-svn init --minimize-url -R argh -i dir "$svnrepo"/dir && - git-svn init --minimize-url -R argh -i e "$svnrepo"/dir/a/b/c/d/e && + svnadmin load -q "$rawsvnrepo" < "$TEST_DIRECTORY"/t9111/svnsync.dump && + git svn init --minimize-url -R arr -i bar "$svnrepo"/bar && + git svn init --minimize-url -R argh -i dir "$svnrepo"/dir && + git svn init --minimize-url -R argh -i e "$svnrepo"/dir/a/b/c/d/e && git config svn.useSvnsyncProps true && - git-svn fetch --all + git svn fetch --all ' uuid=161ce429-a9dd-4828-af4a-52023f968c89 @@ -21,31 +21,31 @@ uuid=161ce429-a9dd-4828-af4a-52023f968c89 bar_url=http://mayonaise/svnrepo/bar test_expect_success 'verify metadata for /bar' " git cat-file commit refs/remotes/bar | \ - grep '^git-svn-id: $bar_url@12 $uuid$' && + grep '^${git_svn_id}: $bar_url@12 $uuid$' && git cat-file commit refs/remotes/bar~1 | \ - grep '^git-svn-id: $bar_url@11 $uuid$' && + grep '^${git_svn_id}: $bar_url@11 $uuid$' && git cat-file commit refs/remotes/bar~2 | \ - grep '^git-svn-id: $bar_url@10 $uuid$' && + grep '^${git_svn_id}: $bar_url@10 $uuid$' && git cat-file commit refs/remotes/bar~3 | \ - grep '^git-svn-id: $bar_url@9 $uuid$' && + grep '^${git_svn_id}: $bar_url@9 $uuid$' && git cat-file commit refs/remotes/bar~4 | \ - grep '^git-svn-id: $bar_url@6 $uuid$' && + grep '^${git_svn_id}: $bar_url@6 $uuid$' && git cat-file commit refs/remotes/bar~5 | \ - grep '^git-svn-id: $bar_url@1 $uuid$' + grep '^${git_svn_id}: $bar_url@1 $uuid$' " e_url=http://mayonaise/svnrepo/dir/a/b/c/d/e test_expect_success 'verify metadata for /dir/a/b/c/d/e' " git cat-file commit refs/remotes/e | \ - grep '^git-svn-id: $e_url@1 $uuid$' + grep '^${git_svn_id}: $e_url@1 $uuid$' " dir_url=http://mayonaise/svnrepo/dir test_expect_success 'verify metadata for /dir' " git cat-file commit refs/remotes/dir | \ - grep '^git-svn-id: $dir_url@2 $uuid$' && + grep '^${git_svn_id}: $dir_url@2 $uuid$' && git cat-file commit refs/remotes/dir~1 | \ - grep '^git-svn-id: $dir_url@1 $uuid$' + grep '^${git_svn_id}: $dir_url@1 $uuid$' " test_done diff --git a/t/t9112-git-svn-md5less-file.sh b/t/t9112-git-svn-md5less-file.sh index d470a920e4..a61d6716d2 100755 --- a/t/t9112-git-svn-md5less-file.sh +++ b/t/t9112-git-svn-md5less-file.sh @@ -42,6 +42,6 @@ EOF test_expect_success 'load svn dumpfile' 'svnadmin load "$rawsvnrepo" < dumpfile.svn' -test_expect_success 'initialize git-svn' 'git-svn init "$svnrepo"' -test_expect_success 'fetch revisions from svn' 'git-svn fetch' +test_expect_success 'initialize git svn' 'git svn init "$svnrepo"' +test_expect_success 'fetch revisions from svn' 'git svn fetch' test_done diff --git a/t/t9113-git-svn-dcommit-new-file.sh b/t/t9113-git-svn-dcommit-new-file.sh index ae78e334ac..250c53022b 100755 --- a/t/t9113-git-svn-dcommit-new-file.sh +++ b/t/t9113-git-svn-dcommit-new-file.sh @@ -8,7 +8,7 @@ # daemon running on a users system if the test fails. # Not all git users will need to interact with SVN. -test_description='git-svn dcommit new files over svn:// test' +test_description='git svn dcommit new files over svn:// test' . ./lib-git-svn.sh diff --git a/t/t9114-git-svn-dcommit-merge.sh b/t/t9114-git-svn-dcommit-merge.sh index 61d7781616..17b2855c4f 100755 --- a/t/t9114-git-svn-dcommit-merge.sh +++ b/t/t9114-git-svn-dcommit-merge.sh @@ -3,7 +3,7 @@ # Copyright (c) 2007 Eric Wong # Based on a script by Joakim Tjernlund <joakim.tjernlund@transmode.se> -test_description='git-svn dcommit handles merges' +test_description='git svn dcommit handles merges' . ./lib-git-svn.sh diff --git a/t/t9115-git-svn-dcommit-funky-renames.sh b/t/t9115-git-svn-dcommit-funky-renames.sh index f0fbd3aff7..9be7aefaee 100755 --- a/t/t9115-git-svn-dcommit-funky-renames.sh +++ b/t/t9115-git-svn-dcommit-funky-renames.sh @@ -3,12 +3,12 @@ # Copyright (c) 2007 Eric Wong -test_description='git-svn dcommit can commit renames of files with ugly names' +test_description='git svn dcommit can commit renames of files with ugly names' . ./lib-git-svn.sh test_expect_success 'load repository with strange names' ' - svnadmin load -q "$rawsvnrepo" < ../t9115/funky-names.dump && + svnadmin load -q "$rawsvnrepo" < "$TEST_DIRECTORY"/t9115/funky-names.dump && start_httpd gtk+ ' @@ -75,7 +75,7 @@ test_expect_success 'make a commit to test rebase' ' git svn dcommit ' -test_expect_success 'git-svn rebase works inside a fresh-cloned repository' ' +test_expect_success 'git svn rebase works inside a fresh-cloned repository' ' cd test-rebase && git svn rebase && test -e test-rebase-main && diff --git a/t/t9116-git-svn-log.sh b/t/t9116-git-svn-log.sh index 4b2cc878f6..fd6d1d2046 100755 --- a/t/t9116-git-svn-log.sh +++ b/t/t9116-git-svn-log.sh @@ -3,7 +3,7 @@ # Copyright (c) 2007 Eric Wong # -test_description='git-svn log tests' +test_description='git svn log tests' . ./lib-git-svn.sh test_expect_success 'setup repository and import' ' @@ -16,8 +16,8 @@ test_expect_success 'setup repository and import' ' done && \ svn import -m test . "$svnrepo" cd .. && - git-svn init "$svnrepo" -T trunk -b branches -t tags && - git-svn fetch && + git svn init "$svnrepo" -T trunk -b branches -t tags && + git svn fetch && git reset --hard trunk && echo bye >> README && git commit -a -m bye && diff --git a/t/t9117-git-svn-init-clone.sh b/t/t9117-git-svn-init-clone.sh index 7a689bb1cd..dde46cd92f 100755 --- a/t/t9117-git-svn-init-clone.sh +++ b/t/t9117-git-svn-init-clone.sh @@ -3,7 +3,7 @@ # Copyright (c) 2007 Eric Wong # -test_description='git-svn init/clone tests' +test_description='git svn init/clone tests' . ./lib-git-svn.sh diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh index 3281cbd347..7a7c128687 100755 --- a/t/t9118-git-svn-funky-branch-names.sh +++ b/t/t9118-git-svn-funky-branch-names.sh @@ -3,9 +3,13 @@ # Copyright (c) 2007 Eric Wong # -test_description='git-svn funky branch names' +test_description='git svn funky branch names' . ./lib-git-svn.sh +# Abo-Uebernahme (Bug #994) +scary_uri='Abo-Uebernahme%20%28Bug%20%23994%29' +scary_ref='Abo-Uebernahme%20(Bug%20#994)' + test_expect_success 'setup svnrepo' ' mkdir project project/trunk project/branches project/tags && echo foo > project/trunk/foo && @@ -15,6 +19,8 @@ test_expect_success 'setup svnrepo' ' "$svnrepo/pr ject/branches/fun plugin" && svn cp -m "more fun!" "$svnrepo/pr ject/branches/fun plugin" \ "$svnrepo/pr ject/branches/more fun plugin!" && + svn cp -m "scary" "$svnrepo/pr ject/branches/fun plugin" \ + "$svnrepo/pr ject/branches/$scary_uri" && start_httpd ' @@ -23,6 +29,7 @@ test_expect_success 'test clone with funky branch names' ' cd project && git rev-parse "refs/remotes/fun%20plugin" && git rev-parse "refs/remotes/more%20fun%20plugin!" && + git rev-parse "refs/remotes/$scary_ref" && cd .. ' @@ -35,6 +42,15 @@ test_expect_success 'test dcommit to funky branch' " cd .. " +test_expect_success 'test dcommit to scary branch' ' + cd project && + git reset --hard "refs/remotes/$scary_ref" && + echo urls are scary >> foo && + git commit -m "eep" -- foo && + git svn dcommit && + cd .. + ' + stop_httpd test_done diff --git a/t/t9119-git-svn-info.sh b/t/t9119-git-svn-info.sh index 5fd36a1483..27dd7c273a 100755 --- a/t/t9119-git-svn-info.sh +++ b/t/t9119-git-svn-info.sh @@ -2,16 +2,14 @@ # # Copyright (c) 2007 David D. Kilzer -test_description='git-svn info' +test_description='git svn info' . ./lib-git-svn.sh -set -e - # Tested with: svn, version 1.4.4 (r25188) -v=`svn --version | sed -n -e 's/^svn, version \(1\.4\.[0-9]\).*$/\1/p'` +v=`svn --version | sed -n -e 's/^svn, version \(1\.[0-9]*\.[0-9]*\).*$/\1/p'` case $v in -1.4.*) +1.[45].*) ;; *) say "skipping svn-info test (SVN version: $v not supported)" @@ -36,6 +34,8 @@ ptouch() { ' "`svn info $2 | grep '^Text Last Updated:'`" "$1" } +quoted_svnrepo="$(echo $svnrepo | sed 's/ /%20/')" + test_expect_success 'setup repository and import' ' mkdir info && cd info && @@ -47,80 +47,92 @@ test_expect_success 'setup repository and import' ' ln -s directory symlink-directory && svn import -m "initial" . "$svnrepo" && cd .. && + svn co "$svnrepo" svnwc && + cd svnwc && + echo foo > foo && + svn add foo && + svn commit -m "change outside directory" && + svn update && + cd .. && mkdir gitwc && cd gitwc && - git-svn init "$svnrepo" && - git-svn fetch && + git svn init "$svnrepo" && + git svn fetch && cd .. && - svn co "$svnrepo" svnwc && - ptouch svnwc/file gitwc/file && - ptouch svnwc/directory gitwc/directory && - ptouch svnwc/symlink-file gitwc/symlink-file && - ptouch svnwc/symlink-directory gitwc/symlink-directory + 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 && - git-diff expected.info actual.info + (cd gitwc; git svn info) > actual.info && + test_cmp expected.info actual.info " test_expect_success 'info --url' ' - test "$(cd gitwc; git-svn info --url)" = "$svnrepo" + test "$(cd gitwc; git svn info --url)" = "$quoted_svnrepo" ' test_expect_success 'info .' " (cd svnwc; svn info .) > expected.info-dot && - (cd gitwc; git-svn info .) > actual.info-dot && - git-diff expected.info-dot actual.info-dot + (cd gitwc; git svn info .) > actual.info-dot && + test_cmp expected.info-dot actual.info-dot " test_expect_success 'info --url .' ' - test "$(cd gitwc; git-svn info --url .)" = "$svnrepo" + test "$(cd gitwc; git svn info --url .)" = "$quoted_svnrepo" ' test_expect_success 'info file' " (cd svnwc; svn info file) > expected.info-file && - (cd gitwc; git-svn info file) > actual.info-file && - git-diff expected.info-file actual.info-file + (cd gitwc; git svn info file) > actual.info-file && + test_cmp expected.info-file actual.info-file " test_expect_success 'info --url file' ' - test "$(cd gitwc; git-svn info --url file)" = "$svnrepo/file" + test "$(cd gitwc; git svn info --url file)" = "$quoted_svnrepo/file" ' test_expect_success 'info directory' " (cd svnwc; svn info directory) > expected.info-directory && - (cd gitwc; git-svn info directory) > actual.info-directory && - git-diff expected.info-directory actual.info-directory + (cd gitwc; git svn info directory) > actual.info-directory && + test_cmp 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_expect_success 'info --url directory' ' - test "$(cd gitwc; git-svn info --url directory)" = "$svnrepo/directory" + test "$(cd gitwc; git svn info --url directory)" = "$quoted_svnrepo/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 && - git-diff expected.info-symlink-file actual.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_expect_success 'info --url symlink-file' ' - test "$(cd gitwc; git-svn info --url symlink-file)" \ - = "$svnrepo/symlink-file" + test "$(cd gitwc; git svn info --url symlink-file)" \ + = "$quoted_svnrepo/symlink-file" ' test_expect_success 'info symlink-directory' " (cd svnwc; svn info symlink-directory) \ > expected.info-symlink-directory && - (cd gitwc; git-svn info symlink-directory) \ + (cd gitwc; git svn info symlink-directory) \ > actual.info-symlink-directory && - git-diff expected.info-symlink-directory actual.info-symlink-directory + test_cmp expected.info-symlink-directory actual.info-symlink-directory " test_expect_success 'info --url symlink-directory' ' - test "$(cd gitwc; git-svn info --url symlink-directory)" \ - = "$svnrepo/symlink-directory" + test "$(cd gitwc; git svn info --url symlink-directory)" \ + = "$quoted_svnrepo/symlink-directory" ' test_expect_success 'info added-file' " @@ -134,13 +146,13 @@ test_expect_success 'info added-file' " svn add added-file > /dev/null && cd .. && (cd svnwc; svn info added-file) > expected.info-added-file && - (cd gitwc; git-svn info added-file) > actual.info-added-file && - git-diff expected.info-added-file actual.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_expect_success 'info --url added-file' ' - test "$(cd gitwc; git-svn info --url added-file)" \ - = "$svnrepo/added-file" + test "$(cd gitwc; git svn info --url added-file)" \ + = "$quoted_svnrepo/added-file" ' test_expect_success 'info added-directory' " @@ -155,14 +167,14 @@ test_expect_success 'info added-directory' " cd .. && (cd svnwc; svn info added-directory) \ > expected.info-added-directory && - (cd gitwc; git-svn info added-directory) \ + (cd gitwc; git svn info added-directory) \ > actual.info-added-directory && - git-diff expected.info-added-directory actual.info-added-directory + test_cmp expected.info-added-directory actual.info-added-directory " test_expect_success 'info --url added-directory' ' - test "$(cd gitwc; git-svn info --url added-directory)" \ - = "$svnrepo/added-directory" + test "$(cd gitwc; git svn info --url added-directory)" \ + = "$quoted_svnrepo/added-directory" ' test_expect_success 'info added-symlink-file' " @@ -177,15 +189,15 @@ test_expect_success 'info added-symlink-file' " 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) \ + (cd gitwc; git svn info added-symlink-file) \ > actual.info-added-symlink-file && - git-diff expected.info-added-symlink-file \ + test_cmp expected.info-added-symlink-file \ actual.info-added-symlink-file " test_expect_success 'info --url added-symlink-file' ' - test "$(cd gitwc; git-svn info --url added-symlink-file)" \ - = "$svnrepo/added-symlink-file" + test "$(cd gitwc; git svn info --url added-symlink-file)" \ + = "$quoted_svnrepo/added-symlink-file" ' test_expect_success 'info added-symlink-directory' " @@ -200,15 +212,15 @@ test_expect_success 'info added-symlink-directory' " 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) \ + (cd gitwc; git svn info added-symlink-directory) \ > actual.info-added-symlink-directory && - git-diff expected.info-added-symlink-directory \ + test_cmp expected.info-added-symlink-directory \ actual.info-added-symlink-directory " test_expect_success 'info --url added-symlink-directory' ' - test "$(cd gitwc; git-svn info --url added-symlink-directory)" \ - = "$svnrepo/added-symlink-directory" + test "$(cd gitwc; git svn info --url added-symlink-directory)" \ + = "$quoted_svnrepo/added-symlink-directory" ' # The next few tests replace the "Text Last Updated" value with a @@ -226,15 +238,15 @@ test_expect_success 'info deleted-file' " (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) | + (cd gitwc; git svn info file) | sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \ > actual.info-deleted-file && - git-diff expected.info-deleted-file actual.info-deleted-file + test_cmp expected.info-deleted-file actual.info-deleted-file " test_expect_success 'info --url file (deleted)' ' - test "$(cd gitwc; git-svn info --url file)" \ - = "$svnrepo/file" + test "$(cd gitwc; git svn info --url file)" \ + = "$quoted_svnrepo/file" ' test_expect_success 'info deleted-directory' " @@ -247,15 +259,15 @@ test_expect_success 'info deleted-directory' " (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) | + (cd gitwc; git svn info directory) | sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \ > actual.info-deleted-directory && - git-diff expected.info-deleted-directory actual.info-deleted-directory + test_cmp expected.info-deleted-directory actual.info-deleted-directory " test_expect_success 'info --url directory (deleted)' ' - test "$(cd gitwc; git-svn info --url directory)" \ - = "$svnrepo/directory" + test "$(cd gitwc; git svn info --url directory)" \ + = "$quoted_svnrepo/directory" ' test_expect_success 'info deleted-symlink-file' " @@ -268,16 +280,16 @@ test_expect_success 'info deleted-symlink-file' " (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) | + (cd gitwc; git svn info symlink-file) | sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \ > actual.info-deleted-symlink-file && - git-diff expected.info-deleted-symlink-file \ + test_cmp expected.info-deleted-symlink-file \ actual.info-deleted-symlink-file " test_expect_success 'info --url symlink-file (deleted)' ' - test "$(cd gitwc; git-svn info --url symlink-file)" \ - = "$svnrepo/symlink-file" + test "$(cd gitwc; git svn info --url symlink-file)" \ + = "$quoted_svnrepo/symlink-file" ' test_expect_success 'info deleted-symlink-directory' " @@ -290,16 +302,16 @@ test_expect_success 'info deleted-symlink-directory' " (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) | + (cd gitwc; git svn info symlink-directory) | sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \ > actual.info-deleted-symlink-directory && - git-diff expected.info-deleted-symlink-directory \ + test_cmp expected.info-deleted-symlink-directory \ actual.info-deleted-symlink-directory " test_expect_success 'info --url symlink-directory (deleted)' ' - test "$(cd gitwc; git-svn info --url symlink-directory)" \ - = "$svnrepo/symlink-directory" + test "$(cd gitwc; git svn info --url symlink-directory)" \ + = "$quoted_svnrepo/symlink-directory" ' # NOTE: git does not have the concept of replaced objects, @@ -307,82 +319,59 @@ test_expect_success 'info --url symlink-directory (deleted)' ' test_expect_success 'info unknown-file' " echo two > gitwc/unknown-file && - cp gitwc/unknown-file svnwc/unknown-file && - ptouch gitwc/unknown-file svnwc/unknown-file && - (cd svnwc; svn info unknown-file) 2> expected.info-unknown-file && - (cd gitwc; git-svn info unknown-file) 2> actual.info-unknown-file && - git-diff expected.info-unknown-file actual.info-unknown-file + (cd gitwc; test_must_fail git svn info unknown-file) \ + 2> actual.info-unknown-file && + grep unknown-file actual.info-unknown-file " test_expect_success 'info --url unknown-file' ' - test -z "$(cd gitwc; git-svn info --url unknown-file \ - 2> ../actual.info--url-unknown-file)" && - git-diff expected.info-unknown-file actual.info--url-unknown-file + echo two > gitwc/unknown-file && + (cd gitwc; test_must_fail git svn info --url unknown-file) \ + 2> actual.info-url-unknown-file && + grep unknown-file actual.info-url-unknown-file ' test_expect_success 'info unknown-directory' " mkdir gitwc/unknown-directory svnwc/unknown-directory && - ptouch gitwc/unknown-directory svnwc/unknown-directory && - touch gitwc/unknown-directory/.placeholder && - (cd svnwc; svn info unknown-directory) \ - 2> expected.info-unknown-directory && - (cd gitwc; git-svn info unknown-directory) \ - 2> actual.info-unknown-directory && - git-diff expected.info-unknown-directory actual.info-unknown-directory + (cd gitwc; test_must_fail git svn info unknown-directory) \ + 2> actual.info-unknown-directory && + grep unknown-directory actual.info-unknown-directory " test_expect_success 'info --url unknown-directory' ' - test -z "$(cd gitwc; git-svn info --url unknown-directory \ - 2> ../actual.info--url-unknown-directory)" && - git-diff expected.info-unknown-directory \ - actual.info--url-unknown-directory + (cd gitwc; test_must_fail git svn info --url unknown-directory) \ + 2> actual.info-url-unknown-directory && + grep unknown-directory actual.info-url-unknown-directory ' test_expect_success 'info unknown-symlink-file' " cd gitwc && ln -s unknown-file unknown-symlink-file && cd .. && - cd svnwc && - ln -s unknown-file unknown-symlink-file && - cd .. && - ptouch gitwc/unknown-symlink-file svnwc/unknown-symlink-file && - (cd svnwc; svn info unknown-symlink-file) \ - 2> expected.info-unknown-symlink-file && - (cd gitwc; git-svn info unknown-symlink-file) \ - 2> actual.info-unknown-symlink-file && - git-diff expected.info-unknown-symlink-file \ - actual.info-unknown-symlink-file + (cd gitwc; test_must_fail git svn info unknown-symlink-file) \ + 2> actual.info-unknown-symlink-file && + grep unknown-symlink-file actual.info-unknown-symlink-file " test_expect_success 'info --url unknown-symlink-file' ' - test -z "$(cd gitwc; git-svn info --url unknown-symlink-file \ - 2> ../actual.info--url-unknown-symlink-file)" && - git-diff expected.info-unknown-symlink-file \ - actual.info--url-unknown-symlink-file + (cd gitwc; test_must_fail git svn info --url unknown-symlink-file) \ + 2> actual.info-url-unknown-symlink-file && + grep unknown-symlink-file actual.info-url-unknown-symlink-file ' test_expect_success 'info unknown-symlink-directory' " cd gitwc && ln -s unknown-directory unknown-symlink-directory && cd .. && - cd svnwc && - ln -s unknown-directory unknown-symlink-directory && - cd .. && - ptouch gitwc/unknown-symlink-directory \ - svnwc/unknown-symlink-directory && - (cd svnwc; svn info unknown-symlink-directory) \ - 2> expected.info-unknown-symlink-directory && - (cd gitwc; git-svn info unknown-symlink-directory) \ - 2> actual.info-unknown-symlink-directory && - git-diff expected.info-unknown-symlink-directory \ - actual.info-unknown-symlink-directory + (cd gitwc; test_must_fail git svn info unknown-symlink-directory) \ + 2> actual.info-unknown-symlink-directory && + grep unknown-symlink-directory actual.info-unknown-symlink-directory " test_expect_success 'info --url unknown-symlink-directory' ' - test -z "$(cd gitwc; git-svn info --url unknown-symlink-directory \ - 2> ../actual.info--url-unknown-symlink-directory)" && - git-diff expected.info-unknown-symlink-directory \ - actual.info--url-unknown-symlink-directory + (cd gitwc; test_must_fail git svn info --url unknown-symlink-directory) \ + 2> actual.info-url-unknown-symlink-directory && + grep unknown-symlink-directory actual.info-url-unknown-symlink-directory ' test_done diff --git a/t/t9120-git-svn-clone-with-percent-escapes.sh b/t/t9120-git-svn-clone-with-percent-escapes.sh index 5979e133b9..ef2c0523cd 100755 --- a/t/t9120-git-svn-clone-with-percent-escapes.sh +++ b/t/t9120-git-svn-clone-with-percent-escapes.sh @@ -3,7 +3,7 @@ # Copyright (c) 2008 Kevin Ballard # -test_description='git-svn clone with percent escapes' +test_description='git svn clone with percent escapes' . ./lib-git-svn.sh test_expect_success 'setup svnrepo' ' @@ -21,7 +21,7 @@ else test_expect_success 'test clone with percent escapes' ' git svn clone "$svnrepo/pr%20ject" clone && cd clone && - git rev-parse refs/remotes/git-svn && + git rev-parse refs/${remotes_git_svn} && cd .. ' fi diff --git a/t/t9121-git-svn-fetch-renamed-dir.sh b/t/t9121-git-svn-fetch-renamed-dir.sh index 99230b0810..000cad37c6 100755 --- a/t/t9121-git-svn-fetch-renamed-dir.sh +++ b/t/t9121-git-svn-fetch-renamed-dir.sh @@ -3,12 +3,12 @@ # Copyright (c) 2008 Santhosh Kumar Mani -test_description='git-svn can fetch renamed directories' +test_description='git svn can fetch renamed directories' . ./lib-git-svn.sh test_expect_success 'load repository with renamed directory' ' - svnadmin load -q "$rawsvnrepo" < ../t9121/renamed-dir.dump + svnadmin load -q "$rawsvnrepo" < "$TEST_DIRECTORY"/t9121/renamed-dir.dump ' test_expect_success 'init and fetch repository' ' diff --git a/t/t9122-git-svn-author.sh b/t/t9122-git-svn-author.sh index 1190576a65..1b1cf47281 100755 --- a/t/t9122-git-svn-author.sh +++ b/t/t9122-git-svn-author.sh @@ -13,7 +13,7 @@ test_expect_success 'setup svn repository' ' ) ' -test_expect_success 'interact with it via git-svn' ' +test_expect_success 'interact with it via git svn' ' mkdir work.git && ( cd work.git && diff --git a/t/t9123-git-svn-rebuild-with-rewriteroot.sh b/t/t9123-git-svn-rebuild-with-rewriteroot.sh index c18878fad1..cf0415274c 100755 --- a/t/t9123-git-svn-rebuild-with-rewriteroot.sh +++ b/t/t9123-git-svn-rebuild-with-rewriteroot.sh @@ -3,21 +3,21 @@ # Copyright (c) 2008 Jan Krüger # -test_description='git-svn respects rewriteRoot during rebuild' +test_description='git svn respects rewriteRoot during rebuild' . ./lib-git-svn.sh mkdir import cd import touch foo - svn import -m 'import for git-svn' . "$svnrepo" >/dev/null + svn import -m 'import for git svn' . "$svnrepo" >/dev/null cd .. rm -rf import test_expect_success 'init, fetch and checkout repository' ' git svn init --rewrite-root=http://invalid.invalid/ "$svnrepo" && git svn fetch - git checkout -b mybranch remotes/git-svn + git checkout -b mybranch ${remotes_git_svn} ' test_expect_success 'remove rev_map' ' diff --git a/t/t9124-git-svn-dcommit-auto-props.sh b/t/t9124-git-svn-dcommit-auto-props.sh index 8223c5909e..263dbf5fc2 100755 --- a/t/t9124-git-svn-dcommit-auto-props.sh +++ b/t/t9124-git-svn-dcommit-auto-props.sh @@ -2,7 +2,7 @@ # # Copyright (c) 2008 Brad King -test_description='git-svn dcommit honors auto-props' +test_description='git svn dcommit honors auto-props' . ./lib-git-svn.sh @@ -16,26 +16,24 @@ enable-auto-props=$1 EOF } -test_expect_success 'initialize git-svn' ' +test_expect_success 'initialize git svn' ' mkdir import && ( cd import && echo foo >foo && - svn import -m "import for git-svn" . "$svnrepo" + svn import -m "import for git svn" . "$svnrepo" ) && rm -rf import && - git-svn init "$svnrepo" - git-svn fetch + git svn init "$svnrepo" + git svn fetch ' test_expect_success 'enable auto-props config' ' - cd "$gittestrepo" && mkdir user && generate_auto_props yes >user/config ' test_expect_success 'add files matching auto-props' ' - cd "$gittestrepo" && echo "#!$SHELL_PATH" >exec1.sh && chmod +x exec1.sh && echo "hello" >hello.txt && @@ -46,12 +44,10 @@ test_expect_success 'add files matching auto-props' ' ' test_expect_success 'disable auto-props config' ' - cd "$gittestrepo" && generate_auto_props no >user/config ' test_expect_success 'add files matching disabled auto-props' ' - cd "$gittestrepo" && echo "#$SHELL_PATH" >exec2.sh && chmod +x exec2.sh && echo "world" >world.txt && @@ -62,6 +58,7 @@ test_expect_success 'add files matching disabled auto-props' ' ' test_expect_success 'check resulting svn repository' ' +( mkdir work && cd work && svn co "$svnrepo" && @@ -81,6 +78,24 @@ test_expect_success 'check resulting svn repository' ' test "x$(svn propget svn:mime-type world.txt)" = "x" && test "x$(svn propget svn:eol-style world.txt)" = "x" && test "x$(svn propget svn:mime-type zot)" = "x" +) +' + +test_expect_success 'check renamed file' ' + test -d user && + generate_auto_props yes > user/config && + git mv foo foo.sh && + git commit -m "foo => foo.sh" && + git svn dcommit --config-dir=user && + ( + cd work/svnrepo && + svn up && + test ! -e foo && + test -e foo.sh && + test "x$(svn propget svn:mime-type foo.sh)" = \ + "xapplication/x-shellscript" && + test "x$(svn propget svn:eol-style foo.sh)" = "xLF" + ) ' test_done diff --git a/t/t9125-git-svn-multi-glob-branch-names.sh b/t/t9125-git-svn-multi-glob-branch-names.sh index 6b62b52f54..475c751c1c 100755 --- a/t/t9125-git-svn-multi-glob-branch-names.sh +++ b/t/t9125-git-svn-multi-glob-branch-names.sh @@ -1,7 +1,7 @@ #!/bin/sh # Copyright (c) 2008 Marcus Griep -test_description='git-svn multi-glob branch names' +test_description='git svn multi-glob branch names' . ./lib-git-svn.sh test_expect_success 'setup svnrepo' ' diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh index 3e32e84e6c..245a7c3662 100755 --- a/t/t9200-git-cvsexportcommit.sh +++ b/t/t9200-git-cvsexportcommit.sh @@ -9,7 +9,7 @@ test_description='Test export of commits to CVS' cvs >/dev/null 2>&1 if test $? -ne 1 then - test_expect_success 'skipping git-cvsexportcommit tests, cvs not found' : + test_expect_success 'skipping git cvsexportcommit tests, cvs not found' : test_done exit fi @@ -45,8 +45,8 @@ test_expect_success \ 'mkdir A B C D E F && echo hello1 >A/newfile1.txt && echo hello2 >B/newfile2.txt && - cp ../test9200a.png C/newfile3.png && - cp ../test9200a.png D/newfile4.png && + cp "$TEST_DIRECTORY"/test9200a.png C/newfile3.png && + cp "$TEST_DIRECTORY"/test9200a.png D/newfile4.png && git add A/newfile1.txt && git add B/newfile2.txt && git add C/newfile3.png && @@ -71,8 +71,8 @@ test_expect_success \ rm -f B/newfile2.txt && rm -f C/newfile3.png && echo Hello5 >E/newfile5.txt && - cp ../test9200b.png D/newfile4.png && - cp ../test9200a.png F/newfile6.png && + cp "$TEST_DIRECTORY"/test9200b.png D/newfile4.png && + cp "$TEST_DIRECTORY"/test9200a.png F/newfile6.png && git add E/newfile5.txt && git add F/newfile6.png && git commit -a -m "Test: Remove, add and update" && @@ -91,7 +91,7 @@ test_expect_success \ diff F/newfile6.png ../F/newfile6.png )' -# Should fail (but only on the git-cvsexportcommit stage) +# Should fail (but only on the git cvsexportcommit stage) test_expect_success \ 'Fail to change binary more than one generation old' \ 'cat F/newfile6.png >>D/newfile4.png && @@ -160,24 +160,24 @@ test_expect_success \ 'mkdir "G g" && echo ok then >"G g/with spaces.txt" && git add "G g/with spaces.txt" && \ - cp ../test9200a.png "G g/with spaces.png" && \ + cp "$TEST_DIRECTORY"/test9200a.png "G g/with spaces.png" && \ git add "G g/with spaces.png" && git commit -a -m "With spaces" && id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && - git-cvsexportcommit -c $id && + git cvsexportcommit -c $id && check_entries "G g" "with spaces.png/1.1/-kb|with spaces.txt/1.1/" )' test_expect_success \ 'Update file with spaces in file name' \ 'echo Ok then >>"G g/with spaces.txt" && - cat ../test9200a.png >>"G g/with spaces.png" && \ + cat "$TEST_DIRECTORY"/test9200a.png >>"G g/with spaces.png" && \ git add "G g/with spaces.png" && git commit -a -m "Update with spaces" && id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && - git-cvsexportcommit -c $id + git cvsexportcommit -c $id check_entries "G g" "with spaces.png/1.2/-kb|with spaces.txt/1.2/" )' @@ -197,12 +197,12 @@ test_expect_success \ 'mkdir -p Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö && echo Foo >Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.txt && git add Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.txt && - cp ../test9200a.png Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.png && + cp "$TEST_DIRECTORY"/test9200a.png Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.png && git add Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö/gårdetsågårdet.png && git commit -a -m "Går det så går det" && \ id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && - git-cvsexportcommit -v -c $id && + git cvsexportcommit -v -c $id && check_entries \ "Å/goo/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/å/ä/ö" \ "gårdetsågårdet.png/1.1/-kb|gårdetsågårdet.txt/1.1/" @@ -222,7 +222,7 @@ test_expect_success \ git commit -a -m "Update two" && id=$(git rev-list --max-count=1 HEAD) && (cd "$CVSWORK" && - test_must_fail git-cvsexportcommit -c $id + test_must_fail git cvsexportcommit -c $id )' case "$(git config --bool core.filemode)" in @@ -239,7 +239,7 @@ test_expect_success \ git add G/off && git commit -a -m "Execute test" && (cd "$CVSWORK" && - git-cvsexportcommit -c HEAD + git cvsexportcommit -c HEAD test -x G/on && ! test -x G/off )' diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index c6bc0a607f..328444a306 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -3,9 +3,9 @@ # Copyright (c) 2007 Shawn Pearce # -test_description='test git-fast-import utility' +test_description='test git fast-import utility' . ./test-lib.sh -. ../diff-lib.sh ;# test-lib chdir's into trash +. "$TEST_DIRECTORY"/diff-lib.sh ;# test-lib chdir's into trash file2_data='file2 second line of EOF' @@ -59,7 +59,7 @@ M 755 :4 file4 INPUT_END test_expect_success \ 'A: create pack from stdin' \ - 'git-fast-import --export-marks=marks.out <input && + 'git fast-import --export-marks=marks.out <input && git whatchanged master' test_expect_success \ 'A: verify pack' \ @@ -113,7 +113,7 @@ test_expect_success \ test_expect_success \ 'A: verify marks import' \ - 'git-fast-import \ + 'git fast-import \ --import-marks=marks.out \ --export-marks=marks.new \ </dev/null && @@ -133,7 +133,7 @@ M 755 :2 copy-of-file2 INPUT_END test_expect_success \ 'A: verify marks import does not crash' \ - 'git-fast-import --import-marks=marks.out <input && + 'git fast-import --import-marks=marks.out <input && git whatchanged verify--import-marks' test_expect_success \ 'A: verify pack' \ @@ -166,7 +166,7 @@ M 755 0000000000000000000000000000000000000001 zero1 INPUT_END test_expect_success 'B: fail on invalid blob sha1' ' - test_must_fail git-fast-import <input + test_must_fail git fast-import <input ' rm -f .git/objects/pack_* .git/objects/index_* @@ -181,7 +181,7 @@ from refs/heads/master INPUT_END test_expect_success 'B: fail on invalid branch name ".badbranchname"' ' - test_must_fail git-fast-import <input + test_must_fail git fast-import <input ' rm -f .git/objects/pack_* .git/objects/index_* @@ -196,7 +196,7 @@ from refs/heads/master INPUT_END test_expect_success 'B: fail on invalid branch name "bad[branch]name"' ' - test_must_fail git-fast-import <input + test_must_fail git fast-import <input ' rm -f .git/objects/pack_* .git/objects/index_* @@ -212,7 +212,7 @@ from refs/heads/master INPUT_END test_expect_success \ 'B: accept branch name "TEMP_TAG"' \ - 'git-fast-import <input && + 'git fast-import <input && test -f .git/TEMP_TAG && test `git rev-parse master` = `git rev-parse TEMP_TAG^`' rm -f .git/TEMP_TAG @@ -221,7 +221,7 @@ rm -f .git/TEMP_TAG ### series C ### -newf=`echo hi newf | git-hash-object -w --stdin` +newf=`echo hi newf | git hash-object -w --stdin` oldf=`git rev-parse --verify master:file2` test_tick cat >input <<INPUT_END @@ -239,7 +239,7 @@ D file3 INPUT_END test_expect_success \ 'C: incremental import create pack from stdin' \ - 'git-fast-import <input && + 'git fast-import <input && git whatchanged branch' test_expect_success \ 'C: verify pack' \ @@ -297,7 +297,7 @@ EOF INPUT_END test_expect_success \ 'D: inline data in commit' \ - 'git-fast-import <input && + 'git fast-import <input && git whatchanged branch' test_expect_success \ 'D: verify pack' \ @@ -340,11 +340,11 @@ from refs/heads/branch^0 INPUT_END test_expect_success 'E: rfc2822 date, --date-format=raw' ' - test_must_fail git-fast-import --date-format=raw <input + test_must_fail git fast-import --date-format=raw <input ' test_expect_success \ 'E: rfc2822 date, --date-format=rfc2822' \ - 'git-fast-import --date-format=rfc2822 <input' + 'git fast-import --date-format=rfc2822 <input' test_expect_success \ 'E: verify pack' \ 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done' @@ -381,7 +381,7 @@ from refs/heads/branch INPUT_END test_expect_success \ 'F: non-fast-forward update skips' \ - 'if git-fast-import <input + 'if git fast-import <input then echo BAD gfi did not fail return 1 @@ -431,7 +431,7 @@ from refs/heads/branch~1 INPUT_END test_expect_success \ 'G: non-fast-forward update forced' \ - 'git-fast-import --force <input' + 'git fast-import --force <input' test_expect_success \ 'G: verify pack' \ 'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done' @@ -467,7 +467,7 @@ EOF INPUT_END test_expect_success \ 'H: deletall, add 1' \ - 'git-fast-import <input && + 'git fast-import <input && git whatchanged H' test_expect_success \ 'H: verify pack' \ @@ -507,7 +507,7 @@ from refs/heads/branch INPUT_END test_expect_success \ 'I: export-pack-edges' \ - 'git-fast-import --export-pack-edges=edges.list <input' + 'git fast-import --export-pack-edges=edges.list <input' cat >expect <<EOF .git/objects/pack/pack-.pack: `git rev-parse --verify export-boundary` @@ -541,7 +541,7 @@ COMMIT INPUT_END test_expect_success \ 'J: reset existing branch creates empty commit' \ - 'git-fast-import <input' + 'git fast-import <input' test_expect_success \ 'J: branch has 1 commit, empty tree' \ 'test 1 = `git rev-list J | wc -l` && @@ -571,7 +571,7 @@ from refs/heads/branch^1 INPUT_END test_expect_success \ 'K: reinit branch with from' \ - 'git-fast-import <input' + 'git fast-import <input' test_expect_success \ 'K: verify K^1 = branch^1' \ 'test `git rev-parse --verify branch^1` \ @@ -623,7 +623,7 @@ EXPECT_END test_expect_success \ 'L: verify internal tree sorting' \ - 'git-fast-import <input && + 'git fast-import <input && git diff-tree --abbrev --raw L^ L >output && test_cmp expect output' @@ -649,7 +649,7 @@ cat >expect <<EOF EOF test_expect_success \ 'M: rename file in same subdirectory' \ - 'git-fast-import <input && + 'git fast-import <input && git diff-tree -M -r M1^ M1 >actual && compare_diff_raw expect actual' @@ -670,7 +670,7 @@ cat >expect <<EOF EOF test_expect_success \ 'M: rename file to new subdirectory' \ - 'git-fast-import <input && + 'git fast-import <input && git diff-tree -M -r M2^ M2 >actual && compare_diff_raw expect actual' @@ -691,7 +691,7 @@ cat >expect <<EOF EOF test_expect_success \ 'M: rename subdirectory to new subdirectory' \ - 'git-fast-import <input && + 'git fast-import <input && git diff-tree -M -r M3^ M3 >actual && compare_diff_raw expect actual' @@ -717,7 +717,7 @@ cat >expect <<EOF EOF test_expect_success \ 'N: copy file in same subdirectory' \ - 'git-fast-import <input && + 'git fast-import <input && git diff-tree -C --find-copies-harder -r N1^ N1 >actual && compare_diff_raw expect actual' @@ -751,7 +751,7 @@ cat >expect <<EOF EOF test_expect_success \ 'N: copy then modify subdirectory' \ - 'git-fast-import <input && + 'git fast-import <input && git diff-tree -C --find-copies-harder -r N2^^ N2 >actual && compare_diff_raw expect actual' @@ -775,8 +775,8 @@ INPUT_END test_expect_success \ 'N: copy dirty subdirectory' \ - 'git-fast-import <input && - test `git-rev-parse N2^{tree}` = `git-rev-parse N3^{tree}`' + 'git fast-import <input && + test `git rev-parse N2^{tree}` = `git rev-parse N3^{tree}`' ### ### series O @@ -815,8 +815,8 @@ INPUT_END test_expect_success \ 'O: comments are all skipped' \ - 'git-fast-import <input && - test `git-rev-parse N3` = `git-rev-parse O1`' + 'git fast-import <input && + test `git rev-parse N3` = `git rev-parse O1`' cat >input <<INPUT_END commit refs/heads/O2 @@ -836,8 +836,8 @@ INPUT_END test_expect_success \ 'O: blank lines not necessary after data commands' \ - 'git-fast-import <input && - test `git-rev-parse N3` = `git-rev-parse O2`' + 'git fast-import <input && + test `git rev-parse N3` = `git rev-parse O2`' test_expect_success \ 'O: repack before next test' \ @@ -881,7 +881,7 @@ commits INPUT_END test_expect_success \ 'O: blank lines not necessary after other commands' \ - 'git-fast-import <input && + 'git fast-import <input && test 8 = `find .git/objects/pack -type f | wc -l` && test `git rev-parse refs/tags/O3-2nd` = `git rev-parse O3^` && git log --reverse --pretty=oneline O3 | sed s/^.*z// >actual && @@ -914,7 +914,7 @@ progress I'm done! INPUT_END test_expect_success \ 'O: progress outputs as requested by input' \ - 'git-fast-import <input >actual && + 'git fast-import <input >actual && grep "progress " <input >expect && test_cmp expect actual' @@ -979,7 +979,7 @@ INPUT_END test_expect_success \ 'P: supermodule & submodule mix' \ - 'git-fast-import <input && + 'git fast-import <input && git checkout subuse1 && rm -rf sub && mkdir sub && cd sub && git init && @@ -989,8 +989,8 @@ test_expect_success \ git submodule init && git submodule update' -SUBLAST=$(git-rev-parse --verify sub) -SUBPREV=$(git-rev-parse --verify sub^) +SUBLAST=$(git rev-parse --verify sub) +SUBPREV=$(git rev-parse --verify sub^) cat >input <<INPUT_END blob @@ -1024,8 +1024,8 @@ test_expect_success \ 'P: verbatim SHA gitlinks' \ 'git branch -D sub && git gc && git prune && - git-fast-import <input && - test $(git-rev-parse --verify subuse2) = $(git-rev-parse --verify subuse1)' + git fast-import <input && + test $(git rev-parse --verify subuse2) = $(git rev-parse --verify subuse1)' test_tick cat >input <<INPUT_END @@ -1045,7 +1045,7 @@ DATA INPUT_END test_expect_success 'P: fail on inline gitlink' ' - test_must_fail git-fast-import <input' + test_must_fail git fast-import <input' test_tick cat >input <<INPUT_END @@ -1068,6 +1068,6 @@ M 160000 :1 sub INPUT_END test_expect_success 'P: fail on blob mark in gitlink' ' - test_must_fail git-fast-import <input' + test_must_fail git fast-import <input' test_done diff --git a/t/t9301-fast-export.sh b/t/t9301-fast-export.sh index c19b4a2bab..6ddd7c19fd 100755 --- a/t/t9301-fast-export.sh +++ b/t/t9301-fast-export.sh @@ -3,7 +3,7 @@ # Copyright (c) 2007 Johannes E. Schindelin # -test_description='git-fast-export' +test_description='git fast-export' . ./test-lib.sh test_expect_success 'setup' ' @@ -67,7 +67,7 @@ test_expect_success 'iso-8859-1' ' git config i18n.commitencoding ISO-8859-1 && # use author and committer name in ISO-8859-1 to match it. - . ../t3901-8859-1.txt && + . "$TEST_DIRECTORY"/t3901-8859-1.txt && test_tick && echo rosten >file && git commit -s -m den file && diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index 4b91f8d4c4..c1850d2923 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -488,4 +488,17 @@ test_expect_success 'cvs co -c (shows module database)' ' ! grep -v "^master[ ]\+master$" < out ' +#------------ +# CVS ANNOTATE +#------------ + +cd "$WORKDIR" +test_expect_success 'cvs annotate' ' + cd cvswork && + GIT_CONFIG="$git_config" cvs annotate merge >../out && + sed -e "s/ .*//" ../out >../actual && + for i in 3 1 1 1 1 1 1 1 2 4; do echo 1.$i; done >../expect && + test_cmp ../expect ../actual +' + test_done diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh index ae7082be1d..46ba19be7d 100755 --- a/t/t9500-gitweb-standalone-no-errors.sh +++ b/t/t9500-gitweb-standalone-no-errors.sh @@ -25,9 +25,9 @@ our \$site_name = "[localhost]"; our \$site_header = ""; our \$site_footer = ""; our \$home_text = "indextext.html"; -our @stylesheets = ("file:///$safe_pwd/../../gitweb/gitweb.css"); -our \$logo = "file:///$safe_pwd/../../gitweb/git-logo.png"; -our \$favicon = "file:///$safe_pwd/../../gitweb/git-favicon.png"; +our @stylesheets = ("file:///$TEST_DIRECTORY/../gitweb/gitweb.css"); +our \$logo = "file:///$TEST_DIRECTORY/../gitweb/git-logo.png"; +our \$favicon = "file:///$TEST_DIRECTORY/../gitweb/git-favicon.png"; our \$projects_list = ""; our \$export_ok = ""; our \$strict_export = ""; @@ -54,7 +54,7 @@ gitweb_run () { # written to web server logs, so we are not interested in that: # we are interested only in properly formatted errors/warnings rm -f gitweb.log && - perl -- "$(pwd)/../../gitweb/gitweb.perl" \ + perl -- "$TEST_DIRECTORY/../gitweb/gitweb.perl" \ >/dev/null 2>gitweb.log && if grep -q -s "^[[]" gitweb.log >/dev/null; then false; else true; fi @@ -525,20 +525,20 @@ test_debug 'cat gitweb.log' test_expect_success \ 'encode(commit): utf8' \ - '. ../t3901-utf8.txt && + '. "$TEST_DIRECTORY"/t3901-utf8.txt && echo "UTF-8" >> file && git add file && - git commit -F ../t3900/1-UTF-8.txt && + git commit -F "$TEST_DIRECTORY"/t3900/1-UTF-8.txt && gitweb_run "p=.git;a=commit"' test_debug 'cat gitweb.log' test_expect_success \ 'encode(commit): iso-8859-1' \ - '. ../t3901-8859-1.txt && + '. "$TEST_DIRECTORY"/t3901-8859-1.txt && echo "ISO-8859-1" >> file && git add file && git config i18n.commitencoding ISO-8859-1 && - git commit -F ../t3900/ISO-8859-1.txt && + git commit -F "$TEST_DIRECTORY"/t3900/ISO-8859-1.txt && git config --unset i18n.commitencoding && gitweb_run "p=.git;a=commit"' test_debug 'cat gitweb.log' diff --git a/t/t9600-cvsimport.sh b/t/t9600-cvsimport.sh index 0d7786a8c7..d2379e7f62 100755 --- a/t/t9600-cvsimport.sh +++ b/t/t9600-cvsimport.sh @@ -1,6 +1,6 @@ #!/bin/sh -test_description='git-cvsimport basic tests' +test_description='git cvsimport basic tests' . ./test-lib.sh CVSROOT=$(pwd)/cvsroot diff --git a/t/t9700-perl-git.sh b/t/t9700-perl-git.sh index 9706ee5773..b81d5dfc34 100755 --- a/t/t9700-perl-git.sh +++ b/t/t9700-perl-git.sh @@ -27,18 +27,18 @@ test_expect_success \ echo "changed file 1" > file1 && git commit -a -m "second commit" && - git-config --add color.test.slot1 green && - git-config --add test.string value && - git-config --add test.dupstring value1 && - git-config --add test.dupstring value2 && - git-config --add test.booltrue true && - git-config --add test.boolfalse no && - git-config --add test.boolother other && - git-config --add test.int 2k + git config --add color.test.slot1 green && + git config --add test.string value && + git config --add test.dupstring value1 && + git config --add test.dupstring value2 && + git config --add test.booltrue true && + git config --add test.boolfalse no && + git config --add test.boolother other && + git config --add test.int 2k ' test_external_without_stderr \ 'Perl API' \ - perl ../t9700/test.pl + perl "$TEST_DIRECTORY"/t9700/test.pl test_done diff --git a/t/t9700/test.pl b/t/t9700/test.pl index 4d2312548a..851cea4a4b 100755 --- a/t/t9700/test.pl +++ b/t/t9700/test.pl @@ -14,10 +14,7 @@ use File::Temp; BEGIN { use_ok('Git') } # set up -our $repo_dir = "trash directory"; our $abs_repo_dir = Cwd->cwd; -die "this must be run by calling the t/t97* shell script(s)\n" - if basename(Cwd->cwd) ne $repo_dir; ok(our $r = Git->repository(Directory => "."), "open repository"); # config diff --git a/t/test-lib.sh b/t/test-lib.sh index 11c027571b..e2b106cb6a 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -406,7 +406,7 @@ test_create_repo () { error "bug in the test script: not 1 parameter to test-create-repo" owd=`pwd` repo="$1" - mkdir "$repo" + mkdir -p "$repo" cd "$repo" || error "Cannot setup test environment" "$GIT_EXEC_PATH/git" init "--template=$GIT_EXEC_PATH/templates/blt/" >&3 2>&4 || error "cannot run git init -- have you built things yet?" @@ -449,6 +449,11 @@ test_done () { # we will leave things as they are. say_color pass "passed all $msg" + + test -d "$remove_trash" && + cd "$(dirname "$remove_trash")" && + rm -rf "$(basename "$remove_trash")" + exit 0 ;; *) @@ -485,7 +490,8 @@ fi . ../GIT-BUILD-OPTIONS # Test repository -test="trash directory" +test="trash directory.$(basename "$0" .sh)" +test ! -z "$debug" || remove_trash="$TEST_DIRECTORY/$test" rm -fr "$test" || { trap - exit echo >&5 "FATAL: Cannot prepare test area" diff --git a/templates/Makefile b/templates/Makefile index cc3fc3094c..a12c6e214e 100644 --- a/templates/Makefile +++ b/templates/Makefile @@ -23,17 +23,19 @@ all: boilerplates.made custom bpsrc = $(filter-out %~,$(wildcard *--*)) boilerplates.made : $(bpsrc) - $(QUIET)ls *--* 2>/dev/null | \ + $(QUIET)umask 022 && ls *--* 2>/dev/null | \ while read boilerplate; \ do \ case "$$boilerplate" in *~) continue ;; esac && \ dst=`echo "$$boilerplate" | sed -e 's|^this|.|;s|--|/|g'` && \ dir=`expr "$$dst" : '\(.*\)/'` && \ - $(INSTALL) -d -m 755 blt/$$dir && \ + mkdir -p blt/$$dir && \ case "$$boilerplate" in \ - *--) ;; \ - *) cp -p $$boilerplate blt/$$dst ;; \ - esac || exit; \ + *--) continue;; \ + esac && \ + cp $$boilerplate blt/$$dst && \ + if test -x "blt/$$dst"; then rx=rx; else rx=r; fi && \ + chmod a+$$rx "blt/$$dst" || exit; \ done && \ date >$@ diff --git a/tree-diff.c b/tree-diff.c index bbb126fc46..9f67af6c1f 100644 --- a/tree-diff.c +++ b/tree-diff.c @@ -303,7 +303,7 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru update_tree_entry(t2); continue; } - die("git-diff-tree: internal error"); + die("git diff-tree: internal error"); } return 0; } diff --git a/unpack-trees.c b/unpack-trees.c index cba0aca062..ef21c62195 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -376,6 +376,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options state.refresh_cache = 1; memset(&o->result, 0, sizeof(o->result)); + o->result.initialized = 1; if (o->src_index) o->result.timestamp = o->src_index->timestamp; o->merge_size = len; diff --git a/upload-pack.c b/upload-pack.c index c911e70c9a..e5adbc011e 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -157,7 +157,7 @@ static void create_pack_file(void) /* .data is just a boolean: any non-NULL value will do */ rev_list.data = create_full_pack ? &rev_list : NULL; if (start_async(&rev_list)) - die("git-upload-pack: unable to fork git-rev-list"); + die("git upload-pack: unable to fork git-rev-list"); argv[arg++] = "pack-objects"; argv[arg++] = "--stdout"; @@ -177,7 +177,7 @@ static void create_pack_file(void) pack_objects.argv = argv; if (start_command(&pack_objects)) - die("git-upload-pack: unable to fork git-pack-objects"); + die("git upload-pack: unable to fork git-pack-objects"); /* We read from pack_objects.err to capture stderr output for * progress bar, and pack_objects.out to capture the pack data. @@ -271,7 +271,7 @@ static void create_pack_file(void) } if (finish_command(&pack_objects)) { - error("git-upload-pack: git-pack-objects died with error."); + error("git upload-pack: git-pack-objects died with error."); goto fail; } if (finish_async(&rev_list)) @@ -291,7 +291,7 @@ static void create_pack_file(void) fail: send_client_data(3, abort_msg, sizeof(abort_msg)); - die("git-upload-pack: %s", abort_msg); + die("git upload-pack: %s", abort_msg); } static int got_sha1(char *hex, unsigned char *sha1) @@ -300,7 +300,7 @@ static int got_sha1(char *hex, unsigned char *sha1) int we_knew_they_have = 0; if (get_sha1_hex(hex, sha1)) - die("git-upload-pack: expected SHA1 object, got '%s'", hex); + die("git upload-pack: expected SHA1 object, got '%s'", hex); if (!has_sha1_file(sha1)) return -1; @@ -440,7 +440,7 @@ static int get_common_commits(void) packet_write(1, "NAK\n"); return -1; } - die("git-upload-pack: expected SHA1 list, got '%s'", line); + die("git upload-pack: expected SHA1 list, got '%s'", line); } } @@ -485,7 +485,7 @@ static void receive_needs(void) } if (prefixcmp(line, "want ") || get_sha1_hex(line+5, sha1_buf)) - die("git-upload-pack: protocol error, " + die("git upload-pack: protocol error, " "expected to get sha, not '%s'", line); if (strstr(line+45, "multi_ack")) multi_ack = 1; @@ -512,7 +512,7 @@ static void receive_needs(void) */ o = lookup_object(sha1_buf); if (!o || !(o->flags & OUR_REF)) - die("git-upload-pack: not our ref %s", line+5); + die("git upload-pack: not our ref %s", line+5); if (!(o->flags & WANTED)) { o->flags |= WANTED; add_object_array(o, NULL, &want_obj); @@ -577,7 +577,7 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo struct object *o = parse_object(sha1); if (!o) - die("git-upload-pack: cannot find object %s:", sha1_to_hex(sha1)); + die("git upload-pack: cannot find object %s:", sha1_to_hex(sha1)); if (capabilities) packet_write(1, "%s %s%c%s\n", sha1_to_hex(sha1), refname, diff --git a/xdiff-interface.c b/xdiff-interface.c index 61dc5c5470..944ad9887f 100644 --- a/xdiff-interface.c +++ b/xdiff-interface.c @@ -1,5 +1,12 @@ #include "cache.h" #include "xdiff-interface.h" +#include "strbuf.h" + +struct xdiff_emit_state { + xdiff_emit_consume_fn consume; + void *consume_callback_data; + struct strbuf remainder; +}; static int parse_num(char **cp_p, int *num_p) { @@ -55,13 +62,13 @@ static void consume_one(void *priv_, char *s, unsigned long size) unsigned long this_size; ep = memchr(s, '\n', size); this_size = (ep == NULL) ? size : (ep - s + 1); - priv->consume(priv, s, this_size); + priv->consume(priv->consume_callback_data, s, this_size); size -= this_size; s += this_size; } } -int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf) +static int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf) { struct xdiff_emit_state *priv = priv_; int i; @@ -69,36 +76,22 @@ int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf) for (i = 0; i < nbuf; i++) { if (mb[i].ptr[mb[i].size-1] != '\n') { /* Incomplete line */ - priv->remainder = xrealloc(priv->remainder, - priv->remainder_size + - mb[i].size); - memcpy(priv->remainder + priv->remainder_size, - mb[i].ptr, mb[i].size); - priv->remainder_size += mb[i].size; + strbuf_add(&priv->remainder, mb[i].ptr, mb[i].size); continue; } /* we have a complete line */ - if (!priv->remainder) { + if (!priv->remainder.len) { consume_one(priv, mb[i].ptr, mb[i].size); continue; } - priv->remainder = xrealloc(priv->remainder, - priv->remainder_size + - mb[i].size); - memcpy(priv->remainder + priv->remainder_size, - mb[i].ptr, mb[i].size); - consume_one(priv, priv->remainder, - priv->remainder_size + mb[i].size); - free(priv->remainder); - priv->remainder = NULL; - priv->remainder_size = 0; + strbuf_add(&priv->remainder, mb[i].ptr, mb[i].size); + consume_one(priv, priv->remainder.buf, priv->remainder.len); + strbuf_reset(&priv->remainder); } - if (priv->remainder) { - consume_one(priv, priv->remainder, priv->remainder_size); - free(priv->remainder); - priv->remainder = NULL; - priv->remainder_size = 0; + if (priv->remainder.len) { + consume_one(priv, priv->remainder.buf, priv->remainder.len); + strbuf_reset(&priv->remainder); } return 0; } @@ -141,6 +134,25 @@ int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t co return xdl_diff(&a, &b, xpp, xecfg, xecb); } +int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2, + xdiff_emit_consume_fn fn, void *consume_callback_data, + xpparam_t const *xpp, + xdemitconf_t const *xecfg, xdemitcb_t *xecb) +{ + int ret; + struct xdiff_emit_state state; + + memset(&state, 0, sizeof(state)); + state.consume = fn; + state.consume_callback_data = consume_callback_data; + xecb->outf = xdiff_outf; + xecb->priv = &state; + strbuf_init(&state.remainder, 0); + ret = xdi_diff(mf1, mf2, xpp, xecfg, xecb); + strbuf_release(&state.remainder); + return ret; +} + int read_mmfile(mmfile_t *ptr, const char *filename) { struct stat st; diff --git a/xdiff-interface.h b/xdiff-interface.h index f7f791d96b..558492ba38 100644 --- a/xdiff-interface.h +++ b/xdiff-interface.h @@ -3,18 +3,13 @@ #include "xdiff/xdiff.h" -struct xdiff_emit_state; - typedef void (*xdiff_emit_consume_fn)(void *, char *, unsigned long); -struct xdiff_emit_state { - xdiff_emit_consume_fn consume; - char *remainder; - unsigned long remainder_size; -}; - int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *ecb); -int xdiff_outf(void *priv_, mmbuffer_t *mb, int nbuf); +int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2, + xdiff_emit_consume_fn fn, void *consume_callback_data, + xpparam_t const *xpp, + xdemitconf_t const *xecfg, xdemitcb_t *xecb); int parse_hunk_header(char *line, int len, int *ob, int *on, int *nb, int *nn); |