Merge branch 'tr/rev-list-reverse'
authorJunio C Hamano <gitster@pobox.com>
Fri, 19 Sep 2008 03:18:37 +0000 (20:18 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 19 Sep 2008 03:18:37 +0000 (20:18 -0700)
* tr/rev-list-reverse:
t6013: replace use of 'tac' with equivalent Perl
rev-list: fix --reverse interaction with --parents

403 files changed:
.gitignore
Documentation/Makefile
Documentation/RelNotes-1.5.2.txt
Documentation/RelNotes-1.5.3.txt
Documentation/RelNotes-1.5.4.4.txt
Documentation/RelNotes-1.5.4.5.txt
Documentation/RelNotes-1.5.6.5.txt
Documentation/RelNotes-1.6.0.1.txt [new file with mode: 0644]
Documentation/RelNotes-1.6.0.2.txt [new file with mode: 0644]
Documentation/RelNotes-1.6.0.txt
Documentation/RelNotes-1.6.1.txt [new file with mode: 0644]
Documentation/SubmittingPatches
Documentation/config.txt
Documentation/diff-options.txt
Documentation/git-am.txt
Documentation/git-annotate.txt
Documentation/git-cat-file.txt
Documentation/git-checkout.txt
Documentation/git-clone.txt
Documentation/git-commit-tree.txt
Documentation/git-commit.txt
Documentation/git-count-objects.txt
Documentation/git-cvsserver.txt
Documentation/git-daemon.txt
Documentation/git-diff-tree.txt
Documentation/git-filter-branch.txt
Documentation/git-for-each-ref.txt
Documentation/git-format-patch.txt
Documentation/git-hash-object.txt
Documentation/git-help.txt
Documentation/git-imap-send.txt
Documentation/git-merge-base.txt
Documentation/git-merge.txt
Documentation/git-mergetool.txt
Documentation/git-name-rev.txt
Documentation/git-push.txt
Documentation/git-read-tree.txt
Documentation/git-rerere.txt
Documentation/git-revert.txt
Documentation/git-rm.txt
Documentation/git-send-email.txt
Documentation/git-stash.txt
Documentation/git-submodule.txt
Documentation/git-svn.txt
Documentation/git-var.txt
Documentation/git-web--browse.txt
Documentation/git.txt
Documentation/gitattributes.txt
Documentation/gitcore-tutorial.txt
Documentation/gitk.txt
Documentation/gitmodules.txt
Documentation/gittutorial.txt
Documentation/i18n.txt
Documentation/merge-config.txt
Documentation/pretty-formats.txt
Documentation/pull-fetch-param.txt
Documentation/rev-list-options.txt
Documentation/user-manual.txt
GIT-VERSION-GEN
INSTALL
Makefile
RelNotes
archive.c
builtin-add.c
builtin-apply.c
builtin-archive.c
builtin-blame.c
builtin-bundle.c
builtin-cat-file.c
builtin-check-ref-format.c
builtin-checkout-index.c
builtin-checkout.c
builtin-clone.c
builtin-commit-tree.c
builtin-commit.c
builtin-count-objects.c
builtin-diff-index.c
builtin-diff-tree.c
builtin-diff.c
builtin-fast-export.c
builtin-fetch-pack.c
builtin-fetch.c
builtin-for-each-ref.c
builtin-fsck.c
builtin-grep.c
builtin-help.c [new file with mode: 0644]
builtin-http-fetch.c
builtin-init-db.c
builtin-log.c
builtin-ls-files.c
builtin-ls-tree.c
builtin-mailinfo.c
builtin-merge-base.c
builtin-merge-recursive.c
builtin-merge.c
builtin-name-rev.c
builtin-pack-objects.c
builtin-prune.c
builtin-push.c
builtin-read-tree.c
builtin-reflog.c
builtin-remote.c
builtin-rev-list.c
builtin-revert.c
builtin-rm.c
builtin-send-pack.c
builtin-show-ref.c
builtin-tag.c
builtin-tar-tree.c
builtin-unpack-objects.c
builtin-update-index.c
builtin-verify-pack.c
builtin.h
cache.h
combine-diff.c
commit.h
compat/fnmatch.c [deleted file]
compat/fnmatch.h [deleted file]
compat/fnmatch/fnmatch.c [new file with mode: 0644]
compat/fnmatch/fnmatch.h [new file with mode: 0644]
compat/mingw.c
compat/mingw.h
compat/regex.c [deleted file]
compat/regex.h [deleted file]
compat/regex/regex.c [new file with mode: 0644]
compat/regex/regex.h [new file with mode: 0644]
compat/snprintf.c
config.mak.in
configure.ac
connect.c
contrib/completion/git-completion.bash
contrib/fast-import/git-p4
contrib/fast-import/git-p4.txt
csum-file.c
ctype.c
daemon.c
decorate.c
decorate.h
diff.c
diff.h
dir.c
entry.c
fast-import.c
git-am.sh
git-bisect.sh
git-compat-util.h
git-cvsimport.perl
git-filter-branch.sh
git-gui/GIT-VERSION-GEN
git-gui/git-gui.sh
git-gui/lib/blame.tcl
git-gui/lib/browser.tcl
git-gui/lib/commit.tcl
git-gui/lib/diff.tcl
git-gui/lib/index.tcl
git-gui/lib/mergetool.tcl [new file with mode: 0644]
git-gui/lib/option.tcl
git-gui/po/README
git-gui/po/de.po
git-gui/po/fr.po
git-gui/po/git-gui.pot
git-gui/po/it.po
git-gui/po/ja.po
git-gui/po/po2msg.sh
git-gui/po/sv.po
git-merge-octopus.sh
git-rebase--interactive.sh
git-rebase.sh
git-stash.sh
git-submodule.sh
git-svn.perl
git.c
git.spec.in
gitk-git/gitk
gitk-git/po/de.po
gitk-git/po/sv.po
gitweb/gitweb.css
gitweb/gitweb.perl
grep.c
grep.h
hash-object.c
help.c
help.h [new file with mode: 0644]
http-push.c
http.c
imap-send.c
index-pack.c
levenshtein.c [new file with mode: 0644]
levenshtein.h [new file with mode: 0644]
log-tree.c
merge-index.c
object.h
pack-revindex.c
pack-revindex.h
pack-write.c
pack.h
pager.c
parse-options.c
parse-options.h
path.c
perl/Git.pm
perl/Makefile
pretty.c
read-cache.c
receive-pack.c
refs.c
remote.c
remote.h
revision.c
revision.h
run-command.c
run-command.h
setup.c
sha1_file.c
sha1_name.c
shell.c
sideband.c
t/.gitignore
t/Makefile
t/lib-git-svn.sh
t/lib-httpd.sh
t/t0022-crlf-rename.sh
t/t0023-crlf-am.sh
t/t0050-filesystem.sh
t/t0055-beyond-symlinks.sh [new file with mode: 0755]
t/t1000-read-tree-m-3way.sh
t/t1002-read-tree-m-u-2way.sh
t/t1007-hash-object.sh
t/t1200-tutorial.sh
t/t1303-wacky-config.sh
t/t1400-update-ref.sh
t/t1410-reflog.sh
t/t1501-worktree.sh
t/t1503-rev-parse-verify.sh
t/t2005-checkout-index-symlinks.sh
t/t2050-git-dir-relative.sh
t/t2101-update-index-reupdate.sh
t/t2102-update-index-symlinks.sh
t/t2200-add-update.sh
t/t3001-ls-files-others-exclude.sh
t/t3020-ls-files-error-unmatch.sh
t/t3030-merge-recursive.sh
t/t3200-branch.sh
t/t3210-pack-refs.sh
t/t3300-funny-names.sh
t/t3400-rebase.sh
t/t3401-rebase-partial.sh
t/t3403-rebase-skip.sh
t/t3404-rebase-interactive.sh
t/t3407-rebase-abort.sh
t/t3500-cherry.sh
t/t3504-cherry-pick-rerere.sh [new file with mode: 0755]
t/t3600-rm.sh
t/t3700-add.sh
t/t3800-mktag.sh
t/t3900-i18n-commit.sh
t/t3901-i18n-patch.sh
t/t3902-quoted.sh
t/t3903-stash.sh
t/t4000-diff-format.sh
t/t4001-diff-rename.sh
t/t4002-diff-basic.sh
t/t4003-diff-rename-1.sh
t/t4004-diff-rename-symlink.sh
t/t4005-diff-rename-2.sh
t/t4007-rename-3.sh
t/t4008-diff-break-rewrite.sh
t/t4009-diff-rename-4.sh
t/t4010-diff-pathspec.sh
t/t4011-diff-symlink.sh
t/t4012-diff-binary.sh
t/t4013-diff-various.sh
t/t4014-format-patch.sh
t/t4015-diff-whitespace.sh
t/t4016-diff-quote.sh
t/t4018-diff-funcname.sh
t/t4019-diff-wserror.sh
t/t4020-diff-external.sh
t/t4022-diff-rewrite.sh
t/t4023-diff-rename-typechange.sh
t/t4027-diff-submodule.sh
t/t4029-diff-trailing-space.sh [new file with mode: 0755]
t/t4100-apply-stat.sh
t/t4101-apply-nonl.sh
t/t4103-apply-binary.sh
t/t4104-apply-boundary.sh
t/t4124-apply-ws-rule.sh
t/t4127-apply-same-fn.sh
t/t4150-am.sh
t/t4151-am-abort.sh
t/t4202-log.sh
t/t5100-mailinfo.sh
t/t5100/info-from.expect [new file with mode: 0644]
t/t5100/info-from.in [new file with mode: 0644]
t/t5100/info0011 [new file with mode: 0644]
t/t5100/msg0011 [new file with mode: 0644]
t/t5100/patch0011 [new file with mode: 0644]
t/t5100/sample.mbox
t/t5300-pack-object.sh
t/t5301-sliding-window.sh
t/t5302-pack-index.sh
t/t5304-prune.sh
t/t5305-include-tag.sh
t/t5306-pack-nobase.sh [new file with mode: 0755]
t/t5400-send-pack.sh
t/t5401-update-hooks.sh
t/t5402-post-merge-hook.sh
t/t5403-post-checkout-hook.sh
t/t5500-fetch-pack.sh
t/t5505-remote.sh
t/t5510-fetch.sh
t/t5515-fetch-merge-logic.sh
t/t5530-upload-pack-error.sh
t/t5540-http-push.sh
t/t5600-clone-fail-cleanup.sh
t/t5601-clone.sh
t/t5602-clone-remote-exec.sh
t/t6002-rev-list-bisect.sh
t/t6003-rev-list-topo-order.sh
t/t6006-rev-list-format.sh
t/t6010-merge-base.sh
t/t6023-merge-file.sh
t/t6025-merge-symlinks.sh
t/t6026-merge-attr.sh
t/t6027-merge-binary.sh
t/t6030-bisect-porcelain.sh
t/t6101-rev-parse-parents.sh
t/t6120-describe.sh
t/t6200-fmt-merge-msg.sh
t/t6300-for-each-ref.sh
t/t7001-mv.sh
t/t7002-grep.sh
t/t7003-filter-branch.sh
t/t7004-tag.sh
t/t7101-reset.sh
t/t7102-reset.sh
t/t7103-reset-bare.sh
t/t7201-co.sh
t/t7300-clean.sh
t/t7400-submodule-basic.sh
t/t7401-submodule-summary.sh
t/t7500-commit.sh
t/t7501-commit.sh
t/t7502-status.sh
t/t7505-prepare-commit-msg-hook.sh
t/t7506-status-submodule.sh
t/t7600-merge.sh
t/t7601-merge-pull-config.sh
t/t7602-merge-octopus-many.sh
t/t7603-merge-reduce-heads.sh
t/t7604-merge-custom-message.sh
t/t7605-merge-resolve.sh
t/t7606-merge-custom.sh [new file with mode: 0755]
t/t7610-mergetool.sh
t/t7701-repack-unpack-unreachable.sh
t/t8001-annotate.sh
t/t8002-blame.sh
t/t9001-send-email.sh
t/t9100-git-svn-basic.sh
t/t9101-git-svn-props.sh
t/t9102-git-svn-deep-rmdir.sh
t/t9103-git-svn-tracked-directory-removed.sh
t/t9104-git-svn-follow-parent.sh
t/t9105-git-svn-commit-diff.sh
t/t9106-git-svn-commit-diff-clobber.sh
t/t9106-git-svn-dcommit-clobber-series.sh
t/t9107-git-svn-migrate.sh
t/t9108-git-svn-glob.sh
t/t9108-git-svn-multi-glob.sh [new file with mode: 0755]
t/t9110-git-svn-use-svm-props.sh
t/t9111-git-svn-use-svnsync-props.sh
t/t9112-git-svn-md5less-file.sh
t/t9113-git-svn-dcommit-new-file.sh
t/t9114-git-svn-dcommit-merge.sh
t/t9115-git-svn-dcommit-funky-renames.sh
t/t9116-git-svn-log.sh
t/t9117-git-svn-init-clone.sh
t/t9118-git-svn-funky-branch-names.sh
t/t9119-git-svn-info.sh
t/t9120-git-svn-clone-with-percent-escapes.sh
t/t9121-git-svn-fetch-renamed-dir.sh
t/t9122-git-svn-author.sh
t/t9123-git-svn-rebuild-with-rewriteroot.sh
t/t9124-git-svn-dcommit-auto-props.sh
t/t9125-git-svn-multi-glob-branch-names.sh [new file with mode: 0755]
t/t9200-git-cvsexportcommit.sh
t/t9300-fast-import.sh
t/t9301-fast-export.sh
t/t9400-git-cvsserver-server.sh
t/t9500-gitweb-standalone-no-errors.sh
t/t9600-cvsimport.sh
t/t9700-perl-git.sh
t/t9700/test.pl
t/test-lib.sh
templates/Makefile
test-parse-options.c
transport.c
tree-diff.c
unpack-trees.c
unpack-trees.h
upload-pack.c
xdiff-interface.c
xdiff-interface.h
index a213e8e25bb2442326e86cbfb9ef56319f482869..bbaf9de0bca797508b9c2a011d0d18eac8907157 100644 (file)
@@ -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
index 62269e39c4edf95b2cf2e6a60bff2a33b239b07e..ded0e40b978e6f4b85530541c45782f2b383ea44 100644 (file)
@@ -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
index 6195715dc78a26ce9ac452bd64852455fb79137c..e8328d090a438e496ff2e6a2026f633d77f589b5 100644 (file)
@@ -36,7 +36,7 @@ Updates since v1.5.1
   expansion).  These conversions apply when checking files in
   or out, and exporting via git-archive.
 
-* The packfile format now optionally suports 64-bit index.
+* The packfile format now optionally supports 64-bit index.
 
   This release supports the "version 2" format of the .idx
   file.  This is automatically enabled when a huge packfile
index d03894b92645f2dd0d7cb464d3ab1905d8cb62ed..0668d3c0cadc8e252ae07e0f873f603fafa02c27 100644 (file)
@@ -86,7 +86,7 @@ Updates since v1.5.2
 
   - "git rev-list" learned --regexp-ignore-case and
     --extended-regexp options to tweak its matching logic used
-    for --grep fitering.
+    for --grep filtering.
 
   - "git describe --contains" is a handier way to call more
     obscure command "git name-rev --tags".
@@ -243,7 +243,7 @@ Updates since v1.5.2
 
   - We used to have core.legacyheaders configuration, when
     set to false, allowed git to write loose objects in a format
-    that mimicks the format used by objects stored in packs.  It
+    that mimics the format used by objects stored in packs.  It
     turns out that this was not so useful.  Although we will
     continue to read objects written in that format, we do not
     honor that configuration anymore and create loose objects in
@@ -302,7 +302,7 @@ Updates since v1.5.2
     small enough delta results it creates while looking for the
     best delta candidates.
 
-  - "git pack-objects" learned a new heuristcs to prefer delta
+  - "git pack-objects" learned a new heuristic to prefer delta
     that is shallower in depth over the smallest delta
     possible.  This improves both overall packfile access
     performance and packfile density.
index 89fa6d03bc038d6210e94d7fe9fbbffdbc84d883..323c1a88c7fe2be146d2ae7682de6f723acd6fa8 100644 (file)
@@ -55,7 +55,7 @@ Fixes since v1.5.4.3
 
  * "git log --merge" did not work well with --left-right option.
 
- * "git svn" promprted for client cert password every time it accessed the
+ * "git svn" prompted for client cert password every time it accessed the
    server.
 
  * The reset command in "git fast-import" data stream was documented to
index 02823413987d5a10364d936327e3a1cfb38cbac2..bbd130e36d411e70f7c3b3b4fcfe531d383e9f0e 100644 (file)
@@ -9,7 +9,7 @@ Fixes since v1.5.4.4
    1.5.4).
 
  * Bogus refspec configuration such as "remote.there.fetch = =" were not
-   detected as errors (regressionin 1.5.4).
+   detected as errors (regression in 1.5.4).
 
  * You couldn't specify a custom editor whose path contains a whitespace
    via GIT_EDITOR (and core.editor).
index fc40438b1637d5d5d1bd8112407501c542d4e2c5..47ca1724620fa25491c27984a41ca56e2aa4e323 100644 (file)
@@ -4,10 +4,20 @@ GIT v1.5.6.5 Release Notes
 Fixes since v1.5.6.4
 --------------------
 
+* "git cvsimport" used to spit out "UNKNOWN LINE..." diagnostics to stdout.
+
+* "git commit -F filename" and "git tag -F filename" run from subdirectories
+  did not read the right file.
+
 * "git init --template=" with blank "template" parameter linked files
   under root directories to .git, which was a total nonsense.  Instead, it
   means "I do not want to use anything from the template directory".
 
+* "git diff-tree" and other diff plumbing ignored diff.renamelimit configuration
+  variable when the user explicitly asked for rename detection.
+
+* "git name-rev --name-only" did not work when "--stdin" option was in effect.
+
 * "git show-branch" mishandled its 8th branch.
 
 * Addition of "git update-index --ignore-submodules" that happened during
diff --git a/Documentation/RelNotes-1.6.0.1.txt b/Documentation/RelNotes-1.6.0.1.txt
new file mode 100644 (file)
index 0000000..49d7a1c
--- /dev/null
@@ -0,0 +1,36 @@
+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.
+
+* "git for-each-ref" tried to dereference NULL when asked for '%(body)" on
+  a tag with a single incomplete line as its payload.
+
+* "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.
+
+* "git mailinfo" also was unhappy when the "From: " line only had a bare
+  e-mail address.
+
+* "git merge" did not refresh the index correctly when a merge resulted in
+  a fast-forward.
+
+* "git merge" did not resolve a truly trivial merges that can be done
+  without content level merges.
+
+* "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 (file)
index 0000000..7a9646f
--- /dev/null
@@ -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
index 2542cf53d2e40b06afe918fcf1cd35de19126d9e..de7ef166b692fd0db72db3e7f9e3a4d1b402da54 100644 (file)
@@ -5,7 +5,7 @@ User visible changes
 --------------------
 
 With the default Makefile settings, most of the programs are now
-installed outside your $PATH, except for "git", "gitk", "git-gui" and
+installed outside your $PATH, except for "git", "gitk" and
 some server side programs that need to be accessible for technical
 reasons.  Invoking a git subcommand as "git-xyzzy" from the command
 line has been deprecated since early 2006 (and officially announced in
@@ -28,6 +28,16 @@ introduced in v1.5.2 and v1.4.4.5.  If you want to keep your repositories
 backwards compatible past these versions, set repack.useDeltaBaseOffset
 to false or pack.indexVersion to 1, respectively.
 
+We used to prevent sample hook scripts shipped in templates/ from
+triggering by default by relying on the fact that we install them as
+unexecutable, but on some filesystems, this approach does not work.
+They are now shipped with ".sample" suffix.  If you want to activate
+any of these samples as-is, rename them to drop the ".sample" suffix,
+instead of running "chmod +x" on them.  For example, you can rename
+hooks/post-update.sample to hooks/post-update to enable the sample
+hook that runs update-server-info, in order to make repositories
+friendly to dumb protocols (i.e. HTTP).
+
 GIT_CONFIG, which was only documented as affecting "git config", but
 actually affected all git commands, now only affects "git config".
 GIT_LOCAL_CONFIG, also only documented as affecting "git config" and
@@ -56,11 +66,7 @@ Updates since v1.5.6
   gangs.
 
 * Sample hook scripts shipped in templates/ are now suffixed with
-  *.sample.  We used to prevent them from triggering by default by
-  relying on the fact that we install them as unexecutable, but on
-  some filesystems this approach does not work.  Instead of running
-  "chmod +x" on them, the users who want to activate these samples
-  as-is can now rename them dropping *.sample suffix.
+  *.sample.
 
 * perl's in-place edit (-i) does not work well without backup files on Windows;
   some tests are rewritten to cope with this.
@@ -142,6 +148,10 @@ Updates since v1.5.6
 * git-archive uses the zlib default compression level when creating
   zip archive.
 
+* git-archive's command line options --exec and --remote can take their
+  parameters as separate command line arguments, similar to other commands.
+  IOW, both "--exec=path" and "--exec path" are now supported.
+
 * With -v option, git-branch describes the remote tracking statistics
   similar to the way git-checkout reports by how many commits your branch
   is ahead/behind.
@@ -161,10 +171,16 @@ Updates since v1.5.6
 * git-clone can clone from a remote whose URL would be rewritten by
   configuration stored in $HOME/.gitconfig now.
 
+* "git-clone --mirror" is a handy way to set up a bare mirror repository.
+
 * git-cvsserver learned to respond to "cvs co -c".
 
 * git-diff --check now checks leftover merge conflict markers.
 
+* "git-diff -p" learned to grab a better hunk header lines in
+  BibTex, Pascal/Delphi, and Ruby files and also pays attention to
+  chapter and part boundary in TeX documents.
+
 * When remote side used to have branch 'foo' and git-fetch finds that now
   it has branch 'foo/bar', it refuses to lose the existing remote tracking
   branch and its reflog.  The error message has been improved to suggest
@@ -176,6 +192,10 @@ Updates since v1.5.6
 
 * fast-import and fast-export learned to export and import gitlinks.
 
+* "gitk" left background process behind after being asked to dig very deep
+  history and the user killed the UI; the process is killed when the UI goes
+  away now.
+
 * git-rebase records the original tip of branch in ORIG_HEAD before it is
   rewound.
 
@@ -187,7 +207,7 @@ Updates since v1.5.6
   command internally uses rev-parse to interpret its arguments.
 
 * git-rev-list learned --children option to show child commits it
-  encountered during the traversal, instead of shoing parent commits.
+  encountered during the traversal, instead of showing parent commits.
 
 * git-send-mail can talk not just over SSL but over TLS now.
 
@@ -225,15 +245,14 @@ Fixes since v1.5.6
 All of the fixes in v1.5.6 maintenance series are included in
 this release, unless otherwise noted.
 
-* git-clone ignored its -u option; the fix needs to be backported to
-  'maint';
+ * git-clone ignored its -u option; the fix needs to be backported to
+   'maint';
+
+ * git-mv used to lose the distinction between changes that are staged
+   and that are only in the working tree, by staging both in the index
+   after moving such a path.
 
-* git-mv used to lose the distinction between changes that are staged
-  and that are only in the working tree, by staging both in the index
-  after moving such a path.
+ * "git-rebase -i -p" rewrote the parents to wrong ones when amending
+   (either edit or squash) was involved, and did not work correctly
+   when fast forwarding.
 
----
-exec >/var/tmp/1
-O=v1.6.0-rc0-104-g81dc230
-echo O=$(git describe refs/heads/master)
-git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
diff --git a/Documentation/RelNotes-1.6.1.txt b/Documentation/RelNotes-1.6.1.txt
new file mode 100644 (file)
index 0000000..609d4ca
--- /dev/null
@@ -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
index 841bead9db18a025638570c10cac72bcf4791f68..a1e9100f9e3ccb8466ec603e154cb230dc2cb33b 100644 (file)
@@ -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 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.
 
index 61c376057c0f2b9510bf6f1b2beb42f9859b7f46..922ac7b44da1c2cc04bf024307e9ccd54709580f 100644 (file)
@@ -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,12 +697,12 @@ 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
        treat it as text. If `crlf` is explicitly unset, the file
-       will be set with '-kb' mode, which supresses any newline munging
+       will be set with '-kb' mode, which suppresses any newline munging
        the client might otherwise do. If `crlf` is not specified,
        then 'gitcvs.allbinary' is used. See linkgit:gitattributes[5].
 
@@ -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
@@ -978,6 +996,13 @@ pack.packSizeLimit::
        can be overridden by the `\--max-pack-size` option of
        linkgit:git-repack[1].
 
+pager.<cmd>::
+       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
        at once.
index cba90fd27c6a1baaca884328e96adc8a6da8fc36..6e268326da9e34882313b7b3d094a617c3966d29 100644 (file)
@@ -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 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
index c45c53ec2404725394563a9fba40f31cd314adb2..b9c6fac7483dbefba0afb60a76ac0362aa390a6d 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 --------
 [verse]
 'git am' [--signoff] [--keep] [--utf8 | --no-utf8]
-         [--3way] [--interactive] [--binary]
+        [--3way] [--interactive]
          [--whitespace=<option>] [-C<n>] [-p<n>]
         [<mbox> | <Maildir>...]
 'git am' (--skip | --resolved | --abort)
@@ -59,11 +59,6 @@ default.   You could use `--no-utf8` to override this.
        it is supposed to apply to, and we have those blobs
        available locally.
 
--b::
---binary::
-       Pass `--allow-binary-replacement` flag to 'git-apply'
-       (see linkgit:git-apply[1]).
-
 --whitespace=<option>::
        This flag is passed to the 'git-apply' (see linkgit:git-apply[1])
        program that applies
index 8b6b56a54409dd586047a1a6cdf1138e8bb0e77b..0aba022ba6838442721a0584f3eaa293a3a90f74 100644 (file)
@@ -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[]
index d35e8a04fe28b095b5405ae2e0b09e3ab448bf63..668f697c2a03c29f589e249de832ddf01b9b1e6d 100644 (file)
@@ -81,7 +81,7 @@ object specified on stdin:
 ------------
 
 If '--batch-check' is specified, output of the following form is printed for
-each object specified fon stdin:
+each object specified on stdin:
 
 ------------
 <sha1> SP <type> SP <size> LF
index 5aa69c0e12a6756fd6f79c117008a373f65ba5f5..be54a0299fb2b6849993aa27d18c829ce91e7e00 100644 (file)
@@ -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.
index 26fd1b111798461b9150f1416721aa460f1ea525..0e14e732fd470b7f48882c9959235785df19b7b0 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 --------
 [verse]
 'git clone' [--template=<template_directory>]
-         [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare]
+         [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]
          [-o <name>] [-u <upload-pack>] [--reference <repository>]
          [--depth <depth>] [--] <repository> [<directory>]
 
@@ -106,6 +106,9 @@ then the cloned repository will become corrupt.
        used, neither remote-tracking branches nor the related
        configuration variables are created.
 
+--mirror::
+       Set up a mirror of the remote repository.  This implies --bare.
+
 --origin <name>::
 -o <name>::
        Instead of using the remote name 'origin' to keep track
index feec58400b64c65c8f96f2d1834016455c89829e..b8834baced4b25d6df47eb578c4d745d23e8cc73 100644 (file)
@@ -16,12 +16,12 @@ This is usually not what an end user wants to run directly.  See
 linkgit:git-commit[1] instead.
 
 Creates a new commit object based on the provided tree object and
-emits the new commit object id on stdout. If no parent is given then
-it is considered to be an initial tree.
+emits the new commit object id on stdout.
 
-A commit object usually has 1 parent (a commit after a change) or up
-to 16 parents.  More than one parent represents a merge of branches
-that led to them.
+A commit object may have any number of parents. With exactly one
+parent, it is an ordinary commit. Having more than one parent makes
+the commit a merge between several lines of history. Initial (root)
+commits have no parents.
 
 While a tree represents a particular directory state of a working
 directory, a commit represents that state in "time", and explains how
@@ -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
 ----------
index 0e25bb862704eee4a22fe5349c04823d14ea9cba..eb05b0f49b0c513581150415d1a4e679d7bfbea6 100644 (file)
@@ -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>::
index 75a8da1ca906aee4cc6a7d0c3ff19862b8e0fc2f..6bc1c21e6283284e2eae16d7ec4cb8183d8e0851 100644 (file)
@@ -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
index c2d3c90d27084e7de7e0f7c37b40f130f6960244..785779e22122156bdc8c58a94d36edb66a8ee266 100644 (file)
@@ -11,7 +11,7 @@ SYNOPSIS
 SSH:
 
 [verse]
-export CVS_SERVER=git-cvsserver
+export CVS_SERVER="git cvsserver"
 'cvs' -d :ext:user@server/path/repo.git co <HEAD_name>
 
 pserver (/etc/inetd.conf):
@@ -109,7 +109,7 @@ Note: Newer CVS versions (>= 1.12.11) also support specifying
 CVS_SERVER directly in CVSROOT like
 
 ------
-cvs -d ":ext;CVS_SERVER=git-cvsserver:user@server/path/repo.git" co <HEAD_name>
+cvs -d ":ext;CVS_SERVER=git cvsserver:user@server/path/repo.git" co <HEAD_name>
 ------
 This has the advantage that it will be saved in your 'CVS/Root' files and
 you don't need to worry about always setting the correct environment
@@ -158,7 +158,7 @@ allowing access over SSH.
 --
 ------
      export CVSROOT=:ext:user@server:/var/git/project.git
-     export CVS_SERVER=git-cvsserver
+     export CVS_SERVER="git cvsserver"
 ------
 --
 4. For SSH clients that will make commits, make sure their server-side
@@ -283,7 +283,7 @@ To get a checkout with the Eclipse CVS client:
 Protocol notes: If you are using anonymous access via pserver, just select that.
 Those using SSH access should choose the 'ext' protocol, and configure 'ext'
 access on the Preferences->Team->CVS->ExtConnection pane. Set CVS_SERVER to
-'git-cvsserver'. Note that password support is not good when using 'ext',
+"'git cvsserver'". Note that password support is not good when using 'ext',
 you will definitely want to have SSH keys setup.
 
 Alternatively, you can just use the non-standard extssh protocol that Eclipse
index 4ba4b75c1126d87c48935e7697e05f0d5210ad2d..b08a08cd95b6da192a008c58d7973769dfe3fc8c 100644 (file)
@@ -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.
index 8c8f35b7a762d42d3c45ff9f4eee1cb32d3917b6..5d48664e624f59e0df16121ed67d84939f6d2a31 100644 (file)
@@ -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 pair of <tree-ish>
-       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.  This does not apply to the case where two <tree-ish>
-separated with a single space are given.
+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
index a518ba6072127afce1b117a6c70022415979d079..b0e710d5f9c05eb86ce3ccc4e1aa4a7868f3abff 100644 (file)
@@ -13,7 +13,7 @@ SYNOPSIS
        [--msg-filter <command>] [--commit-filter <command>]
        [--tag-name-filter <command>] [--subdirectory-filter <directory>]
        [--original <namespace>] [-d <directory>] [-f | --force]
-       [<rev-list options>...]
+       [--] [<rev-list options>...]
 
 DESCRIPTION
 -----------
@@ -168,10 +168,10 @@ to other tags will be rewritten to point to the underlying commit.
        'refs/original/', unless forced.
 
 <rev-list options>...::
-       When options are given after the new branch name, they will
-       be passed to 'git-rev-list'.  Only commits in the resulting
-       output will be filtered, although the filtered commits can still
-       reference parents which are outside of that set.
+       Arguments for 'git-rev-list'.  All positive refs included by
+       these options are rewritten.  You may also specify options
+       such as '--all', but you must use '--' to separate them from
+       the 'git-filter-branch' options.
 
 
 Examples
@@ -196,6 +196,17 @@ git filter-branch --index-filter 'git rm --cached filename' HEAD
 
 Now, you will get the rewritten history saved in HEAD.
 
+To rewrite the repository to look as if `foodir/` had been its project
+root, and discard all other history:
+
+-------------------------------------------------------
+git filter-branch --subdirectory-filter foodir -- --all
+-------------------------------------------------------
+
+Thus you can, e.g., turn a library subdirectory into a repository of
+its own.  Note the `\--` that separates 'filter-branch' options from
+revision options, and the `\--all` to rewrite all branches and tags.
+
 To set a commit (which typically is at the tip of another
 history) to be the parent of the current initial commit, in
 order to paste the other history behind the current history:
index 609f9496bac7c7a9f4772aa75293bda6e5e755c5..ebd7c5fbb34576fd2af98b00d9045340ff77ee2b 100644 (file)
@@ -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.
@@ -49,7 +49,7 @@ OPTIONS
 
 <pattern>...::
        If one or more patterns are given, only refs are shown that
-       match againt at least one pattern, either using fnmatch(3) or
+       match against at least one pattern, either using fnmatch(3) or
        literally, in the latter case matching completely or from the
        beginning up to a slash.
 
index 010d9e432231f41a179023df2e85610583b572cf..adb4ea7b1b6c70fb6fc2486487ef34ed280ec015 100644 (file)
@@ -147,9 +147,9 @@ include::diff-options.txt[]
        to any configured headers, and may be used multiple times.
 
 --cover-letter::
-       Generate a cover letter template.  You still have to fill in
-       a description, but the shortlog and the diffstat will be
-       generated for you.
+       In addition to the patches, generate a cover letter file
+       containing the shortlog and the overall diffstat.  You can
+       fill in a description in the file before sending it out.
 
 --suffix=.<sfx>::
        Instead of using `.patch` as the suffix for generated
index ac928e198e75595a6fcd4e83b89aaf68987bd420..0af40cfb85ca6e0eb6e540f0beb47e449ef25afd 100644 (file)
@@ -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>
index f414583fc48e85e4785fbf5f9431bb81a96ccd9d..d9b9c34b3a60f09bea4f9e53b5127f33f356e042 100644 (file)
@@ -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
 ~~~~~~~~~~~~~~~
index b3d8da33ee64730794821440c287f30c4bb85789..bd49a0aee8881f983077d74bd8d0fbe5764dfea5 100644 (file)
@@ -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
 ..........................
 
 
index 1a7ecbf8f39381b0c7b2da513dfa26eacec15cf6..2f0c5259e01917e456954de5eb59597a2c829b0c 100644 (file)
@@ -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
 ------
index 17a15acb07df2d8beed4a41cdcf820010f95b35b..685e1fed586cb74a50b95d10fff6c8773cc7c8e7 100644 (file)
@@ -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
 --------
index 31570b1e27af6a603df98868c627da08d91c17cc..e0b2703b380cb46b23870a97b861462d8e8f758a 100644 (file)
@@ -40,7 +40,7 @@ tool is available in PATH.
 +
 Instead of running one of the known merge tool programs
 'git-mergetool' can be customized to run an alternative program
-by specifying the command line to invoke in a configration
+by specifying the command line to invoke in a configuration
 variable `mergetool.<tool>.cmd`.
 +
 When 'git-mergetool' is invoked with this tool (either through the
index 6e77ab135353aaf713b638a70701717db1706c2c..7ca8a7b48cea191b58db93581f02fa4ff265acdc 100644 (file)
@@ -38,8 +38,7 @@ OPTIONS
        Instead of printing both the SHA-1 and the name, print only
        the name.  If given with --tags the usual tag prefix of
        "tags/" is also omitted from the name, matching the output
-       of 'git-describe' more closely.  This option
-       cannot be combined with --stdin.
+       of `git-describe` more closely.
 
 --no-undefined::
        Die with error code != 0 when a reference is undefined,
@@ -60,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.
index 050c3ddae2732fdf4cb9f3b0f798e3d2d190fa4e..45c96435fa66ab4b1b57b6a860a2fc264321cfe4 100644 (file)
@@ -31,8 +31,8 @@ OPTIONS
        operation.  See the section <<URLS,GIT URLS>> below.
 
 <refspec>...::
-       The canonical format of each <refspec> parameter is
-       `+?<src>:<dst>`; that is, an optional plus `+`, followed
+       The canonical format of a <refspec> parameter is
+       `+?<src>:<dst>`; that is, an optional plus `{plus}`, followed
        by the source ref, followed by a colon `:`, followed by
        the destination ref.
 +
index 6f4b9b017f7b504a2b9e909639a61b1ef7750af0..309deac23b5bf8eea28441d34e78b7cdb3a02d28 100644 (file)
@@ -160,7 +160,10 @@ Here are the "carry forward" rules:
       0 nothing             nothing  nothing  (does not happen)
       1 nothing             nothing  exists   use M
       2 nothing             exists   nothing  remove path from index
-      3 nothing             exists   exists   use M
+      3 nothing             exists   exists,  use M if "initial checkout"
+                                    H == M   keep index otherwise
+                                    exists   fail
+                                    H != M
 
         clean I==H  I==M
        ------------------
@@ -207,6 +210,12 @@ you picked it up via e-mail in a patch form), `git diff-index
 merge, but it would not show in `git diff-index --cached $M`
 output after two-tree merge.
 
+Case #3 is slightly tricky and needs explanation.  The result from this
+rule logically should be to remove the path if the user staged the removal
+of the path and then swiching to a new branch.  That however will prevent
+the initial checkout from happening, so the rule is modified to use M (new
+tree) only when the contents of the index is empty.  Otherwise the removal
+of the path is kept as long as $H and $M are the same.
 
 3-Way Merge
 ~~~~~~~~~~~
index 89f321b414212a555f1e0fb0ff0ce6f4c180fd06..64715c17da6c313a1cec4c353300eb0faee2313b 100644 (file)
@@ -90,15 +90,15 @@ One way to do it is to pull master into the topic branch:
 
 The commits marked with `*` touch the same area in the same
 file; you need to resolve the conflicts when creating the commit
-marked with `+`.  Then you can test the result to make sure your
+marked with `{plus}`.  Then you can test the result to make sure your
 work-in-progress still works with what is in the latest master.
 
 After this test merge, there are two ways to continue your work
 on the topic.  The easiest is to build on top of the test merge
-commit `+`, and when your work in the topic branch is finally
+commit `{plus}`, and when your work in the topic branch is finally
 ready, pull the topic branch into master, and/or ask the
 upstream to pull from you.  By that time, however, the master or
-the upstream might have been advanced since the test merge `+`,
+the upstream might have been advanced since the test merge `{plus}`,
 in which case the final commit graph would look like this:
 
 ------------
index 98cfa3c0d0f27e0cb603f07c76285f85ef07a771..caa07298a6b6c0ea2fe2257cb2c62fcae2e62d46 100644 (file)
@@ -15,6 +15,15 @@ Given one existing commit, revert the change the patch introduces, and record a
 new commit that records it.  This requires your working tree to be clean (no
 modifications from the HEAD commit).
 
+Note: 'git revert' is used to record a new commit to reverse the
+effect of an earlier commit (often a faulty one).  If you want to
+throw away all uncommitted changes in your working directory, you
+should see linkgit:git-reset[1], particularly the '--hard' option.  If
+you want to extract specific files as they were in another commit, you
+should see linkgit:git-checkout[1], specifically the 'git checkout
+<commit> -- <filename>' syntax.  Take care with these alternatives as
+both will discard uncommitted changes in your working directory.
+
 OPTIONS
 -------
 <commit>::
index 4d0c495bc3ecb5482165a46956efe73dfdc5ee72..5afb1e7428126c79171cf7e7b1fb027e1de64c86 100644 (file)
@@ -7,7 +7,7 @@ git-rm - Remove files from the working tree and from the index
 
 SYNOPSIS
 --------
-'git rm' [-f] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] <file>...
+'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch] [--quiet] [--] <file>...
 
 DESCRIPTION
 -----------
@@ -36,6 +36,7 @@ OPTIONS
        but this requires the `-r` option to be explicitly given.
 
 -f::
+--force::
        Override the up-to-date check.
 
 -n::
index e2437f30ca1314dc00a55f72c4e2a325cc75c7b6..3c3e1b0e77abe171ac7531b8098ea2af7d6809dd 100644 (file)
@@ -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.
index 7d50d74cc9a945f0dd82b0c26509bf0392eff837..051f94d26f9f057cbd4db0d6886ca1a4d33c912c 100644 (file)
@@ -8,11 +8,13 @@ git-stash - Stash the changes in a dirty working directory away
 SYNOPSIS
 --------
 [verse]
-'git stash' list
-'git stash' (show | apply | drop | pop ) [<stash>]
+'git stash' list [<options>]
+'git stash' (show | drop | pop ) [<stash>]
+'git stash' apply [--index] [<stash>]
 'git stash' branch <branchname> [<stash>]
-'git stash' [save [<message>]]
+'git stash' [save [--keep-index] [<message>]]
 'git stash' clear
+'git stash' create
 
 DESCRIPTION
 -----------
@@ -116,6 +118,11 @@ pop [<stash>]::
        of the current working tree state. When no `<stash>` is given,
        `stash@\{0}` is assumed. See also `apply`.
 
+create::
+
+       Create a stash (which is a regular commit object) and return its
+       object name, without storing it anywhere in the ref namespace.
+
 
 DISCUSSION
 ----------
@@ -152,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
@@ -167,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
@@ -175,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::
@@ -196,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'
 ----------------------------------------------------------------
index bf33b0cba05e8858e28275661c731aae6c8372ee..babaa9bc46a404c4610abc4e4c4281b6c5c5ea6c 100644 (file)
@@ -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::
index f230125a81baab9f13bf84e3543b63fc77a8e827..1e644ca6dc8c42be81f52243a1af992c9d56f21c 100644 (file)
@@ -13,7 +13,7 @@ DESCRIPTION
 -----------
 'git-svn' is a simple conduit for changesets between Subversion and git.
 It provides a bidirectional flow of changes between a Subversion and a git
-respository.
+repository.
 
 'git-svn' can track a single Subversion branch simply by using a
 URL to the branch, follow branches laid out in the Subversion recommended
@@ -138,6 +138,15 @@ and have no uncommitted changes.
 +
 --no-rebase;;
        After committing, do not rebase or reset.
+--commit-url <URL>;;
+       Commit to this SVN URL (the full path).  This is intended to
+       allow existing git-svn repositories created with one transport
+       method (e.g. `svn://` or `http://` for anonymous read) to be
+       reused if a user is later given access to an alternate transport
+       method (e.g. `svn+ssh://` or `https://`) for commit.
+
+       Using this option for any other purpose (don't ask)
+       is very strongly discouraged.
 --
 
 'log'::
@@ -209,7 +218,7 @@ Any other arguments are passed directly to 'git-log'
        Recursively finds the svn:ignore property on directories and
        creates matching .gitignore files. The resulting files are staged to
        be committed, but are not committed. Use -r/--revision to refer to a
-       specfic revision.
+       specific revision.
 
 'show-ignore'::
        Recursively finds and lists the svn:ignore property on
index 3647dd6c8f9c74a688f7a143119386ba89a8f13d..e2f4c0901bcb4bcc5361e400ff40d70062c77ae6 100644 (file)
@@ -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
 --------
index 36afad8d4e0d67a8d9dd33d3bc590789e9f6604d..7f7a45b2eaa3997cbf5a250fb78387e2a0959a11 100644 (file)
@@ -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.
 
index 44ea35e949dbbc0e5785ba2831072059881058f8..df420aeb331592192ab27d76af780c8c97a95e87 100644 (file)
@@ -43,9 +43,17 @@ unreleased) version of git, that is available from 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v1.5.6.4/git.html[documentation for release 1.5.6.4]
+* 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]
+
+* release notes for
+  link:RelNotes-1.5.6.5.txt[1.5.6.5],
   link:RelNotes-1.5.6.4.txt[1.5.6.4],
   link:RelNotes-1.5.6.3.txt[1.5.6.3],
   link:RelNotes-1.5.6.2.txt[1.5.6.2],
@@ -491,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'
@@ -602,7 +611,7 @@ contributors on the git-list <git@vger.kernel.org>.
 SEE ALSO
 --------
 linkgit:gittutorial[7], linkgit:gittutorial-2[7],
-linkgit:everyday[7], linkgit:gitcvs-migration[7],
+link:everyday.html[Everyday Git], linkgit:gitcvs-migration[7],
 linkgit:gitglossary[7], linkgit:gitcore-tutorial[7],
 linkgit:gitcli[7], link:user-manual.html[The Git User's Manual]
 
index d7b41142d2c843bc5460f03c73c609b1c53ff4a6..6f3551dc825a04628e7bcd133421093d89f01956 100644 (file)
@@ -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::
 
@@ -307,9 +306,24 @@ backslash, and zero or more occurrences of `sub` followed by
 There are a few built-in patterns to make this easier, and `tex`
 is one of them, so you do not have to write the above in your
 configuration file (you still need to enable this with the
-attribute mechanism, via `.gitattributes`).  Another built-in
-pattern is defined for `java` that defines a pattern suitable
-for program text in Java language.
+attribute mechanism, via `.gitattributes`).  The following built in
+patterns are available:
+
+- `bibtex` suitable for files with BibTeX coded references.
+
+- `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.
 
 
 Performing a three-way merge
@@ -473,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
 -------
 
index 49179b0a00fad1ecda1fdf0537ccbce77f5fc494..a417e592ac6a7ed72186dcfc241592ccdc25c9d2 100644 (file)
@@ -1366,8 +1366,9 @@ your login shell is 'bash', only `.bashrc` is read and not
 
 [NOTE]
 If you plan to publish this repository to be accessed over http,
-you should do `chmod +x my-git.git/hooks/post-update` at this
-point.  This makes sure that every time you push into this
+you should do `mv my-git.git/hooks/post-update.sample
+my-git.git/hooks/post-update` at this point.
+This makes sure that every time you push into this
 repository, `git update-server-info` is run.
 
 Your "public repository" is now ready to accept your changes.
@@ -1486,11 +1487,11 @@ A recommended workflow for a "project lead" goes like this:
 If other people are pulling from your repository over dumb
 transport protocols (HTTP), you need to keep this repository
 'dumb transport friendly'.  After `git init`,
-`$GIT_DIR/hooks/post-update` copied from the standard templates
-would contain a call to 'git-update-server-info' but the
-`post-update` hook itself is disabled by default -- enable it
-with `chmod +x post-update`.  This makes sure 'git-update-server-info'
-keeps the necessary files up-to-date.
+`$GIT_DIR/hooks/post-update.sample` copied from the standard templates
+would contain a call to 'git-update-server-info'
+but you need to manually enable the hook with
+`mv post-update.sample post-update`.  This makes sure
+'git-update-server-info' keeps the necessary files up-to-date.
 
 3. Push into the public repository from your primary
    repository.
index 6e827cd11c6d464e1369bf1ca23af0dd53b9be32..ae29a00d591289b0b2534402599fa7a6fe1e3266 100644 (file)
@@ -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
index f8d122a8b90ca7cb4920768ca23fd9a27574ffdf..d1a17e2625890245341a2099cc2b058e63564da2 100644 (file)
@@ -7,7 +7,7 @@ gitmodules - defining submodule properties
 
 SYNOPSIS
 --------
-gitmodules
+$GIT_WORK_DIR/.gitmodules
 
 
 DESCRIPTION
index 48d1454a90cf9453e5e3c9fa01b3dbc369a58f1f..384972cb9bb4a04c55bd8c4796bcd3408e44d5e9 100644 (file)
@@ -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
index fb0d7da56b902217f8f1f4d4bc85186d6bf0dc4c..d2970f8357505f5973989f2e118b812d3d3dde67 100644 (file)
@@ -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
index 48ce747cf4dad592d642735856eb156e93d6cf30..c735788b0f1c8efb0b250d4810be420be6c62f89 100644 (file)
@@ -1,5 +1,5 @@
 merge.stat::
-       Whether to print the diffstat berween 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::
@@ -16,7 +16,7 @@ merge.tool::
        linkgit:git-mergetool[1].  Valid built-in values are: "kdiff3",
        "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and
        "opendiff".  Any other value is treated is custom merge tool
-       and there must be a corresponing mergetool.<tool>.cmd option.
+       and there must be a corresponding mergetool.<tool>.cmd option.
 
 merge.verbosity::
        Controls the amount of output shown by the recursive merge
index c11d4957714db202a012209e2437b9e050a28ae0..388d4925e6bc4bacb708f75437e9aaa216fcb9cc 100644 (file)
@@ -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
index 00a8d210476089257be3d09ac8a16d1f8e1dd8dc..ebdd948cd23931e9bbc35bb304868ce46902e464 100644 (file)
@@ -6,7 +6,7 @@
 
 <refspec>::
        The canonical format of a <refspec> parameter is
-       `+?<src>:<dst>`; that is, an optional plus `+`, followed
+       `+?<src>:<dst>`; that is, an optional plus `{plus}`, followed
        by the source ref, followed by a colon `:`, followed by
        the destination ref.
 +
index ee6822a85df9965901403e99d353fc3c0e1a9eed..0ce916a1887b0846bfc5a6e2233242601e0dde79 100644 (file)
@@ -43,11 +43,13 @@ endif::git-rev-list[]
 
 --parents::
 
-       Print the parents of the commit.
+       Print the parents of the commit.  Also enables parent
+       rewriting, see 'History Simplification' below.
 
 --children::
 
-       Print the children of the commit.
+       Print the children of the commit.  Also enables parent
+       rewriting, see 'History Simplification' below.
 
 ifdef::git-rev-list[]
 --timestamp::
@@ -71,7 +73,7 @@ For example, if you have this topology:
          o---x---a---a  branch A
 -----------------------------------------------------------------------
 +
-you would get an output line this:
+you would get an output like this:
 +
 -----------------------------------------------------------------------
        $ git rev-list --left-right --boundary --pretty=oneline A...B
@@ -94,6 +96,7 @@ you would get an output line this:
 This implies the '--topo-order' option by default, but the
 '--date-order' option may also be specified.
 
+ifndef::git-rev-list[]
 Diff Formatting
 ~~~~~~~~~~~~~~~
 
@@ -123,6 +126,7 @@ options may be given. See linkgit:git-diff-files[1] for more options.
 -t::
 
        Show the tree objects in the diff output. This implies '-r'.
+endif::git-rev-list[]
 
 Commit Limiting
 ~~~~~~~~~~~~~~~
@@ -191,20 +195,6 @@ endif::git-rev-list[]
 
        Stop when a given path disappears from the tree.
 
---full-history::
-
-       Show also parts of history irrelevant to current state of given
-       paths. This turns off history simplification, which removed merges
-       which didn't change anything at all at some child. It will still actually
-       simplify away merges that didn't change anything at all into either
-       child.
-
---simplify-merges::
-
-       Simplify away commits that did not change the given paths, similar
-       to `--full-history`, and further remove merges none of whose
-       parent history changes the given paths.
-
 --no-merges::
 
        Do not print commits with more than one parent.
@@ -270,11 +260,10 @@ With '\--pretty' format other than oneline (for obvious reasons),
 this causes the output to have two extra lines of information
 taken from the reflog.  By default, 'commit@\{Nth}' notation is
 used in the output.  When the starting commit is specified as
-'commit@{now}', output also uses 'commit@\{timestamp}' notation
+'commit@\{now}', output also uses 'commit@\{timestamp}' notation
 instead.  Under '\--pretty=oneline', the commit message is
 prefixed with this information on the same line.
-
-Cannot be combined with '\--reverse'.
+This option cannot be combined with '\--reverse'.
 See also linkgit:git-reflog[1].
 
 --merge::
@@ -287,18 +276,186 @@ See also linkgit:git-reflog[1].
        Output uninteresting commits at the boundary, which are usually
        not shown.
 
+--
+
+History Simplification
+~~~~~~~~~~~~~~~~~~~~~~
+
+When optional paths are given, 'git-rev-list' simplifies commits with
+various strategies, according to the options you have selected.
+
+Suppose you specified `foo` as the <paths>.  We shall call commits
+that modify `foo` !TREESAME, and the rest TREESAME.  (In a diff
+filtered for `foo`, they look different and equal, respectively.)
+
+In the following, we will always refer to the same example history to
+illustrate the differences between simplification settings.  We assume
+that you are filtering for a file `foo` in this commit graph:
+-----------------------------------------------------------------------
+         .-A---M---N---O---P
+        /     /   /   /   /
+       I     B   C   D   E
+        \   /   /   /   /
+         `-------------'
+-----------------------------------------------------------------------
+The horizontal line of history A--P is taken to be the first parent of
+each merge.  The commits are:
+
+* `I` is the initial commit, in which `foo` exists with contents
+  "asdf", and a file `quux` exists with contents "quux".  Initial
+  commits are compared to an empty tree, so `I` is !TREESAME.
+
+* In `A`, `foo` contains just "foo".
+
+* `B` contains the same change as `A`.  Its merge `M` is trivial and
+  hence TREESAME to all parents.
+
+* `C` does not change `foo`, but its merge `N` changes it to "foobar",
+  so it is not TREESAME to any parent.
+
+* `D` sets `foo` to "baz".  Its merge `O` combines the strings from
+  `N` and `D` to "foobarbaz"; i.e., it is not TREESAME to any parent.
+
+* `E` changes `quux` to "xyzzy", and its merge `P` combines the
+  strings to "quux xyzzy".  Despite appearing interesting, `P` is
+  TREESAME to all parents.
+
+'rev-list' walks backwards through history, including or excluding
+commits based on whether '\--full-history' and/or parent rewriting
+(via '\--parents' or '\--children') are used.  The following settings
+are available.
+
+Default mode::
+
+       Commits are included if they are not TREESAME to any parent
+       (though this can be changed, see '\--sparse' below).  If the
+       commit was a merge, and it was TREESAME to one parent, follow
+       only that parent.  (Even if there are several TREESAME
+       parents, follow only one of them.)  Otherwise, follow all
+       parents.
++
+This results in:
++
+-----------------------------------------------------------------------
+         .-A---N---O
+        /         /
+       I---------D
+-----------------------------------------------------------------------
++
+Note how the rule to only follow the TREESAME parent, if one is
+available, removed `B` from consideration entirely.  `C` was
+considered via `N`, but is TREESAME.  Root commits are compared to an
+empty tree, so `I` is !TREESAME.
++
+Parent/child relations are only visible with --parents, but that does
+not affect the commits selected in default mode, so we have shown the
+parent lines.
+
+--full-history without parent rewriting::
+
+       This mode differs from the default in one point: always follow
+       all parents of a merge, even if it is TREESAME to one of them.
+       Even if more than one side of the merge has commits that are
+       included, this does not imply that the merge itself is!  In
+       the example, we get
++
+-----------------------------------------------------------------------
+       I  A  B  N  D  O
+-----------------------------------------------------------------------
++
+`P` and `M` were excluded because they are TREESAME to a parent.  `E`,
+`C` and `B` were all walked, but only `B` was !TREESAME, so the others
+do not appear.
++
+Note that without parent rewriting, it is not really possible to talk
+about the parent/child relationships between the commits, so we show
+them disconnected.
+
+--full-history with parent rewriting::
+
+       Ordinary commits are only included if they are !TREESAME
+       (though this can be changed, see '\--sparse' below).
++
+Merges are always included.  However, their parent list is rewritten:
+Along each parent, prune away commits that are not included
+themselves.  This results in
++
+-----------------------------------------------------------------------
+         .-A---M---N---O---P
+        /     /   /   /   /
+       I     B   /   D   /
+        \   /   /   /   /
+         `-------------'
+-----------------------------------------------------------------------
++
+Compare to '\--full-history' without rewriting above.  Note that `E`
+was pruned away because it is TREESAME, but the parent list of P was
+rewritten to contain `E`'s parent `I`.  The same happened for `C` and
+`N`.  Note also that `P` was included despite being TREESAME.
+
+In addition to the above settings, you can change whether TREESAME
+affects inclusion:
+
 --dense::
+
+       Commits that are walked are included if they are not TREESAME
+       to any parent.
+
 --sparse::
 
-When optional paths are given, the default behaviour ('--dense') is to
-only output commits that changes at least one of them, and also ignore
-merges that do not touch the given paths.
+       All commits that are walked are included.
++
+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::
 
-Use the '--sparse' flag to makes the command output all eligible commits
-(still subject to count and age limitation), but apply merge
-simplification nevertheless.
+       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
+~~~~~~~~~~~~~~~~~
+
 --bisect::
 
 Limit output to the one commit object which is roughly halfway between
@@ -348,7 +505,6 @@ after all the sorted commit objects, there will be the same text as if
 `--bisect-vars` had been used alone.
 endif::git-rev-list[]
 
---
 
 Commit Ordering
 ~~~~~~~~~~~~~~~
index 43f4e392fd01c14de3a1ed90af1de7795869d2b6..08d1310bf5fc5590ada1ee5b2af77d361ff4d874 100644 (file)
@@ -1128,8 +1128,8 @@ This typically includes files generated by a build process or temporary
 backup files made by your editor. Of course, 'not' tracking files with git
 is just a matter of 'not' calling "`git-add`" on them. But it quickly becomes
 annoying to have these untracked files lying around; e.g. they make
-"`git add .`" and "`git commit -a`" practically useless, and they keep
-showing up in the output of "`git status`".
+"`git add .`" practically useless, and they keep showing up in the output of
+"`git status`".
 
 You can tell git to ignore certain files by creating a file called .gitignore
 in the top level of your working directory, with contents such as:
@@ -1890,7 +1890,7 @@ adjustments to give web clients some extra information they need:
 $ mv proj.git /home/you/public_html/proj.git
 $ cd proj.git
 $ git --bare update-server-info
-$ chmod a+x hooks/post-update
+$ mv hooks/post-update.sample hooks/post-update
 -------------------------------------------------
 
 (For an explanation of the last two lines, see
@@ -2825,8 +2825,8 @@ You can also add a "+" to force the update each time:
 $ git config remote.example.fetch +master:ref/remotes/example/master
 -------------------------------------------------
 
-Don't do this unless you're sure you won't mind "git-fetch" possibly
-throwing away commits on mybranch.
+Don't do this unless you're sure you won't mind "git fetch" possibly
+throwing away commits on 'example/master'.
 
 Also note that all of the above configuration can be performed by
 directly editing the file .git/config instead of using
index cb7cd4b53827fa6820e84b1318572d0115b3b17f..6c7465c75865577a87260c7936cb286ab84c6db6 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.5.6.GIT
+DEF_VER=v1.6.0.2.GIT
 
 LF='
 '
@@ -16,6 +16,7 @@ elif test -d .git -o -f .git &&
        case "$VN" in
        *$LF*) (exit 1) ;;
        v[0-9]*)
+               git update-index -q --refresh
                test -z "$(git diff-index --name-only HEAD --)" ||
                VN="$VN-dirty" ;;
        esac
diff --git a/INSTALL b/INSTALL
index 7d0c2c2f865d6ed969038e7543dbeb8933723ec3..a4fd8624bc6550d0553f2271343f4e6b610be103 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -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:
@@ -30,7 +30,7 @@ Issues of note:
    around 1997), it changed its name to gnuit and the name conflict is no
    longer a problem.
 
-   NOTE: When compiled with backward compatiblity option, the GNU
+   NOTE: When compiled with backward compatibility option, the GNU
    Interactive Tools package still can install "git", but you can build it
    with --disable-transition option to avoid this.
 
@@ -73,7 +73,7 @@ Issues of note:
        - "ssh" is used to push and pull over the net
 
        - "perl" and POSIX-compliant shells are needed to use most of
-         the barebone Porcelainish scripts.
+         the bare-bones Porcelainish scripts.
 
  - Some platform specific issues are dealt with Makefile rules,
    but depending on your specific installation, you may not
@@ -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
index 52c67c1a472455dcce5c19a21bbfd0520ff7dd26..3c0664a0734a156859ea204ae4b9b5979620c28c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -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
@@ -1060,9 +1084,11 @@ export TAR INSTALL DESTDIR SHELL_PATH
 
 ### Build rules
 
-all:: $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
+SHELL = $(SHELL_PATH)
+
+all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
 ifneq (,$X)
-       $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), $(RM) '$p';)
+       $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) git$X)), test '$p' -ef '$p$X' || $(RM) '$p';)
 endif
 
 all::
@@ -1073,6 +1099,11 @@ endif
        $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all
        $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1)
 
+please_set_SHELL_PATH_to_a_more_modern_shell:
+       @$$(:)
+
+shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
+
 strip: $(PROGRAMS) git$X
        $(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X
 
@@ -1084,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
 
@@ -1208,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
 
@@ -1216,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
@@ -1241,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
 
@@ -1344,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
@@ -1356,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:
@@ -1380,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
@@ -1434,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*
@@ -1455,6 +1491,7 @@ endif
        $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-GUI-VARS GIT-BUILD-OPTIONS
 
 .PHONY: all install clean strip
+.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
 .PHONY: .FORCE-GIT-VERSION-FILE TAGS tags cscope .FORCE-GIT-CFLAGS
 .PHONY: .FORCE-GIT-BUILD-OPTIONS
 
index b9a53c3416991b66e1d35c2bbf663b48340b0041..3d420845b117b3f3eb82d1f0948a61c7989d8af9 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes-1.6.0.txt
\ No newline at end of file
+Documentation/RelNotes-1.6.1.txt
\ No newline at end of file
index f834b5f51f4cf5d3b73d21dfd99198caef3b19f8..e2280df56723809c5af1d566f0721e2639fff10c 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -3,9 +3,15 @@
 #include "tree-walk.h"
 #include "attr.h"
 #include "archive.h"
-
-static const char archive_usage[] = \
-"git archive --format=<fmt> [--prefix=<prefix>/] [--verbose] [<extra>] <tree-ish> [path...]";
+#include "parse-options.h"
+
+static char const * const archive_usage[] = {
+       "git archive [options] <tree-ish> [path...]",
+       "git archive --list",
+       "git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [path...]",
+       "git archive --remote <repo> [--exec <cmd>] --list",
+       NULL
+};
 
 #define USES_ZLIB_COMPRESSION 1
 
@@ -42,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;
        }
@@ -175,6 +181,9 @@ static const struct archiver *lookup_archiver(const char *name)
 {
        int i;
 
+       if (!name)
+               return NULL;
+
        for (i = 0; i < ARRAY_SIZE(archivers); i++) {
                if (!strcmp(name, archivers[i].name))
                        return &archivers[i];
@@ -232,51 +241,70 @@ static void parse_treeish_arg(const char **argv,
        ar_args->time = archive_time;
 }
 
+#define OPT__COMPR(s, v, h, p) \
+       { OPTION_SET_INT, (s), NULL, (v), NULL, (h), \
+         PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, (p) }
+#define OPT__COMPR_HIDDEN(s, v, p) \
+       { OPTION_SET_INT, (s), NULL, (v), NULL, "", \
+         PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_HIDDEN, NULL, (p) }
+
 static int parse_archive_args(int argc, const char **argv,
                const struct archiver **ar, struct archiver_args *args)
 {
        const char *format = "tar";
-       const char *base = "";
+       const char *base = NULL;
+       const char *remote = NULL;
+       const char *exec = NULL;
        int compression_level = -1;
        int verbose = 0;
        int i;
-
-       for (i = 1; i < argc; i++) {
-               const char *arg = argv[i];
-
-               if (!strcmp(arg, "--list") || !strcmp(arg, "-l")) {
-                       for (i = 0; i < ARRAY_SIZE(archivers); i++)
-                               printf("%s\n", archivers[i].name);
-                       exit(0);
-               }
-               if (!strcmp(arg, "--verbose") || !strcmp(arg, "-v")) {
-                       verbose = 1;
-                       continue;
-               }
-               if (!prefixcmp(arg, "--format=")) {
-                       format = arg + 9;
-                       continue;
-               }
-               if (!prefixcmp(arg, "--prefix=")) {
-                       base = arg + 9;
-                       continue;
-               }
-               if (!strcmp(arg, "--")) {
-                       i++;
-                       break;
-               }
-               if (arg[0] == '-' && isdigit(arg[1]) && arg[2] == '\0') {
-                       compression_level = arg[1] - '0';
-                       continue;
-               }
-               if (arg[0] == '-')
-                       die("Unknown argument: %s", arg);
-               break;
+       int list = 0;
+       struct option opts[] = {
+               OPT_GROUP(""),
+               OPT_STRING(0, "format", &format, "fmt", "archive format"),
+               OPT_STRING(0, "prefix", &base, "prefix",
+                       "prepend prefix to each pathname in the archive"),
+               OPT__VERBOSE(&verbose),
+               OPT__COMPR('0', &compression_level, "store only", 0),
+               OPT__COMPR('1', &compression_level, "compress faster", 1),
+               OPT__COMPR_HIDDEN('2', &compression_level, 2),
+               OPT__COMPR_HIDDEN('3', &compression_level, 3),
+               OPT__COMPR_HIDDEN('4', &compression_level, 4),
+               OPT__COMPR_HIDDEN('5', &compression_level, 5),
+               OPT__COMPR_HIDDEN('6', &compression_level, 6),
+               OPT__COMPR_HIDDEN('7', &compression_level, 7),
+               OPT__COMPR_HIDDEN('8', &compression_level, 8),
+               OPT__COMPR('9', &compression_level, "compress better", 9),
+               OPT_GROUP(""),
+               OPT_BOOLEAN('l', "list", &list,
+                       "list supported archive formats"),
+               OPT_GROUP(""),
+               OPT_STRING(0, "remote", &remote, "repo",
+                       "retrieve the archive from remote repository <repo>"),
+               OPT_STRING(0, "exec", &exec, "cmd",
+                       "path to the remote git-upload-archive command"),
+               OPT_END()
+       };
+
+       argc = parse_options(argc, argv, opts, archive_usage, 0);
+
+       if (remote)
+               die("Unexpected option --remote");
+       if (exec)
+               die("Option --exec can only be used together with --remote");
+
+       if (!base)
+               base = "";
+
+       if (list) {
+               for (i = 0; i < ARRAY_SIZE(archivers); i++)
+                       printf("%s\n", archivers[i].name);
+               exit(0);
        }
 
        /* We need at least one parameter -- tree-ish */
-       if (argc - 1 < i)
-               usage(archive_usage);
+       if (argc < 1)
+               usage_with_options(archive_usage, opts);
        *ar = lookup_archiver(format);
        if (!*ar)
                die("Unknown archive format '%s'", format);
@@ -294,7 +322,7 @@ static int parse_archive_args(int argc, const char **argv,
        args->base = base;
        args->baselen = strlen(base);
 
-       return i;
+       return argc;
 }
 
 int write_archive(int argc, const char **argv, const char *prefix,
@@ -302,13 +330,11 @@ int write_archive(int argc, const char **argv, const char *prefix,
 {
        const struct archiver *ar = NULL;
        struct archiver_args args;
-       int tree_idx;
 
-       tree_idx = parse_archive_args(argc, argv, &ar, &args);
+       argc = parse_archive_args(argc, argv, &ar, &args);
        if (setup_prefix && prefix == NULL)
                prefix = setup_git_directory();
 
-       argv += tree_idx;
        parse_treeish_arg(argv, &args, prefix);
        parse_pathspec_arg(argv + 1, &args);
 
index fc3f96eaefff91e4e85adb92162716939f0ecd72..7c874e31154a4c3f96b3403db1bdcb0b36fdec3e 100644 (file)
@@ -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);
index 2216a0bf7cd53adc31346f66a3b9786a1d688bad..20bef1f21d393b0ddf36b8336af85a70c9b8c39c 100644 (file)
@@ -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.
index 22445acbfc5279f391ac6afa855b21064ec54535..5ceec433fd590e8bf6a51700ea69c37f9af30fa7 100644 (file)
@@ -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);
index 4ea343189fdad035318e94ce0c6c2ec16b62ba7f..6b7b9f4466989ca02d3a5e53caac9ff5c7e8a922 100644 (file)
@@ -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);
index ac476e7a4b45fc55b6b6d1e4d02be0c35aba2c7b..9b58152047baebfdd6f26ffab31d49347e0cb069 100644 (file)
@@ -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)
 {
index 7441a56acdbefdd8044a406f4d756ce8a4f06644..3fba6b9e743545868368a0e554466fca3814316a 100644 (file)
@@ -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;
index fe04be77a9312c11fa054897c5982fa6c74b8e5e..701de439ae0f508f3a8ab41559230357be60637e 100644 (file)
@@ -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]);
 }
index 71ebabf9903bd90b7da59c47f1c0819b5f25c538..55b7aafe06680fa51729ddb7fa97f9cd319a470e 100644 (file)
@@ -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);
index 411cc513c65ba854221ad52dd6aeaaac7d213c9d..9377a1c71ea8571d3e36e9e19aa322db765e93c8 100644 (file)
@@ -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;
 };
@@ -242,6 +269,8 @@ static int merge_working_tree(struct checkout_opts *opts,
                }
 
                /* 2-way merge to the new branch */
+               topts.initial_checkout = (!active_nr &&
+                                         (old->commit == new->commit));
                topts.update = 1;
                topts.merge = 1;
                topts.gently = opts->merge;
@@ -386,13 +415,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 +464,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");
index e086a40b41810c30a4f5228daa4e38857dae84d5..c8435295cedd920f34a13ec686c73d6b835b28ee 100644 (file)
@@ -33,7 +33,7 @@ static const char * const builtin_clone_usage[] = {
        NULL
 };
 
-static int option_quiet, option_no_checkout, option_bare;
+static int option_quiet, option_no_checkout, option_bare, option_mirror;
 static int option_local, option_no_hardlinks, option_shared;
 static char *option_template, *option_reference, *option_depth;
 static char *option_origin = NULL;
@@ -45,6 +45,8 @@ static struct option builtin_clone_options[] = {
                    "don't create a checkout"),
        OPT_BOOLEAN(0, "bare", &option_bare, "create a bare repository"),
        OPT_BOOLEAN(0, "naked", &option_bare, "create a bare repository"),
+       OPT_BOOLEAN(0, "mirror", &option_mirror,
+                   "create a mirror repository (implies bare)"),
        OPT_BOOLEAN('l', "local", &option_local,
                    "to clone from a local repository"),
        OPT_BOOLEAN(0, "no-hardlinks", &option_no_hardlinks,
@@ -93,7 +95,7 @@ static char *get_repo_path(const char *repo, int *is_bundle)
        return NULL;
 }
 
-static char *guess_dir_name(const char *repo, int is_bundle)
+static char *guess_dir_name(const char *repo, int is_bundle, int is_bare)
 {
        const char *end = repo + strlen(repo), *start;
 
@@ -129,6 +131,12 @@ static char *guess_dir_name(const char *repo, int is_bundle)
                        end -= 4;
        }
 
+       if (is_bare) {
+               char *result = xmalloc(end - start + 5);
+               sprintf(result, "%.*s.git", (int)(end - start), start);
+               return result;
+       }
+
        return xstrndup(start, end - start);
 }
 
@@ -139,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;
@@ -322,7 +339,8 @@ static struct ref *write_remote_refs(const struct ref *refs,
        struct ref *r;
 
        get_fetch_map(refs, refspec, &tail, 0);
-       get_fetch_map(refs, tag_refspec, &tail, 0);
+       if (!option_mirror)
+               get_fetch_map(refs, tag_refspec, &tail, 0);
 
        for (r = local_refs; r; r = r->next)
                add_extra_ref(r->peer_ref->name, r->old_sha1, 0);
@@ -345,6 +363,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        char branch_top[256], key[256], value[256];
        struct strbuf reflog_msg;
        struct transport *transport = NULL;
+       char *src_ref_prefix = "refs/heads/";
 
        struct refspec refspec;
 
@@ -359,6 +378,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        if (option_no_hardlinks)
                use_local_hardlinks = 0;
 
+       if (option_mirror)
+               option_bare = 1;
+
        if (option_bare) {
                if (option_origin)
                        die("--bare and --origin %s options are incompatible.",
@@ -374,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
@@ -383,7 +405,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        if (argc == 2)
                dir = xstrdup(argv[1]);
        else
-               dir = guess_dir_name(repo_name, is_bundle);
+               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);
@@ -409,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;
@@ -440,26 +464,36 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        git_config(git_default_config, NULL);
 
        if (option_bare) {
-               strcpy(branch_top, "refs/heads/");
+               if (option_mirror)
+                       src_ref_prefix = "refs/";
+               strcpy(branch_top, src_ref_prefix);
 
                git_config_set("core.bare", "true");
        } else {
                snprintf(branch_top, sizeof(branch_top),
                         "refs/remotes/%s/", option_origin);
+       }
 
+       if (option_mirror || !option_bare) {
                /* Configure the remote */
+               if (option_mirror) {
+                       snprintf(key, sizeof(key),
+                                       "remote.%s.mirror", option_origin);
+                       git_config_set(key, "true");
+               }
+
                snprintf(key, sizeof(key), "remote.%s.url", option_origin);
                git_config_set(key, repo);
 
                snprintf(key, sizeof(key), "remote.%s.fetch", option_origin);
                snprintf(value, sizeof(value),
-                               "+refs/heads/*:%s*", branch_top);
+                               "+%s*:%s*", src_ref_prefix, branch_top);
                git_config_set_multivar(key, value, "^$", 0);
        }
 
        refspec.force = 0;
        refspec.pattern = 1;
-       refspec.src = "refs/heads/";
+       refspec.src = src_ref_prefix;
        refspec.dst = branch_top;
 
        if (path && !is_bundle)
index 7a9a309be0543da7d27e7710ef82271f2582e0a9..f2684bb75e2319f2797bfe626e15bc27bd76f21a 100644 (file)
@@ -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));
index b783e6eb46d2603d61d3260420c5dff48913d182..8165bb3d31c6cdd92c83663c5dd081e564dcfc1e 100644 (file)
@@ -46,7 +46,7 @@ static enum {
        COMMIT_PARTIAL,
 } commit_style;
 
-static char *logfile, *force_author;
+static const char *logfile, *force_author;
 static const char *template_file;
 static char *edit_message, *use_message;
 static char *author_name, *author_email, *author_date;
@@ -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,12 +710,43 @@ 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 * const usage[],
+                                     const char *prefix)
 {
        int f = 0;
 
        argc = parse_options(argc, argv, builtin_commit_options, usage, 0);
+       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;
@@ -836,7 +867,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
        if (wt_status_use_color == -1)
                wt_status_use_color = git_use_color_default;
 
-       argc = parse_and_validate_options(argc, argv, builtin_status_usage);
+       argc = parse_and_validate_options(argc, argv, builtin_status_usage, prefix);
 
        index_file = prepare_index(argc, argv, prefix);
 
@@ -879,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);
        }
@@ -929,7 +960,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 
        git_config(git_commit_config, NULL);
 
-       argc = parse_and_validate_options(argc, argv, builtin_commit_usage);
+       argc = parse_and_validate_options(argc, argv, builtin_commit_usage, prefix);
 
        index_file = prepare_index(argc, argv, prefix);
 
index 91b5487478998e39bb8ae4a5cb667360cff82c9a..ab35b65b073e9bc089fcc96f295ca3bc457c992a 100644 (file)
@@ -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;
 }
index 17d851b29ee5de33e01745eabcd5cd735c30b352..04837494feba401c7f689eab5574768d3fd126de 100644 (file)
@@ -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;
index 415cb1612f5322da89850874ba81885e41808678..8ecefd4f0f99117534deb9ca7d4446ade5c00223 100644 (file)
@@ -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"
index 7ffea975059f9e13b07ca680e6707ffc14973f90..037c3039a43d198f228fbc64e46d85d4170c1329 100644 (file)
@@ -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;
index 070971616dbb12d005c5c9a1f82cc5b0c5391f62..7c93eb878d7da87b39959fb9599e4b7b6b81570b 100644 (file)
@@ -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++;
        }
index 273239af3be61736ee4ff484d628950c4de7311a..4dfef29bcd23a174593203e521247a3d4209cf89 100644 (file)
@@ -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++)
index 7eec4a0e43ad5760f1060a7d5bcf2a5083015130..ee93d3a93da0267caa485fa552c29d779aecfdf7 100644 (file)
@@ -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
index 445039e19c75e4c9321f7ee64289ef8201a25c14..21e92bbcb577c0361df51bd81e6fb5ab546619ea 100644 (file)
@@ -459,8 +459,10 @@ static void find_subpos(const char *buf, unsigned long sz, const char **sub, con
                return;
        *sub = buf; /* first non-empty line */
        buf = strchr(buf, '\n');
-       if (!buf)
+       if (!buf) {
+               *body = "";
                return; /* no body */
+       }
        while (*buf == '\n')
                buf++; /* skip blank between subject and body */
        *body = buf;
@@ -650,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;
index 6eb7da88d3e8591a8c544acc61a42e00babff120..d3f3de9446a9184e9457fe4b743c4e43a9256597 100644 (file)
@@ -385,7 +385,7 @@ static void fsck_dir(int i, char *path)
                        add_sha1_list(sha1, DIRENT_SORT_HINT(de));
                        continue;
                }
-               if (prefixcmp(de->d_name, "tmp_obj_"))
+               if (!prefixcmp(de->d_name, "tmp_obj_"))
                        continue;
                fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
        }
index 631129ddfd0ffe06f919882d22cfc494d9553f50..3a51662a35878ae6b5965c90abb747b5b27c5493 100644 (file)
@@ -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 (file)
index 0000000..64207cb
--- /dev/null
@@ -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;
+}
index 3a062487a7eacd01ed824b46a9124dd343cd2e60..f3e63d7206604029504aaf85b3d2e7731d054d2c 100644 (file)
@@ -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);
index baf0d09ac4ea372b4015d399560a133b401b55cc..8140c1299afe368266de1153f3bb891f000fe5f5 100644 (file)
@@ -37,7 +37,7 @@ static void copy_templates_1(char *path, int baselen,
 
        /* Note: if ".git/hooks" file exists in the repository being
         * re-initialized, /etc/core-git/templates/hooks/update would
-        * cause git-init to fail here.  I think this is sane but
+        * cause "git init" to fail here.  I think this is sane but
         * it means that the set of templates we ship by default, along
         * with the way the namespace under .git/ is organized, should
         * be really carefully chosen.
index f4975cf35f7f1555739f7657ee62ed983d18cb84..1d3c5cbf580f3989d9605ed68f80beb050e19d39 100644 (file)
@@ -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)
@@ -461,7 +470,7 @@ static int extra_cc_alloc;
 static void add_header(const char *value)
 {
        int len = strlen(value);
-       while (value[len - 1] == '\n')
+       while (len && value[len - 1] == '\n')
                len--;
        if (!strncasecmp(value, "to: ", 4)) {
                ALLOC_GROW(extra_to, extra_to_nr + 1, extra_to_alloc);
@@ -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)
index e8d568eed7ab700bc338af8f589d2f61e81f323c..068f424696864f3db1c1b78ef25a92a197ff5474 100644 (file)
@@ -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;
index d25767a1f7eb0a8b45bc1eed6b9aa95de0847f18..cb61717685b09a2e409440206e27fce68831e04d 100644 (file)
@@ -66,17 +66,16 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
                /*
                 * Maybe we want to have some recursive version here?
                 *
-                * Something like:
+                * Something similar to this incomplete example:
                 *
                if (show_subprojects(base, baselen, pathname)) {
-                       if (fork()) {
-                               chdir(base);
-                               exec ls-tree;
-                       }
-                       waitpid();
+                       struct child_process ls_tree;
+
+                       ls_tree.dir = base;
+                       ls_tree.argv = ls-tree;
+                       start_command(&ls_tree);
                }
                 *
-                * ..or similar..
                 */
                type = commit_type;
        } else if (S_ISDIR(mode)) {
index f974b9df968c74c5d62d58b2a09493e6abb4322e..e890f7a6d1ff7248aed4f03ebbcdfafd7e472dad 100644 (file)
@@ -107,7 +107,7 @@ static void handle_from(const struct strbuf *from)
        el = strcspn(at, " \n\t\r\v\f>");
        strbuf_reset(&email);
        strbuf_add(&email, at, el);
-       strbuf_remove(&f, at - f.buf, el + 1);
+       strbuf_remove(&f, at - f.buf, el + (at[el] ? 1 : 0));
 
        /* The remainder is name.  It could be "John Doe <john.doe@xz>"
         * or "john.doe@xz (John Doe)", but we have removed the
@@ -175,7 +175,7 @@ static void handle_content_type(struct strbuf *line)
                 message_type = TYPE_OTHER;
        if (slurp_attr(line->buf, "boundary=", boundary)) {
                strbuf_insert(boundary, 0, "--", 2);
-               if (content_top++ >= &content[MAX_BOUNDARIES]) {
+               if (++content_top > &content[MAX_BOUNDARIES]) {
                        fprintf(stderr, "Too many boundaries to handle\n");
                        exit(1);
                }
@@ -203,7 +203,8 @@ static void handle_content_transfer_encoding(const struct strbuf *line)
 
 static int is_multipart_boundary(const struct strbuf *line)
 {
-       return !strbuf_cmp(line, *content_top);
+       return (((*content_top)->len <= line->len) &&
+               !memcmp(line->buf, (*content_top)->buf, (*content_top)->len));
 }
 
 static void cleanup_subject(struct strbuf *subject)
@@ -602,7 +603,7 @@ static void handle_filter(struct strbuf *line);
 static int find_boundary(void)
 {
        while (!strbuf_getline(&line, fin, '\n')) {
-               if (is_multipart_boundary(&line))
+               if (*content_top && is_multipart_boundary(&line))
                        return 1;
        }
        return 0;
@@ -625,7 +626,7 @@ static int handle_boundary(void)
                /* technically won't happen as is_multipart_boundary()
                   will fail first.  But just in case..
                 */
-               if (content_top-- < content) {
+               if (--content_top < content) {
                        fprintf(stderr, "Detected mismatched boundaries, "
                                        "can't recover\n");
                        exit(1);
@@ -649,8 +650,11 @@ static int handle_boundary(void)
                check_header(&line, p_hdr_data, 0);
 
        strbuf_release(&newline);
-       /* eat the blank line after section info */
-       return (strbuf_getline(&line, fin, '\n') == 0);
+       /* replenish line */
+       if (strbuf_getline(&line, fin, '\n'))
+               return 0;
+       strbuf_addch(&line, '\n');
+       return 1;
 }
 
 static inline int patchbreak(const struct strbuf *line)
@@ -757,9 +761,10 @@ static void handle_body(void)
                /* process any boundary lines */
                if (*content_top && is_multipart_boundary(&line)) {
                        /* flush any leftover */
-                       if (line.len)
-                               handle_filter(&line);
-
+                       if (prev.len) {
+                               handle_filter(&prev);
+                               strbuf_reset(&prev);
+                       }
                        if (!handle_boundary())
                                goto handle_body_out;
                }
index 3382b1382a7dcbd525126a35209072da4b4d8041..b08da516e491e7089b1bb178e9a4b05c2ab36539 100644 (file)
@@ -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);
 }
index 43e55bf90154c51b94527b2ab7eb7c60fe36e9ec..dfb363ee2f2e5764264722171de17a9a57556dd8 100644 (file)
@@ -729,13 +729,13 @@ static void conflict_rename_rename(struct rename *ren1,
        const char *dst_name2 = ren2_dst;
        if (string_list_has_string(&current_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(&current_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(&current_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;
index dde0c7ed33118ff8d0cc421e8a0366e342c6d011..9ad9791068c9330f28413ac67315246989c8d96d 100644 (file)
@@ -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(&not_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(&not_strategies, ent->name, ent->len);
+                       exclude_cmds(&main_cmds, &not_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,7 @@ 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);
 
@@ -650,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;
@@ -742,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");
 
@@ -775,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.");
 
        /*
@@ -832,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]);
@@ -936,7 +977,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                        hex,
                        find_unique_abbrev(remoteheads->item->object.sha1,
                        DEFAULT_ABBREV));
-               refresh_cache(REFRESH_QUIET);
                strbuf_init(&msg, 0);
                strbuf_addstr(&msg, "Fast forward");
                if (have_message)
@@ -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;
index 85612c4dcb719b460623204046e35486e9d9fe97..08c8aabf9428447abad7def693d7b22c5330e180 100644 (file)
@@ -176,6 +176,48 @@ static char const * const name_rev_usage[] = {
        NULL
 };
 
+static void name_rev_line(char *p, struct name_ref_data *data)
+{
+       int forty = 0;
+       char *p_start;
+       for (p_start = p; *p; p++) {
+#define ishex(x) (isdigit((x)) || ((x) >= 'a' && (x) <= 'f'))
+               if (!ishex(*p))
+                       forty = 0;
+               else if (++forty == 40 &&
+                        !ishex(*(p+1))) {
+                       unsigned char sha1[40];
+                       const char *name = NULL;
+                       char c = *(p+1);
+                       int p_len = p - p_start + 1;
+
+                       forty = 0;
+
+                       *(p+1) = 0;
+                       if (!get_sha1(p - 39, sha1)) {
+                               struct object *o =
+                                       lookup_object(sha1);
+                               if (o)
+                                       name = get_rev_name(o);
+                       }
+                       *(p+1) = c;
+
+                       if (!name)
+                               continue;
+
+                       if (data->name_only)
+                               printf("%.*s%s", p_len - 40, p_start, name);
+                       else
+                               printf("%.*s (%s)", p_len, p_start, name);
+                       p_start = p + 1;
+               }
+       }
+
+       /* flush */
+       if (p_start != p)
+               fwrite(p_start, p - p_start, 1, stdout);
+}
+
 int cmd_name_rev(int argc, const char **argv, const char *prefix)
 {
        struct object_array revs = { 0, 0, NULL };
@@ -234,47 +276,12 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
 
        if (transform_stdin) {
                char buffer[2048];
-               char *p, *p_start;
 
                while (!feof(stdin)) {
-                       int forty = 0;
-                       p = fgets(buffer, sizeof(buffer), stdin);
+                       char *p = fgets(buffer, sizeof(buffer), stdin);
                        if (!p)
                                break;
-
-                       for (p_start = p; *p; p++) {
-#define ishex(x) (isdigit((x)) || ((x) >= 'a' && (x) <= 'f'))
-                               if (!ishex(*p))
-                                       forty = 0;
-                               else if (++forty == 40 &&
-                                               !ishex(*(p+1))) {
-                                       unsigned char sha1[40];
-                                       const char *name = NULL;
-                                       char c = *(p+1);
-
-                                       forty = 0;
-
-                                       *(p+1) = 0;
-                                       if (!get_sha1(p - 39, sha1)) {
-                                               struct object *o =
-                                                       lookup_object(sha1);
-                                               if (o)
-                                                       name = get_rev_name(o);
-                                       }
-                                       *(p+1) = c;
-
-                                       if (!name)
-                                               continue;
-
-                                       fwrite(p_start, p - p_start + 1, 1, stdout);
-                                       printf(" (%s)", name);
-                                       p_start = p + 1;
-                               }
-                       }
-
-                       /* flush */
-                       if (p_start != p)
-                               fwrite(p_start, p - p_start, 1, stdout);
+                       name_rev_line(p, &data);
                }
        } else if (all) {
                int i, max;
index 2dadec1630c266bbaf42e84810f7059ed5c43b1e..217fd49da9ad98e660e6522024793ae3a357e837 100644 (file)
@@ -23,7 +23,7 @@
 #endif
 
 static const char pack_usage[] = "\
-git-pack-objects [{ -q | --progress | --all-progress }] \n\
+git pack-objects [{ -q | --progress | --all-progress }] \n\
        [--max-pack-size=N] [--local] [--incremental] \n\
        [--window=N] [--window-memory=N] [--depth=N] \n\
        [--no-reuse-delta] [--no-reuse-object] [--delta-base-offset] \n\
@@ -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;
        }
@@ -1870,7 +1872,7 @@ static void mark_in_pack_object(struct object *object, struct packed_git *p, str
 
 /*
  * Compare the objects in the offset order, in order to emulate the
- * "git-rev-list --objects" output that produced the pack originally.
+ * "git rev-list --objects" output that produced the pack originally.
  */
 static int ofscmp(const void *a_, const void *b_)
 {
index 947de8cf258c73d8a327ef3a1daed417ba533f1b..c767a0ac8930166315c26d8ece2e72b4f1942d55 100644 (file)
@@ -69,11 +69,6 @@ static int prune_dir(int i, char *path)
                        if (de->d_name[0] != '.')
                                break;
                        continue;
-               case 14:
-                       if (prefixcmp(de->d_name, "tmp_obj_"))
-                               break;
-                       prune_tmp_object(path, de->d_name);
-                       continue;
                case 38:
                        sprintf(name, "%02x", i);
                        memcpy(name+2, de->d_name, len+1);
@@ -90,6 +85,10 @@ static int prune_dir(int i, char *path)
                        prune_object(path, de->d_name, sha1);
                        continue;
                }
+               if (!prefixcmp(de->d_name, "tmp_obj_")) {
+                       prune_tmp_object(path, de->d_name);
+                       continue;
+               }
                fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
        }
        if (!show_only)
index c1ed68d938f67343c6938cfef54d5ff69a522a63..cc6666f75e7db8a546d4a1589335589190e414fe 100644 (file)
@@ -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)) {
index 72a6de302f88728af17ce5c5c6983c5267afc6f6..0706c958181c54aeb18d91f6e3dbe7c9f572b94d 100644 (file)
@@ -64,7 +64,7 @@ static void prime_cache_tree(void)
 
 }
 
-static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <sha1> [<sha2> [<sha3>]])";
+static const char read_tree_usage[] = "git read-tree (<sha> | [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <sha1> [<sha2> [<sha3>]])";
 
 static struct lock_file lock_file;
 
@@ -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)
@@ -204,6 +206,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
                        break;
                case 2:
                        opts.fn = twoway_merge;
+                       opts.initial_checkout = !active_nr;
                        break;
                case 3:
                default:
index 0c34e378199064e87aa09caf0fa0a2346333ec69..6b3667ef0ebdfc2b8b70b24e474b22989fbf0cb7 100644 (file)
@@ -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);
@@ -604,8 +604,8 @@ static int cmd_reflog_delete(int argc, const char **argv, const char *prefix)
                        continue;
                }
 
-               if (!dwim_ref(argv[i], spec - argv[i], sha1, &ref)) {
-                       status |= error("%s points nowhere!", argv[i]);
+               if (!dwim_log(argv[i], spec - argv[i], sha1, &ref)) {
+                       status |= error("no reflog for '%s'", argv[i]);
                        continue;
                }
 
index 54d1c3e3d16b2cebcff0c6c57d98756e48472b67..01945a8651c9a42f19fba850036ed2a1339675f1 100644 (file)
@@ -115,7 +115,7 @@ static int add(int argc, const char **argv)
        if (mirror) {
                strbuf_reset(&buf);
                strbuf_addf(&buf, "remote.%s.mirror", name);
-               if (git_config_set(buf.buf, "yes"))
+               if (git_config_set(buf.buf, "true"))
                        return 1;
        }
 
index 893762c80f4910fadf2d6df414bd835cccb7faaa..facaff288dba2789f0637c4554bd130440e2a3da 100644 (file)
@@ -178,7 +178,7 @@ static void finish_object(struct object_array_entry *p)
 static void show_object(struct object_array_entry *p)
 {
        /* An object with name "foo\n0000000..." can be used to
-        * confuse downstream git-pack-objects very badly.
+        * confuse downstream "git pack-objects" very badly.
         */
        const char *ep = strchr(p->name, '\n');
 
@@ -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;
 
index 27881e94937dd79b9a0524eb2d9770427ec4f4fb..36677053f87b107f658f1472369755c4fe957a46 100644 (file)
@@ -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)
index ee8247b08cd007f73d5dfffa560a9efe33d327b9..fdac34f2423409add48706497fa01010219baf72 100644 (file)
@@ -104,7 +104,7 @@ static int check_local_mod(unsigned char *head, int index_only)
                                     "from both the file and the HEAD\n"
                                     "(use -f to force removal)", name);
                else if (!index_only) {
-                       /* It's not dangerous to git-rm --cached a
+                       /* It's not dangerous to "git rm --cached" a
                         * file if the index matches the file or the
                         * HEAD, since it means the deleted content is
                         * still available somewhere.
@@ -131,7 +131,7 @@ static struct option builtin_rm_options[] = {
        OPT__DRY_RUN(&show_only),
        OPT__QUIET(&quiet),
        OPT_BOOLEAN( 0 , "cached",         &index_only, "only remove from the index"),
-       OPT_BOOLEAN('f', NULL,             &force,      "override the up-to-date check"),
+       OPT_BOOLEAN('f', "force",          &force,      "override the up-to-date check"),
        OPT_BOOLEAN('r', NULL,             &recursive,  "allow recursive removal"),
        OPT_BOOLEAN( 0 , "ignore-unmatch", &ignore_unmatch,
                                "exit with a zero status even if nothing matched"),
@@ -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));
                }
        }
 
index 7588d22885d0af24ae80f1d687ccd097fe365021..2af9f2934142f55858f4b5c76deb6397ac74b9f8 100644 (file)
@@ -43,7 +43,7 @@ static int pack_objects(int fd, struct ref *refs)
        po.out = fd;
        po.git_cmd = 1;
        if (start_command(&po))
-               die("git-pack-objects failed (%s)", strerror(errno));
+               die("git pack-objects failed (%s)", strerror(errno));
 
        /*
         * We feed the pack-objects we just spawned with revision
index add16004f11375b1ad2b97f9b1bf1ced5c437f81..572b114119db15f5f42dd79e3bc15e6d219f71db 100644 (file)
@@ -62,7 +62,7 @@ static int show_ref(const char *refname, const unsigned char *sha1, int flag, vo
         * 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 @@ static int show_ref(const char *refname, const unsigned char *sha1, int flag, vo
        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);
index 325b1b2632e44121c23bc6df556bf3aa4e32ba04..f2853d08c77368b37b40c7ea51f5a124208d385f 100644 (file)
@@ -346,7 +346,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 
        int annotate = 0, sign = 0, force = 0, lines = 0,
                list = 0, delete = 0, verify = 0;
-       char *msgfile = NULL, *keyid = NULL;
+       const char *msgfile = NULL, *keyid = NULL;
        struct msg_arg msg = { 0, STRBUF_INIT };
        struct option options[] = {
                OPT_BOOLEAN('l', NULL, &list, "list tag names"),
@@ -372,6 +372,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        git_config(git_tag_config, NULL);
 
        argc = parse_options(argc, argv, options, git_tag_usage, 0);
+       msgfile = parse_options_fix_filename(prefix, msgfile);
 
        if (keyid) {
                sign = 1;
index f4bea4a322c26a54734286073c5e67444555c2d9..0713bca778e7be18b58ec5d207dc7c8cd7e982ed 100644 (file)
@@ -9,26 +9,26 @@
 
 static const char tar_tree_usage[] =
 "git tar-tree [--remote=<repo>] <tree-ish> [basedir]\n"
-"*** Note that this command is now deprecated; use git-archive instead.";
+"*** Note that this command is now deprecated; use \"git archive\" instead.";
 
 int cmd_tar_tree(int argc, const char **argv, const char *prefix)
 {
        /*
-        * git-tar-tree is now a wrapper around git-archive --format=tar
+        * "git tar-tree" is now a wrapper around "git archive --format=tar"
         *
         * $0 --remote=<repo> arg... ==>
-        *      git-archive --format=tar --remote=<repo> arg...
+        *      git archive --format=tar --remote=<repo> arg...
         * $0 tree-ish ==>
-        *      git-archive --format=tar tree-ish
+        *      git archive --format=tar tree-ish
         * $0 tree-ish basedir ==>
-        *      git-archive --format-tar --prefix=basedir tree-ish
+        *      git archive --format-tar --prefix=basedir tree-ish
         */
        int i;
        const char **nargv = xcalloc(sizeof(*nargv), argc + 2);
        char *basedir_arg;
        int nargc = 0;
 
-       nargv[nargc++] = "git-archive";
+       nargv[nargc++] = "archive";
        nargv[nargc++] = "--format=tar";
 
        if (2 <= argc && !prefixcmp(argv[1], "--remote=")) {
@@ -53,8 +53,8 @@ int cmd_tar_tree(int argc, const char **argv, const char *prefix)
        nargv[nargc] = NULL;
 
        fprintf(stderr,
-               "*** git-tar-tree is now deprecated.\n"
-               "*** Running git-archive instead.\n***");
+               "*** \"git tar-tree\" is now deprecated.\n"
+               "*** Running \"git archive\" instead.\n***");
        for (i = 0; i < nargc; i++) {
                fputc(' ', stderr);
                sq_quote_print(stderr, nargv[i]);
@@ -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;
 }
index a8918666655bb91f952ccdac18715bd9ba4a09f2..40b20f26e86acca2ee37b34519e84a1ce79689c3 100644 (file)
@@ -13,7 +13,7 @@
 #include "fsck.h"
 
 static int dry_run, quiet, recover, has_errors, strict;
-static const char unpack_usage[] = "git-unpack-objects [-n] [-q] [-r] [--strict] < pack-file";
+static const char unpack_usage[] = "git unpack-objects [-n] [-q] [-r] [--strict] < pack-file";
 
 /* We always read in 4kB chunks. */
 static unsigned char buffer[4096];
index 38eb53ccba2b97a0fccf50d6ba0b7424fe2d1bcb..417f9724abdce3c49df316505eff1019126a5058 100644 (file)
@@ -14,7 +14,7 @@
  * Default to not allowing changes to the list of files. The
  * tool doesn't actually care, but this makes it harder to add
  * files to the revision control by mistake by doing something
- * like "git-update-index *" and suddenly having all the object
+ * like "git update-index *" and suddenly having all the object
  * files be revision controlled.
  */
 static int allow_add;
@@ -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;
        }
@@ -310,18 +313,18 @@ static void read_index_info(int line_termination)
                /* This reads lines formatted in one of three formats:
                 *
                 * (1) mode         SP sha1          TAB path
-                * The first format is what "git-apply --index-info"
+                * The first format is what "git apply --index-info"
                 * reports, and used to reconstruct a partial tree
                 * that is used for phony merge base tree when falling
                 * back on 3-way merge.
                 *
                 * (2) mode SP type SP sha1          TAB path
-                * The second format is to stuff git-ls-tree output
+                * The second format is to stuff "git ls-tree" output
                 * into the index file.
                 *
                 * (3) mode         SP sha1 SP stage TAB path
                 * This format is to put higher order stages into the
-                * index file and matches git-ls-files --stage output.
+                * index file and matches "git ls-files --stage" output.
                 */
                errno = 0;
                ul = strtoul(buf.buf, &ptr, 8);
@@ -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] == '"') {
index f4ac595695b1fff1317ff7d14ea9427780327aea..25a29f11a4b9642c1bd367b81779d8f09ae04604 100644 (file)
@@ -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++;
index f3502d305e4f65e9707fe8b738f64be6e49f7f84..e67cb2090e8c111be4b137939953f3e006f31dfd 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -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,
diff --git a/cache.h b/cache.h
index 2475de9fa837596303284157e08b3080d64351ee..de8c2b6266ee96d0958cb2c1430b2b2da99f1e86 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -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,
index 9f80a1c5e3a461afd11966625589684d61187911..dcb90b1701aab6f2e22a0953067d85dcf734d6d2 100644 (file)
@@ -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:
index 77de9621d9c926c6fb8a2bf9ca81c6c376a2ad41..de15f4d715ded4d8fd4f882b44fd9a320e7cdb2e 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -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.c
deleted file mode 100644 (file)
index 1f4ead5..0000000
+++ /dev/null
@@ -1,488 +0,0 @@
-/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with this library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-#if HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-/* Enable GNU extensions in fnmatch.h.  */
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE   1
-#endif
-
-#include <errno.h>
-#include <fnmatch.h>
-#include <ctype.h>
-
-#if HAVE_STRING_H || defined _LIBC
-# include <string.h>
-#else
-# include <strings.h>
-#endif
-
-#if defined STDC_HEADERS || defined _LIBC
-# include <stdlib.h>
-#endif
-
-/* For platform which support the ISO C amendement 1 functionality we
-   support user defined character classes.  */
-#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
-/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>.  */
-# include <wchar.h>
-# include <wctype.h>
-#endif
-
-/* Comment out all this code if we are using the GNU C Library, and are not
-   actually compiling the library itself.  This code is part of the GNU C
-   Library, but also included in many other GNU distributions.  Compiling
-   and linking in this code is a waste when using the GNU C library
-   (especially if it is a shared library).  Rather than having every GNU
-   program understand `configure --with-gnu-libc' and omit the object files,
-   it is simpler to just do this in the source for each such file.  */
-
-#if defined _LIBC || !defined __GNU_LIBRARY__
-
-
-# if defined STDC_HEADERS || !defined isascii
-#  define ISASCII(c) 1
-# else
-#  define ISASCII(c) isascii(c)
-# endif
-
-# ifdef isblank
-#  define ISBLANK(c) (ISASCII (c) && isblank (c))
-# else
-#  define ISBLANK(c) ((c) == ' ' || (c) == '\t')
-# endif
-# ifdef isgraph
-#  define ISGRAPH(c) (ISASCII (c) && isgraph (c))
-# else
-#  define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
-# endif
-
-# define ISPRINT(c) (ISASCII (c) && isprint (c))
-# define ISDIGIT(c) (ISASCII (c) && isdigit (c))
-# define ISALNUM(c) (ISASCII (c) && isalnum (c))
-# define ISALPHA(c) (ISASCII (c) && isalpha (c))
-# define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
-# define ISLOWER(c) (ISASCII (c) && islower (c))
-# define ISPUNCT(c) (ISASCII (c) && ispunct (c))
-# define ISSPACE(c) (ISASCII (c) && isspace (c))
-# define ISUPPER(c) (ISASCII (c) && isupper (c))
-# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
-
-# define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
-
-# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
-/* The GNU C library provides support for user-defined character classes
-   and the functions from ISO C amendement 1.  */
-#  ifdef CHARCLASS_NAME_MAX
-#   define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
-#  else
-/* This shouldn't happen but some implementation might still have this
-   problem.  Use a reasonable default value.  */
-#   define CHAR_CLASS_MAX_LENGTH 256
-#  endif
-
-#  ifdef _LIBC
-#   define IS_CHAR_CLASS(string) __wctype (string)
-#  else
-#   define IS_CHAR_CLASS(string) wctype (string)
-#  endif
-# else
-#  define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
-
-#  define IS_CHAR_CLASS(string)                                                      \
-   (STREQ (string, "alpha") || STREQ (string, "upper")                       \
-    || STREQ (string, "lower") || STREQ (string, "digit")                    \
-    || STREQ (string, "alnum") || STREQ (string, "xdigit")                   \
-    || STREQ (string, "space") || STREQ (string, "print")                    \
-    || STREQ (string, "punct") || STREQ (string, "graph")                    \
-    || STREQ (string, "cntrl") || STREQ (string, "blank"))
-# endif
-
-/* Avoid depending on library functions or files
-   whose names are inconsistent.  */
-
-# if !defined _LIBC && !defined getenv
-extern char *getenv ();
-# endif
-
-# ifndef errno
-extern int errno;
-# endif
-
-/* This function doesn't exist on most systems.  */
-
-# if !defined HAVE___STRCHRNUL && !defined _LIBC
-static char *
-__strchrnul (s, c)
-     const char *s;
-     int c;
-{
-  char *result = strchr (s, c);
-  if (result == NULL)
-    result = strchr (s, '\0');
-  return result;
-}
-# endif
-
-# ifndef internal_function
-/* Inside GNU libc we mark some function in a special way.  In other
-   environments simply ignore the marking.  */
-#  define internal_function
-# endif
-
-/* Match STRING against the filename pattern PATTERN, returning zero if
-   it matches, nonzero if not.  */
-static int internal_fnmatch __P ((const char *pattern, const char *string,
-                                 int no_leading_period, int flags))
-     internal_function;
-static int
-internal_function
-internal_fnmatch (pattern, string, no_leading_period, flags)
-     const char *pattern;
-     const char *string;
-     int no_leading_period;
-     int flags;
-{
-  register const char *p = pattern, *n = string;
-  register unsigned char c;
-
-/* Note that this evaluates C many times.  */
-# ifdef _LIBC
-#  define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
-# else
-#  define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
-# endif
-
-  while ((c = *p++) != '\0')
-    {
-      c = FOLD (c);
-
-      switch (c)
-       {
-       case '?':
-         if (*n == '\0')
-           return FNM_NOMATCH;
-         else if (*n == '/' && (flags & FNM_FILE_NAME))
-           return FNM_NOMATCH;
-         else if (*n == '.' && no_leading_period
-                  && (n == string
-                      || (n[-1] == '/' && (flags & FNM_FILE_NAME))))
-           return FNM_NOMATCH;
-         break;
-
-       case '\\':
-         if (!(flags & FNM_NOESCAPE))
-           {
-             c = *p++;
-             if (c == '\0')
-               /* Trailing \ loses.  */
-               return FNM_NOMATCH;
-             c = FOLD (c);
-           }
-         if (FOLD ((unsigned char) *n) != c)
-           return FNM_NOMATCH;
-         break;
-
-       case '*':
-         if (*n == '.' && no_leading_period
-             && (n == string
-                 || (n[-1] == '/' && (flags & FNM_FILE_NAME))))
-           return FNM_NOMATCH;
-
-         for (c = *p++; c == '?' || c == '*'; c = *p++)
-           {
-             if (*n == '/' && (flags & FNM_FILE_NAME))
-               /* A slash does not match a wildcard under FNM_FILE_NAME.  */
-               return FNM_NOMATCH;
-             else if (c == '?')
-               {
-                 /* A ? needs to match one character.  */
-                 if (*n == '\0')
-                   /* There isn't another character; no match.  */
-                   return FNM_NOMATCH;
-                 else
-                   /* One character of the string is consumed in matching
-                      this ? wildcard, so *??? won't match if there are
-                      less than three characters.  */
-                   ++n;
-               }
-           }
-
-         if (c == '\0')
-           /* The wildcard(s) is/are the last element of the pattern.
-              If the name is a file name and contains another slash
-              this does mean it cannot match.  */
-           return ((flags & FNM_FILE_NAME) && strchr (n, '/') != NULL
-                   ? FNM_NOMATCH : 0);
-         else
-           {
-             const char *endp;
-
-             endp = __strchrnul (n, (flags & FNM_FILE_NAME) ? '/' : '\0');
-
-             if (c == '[')
-               {
-                 int flags2 = ((flags & FNM_FILE_NAME)
-                               ? flags : (flags & ~FNM_PERIOD));
-
-                 for (--p; n < endp; ++n)
-                   if (internal_fnmatch (p, n,
-                                         (no_leading_period
-                                          && (n == string
-                                              || (n[-1] == '/'
-                                                  && (flags
-                                                      & FNM_FILE_NAME)))),
-                                         flags2)
-                       == 0)
-                     return 0;
-               }
-             else if (c == '/' && (flags & FNM_FILE_NAME))
-               {
-                 while (*n != '\0' && *n != '/')
-                   ++n;
-                 if (*n == '/'
-                     && (internal_fnmatch (p, n + 1, flags & FNM_PERIOD,
-                                           flags) == 0))
-                   return 0;
-               }
-             else
-               {
-                 int flags2 = ((flags & FNM_FILE_NAME)
-                               ? flags : (flags & ~FNM_PERIOD));
-
-                 if (c == '\\' && !(flags & FNM_NOESCAPE))
-                   c = *p;
-                 c = FOLD (c);
-                 for (--p; n < endp; ++n)
-                   if (FOLD ((unsigned char) *n) == c
-                       && (internal_fnmatch (p, n,
-                                             (no_leading_period
-                                              && (n == string
-                                                  || (n[-1] == '/'
-                                                      && (flags
-                                                          & FNM_FILE_NAME)))),
-                                             flags2) == 0))
-                     return 0;
-               }
-           }
-
-         /* If we come here no match is possible with the wildcard.  */
-         return FNM_NOMATCH;
-
-       case '[':
-         {
-           /* Nonzero if the sense of the character class is inverted.  */
-           static int posixly_correct;
-           register int not;
-           char cold;
-
-           if (posixly_correct == 0)
-             posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
-
-           if (*n == '\0')
-             return FNM_NOMATCH;
-
-           if (*n == '.' && no_leading_period && (n == string
-                                                  || (n[-1] == '/'
-                                                      && (flags
-                                                          & FNM_FILE_NAME))))
-             return FNM_NOMATCH;
-
-           if (*n == '/' && (flags & FNM_FILE_NAME))
-             /* `/' cannot be matched.  */
-             return FNM_NOMATCH;
-
-           not = (*p == '!' || (posixly_correct < 0 && *p == '^'));
-           if (not)
-             ++p;
-
-           c = *p++;
-           for (;;)
-             {
-               unsigned char fn = FOLD ((unsigned char) *n);
-
-               if (!(flags & FNM_NOESCAPE) && c == '\\')
-                 {
-                   if (*p == '\0')
-                     return FNM_NOMATCH;
-                   c = FOLD ((unsigned char) *p);
-                   ++p;
-
-                   if (c == fn)
-                     goto matched;
-                 }
-               else if (c == '[' && *p == ':')
-                 {
-                   /* Leave room for the null.  */
-                   char str[CHAR_CLASS_MAX_LENGTH + 1];
-                   size_t c1 = 0;
-# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
-                   wctype_t wt;
-# endif
-                   const char *startp = p;
-
-                   for (;;)
-                     {
-                       if (c1 == CHAR_CLASS_MAX_LENGTH)
-                         /* The name is too long and therefore the pattern
-                            is ill-formed.  */
-                         return FNM_NOMATCH;
-
-                       c = *++p;
-                       if (c == ':' && p[1] == ']')
-                         {
-                           p += 2;
-                           break;
-                         }
-                       if (c < 'a' || c >= 'z')
-                         {
-                           /* This cannot possibly be a character class name.
-                              Match it as a normal range.  */
-                           p = startp;
-                           c = '[';
-                           goto normal_bracket;
-                         }
-                       str[c1++] = c;
-                     }
-                   str[c1] = '\0';
-
-# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
-                   wt = IS_CHAR_CLASS (str);
-                   if (wt == 0)
-                     /* Invalid character class name.  */
-                     return FNM_NOMATCH;
-
-                   if (__iswctype (__btowc ((unsigned char) *n), wt))
-                     goto matched;
-# else
-                   if ((STREQ (str, "alnum") && ISALNUM ((unsigned char) *n))
-                       || (STREQ (str, "alpha") && ISALPHA ((unsigned char) *n))
-                       || (STREQ (str, "blank") && ISBLANK ((unsigned char) *n))
-                       || (STREQ (str, "cntrl") && ISCNTRL ((unsigned char) *n))
-                       || (STREQ (str, "digit") && ISDIGIT ((unsigned char) *n))
-                       || (STREQ (str, "graph") && ISGRAPH ((unsigned char) *n))
-                       || (STREQ (str, "lower") && ISLOWER ((unsigned char) *n))
-                       || (STREQ (str, "print") && ISPRINT ((unsigned char) *n))
-                       || (STREQ (str, "punct") && ISPUNCT ((unsigned char) *n))
-                       || (STREQ (str, "space") && ISSPACE ((unsigned char) *n))
-                       || (STREQ (str, "upper") && ISUPPER ((unsigned char) *n))
-                       || (STREQ (str, "xdigit") && ISXDIGIT ((unsigned char) *n)))
-                     goto matched;
-# endif
-                 }
-               else if (c == '\0')
-                 /* [ (unterminated) loses.  */
-                 return FNM_NOMATCH;
-               else
-                 {
-                 normal_bracket:
-                   if (FOLD (c) == fn)
-                     goto matched;
-
-                   cold = c;
-                   c = *p++;
-
-                   if (c == '-' && *p != ']')
-                     {
-                       /* It is a range.  */
-                       unsigned char cend = *p++;
-                       if (!(flags & FNM_NOESCAPE) && cend == '\\')
-                         cend = *p++;
-                       if (cend == '\0')
-                         return FNM_NOMATCH;
-
-                       if (cold <= fn && fn <= FOLD (cend))
-                         goto matched;
-
-                       c = *p++;
-                     }
-                 }
-
-               if (c == ']')
-                 break;
-             }
-
-           if (!not)
-             return FNM_NOMATCH;
-           break;
-
-         matched:
-           /* Skip the rest of the [...] that already matched.  */
-           while (c != ']')
-             {
-               if (c == '\0')
-                 /* [... (unterminated) loses.  */
-                 return FNM_NOMATCH;
-
-               c = *p++;
-               if (!(flags & FNM_NOESCAPE) && c == '\\')
-                 {
-                   if (*p == '\0')
-                     return FNM_NOMATCH;
-                   /* XXX 1003.2d11 is unclear if this is right.  */
-                   ++p;
-                 }
-               else if (c == '[' && *p == ':')
-                 {
-                   do
-                     if (*++p == '\0')
-                       return FNM_NOMATCH;
-                   while (*p != ':' || p[1] == ']');
-                   p += 2;
-                   c = *p;
-                 }
-             }
-           if (not)
-             return FNM_NOMATCH;
-         }
-         break;
-
-       default:
-         if (c != FOLD ((unsigned char) *n))
-           return FNM_NOMATCH;
-       }
-
-      ++n;
-    }
-
-  if (*n == '\0')
-    return 0;
-
-  if ((flags & FNM_LEADING_DIR) && *n == '/')
-    /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
-    return 0;
-
-  return FNM_NOMATCH;
-
-# undef FOLD
-}
-
-
-int
-fnmatch (pattern, string, flags)
-     const char *pattern;
-     const char *string;
-     int flags;
-{
-  return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags);
-}
-
-#endif /* _LIBC or not __GNU_LIBRARY__.  */
diff --git a/compat/fnmatch.h b/compat/fnmatch.h
deleted file mode 100644 (file)
index cc3ec37..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with the GNU C Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
-
-#ifndef        _FNMATCH_H
-#define        _FNMATCH_H      1
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32
-# if !defined __GLIBC__ || !defined __P
-#  undef       __P
-#  define __P(protos)  protos
-# endif
-#else /* Not C++ or ANSI C.  */
-# undef        __P
-# define __P(protos)   ()
-/* We can get away without defining `const' here only because in this file
-   it is used only inside the prototype for `fnmatch', which is elided in
-   non-ANSI C where `const' is problematical.  */
-#endif /* C++ or ANSI C.  */
-
-#ifndef const
-# if (defined __STDC__ && __STDC__) || defined __cplusplus
-#  define __const      const
-# else
-#  define __const
-# endif
-#endif
-
-/* We #undef these before defining them because some losing systems
-   (HP-UX A.08.07 for example) define these in <unistd.h>.  */
-#undef FNM_PATHNAME
-#undef FNM_NOESCAPE
-#undef FNM_PERIOD
-
-/* Bits set in the FLAGS argument to `fnmatch'.  */
-#define        FNM_PATHNAME    (1 << 0) /* No wildcard can ever match `/'.  */
-#define        FNM_NOESCAPE    (1 << 1) /* Backslashes don't quote special chars.  */
-#define        FNM_PERIOD      (1 << 2) /* Leading `.' is matched only explicitly.  */
-
-#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE
-# define FNM_FILE_NAME  FNM_PATHNAME   /* Preferred GNU name.  */
-# define FNM_LEADING_DIR (1 << 3)      /* Ignore `/...' after a match.  */
-# define FNM_CASEFOLD   (1 << 4)       /* Compare without regard to case.  */
-#endif
-
-/* Value returned by `fnmatch' if STRING does not match PATTERN.  */
-#define        FNM_NOMATCH     1
-
-/* This value is returned if the implementation does not support
-   `fnmatch'.  Since this is not the case here it will never be
-   returned but the conformance test suites still require the symbol
-   to be defined.  */
-#ifdef _XOPEN_SOURCE
-# define FNM_NOSYS     (-1)
-#endif
-
-/* Match NAME against the filename pattern PATTERN,
-   returning zero if it matches, FNM_NOMATCH if not.  */
-extern int fnmatch __P ((__const char *__pattern, __const char *__name,
-                        int __flags));
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* fnmatch.h */
diff --git a/compat/fnmatch/fnmatch.c b/compat/fnmatch/fnmatch.c
new file mode 100644 (file)
index 0000000..1f4ead5
--- /dev/null
@@ -0,0 +1,488 @@
+/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with this library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Enable GNU extensions in fnmatch.h.  */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE   1
+#endif
+
+#include <errno.h>
+#include <fnmatch.h>
+#include <ctype.h>
+
+#if HAVE_STRING_H || defined _LIBC
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#endif
+
+/* For platform which support the ISO C amendement 1 functionality we
+   support user defined character classes.  */
+#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>.  */
+# include <wchar.h>
+# include <wctype.h>
+#endif
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#if defined _LIBC || !defined __GNU_LIBRARY__
+
+
+# if defined STDC_HEADERS || !defined isascii
+#  define ISASCII(c) 1
+# else
+#  define ISASCII(c) isascii(c)
+# endif
+
+# ifdef isblank
+#  define ISBLANK(c) (ISASCII (c) && isblank (c))
+# else
+#  define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+# endif
+# ifdef isgraph
+#  define ISGRAPH(c) (ISASCII (c) && isgraph (c))
+# else
+#  define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
+# endif
+
+# define ISPRINT(c) (ISASCII (c) && isprint (c))
+# define ISDIGIT(c) (ISASCII (c) && isdigit (c))
+# define ISALNUM(c) (ISASCII (c) && isalnum (c))
+# define ISALPHA(c) (ISASCII (c) && isalpha (c))
+# define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
+# define ISLOWER(c) (ISASCII (c) && islower (c))
+# define ISPUNCT(c) (ISASCII (c) && ispunct (c))
+# define ISSPACE(c) (ISASCII (c) && isspace (c))
+# define ISUPPER(c) (ISASCII (c) && isupper (c))
+# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
+
+# define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
+
+# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+/* The GNU C library provides support for user-defined character classes
+   and the functions from ISO C amendement 1.  */
+#  ifdef CHARCLASS_NAME_MAX
+#   define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
+#  else
+/* This shouldn't happen but some implementation might still have this
+   problem.  Use a reasonable default value.  */
+#   define CHAR_CLASS_MAX_LENGTH 256
+#  endif
+
+#  ifdef _LIBC
+#   define IS_CHAR_CLASS(string) __wctype (string)
+#  else
+#   define IS_CHAR_CLASS(string) wctype (string)
+#  endif
+# else
+#  define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
+
+#  define IS_CHAR_CLASS(string)                                                      \
+   (STREQ (string, "alpha") || STREQ (string, "upper")                       \
+    || STREQ (string, "lower") || STREQ (string, "digit")                    \
+    || STREQ (string, "alnum") || STREQ (string, "xdigit")                   \
+    || STREQ (string, "space") || STREQ (string, "print")                    \
+    || STREQ (string, "punct") || STREQ (string, "graph")                    \
+    || STREQ (string, "cntrl") || STREQ (string, "blank"))
+# endif
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+# if !defined _LIBC && !defined getenv
+extern char *getenv ();
+# endif
+
+# ifndef errno
+extern int errno;
+# endif
+
+/* This function doesn't exist on most systems.  */
+
+# if !defined HAVE___STRCHRNUL && !defined _LIBC
+static char *
+__strchrnul (s, c)
+     const char *s;
+     int c;
+{
+  char *result = strchr (s, c);
+  if (result == NULL)
+    result = strchr (s, '\0');
+  return result;
+}
+# endif
+
+# ifndef internal_function
+/* Inside GNU libc we mark some function in a special way.  In other
+   environments simply ignore the marking.  */
+#  define internal_function
+# endif
+
+/* Match STRING against the filename pattern PATTERN, returning zero if
+   it matches, nonzero if not.  */
+static int internal_fnmatch __P ((const char *pattern, const char *string,
+                                 int no_leading_period, int flags))
+     internal_function;
+static int
+internal_function
+internal_fnmatch (pattern, string, no_leading_period, flags)
+     const char *pattern;
+     const char *string;
+     int no_leading_period;
+     int flags;
+{
+  register const char *p = pattern, *n = string;
+  register unsigned char c;
+
+/* Note that this evaluates C many times.  */
+# ifdef _LIBC
+#  define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
+# else
+#  define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
+# endif
+
+  while ((c = *p++) != '\0')
+    {
+      c = FOLD (c);
+
+      switch (c)
+       {
+       case '?':
+         if (*n == '\0')
+           return FNM_NOMATCH;
+         else if (*n == '/' && (flags & FNM_FILE_NAME))
+           return FNM_NOMATCH;
+         else if (*n == '.' && no_leading_period
+                  && (n == string
+                      || (n[-1] == '/' && (flags & FNM_FILE_NAME))))
+           return FNM_NOMATCH;
+         break;
+
+       case '\\':
+         if (!(flags & FNM_NOESCAPE))
+           {
+             c = *p++;
+             if (c == '\0')
+               /* Trailing \ loses.  */
+               return FNM_NOMATCH;
+             c = FOLD (c);
+           }
+         if (FOLD ((unsigned char) *n) != c)
+           return FNM_NOMATCH;
+         break;
+
+       case '*':
+         if (*n == '.' && no_leading_period
+             && (n == string
+                 || (n[-1] == '/' && (flags & FNM_FILE_NAME))))
+           return FNM_NOMATCH;
+
+         for (c = *p++; c == '?' || c == '*'; c = *p++)
+           {
+             if (*n == '/' && (flags & FNM_FILE_NAME))
+               /* A slash does not match a wildcard under FNM_FILE_NAME.  */
+               return FNM_NOMATCH;
+             else if (c == '?')
+               {
+                 /* A ? needs to match one character.  */
+                 if (*n == '\0')
+                   /* There isn't another character; no match.  */
+                   return FNM_NOMATCH;
+                 else
+                   /* One character of the string is consumed in matching
+                      this ? wildcard, so *??? won't match if there are
+                      less than three characters.  */
+                   ++n;
+               }
+           }
+
+         if (c == '\0')
+           /* The wildcard(s) is/are the last element of the pattern.
+              If the name is a file name and contains another slash
+              this does mean it cannot match.  */
+           return ((flags & FNM_FILE_NAME) && strchr (n, '/') != NULL
+                   ? FNM_NOMATCH : 0);
+         else
+           {
+             const char *endp;
+
+             endp = __strchrnul (n, (flags & FNM_FILE_NAME) ? '/' : '\0');
+
+             if (c == '[')
+               {
+                 int flags2 = ((flags & FNM_FILE_NAME)
+                               ? flags : (flags & ~FNM_PERIOD));
+
+                 for (--p; n < endp; ++n)
+                   if (internal_fnmatch (p, n,
+                                         (no_leading_period
+                                          && (n == string
+                                              || (n[-1] == '/'
+                                                  && (flags
+                                                      & FNM_FILE_NAME)))),
+                                         flags2)
+                       == 0)
+                     return 0;
+               }
+             else if (c == '/' && (flags & FNM_FILE_NAME))
+               {
+                 while (*n != '\0' && *n != '/')
+                   ++n;
+                 if (*n == '/'
+                     && (internal_fnmatch (p, n + 1, flags & FNM_PERIOD,
+                                           flags) == 0))
+                   return 0;
+               }
+             else
+               {
+                 int flags2 = ((flags & FNM_FILE_NAME)
+                               ? flags : (flags & ~FNM_PERIOD));
+
+                 if (c == '\\' && !(flags & FNM_NOESCAPE))
+                   c = *p;
+                 c = FOLD (c);
+                 for (--p; n < endp; ++n)
+                   if (FOLD ((unsigned char) *n) == c
+                       && (internal_fnmatch (p, n,
+                                             (no_leading_period
+                                              && (n == string
+                                                  || (n[-1] == '/'
+                                                      && (flags
+                                                          & FNM_FILE_NAME)))),
+                                             flags2) == 0))
+                     return 0;
+               }
+           }
+
+         /* If we come here no match is possible with the wildcard.  */
+         return FNM_NOMATCH;
+
+       case '[':
+         {
+           /* Nonzero if the sense of the character class is inverted.  */
+           static int posixly_correct;
+           register int not;
+           char cold;
+
+           if (posixly_correct == 0)
+             posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
+
+           if (*n == '\0')
+             return FNM_NOMATCH;
+
+           if (*n == '.' && no_leading_period && (n == string
+                                                  || (n[-1] == '/'
+                                                      && (flags
+                                                          & FNM_FILE_NAME))))
+             return FNM_NOMATCH;
+
+           if (*n == '/' && (flags & FNM_FILE_NAME))
+             /* `/' cannot be matched.  */
+             return FNM_NOMATCH;
+
+           not = (*p == '!' || (posixly_correct < 0 && *p == '^'));
+           if (not)
+             ++p;
+
+           c = *p++;
+           for (;;)
+             {
+               unsigned char fn = FOLD ((unsigned char) *n);
+
+               if (!(flags & FNM_NOESCAPE) && c == '\\')
+                 {
+                   if (*p == '\0')
+                     return FNM_NOMATCH;
+                   c = FOLD ((unsigned char) *p);
+                   ++p;
+
+                   if (c == fn)
+                     goto matched;
+                 }
+               else if (c == '[' && *p == ':')
+                 {
+                   /* Leave room for the null.  */
+                   char str[CHAR_CLASS_MAX_LENGTH + 1];
+                   size_t c1 = 0;
+# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+                   wctype_t wt;
+# endif
+                   const char *startp = p;
+
+                   for (;;)
+                     {
+                       if (c1 == CHAR_CLASS_MAX_LENGTH)
+                         /* The name is too long and therefore the pattern
+                            is ill-formed.  */
+                         return FNM_NOMATCH;
+
+                       c = *++p;
+                       if (c == ':' && p[1] == ']')
+                         {
+                           p += 2;
+                           break;
+                         }
+                       if (c < 'a' || c >= 'z')
+                         {
+                           /* This cannot possibly be a character class name.
+                              Match it as a normal range.  */
+                           p = startp;
+                           c = '[';
+                           goto normal_bracket;
+                         }
+                       str[c1++] = c;
+                     }
+                   str[c1] = '\0';
+
+# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
+                   wt = IS_CHAR_CLASS (str);
+                   if (wt == 0)
+                     /* Invalid character class name.  */
+                     return FNM_NOMATCH;
+
+                   if (__iswctype (__btowc ((unsigned char) *n), wt))
+                     goto matched;
+# else
+                   if ((STREQ (str, "alnum") && ISALNUM ((unsigned char) *n))
+                       || (STREQ (str, "alpha") && ISALPHA ((unsigned char) *n))
+                       || (STREQ (str, "blank") && ISBLANK ((unsigned char) *n))
+                       || (STREQ (str, "cntrl") && ISCNTRL ((unsigned char) *n))
+                       || (STREQ (str, "digit") && ISDIGIT ((unsigned char) *n))
+                       || (STREQ (str, "graph") && ISGRAPH ((unsigned char) *n))
+                       || (STREQ (str, "lower") && ISLOWER ((unsigned char) *n))
+                       || (STREQ (str, "print") && ISPRINT ((unsigned char) *n))
+                       || (STREQ (str, "punct") && ISPUNCT ((unsigned char) *n))
+                       || (STREQ (str, "space") && ISSPACE ((unsigned char) *n))
+                       || (STREQ (str, "upper") && ISUPPER ((unsigned char) *n))
+                       || (STREQ (str, "xdigit") && ISXDIGIT ((unsigned char) *n)))
+                     goto matched;
+# endif
+                 }
+               else if (c == '\0')
+                 /* [ (unterminated) loses.  */
+                 return FNM_NOMATCH;
+               else
+                 {
+                 normal_bracket:
+                   if (FOLD (c) == fn)
+                     goto matched;
+
+                   cold = c;
+                   c = *p++;
+
+                   if (c == '-' && *p != ']')
+                     {
+                       /* It is a range.  */
+                       unsigned char cend = *p++;
+                       if (!(flags & FNM_NOESCAPE) && cend == '\\')
+                         cend = *p++;
+                       if (cend == '\0')
+                         return FNM_NOMATCH;
+
+                       if (cold <= fn && fn <= FOLD (cend))
+                         goto matched;
+
+                       c = *p++;
+                     }
+                 }
+
+               if (c == ']')
+                 break;
+             }
+
+           if (!not)
+             return FNM_NOMATCH;
+           break;
+
+         matched:
+           /* Skip the rest of the [...] that already matched.  */
+           while (c != ']')
+             {
+               if (c == '\0')
+                 /* [... (unterminated) loses.  */
+                 return FNM_NOMATCH;
+
+               c = *p++;
+               if (!(flags & FNM_NOESCAPE) && c == '\\')
+                 {
+                   if (*p == '\0')
+                     return FNM_NOMATCH;
+                   /* XXX 1003.2d11 is unclear if this is right.  */
+                   ++p;
+                 }
+               else if (c == '[' && *p == ':')
+                 {
+                   do
+                     if (*++p == '\0')
+                       return FNM_NOMATCH;
+                   while (*p != ':' || p[1] == ']');
+                   p += 2;
+                   c = *p;
+                 }
+             }
+           if (not)
+             return FNM_NOMATCH;
+         }
+         break;
+
+       default:
+         if (c != FOLD ((unsigned char) *n))
+           return FNM_NOMATCH;
+       }
+
+      ++n;
+    }
+
+  if (*n == '\0')
+    return 0;
+
+  if ((flags & FNM_LEADING_DIR) && *n == '/')
+    /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
+    return 0;
+
+  return FNM_NOMATCH;
+
+# undef FOLD
+}
+
+
+int
+fnmatch (pattern, string, flags)
+     const char *pattern;
+     const char *string;
+     int flags;
+{
+  return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags);
+}
+
+#endif /* _LIBC or not __GNU_LIBRARY__.  */
diff --git a/compat/fnmatch/fnmatch.h b/compat/fnmatch/fnmatch.h
new file mode 100644 (file)
index 0000000..cc3ec37
--- /dev/null
@@ -0,0 +1,84 @@
+/* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#ifndef        _FNMATCH_H
+#define        _FNMATCH_H      1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32
+# if !defined __GLIBC__ || !defined __P
+#  undef       __P
+#  define __P(protos)  protos
+# endif
+#else /* Not C++ or ANSI C.  */
+# undef        __P
+# define __P(protos)   ()
+/* We can get away without defining `const' here only because in this file
+   it is used only inside the prototype for `fnmatch', which is elided in
+   non-ANSI C where `const' is problematical.  */
+#endif /* C++ or ANSI C.  */
+
+#ifndef const
+# if (defined __STDC__ && __STDC__) || defined __cplusplus
+#  define __const      const
+# else
+#  define __const
+# endif
+#endif
+
+/* We #undef these before defining them because some losing systems
+   (HP-UX A.08.07 for example) define these in <unistd.h>.  */
+#undef FNM_PATHNAME
+#undef FNM_NOESCAPE
+#undef FNM_PERIOD
+
+/* Bits set in the FLAGS argument to `fnmatch'.  */
+#define        FNM_PATHNAME    (1 << 0) /* No wildcard can ever match `/'.  */
+#define        FNM_NOESCAPE    (1 << 1) /* Backslashes don't quote special chars.  */
+#define        FNM_PERIOD      (1 << 2) /* Leading `.' is matched only explicitly.  */
+
+#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE
+# define FNM_FILE_NAME  FNM_PATHNAME   /* Preferred GNU name.  */
+# define FNM_LEADING_DIR (1 << 3)      /* Ignore `/...' after a match.  */
+# define FNM_CASEFOLD   (1 << 4)       /* Compare without regard to case.  */
+#endif
+
+/* Value returned by `fnmatch' if STRING does not match PATTERN.  */
+#define        FNM_NOMATCH     1
+
+/* This value is returned if the implementation does not support
+   `fnmatch'.  Since this is not the case here it will never be
+   returned but the conformance test suites still require the symbol
+   to be defined.  */
+#ifdef _XOPEN_SOURCE
+# define FNM_NOSYS     (-1)
+#endif
+
+/* Match NAME against the filename pattern PATTERN,
+   returning zero if it matches, FNM_NOMATCH if not.  */
+extern int fnmatch __P ((__const char *__pattern, __const char *__name,
+                        int __flags));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* fnmatch.h */
index 772cad510d5d260fdf33b4f7d6ff79f9f3367b05..ccfa2a0a3d3263862beb0d2796be1aba78574986 100644 (file)
@@ -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));
index 290a9e6f822df97984b9f769508aab36419eaf02..4f275cb8e6a67515292a9dfc60bd1343065067a9 100644 (file)
@@ -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
@@ -228,9 +218,10 @@ char **env_setenv(char **env, const char *name);
  * A replacement of main() that ensures that argv[0] has a path
  */
 
-#define main(c,v) main(int argc, const char **argv) \
+#define main(c,v) dummy_decl_mingw_main(); \
+static int mingw_main(); \
+int main(int argc, const char **argv) \
 { \
-       static int mingw_main(); \
        argv[0] = xstrdup(_pgmptr); \
        return mingw_main(argc, argv); \
 } \
diff --git a/compat/regex.c b/compat/regex.c
deleted file mode 100644 (file)
index 87b33e4..0000000
+++ /dev/null
@@ -1,4927 +0,0 @@
-/* Extended regular expression matching and search library,
-   version 0.12.
-   (Implements POSIX draft P10003.2/D11.2, except for
-   internationalization features.)
-
-   Copyright (C) 1993 Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
-
-/* AIX requires this to be the first thing in the file. */
-#if defined (_AIX) && !defined (REGEX_MALLOC)
-  #pragma alloca
-#endif
-
-#define _GNU_SOURCE
-
-/* We need this for `regex.h', and perhaps for the Emacs include files.  */
-#include <sys/types.h>
-
-/* We used to test for `BSTRING' here, but only GCC and Emacs define
-   `BSTRING', as far as I know, and neither of them use this code.  */
-#include <string.h>
-#ifndef bcmp
-#define bcmp(s1, s2, n)        memcmp ((s1), (s2), (n))
-#endif
-#ifndef bcopy
-#define bcopy(s, d, n) memcpy ((d), (s), (n))
-#endif
-#ifndef bzero
-#define bzero(s, n)    memset ((s), 0, (n))
-#endif
-
-#include <stdlib.h>
-
-
-/* Define the syntax stuff for \<, \>, etc.  */
-
-/* This must be nonzero for the wordchar and notwordchar pattern
-   commands in re_match_2.  */
-#ifndef Sword
-#define Sword 1
-#endif
-
-#ifdef SYNTAX_TABLE
-
-extern char *re_syntax_table;
-
-#else /* not SYNTAX_TABLE */
-
-/* How many characters in the character set.  */
-#define CHAR_SET_SIZE 256
-
-static char re_syntax_table[CHAR_SET_SIZE];
-
-static void
-init_syntax_once ()
-{
-   register int c;
-   static int done = 0;
-
-   if (done)
-     return;
-
-   bzero (re_syntax_table, sizeof re_syntax_table);
-
-   for (c = 'a'; c <= 'z'; c++)
-     re_syntax_table[c] = Sword;
-
-   for (c = 'A'; c <= 'Z'; c++)
-     re_syntax_table[c] = Sword;
-
-   for (c = '0'; c <= '9'; c++)
-     re_syntax_table[c] = Sword;
-
-   re_syntax_table['_'] = Sword;
-
-   done = 1;
-}
-
-#endif /* not SYNTAX_TABLE */
-
-#define SYNTAX(c) re_syntax_table[c]
-
-\f
-/* Get the interface, including the syntax bits.  */
-#include "regex.h"
-
-/* isalpha etc. are used for the character classes.  */
-#include <ctype.h>
-
-#ifndef isascii
-#define isascii(c) 1
-#endif
-
-#ifdef isblank
-#define ISBLANK(c) (isascii (c) && isblank (c))
-#else
-#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
-#endif
-#ifdef isgraph
-#define ISGRAPH(c) (isascii (c) && isgraph (c))
-#else
-#define ISGRAPH(c) (isascii (c) && isprint (c) && !isspace (c))
-#endif
-
-#define ISPRINT(c) (isascii (c) && isprint (c))
-#define ISDIGIT(c) (isascii (c) && isdigit (c))
-#define ISALNUM(c) (isascii (c) && isalnum (c))
-#define ISALPHA(c) (isascii (c) && isalpha (c))
-#define ISCNTRL(c) (isascii (c) && iscntrl (c))
-#define ISLOWER(c) (isascii (c) && islower (c))
-#define ISPUNCT(c) (isascii (c) && ispunct (c))
-#define ISSPACE(c) (isascii (c) && isspace (c))
-#define ISUPPER(c) (isascii (c) && isupper (c))
-#define ISXDIGIT(c) (isascii (c) && isxdigit (c))
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-/* We remove any previous definition of `SIGN_EXTEND_CHAR',
-   since ours (we hope) works properly with all combinations of
-   machines, compilers, `char' and `unsigned char' argument types.
-   (Per Bothner suggested the basic approach.)  */
-#undef SIGN_EXTEND_CHAR
-#if __STDC__
-#define SIGN_EXTEND_CHAR(c) ((signed char) (c))
-#else  /* not __STDC__ */
-/* As in Harbison and Steele.  */
-#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
-#endif
-\f
-/* Should we use malloc or alloca?  If REGEX_MALLOC is not defined, we
-   use `alloca' instead of `malloc'.  This is because using malloc in
-   re_search* or re_match* could cause memory leaks when C-g is used in
-   Emacs; also, malloc is slower and causes storage fragmentation.  On
-   the other hand, malloc is more portable, and easier to debug.
-
-   Because we sometimes use alloca, some routines have to be macros,
-   not functions -- `alloca'-allocated space disappears at the end of the
-   function it is called in.  */
-
-#ifdef REGEX_MALLOC
-
-#define REGEX_ALLOCATE malloc
-#define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize)
-
-#else /* not REGEX_MALLOC  */
-
-/* Emacs already defines alloca, sometimes.  */
-#ifndef alloca
-
-/* Make alloca work the best possible way.  */
-#ifdef __GNUC__
-#define alloca __builtin_alloca
-#else /* not __GNUC__ */
-#if HAVE_ALLOCA_H
-#include <alloca.h>
-#else /* not __GNUC__ or HAVE_ALLOCA_H */
-#ifndef _AIX /* Already did AIX, up at the top.  */
-char *alloca ();
-#endif /* not _AIX */
-#endif /* not HAVE_ALLOCA_H */
-#endif /* not __GNUC__ */
-
-#endif /* not alloca */
-
-#define REGEX_ALLOCATE alloca
-
-/* Assumes a `char *destination' variable.  */
-#define REGEX_REALLOCATE(source, osize, nsize)                         \
-  (destination = (char *) alloca (nsize),                              \
-   bcopy (source, destination, osize),                                 \
-   destination)
-
-#endif /* not REGEX_MALLOC */
-
-
-/* True if `size1' is non-NULL and PTR is pointing anywhere inside
-   `string1' or just past its end.  This works if PTR is NULL, which is
-   a good thing.  */
-#define FIRST_STRING_P(ptr)                                    \
-  (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
-
-/* (Re)Allocate N items of type T using malloc, or fail.  */
-#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t)))
-#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t)))
-#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t)))
-
-#define BYTEWIDTH 8 /* In bits.  */
-
-#define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
-
-#define MAX(a, b) ((a) > (b) ? (a) : (b))
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-
-typedef char boolean;
-#define false 0
-#define true 1
-\f
-/* These are the command codes that appear in compiled regular
-   expressions.  Some opcodes are followed by argument bytes.  A
-   command code can specify any interpretation whatsoever for its
-   arguments.  Zero bytes may appear in the compiled regular expression.
-
-   The value of `exactn' is needed in search.c (search_buffer) in Emacs.
-   So regex.h defines a symbol `RE_EXACTN_VALUE' to be 1; the value of
-   `exactn' we use here must also be 1.  */
-
-typedef enum
-{
-  no_op = 0,
-
-       /* Followed by one byte giving n, then by n literal bytes.  */
-  exactn = 1,
-
-       /* Matches any (more or less) character.  */
-  anychar,
-
-       /* Matches any one char belonging to specified set.  First
-          following byte is number of bitmap bytes.  Then come bytes
-          for a bitmap saying which chars are in.  Bits in each byte
-          are ordered low-bit-first.  A character is in the set if its
-          bit is 1.  A character too large to have a bit in the map is
-          automatically not in the set.  */
-  charset,
-
-       /* Same parameters as charset, but match any character that is
-          not one of those specified.  */
-  charset_not,
-
-       /* Start remembering the text that is matched, for storing in a
-          register.  Followed by one byte with the register number, in
-          the range 0 to one less than the pattern buffer's re_nsub
-          field.  Then followed by one byte with the number of groups
-          inner to this one.  (This last has to be part of the
-          start_memory only because we need it in the on_failure_jump
-          of re_match_2.)  */
-  start_memory,
-
-       /* Stop remembering the text that is matched and store it in a
-          memory register.  Followed by one byte with the register
-          number, in the range 0 to one less than `re_nsub' in the
-          pattern buffer, and one byte with the number of inner groups,
-          just like `start_memory'.  (We need the number of inner
-          groups here because we don't have any easy way of finding the
-          corresponding start_memory when we're at a stop_memory.)  */
-  stop_memory,
-
-       /* Match a duplicate of something remembered. Followed by one
-          byte containing the register number.  */
-  duplicate,
-
-       /* Fail unless at beginning of line.  */
-  begline,
-
-       /* Fail unless at end of line.  */
-  endline,
-
-       /* Succeeds if at beginning of buffer (if emacs) or at beginning
-          of string to be matched (if not).  */
-  begbuf,
-
-       /* Analogously, for end of buffer/string.  */
-  endbuf,
-
-       /* Followed by two byte relative address to which to jump.  */
-  jump,
-
-       /* Same as jump, but marks the end of an alternative.  */
-  jump_past_alt,
-
-       /* Followed by two-byte relative address of place to resume at
-          in case of failure.  */
-  on_failure_jump,
-
-       /* Like on_failure_jump, but pushes a placeholder instead of the
-          current string position when executed.  */
-  on_failure_keep_string_jump,
-
-       /* Throw away latest failure point and then jump to following
-          two-byte relative address.  */
-  pop_failure_jump,
-
-       /* Change to pop_failure_jump if know won't have to backtrack to
-          match; otherwise change to jump.  This is used to jump
-          back to the beginning of a repeat.  If what follows this jump
-          clearly won't match what the repeat does, such that we can be
-          sure that there is no use backtracking out of repetitions
-          already matched, then we change it to a pop_failure_jump.
-          Followed by two-byte address.  */
-  maybe_pop_jump,
-
-       /* Jump to following two-byte address, and push a dummy failure
-          point. This failure point will be thrown away if an attempt
-          is made to use it for a failure.  A `+' construct makes this
-          before the first repeat.  Also used as an intermediary kind
-          of jump when compiling an alternative.  */
-  dummy_failure_jump,
-
-       /* Push a dummy failure point and continue.  Used at the end of
-          alternatives.  */
-  push_dummy_failure,
-
-       /* Followed by two-byte relative address and two-byte number n.
-          After matching N times, jump to the address upon failure.  */
-  succeed_n,
-
-       /* Followed by two-byte relative address, and two-byte number n.
-          Jump to the address N times, then fail.  */
-  jump_n,
-
-       /* Set the following two-byte relative address to the
-          subsequent two-byte number.  The address *includes* the two
-          bytes of number.  */
-  set_number_at,
-
-  wordchar,    /* Matches any word-constituent character.  */
-  notwordchar, /* Matches any char that is not a word-constituent.  */
-
-  wordbeg,     /* Succeeds if at word beginning.  */
-  wordend,     /* Succeeds if at word end.  */
-
-  wordbound,   /* Succeeds if at a word boundary.  */
-  notwordbound /* Succeeds if not at a word boundary.  */
-
-#ifdef emacs
-  ,before_dot, /* Succeeds if before point.  */
-  at_dot,      /* Succeeds if at point.  */
-  after_dot,   /* Succeeds if after point.  */
-
-       /* Matches any character whose syntax is specified.  Followed by
-          a byte which contains a syntax code, e.g., Sword.  */
-  syntaxspec,
-
-       /* Matches any character whose syntax is not that specified.  */
-  notsyntaxspec
-#endif /* emacs */
-} re_opcode_t;
-\f
-/* Common operations on the compiled pattern.  */
-
-/* Store NUMBER in two contiguous bytes starting at DESTINATION.  */
-
-#define STORE_NUMBER(destination, number)                              \
-  do {                                                                 \
-    (destination)[0] = (number) & 0377;                                        \
-    (destination)[1] = (number) >> 8;                                  \
-  } while (0)
-
-/* Same as STORE_NUMBER, except increment DESTINATION to
-   the byte after where the number is stored.  Therefore, DESTINATION
-   must be an lvalue.  */
-
-#define STORE_NUMBER_AND_INCR(destination, number)                     \
-  do {                                                                 \
-    STORE_NUMBER (destination, number);                                        \
-    (destination) += 2;                                                        \
-  } while (0)
-
-/* Put into DESTINATION a number stored in two contiguous bytes starting
-   at SOURCE.  */
-
-#define EXTRACT_NUMBER(destination, source)                            \
-  do {                                                                 \
-    (destination) = *(source) & 0377;                                  \
-    (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8;          \
-  } while (0)
-
-#ifdef DEBUG
-static void
-extract_number (dest, source)
-    int *dest;
-    unsigned char *source;
-{
-  int temp = SIGN_EXTEND_CHAR (*(source + 1));
-  *dest = *source & 0377;
-  *dest += temp << 8;
-}
-
-#ifndef EXTRACT_MACROS /* To debug the macros.  */
-#undef EXTRACT_NUMBER
-#define EXTRACT_NUMBER(dest, src) extract_number (&dest, src)
-#endif /* not EXTRACT_MACROS */
-
-#endif /* DEBUG */
-
-/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number.
-   SOURCE must be an lvalue.  */
-
-#define EXTRACT_NUMBER_AND_INCR(destination, source)                   \
-  do {                                                                 \
-    EXTRACT_NUMBER (destination, source);                              \
-    (source) += 2;                                                     \
-  } while (0)
-
-#ifdef DEBUG
-static void
-extract_number_and_incr (destination, source)
-    int *destination;
-    unsigned char **source;
-{
-  extract_number (destination, *source);
-  *source += 2;
-}
-
-#ifndef EXTRACT_MACROS
-#undef EXTRACT_NUMBER_AND_INCR
-#define EXTRACT_NUMBER_AND_INCR(dest, src) \
-  extract_number_and_incr (&dest, &src)
-#endif /* not EXTRACT_MACROS */
-
-#endif /* DEBUG */
-\f
-/* If DEBUG is defined, Regex prints many voluminous messages about what
-   it is doing (if the variable `debug' is nonzero).  If linked with the
-   main program in `iregex.c', you can enter patterns and strings
-   interactively.  And if linked with the main program in `main.c' and
-   the other test files, you can run the already-written tests.  */
-
-#ifdef DEBUG
-
-/* We use standard I/O for debugging.  */
-#include <stdio.h>
-
-/* It is useful to test things that ``must'' be true when debugging.  */
-#include <assert.h>
-
-static int debug = 0;
-
-#define DEBUG_STATEMENT(e) e
-#define DEBUG_PRINT1(x) if (debug) printf (x)
-#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
-#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
-#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
-#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)                          \
-  if (debug) print_partial_compiled_pattern (s, e)
-#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)                 \
-  if (debug) print_double_string (w, s1, sz1, s2, sz2)
-
-
-extern void printchar ();
-
-/* Print the fastmap in human-readable form.  */
-
-void
-print_fastmap (fastmap)
-    char *fastmap;
-{
-  unsigned was_a_range = 0;
-  unsigned i = 0;
-
-  while (i < (1 << BYTEWIDTH))
-    {
-      if (fastmap[i++])
-       {
-         was_a_range = 0;
-         printchar (i - 1);
-         while (i < (1 << BYTEWIDTH)  &&  fastmap[i])
-           {
-             was_a_range = 1;
-             i++;
-           }
-         if (was_a_range)
-           {
-             printf ("-");
-             printchar (i - 1);
-           }
-       }
-    }
-  putchar ('\n');
-}
-
-
-/* Print a compiled pattern string in human-readable form, starting at
-   the START pointer into it and ending just before the pointer END.  */
-
-void
-print_partial_compiled_pattern (start, end)
-    unsigned char *start;
-    unsigned char *end;
-{
-  int mcnt, mcnt2;
-  unsigned char *p = start;
-  unsigned char *pend = end;
-
-  if (start == NULL)
-    {
-      printf ("(null)\n");
-      return;
-    }
-
-  /* Loop over pattern commands.  */
-  while (p < pend)
-    {
-      switch ((re_opcode_t) *p++)
-       {
-       case no_op:
-         printf ("/no_op");
-         break;
-
-       case exactn:
-         mcnt = *p++;
-         printf ("/exactn/%d", mcnt);
-         do
-           {
-             putchar ('/');
-             printchar (*p++);
-           }
-         while (--mcnt);
-         break;
-
-       case start_memory:
-         mcnt = *p++;
-         printf ("/start_memory/%d/%d", mcnt, *p++);
-         break;
-
-       case stop_memory:
-         mcnt = *p++;
-         printf ("/stop_memory/%d/%d", mcnt, *p++);
-         break;
-
-       case duplicate:
-         printf ("/duplicate/%d", *p++);
-         break;
-
-       case anychar:
-         printf ("/anychar");
-         break;
-
-       case charset:
-       case charset_not:
-         {
-           register int c;
-
-           printf ("/charset%s",
-                   (re_opcode_t) *(p - 1) == charset_not ? "_not" : "");
-
-           assert (p + *p < pend);
-
-           for (c = 0; c < *p; c++)
-             {
-               unsigned bit;
-               unsigned char map_byte = p[1 + c];
-
-               putchar ('/');
-
-               for (bit = 0; bit < BYTEWIDTH; bit++)
-                 if (map_byte & (1 << bit))
-                   printchar (c * BYTEWIDTH + bit);
-             }
-           p += 1 + *p;
-           break;
-         }
-
-       case begline:
-         printf ("/begline");
-         break;
-
-       case endline:
-         printf ("/endline");
-         break;
-
-       case on_failure_jump:
-         extract_number_and_incr (&mcnt, &p);
-         printf ("/on_failure_jump/0/%d", mcnt);
-         break;
-
-       case on_failure_keep_string_jump:
-         extract_number_and_incr (&mcnt, &p);
-         printf ("/on_failure_keep_string_jump/0/%d", mcnt);
-         break;
-
-       case dummy_failure_jump:
-         extract_number_and_incr (&mcnt, &p);
-         printf ("/dummy_failure_jump/0/%d", mcnt);
-         break;
-
-       case push_dummy_failure:
-         printf ("/push_dummy_failure");
-         break;
-
-       case maybe_pop_jump:
-         extract_number_and_incr (&mcnt, &p);
-         printf ("/maybe_pop_jump/0/%d", mcnt);
-         break;
-
-       case pop_failure_jump:
-         extract_number_and_incr (&mcnt, &p);
-         printf ("/pop_failure_jump/0/%d", mcnt);
-         break;
-
-       case jump_past_alt:
-         extract_number_and_incr (&mcnt, &p);
-         printf ("/jump_past_alt/0/%d", mcnt);
-         break;
-
-       case jump:
-         extract_number_and_incr (&mcnt, &p);
-         printf ("/jump/0/%d", mcnt);
-         break;
-
-       case succeed_n:
-         extract_number_and_incr (&mcnt, &p);
-         extract_number_and_incr (&mcnt2, &p);
-         printf ("/succeed_n/0/%d/0/%d", mcnt, mcnt2);
-         break;
-
-       case jump_n:
-         extract_number_and_incr (&mcnt, &p);
-         extract_number_and_incr (&mcnt2, &p);
-         printf ("/jump_n/0/%d/0/%d", mcnt, mcnt2);
-         break;
-
-       case set_number_at:
-         extract_number_and_incr (&mcnt, &p);
-         extract_number_and_incr (&mcnt2, &p);
-         printf ("/set_number_at/0/%d/0/%d", mcnt, mcnt2);
-         break;
-
-       case wordbound:
-         printf ("/wordbound");
-         break;
-
-       case notwordbound:
-         printf ("/notwordbound");
-         break;
-
-       case wordbeg:
-         printf ("/wordbeg");
-         break;
-
-       case wordend:
-         printf ("/wordend");
-
-#ifdef emacs
-       case before_dot:
-         printf ("/before_dot");
-         break;
-
-       case at_dot:
-         printf ("/at_dot");
-         break;
-
-       case after_dot:
-         printf ("/after_dot");
-         break;
-
-       case syntaxspec:
-         printf ("/syntaxspec");
-         mcnt = *p++;
-         printf ("/%d", mcnt);
-         break;
-
-       case notsyntaxspec:
-         printf ("/notsyntaxspec");
-         mcnt = *p++;
-         printf ("/%d", mcnt);
-         break;
-#endif /* emacs */
-
-       case wordchar:
-         printf ("/wordchar");
-         break;
-
-       case notwordchar:
-         printf ("/notwordchar");
-         break;
-
-       case begbuf:
-         printf ("/begbuf");
-         break;
-
-       case endbuf:
-         printf ("/endbuf");
-         break;
-
-       default:
-         printf ("?%d", *(p-1));
-       }
-    }
-  printf ("/\n");
-}
-
-
-void
-print_compiled_pattern (bufp)
-    struct re_pattern_buffer *bufp;
-{
-  unsigned char *buffer = bufp->buffer;
-
-  print_partial_compiled_pattern (buffer, buffer + bufp->used);
-  printf ("%d bytes used/%d bytes allocated.\n", bufp->used, bufp->allocated);
-
-  if (bufp->fastmap_accurate && bufp->fastmap)
-    {
-      printf ("fastmap: ");
-      print_fastmap (bufp->fastmap);
-    }
-
-  printf ("re_nsub: %d\t", bufp->re_nsub);
-  printf ("regs_alloc: %d\t", bufp->regs_allocated);
-  printf ("can_be_null: %d\t", bufp->can_be_null);
-  printf ("newline_anchor: %d\n", bufp->newline_anchor);
-  printf ("no_sub: %d\t", bufp->no_sub);
-  printf ("not_bol: %d\t", bufp->not_bol);
-  printf ("not_eol: %d\t", bufp->not_eol);
-  printf ("syntax: %d\n", bufp->syntax);
-  /* Perhaps we should print the translate table?  */
-}
-
-
-void
-print_double_string (where, string1, size1, string2, size2)
-    const char *where;
-    const char *string1;
-    const char *string2;
-    int size1;
-    int size2;
-{
-  unsigned this_char;
-
-  if (where == NULL)
-    printf ("(null)");
-  else
-    {
-      if (FIRST_STRING_P (where))
-       {
-         for (this_char = where - string1; this_char < size1; this_char++)
-           printchar (string1[this_char]);
-
-         where = string2;
-       }
-
-      for (this_char = where - string2; this_char < size2; this_char++)
-       printchar (string2[this_char]);
-    }
-}
-
-#else /* not DEBUG */
-
-#undef assert
-#define assert(e)
-
-#define DEBUG_STATEMENT(e)
-#define DEBUG_PRINT1(x)
-#define DEBUG_PRINT2(x1, x2)
-#define DEBUG_PRINT3(x1, x2, x3)
-#define DEBUG_PRINT4(x1, x2, x3, x4)
-#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)
-#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
-
-#endif /* not DEBUG */
-\f
-/* Set by `re_set_syntax' to the current regexp syntax to recognize.  Can
-   also be assigned to arbitrarily: each pattern buffer stores its own
-   syntax, so it can be changed between regex compilations.  */
-reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS;
-
-
-/* Specify the precise syntax of regexps for compilation.  This provides
-   for compatibility for various utilities which historically have
-   different, incompatible syntaxes.
-
-   The argument SYNTAX is a bit mask comprised of the various bits
-   defined in regex.h.  We return the old syntax.  */
-
-reg_syntax_t
-re_set_syntax (syntax)
-    reg_syntax_t syntax;
-{
-  reg_syntax_t ret = re_syntax_options;
-
-  re_syntax_options = syntax;
-  return ret;
-}
-\f
-/* This table gives an error message for each of the error codes listed
-   in regex.h.  Obviously the order here has to be same as there.  */
-
-static const char *re_error_msg[] =
-  { NULL,                                      /* REG_NOERROR */
-    "No match",                                        /* REG_NOMATCH */
-    "Invalid regular expression",              /* REG_BADPAT */
-    "Invalid collation character",             /* REG_ECOLLATE */
-    "Invalid character class name",            /* REG_ECTYPE */
-    "Trailing backslash",                      /* REG_EESCAPE */
-    "Invalid back reference",                  /* REG_ESUBREG */
-    "Unmatched [ or [^",                       /* REG_EBRACK */
-    "Unmatched ( or \\(",                      /* REG_EPAREN */
-    "Unmatched \\{",                           /* REG_EBRACE */
-    "Invalid content of \\{\\}",               /* REG_BADBR */
-    "Invalid range end",                       /* REG_ERANGE */
-    "Memory exhausted",                                /* REG_ESPACE */
-    "Invalid preceding regular expression",    /* REG_BADRPT */
-    "Premature end of regular expression",     /* REG_EEND */
-    "Regular expression too big",              /* REG_ESIZE */
-    "Unmatched ) or \\)",                      /* REG_ERPAREN */
-  };
-\f
-/* Subroutine declarations and macros for regex_compile.  */
-
-static void store_op1 (), store_op2 ();
-static void insert_op1 (), insert_op2 ();
-static boolean at_begline_loc_p (), at_endline_loc_p ();
-static boolean group_in_compile_stack ();
-static reg_errcode_t compile_range ();
-
-/* Fetch the next character in the uncompiled pattern---translating it
-   if necessary.  Also cast from a signed character in the constant
-   string passed to us by the user to an unsigned char that we can use
-   as an array index (in, e.g., `translate').  */
-#define PATFETCH(c)                                                    \
-  do {if (p == pend) return REG_EEND;                                  \
-    c = (unsigned char) *p++;                                          \
-    if (translate) c = translate[c];                                   \
-  } while (0)
-
-/* Fetch the next character in the uncompiled pattern, with no
-   translation.  */
-#define PATFETCH_RAW(c)                                                        \
-  do {if (p == pend) return REG_EEND;                                  \
-    c = (unsigned char) *p++;                                          \
-  } while (0)
-
-/* Go backwards one character in the pattern.  */
-#define PATUNFETCH p--
-
-
-/* If `translate' is non-null, return translate[D], else just D.  We
-   cast the subscript to translate because some data is declared as
-   `char *', to avoid warnings when a string constant is passed.  But
-   when we use a character as a subscript we must make it unsigned.  */
-#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d))
-
-
-/* Macros for outputting the compiled pattern into `buffer'.  */
-
-/* If the buffer isn't allocated when it comes in, use this.  */
-#define INIT_BUF_SIZE  32
-
-/* Make sure we have at least N more bytes of space in buffer.  */
-#define GET_BUFFER_SPACE(n)                                            \
-    while (b - bufp->buffer + (n) > bufp->allocated)                   \
-      EXTEND_BUFFER ()
-
-/* Make sure we have one more byte of buffer space and then add C to it.  */
-#define BUF_PUSH(c)                                                    \
-  do {                                                                 \
-    GET_BUFFER_SPACE (1);                                              \
-    *b++ = (unsigned char) (c);                                                \
-  } while (0)
-
-
-/* Ensure we have two more bytes of buffer space and then append C1 and C2.  */
-#define BUF_PUSH_2(c1, c2)                                             \
-  do {                                                                 \
-    GET_BUFFER_SPACE (2);                                              \
-    *b++ = (unsigned char) (c1);                                       \
-    *b++ = (unsigned char) (c2);                                       \
-  } while (0)
-
-
-/* As with BUF_PUSH_2, except for three bytes.  */
-#define BUF_PUSH_3(c1, c2, c3)                                         \
-  do {                                                                 \
-    GET_BUFFER_SPACE (3);                                              \
-    *b++ = (unsigned char) (c1);                                       \
-    *b++ = (unsigned char) (c2);                                       \
-    *b++ = (unsigned char) (c3);                                       \
-  } while (0)
-
-
-/* Store a jump with opcode OP at LOC to location TO.  We store a
-   relative address offset by the three bytes the jump itself occupies.  */
-#define STORE_JUMP(op, loc, to) \
-  store_op1 (op, loc, (to) - (loc) - 3)
-
-/* Likewise, for a two-argument jump.  */
-#define STORE_JUMP2(op, loc, to, arg) \
-  store_op2 (op, loc, (to) - (loc) - 3, arg)
-
-/* Like `STORE_JUMP', but for inserting.  Assume `b' is the buffer end.  */
-#define INSERT_JUMP(op, loc, to) \
-  insert_op1 (op, loc, (to) - (loc) - 3, b)
-
-/* Like `STORE_JUMP2', but for inserting.  Assume `b' is the buffer end.  */
-#define INSERT_JUMP2(op, loc, to, arg) \
-  insert_op2 (op, loc, (to) - (loc) - 3, arg, b)
-
-
-/* This is not an arbitrary limit: the arguments which represent offsets
-   into the pattern are two bytes long.  So if 2^16 bytes turns out to
-   be too small, many things would have to change.  */
-#define MAX_BUF_SIZE (1L << 16)
-
-
-/* Extend the buffer by twice its current size via realloc and
-   reset the pointers that pointed into the old block to point to the
-   correct places in the new one.  If extending the buffer results in it
-   being larger than MAX_BUF_SIZE, then flag memory exhausted.  */
-#define EXTEND_BUFFER()                                                        \
-  do {                                                                         \
-    unsigned char *old_buffer = bufp->buffer;                          \
-    if (bufp->allocated == MAX_BUF_SIZE)                               \
-      return REG_ESIZE;                                                        \
-    bufp->allocated <<= 1;                                             \
-    if (bufp->allocated > MAX_BUF_SIZE)                                        \
-      bufp->allocated = MAX_BUF_SIZE;                                  \
-    bufp->buffer = (unsigned char *) realloc (bufp->buffer, bufp->allocated);\
-    if (bufp->buffer == NULL)                                          \
-      return REG_ESPACE;                                               \
-    /* If the buffer moved, move all the pointers into it.  */         \
-    if (old_buffer != bufp->buffer)                                    \
-      {                                                                        \
-       b = (b - old_buffer) + bufp->buffer;                            \
-       begalt = (begalt - old_buffer) + bufp->buffer;                  \
-       if (fixup_alt_jump)                                             \
-         fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\
-       if (laststart)                                                  \
-         laststart = (laststart - old_buffer) + bufp->buffer;          \
-       if (pending_exact)                                              \
-         pending_exact = (pending_exact - old_buffer) + bufp->buffer;  \
-      }                                                                        \
-  } while (0)
-
-
-/* Since we have one byte reserved for the register number argument to
-   {start,stop}_memory, the maximum number of groups we can report
-   things about is what fits in that byte.  */
-#define MAX_REGNUM 255
-
-/* But patterns can have more than `MAX_REGNUM' registers.  We just
-   ignore the excess.  */
-typedef unsigned regnum_t;
-
-
-/* Macros for the compile stack.  */
-
-/* Since offsets can go either forwards or backwards, this type needs to
-   be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1.  */
-typedef int pattern_offset_t;
-
-typedef struct
-{
-  pattern_offset_t begalt_offset;
-  pattern_offset_t fixup_alt_jump;
-  pattern_offset_t inner_group_offset;
-  pattern_offset_t laststart_offset;
-  regnum_t regnum;
-} compile_stack_elt_t;
-
-
-typedef struct
-{
-  compile_stack_elt_t *stack;
-  unsigned size;
-  unsigned avail;                      /* Offset of next open position.  */
-} compile_stack_type;
-
-
-#define INIT_COMPILE_STACK_SIZE 32
-
-#define COMPILE_STACK_EMPTY  (compile_stack.avail == 0)
-#define COMPILE_STACK_FULL  (compile_stack.avail == compile_stack.size)
-
-/* The next available element.  */
-#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
-
-
-/* Set the bit for character C in a list.  */
-#define SET_LIST_BIT(c)                               \
-  (b[((unsigned char) (c)) / BYTEWIDTH]               \
-   |= 1 << (((unsigned char) c) % BYTEWIDTH))
-
-
-/* Get the next unsigned number in the uncompiled pattern.  */
-#define GET_UNSIGNED_NUMBER(num)                                       \
-  { if (p != pend)                                                     \
-     {                                                                 \
-       PATFETCH (c);                                                   \
-       while (ISDIGIT (c))                                             \
-        {                                                              \
-          if (num < 0)                                                 \
-             num = 0;                                                  \
-          num = num * 10 + c - '0';                                    \
-          if (p == pend)                                               \
-             break;                                                    \
-          PATFETCH (c);                                                \
-        }                                                              \
-       }                                                               \
-    }
-
-#define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
-
-#define IS_CHAR_CLASS(string)                                          \
-   (STREQ (string, "alpha") || STREQ (string, "upper")                 \
-    || STREQ (string, "lower") || STREQ (string, "digit")              \
-    || STREQ (string, "alnum") || STREQ (string, "xdigit")             \
-    || STREQ (string, "space") || STREQ (string, "print")              \
-    || STREQ (string, "punct") || STREQ (string, "graph")              \
-    || STREQ (string, "cntrl") || STREQ (string, "blank"))
-\f
-/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
-   Returns one of error codes defined in `regex.h', or zero for success.
-
-   Assumes the `allocated' (and perhaps `buffer') and `translate'
-   fields are set in BUFP on entry.
-
-   If it succeeds, results are put in BUFP (if it returns an error, the
-   contents of BUFP are undefined):
-     `buffer' is the compiled pattern;
-     `syntax' is set to SYNTAX;
-     `used' is set to the length of the compiled pattern;
-     `fastmap_accurate' is zero;
-     `re_nsub' is the number of subexpressions in PATTERN;
-     `not_bol' and `not_eol' are zero;
-
-   The `fastmap' and `newline_anchor' fields are neither
-   examined nor set.  */
-
-static reg_errcode_t
-regex_compile (pattern, size, syntax, bufp)
-     const char *pattern;
-     int size;
-     reg_syntax_t syntax;
-     struct re_pattern_buffer *bufp;
-{
-  /* We fetch characters from PATTERN here.  Even though PATTERN is
-     `char *' (i.e., signed), we declare these variables as unsigned, so
-     they can be reliably used as array indices.  */
-  register unsigned char c, c1;
-
-  /* A random tempory spot in PATTERN.  */
-  const char *p1;
-
-  /* Points to the end of the buffer, where we should append.  */
-  register unsigned char *b;
-
-  /* Keeps track of unclosed groups.  */
-  compile_stack_type compile_stack;
-
-  /* Points to the current (ending) position in the pattern.  */
-  const char *p = pattern;
-  const char *pend = pattern + size;
-
-  /* How to translate the characters in the pattern.  */
-  char *translate = bufp->translate;
-
-  /* Address of the count-byte of the most recently inserted `exactn'
-     command.  This makes it possible to tell if a new exact-match
-     character can be added to that command or if the character requires
-     a new `exactn' command.  */
-  unsigned char *pending_exact = 0;
-
-  /* Address of start of the most recently finished expression.
-     This tells, e.g., postfix * where to find the start of its
-     operand.  Reset at the beginning of groups and alternatives.  */
-  unsigned char *laststart = 0;
-
-  /* Address of beginning of regexp, or inside of last group.  */
-  unsigned char *begalt;
-
-  /* Place in the uncompiled pattern (i.e., the {) to
-     which to go back if the interval is invalid.  */
-  const char *beg_interval;
-
-  /* Address of the place where a forward jump should go to the end of
-     the containing expression.  Each alternative of an `or' -- except the
-     last -- ends with a forward jump of this sort.  */
-  unsigned char *fixup_alt_jump = 0;
-
-  /* Counts open-groups as they are encountered.  Remembered for the
-     matching close-group on the compile stack, so the same register
-     number is put in the stop_memory as the start_memory.  */
-  regnum_t regnum = 0;
-
-#ifdef DEBUG
-  DEBUG_PRINT1 ("\nCompiling pattern: ");
-  if (debug)
-    {
-      unsigned debug_count;
-
-      for (debug_count = 0; debug_count < size; debug_count++)
-       printchar (pattern[debug_count]);
-      putchar ('\n');
-    }
-#endif /* DEBUG */
-
-  /* Initialize the compile stack.  */
-  compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t);
-  if (compile_stack.stack == NULL)
-    return REG_ESPACE;
-
-  compile_stack.size = INIT_COMPILE_STACK_SIZE;
-  compile_stack.avail = 0;
-
-  /* Initialize the pattern buffer.  */
-  bufp->syntax = syntax;
-  bufp->fastmap_accurate = 0;
-  bufp->not_bol = bufp->not_eol = 0;
-
-  /* Set `used' to zero, so that if we return an error, the pattern
-     printer (for debugging) will think there's no pattern.  We reset it
-     at the end.  */
-  bufp->used = 0;
-
-  /* Always count groups, whether or not bufp->no_sub is set.  */
-  bufp->re_nsub = 0;
-
-#if !defined (emacs) && !defined (SYNTAX_TABLE)
-  /* Initialize the syntax table.  */
-   init_syntax_once ();
-#endif
-
-  if (bufp->allocated == 0)
-    {
-      if (bufp->buffer)
-       { /* If zero allocated, but buffer is non-null, try to realloc
-            enough space.  This loses if buffer's address is bogus, but
-            that is the user's responsibility.  */
-         RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char);
-       }
-      else
-       { /* Caller did not allocate a buffer.  Do it for them.  */
-         bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char);
-       }
-      if (!bufp->buffer) return REG_ESPACE;
-
-      bufp->allocated = INIT_BUF_SIZE;
-    }
-
-  begalt = b = bufp->buffer;
-
-  /* Loop through the uncompiled pattern until we're at the end.  */
-  while (p != pend)
-    {
-      PATFETCH (c);
-
-      switch (c)
-       {
-       case '^':
-         {
-           if (   /* If at start of pattern, it's an operator.  */
-                  p == pattern + 1
-                  /* If context independent, it's an operator.  */
-               || syntax & RE_CONTEXT_INDEP_ANCHORS
-                  /* Otherwise, depends on what's come before.  */
-               || at_begline_loc_p (pattern, p, syntax))
-             BUF_PUSH (begline);
-           else
-             goto normal_char;
-         }
-         break;
-
-
-       case '$':
-         {
-           if (   /* If at end of pattern, it's an operator.  */
-                  p == pend
-                  /* If context independent, it's an operator.  */
-               || syntax & RE_CONTEXT_INDEP_ANCHORS
-                  /* Otherwise, depends on what's next.  */
-               || at_endline_loc_p (p, pend, syntax))
-              BUF_PUSH (endline);
-            else
-              goto normal_char;
-          }
-          break;
-
-
-       case '+':
-       case '?':
-         if ((syntax & RE_BK_PLUS_QM)
-             || (syntax & RE_LIMITED_OPS))
-           goto normal_char;
-       handle_plus:
-       case '*':
-         /* If there is no previous pattern... */
-         if (!laststart)
-           {
-             if (syntax & RE_CONTEXT_INVALID_OPS)
-               return REG_BADRPT;
-             else if (!(syntax & RE_CONTEXT_INDEP_OPS))
-               goto normal_char;
-           }
-
-         {
-           /* Are we optimizing this jump?  */
-           boolean keep_string_p = false;
-
-           /* 1 means zero (many) matches is allowed.  */
-           char zero_times_ok = 0, many_times_ok = 0;
-
-           /* If there is a sequence of repetition chars, collapse it
-              down to just one (the right one).  We can't combine
-              interval operators with these because of, e.g., `a{2}*',
-              which should only match an even number of `a's.  */
-
-           for (;;)
-             {
-               zero_times_ok |= c != '+';
-               many_times_ok |= c != '?';
-
-               if (p == pend)
-                 break;
-
-               PATFETCH (c);
-
-               if (c == '*'
-                   || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
-                 ;
-
-               else if (syntax & RE_BK_PLUS_QM  &&  c == '\\')
-                 {
-                   if (p == pend) return REG_EESCAPE;
-
-                   PATFETCH (c1);
-                   if (!(c1 == '+' || c1 == '?'))
-                     {
-                       PATUNFETCH;
-                       PATUNFETCH;
-                       break;
-                     }
-
-                   c = c1;
-                 }
-               else
-                 {
-                   PATUNFETCH;
-                   break;
-                 }
-
-               /* If we get here, we found another repeat character.  */
-              }
-
-           /* Star, etc. applied to an empty pattern is equivalent
-              to an empty pattern.  */
-           if (!laststart)
-             break;
-
-           /* Now we know whether or not zero matches is allowed
-              and also whether or not two or more matches is allowed.  */
-           if (many_times_ok)
-             { /* More than one repetition is allowed, so put in at the
-                  end a backward relative jump from `b' to before the next
-                  jump we're going to put in below (which jumps from
-                  laststart to after this jump).
-
-                  But if we are at the `*' in the exact sequence `.*\n',
-                  insert an unconditional jump backwards to the .,
-                  instead of the beginning of the loop.  This way we only
-                  push a failure point once, instead of every time
-                  through the loop.  */
-               assert (p - 1 > pattern);
-
-               /* Allocate the space for the jump.  */
-               GET_BUFFER_SPACE (3);
-
-               /* We know we are not at the first character of the pattern,
-                  because laststart was nonzero.  And we've already
-                  incremented `p', by the way, to be the character after
-                  the `*'.  Do we have to do something analogous here
-                  for null bytes, because of RE_DOT_NOT_NULL?  */
-               if (TRANSLATE (*(p - 2)) == TRANSLATE ('.')
-                   && zero_times_ok
-                   && p < pend && TRANSLATE (*p) == TRANSLATE ('\n')
-                   && !(syntax & RE_DOT_NEWLINE))
-                 { /* We have .*\n.  */
-                   STORE_JUMP (jump, b, laststart);
-                   keep_string_p = true;
-                 }
-               else
-                 /* Anything else.  */
-                 STORE_JUMP (maybe_pop_jump, b, laststart - 3);
-
-               /* We've added more stuff to the buffer.  */
-               b += 3;
-             }
-
-           /* On failure, jump from laststart to b + 3, which will be the
-              end of the buffer after this jump is inserted.  */
-           GET_BUFFER_SPACE (3);
-           INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump
-                                      : on_failure_jump,
-                        laststart, b + 3);
-           pending_exact = 0;
-           b += 3;
-
-           if (!zero_times_ok)
-             {
-               /* At least one repetition is required, so insert a
-                  `dummy_failure_jump' before the initial
-                  `on_failure_jump' instruction of the loop. This
-                  effects a skip over that instruction the first time
-                  we hit that loop.  */
-               GET_BUFFER_SPACE (3);
-               INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6);
-               b += 3;
-             }
-           }
-         break;
-
-
-       case '.':
-         laststart = b;
-         BUF_PUSH (anychar);
-         break;
-
-
-       case '[':
-         {
-           boolean had_char_class = false;
-
-           if (p == pend) return REG_EBRACK;
-
-           /* Ensure that we have enough space to push a charset: the
-              opcode, the length count, and the bitset; 34 bytes in all.  */
-           GET_BUFFER_SPACE (34);
-
-           laststart = b;
-
-           /* We test `*p == '^' twice, instead of using an if
-              statement, so we only need one BUF_PUSH.  */
-           BUF_PUSH (*p == '^' ? charset_not : charset);
-           if (*p == '^')
-             p++;
-
-           /* Remember the first position in the bracket expression.  */
-           p1 = p;
-
-           /* Push the number of bytes in the bitmap.  */
-           BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
-
-           /* Clear the whole map.  */
-           bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
-
-           /* charset_not matches newline according to a syntax bit.  */
-           if ((re_opcode_t) b[-2] == charset_not
-               && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
-             SET_LIST_BIT ('\n');
-
-           /* Read in characters and ranges, setting map bits.  */
-           for (;;)
-             {
-               if (p == pend) return REG_EBRACK;
-
-               PATFETCH (c);
-
-               /* \ might escape characters inside [...] and [^...].  */
-               if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
-                 {
-                   if (p == pend) return REG_EESCAPE;
-
-                   PATFETCH (c1);
-                   SET_LIST_BIT (c1);
-                   continue;
-                 }
-
-               /* Could be the end of the bracket expression.  If it's
-                  not (i.e., when the bracket expression is `[]' so
-                  far), the ']' character bit gets set way below.  */
-               if (c == ']' && p != p1 + 1)
-                 break;
-
-               /* Look ahead to see if it's a range when the last thing
-                  was a character class.  */
-               if (had_char_class && c == '-' && *p != ']')
-                 return REG_ERANGE;
-
-               /* Look ahead to see if it's a range when the last thing
-                  was a character: if this is a hyphen not at the
-                  beginning or the end of a list, then it's the range
-                  operator.  */
-               if (c == '-'
-                   && !(p - 2 >= pattern && p[-2] == '[')
-                   && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
-                   && *p != ']')
-                 {
-                   reg_errcode_t ret
-                     = compile_range (&p, pend, translate, syntax, b);
-                   if (ret != REG_NOERROR) return ret;
-                 }
-
-               else if (p[0] == '-' && p[1] != ']')
-                 { /* This handles ranges made up of characters only.  */
-                   reg_errcode_t ret;
-
-                   /* Move past the `-'.  */
-                   PATFETCH (c1);
-
-                   ret = compile_range (&p, pend, translate, syntax, b);
-                   if (ret != REG_NOERROR) return ret;
-                 }
-
-               /* See if we're at the beginning of a possible character
-                  class.  */
-
-               else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
-                 { /* Leave room for the null.  */
-                   char str[CHAR_CLASS_MAX_LENGTH + 1];
-
-                   PATFETCH (c);
-                   c1 = 0;
-
-                   /* If pattern is `[[:'.  */
-                   if (p == pend) return REG_EBRACK;
-
-                   for (;;)
-                     {
-                       PATFETCH (c);
-                       if (c == ':' || c == ']' || p == pend
-                           || c1 == CHAR_CLASS_MAX_LENGTH)
-                         break;
-                       str[c1++] = c;
-                     }
-                   str[c1] = '\0';
-
-                   /* If isn't a word bracketed by `[:' and:`]':
-                      undo the ending character, the letters, and leave
-                      the leading `:' and `[' (but set bits for them).  */
-                   if (c == ':' && *p == ']')
-                     {
-                       int ch;
-                       boolean is_alnum = STREQ (str, "alnum");
-                       boolean is_alpha = STREQ (str, "alpha");
-                       boolean is_blank = STREQ (str, "blank");
-                       boolean is_cntrl = STREQ (str, "cntrl");
-                       boolean is_digit = STREQ (str, "digit");
-                       boolean is_graph = STREQ (str, "graph");
-                       boolean is_lower = STREQ (str, "lower");
-                       boolean is_print = STREQ (str, "print");
-                       boolean is_punct = STREQ (str, "punct");
-                       boolean is_space = STREQ (str, "space");
-                       boolean is_upper = STREQ (str, "upper");
-                       boolean is_xdigit = STREQ (str, "xdigit");
-
-                       if (!IS_CHAR_CLASS (str)) return REG_ECTYPE;
-
-                       /* Throw away the ] at the end of the character
-                          class.  */
-                       PATFETCH (c);
-
-                       if (p == pend) return REG_EBRACK;
-
-                       for (ch = 0; ch < 1 << BYTEWIDTH; ch++)
-                         {
-                           if (   (is_alnum  && ISALNUM (ch))
-                               || (is_alpha  && ISALPHA (ch))
-                               || (is_blank  && ISBLANK (ch))
-                               || (is_cntrl  && ISCNTRL (ch))
-                               || (is_digit  && ISDIGIT (ch))
-                               || (is_graph  && ISGRAPH (ch))
-                               || (is_lower  && ISLOWER (ch))
-                               || (is_print  && ISPRINT (ch))
-                               || (is_punct  && ISPUNCT (ch))
-                               || (is_space  && ISSPACE (ch))
-                               || (is_upper  && ISUPPER (ch))
-                               || (is_xdigit && ISXDIGIT (ch)))
-                           SET_LIST_BIT (ch);
-                         }
-                       had_char_class = true;
-                     }
-                   else
-                     {
-                       c1++;
-                       while (c1--)
-                         PATUNFETCH;
-                       SET_LIST_BIT ('[');
-                       SET_LIST_BIT (':');
-                       had_char_class = false;
-                     }
-                 }
-               else
-                 {
-                   had_char_class = false;
-                   SET_LIST_BIT (c);
-                 }
-             }
-
-           /* Discard any (non)matching list bytes that are all 0 at the
-              end of the map.  Decrease the map-length byte too.  */
-           while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
-             b[-1]--;
-           b += b[-1];
-         }
-         break;
-
-
-       case '(':
-         if (syntax & RE_NO_BK_PARENS)
-           goto handle_open;
-         else
-           goto normal_char;
-
-
-       case ')':
-         if (syntax & RE_NO_BK_PARENS)
-           goto handle_close;
-         else
-           goto normal_char;
-
-
-       case '\n':
-         if (syntax & RE_NEWLINE_ALT)
-           goto handle_alt;
-         else
-           goto normal_char;
-
-
-       case '|':
-         if (syntax & RE_NO_BK_VBAR)
-           goto handle_alt;
-         else
-           goto normal_char;
-
-
-       case '{':
-          if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES)
-            goto handle_interval;
-          else
-            goto normal_char;
-
-
-       case '\\':
-         if (p == pend) return REG_EESCAPE;
-
-         /* Do not translate the character after the \, so that we can
-            distinguish, e.g., \B from \b, even if we normally would
-            translate, e.g., B to b.  */
-         PATFETCH_RAW (c);
-
-         switch (c)
-           {
-           case '(':
-             if (syntax & RE_NO_BK_PARENS)
-               goto normal_backslash;
-
-           handle_open:
-             bufp->re_nsub++;
-             regnum++;
-
-             if (COMPILE_STACK_FULL)
-               {
-                 RETALLOC (compile_stack.stack, compile_stack.size << 1,
-                           compile_stack_elt_t);
-                 if (compile_stack.stack == NULL) return REG_ESPACE;
-
-                 compile_stack.size <<= 1;
-               }
-
-             /* These are the values to restore when we hit end of this
-                group.  They are all relative offsets, so that if the
-                whole pattern moves because of realloc, they will still
-                be valid.  */
-             COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer;
-             COMPILE_STACK_TOP.fixup_alt_jump
-               = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0;
-             COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer;
-             COMPILE_STACK_TOP.regnum = regnum;
-
-             /* We will eventually replace the 0 with the number of
-                groups inner to this one.  But do not push a
-                start_memory for groups beyond the last one we can
-                represent in the compiled pattern.  */
-             if (regnum <= MAX_REGNUM)
-               {
-                 COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2;
-                 BUF_PUSH_3 (start_memory, regnum, 0);
-               }
-
-             compile_stack.avail++;
-
-             fixup_alt_jump = 0;
-             laststart = 0;
-             begalt = b;
-             /* If we've reached MAX_REGNUM groups, then this open
-                won't actually generate any code, so we'll have to
-                clear pending_exact explicitly.  */
-             pending_exact = 0;
-             break;
-
-
-           case ')':
-             if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
-
-             if (COMPILE_STACK_EMPTY)
-             {
-               if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
-                 goto normal_backslash;
-               else
-                 return REG_ERPAREN;
-             }
-
-           handle_close:
-             if (fixup_alt_jump)
-               { /* Push a dummy failure point at the end of the
-                    alternative for a possible future
-                    `pop_failure_jump' to pop.  See comments at
-                    `push_dummy_failure' in `re_match_2'.  */
-                 BUF_PUSH (push_dummy_failure);
-
-                 /* We allocated space for this jump when we assigned
-                    to `fixup_alt_jump', in the `handle_alt' case below.  */
-                 STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1);
-               }
-
-             /* See similar code for backslashed left paren above.  */
-             if (COMPILE_STACK_EMPTY)
-             {
-               if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
-                 goto normal_char;
-               else
-                 return REG_ERPAREN;
-             }
-
-             /* Since we just checked for an empty stack above, this
-                ``can't happen''.  */
-             assert (compile_stack.avail != 0);
-             {
-               /* We don't just want to restore into `regnum', because
-                  later groups should continue to be numbered higher,
-                  as in `(ab)c(de)' -- the second group is #2.  */
-               regnum_t this_group_regnum;
-
-               compile_stack.avail--;
-               begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset;
-               fixup_alt_jump
-                 = COMPILE_STACK_TOP.fixup_alt_jump
-                   ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1
-                   : 0;
-               laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset;
-               this_group_regnum = COMPILE_STACK_TOP.regnum;
-               /* If we've reached MAX_REGNUM groups, then this open
-                  won't actually generate any code, so we'll have to
-                  clear pending_exact explicitly.  */
-               pending_exact = 0;
-
-               /* We're at the end of the group, so now we know how many
-                  groups were inside this one.  */
-               if (this_group_regnum <= MAX_REGNUM)
-                 {
-                   unsigned char *inner_group_loc
-                     = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset;
-
-                   *inner_group_loc = regnum - this_group_regnum;
-                   BUF_PUSH_3 (stop_memory, this_group_regnum,
-                               regnum - this_group_regnum);
-                 }
-             }
-             break;
-
-
-           case '|':                                   /* `\|'.  */
-             if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR)
-               goto normal_backslash;
-           handle_alt:
-             if (syntax & RE_LIMITED_OPS)
-               goto normal_char;
-
-             /* Insert before the previous alternative a jump which
-                jumps to this alternative if the former fails.  */
-             GET_BUFFER_SPACE (3);
-             INSERT_JUMP (on_failure_jump, begalt, b + 6);
-             pending_exact = 0;
-             b += 3;
-
-             /* The alternative before this one has a jump after it
-                which gets executed if it gets matched.  Adjust that
-                jump so it will jump to this alternative's analogous
-                jump (put in below, which in turn will jump to the next
-                (if any) alternative's such jump, etc.).  The last such
-                jump jumps to the correct final destination.  A picture:
-                         _____ _____
-                         |   | |   |
-                         |   v |   v
-                        a | b   | c
-
-                If we are at `b', then fixup_alt_jump right now points to a
-                three-byte space after `a'.  We'll put in the jump, set
-                fixup_alt_jump to right after `b', and leave behind three
-                bytes which we'll fill in when we get to after `c'.  */
-
-             if (fixup_alt_jump)
-               STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
-
-             /* Mark and leave space for a jump after this alternative,
-                to be filled in later either by next alternative or
-                when know we're at the end of a series of alternatives.  */
-             fixup_alt_jump = b;
-             GET_BUFFER_SPACE (3);
-             b += 3;
-
-             laststart = 0;
-             begalt = b;
-             break;
-
-
-           case '{':
-             /* If \{ is a literal.  */
-             if (!(syntax & RE_INTERVALS)
-                    /* If we're at `\{' and it's not the open-interval
-                       operator.  */
-                 || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
-                 || (p - 2 == pattern  &&  p == pend))
-               goto normal_backslash;
-
-           handle_interval:
-             {
-               /* If got here, then the syntax allows intervals.  */
-
-               /* At least (most) this many matches must be made.  */
-               int lower_bound = -1, upper_bound = -1;
-
-               beg_interval = p - 1;
-
-               if (p == pend)
-                 {
-                   if (syntax & RE_NO_BK_BRACES)
-                     goto unfetch_interval;
-                   else
-                     return REG_EBRACE;
-                 }
-
-               GET_UNSIGNED_NUMBER (lower_bound);
-
-               if (c == ',')
-                 {
-                   GET_UNSIGNED_NUMBER (upper_bound);
-                   if (upper_bound < 0) upper_bound = RE_DUP_MAX;
-                 }
-               else
-                 /* Interval such as `{1}' => match exactly once. */
-                 upper_bound = lower_bound;
-
-               if (lower_bound < 0 || upper_bound > RE_DUP_MAX
-                   || lower_bound > upper_bound)
-                 {
-                   if (syntax & RE_NO_BK_BRACES)
-                     goto unfetch_interval;
-                   else
-                     return REG_BADBR;
-                 }
-
-               if (!(syntax & RE_NO_BK_BRACES))
-                 {
-                   if (c != '\\') return REG_EBRACE;
-
-                   PATFETCH (c);
-                 }
-
-               if (c != '}')
-                 {
-                   if (syntax & RE_NO_BK_BRACES)
-                     goto unfetch_interval;
-                   else
-                     return REG_BADBR;
-                 }
-
-               /* We just parsed a valid interval.  */
-
-               /* If it's invalid to have no preceding re.  */
-               if (!laststart)
-                 {
-                   if (syntax & RE_CONTEXT_INVALID_OPS)
-                     return REG_BADRPT;
-                   else if (syntax & RE_CONTEXT_INDEP_OPS)
-                     laststart = b;
-                   else
-                     goto unfetch_interval;
-                 }
-
-               /* If the upper bound is zero, don't want to succeed at
-                  all; jump from `laststart' to `b + 3', which will be
-                  the end of the buffer after we insert the jump.  */
-                if (upper_bound == 0)
-                  {
-                    GET_BUFFER_SPACE (3);
-                    INSERT_JUMP (jump, laststart, b + 3);
-                    b += 3;
-                  }
-
-                /* Otherwise, we have a nontrivial interval.  When
-                   we're all done, the pattern will look like:
-                     set_number_at <jump count> <upper bound>
-                     set_number_at <succeed_n count> <lower bound>
-                     succeed_n <after jump addr> <succed_n count>
-                     <body of loop>
-                     jump_n <succeed_n addr> <jump count>
-                   (The upper bound and `jump_n' are omitted if
-                   `upper_bound' is 1, though.)  */
-                else
-                  { /* If the upper bound is > 1, we need to insert
-                       more at the end of the loop.  */
-                    unsigned nbytes = 10 + (upper_bound > 1) * 10;
-
-                    GET_BUFFER_SPACE (nbytes);
-
-                    /* Initialize lower bound of the `succeed_n', even
-                       though it will be set during matching by its
-                       attendant `set_number_at' (inserted next),
-                       because `re_compile_fastmap' needs to know.
-                       Jump to the `jump_n' we might insert below.  */
-                    INSERT_JUMP2 (succeed_n, laststart,
-                                  b + 5 + (upper_bound > 1) * 5,
-                                  lower_bound);
-                    b += 5;
-
-                    /* Code to initialize the lower bound.  Insert
-                       before the `succeed_n'.  The `5' is the last two
-                       bytes of this `set_number_at', plus 3 bytes of
-                       the following `succeed_n'.  */
-                    insert_op2 (set_number_at, laststart, 5, lower_bound, b);
-                    b += 5;
-
-                    if (upper_bound > 1)
-                      { /* More than one repetition is allowed, so
-                           append a backward jump to the `succeed_n'
-                           that starts this interval.
-
-                           When we've reached this during matching,
-                           we'll have matched the interval once, so
-                           jump back only `upper_bound - 1' times.  */
-                        STORE_JUMP2 (jump_n, b, laststart + 5,
-                                     upper_bound - 1);
-                        b += 5;
-
-                        /* The location we want to set is the second
-                           parameter of the `jump_n'; that is `b-2' as
-                           an absolute address.  `laststart' will be
-                           the `set_number_at' we're about to insert;
-                           `laststart+3' the number to set, the source
-                           for the relative address.  But we are
-                           inserting into the middle of the pattern --
-                           so everything is getting moved up by 5.
-                           Conclusion: (b - 2) - (laststart + 3) + 5,
-                           i.e., b - laststart.
-
-                           We insert this at the beginning of the loop
-                           so that if we fail during matching, we'll
-                           reinitialize the bounds.  */
-                        insert_op2 (set_number_at, laststart, b - laststart,
-                                    upper_bound - 1, b);
-                        b += 5;
-                      }
-                  }
-               pending_exact = 0;
-               beg_interval = NULL;
-             }
-             break;
-
-           unfetch_interval:
-             /* If an invalid interval, match the characters as literals.  */
-              assert (beg_interval);
-              p = beg_interval;
-              beg_interval = NULL;
-
-              /* normal_char and normal_backslash need `c'.  */
-              PATFETCH (c);
-
-              if (!(syntax & RE_NO_BK_BRACES))
-                {
-                  if (p > pattern  &&  p[-1] == '\\')
-                    goto normal_backslash;
-                }
-              goto normal_char;
-
-#ifdef emacs
-           /* There is no way to specify the before_dot and after_dot
-              operators.  rms says this is ok.  --karl  */
-           case '=':
-             BUF_PUSH (at_dot);
-             break;
-
-           case 's':
-             laststart = b;
-             PATFETCH (c);
-             BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]);
-             break;
-
-           case 'S':
-             laststart = b;
-             PATFETCH (c);
-             BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
-             break;
-#endif /* emacs */
-
-
-           case 'w':
-             laststart = b;
-             BUF_PUSH (wordchar);
-             break;
-
-
-           case 'W':
-             laststart = b;
-             BUF_PUSH (notwordchar);
-             break;
-
-
-           case '<':
-             BUF_PUSH (wordbeg);
-             break;
-
-           case '>':
-             BUF_PUSH (wordend);
-             break;
-
-           case 'b':
-             BUF_PUSH (wordbound);
-             break;
-
-           case 'B':
-             BUF_PUSH (notwordbound);
-             break;
-
-           case '`':
-             BUF_PUSH (begbuf);
-             break;
-
-           case '\'':
-             BUF_PUSH (endbuf);
-             break;
-
-           case '1': case '2': case '3': case '4': case '5':
-           case '6': case '7': case '8': case '9':
-             if (syntax & RE_NO_BK_REFS)
-               goto normal_char;
-
-             c1 = c - '0';
-
-             if (c1 > regnum)
-               return REG_ESUBREG;
-
-             /* Can't back reference to a subexpression if inside of it.  */
-             if (group_in_compile_stack (compile_stack, c1))
-               goto normal_char;
-
-             laststart = b;
-             BUF_PUSH_2 (duplicate, c1);
-             break;
-
-
-           case '+':
-           case '?':
-             if (syntax & RE_BK_PLUS_QM)
-               goto handle_plus;
-             else
-               goto normal_backslash;
-
-           default:
-           normal_backslash:
-             /* You might think it would be useful for \ to mean
-                not to translate; but if we don't translate it
-                it will never match anything.  */
-             c = TRANSLATE (c);
-             goto normal_char;
-           }
-         break;
-
-
-       default:
-       /* Expects the character in `c'.  */
-       normal_char:
-             /* If no exactn currently being built.  */
-         if (!pending_exact
-
-             /* If last exactn not at current position.  */
-             || pending_exact + *pending_exact + 1 != b
-
-             /* We have only one byte following the exactn for the count.  */
-             || *pending_exact == (1 << BYTEWIDTH) - 1
-
-             /* If followed by a repetition operator.  */
-             || *p == '*' || *p == '^'
-             || ((syntax & RE_BK_PLUS_QM)
-                 ? *p == '\\' && (p[1] == '+' || p[1] == '?')
-                 : (*p == '+' || *p == '?'))
-             || ((syntax & RE_INTERVALS)
-                 && ((syntax & RE_NO_BK_BRACES)
-                     ? *p == '{'
-                     : (p[0] == '\\' && p[1] == '{'))))
-           {
-             /* Start building a new exactn.  */
-
-             laststart = b;
-
-             BUF_PUSH_2 (exactn, 0);
-             pending_exact = b - 1;
-           }
-
-         BUF_PUSH (c);
-         (*pending_exact)++;
-         break;
-       } /* switch (c) */
-    } /* while p != pend */
-
-
-  /* Through the pattern now.  */
-
-  if (fixup_alt_jump)
-    STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
-
-  if (!COMPILE_STACK_EMPTY)
-    return REG_EPAREN;
-
-  free (compile_stack.stack);
-
-  /* We have succeeded; set the length of the buffer.  */
-  bufp->used = b - bufp->buffer;
-
-#ifdef DEBUG
-  if (debug)
-    {
-      DEBUG_PRINT1 ("\nCompiled pattern: ");
-      print_compiled_pattern (bufp);
-    }
-#endif /* DEBUG */
-
-  return REG_NOERROR;
-} /* regex_compile */
-\f
-/* Subroutines for `regex_compile'.  */
-
-/* Store OP at LOC followed by two-byte integer parameter ARG.  */
-
-static void
-store_op1 (op, loc, arg)
-    re_opcode_t op;
-    unsigned char *loc;
-    int arg;
-{
-  *loc = (unsigned char) op;
-  STORE_NUMBER (loc + 1, arg);
-}
-
-
-/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2.  */
-
-static void
-store_op2 (op, loc, arg1, arg2)
-    re_opcode_t op;
-    unsigned char *loc;
-    int arg1, arg2;
-{
-  *loc = (unsigned char) op;
-  STORE_NUMBER (loc + 1, arg1);
-  STORE_NUMBER (loc + 3, arg2);
-}
-
-
-/* Copy the bytes from LOC to END to open up three bytes of space at LOC
-   for OP followed by two-byte integer parameter ARG.  */
-
-static void
-insert_op1 (op, loc, arg, end)
-    re_opcode_t op;
-    unsigned char *loc;
-    int arg;
-    unsigned char *end;
-{
-  register unsigned char *pfrom = end;
-  register unsigned char *pto = end + 3;
-
-  while (pfrom != loc)
-    *--pto = *--pfrom;
-
-  store_op1 (op, loc, arg);
-}
-
-
-/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2.  */
-
-static void
-insert_op2 (op, loc, arg1, arg2, end)
-    re_opcode_t op;
-    unsigned char *loc;
-    int arg1, arg2;
-    unsigned char *end;
-{
-  register unsigned char *pfrom = end;
-  register unsigned char *pto = end + 5;
-
-  while (pfrom != loc)
-    *--pto = *--pfrom;
-
-  store_op2 (op, loc, arg1, arg2);
-}
-
-
-/* P points to just after a ^ in PATTERN.  Return true if that ^ comes
-   after an alternative or a begin-subexpression.  We assume there is at
-   least one character before the ^.  */
-
-static boolean
-at_begline_loc_p (pattern, p, syntax)
-    const char *pattern, *p;
-    reg_syntax_t syntax;
-{
-  const char *prev = p - 2;
-  boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
-
-  return
-       /* After a subexpression?  */
-       (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash))
-       /* After an alternative?  */
-    || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash));
-}
-
-
-/* The dual of at_begline_loc_p.  This one is for $.  We assume there is
-   at least one character after the $, i.e., `P < PEND'.  */
-
-static boolean
-at_endline_loc_p (p, pend, syntax)
-    const char *p, *pend;
-    int syntax;
-{
-  const char *next = p;
-  boolean next_backslash = *next == '\\';
-  const char *next_next = p + 1 < pend ? p + 1 : NULL;
-
-  return
-       /* Before a subexpression?  */
-       (syntax & RE_NO_BK_PARENS ? *next == ')'
-       : next_backslash && next_next && *next_next == ')')
-       /* Before an alternative?  */
-    || (syntax & RE_NO_BK_VBAR ? *next == '|'
-       : next_backslash && next_next && *next_next == '|');
-}
-
-
-/* Returns true if REGNUM is in one of COMPILE_STACK's elements and
-   false if it's not.  */
-
-static boolean
-group_in_compile_stack (compile_stack, regnum)
-    compile_stack_type compile_stack;
-    regnum_t regnum;
-{
-  int this_element;
-
-  for (this_element = compile_stack.avail - 1;
-       this_element >= 0;
-       this_element--)
-    if (compile_stack.stack[this_element].regnum == regnum)
-      return true;
-
-  return false;
-}
-
-
-/* Read the ending character of a range (in a bracket expression) from the
-   uncompiled pattern *P_PTR (which ends at PEND).  We assume the
-   starting character is in `P[-2]'.  (`P[-1]' is the character `-'.)
-   Then we set the translation of all bits between the starting and
-   ending characters (inclusive) in the compiled pattern B.
-
-   Return an error code.
-
-   We use these short variable names so we can use the same macros as
-   `regex_compile' itself.  */
-
-static reg_errcode_t
-compile_range (p_ptr, pend, translate, syntax, b)
-    const char **p_ptr, *pend;
-    char *translate;
-    reg_syntax_t syntax;
-    unsigned char *b;
-{
-  unsigned this_char;
-
-  const char *p = *p_ptr;
-  int range_start, range_end;
-
-  if (p == pend)
-    return REG_ERANGE;
-
-  /* Even though the pattern is a signed `char *', we need to fetch
-     with unsigned char *'s; if the high bit of the pattern character
-     is set, the range endpoints will be negative if we fetch using a
-     signed char *.
-
-     We also want to fetch the endpoints without translating them; the
-     appropriate translation is done in the bit-setting loop below.  */
-  range_start = ((unsigned char *) p)[-2];
-  range_end   = ((unsigned char *) p)[0];
-
-  /* Have to increment the pointer into the pattern string, so the
-     caller isn't still at the ending character.  */
-  (*p_ptr)++;
-
-  /* If the start is after the end, the range is empty.  */
-  if (range_start > range_end)
-    return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
-
-  /* Here we see why `this_char' has to be larger than an `unsigned
-     char' -- the range is inclusive, so if `range_end' == 0xff
-     (assuming 8-bit characters), we would otherwise go into an infinite
-     loop, since all characters <= 0xff.  */
-  for (this_char = range_start; this_char <= range_end; this_char++)
-    {
-      SET_LIST_BIT (TRANSLATE (this_char));
-    }
-
-  return REG_NOERROR;
-}
-\f
-/* Failure stack declarations and macros; both re_compile_fastmap and
-   re_match_2 use a failure stack.  These have to be macros because of
-   REGEX_ALLOCATE.  */
-
-
-/* Number of failure points for which to initially allocate space
-   when matching.  If this number is exceeded, we allocate more
-   space, so it is not a hard limit.  */
-#ifndef INIT_FAILURE_ALLOC
-#define INIT_FAILURE_ALLOC 5
-#endif
-
-/* Roughly the maximum number of failure points on the stack.  Would be
-   exactly that if always used MAX_FAILURE_SPACE each time we failed.
-   This is a variable only so users of regex can assign to it; we never
-   change it ourselves.  */
-int re_max_failures = 2000;
-
-typedef const unsigned char *fail_stack_elt_t;
-
-typedef struct
-{
-  fail_stack_elt_t *stack;
-  unsigned size;
-  unsigned avail;                      /* Offset of next open position.  */
-} fail_stack_type;
-
-#define FAIL_STACK_EMPTY()     (fail_stack.avail == 0)
-#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0)
-#define FAIL_STACK_FULL()      (fail_stack.avail == fail_stack.size)
-#define FAIL_STACK_TOP()       (fail_stack.stack[fail_stack.avail])
-
-
-/* Initialize `fail_stack'.  Do `return -2' if the alloc fails.  */
-
-#define INIT_FAIL_STACK()                                              \
-  do {                                                                 \
-    fail_stack.stack = (fail_stack_elt_t *)                            \
-      REGEX_ALLOCATE (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \
-                                                                       \
-    if (fail_stack.stack == NULL)                                      \
-      return -2;                                                       \
-                                                                       \
-    fail_stack.size = INIT_FAILURE_ALLOC;                              \
-    fail_stack.avail = 0;                                              \
-  } while (0)
-
-
-/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items.
-
-   Return 1 if succeeds, and 0 if either ran out of memory
-   allocating space for it or it was already too large.
-
-   REGEX_REALLOCATE requires `destination' be declared.   */
-
-#define DOUBLE_FAIL_STACK(fail_stack)                                  \
-  ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS             \
-   ? 0                                                                 \
-   : ((fail_stack).stack = (fail_stack_elt_t *)                                \
-       REGEX_REALLOCATE ((fail_stack).stack,                           \
-         (fail_stack).size * sizeof (fail_stack_elt_t),                \
-         ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)),        \
-                                                                       \
-      (fail_stack).stack == NULL                                       \
-      ? 0                                                              \
-      : ((fail_stack).size <<= 1,                                      \
-        1)))
-
-
-/* Push PATTERN_OP on FAIL_STACK.
-
-   Return 1 if was able to do so and 0 if ran out of memory allocating
-   space to do so.  */
-#define PUSH_PATTERN_OP(pattern_op, fail_stack)                                \
-  ((FAIL_STACK_FULL ()                                                 \
-    && !DOUBLE_FAIL_STACK (fail_stack))                                        \
-    ? 0                                                                        \
-    : ((fail_stack).stack[(fail_stack).avail++] = pattern_op,          \
-       1))
-
-/* This pushes an item onto the failure stack.  Must be a four-byte
-   value.  Assumes the variable `fail_stack'.  Probably should only
-   be called from within `PUSH_FAILURE_POINT'.  */
-#define PUSH_FAILURE_ITEM(item)                                                \
-  fail_stack.stack[fail_stack.avail++] = (fail_stack_elt_t) item
-
-/* The complement operation.  Assumes `fail_stack' is nonempty.  */
-#define POP_FAILURE_ITEM() fail_stack.stack[--fail_stack.avail]
-
-/* Used to omit pushing failure point id's when we're not debugging.  */
-#ifdef DEBUG
-#define DEBUG_PUSH PUSH_FAILURE_ITEM
-#define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_ITEM ()
-#else
-#define DEBUG_PUSH(item)
-#define DEBUG_POP(item_addr)
-#endif
-
-
-/* Push the information about the state we will need
-   if we ever fail back to it.
-
-   Requires variables fail_stack, regstart, regend, reg_info, and
-   num_regs be declared.  DOUBLE_FAIL_STACK requires `destination' be
-   declared.
-
-   Does `return FAILURE_CODE' if runs out of memory.  */
-
-#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code)  \
-  do {                                                                 \
-    char *destination;                                                 \
-    /* Must be int, so when we don't save any registers, the arithmetic        \
-       of 0 + -1 isn't done as unsigned.  */                           \
-    int this_reg;                                                      \
-                                                                       \
-    DEBUG_STATEMENT (failure_id++);                                    \
-    DEBUG_STATEMENT (nfailure_points_pushed++);                                \
-    DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id);          \
-    DEBUG_PRINT2 ("  Before push, next avail: %d\n", (fail_stack).avail);\
-    DEBUG_PRINT2 ("                     size: %d\n", (fail_stack).size);\
-                                                                       \
-    DEBUG_PRINT2 ("  slots needed: %d\n", NUM_FAILURE_ITEMS);          \
-    DEBUG_PRINT2 ("     available: %d\n", REMAINING_AVAIL_SLOTS);      \
-                                                                       \
-    /* Ensure we have enough space allocated for what we will push.  */        \
-    while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS)                  \
-      {                                                                        \
-       if (!DOUBLE_FAIL_STACK (fail_stack))                    \
-         return failure_code;                                          \
-                                                                       \
-       DEBUG_PRINT2 ("\n  Doubled stack; size now: %d\n",              \
-                      (fail_stack).size);                              \
-       DEBUG_PRINT2 ("  slots available: %d\n", REMAINING_AVAIL_SLOTS);\
-      }                                                                        \
-                                                                       \
-    /* Push the info, starting with the registers.  */                 \
-    DEBUG_PRINT1 ("\n");                                               \
-                                                                       \
-    for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \
-        this_reg++)                                                    \
-      {                                                                        \
-       DEBUG_PRINT2 ("  Pushing reg: %d\n", this_reg);                 \
-       DEBUG_STATEMENT (num_regs_pushed++);                            \
-                                                                       \
-       DEBUG_PRINT2 ("    start: 0x%x\n", regstart[this_reg]);         \
-       PUSH_FAILURE_ITEM (regstart[this_reg]);                         \
-                                                                       \
-       DEBUG_PRINT2 ("    end: 0x%x\n", regend[this_reg]);             \
-       PUSH_FAILURE_ITEM (regend[this_reg]);                           \
-                                                                       \
-       DEBUG_PRINT2 ("    info: 0x%x\n      ", reg_info[this_reg]);    \
-       DEBUG_PRINT2 (" match_null=%d",                                 \
-                     REG_MATCH_NULL_STRING_P (reg_info[this_reg]));    \
-       DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg]));    \
-       DEBUG_PRINT2 (" matched_something=%d",                          \
-                     MATCHED_SOMETHING (reg_info[this_reg]));          \
-       DEBUG_PRINT2 (" ever_matched=%d",                               \
-                     EVER_MATCHED_SOMETHING (reg_info[this_reg]));     \
-       DEBUG_PRINT1 ("\n");                                            \
-       PUSH_FAILURE_ITEM (reg_info[this_reg].word);                    \
-      }                                                                        \
-                                                                       \
-    DEBUG_PRINT2 ("  Pushing  low active reg: %d\n", lowest_active_reg);\
-    PUSH_FAILURE_ITEM (lowest_active_reg);                             \
-                                                                       \
-    DEBUG_PRINT2 ("  Pushing high active reg: %d\n", highest_active_reg);\
-    PUSH_FAILURE_ITEM (highest_active_reg);                            \
-                                                                       \
-    DEBUG_PRINT2 ("  Pushing pattern 0x%x: ", pattern_place);          \
-    DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend);          \
-    PUSH_FAILURE_ITEM (pattern_place);                                 \
-                                                                       \
-    DEBUG_PRINT2 ("  Pushing string 0x%x: `", string_place);           \
-    DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2,   \
-                                size2);                                \
-    DEBUG_PRINT1 ("'\n");                                              \
-    PUSH_FAILURE_ITEM (string_place);                                  \
-                                                                       \
-    DEBUG_PRINT2 ("  Pushing failure id: %u\n", failure_id);           \
-    DEBUG_PUSH (failure_id);                                           \
-  } while (0)
-
-/* This is the number of items that are pushed and popped on the stack
-   for each register.  */
-#define NUM_REG_ITEMS  3
-
-/* Individual items aside from the registers.  */
-#ifdef DEBUG
-#define NUM_NONREG_ITEMS 5 /* Includes failure point id.  */
-#else
-#define NUM_NONREG_ITEMS 4
-#endif
-
-/* We push at most this many items on the stack.  */
-#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
-
-/* We actually push this many items.  */
-#define NUM_FAILURE_ITEMS                                              \
-  ((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS        \
-    + NUM_NONREG_ITEMS)
-
-/* How many items can still be added to the stack without overflowing it.  */
-#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
-
-
-/* Pops what PUSH_FAIL_STACK pushes.
-
-   We restore into the parameters, all of which should be lvalues:
-     STR -- the saved data position.
-     PAT -- the saved pattern position.
-     LOW_REG, HIGH_REG -- the highest and lowest active registers.
-     REGSTART, REGEND -- arrays of string positions.
-     REG_INFO -- array of information about each subexpression.
-
-   Also assumes the variables `fail_stack' and (if debugging), `bufp',
-   `pend', `string1', `size1', `string2', and `size2'.  */
-
-#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\
-{                                                                      \
-  DEBUG_STATEMENT (fail_stack_elt_t failure_id;)                       \
-  int this_reg;                                                                \
-  const unsigned char *string_temp;                                    \
-                                                                       \
-  assert (!FAIL_STACK_EMPTY ());                                       \
-                                                                       \
-  /* Remove failure points and point to how many regs pushed.  */      \
-  DEBUG_PRINT1 ("POP_FAILURE_POINT:\n");                               \
-  DEBUG_PRINT2 ("  Before pop, next avail: %d\n", fail_stack.avail);   \
-  DEBUG_PRINT2 ("                    size: %d\n", fail_stack.size);    \
-                                                                       \
-  assert (fail_stack.avail >= NUM_NONREG_ITEMS);                       \
-                                                                       \
-  DEBUG_POP (&failure_id);                                             \
-  DEBUG_PRINT2 ("  Popping failure id: %u\n", failure_id);             \
-                                                                       \
-  /* If the saved string location is NULL, it came from an             \
-     on_failure_keep_string_jump opcode, and we want to throw away the \
-     saved NULL, thus retaining our current position in the string.  */        \
-  string_temp = POP_FAILURE_ITEM ();                                   \
-  if (string_temp != NULL)                                             \
-    str = (const char *) string_temp;                                  \
-                                                                       \
-  DEBUG_PRINT2 ("  Popping string 0x%x: `", str);                      \
-  DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2);     \
-  DEBUG_PRINT1 ("'\n");                                                        \
-                                                                       \
-  pat = (unsigned char *) POP_FAILURE_ITEM ();                         \
-  DEBUG_PRINT2 ("  Popping pattern 0x%x: ", pat);                      \
-  DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend);                      \
-                                                                       \
-  /* Restore register info.  */                                                \
-  high_reg = (unsigned) POP_FAILURE_ITEM ();                           \
-  DEBUG_PRINT2 ("  Popping high active reg: %d\n", high_reg);          \
-                                                                       \
-  low_reg = (unsigned) POP_FAILURE_ITEM ();                            \
-  DEBUG_PRINT2 ("  Popping  low active reg: %d\n", low_reg);           \
-                                                                       \
-  for (this_reg = high_reg; this_reg >= low_reg; this_reg--)           \
-    {                                                                  \
-      DEBUG_PRINT2 ("    Popping reg: %d\n", this_reg);                        \
-                                                                       \
-      reg_info[this_reg].word = POP_FAILURE_ITEM ();                   \
-      DEBUG_PRINT2 ("      info: 0x%x\n", reg_info[this_reg]);         \
-                                                                       \
-      regend[this_reg] = (const char *) POP_FAILURE_ITEM ();           \
-      DEBUG_PRINT2 ("      end: 0x%x\n", regend[this_reg]);            \
-                                                                       \
-      regstart[this_reg] = (const char *) POP_FAILURE_ITEM ();         \
-      DEBUG_PRINT2 ("      start: 0x%x\n", regstart[this_reg]);                \
-    }                                                                  \
-                                                                       \
-  DEBUG_STATEMENT (nfailure_points_popped++);                          \
-} /* POP_FAILURE_POINT */
-\f
-/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in
-   BUFP.  A fastmap records which of the (1 << BYTEWIDTH) possible
-   characters can start a string that matches the pattern.  This fastmap
-   is used by re_search to skip quickly over impossible starting points.
-
-   The caller must supply the address of a (1 << BYTEWIDTH)-byte data
-   area as BUFP->fastmap.
-
-   We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in
-   the pattern buffer.
-
-   Returns 0 if we succeed, -2 if an internal error.   */
-
-int
-re_compile_fastmap (bufp)
-     struct re_pattern_buffer *bufp;
-{
-  int j, k;
-  fail_stack_type fail_stack;
-#ifndef REGEX_MALLOC
-  char *destination;
-#endif
-  /* We don't push any register information onto the failure stack.  */
-  unsigned num_regs = 0;
-
-  register char *fastmap = bufp->fastmap;
-  unsigned char *pattern = bufp->buffer;
-  unsigned long size = bufp->used;
-  const unsigned char *p = pattern;
-  register unsigned char *pend = pattern + size;
-
-  /* Assume that each path through the pattern can be null until
-     proven otherwise.  We set this false at the bottom of switch
-     statement, to which we get only if a particular path doesn't
-     match the empty string.  */
-  boolean path_can_be_null = true;
-
-  /* We aren't doing a `succeed_n' to begin with.  */
-  boolean succeed_n_p = false;
-
-  assert (fastmap != NULL && p != NULL);
-
-  INIT_FAIL_STACK ();
-  bzero (fastmap, 1 << BYTEWIDTH);  /* Assume nothing's valid.  */
-  bufp->fastmap_accurate = 1;      /* It will be when we're done.  */
-  bufp->can_be_null = 0;
-
-  while (p != pend || !FAIL_STACK_EMPTY ())
-    {
-      if (p == pend)
-       {
-         bufp->can_be_null |= path_can_be_null;
-
-         /* Reset for next path.  */
-         path_can_be_null = true;
-
-         p = fail_stack.stack[--fail_stack.avail];
-       }
-
-      /* We should never be about to go beyond the end of the pattern.  */
-      assert (p < pend);
-
-#ifdef SWITCH_ENUM_BUG
-      switch ((int) ((re_opcode_t) *p++))
-#else
-      switch ((re_opcode_t) *p++)
-#endif
-       {
-
-       /* I guess the idea here is to simply not bother with a fastmap
-          if a backreference is used, since it's too hard to figure out
-          the fastmap for the corresponding group.  Setting
-          `can_be_null' stops `re_search_2' from using the fastmap, so
-          that is all we do.  */
-       case duplicate:
-         bufp->can_be_null = 1;
-         return 0;
-
-
-      /* Following are the cases which match a character.  These end
-        with `break'.  */
-
-       case exactn:
-         fastmap[p[1]] = 1;
-         break;
-
-
-       case charset:
-         for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
-           if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
-             fastmap[j] = 1;
-         break;
-
-
-       case charset_not:
-         /* Chars beyond end of map must be allowed.  */
-         for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
-           fastmap[j] = 1;
-
-         for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
-           if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
-             fastmap[j] = 1;
-         break;
-
-
-       case wordchar:
-         for (j = 0; j < (1 << BYTEWIDTH); j++)
-           if (SYNTAX (j) == Sword)
-             fastmap[j] = 1;
-         break;
-
-
-       case notwordchar:
-         for (j = 0; j < (1 << BYTEWIDTH); j++)
-           if (SYNTAX (j) != Sword)
-             fastmap[j] = 1;
-         break;
-
-
-       case anychar:
-         /* `.' matches anything ...  */
-         for (j = 0; j < (1 << BYTEWIDTH); j++)
-           fastmap[j] = 1;
-
-         /* ... except perhaps newline.  */
-         if (!(bufp->syntax & RE_DOT_NEWLINE))
-           fastmap['\n'] = 0;
-
-         /* Return if we have already set `can_be_null'; if we have,
-            then the fastmap is irrelevant.  Something's wrong here.  */
-         else if (bufp->can_be_null)
-           return 0;
-
-         /* Otherwise, have to check alternative paths.  */
-         break;
-
-
-#ifdef emacs
-       case syntaxspec:
-         k = *p++;
-         for (j = 0; j < (1 << BYTEWIDTH); j++)
-           if (SYNTAX (j) == (enum syntaxcode) k)
-             fastmap[j] = 1;
-         break;
-
-
-       case notsyntaxspec:
-         k = *p++;
-         for (j = 0; j < (1 << BYTEWIDTH); j++)
-           if (SYNTAX (j) != (enum syntaxcode) k)
-             fastmap[j] = 1;
-         break;
-
-
-      /* All cases after this match the empty string.  These end with
-        `continue'.  */
-
-
-       case before_dot:
-       case at_dot:
-       case after_dot:
-         continue;
-#endif /* not emacs */
-
-
-       case no_op:
-       case begline:
-       case endline:
-       case begbuf:
-       case endbuf:
-       case wordbound:
-       case notwordbound:
-       case wordbeg:
-       case wordend:
-       case push_dummy_failure:
-         continue;
-
-
-       case jump_n:
-       case pop_failure_jump:
-       case maybe_pop_jump:
-       case jump:
-       case jump_past_alt:
-       case dummy_failure_jump:
-         EXTRACT_NUMBER_AND_INCR (j, p);
-         p += j;
-         if (j > 0)
-           continue;
-
-         /* Jump backward implies we just went through the body of a
-            loop and matched nothing.  Opcode jumped to should be
-            `on_failure_jump' or `succeed_n'.  Just treat it like an
-            ordinary jump.  For a * loop, it has pushed its failure
-            point already; if so, discard that as redundant.  */
-         if ((re_opcode_t) *p != on_failure_jump
-             && (re_opcode_t) *p != succeed_n)
-           continue;
-
-         p++;
-         EXTRACT_NUMBER_AND_INCR (j, p);
-         p += j;
-
-         /* If what's on the stack is where we are now, pop it.  */
-         if (!FAIL_STACK_EMPTY ()
-             && fail_stack.stack[fail_stack.avail - 1] == p)
-           fail_stack.avail--;
-
-         continue;
-
-
-       case on_failure_jump:
-       case on_failure_keep_string_jump:
-       handle_on_failure_jump:
-         EXTRACT_NUMBER_AND_INCR (j, p);
-
-         /* For some patterns, e.g., `(a?)?', `p+j' here points to the
-            end of the pattern.  We don't want to push such a point,
-            since when we restore it above, entering the switch will
-            increment `p' past the end of the pattern.  We don't need
-            to push such a point since we obviously won't find any more
-            fastmap entries beyond `pend'.  Such a pattern can match
-            the null string, though.  */
-         if (p + j < pend)
-           {
-             if (!PUSH_PATTERN_OP (p + j, fail_stack))
-               return -2;
-           }
-         else
-           bufp->can_be_null = 1;
-
-         if (succeed_n_p)
-           {
-             EXTRACT_NUMBER_AND_INCR (k, p);   /* Skip the n.  */
-             succeed_n_p = false;
-           }
-
-         continue;
-
-
-       case succeed_n:
-         /* Get to the number of times to succeed.  */
-         p += 2;
-
-         /* Increment p past the n for when k != 0.  */
-         EXTRACT_NUMBER_AND_INCR (k, p);
-         if (k == 0)
-           {
-             p -= 4;
-             succeed_n_p = true;  /* Spaghetti code alert.  */
-             goto handle_on_failure_jump;
-           }
-         continue;
-
-
-       case set_number_at:
-         p += 4;
-         continue;
-
-
-       case start_memory:
-       case stop_memory:
-         p += 2;
-         continue;
-
-
-       default:
-         abort (); /* We have listed all the cases.  */
-       } /* switch *p++ */
-
-      /* Getting here means we have found the possible starting
-        characters for one path of the pattern -- and that the empty
-        string does not match.  We need not follow this path further.
-        Instead, look at the next alternative (remembered on the
-        stack), or quit if no more.  The test at the top of the loop
-        does these things.  */
-      path_can_be_null = false;
-      p = pend;
-    } /* while p */
-
-  /* Set `can_be_null' for the last path (also the first path, if the
-     pattern is empty).  */
-  bufp->can_be_null |= path_can_be_null;
-  return 0;
-} /* re_compile_fastmap */
-\f
-/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
-   ENDS.  Subsequent matches using PATTERN_BUFFER and REGS will use
-   this memory for recording register information.  STARTS and ENDS
-   must be allocated using the malloc library routine, and must each
-   be at least NUM_REGS * sizeof (regoff_t) bytes long.
-
-   If NUM_REGS == 0, then subsequent matches should allocate their own
-   register data.
-
-   Unless this function is called, the first search or match using
-   PATTERN_BUFFER will allocate its own register data, without
-   freeing the old data.  */
-
-void
-re_set_registers (bufp, regs, num_regs, starts, ends)
-    struct re_pattern_buffer *bufp;
-    struct re_registers *regs;
-    unsigned num_regs;
-    regoff_t *starts, *ends;
-{
-  if (num_regs)
-    {
-      bufp->regs_allocated = REGS_REALLOCATE;
-      regs->num_regs = num_regs;
-      regs->start = starts;
-      regs->end = ends;
-    }
-  else
-    {
-      bufp->regs_allocated = REGS_UNALLOCATED;
-      regs->num_regs = 0;
-      regs->start = regs->end = (regoff_t) 0;
-    }
-}
-\f
-/* Searching routines.  */
-
-/* Like re_search_2, below, but only one string is specified, and
-   doesn't let you say where to stop matching. */
-
-int
-re_search (bufp, string, size, startpos, range, regs)
-     struct re_pattern_buffer *bufp;
-     const char *string;
-     int size, startpos, range;
-     struct re_registers *regs;
-{
-  return re_search_2 (bufp, NULL, 0, string, size, startpos, range,
-                     regs, size);
-}
-
-
-/* Using the compiled pattern in BUFP->buffer, first tries to match the
-   virtual concatenation of STRING1 and STRING2, starting first at index
-   STARTPOS, then at STARTPOS + 1, and so on.
-
-   STRING1 and STRING2 have length SIZE1 and SIZE2, respectively.
-
-   RANGE is how far to scan while trying to match.  RANGE = 0 means try
-   only at STARTPOS; in general, the last start tried is STARTPOS +
-   RANGE.
-
-   In REGS, return the indices of the virtual concatenation of STRING1
-   and STRING2 that matched the entire BUFP->buffer and its contained
-   subexpressions.
-
-   Do not consider matching one past the index STOP in the virtual
-   concatenation of STRING1 and STRING2.
-
-   We return either the position in the strings at which the match was
-   found, -1 if no match, or -2 if error (such as failure
-   stack overflow).  */
-
-int
-re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
-     struct re_pattern_buffer *bufp;
-     const char *string1, *string2;
-     int size1, size2;
-     int startpos;
-     int range;
-     struct re_registers *regs;
-     int stop;
-{
-  int val;
-  register char *fastmap = bufp->fastmap;
-  register char *translate = bufp->translate;
-  int total_size = size1 + size2;
-  int endpos = startpos + range;
-
-  /* Check for out-of-range STARTPOS.  */
-  if (startpos < 0 || startpos > total_size)
-    return -1;
-
-  /* Fix up RANGE if it might eventually take us outside
-     the virtual concatenation of STRING1 and STRING2.  */
-  if (endpos < -1)
-    range = -1 - startpos;
-  else if (endpos > total_size)
-    range = total_size - startpos;
-
-  /* If the search isn't to be a backwards one, don't waste time in a
-     search for a pattern that must be anchored.  */
-  if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0)
-    {
-      if (startpos > 0)
-       return -1;
-      else
-       range = 1;
-    }
-
-  /* Update the fastmap now if not correct already.  */
-  if (fastmap && !bufp->fastmap_accurate)
-    if (re_compile_fastmap (bufp) == -2)
-      return -2;
-
-  /* Loop through the string, looking for a place to start matching.  */
-  for (;;)
-    {
-      /* If a fastmap is supplied, skip quickly over characters that
-        cannot be the start of a match.  If the pattern can match the
-        null string, however, we don't need to skip characters; we want
-        the first null string.  */
-      if (fastmap && startpos < total_size && !bufp->can_be_null)
-       {
-         if (range > 0)        /* Searching forwards.  */
-           {
-             register const char *d;
-             register int lim = 0;
-             int irange = range;
-
-             if (startpos < size1 && startpos + range >= size1)
-               lim = range - (size1 - startpos);
-
-             d = (startpos >= size1 ? string2 - size1 : string1) + startpos;
-
-             /* Written out as an if-else to avoid testing `translate'
-                inside the loop.  */
-             if (translate)
-               while (range > lim
-                      && !fastmap[(unsigned char)
-                                  translate[(unsigned char) *d++]])
-                 range--;
-             else
-               while (range > lim && !fastmap[(unsigned char) *d++])
-                 range--;
-
-             startpos += irange - range;
-           }
-         else                          /* Searching backwards.  */
-           {
-             register char c = (size1 == 0 || startpos >= size1
-                                ? string2[startpos - size1]
-                                : string1[startpos]);
-
-             if (!fastmap[(unsigned char) TRANSLATE (c)])
-               goto advance;
-           }
-       }
-
-      /* If can't match the null string, and that's all we have left, fail.  */
-      if (range >= 0 && startpos == total_size && fastmap
-         && !bufp->can_be_null)
-       return -1;
-
-      val = re_match_2 (bufp, string1, size1, string2, size2,
-                       startpos, regs, stop);
-      if (val >= 0)
-       return startpos;
-
-      if (val == -2)
-       return -2;
-
-    advance:
-      if (!range)
-       break;
-      else if (range > 0)
-       {
-         range--;
-         startpos++;
-       }
-      else
-       {
-         range++;
-         startpos--;
-       }
-    }
-  return -1;
-} /* re_search_2 */
-\f
-/* Declarations and macros for re_match_2.  */
-
-static int bcmp_translate ();
-static boolean alt_match_null_string_p (),
-              common_op_match_null_string_p (),
-              group_match_null_string_p ();
-
-/* Structure for per-register (a.k.a. per-group) information.
-   This must not be longer than one word, because we push this value
-   onto the failure stack.  Other register information, such as the
-   starting and ending positions (which are addresses), and the list of
-   inner groups (which is a bits list) are maintained in separate
-   variables.
-
-   We are making a (strictly speaking) nonportable assumption here: that
-   the compiler will pack our bit fields into something that fits into
-   the type of `word', i.e., is something that fits into one item on the
-   failure stack.  */
-typedef union
-{
-  fail_stack_elt_t word;
-  struct
-  {
-      /* This field is one if this group can match the empty string,
-        zero if not.  If not yet determined,  `MATCH_NULL_UNSET_VALUE'.  */
-#define MATCH_NULL_UNSET_VALUE 3
-    unsigned match_null_string_p : 2;
-    unsigned is_active : 1;
-    unsigned matched_something : 1;
-    unsigned ever_matched_something : 1;
-  } bits;
-} register_info_type;
-
-#define REG_MATCH_NULL_STRING_P(R)  ((R).bits.match_null_string_p)
-#define IS_ACTIVE(R)  ((R).bits.is_active)
-#define MATCHED_SOMETHING(R)  ((R).bits.matched_something)
-#define EVER_MATCHED_SOMETHING(R)  ((R).bits.ever_matched_something)
-
-
-/* Call this when have matched a real character; it sets `matched' flags
-   for the subexpressions which we are currently inside.  Also records
-   that those subexprs have matched.  */
-#define SET_REGS_MATCHED()                                             \
-  do                                                                   \
-    {                                                                  \
-      unsigned r;                                                      \
-      for (r = lowest_active_reg; r <= highest_active_reg; r++)                \
-       {                                                               \
-         MATCHED_SOMETHING (reg_info[r])                               \
-           = EVER_MATCHED_SOMETHING (reg_info[r])                      \
-           = 1;                                                        \
-       }                                                               \
-    }                                                                  \
-  while (0)
-
-
-/* This converts PTR, a pointer into one of the search strings `string1'
-   and `string2' into an offset from the beginning of that string.  */
-#define POINTER_TO_OFFSET(ptr)                                         \
-  (FIRST_STRING_P (ptr) ? (ptr) - string1 : (ptr) - string2 + size1)
-
-/* Registers are set to a sentinel when they haven't yet matched.  */
-#define REG_UNSET_VALUE ((char *) -1)
-#define REG_UNSET(e) ((e) == REG_UNSET_VALUE)
-
-
-/* Macros for dealing with the split strings in re_match_2.  */
-
-#define MATCHING_IN_FIRST_STRING  (dend == end_match_1)
-
-/* Call before fetching a character with *d.  This switches over to
-   string2 if necessary.  */
-#define PREFETCH()                                                     \
-  while (d == dend)                                                    \
-    {                                                                  \
-      /* End of string2 => fail.  */                                   \
-      if (dend == end_match_2)                                                 \
-       goto fail;                                                      \
-      /* End of string1 => advance to string2.  */                     \
-      d = string2;                                                     \
-      dend = end_match_2;                                              \
-    }
-
-
-/* Test if at very beginning or at very end of the virtual concatenation
-   of `string1' and `string2'.  If only one string, it's `string2'.  */
-#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2)
-#define AT_STRINGS_END(d) ((d) == end2)
-
-
-/* Test if D points to a character which is word-constituent.  We have
-   two special cases to check for: if past the end of string1, look at
-   the first character in string2; and if before the beginning of
-   string2, look at the last character in string1.  */
-#define WORDCHAR_P(d)                                                  \
-  (SYNTAX ((d) == end1 ? *string2                                      \
-          : (d) == string2 - 1 ? *(end1 - 1) : *(d))                   \
-   == Sword)
-
-/* Test if the character before D and the one at D differ with respect
-   to being word-constituent.  */
-#define AT_WORD_BOUNDARY(d)                                            \
-  (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)                            \
-   || WORDCHAR_P (d - 1) != WORDCHAR_P (d))
-
-
-/* Free everything we malloc.  */
-#ifdef REGEX_MALLOC
-#define FREE_VAR(var) if (var) free (var); var = NULL
-#define FREE_VARIABLES()                                               \
-  do {                                                                 \
-    FREE_VAR (fail_stack.stack);                                       \
-    FREE_VAR (regstart);                                               \
-    FREE_VAR (regend);                                                 \
-    FREE_VAR (old_regstart);                                           \
-    FREE_VAR (old_regend);                                             \
-    FREE_VAR (best_regstart);                                          \
-    FREE_VAR (best_regend);                                            \
-    FREE_VAR (reg_info);                                               \
-    FREE_VAR (reg_dummy);                                              \
-    FREE_VAR (reg_info_dummy);                                         \
-  } while (0)
-#else /* not REGEX_MALLOC */
-/* Some MIPS systems (at least) want this to free alloca'd storage.  */
-#define FREE_VARIABLES() alloca (0)
-#endif /* not REGEX_MALLOC */
-
-
-/* These values must meet several constraints.  They must not be valid
-   register values; since we have a limit of 255 registers (because
-   we use only one byte in the pattern for the register number), we can
-   use numbers larger than 255.  They must differ by 1, because of
-   NUM_FAILURE_ITEMS above.  And the value for the lowest register must
-   be larger than the value for the highest register, so we do not try
-   to actually save any registers when none are active.  */
-#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH)
-#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1)
-\f
-/* Matching routines.  */
-
-#ifndef emacs   /* Emacs never uses this.  */
-/* re_match is like re_match_2 except it takes only a single string.  */
-
-int
-re_match (bufp, string, size, pos, regs)
-     struct re_pattern_buffer *bufp;
-     const char *string;
-     int size, pos;
-     struct re_registers *regs;
- {
-  return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size);
-}
-#endif /* not emacs */
-
-
-/* re_match_2 matches the compiled pattern in BUFP against the
-   the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
-   and SIZE2, respectively).  We start matching at POS, and stop
-   matching at STOP.
-
-   If REGS is non-null and the `no_sub' field of BUFP is nonzero, we
-   store offsets for the substring each group matched in REGS.  See the
-   documentation for exactly how many groups we fill.
-
-   We return -1 if no match, -2 if an internal error (such as the
-   failure stack overflowing).  Otherwise, we return the length of the
-   matched substring.  */
-
-int
-re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
-     struct re_pattern_buffer *bufp;
-     const char *string1, *string2;
-     int size1, size2;
-     int pos;
-     struct re_registers *regs;
-     int stop;
-{
-  /* General temporaries.  */
-  int mcnt;
-  unsigned char *p1;
-
-  /* Just past the end of the corresponding string.  */
-  const char *end1, *end2;
-
-  /* Pointers into string1 and string2, just past the last characters in
-     each to consider matching.  */
-  const char *end_match_1, *end_match_2;
-
-  /* Where we are in the data, and the end of the current string.  */
-  const char *d, *dend;
-
-  /* Where we are in the pattern, and the end of the pattern.  */
-  unsigned char *p = bufp->buffer;
-  register unsigned char *pend = p + bufp->used;
-
-  /* We use this to map every character in the string.  */
-  char *translate = bufp->translate;
-
-  /* Failure point stack.  Each place that can handle a failure further
-     down the line pushes a failure point on this stack.  It consists of
-     restart, regend, and reg_info for all registers corresponding to
-     the subexpressions we're currently inside, plus the number of such
-     registers, and, finally, two char *'s.  The first char * is where
-     to resume scanning the pattern; the second one is where to resume
-     scanning the strings.  If the latter is zero, the failure point is
-     a ``dummy''; if a failure happens and the failure point is a dummy,
-     it gets discarded and the next next one is tried.  */
-  fail_stack_type fail_stack;
-#ifdef DEBUG
-  static unsigned failure_id = 0;
-  unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
-#endif
-
-  /* We fill all the registers internally, independent of what we
-     return, for use in backreferences.  The number here includes
-     an element for register zero.  */
-  unsigned num_regs = bufp->re_nsub + 1;
-
-  /* The currently active registers.  */
-  unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG;
-  unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG;
-
-  /* Information on the contents of registers. These are pointers into
-     the input strings; they record just what was matched (on this
-     attempt) by a subexpression part of the pattern, that is, the
-     regnum-th regstart pointer points to where in the pattern we began
-     matching and the regnum-th regend points to right after where we
-     stopped matching the regnum-th subexpression.  (The zeroth register
-     keeps track of what the whole pattern matches.)  */
-  const char **regstart = NULL, **regend = NULL;
-
-  /* If a group that's operated upon by a repetition operator fails to
-     match anything, then the register for its start will need to be
-     restored because it will have been set to wherever in the string we
-     are when we last see its open-group operator.  Similarly for a
-     register's end.  */
-  const char **old_regstart = NULL, **old_regend = NULL;
-
-  /* The is_active field of reg_info helps us keep track of which (possibly
-     nested) subexpressions we are currently in. The matched_something
-     field of reg_info[reg_num] helps us tell whether or not we have
-     matched any of the pattern so far this time through the reg_num-th
-     subexpression.  These two fields get reset each time through any
-     loop their register is in.  */
-  register_info_type *reg_info = NULL;
-
-  /* The following record the register info as found in the above
-     variables when we find a match better than any we've seen before.
-     This happens as we backtrack through the failure points, which in
-     turn happens only if we have not yet matched the entire string. */
-  unsigned best_regs_set = false;
-  const char **best_regstart = NULL, **best_regend = NULL;
-
-  /* Logically, this is `best_regend[0]'.  But we don't want to have to
-     allocate space for that if we're not allocating space for anything
-     else (see below).  Also, we never need info about register 0 for
-     any of the other register vectors, and it seems rather a kludge to
-     treat `best_regend' differently than the rest.  So we keep track of
-     the end of the best match so far in a separate variable.  We
-     initialize this to NULL so that when we backtrack the first time
-     and need to test it, it's not garbage.  */
-  const char *match_end = NULL;
-
-  /* Used when we pop values we don't care about.  */
-  const char **reg_dummy = NULL;
-  register_info_type *reg_info_dummy = NULL;
-
-#ifdef DEBUG
-  /* Counts the total number of registers pushed.  */
-  unsigned num_regs_pushed = 0;
-#endif
-
-  DEBUG_PRINT1 ("\n\nEntering re_match_2.\n");
-
-  INIT_FAIL_STACK ();
-
-  /* Do not bother to initialize all the register variables if there are
-     no groups in the pattern, as it takes a fair amount of time.  If
-     there are groups, we include space for register 0 (the whole
-     pattern), even though we never use it, since it simplifies the
-     array indexing.  We should fix this.  */
-  if (bufp->re_nsub)
-    {
-      regstart = REGEX_TALLOC (num_regs, const char *);
-      regend = REGEX_TALLOC (num_regs, const char *);
-      old_regstart = REGEX_TALLOC (num_regs, const char *);
-      old_regend = REGEX_TALLOC (num_regs, const char *);
-      best_regstart = REGEX_TALLOC (num_regs, const char *);
-      best_regend = REGEX_TALLOC (num_regs, const char *);
-      reg_info = REGEX_TALLOC (num_regs, register_info_type);
-      reg_dummy = REGEX_TALLOC (num_regs, const char *);
-      reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type);
-
-      if (!(regstart && regend && old_regstart && old_regend && reg_info
-           && best_regstart && best_regend && reg_dummy && reg_info_dummy))
-       {
-         FREE_VARIABLES ();
-         return -2;
-       }
-    }
-#ifdef REGEX_MALLOC
-  else
-    {
-      /* We must initialize all our variables to NULL, so that
-        `FREE_VARIABLES' doesn't try to free them.  */
-      regstart = regend = old_regstart = old_regend = best_regstart
-       = best_regend = reg_dummy = NULL;
-      reg_info = reg_info_dummy = (register_info_type *) NULL;
-    }
-#endif /* REGEX_MALLOC */
-
-  /* The starting position is bogus.  */
-  if (pos < 0 || pos > size1 + size2)
-    {
-      FREE_VARIABLES ();
-      return -1;
-    }
-
-  /* Initialize subexpression text positions to -1 to mark ones that no
-     start_memory/stop_memory has been seen for. Also initialize the
-     register information struct.  */
-  for (mcnt = 1; mcnt < num_regs; mcnt++)
-    {
-      regstart[mcnt] = regend[mcnt]
-       = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE;
-
-      REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE;
-      IS_ACTIVE (reg_info[mcnt]) = 0;
-      MATCHED_SOMETHING (reg_info[mcnt]) = 0;
-      EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0;
-    }
-
-  /* We move `string1' into `string2' if the latter's empty -- but not if
-     `string1' is null.  */
-  if (size2 == 0 && string1 != NULL)
-    {
-      string2 = string1;
-      size2 = size1;
-      string1 = 0;
-      size1 = 0;
-    }
-  end1 = string1 + size1;
-  end2 = string2 + size2;
-
-  /* Compute where to stop matching, within the two strings.  */
-  if (stop <= size1)
-    {
-      end_match_1 = string1 + stop;
-      end_match_2 = string2;
-    }
-  else
-    {
-      end_match_1 = end1;
-      end_match_2 = string2 + stop - size1;
-    }
-
-  /* `p' scans through the pattern as `d' scans through the data.
-     `dend' is the end of the input string that `d' points within.  `d'
-     is advanced into the following input string whenever necessary, but
-     this happens before fetching; therefore, at the beginning of the
-     loop, `d' can be pointing at the end of a string, but it cannot
-     equal `string2'.  */
-  if (size1 > 0 && pos <= size1)
-    {
-      d = string1 + pos;
-      dend = end_match_1;
-    }
-  else
-    {
-      d = string2 + pos - size1;
-      dend = end_match_2;
-    }
-
-  DEBUG_PRINT1 ("The compiled pattern is: ");
-  DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend);
-  DEBUG_PRINT1 ("The string to match is: `");
-  DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2);
-  DEBUG_PRINT1 ("'\n");
-
-  /* This loops over pattern commands.  It exits by returning from the
-     function if the match is complete, or it drops through if the match
-     fails at this starting point in the input data.  */
-  for (;;)
-    {
-      DEBUG_PRINT2 ("\n0x%x: ", p);
-
-      if (p == pend)
-       { /* End of pattern means we might have succeeded.  */
-         DEBUG_PRINT1 ("end of pattern ... ");
-
-         /* If we haven't matched the entire string, and we want the
-            longest match, try backtracking.  */
-         if (d != end_match_2)
-           {
-             DEBUG_PRINT1 ("backtracking.\n");
-
-             if (!FAIL_STACK_EMPTY ())
-               { /* More failure points to try.  */
-                 boolean same_str_p = (FIRST_STRING_P (match_end)
-                                       == MATCHING_IN_FIRST_STRING);
-
-                 /* If exceeds best match so far, save it.  */
-                 if (!best_regs_set
-                     || (same_str_p && d > match_end)
-                     || (!same_str_p && !MATCHING_IN_FIRST_STRING))
-                   {
-                     best_regs_set = true;
-                     match_end = d;
-
-                     DEBUG_PRINT1 ("\nSAVING match as best so far.\n");
-
-                     for (mcnt = 1; mcnt < num_regs; mcnt++)
-                       {
-                         best_regstart[mcnt] = regstart[mcnt];
-                         best_regend[mcnt] = regend[mcnt];
-                       }
-                   }
-                 goto fail;
-               }
-
-             /* If no failure points, don't restore garbage.  */
-             else if (best_regs_set)
-               {
-               restore_best_regs:
-                 /* Restore best match.  It may happen that `dend ==
-                    end_match_1' while the restored d is in string2.
-                    For example, the pattern `x.*y.*z' against the
-                    strings `x-' and `y-z-', if the two strings are
-                    not consecutive in memory.  */
-                 DEBUG_PRINT1 ("Restoring best registers.\n");
-
-                 d = match_end;
-                 dend = ((d >= string1 && d <= end1)
-                          ? end_match_1 : end_match_2);
-
-                 for (mcnt = 1; mcnt < num_regs; mcnt++)
-                   {
-                     regstart[mcnt] = best_regstart[mcnt];
-                     regend[mcnt] = best_regend[mcnt];
-                   }
-               }
-           } /* d != end_match_2 */
-
-         DEBUG_PRINT1 ("Accepting match.\n");
-
-         /* If caller wants register contents data back, do it.  */
-         if (regs && !bufp->no_sub)
-           {
-             /* Have the register data arrays been allocated?  */
-             if (bufp->regs_allocated == REGS_UNALLOCATED)
-               { /* No.  So allocate them with malloc.  We need one
-                    extra element beyond `num_regs' for the `-1' marker
-                    GNU code uses.  */
-                 regs->num_regs = MAX (RE_NREGS, num_regs + 1);
-                 regs->start = TALLOC (regs->num_regs, regoff_t);
-                 regs->end = TALLOC (regs->num_regs, regoff_t);
-                 if (regs->start == NULL || regs->end == NULL)
-                   return -2;
-                 bufp->regs_allocated = REGS_REALLOCATE;
-               }
-             else if (bufp->regs_allocated == REGS_REALLOCATE)
-               { /* Yes.  If we need more elements than were already
-                    allocated, reallocate them.  If we need fewer, just
-                    leave it alone.  */
-                 if (regs->num_regs < num_regs + 1)
-                   {
-                     regs->num_regs = num_regs + 1;
-                     RETALLOC (regs->start, regs->num_regs, regoff_t);
-                     RETALLOC (regs->end, regs->num_regs, regoff_t);
-                     if (regs->start == NULL || regs->end == NULL)
-                       return -2;
-                   }
-               }
-             else
-               assert (bufp->regs_allocated == REGS_FIXED);
-
-             /* Convert the pointer data in `regstart' and `regend' to
-                indices.  Register zero has to be set differently,
-                since we haven't kept track of any info for it.  */
-             if (regs->num_regs > 0)
-               {
-                 regs->start[0] = pos;
-                 regs->end[0] = (MATCHING_IN_FIRST_STRING ? d - string1
-                                 : d - string2 + size1);
-               }
-
-             /* Go through the first `min (num_regs, regs->num_regs)'
-                registers, since that is all we initialized.  */
-             for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++)
-               {
-                 if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt]))
-                   regs->start[mcnt] = regs->end[mcnt] = -1;
-                 else
-                   {
-                     regs->start[mcnt] = POINTER_TO_OFFSET (regstart[mcnt]);
-                     regs->end[mcnt] = POINTER_TO_OFFSET (regend[mcnt]);
-                   }
-               }
-
-             /* If the regs structure we return has more elements than
-                were in the pattern, set the extra elements to -1.  If
-                we (re)allocated the registers, this is the case,
-                because we always allocate enough to have at least one
-                -1 at the end.  */
-             for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++)
-               regs->start[mcnt] = regs->end[mcnt] = -1;
-           } /* regs && !bufp->no_sub */
-
-         FREE_VARIABLES ();
-         DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
-                       nfailure_points_pushed, nfailure_points_popped,
-                       nfailure_points_pushed - nfailure_points_popped);
-         DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
-
-         mcnt = d - pos - (MATCHING_IN_FIRST_STRING
-                           ? string1
-                           : string2 - size1);
-
-         DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
-
-         return mcnt;
-       }
-
-      /* Otherwise match next pattern command.  */
-#ifdef SWITCH_ENUM_BUG
-      switch ((int) ((re_opcode_t) *p++))
-#else
-      switch ((re_opcode_t) *p++)
-#endif
-       {
-       /* Ignore these.  Used to ignore the n of succeed_n's which
-          currently have n == 0.  */
-       case no_op:
-         DEBUG_PRINT1 ("EXECUTING no_op.\n");
-         break;
-
-
-       /* Match the next n pattern characters exactly.  The following
-          byte in the pattern defines n, and the n bytes after that
-          are the characters to match.  */
-       case exactn:
-         mcnt = *p++;
-         DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt);
-
-         /* This is written out as an if-else so we don't waste time
-            testing `translate' inside the loop.  */
-         if (translate)
-           {
-             do
-               {
-                 PREFETCH ();
-                 if (translate[(unsigned char) *d++] != (char) *p++)
-                   goto fail;
-               }
-             while (--mcnt);
-           }
-         else
-           {
-             do
-               {
-                 PREFETCH ();
-                 if (*d++ != (char) *p++) goto fail;
-               }
-             while (--mcnt);
-           }
-         SET_REGS_MATCHED ();
-         break;
-
-
-       /* Match any character except possibly a newline or a null.  */
-       case anychar:
-         DEBUG_PRINT1 ("EXECUTING anychar.\n");
-
-         PREFETCH ();
-
-         if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n')
-             || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000'))
-           goto fail;
-
-         SET_REGS_MATCHED ();
-         DEBUG_PRINT2 ("  Matched `%d'.\n", *d);
-         d++;
-         break;
-
-
-       case charset:
-       case charset_not:
-         {
-           register unsigned char c;
-           boolean not = (re_opcode_t) *(p - 1) == charset_not;
-
-           DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : "");
-
-           PREFETCH ();
-           c = TRANSLATE (*d); /* The character to match.  */
-
-           /* Cast to `unsigned' instead of `unsigned char' in case the
-              bit list is a full 32 bytes long.  */
-           if (c < (unsigned) (*p * BYTEWIDTH)
-               && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
-             not = !not;
-
-           p += 1 + *p;
-
-           if (!not) goto fail;
-
-           SET_REGS_MATCHED ();
-           d++;
-           break;
-         }
-
-
-       /* The beginning of a group is represented by start_memory.
-          The arguments are the register number in the next byte, and the
-          number of groups inner to this one in the next.  The text
-          matched within the group is recorded (in the internal
-          registers data structure) under the register number.  */
-       case start_memory:
-         DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]);
-
-         /* Find out if this group can match the empty string.  */
-         p1 = p;               /* To send to group_match_null_string_p.  */
-
-         if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE)
-           REG_MATCH_NULL_STRING_P (reg_info[*p])
-             = group_match_null_string_p (&p1, pend, reg_info);
-
-         /* Save the position in the string where we were the last time
-            we were at this open-group operator in case the group is
-            operated upon by a repetition operator, e.g., with `(a*)*b'
-            against `ab'; then we want to ignore where we are now in
-            the string in case this attempt to match fails.  */
-         old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
-                            ? REG_UNSET (regstart[*p]) ? d : regstart[*p]
-                            : regstart[*p];
-         DEBUG_PRINT2 ("  old_regstart: %d\n",
-                        POINTER_TO_OFFSET (old_regstart[*p]));
-
-         regstart[*p] = d;
-         DEBUG_PRINT2 ("  regstart: %d\n", POINTER_TO_OFFSET (regstart[*p]));
-
-         IS_ACTIVE (reg_info[*p]) = 1;
-         MATCHED_SOMETHING (reg_info[*p]) = 0;
-
-         /* This is the new highest active register.  */
-         highest_active_reg = *p;
-
-         /* If nothing was active before, this is the new lowest active
-            register.  */
-         if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
-           lowest_active_reg = *p;
-
-         /* Move past the register number and inner group count.  */
-         p += 2;
-         break;
-
-
-       /* The stop_memory opcode represents the end of a group.  Its
-          arguments are the same as start_memory's: the register
-          number, and the number of inner groups.  */
-       case stop_memory:
-         DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]);
-
-         /* We need to save the string position the last time we were at
-            this close-group operator in case the group is operated
-            upon by a repetition operator, e.g., with `((a*)*(b*)*)*'
-            against `aba'; then we want to ignore where we are now in
-            the string in case this attempt to match fails.  */
-         old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
-                          ? REG_UNSET (regend[*p]) ? d : regend[*p]
-                          : regend[*p];
-         DEBUG_PRINT2 ("      old_regend: %d\n",
-                        POINTER_TO_OFFSET (old_regend[*p]));
-
-         regend[*p] = d;
-         DEBUG_PRINT2 ("      regend: %d\n", POINTER_TO_OFFSET (regend[*p]));
-
-         /* This register isn't active anymore.  */
-         IS_ACTIVE (reg_info[*p]) = 0;
-
-         /* If this was the only register active, nothing is active
-            anymore.  */
-         if (lowest_active_reg == highest_active_reg)
-           {
-             lowest_active_reg = NO_LOWEST_ACTIVE_REG;
-             highest_active_reg = NO_HIGHEST_ACTIVE_REG;
-           }
-         else
-           { /* We must scan for the new highest active register, since
-                it isn't necessarily one less than now: consider
-                (a(b)c(d(e)f)g).  When group 3 ends, after the f), the
-                new highest active register is 1.  */
-             unsigned char r = *p - 1;
-             while (r > 0 && !IS_ACTIVE (reg_info[r]))
-               r--;
-
-             /* If we end up at register zero, that means that we saved
-                the registers as the result of an `on_failure_jump', not
-                a `start_memory', and we jumped to past the innermost
-                `stop_memory'.  For example, in ((.)*) we save
-                registers 1 and 2 as a result of the *, but when we pop
-                back to the second ), we are at the stop_memory 1.
-                Thus, nothing is active.  */
-             if (r == 0)
-               {
-                 lowest_active_reg = NO_LOWEST_ACTIVE_REG;
-                 highest_active_reg = NO_HIGHEST_ACTIVE_REG;
-               }
-             else
-               highest_active_reg = r;
-           }
-
-         /* If just failed to match something this time around with a
-            group that's operated on by a repetition operator, try to
-            force exit from the ``loop'', and restore the register
-            information for this group that we had before trying this
-            last match.  */
-         if ((!MATCHED_SOMETHING (reg_info[*p])
-              || (re_opcode_t) p[-3] == start_memory)
-             && (p + 2) < pend)
-           {
-             boolean is_a_jump_n = false;
-
-             p1 = p + 2;
-             mcnt = 0;
-             switch ((re_opcode_t) *p1++)
-               {
-                 case jump_n:
-                   is_a_jump_n = true;
-                 case pop_failure_jump:
-                 case maybe_pop_jump:
-                 case jump:
-                 case dummy_failure_jump:
-                   EXTRACT_NUMBER_AND_INCR (mcnt, p1);
-                   if (is_a_jump_n)
-                     p1 += 2;
-                   break;
-
-                 default:
-                   /* do nothing */ ;
-               }
-             p1 += mcnt;
-
-             /* If the next operation is a jump backwards in the pattern
-                to an on_failure_jump right before the start_memory
-                corresponding to this stop_memory, exit from the loop
-                by forcing a failure after pushing on the stack the
-                on_failure_jump's jump in the pattern, and d.  */
-             if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump
-                 && (re_opcode_t) p1[3] == start_memory && p1[4] == *p)
-               {
-                 /* If this group ever matched anything, then restore
-                    what its registers were before trying this last
-                    failed match, e.g., with `(a*)*b' against `ab' for
-                    regstart[1], and, e.g., with `((a*)*(b*)*)*'
-                    against `aba' for regend[3].
-
-                    Also restore the registers for inner groups for,
-                    e.g., `((a*)(b*))*' against `aba' (register 3 would
-                    otherwise get trashed).  */
-
-                 if (EVER_MATCHED_SOMETHING (reg_info[*p]))
-                   {
-                     unsigned r;
-
-                     EVER_MATCHED_SOMETHING (reg_info[*p]) = 0;
-
-                     /* Restore this and inner groups' (if any) registers.  */
-                     for (r = *p; r < *p + *(p + 1); r++)
-                       {
-                         regstart[r] = old_regstart[r];
-
-                         /* xx why this test?  */
-                         if ((int) old_regend[r] >= (int) regstart[r])
-                           regend[r] = old_regend[r];
-                       }
-                   }
-                 p1++;
-                 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
-                 PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
-
-                 goto fail;
-               }
-           }
-
-         /* Move past the register number and the inner group count.  */
-         p += 2;
-         break;
-
-
-       /* \<digit> has been turned into a `duplicate' command which is
-          followed by the numeric value of <digit> as the register number.  */
-       case duplicate:
-         {
-           register const char *d2, *dend2;
-           int regno = *p++;   /* Get which register to match against.  */
-           DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
-
-           /* Can't back reference a group which we've never matched.  */
-           if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno]))
-             goto fail;
-
-           /* Where in input to try to start matching.  */
-           d2 = regstart[regno];
-
-           /* Where to stop matching; if both the place to start and
-              the place to stop matching are in the same string, then
-              set to the place to stop, otherwise, for now have to use
-              the end of the first string.  */
-
-           dend2 = ((FIRST_STRING_P (regstart[regno])
-                     == FIRST_STRING_P (regend[regno]))
-                    ? regend[regno] : end_match_1);
-           for (;;)
-             {
-               /* If necessary, advance to next segment in register
-                  contents.  */
-               while (d2 == dend2)
-                 {
-                   if (dend2 == end_match_2) break;
-                   if (dend2 == regend[regno]) break;
-
-                   /* End of string1 => advance to string2. */
-                   d2 = string2;
-                   dend2 = regend[regno];
-                 }
-               /* At end of register contents => success */
-               if (d2 == dend2) break;
-
-               /* If necessary, advance to next segment in data.  */
-               PREFETCH ();
-
-               /* How many characters left in this segment to match.  */
-               mcnt = dend - d;
-
-               /* Want how many consecutive characters we can match in
-                  one shot, so, if necessary, adjust the count.  */
-               if (mcnt > dend2 - d2)
-                 mcnt = dend2 - d2;
-
-               /* Compare that many; failure if mismatch, else move
-                  past them.  */
-               if (translate
-                   ? bcmp_translate (d, d2, mcnt, translate)
-                   : bcmp (d, d2, mcnt))
-                 goto fail;
-               d += mcnt, d2 += mcnt;
-             }
-         }
-         break;
-
-
-       /* begline matches the empty string at the beginning of the string
-          (unless `not_bol' is set in `bufp'), and, if
-          `newline_anchor' is set, after newlines.  */
-       case begline:
-         DEBUG_PRINT1 ("EXECUTING begline.\n");
-
-         if (AT_STRINGS_BEG (d))
-           {
-             if (!bufp->not_bol) break;
-           }
-         else if (d[-1] == '\n' && bufp->newline_anchor)
-           {
-             break;
-           }
-         /* In all other cases, we fail.  */
-         goto fail;
-
-
-       /* endline is the dual of begline.  */
-       case endline:
-         DEBUG_PRINT1 ("EXECUTING endline.\n");
-
-         if (AT_STRINGS_END (d))
-           {
-             if (!bufp->not_eol) break;
-           }
-
-         /* We have to ``prefetch'' the next character.  */
-         else if ((d == end1 ? *string2 : *d) == '\n'
-                  && bufp->newline_anchor)
-           {
-             break;
-           }
-         goto fail;
-
-
-       /* Match at the very beginning of the data.  */
-       case begbuf:
-         DEBUG_PRINT1 ("EXECUTING begbuf.\n");
-         if (AT_STRINGS_BEG (d))
-           break;
-         goto fail;
-
-
-       /* Match at the very end of the data.  */
-       case endbuf:
-         DEBUG_PRINT1 ("EXECUTING endbuf.\n");
-         if (AT_STRINGS_END (d))
-           break;
-         goto fail;
-
-
-       /* on_failure_keep_string_jump is used to optimize `.*\n'.  It
-          pushes NULL as the value for the string on the stack.  Then
-          `pop_failure_point' will keep the current value for the
-          string, instead of restoring it.  To see why, consider
-          matching `foo\nbar' against `.*\n'.  The .* matches the foo;
-          then the . fails against the \n.  But the next thing we want
-          to do is match the \n against the \n; if we restored the
-          string value, we would be back at the foo.
-
-          Because this is used only in specific cases, we don't need to
-          check all the things that `on_failure_jump' does, to make
-          sure the right things get saved on the stack.  Hence we don't
-          share its code.  The only reason to push anything on the
-          stack at all is that otherwise we would have to change
-          `anychar's code to do something besides goto fail in this
-          case; that seems worse than this.  */
-       case on_failure_keep_string_jump:
-         DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump");
-
-         EXTRACT_NUMBER_AND_INCR (mcnt, p);
-         DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt);
-
-         PUSH_FAILURE_POINT (p + mcnt, NULL, -2);
-         break;
-
-
-       /* Uses of on_failure_jump:
-
-          Each alternative starts with an on_failure_jump that points
-          to the beginning of the next alternative.  Each alternative
-          except the last ends with a jump that in effect jumps past
-          the rest of the alternatives.  (They really jump to the
-          ending jump of the following alternative, because tensioning
-          these jumps is a hassle.)
-
-          Repeats start with an on_failure_jump that points past both
-          the repetition text and either the following jump or
-          pop_failure_jump back to this on_failure_jump.  */
-       case on_failure_jump:
-       on_failure:
-         DEBUG_PRINT1 ("EXECUTING on_failure_jump");
-
-         EXTRACT_NUMBER_AND_INCR (mcnt, p);
-         DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt);
-
-         /* If this on_failure_jump comes right before a group (i.e.,
-            the original * applied to a group), save the information
-            for that group and all inner ones, so that if we fail back
-            to this point, the group's information will be correct.
-            For example, in \(a*\)*\1, we need the preceding group,
-            and in \(\(a*\)b*\)\2, we need the inner group.  */
-
-         /* We can't use `p' to check ahead because we push
-            a failure point to `p + mcnt' after we do this.  */
-         p1 = p;
-
-         /* We need to skip no_op's before we look for the
-            start_memory in case this on_failure_jump is happening as
-            the result of a completed succeed_n, as in \(a\)\{1,3\}b\1
-            against aba.  */
-         while (p1 < pend && (re_opcode_t) *p1 == no_op)
-           p1++;
-
-         if (p1 < pend && (re_opcode_t) *p1 == start_memory)
-           {
-             /* We have a new highest active register now.  This will
-                get reset at the start_memory we are about to get to,
-                but we will have saved all the registers relevant to
-                this repetition op, as described above.  */
-             highest_active_reg = *(p1 + 1) + *(p1 + 2);
-             if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
-               lowest_active_reg = *(p1 + 1);
-           }
-
-         DEBUG_PRINT1 (":\n");
-         PUSH_FAILURE_POINT (p + mcnt, d, -2);
-         break;
-
-
-       /* A smart repeat ends with `maybe_pop_jump'.
-          We change it to either `pop_failure_jump' or `jump'.  */
-       case maybe_pop_jump:
-         EXTRACT_NUMBER_AND_INCR (mcnt, p);
-         DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt);
-         {
-           register unsigned char *p2 = p;
-
-           /* Compare the beginning of the repeat with what in the
-              pattern follows its end. If we can establish that there
-              is nothing that they would both match, i.e., that we
-              would have to backtrack because of (as in, e.g., `a*a')
-              then we can change to pop_failure_jump, because we'll
-              never have to backtrack.
-
-              This is not true in the case of alternatives: in
-              `(a|ab)*' we do need to backtrack to the `ab' alternative
-              (e.g., if the string was `ab').  But instead of trying to
-              detect that here, the alternative has put on a dummy
-              failure point which is what we will end up popping.  */
-
-           /* Skip over open/close-group commands.  */
-           while (p2 + 2 < pend
-                  && ((re_opcode_t) *p2 == stop_memory
-                      || (re_opcode_t) *p2 == start_memory))
-             p2 += 3;                  /* Skip over args, too.  */
-
-           /* If we're at the end of the pattern, we can change.  */
-           if (p2 == pend)
-             {
-               /* Consider what happens when matching ":\(.*\)"
-                  against ":/".  I don't really understand this code
-                  yet.  */
-               p[-3] = (unsigned char) pop_failure_jump;
-               DEBUG_PRINT1
-                 ("  End of pattern: change to `pop_failure_jump'.\n");
-             }
-
-           else if ((re_opcode_t) *p2 == exactn
-                    || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
-             {
-               register unsigned char c
-                 = *p2 == (unsigned char) endline ? '\n' : p2[2];
-               p1 = p + mcnt;
-
-               /* p1[0] ... p1[2] are the `on_failure_jump' corresponding
-                  to the `maybe_finalize_jump' of this case.  Examine what
-                  follows.  */
-               if ((re_opcode_t) p1[3] == exactn && p1[5] != c)
-                 {
-                   p[-3] = (unsigned char) pop_failure_jump;
-                   DEBUG_PRINT3 ("  %c != %c => pop_failure_jump.\n",
-                                 c, p1[5]);
-                 }
-
-               else if ((re_opcode_t) p1[3] == charset
-                        || (re_opcode_t) p1[3] == charset_not)
-                 {
-                   int not = (re_opcode_t) p1[3] == charset_not;
-
-                   if (c < (unsigned char) (p1[4] * BYTEWIDTH)
-                       && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
-                     not = !not;
-
-                   /* `not' is equal to 1 if c would match, which means
-                       that we can't change to pop_failure_jump.  */
-                   if (!not)
-                     {
-                       p[-3] = (unsigned char) pop_failure_jump;
-                       DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
-                     }
-                 }
-             }
-         }
-         p -= 2;               /* Point at relative address again.  */
-         if ((re_opcode_t) p[-1] != pop_failure_jump)
-           {
-             p[-1] = (unsigned char) jump;
-             DEBUG_PRINT1 ("  Match => jump.\n");
-             goto unconditional_jump;
-           }
-       /* Note fall through.  */
-
-
-       /* The end of a simple repeat has a pop_failure_jump back to
-          its matching on_failure_jump, where the latter will push a
-          failure point.  The pop_failure_jump takes off failure
-          points put on by this pop_failure_jump's matching
-          on_failure_jump; we got through the pattern to here from the
-          matching on_failure_jump, so didn't fail.  */
-       case pop_failure_jump:
-         {
-           /* We need to pass separate storage for the lowest and
-              highest registers, even though we don't care about the
-              actual values.  Otherwise, we will restore only one
-              register from the stack, since lowest will == highest in
-              `pop_failure_point'.  */
-           unsigned dummy_low_reg, dummy_high_reg;
-           unsigned char *pdummy;
-           const char *sdummy;
-
-           DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
-           POP_FAILURE_POINT (sdummy, pdummy,
-                              dummy_low_reg, dummy_high_reg,
-                              reg_dummy, reg_dummy, reg_info_dummy);
-         }
-         /* Note fall through.  */
-
-
-       /* Unconditionally jump (without popping any failure points).  */
-       case jump:
-       unconditional_jump:
-         EXTRACT_NUMBER_AND_INCR (mcnt, p);    /* Get the amount to jump.  */
-         DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
-         p += mcnt;                            /* Do the jump.  */
-         DEBUG_PRINT2 ("(to 0x%x).\n", p);
-         break;
-
-
-       /* We need this opcode so we can detect where alternatives end
-          in `group_match_null_string_p' et al.  */
-       case jump_past_alt:
-         DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n");
-         goto unconditional_jump;
-
-
-       /* Normally, the on_failure_jump pushes a failure point, which
-          then gets popped at pop_failure_jump.  We will end up at
-          pop_failure_jump, also, and with a pattern of, say, `a+', we
-          are skipping over the on_failure_jump, so we have to push
-          something meaningless for pop_failure_jump to pop.  */
-       case dummy_failure_jump:
-         DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n");
-         /* It doesn't matter what we push for the string here.  What
-            the code at `fail' tests is the value for the pattern.  */
-         PUSH_FAILURE_POINT (0, 0, -2);
-         goto unconditional_jump;
-
-
-       /* At the end of an alternative, we need to push a dummy failure
-          point in case we are followed by a `pop_failure_jump', because
-          we don't want the failure point for the alternative to be
-          popped.  For example, matching `(a|ab)*' against `aab'
-          requires that we match the `ab' alternative.  */
-       case push_dummy_failure:
-         DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n");
-         /* See comments just above at `dummy_failure_jump' about the
-            two zeroes.  */
-         PUSH_FAILURE_POINT (0, 0, -2);
-         break;
-
-       /* Have to succeed matching what follows at least n times.
-          After that, handle like `on_failure_jump'.  */
-       case succeed_n:
-         EXTRACT_NUMBER (mcnt, p + 2);
-         DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
-
-         assert (mcnt >= 0);
-         /* Originally, this is how many times we HAVE to succeed.  */
-         if (mcnt > 0)
-           {
-              mcnt--;
-              p += 2;
-              STORE_NUMBER_AND_INCR (p, mcnt);
-              DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p, mcnt);
-           }
-         else if (mcnt == 0)
-           {
-             DEBUG_PRINT2 ("  Setting two bytes from 0x%x to no_op.\n", p+2);
-             p[2] = (unsigned char) no_op;
-             p[3] = (unsigned char) no_op;
-             goto on_failure;
-           }
-         break;
-
-       case jump_n:
-         EXTRACT_NUMBER (mcnt, p + 2);
-         DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt);
-
-         /* Originally, this is how many times we CAN jump.  */
-         if (mcnt)
-           {
-              mcnt--;
-              STORE_NUMBER (p + 2, mcnt);
-              goto unconditional_jump;
-           }
-         /* If don't have to jump any more, skip over the rest of command.  */
-         else
-           p += 4;
-         break;
-
-       case set_number_at:
-         {
-           DEBUG_PRINT1 ("EXECUTING set_number_at.\n");
-
-           EXTRACT_NUMBER_AND_INCR (mcnt, p);
-           p1 = p + mcnt;
-           EXTRACT_NUMBER_AND_INCR (mcnt, p);
-           DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p1, mcnt);
-           STORE_NUMBER (p1, mcnt);
-           break;
-         }
-
-       case wordbound:
-         DEBUG_PRINT1 ("EXECUTING wordbound.\n");
-         if (AT_WORD_BOUNDARY (d))
-           break;
-         goto fail;
-
-       case notwordbound:
-         DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
-         if (AT_WORD_BOUNDARY (d))
-           goto fail;
-         break;
-
-       case wordbeg:
-         DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
-         if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
-           break;
-         goto fail;
-
-       case wordend:
-         DEBUG_PRINT1 ("EXECUTING wordend.\n");
-         if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
-             && (!WORDCHAR_P (d) || AT_STRINGS_END (d)))
-           break;
-         goto fail;
-
-#ifdef emacs
-#ifdef emacs19
-       case before_dot:
-         DEBUG_PRINT1 ("EXECUTING before_dot.\n");
-         if (PTR_CHAR_POS ((unsigned char *) d) >= point)
-           goto fail;
-         break;
-
-       case at_dot:
-         DEBUG_PRINT1 ("EXECUTING at_dot.\n");
-         if (PTR_CHAR_POS ((unsigned char *) d) != point)
-           goto fail;
-         break;
-
-       case after_dot:
-         DEBUG_PRINT1 ("EXECUTING after_dot.\n");
-         if (PTR_CHAR_POS ((unsigned char *) d) <= point)
-           goto fail;
-         break;
-#else /* not emacs19 */
-       case at_dot:
-         DEBUG_PRINT1 ("EXECUTING at_dot.\n");
-         if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point)
-           goto fail;
-         break;
-#endif /* not emacs19 */
-
-       case syntaxspec:
-         DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
-         mcnt = *p++;
-         goto matchsyntax;
-
-       case wordchar:
-         DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
-         mcnt = (int) Sword;
-       matchsyntax:
-         PREFETCH ();
-         if (SYNTAX (*d++) != (enum syntaxcode) mcnt)
-           goto fail;
-         SET_REGS_MATCHED ();
-         break;
-
-       case notsyntaxspec:
-         DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt);
-         mcnt = *p++;
-         goto matchnotsyntax;
-
-       case notwordchar:
-         DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n");
-         mcnt = (int) Sword;
-       matchnotsyntax:
-         PREFETCH ();
-         if (SYNTAX (*d++) == (enum syntaxcode) mcnt)
-           goto fail;
-         SET_REGS_MATCHED ();
-         break;
-
-#else /* not emacs */
-       case wordchar:
-         DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
-         PREFETCH ();
-         if (!WORDCHAR_P (d))
-           goto fail;
-         SET_REGS_MATCHED ();
-         d++;
-         break;
-
-       case notwordchar:
-         DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
-         PREFETCH ();
-         if (WORDCHAR_P (d))
-           goto fail;
-         SET_REGS_MATCHED ();
-         d++;
-         break;
-#endif /* not emacs */
-
-       default:
-         abort ();
-       }
-      continue;  /* Successfully executed one pattern command; keep going.  */
-
-
-    /* We goto here if a matching operation fails. */
-    fail:
-      if (!FAIL_STACK_EMPTY ())
-       { /* A restart point is known.  Restore to that state.  */
-         DEBUG_PRINT1 ("\nFAIL:\n");
-         POP_FAILURE_POINT (d, p,
-                            lowest_active_reg, highest_active_reg,
-                            regstart, regend, reg_info);
-
-         /* If this failure point is a dummy, try the next one.  */
-         if (!p)
-           goto fail;
-
-         /* If we failed to the end of the pattern, don't examine *p.  */
-         assert (p <= pend);
-         if (p < pend)
-           {
-             boolean is_a_jump_n = false;
-
-             /* If failed to a backwards jump that's part of a repetition
-                loop, need to pop this failure point and use the next one.  */
-             switch ((re_opcode_t) *p)
-               {
-               case jump_n:
-                 is_a_jump_n = true;
-               case maybe_pop_jump:
-               case pop_failure_jump:
-               case jump:
-                 p1 = p + 1;
-                 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
-                 p1 += mcnt;
-
-                 if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n)
-                     || (!is_a_jump_n
-                         && (re_opcode_t) *p1 == on_failure_jump))
-                   goto fail;
-                 break;
-               default:
-                 /* do nothing */ ;
-               }
-           }
-
-         if (d >= string1 && d <= end1)
-           dend = end_match_1;
-       }
-      else
-       break;   /* Matching at this starting point really fails.  */
-    } /* for (;;) */
-
-  if (best_regs_set)
-    goto restore_best_regs;
-
-  FREE_VARIABLES ();
-
-  return -1;                           /* Failure to match.  */
-} /* re_match_2 */
-\f
-/* Subroutine definitions for re_match_2.  */
-
-
-/* We are passed P pointing to a register number after a start_memory.
-
-   Return true if the pattern up to the corresponding stop_memory can
-   match the empty string, and false otherwise.
-
-   If we find the matching stop_memory, sets P to point to one past its number.
-   Otherwise, sets P to an undefined byte less than or equal to END.
-
-   We don't handle duplicates properly (yet).  */
-
-static boolean
-group_match_null_string_p (p, end, reg_info)
-    unsigned char **p, *end;
-    register_info_type *reg_info;
-{
-  int mcnt;
-  /* Point to after the args to the start_memory.  */
-  unsigned char *p1 = *p + 2;
-
-  while (p1 < end)
-    {
-      /* Skip over opcodes that can match nothing, and return true or
-        false, as appropriate, when we get to one that can't, or to the
-        matching stop_memory.  */
-
-      switch ((re_opcode_t) *p1)
-       {
-       /* Could be either a loop or a series of alternatives.  */
-       case on_failure_jump:
-         p1++;
-         EXTRACT_NUMBER_AND_INCR (mcnt, p1);
-
-         /* If the next operation is not a jump backwards in the
-            pattern.  */
-
-         if (mcnt >= 0)
-           {
-             /* Go through the on_failure_jumps of the alternatives,
-                seeing if any of the alternatives cannot match nothing.
-                The last alternative starts with only a jump,
-                whereas the rest start with on_failure_jump and end
-                with a jump, e.g., here is the pattern for `a|b|c':
-
-                /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6
-                /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3
-                /exactn/1/c
-
-                So, we have to first go through the first (n-1)
-                alternatives and then deal with the last one separately.  */
-
-
-             /* Deal with the first (n-1) alternatives, which start
-                with an on_failure_jump (see above) that jumps to right
-                past a jump_past_alt.  */
-
-             while ((re_opcode_t) p1[mcnt-3] == jump_past_alt)
-               {
-                 /* `mcnt' holds how many bytes long the alternative
-                    is, including the ending `jump_past_alt' and
-                    its number.  */
-
-                 if (!alt_match_null_string_p (p1, p1 + mcnt - 3,
-                                                     reg_info))
-                   return false;
-
-                 /* Move to right after this alternative, including the
-                    jump_past_alt.  */
-                 p1 += mcnt;
-
-                 /* Break if it's the beginning of an n-th alternative
-                    that doesn't begin with an on_failure_jump.  */
-                 if ((re_opcode_t) *p1 != on_failure_jump)
-                   break;
-
-                 /* Still have to check that it's not an n-th
-                    alternative that starts with an on_failure_jump.  */
-                 p1++;
-                 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
-                 if ((re_opcode_t) p1[mcnt-3] != jump_past_alt)
-                   {
-                     /* Get to the beginning of the n-th alternative.  */
-                     p1 -= 3;
-                     break;
-                   }
-               }
-
-             /* Deal with the last alternative: go back and get number
-                of the `jump_past_alt' just before it.  `mcnt' contains
-                the length of the alternative.  */
-             EXTRACT_NUMBER (mcnt, p1 - 2);
-
-             if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info))
-               return false;
-
-             p1 += mcnt;       /* Get past the n-th alternative.  */
-           } /* if mcnt > 0 */
-         break;
-
-
-       case stop_memory:
-         assert (p1[1] == **p);
-         *p = p1 + 2;
-         return true;
-
-
-       default:
-         if (!common_op_match_null_string_p (&p1, end, reg_info))
-           return false;
-       }
-    } /* while p1 < end */
-
-  return false;
-} /* group_match_null_string_p */
-
-
-/* Similar to group_match_null_string_p, but doesn't deal with alternatives:
-   It expects P to be the first byte of a single alternative and END one
-   byte past the last. The alternative can contain groups.  */
-
-static boolean
-alt_match_null_string_p (p, end, reg_info)
-    unsigned char *p, *end;
-    register_info_type *reg_info;
-{
-  int mcnt;
-  unsigned char *p1 = p;
-
-  while (p1 < end)
-    {
-      /* Skip over opcodes that can match nothing, and break when we get
-        to one that can't.  */
-
-      switch ((re_opcode_t) *p1)
-       {
-       /* It's a loop.  */
-       case on_failure_jump:
-         p1++;
-         EXTRACT_NUMBER_AND_INCR (mcnt, p1);
-         p1 += mcnt;
-         break;
-
-       default:
-         if (!common_op_match_null_string_p (&p1, end, reg_info))
-           return false;
-       }
-    }  /* while p1 < end */
-
-  return true;
-} /* alt_match_null_string_p */
-
-
-/* Deals with the ops common to group_match_null_string_p and
-   alt_match_null_string_p.
-
-   Sets P to one after the op and its arguments, if any.  */
-
-static boolean
-common_op_match_null_string_p (p, end, reg_info)
-    unsigned char **p, *end;
-    register_info_type *reg_info;
-{
-  int mcnt;
-  boolean ret;
-  int reg_no;
-  unsigned char *p1 = *p;
-
-  switch ((re_opcode_t) *p1++)
-    {
-    case no_op:
-    case begline:
-    case endline:
-    case begbuf:
-    case endbuf:
-    case wordbeg:
-    case wordend:
-    case wordbound:
-    case notwordbound:
-#ifdef emacs
-    case before_dot:
-    case at_dot:
-    case after_dot:
-#endif
-      break;
-
-    case start_memory:
-      reg_no = *p1;
-      assert (reg_no > 0 && reg_no <= MAX_REGNUM);
-      ret = group_match_null_string_p (&p1, end, reg_info);
-
-      /* Have to set this here in case we're checking a group which
-        contains a group and a back reference to it.  */
-
-      if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE)
-       REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret;
-
-      if (!ret)
-       return false;
-      break;
-
-    /* If this is an optimized succeed_n for zero times, make the jump.  */
-    case jump:
-      EXTRACT_NUMBER_AND_INCR (mcnt, p1);
-      if (mcnt >= 0)
-       p1 += mcnt;
-      else
-       return false;
-      break;
-
-    case succeed_n:
-      /* Get to the number of times to succeed.  */
-      p1 += 2;
-      EXTRACT_NUMBER_AND_INCR (mcnt, p1);
-
-      if (mcnt == 0)
-       {
-         p1 -= 4;
-         EXTRACT_NUMBER_AND_INCR (mcnt, p1);
-         p1 += mcnt;
-       }
-      else
-       return false;
-      break;
-
-    case duplicate:
-      if (!REG_MATCH_NULL_STRING_P (reg_info[*p1]))
-       return false;
-      break;
-
-    case set_number_at:
-      p1 += 4;
-
-    default:
-      /* All other opcodes mean we cannot match the empty string.  */
-      return false;
-  }
-
-  *p = p1;
-  return true;
-} /* common_op_match_null_string_p */
-
-
-/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN
-   bytes; nonzero otherwise.  */
-
-static int
-bcmp_translate(
-     unsigned char *s1,
-     unsigned char *s2,
-     int len,
-     char *translate
-)
-{
-  register unsigned char *p1 = s1, *p2 = s2;
-  while (len)
-    {
-      if (translate[*p1++] != translate[*p2++]) return 1;
-      len--;
-    }
-  return 0;
-}
-\f
-/* Entry points for GNU code.  */
-
-/* re_compile_pattern is the GNU regular expression compiler: it
-   compiles PATTERN (of length SIZE) and puts the result in BUFP.
-   Returns 0 if the pattern was valid, otherwise an error string.
-
-   Assumes the `allocated' (and perhaps `buffer') and `translate' fields
-   are set in BUFP on entry.
-
-   We call regex_compile to do the actual compilation.  */
-
-const char *
-re_compile_pattern (pattern, length, bufp)
-     const char *pattern;
-     int length;
-     struct re_pattern_buffer *bufp;
-{
-  reg_errcode_t ret;
-
-  /* GNU code is written to assume at least RE_NREGS registers will be set
-     (and at least one extra will be -1).  */
-  bufp->regs_allocated = REGS_UNALLOCATED;
-
-  /* And GNU code determines whether or not to get register information
-     by passing null for the REGS argument to re_match, etc., not by
-     setting no_sub.  */
-  bufp->no_sub = 0;
-
-  /* Match anchors at newline.  */
-  bufp->newline_anchor = 1;
-
-  ret = regex_compile (pattern, length, re_syntax_options, bufp);
-
-  return re_error_msg[(int) ret];
-}
-\f
-/* Entry points compatible with 4.2 BSD regex library.  We don't define
-   them if this is an Emacs or POSIX compilation.  */
-
-#if !defined (emacs) && !defined (_POSIX_SOURCE)
-
-/* BSD has one and only one pattern buffer.  */
-static struct re_pattern_buffer re_comp_buf;
-
-char *
-re_comp (s)
-    const char *s;
-{
-  reg_errcode_t ret;
-
-  if (!s)
-    {
-      if (!re_comp_buf.buffer)
-       return "No previous regular expression";
-      return 0;
-    }
-
-  if (!re_comp_buf.buffer)
-    {
-      re_comp_buf.buffer = (unsigned char *) malloc (200);
-      if (re_comp_buf.buffer == NULL)
-       return "Memory exhausted";
-      re_comp_buf.allocated = 200;
-
-      re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH);
-      if (re_comp_buf.fastmap == NULL)
-       return "Memory exhausted";
-    }
-
-  /* Since `re_exec' always passes NULL for the `regs' argument, we
-     don't need to initialize the pattern buffer fields which affect it.  */
-
-  /* Match anchors at newlines.  */
-  re_comp_buf.newline_anchor = 1;
-
-  ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
-
-  /* Yes, we're discarding `const' here.  */
-  return (char *) re_error_msg[(int) ret];
-}
-
-
-int
-re_exec (s)
-    const char *s;
-{
-  const int len = strlen (s);
-  return
-    0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0);
-}
-#endif /* not emacs and not _POSIX_SOURCE */
-\f
-/* POSIX.2 functions.  Don't define these for Emacs.  */
-
-#ifndef emacs
-
-/* regcomp takes a regular expression as a string and compiles it.
-
-   PREG is a regex_t *.  We do not expect any fields to be initialized,
-   since POSIX says we shouldn't.  Thus, we set
-
-     `buffer' to the compiled pattern;
-     `used' to the length of the compiled pattern;
-     `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
-       REG_EXTENDED bit in CFLAGS is set; otherwise, to
-       RE_SYNTAX_POSIX_BASIC;
-     `newline_anchor' to REG_NEWLINE being set in CFLAGS;
-     `fastmap' and `fastmap_accurate' to zero;
-     `re_nsub' to the number of subexpressions in PATTERN.
-
-   PATTERN is the address of the pattern string.
-
-   CFLAGS is a series of bits which affect compilation.
-
-     If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
-     use POSIX basic syntax.
-
-     If REG_NEWLINE is set, then . and [^...] don't match newline.
-     Also, regexec will try a match beginning after every newline.
-
-     If REG_ICASE is set, then we considers upper- and lowercase
-     versions of letters to be equivalent when matching.
-
-     If REG_NOSUB is set, then when PREG is passed to regexec, that
-     routine will report only success or failure, and nothing about the
-     registers.
-
-   It returns 0 if it succeeds, nonzero if it doesn't.  (See regex.h for
-   the return codes and their meanings.)  */
-
-int
-regcomp (preg, pattern, cflags)
-    regex_t *preg;
-    const char *pattern;
-    int cflags;
-{
-  reg_errcode_t ret;
-  unsigned syntax
-    = (cflags & REG_EXTENDED) ?
-      RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
-
-  /* regex_compile will allocate the space for the compiled pattern.  */
-  preg->buffer = 0;
-  preg->allocated = 0;
-
-  /* Don't bother to use a fastmap when searching.  This simplifies the
-     REG_NEWLINE case: if we used a fastmap, we'd have to put all the
-     characters after newlines into the fastmap.  This way, we just try
-     every character.  */
-  preg->fastmap = 0;
-
-  if (cflags & REG_ICASE)
-    {
-      unsigned i;
-
-      preg->translate = (char *) malloc (CHAR_SET_SIZE);
-      if (preg->translate == NULL)
-       return (int) REG_ESPACE;
-
-      /* Map uppercase characters to corresponding lowercase ones.  */
-      for (i = 0; i < CHAR_SET_SIZE; i++)
-       preg->translate[i] = ISUPPER (i) ? tolower (i) : i;
-    }
-  else
-    preg->translate = NULL;
-
-  /* If REG_NEWLINE is set, newlines are treated differently.  */
-  if (cflags & REG_NEWLINE)
-    { /* REG_NEWLINE implies neither . nor [^...] match newline.  */
-      syntax &= ~RE_DOT_NEWLINE;
-      syntax |= RE_HAT_LISTS_NOT_NEWLINE;
-      /* It also changes the matching behavior.  */
-      preg->newline_anchor = 1;
-    }
-  else
-    preg->newline_anchor = 0;
-
-  preg->no_sub = !!(cflags & REG_NOSUB);
-
-  /* POSIX says a null character in the pattern terminates it, so we
-     can use strlen here in compiling the pattern.  */
-  ret = regex_compile (pattern, strlen (pattern), syntax, preg);
-
-  /* POSIX doesn't distinguish between an unmatched open-group and an
-     unmatched close-group: both are REG_EPAREN.  */
-  if (ret == REG_ERPAREN) ret = REG_EPAREN;
-
-  return (int) ret;
-}
-
-
-/* regexec searches for a given pattern, specified by PREG, in the
-   string STRING.
-
-   If NMATCH is zero or REG_NOSUB was set in the cflags argument to
-   `regcomp', we ignore PMATCH.  Otherwise, we assume PMATCH has at
-   least NMATCH elements, and we set them to the offsets of the
-   corresponding matched substrings.
-
-   EFLAGS specifies `execution flags' which affect matching: if
-   REG_NOTBOL is set, then ^ does not match at the beginning of the
-   string; if REG_NOTEOL is set, then $ does not match at the end.
-
-   We return 0 if we find a match and REG_NOMATCH if not.  */
-
-int
-regexec (preg, string, nmatch, pmatch, eflags)
-    const regex_t *preg;
-    const char *string;
-    size_t nmatch;
-    regmatch_t pmatch[];
-    int eflags;
-{
-  int ret;
-  struct re_registers regs;
-  regex_t private_preg;
-  int len = strlen (string);
-  boolean want_reg_info = !preg->no_sub && nmatch > 0;
-
-  private_preg = *preg;
-
-  private_preg.not_bol = !!(eflags & REG_NOTBOL);
-  private_preg.not_eol = !!(eflags & REG_NOTEOL);
-
-  /* The user has told us exactly how many registers to return
-     information about, via `nmatch'.  We have to pass that on to the
-     matching routines.  */
-  private_preg.regs_allocated = REGS_FIXED;
-
-  if (want_reg_info)
-    {
-      regs.num_regs = nmatch;
-      regs.start = TALLOC (nmatch, regoff_t);
-      regs.end = TALLOC (nmatch, regoff_t);
-      if (regs.start == NULL || regs.end == NULL)
-       return (int) REG_NOMATCH;
-    }
-
-  /* Perform the searching operation.  */
-  ret = re_search (&private_preg, string, len,
-                  /* start: */ 0, /* range: */ len,
-                  want_reg_info ? &regs : (struct re_registers *) 0);
-
-  /* Copy the register information to the POSIX structure.  */
-  if (want_reg_info)
-    {
-      if (ret >= 0)
-       {
-         unsigned r;
-
-         for (r = 0; r < nmatch; r++)
-           {
-             pmatch[r].rm_so = regs.start[r];
-             pmatch[r].rm_eo = regs.end[r];
-           }
-       }
-
-      /* If we needed the temporary register info, free the space now.  */
-      free (regs.start);
-      free (regs.end);
-    }
-
-  /* We want zero return to mean success, unlike `re_search'.  */
-  return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
-}
-
-
-/* Returns a message corresponding to an error code, ERRCODE, returned
-   from either regcomp or regexec.   We don't use PREG here.  */
-
-size_t
-regerror (errcode, preg, errbuf, errbuf_size)
-    int errcode;
-    const regex_t *preg;
-    char *errbuf;
-    size_t errbuf_size;
-{
-  const char *msg;
-  size_t msg_size;
-
-  if (errcode < 0
-      || errcode >= (sizeof (re_error_msg) / sizeof (re_error_msg[0])))
-    /* Only error codes returned by the rest of the code should be passed
-       to this routine.  If we are given anything else, or if other regex
-       code generates an invalid error code, then the program has a bug.
-       Dump core so we can fix it.  */
-    abort ();
-
-  msg = re_error_msg[errcode];
-
-  /* POSIX doesn't require that we do anything in this case, but why
-     not be nice.  */
-  if (! msg)
-    msg = "Success";
-
-  msg_size = strlen (msg) + 1; /* Includes the null.  */
-
-  if (errbuf_size != 0)
-    {
-      if (msg_size > errbuf_size)
-       {
-         strncpy (errbuf, msg, errbuf_size - 1);
-         errbuf[errbuf_size - 1] = 0;
-       }
-      else
-       strcpy (errbuf, msg);
-    }
-
-  return msg_size;
-}
-
-
-/* Free dynamically allocated space used by PREG.  */
-
-void
-regfree (preg)
-    regex_t *preg;
-{
-  if (preg->buffer != NULL)
-    free (preg->buffer);
-  preg->buffer = NULL;
-
-  preg->allocated = 0;
-  preg->used = 0;
-
-  if (preg->fastmap != NULL)
-    free (preg->fastmap);
-  preg->fastmap = NULL;
-  preg->fastmap_accurate = 0;
-
-  if (preg->translate != NULL)
-    free (preg->translate);
-  preg->translate = NULL;
-}
-
-#endif /* not emacs  */
-\f
-/*
-Local variables:
-make-backup-files: t
-version-control: t
-trim-versions-without-asking: nil
-End:
-*/
diff --git a/compat/regex.h b/compat/regex.h
deleted file mode 100644 (file)
index 6eb64f1..0000000
+++ /dev/null
@@ -1,490 +0,0 @@
-/* Definitions for data structures and routines for the regular
-   expression library, version 0.12.
-
-   Copyright (C) 1985, 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
-
-#ifndef __REGEXP_LIBRARY_H__
-#define __REGEXP_LIBRARY_H__
-
-/* POSIX says that <sys/types.h> must be included (by the caller) before
-   <regex.h>.  */
-
-#ifdef VMS
-/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
-   should be there.  */
-#include <stddef.h>
-#endif
-
-
-/* The following bits are used to determine the regexp syntax we
-   recognize.  The set/not-set meanings are chosen so that Emacs syntax
-   remains the value 0.  The bits are given in alphabetical order, and
-   the definitions shifted by one from the previous bit; thus, when we
-   add or remove a bit, only one other definition need change.  */
-typedef unsigned reg_syntax_t;
-
-/* If this bit is not set, then \ inside a bracket expression is literal.
-   If set, then such a \ quotes the following character.  */
-#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)
-
-/* If this bit is not set, then + and ? are operators, and \+ and \? are
-     literals.
-   If set, then \+ and \? are operators and + and ? are literals.  */
-#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
-
-/* If this bit is set, then character classes are supported.  They are:
-     [:alpha:], [:upper:], [:lower:],  [:digit:], [:alnum:], [:xdigit:],
-     [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
-   If not set, then character classes are not supported.  */
-#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
-
-/* If this bit is set, then ^ and $ are always anchors (outside bracket
-     expressions, of course).
-   If this bit is not set, then it depends:
-       ^  is an anchor if it is at the beginning of a regular
-          expression or after an open-group or an alternation operator;
-       $  is an anchor if it is at the end of a regular expression, or
-          before a close-group or an alternation operator.
-
-   This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
-   POSIX draft 11.2 says that * etc. in leading positions is undefined.
-   We already implemented a previous draft which made those constructs
-   invalid, though, so we haven't changed the code back.  */
-#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
-
-/* If this bit is set, then special characters are always special
-     regardless of where they are in the pattern.
-   If this bit is not set, then special characters are special only in
-     some contexts; otherwise they are ordinary.  Specifically,
-     * + ? and intervals are only special when not after the beginning,
-     open-group, or alternation operator.  */
-#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
-
-/* If this bit is set, then *, +, ?, and { cannot be first in an re or
-     immediately after an alternation or begin-group operator.  */
-#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
-
-/* If this bit is set, then . matches newline.
-   If not set, then it doesn't.  */
-#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
-
-/* If this bit is set, then . doesn't match NUL.
-   If not set, then it does.  */
-#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
-
-/* If this bit is set, nonmatching lists [^...] do not match newline.
-   If not set, they do.  */
-#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
-
-/* If this bit is set, either \{...\} or {...} defines an
-     interval, depending on RE_NO_BK_BRACES.
-   If not set, \{, \}, {, and } are literals.  */
-#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
-
-/* If this bit is set, +, ? and | aren't recognized as operators.
-   If not set, they are.  */
-#define RE_LIMITED_OPS (RE_INTERVALS << 1)
-
-/* If this bit is set, newline is an alternation operator.
-   If not set, newline is literal.  */
-#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
-
-/* If this bit is set, then `{...}' defines an interval, and \{ and \}
-     are literals.
-  If not set, then `\{...\}' defines an interval.  */
-#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
-
-/* If this bit is set, (...) defines a group, and \( and \) are literals.
-   If not set, \(...\) defines a group, and ( and ) are literals.  */
-#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
-
-/* If this bit is set, then \<digit> matches <digit>.
-   If not set, then \<digit> is a back-reference.  */
-#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
-
-/* If this bit is set, then | is an alternation operator, and \| is literal.
-   If not set, then \| is an alternation operator, and | is literal.  */
-#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
-
-/* If this bit is set, then an ending range point collating higher
-     than the starting range point, as in [z-a], is invalid.
-   If not set, then when ending range point collates higher than the
-     starting range point, the range is ignored.  */
-#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
-
-/* If this bit is set, then an unmatched ) is ordinary.
-   If not set, then an unmatched ) is invalid.  */
-#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
-
-/* This global variable defines the particular regexp syntax to use (for
-   some interfaces).  When a regexp is compiled, the syntax used is
-   stored in the pattern buffer, so changing this does not affect
-   already-compiled regexps.  */
-extern reg_syntax_t re_syntax_options;
-\f
-/* Define combinations of the above bits for the standard possibilities.
-   (The [[[ comments delimit what gets put into the Texinfo file, so
-   don't delete them!)  */
-/* [[[begin syntaxes]]] */
-#define RE_SYNTAX_EMACS 0
-
-#define RE_SYNTAX_AWK                                                  \
-  (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL                      \
-   | RE_NO_BK_PARENS            | RE_NO_BK_REFS                                \
-   | RE_NO_BK_VBAR               | RE_NO_EMPTY_RANGES                  \
-   | RE_UNMATCHED_RIGHT_PAREN_ORD)
-
-#define RE_SYNTAX_POSIX_AWK                                            \
-  (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
-
-#define RE_SYNTAX_GREP                                                 \
-  (RE_BK_PLUS_QM              | RE_CHAR_CLASSES                                \
-   | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS                           \
-   | RE_NEWLINE_ALT)
-
-#define RE_SYNTAX_EGREP                                                        \
-  (RE_CHAR_CLASSES        | RE_CONTEXT_INDEP_ANCHORS                   \
-   | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE                   \
-   | RE_NEWLINE_ALT       | RE_NO_BK_PARENS                            \
-   | RE_NO_BK_VBAR)
-
-#define RE_SYNTAX_POSIX_EGREP                                          \
-  (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
-
-/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff.  */
-#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
-
-#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
-
-/* Syntax bits common to both basic and extended POSIX regex syntax.  */
-#define _RE_SYNTAX_POSIX_COMMON                                                \
-  (RE_CHAR_CLASSES | RE_DOT_NEWLINE      | RE_DOT_NOT_NULL             \
-   | RE_INTERVALS  | RE_NO_EMPTY_RANGES)
-
-#define RE_SYNTAX_POSIX_BASIC                                          \
-  (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
-
-/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
-   RE_LIMITED_OPS, i.e., \? \+ \| are not recognized.  Actually, this
-   isn't minimal, since other operators, such as \`, aren't disabled.  */
-#define RE_SYNTAX_POSIX_MINIMAL_BASIC                                  \
-  (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
-
-#define RE_SYNTAX_POSIX_EXTENDED                                       \
-  (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS                  \
-   | RE_CONTEXT_INDEP_OPS  | RE_NO_BK_BRACES                           \
-   | RE_NO_BK_PARENS       | RE_NO_BK_VBAR                             \
-   | RE_UNMATCHED_RIGHT_PAREN_ORD)
-
-/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
-   replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added.  */
-#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED                               \
-  (_RE_SYNTAX_POSIX_COMMON  | RE_CONTEXT_INDEP_ANCHORS                 \
-   | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES                          \
-   | RE_NO_BK_PARENS        | RE_NO_BK_REFS                            \
-   | RE_NO_BK_VBAR         | RE_UNMATCHED_RIGHT_PAREN_ORD)
-/* [[[end syntaxes]]] */
-\f
-/* Maximum number of duplicates an interval can allow.  Some systems
-   (erroneously) define this in other header files, but we want our
-   value, so remove any previous define.  */
-#ifdef RE_DUP_MAX
-#undef RE_DUP_MAX
-#endif
-#define RE_DUP_MAX ((1 << 15) - 1)
-
-
-/* POSIX `cflags' bits (i.e., information for `regcomp').  */
-
-/* If this bit is set, then use extended regular expression syntax.
-   If not set, then use basic regular expression syntax.  */
-#define REG_EXTENDED 1
-
-/* If this bit is set, then ignore case when matching.
-   If not set, then case is significant.  */
-#define REG_ICASE (REG_EXTENDED << 1)
-
-/* If this bit is set, then anchors do not match at newline
-     characters in the string.
-   If not set, then anchors do match at newlines.  */
-#define REG_NEWLINE (REG_ICASE << 1)
-
-/* If this bit is set, then report only success or fail in regexec.
-   If not set, then returns differ between not matching and errors.  */
-#define REG_NOSUB (REG_NEWLINE << 1)
-
-
-/* POSIX `eflags' bits (i.e., information for regexec).  */
-
-/* If this bit is set, then the beginning-of-line operator doesn't match
-     the beginning of the string (presumably because it's not the
-     beginning of a line).
-   If not set, then the beginning-of-line operator does match the
-     beginning of the string.  */
-#define REG_NOTBOL 1
-
-/* Like REG_NOTBOL, except for the end-of-line.  */
-#define REG_NOTEOL (1 << 1)
-
-
-/* If any error codes are removed, changed, or added, update the
-   `re_error_msg' table in regex.c.  */
-typedef enum
-{
-  REG_NOERROR = 0,     /* Success.  */
-  REG_NOMATCH,         /* Didn't find a match (for regexec).  */
-
-  /* POSIX regcomp return error codes.  (In the order listed in the
-     standard.)  */
-  REG_BADPAT,          /* Invalid pattern.  */
-  REG_ECOLLATE,                /* Not implemented.  */
-  REG_ECTYPE,          /* Invalid character class name.  */
-  REG_EESCAPE,         /* Trailing backslash.  */
-  REG_ESUBREG,         /* Invalid back reference.  */
-  REG_EBRACK,          /* Unmatched left bracket.  */
-  REG_EPAREN,          /* Parenthesis imbalance.  */
-  REG_EBRACE,          /* Unmatched \{.  */
-  REG_BADBR,           /* Invalid contents of \{\}.  */
-  REG_ERANGE,          /* Invalid range end.  */
-  REG_ESPACE,          /* Ran out of memory.  */
-  REG_BADRPT,          /* No preceding re for repetition op.  */
-
-  /* Error codes we've added.  */
-  REG_EEND,            /* Premature end.  */
-  REG_ESIZE,           /* Compiled pattern bigger than 2^16 bytes.  */
-  REG_ERPAREN          /* Unmatched ) or \); not returned from regcomp.  */
-} reg_errcode_t;
-\f
-/* This data structure represents a compiled pattern.  Before calling
-   the pattern compiler, the fields `buffer', `allocated', `fastmap',
-   `translate', and `no_sub' can be set.  After the pattern has been
-   compiled, the `re_nsub' field is available.  All other fields are
-   private to the regex routines.  */
-
-struct re_pattern_buffer
-{
-/* [[[begin pattern_buffer]]] */
-       /* Space that holds the compiled pattern.  It is declared as
-         `unsigned char *' because its elements are
-          sometimes used as array indexes.  */
-  unsigned char *buffer;
-
-       /* Number of bytes to which `buffer' points.  */
-  unsigned long allocated;
-
-       /* Number of bytes actually used in `buffer'.  */
-  unsigned long used;
-
-       /* Syntax setting with which the pattern was compiled.  */
-  reg_syntax_t syntax;
-
-       /* Pointer to a fastmap, if any, otherwise zero.  re_search uses
-          the fastmap, if there is one, to skip over impossible
-          starting points for matches.  */
-  char *fastmap;
-
-       /* Either a translate table to apply to all characters before
-          comparing them, or zero for no translation.  The translation
-          is applied to a pattern when it is compiled and to a string
-          when it is matched.  */
-  char *translate;
-
-       /* Number of subexpressions found by the compiler.  */
-  size_t re_nsub;
-
-       /* Zero if this pattern cannot match the empty string, one else.
-          Well, in truth it's used only in `re_search_2', to see
-          whether or not we should use the fastmap, so we don't set
-          this absolutely perfectly; see `re_compile_fastmap' (the
-          `duplicate' case).  */
-  unsigned can_be_null : 1;
-
-       /* If REGS_UNALLOCATED, allocate space in the `regs' structure
-            for `max (RE_NREGS, re_nsub + 1)' groups.
-          If REGS_REALLOCATE, reallocate space if necessary.
-          If REGS_FIXED, use what's there.  */
-#define REGS_UNALLOCATED 0
-#define REGS_REALLOCATE 1
-#define REGS_FIXED 2
-  unsigned regs_allocated : 2;
-
-       /* Set to zero when `regex_compile' compiles a pattern; set to one
-          by `re_compile_fastmap' if it updates the fastmap.  */
-  unsigned fastmap_accurate : 1;
-
-       /* If set, `re_match_2' does not return information about
-          subexpressions.  */
-  unsigned no_sub : 1;
-
-       /* If set, a beginning-of-line anchor doesn't match at the
-          beginning of the string.  */
-  unsigned not_bol : 1;
-
-       /* Similarly for an end-of-line anchor.  */
-  unsigned not_eol : 1;
-
-       /* If true, an anchor at a newline matches.  */
-  unsigned newline_anchor : 1;
-
-/* [[[end pattern_buffer]]] */
-};
-
-typedef struct re_pattern_buffer regex_t;
-
-
-/* search.c (search_buffer) in Emacs needs this one opcode value.  It is
-   defined both in `regex.c' and here.  */
-#define RE_EXACTN_VALUE 1
-\f
-/* Type for byte offsets within the string.  POSIX mandates this.  */
-typedef int regoff_t;
-
-
-/* This is the structure we store register match data in.  See
-   regex.texinfo for a full description of what registers match.  */
-struct re_registers
-{
-  unsigned num_regs;
-  regoff_t *start;
-  regoff_t *end;
-};
-
-
-/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
-   `re_match_2' returns information about at least this many registers
-   the first time a `regs' structure is passed.  */
-#ifndef RE_NREGS
-#define RE_NREGS 30
-#endif
-
-
-/* POSIX specification for registers.  Aside from the different names than
-   `re_registers', POSIX uses an array of structures, instead of a
-   structure of arrays.  */
-typedef struct
-{
-  regoff_t rm_so;  /* Byte offset from string's start to substring's start.  */
-  regoff_t rm_eo;  /* Byte offset from string's start to substring's end.  */
-} regmatch_t;
-\f
-/* Declarations for routines.  */
-
-/* To avoid duplicating every routine declaration -- once with a
-   prototype (if we are ANSI), and once without (if we aren't) -- we
-   use the following macro to declare argument types.  This
-   unfortunately clutters up the declarations a bit, but I think it's
-   worth it.  */
-
-#if __STDC__
-
-#define _RE_ARGS(args) args
-
-#else /* not __STDC__ */
-
-#define _RE_ARGS(args) ()
-
-#endif /* not __STDC__ */
-
-/* Sets the current default syntax to SYNTAX, and return the old syntax.
-   You can also simply assign to the `re_syntax_options' variable.  */
-extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
-
-/* Compile the regular expression PATTERN, with length LENGTH
-   and syntax given by the global `re_syntax_options', into the buffer
-   BUFFER.  Return NULL if successful, and an error string if not.  */
-extern const char *re_compile_pattern
-  _RE_ARGS ((const char *pattern, int length,
-            struct re_pattern_buffer *buffer));
-
-
-/* Compile a fastmap for the compiled pattern in BUFFER; used to
-   accelerate searches.  Return 0 if successful and -2 if was an
-   internal error.  */
-extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
-
-
-/* Search in the string STRING (with length LENGTH) for the pattern
-   compiled into BUFFER.  Start searching at position START, for RANGE
-   characters.  Return the starting position of the match, -1 for no
-   match, or -2 for an internal error.  Also return register
-   information in REGS (if REGS and BUFFER->no_sub are nonzero).  */
-extern int re_search
-  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
-           int length, int start, int range, struct re_registers *regs));
-
-
-/* Like `re_search', but search in the concatenation of STRING1 and
-   STRING2.  Also, stop searching at index START + STOP.  */
-extern int re_search_2
-  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
-            int length1, const char *string2, int length2,
-            int start, int range, struct re_registers *regs, int stop));
-
-
-/* Like `re_search', but return how many characters in STRING the regexp
-   in BUFFER matched, starting at position START.  */
-extern int re_match
-  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
-            int length, int start, struct re_registers *regs));
-
-
-/* Relates to `re_match' as `re_search_2' relates to `re_search'.  */
-extern int re_match_2
-  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
-            int length1, const char *string2, int length2,
-            int start, struct re_registers *regs, int stop));
-
-
-/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
-   ENDS.  Subsequent matches using BUFFER and REGS will use this memory
-   for recording register information.  STARTS and ENDS must be
-   allocated with malloc, and must each be at least `NUM_REGS * sizeof
-   (regoff_t)' bytes long.
-
-   If NUM_REGS == 0, then subsequent matches should allocate their own
-   register data.
-
-   Unless this function is called, the first search or match using
-   PATTERN_BUFFER will allocate its own register data, without
-   freeing the old data.  */
-extern void re_set_registers
-  _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
-            unsigned num_regs, regoff_t *starts, regoff_t *ends));
-
-/* 4.2 bsd compatibility.  */
-extern char *re_comp _RE_ARGS ((const char *));
-extern int re_exec _RE_ARGS ((const char *));
-
-/* POSIX compatibility.  */
-extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags));
-extern int regexec
-  _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch,
-            regmatch_t pmatch[], int eflags));
-extern size_t regerror
-  _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf,
-            size_t errbuf_size));
-extern void regfree _RE_ARGS ((regex_t *preg));
-
-#endif /* not __REGEXP_LIBRARY_H__ */
-\f
-/*
-Local variables:
-make-backup-files: t
-version-control: t
-trim-versions-without-asking: nil
-End:
-*/
diff --git a/compat/regex/regex.c b/compat/regex/regex.c
new file mode 100644 (file)
index 0000000..87b33e4
--- /dev/null
@@ -0,0 +1,4927 @@
+/* Extended regular expression matching and search library,
+   version 0.12.
+   (Implements POSIX draft P10003.2/D11.2, except for
+   internationalization features.)
+
+   Copyright (C) 1993 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/* AIX requires this to be the first thing in the file. */
+#if defined (_AIX) && !defined (REGEX_MALLOC)
+  #pragma alloca
+#endif
+
+#define _GNU_SOURCE
+
+/* We need this for `regex.h', and perhaps for the Emacs include files.  */
+#include <sys/types.h>
+
+/* We used to test for `BSTRING' here, but only GCC and Emacs define
+   `BSTRING', as far as I know, and neither of them use this code.  */
+#include <string.h>
+#ifndef bcmp
+#define bcmp(s1, s2, n)        memcmp ((s1), (s2), (n))
+#endif
+#ifndef bcopy
+#define bcopy(s, d, n) memcpy ((d), (s), (n))
+#endif
+#ifndef bzero
+#define bzero(s, n)    memset ((s), 0, (n))
+#endif
+
+#include <stdlib.h>
+
+
+/* Define the syntax stuff for \<, \>, etc.  */
+
+/* This must be nonzero for the wordchar and notwordchar pattern
+   commands in re_match_2.  */
+#ifndef Sword
+#define Sword 1
+#endif
+
+#ifdef SYNTAX_TABLE
+
+extern char *re_syntax_table;
+
+#else /* not SYNTAX_TABLE */
+
+/* How many characters in the character set.  */
+#define CHAR_SET_SIZE 256
+
+static char re_syntax_table[CHAR_SET_SIZE];
+
+static void
+init_syntax_once ()
+{
+   register int c;
+   static int done = 0;
+
+   if (done)
+     return;
+
+   bzero (re_syntax_table, sizeof re_syntax_table);
+
+   for (c = 'a'; c <= 'z'; c++)
+     re_syntax_table[c] = Sword;
+
+   for (c = 'A'; c <= 'Z'; c++)
+     re_syntax_table[c] = Sword;
+
+   for (c = '0'; c <= '9'; c++)
+     re_syntax_table[c] = Sword;
+
+   re_syntax_table['_'] = Sword;
+
+   done = 1;
+}
+
+#endif /* not SYNTAX_TABLE */
+
+#define SYNTAX(c) re_syntax_table[c]
+
+\f
+/* Get the interface, including the syntax bits.  */
+#include "regex.h"
+
+/* isalpha etc. are used for the character classes.  */
+#include <ctype.h>
+
+#ifndef isascii
+#define isascii(c) 1
+#endif
+
+#ifdef isblank
+#define ISBLANK(c) (isascii (c) && isblank (c))
+#else
+#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+#endif
+#ifdef isgraph
+#define ISGRAPH(c) (isascii (c) && isgraph (c))
+#else
+#define ISGRAPH(c) (isascii (c) && isprint (c) && !isspace (c))
+#endif
+
+#define ISPRINT(c) (isascii (c) && isprint (c))
+#define ISDIGIT(c) (isascii (c) && isdigit (c))
+#define ISALNUM(c) (isascii (c) && isalnum (c))
+#define ISALPHA(c) (isascii (c) && isalpha (c))
+#define ISCNTRL(c) (isascii (c) && iscntrl (c))
+#define ISLOWER(c) (isascii (c) && islower (c))
+#define ISPUNCT(c) (isascii (c) && ispunct (c))
+#define ISSPACE(c) (isascii (c) && isspace (c))
+#define ISUPPER(c) (isascii (c) && isupper (c))
+#define ISXDIGIT(c) (isascii (c) && isxdigit (c))
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* We remove any previous definition of `SIGN_EXTEND_CHAR',
+   since ours (we hope) works properly with all combinations of
+   machines, compilers, `char' and `unsigned char' argument types.
+   (Per Bothner suggested the basic approach.)  */
+#undef SIGN_EXTEND_CHAR
+#if __STDC__
+#define SIGN_EXTEND_CHAR(c) ((signed char) (c))
+#else  /* not __STDC__ */
+/* As in Harbison and Steele.  */
+#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
+#endif
+\f
+/* Should we use malloc or alloca?  If REGEX_MALLOC is not defined, we
+   use `alloca' instead of `malloc'.  This is because using malloc in
+   re_search* or re_match* could cause memory leaks when C-g is used in
+   Emacs; also, malloc is slower and causes storage fragmentation.  On
+   the other hand, malloc is more portable, and easier to debug.
+
+   Because we sometimes use alloca, some routines have to be macros,
+   not functions -- `alloca'-allocated space disappears at the end of the
+   function it is called in.  */
+
+#ifdef REGEX_MALLOC
+
+#define REGEX_ALLOCATE malloc
+#define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize)
+
+#else /* not REGEX_MALLOC  */
+
+/* Emacs already defines alloca, sometimes.  */
+#ifndef alloca
+
+/* Make alloca work the best possible way.  */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if HAVE_ALLOCA_H
+#include <alloca.h>
+#else /* not __GNUC__ or HAVE_ALLOCA_H */
+#ifndef _AIX /* Already did AIX, up at the top.  */
+char *alloca ();
+#endif /* not _AIX */
+#endif /* not HAVE_ALLOCA_H */
+#endif /* not __GNUC__ */
+
+#endif /* not alloca */
+
+#define REGEX_ALLOCATE alloca
+
+/* Assumes a `char *destination' variable.  */
+#define REGEX_REALLOCATE(source, osize, nsize)                         \
+  (destination = (char *) alloca (nsize),                              \
+   bcopy (source, destination, osize),                                 \
+   destination)
+
+#endif /* not REGEX_MALLOC */
+
+
+/* True if `size1' is non-NULL and PTR is pointing anywhere inside
+   `string1' or just past its end.  This works if PTR is NULL, which is
+   a good thing.  */
+#define FIRST_STRING_P(ptr)                                    \
+  (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
+
+/* (Re)Allocate N items of type T using malloc, or fail.  */
+#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t)))
+#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t)))
+#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t)))
+
+#define BYTEWIDTH 8 /* In bits.  */
+
+#define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
+
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+typedef char boolean;
+#define false 0
+#define true 1
+\f
+/* These are the command codes that appear in compiled regular
+   expressions.  Some opcodes are followed by argument bytes.  A
+   command code can specify any interpretation whatsoever for its
+   arguments.  Zero bytes may appear in the compiled regular expression.
+
+   The value of `exactn' is needed in search.c (search_buffer) in Emacs.
+   So regex.h defines a symbol `RE_EXACTN_VALUE' to be 1; the value of
+   `exactn' we use here must also be 1.  */
+
+typedef enum
+{
+  no_op = 0,
+
+       /* Followed by one byte giving n, then by n literal bytes.  */
+  exactn = 1,
+
+       /* Matches any (more or less) character.  */
+  anychar,
+
+       /* Matches any one char belonging to specified set.  First
+          following byte is number of bitmap bytes.  Then come bytes
+          for a bitmap saying which chars are in.  Bits in each byte
+          are ordered low-bit-first.  A character is in the set if its
+          bit is 1.  A character too large to have a bit in the map is
+          automatically not in the set.  */
+  charset,
+
+       /* Same parameters as charset, but match any character that is
+          not one of those specified.  */
+  charset_not,
+
+       /* Start remembering the text that is matched, for storing in a
+          register.  Followed by one byte with the register number, in
+          the range 0 to one less than the pattern buffer's re_nsub
+          field.  Then followed by one byte with the number of groups
+          inner to this one.  (This last has to be part of the
+          start_memory only because we need it in the on_failure_jump
+          of re_match_2.)  */
+  start_memory,
+
+       /* Stop remembering the text that is matched and store it in a
+          memory register.  Followed by one byte with the register
+          number, in the range 0 to one less than `re_nsub' in the
+          pattern buffer, and one byte with the number of inner groups,
+          just like `start_memory'.  (We need the number of inner
+          groups here because we don't have any easy way of finding the
+          corresponding start_memory when we're at a stop_memory.)  */
+  stop_memory,
+
+       /* Match a duplicate of something remembered. Followed by one
+          byte containing the register number.  */
+  duplicate,
+
+       /* Fail unless at beginning of line.  */
+  begline,
+
+       /* Fail unless at end of line.  */
+  endline,
+
+       /* Succeeds if at beginning of buffer (if emacs) or at beginning
+          of string to be matched (if not).  */
+  begbuf,
+
+       /* Analogously, for end of buffer/string.  */
+  endbuf,
+
+       /* Followed by two byte relative address to which to jump.  */
+  jump,
+
+       /* Same as jump, but marks the end of an alternative.  */
+  jump_past_alt,
+
+       /* Followed by two-byte relative address of place to resume at
+          in case of failure.  */
+  on_failure_jump,
+
+       /* Like on_failure_jump, but pushes a placeholder instead of the
+          current string position when executed.  */
+  on_failure_keep_string_jump,
+
+       /* Throw away latest failure point and then jump to following
+          two-byte relative address.  */
+  pop_failure_jump,
+
+       /* Change to pop_failure_jump if know won't have to backtrack to
+          match; otherwise change to jump.  This is used to jump
+          back to the beginning of a repeat.  If what follows this jump
+          clearly won't match what the repeat does, such that we can be
+          sure that there is no use backtracking out of repetitions
+          already matched, then we change it to a pop_failure_jump.
+          Followed by two-byte address.  */
+  maybe_pop_jump,
+
+       /* Jump to following two-byte address, and push a dummy failure
+          point. This failure point will be thrown away if an attempt
+          is made to use it for a failure.  A `+' construct makes this
+          before the first repeat.  Also used as an intermediary kind
+          of jump when compiling an alternative.  */
+  dummy_failure_jump,
+
+       /* Push a dummy failure point and continue.  Used at the end of
+          alternatives.  */
+  push_dummy_failure,
+
+       /* Followed by two-byte relative address and two-byte number n.
+          After matching N times, jump to the address upon failure.  */
+  succeed_n,
+
+       /* Followed by two-byte relative address, and two-byte number n.
+          Jump to the address N times, then fail.  */
+  jump_n,
+
+       /* Set the following two-byte relative address to the
+          subsequent two-byte number.  The address *includes* the two
+          bytes of number.  */
+  set_number_at,
+
+  wordchar,    /* Matches any word-constituent character.  */
+  notwordchar, /* Matches any char that is not a word-constituent.  */
+
+  wordbeg,     /* Succeeds if at word beginning.  */
+  wordend,     /* Succeeds if at word end.  */
+
+  wordbound,   /* Succeeds if at a word boundary.  */
+  notwordbound /* Succeeds if not at a word boundary.  */
+
+#ifdef emacs
+  ,before_dot, /* Succeeds if before point.  */
+  at_dot,      /* Succeeds if at point.  */
+  after_dot,   /* Succeeds if after point.  */
+
+       /* Matches any character whose syntax is specified.  Followed by
+          a byte which contains a syntax code, e.g., Sword.  */
+  syntaxspec,
+
+       /* Matches any character whose syntax is not that specified.  */
+  notsyntaxspec
+#endif /* emacs */
+} re_opcode_t;
+\f
+/* Common operations on the compiled pattern.  */
+
+/* Store NUMBER in two contiguous bytes starting at DESTINATION.  */
+
+#define STORE_NUMBER(destination, number)                              \
+  do {                                                                 \
+    (destination)[0] = (number) & 0377;                                        \
+    (destination)[1] = (number) >> 8;                                  \
+  } while (0)
+
+/* Same as STORE_NUMBER, except increment DESTINATION to
+   the byte after where the number is stored.  Therefore, DESTINATION
+   must be an lvalue.  */
+
+#define STORE_NUMBER_AND_INCR(destination, number)                     \
+  do {                                                                 \
+    STORE_NUMBER (destination, number);                                        \
+    (destination) += 2;                                                        \
+  } while (0)
+
+/* Put into DESTINATION a number stored in two contiguous bytes starting
+   at SOURCE.  */
+
+#define EXTRACT_NUMBER(destination, source)                            \
+  do {                                                                 \
+    (destination) = *(source) & 0377;                                  \
+    (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8;          \
+  } while (0)
+
+#ifdef DEBUG
+static void
+extract_number (dest, source)
+    int *dest;
+    unsigned char *source;
+{
+  int temp = SIGN_EXTEND_CHAR (*(source + 1));
+  *dest = *source & 0377;
+  *dest += temp << 8;
+}
+
+#ifndef EXTRACT_MACROS /* To debug the macros.  */
+#undef EXTRACT_NUMBER
+#define EXTRACT_NUMBER(dest, src) extract_number (&dest, src)
+#endif /* not EXTRACT_MACROS */
+
+#endif /* DEBUG */
+
+/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number.
+   SOURCE must be an lvalue.  */
+
+#define EXTRACT_NUMBER_AND_INCR(destination, source)                   \
+  do {                                                                 \
+    EXTRACT_NUMBER (destination, source);                              \
+    (source) += 2;                                                     \
+  } while (0)
+
+#ifdef DEBUG
+static void
+extract_number_and_incr (destination, source)
+    int *destination;
+    unsigned char **source;
+{
+  extract_number (destination, *source);
+  *source += 2;
+}
+
+#ifndef EXTRACT_MACROS
+#undef EXTRACT_NUMBER_AND_INCR
+#define EXTRACT_NUMBER_AND_INCR(dest, src) \
+  extract_number_and_incr (&dest, &src)
+#endif /* not EXTRACT_MACROS */
+
+#endif /* DEBUG */
+\f
+/* If DEBUG is defined, Regex prints many voluminous messages about what
+   it is doing (if the variable `debug' is nonzero).  If linked with the
+   main program in `iregex.c', you can enter patterns and strings
+   interactively.  And if linked with the main program in `main.c' and
+   the other test files, you can run the already-written tests.  */
+
+#ifdef DEBUG
+
+/* We use standard I/O for debugging.  */
+#include <stdio.h>
+
+/* It is useful to test things that ``must'' be true when debugging.  */
+#include <assert.h>
+
+static int debug = 0;
+
+#define DEBUG_STATEMENT(e) e
+#define DEBUG_PRINT1(x) if (debug) printf (x)
+#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
+#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
+#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
+#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)                          \
+  if (debug) print_partial_compiled_pattern (s, e)
+#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)                 \
+  if (debug) print_double_string (w, s1, sz1, s2, sz2)
+
+
+extern void printchar ();
+
+/* Print the fastmap in human-readable form.  */
+
+void
+print_fastmap (fastmap)
+    char *fastmap;
+{
+  unsigned was_a_range = 0;
+  unsigned i = 0;
+
+  while (i < (1 << BYTEWIDTH))
+    {
+      if (fastmap[i++])
+       {
+         was_a_range = 0;
+         printchar (i - 1);
+         while (i < (1 << BYTEWIDTH)  &&  fastmap[i])
+           {
+             was_a_range = 1;
+             i++;
+           }
+         if (was_a_range)
+           {
+             printf ("-");
+             printchar (i - 1);
+           }
+       }
+    }
+  putchar ('\n');
+}
+
+
+/* Print a compiled pattern string in human-readable form, starting at
+   the START pointer into it and ending just before the pointer END.  */
+
+void
+print_partial_compiled_pattern (start, end)
+    unsigned char *start;
+    unsigned char *end;
+{
+  int mcnt, mcnt2;
+  unsigned char *p = start;
+  unsigned char *pend = end;
+
+  if (start == NULL)
+    {
+      printf ("(null)\n");
+      return;
+    }
+
+  /* Loop over pattern commands.  */
+  while (p < pend)
+    {
+      switch ((re_opcode_t) *p++)
+       {
+       case no_op:
+         printf ("/no_op");
+         break;
+
+       case exactn:
+         mcnt = *p++;
+         printf ("/exactn/%d", mcnt);
+         do
+           {
+             putchar ('/');
+             printchar (*p++);
+           }
+         while (--mcnt);
+         break;
+
+       case start_memory:
+         mcnt = *p++;
+         printf ("/start_memory/%d/%d", mcnt, *p++);
+         break;
+
+       case stop_memory:
+         mcnt = *p++;
+         printf ("/stop_memory/%d/%d", mcnt, *p++);
+         break;
+
+       case duplicate:
+         printf ("/duplicate/%d", *p++);
+         break;
+
+       case anychar:
+         printf ("/anychar");
+         break;
+
+       case charset:
+       case charset_not:
+         {
+           register int c;
+
+           printf ("/charset%s",
+                   (re_opcode_t) *(p - 1) == charset_not ? "_not" : "");
+
+           assert (p + *p < pend);
+
+           for (c = 0; c < *p; c++)
+             {
+               unsigned bit;
+               unsigned char map_byte = p[1 + c];
+
+               putchar ('/');
+
+               for (bit = 0; bit < BYTEWIDTH; bit++)
+                 if (map_byte & (1 << bit))
+                   printchar (c * BYTEWIDTH + bit);
+             }
+           p += 1 + *p;
+           break;
+         }
+
+       case begline:
+         printf ("/begline");
+         break;
+
+       case endline:
+         printf ("/endline");
+         break;
+
+       case on_failure_jump:
+         extract_number_and_incr (&mcnt, &p);
+         printf ("/on_failure_jump/0/%d", mcnt);
+         break;
+
+       case on_failure_keep_string_jump:
+         extract_number_and_incr (&mcnt, &p);
+         printf ("/on_failure_keep_string_jump/0/%d", mcnt);
+         break;
+
+       case dummy_failure_jump:
+         extract_number_and_incr (&mcnt, &p);
+         printf ("/dummy_failure_jump/0/%d", mcnt);
+         break;
+
+       case push_dummy_failure:
+         printf ("/push_dummy_failure");
+         break;
+
+       case maybe_pop_jump:
+         extract_number_and_incr (&mcnt, &p);
+         printf ("/maybe_pop_jump/0/%d", mcnt);
+         break;
+
+       case pop_failure_jump:
+         extract_number_and_incr (&mcnt, &p);
+         printf ("/pop_failure_jump/0/%d", mcnt);
+         break;
+
+       case jump_past_alt:
+         extract_number_and_incr (&mcnt, &p);
+         printf ("/jump_past_alt/0/%d", mcnt);
+         break;
+
+       case jump:
+         extract_number_and_incr (&mcnt, &p);
+         printf ("/jump/0/%d", mcnt);
+         break;
+
+       case succeed_n:
+         extract_number_and_incr (&mcnt, &p);
+         extract_number_and_incr (&mcnt2, &p);
+         printf ("/succeed_n/0/%d/0/%d", mcnt, mcnt2);
+         break;
+
+       case jump_n:
+         extract_number_and_incr (&mcnt, &p);
+         extract_number_and_incr (&mcnt2, &p);
+         printf ("/jump_n/0/%d/0/%d", mcnt, mcnt2);
+         break;
+
+       case set_number_at:
+         extract_number_and_incr (&mcnt, &p);
+         extract_number_and_incr (&mcnt2, &p);
+         printf ("/set_number_at/0/%d/0/%d", mcnt, mcnt2);
+         break;
+
+       case wordbound:
+         printf ("/wordbound");
+         break;
+
+       case notwordbound:
+         printf ("/notwordbound");
+         break;
+
+       case wordbeg:
+         printf ("/wordbeg");
+         break;
+
+       case wordend:
+         printf ("/wordend");
+
+#ifdef emacs
+       case before_dot:
+         printf ("/before_dot");
+         break;
+
+       case at_dot:
+         printf ("/at_dot");
+         break;
+
+       case after_dot:
+         printf ("/after_dot");
+         break;
+
+       case syntaxspec:
+         printf ("/syntaxspec");
+         mcnt = *p++;
+         printf ("/%d", mcnt);
+         break;
+
+       case notsyntaxspec:
+         printf ("/notsyntaxspec");
+         mcnt = *p++;
+         printf ("/%d", mcnt);
+         break;
+#endif /* emacs */
+
+       case wordchar:
+         printf ("/wordchar");
+         break;
+
+       case notwordchar:
+         printf ("/notwordchar");
+         break;
+
+       case begbuf:
+         printf ("/begbuf");
+         break;
+
+       case endbuf:
+         printf ("/endbuf");
+         break;
+
+       default:
+         printf ("?%d", *(p-1));
+       }
+    }
+  printf ("/\n");
+}
+
+
+void
+print_compiled_pattern (bufp)
+    struct re_pattern_buffer *bufp;
+{
+  unsigned char *buffer = bufp->buffer;
+
+  print_partial_compiled_pattern (buffer, buffer + bufp->used);
+  printf ("%d bytes used/%d bytes allocated.\n", bufp->used, bufp->allocated);
+
+  if (bufp->fastmap_accurate && bufp->fastmap)
+    {
+      printf ("fastmap: ");
+      print_fastmap (bufp->fastmap);
+    }
+
+  printf ("re_nsub: %d\t", bufp->re_nsub);
+  printf ("regs_alloc: %d\t", bufp->regs_allocated);
+  printf ("can_be_null: %d\t", bufp->can_be_null);
+  printf ("newline_anchor: %d\n", bufp->newline_anchor);
+  printf ("no_sub: %d\t", bufp->no_sub);
+  printf ("not_bol: %d\t", bufp->not_bol);
+  printf ("not_eol: %d\t", bufp->not_eol);
+  printf ("syntax: %d\n", bufp->syntax);
+  /* Perhaps we should print the translate table?  */
+}
+
+
+void
+print_double_string (where, string1, size1, string2, size2)
+    const char *where;
+    const char *string1;
+    const char *string2;
+    int size1;
+    int size2;
+{
+  unsigned this_char;
+
+  if (where == NULL)
+    printf ("(null)");
+  else
+    {
+      if (FIRST_STRING_P (where))
+       {
+         for (this_char = where - string1; this_char < size1; this_char++)
+           printchar (string1[this_char]);
+
+         where = string2;
+       }
+
+      for (this_char = where - string2; this_char < size2; this_char++)
+       printchar (string2[this_char]);
+    }
+}
+
+#else /* not DEBUG */
+
+#undef assert
+#define assert(e)
+
+#define DEBUG_STATEMENT(e)
+#define DEBUG_PRINT1(x)
+#define DEBUG_PRINT2(x1, x2)
+#define DEBUG_PRINT3(x1, x2, x3)
+#define DEBUG_PRINT4(x1, x2, x3, x4)
+#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)
+#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
+
+#endif /* not DEBUG */
+\f
+/* Set by `re_set_syntax' to the current regexp syntax to recognize.  Can
+   also be assigned to arbitrarily: each pattern buffer stores its own
+   syntax, so it can be changed between regex compilations.  */
+reg_syntax_t re_syntax_options = RE_SYNTAX_EMACS;
+
+
+/* Specify the precise syntax of regexps for compilation.  This provides
+   for compatibility for various utilities which historically have
+   different, incompatible syntaxes.
+
+   The argument SYNTAX is a bit mask comprised of the various bits
+   defined in regex.h.  We return the old syntax.  */
+
+reg_syntax_t
+re_set_syntax (syntax)
+    reg_syntax_t syntax;
+{
+  reg_syntax_t ret = re_syntax_options;
+
+  re_syntax_options = syntax;
+  return ret;
+}
+\f
+/* This table gives an error message for each of the error codes listed
+   in regex.h.  Obviously the order here has to be same as there.  */
+
+static const char *re_error_msg[] =
+  { NULL,                                      /* REG_NOERROR */
+    "No match",                                        /* REG_NOMATCH */
+    "Invalid regular expression",              /* REG_BADPAT */
+    "Invalid collation character",             /* REG_ECOLLATE */
+    "Invalid character class name",            /* REG_ECTYPE */
+    "Trailing backslash",                      /* REG_EESCAPE */
+    "Invalid back reference",                  /* REG_ESUBREG */
+    "Unmatched [ or [^",                       /* REG_EBRACK */
+    "Unmatched ( or \\(",                      /* REG_EPAREN */
+    "Unmatched \\{",                           /* REG_EBRACE */
+    "Invalid content of \\{\\}",               /* REG_BADBR */
+    "Invalid range end",                       /* REG_ERANGE */
+    "Memory exhausted",                                /* REG_ESPACE */
+    "Invalid preceding regular expression",    /* REG_BADRPT */
+    "Premature end of regular expression",     /* REG_EEND */
+    "Regular expression too big",              /* REG_ESIZE */
+    "Unmatched ) or \\)",                      /* REG_ERPAREN */
+  };
+\f
+/* Subroutine declarations and macros for regex_compile.  */
+
+static void store_op1 (), store_op2 ();
+static void insert_op1 (), insert_op2 ();
+static boolean at_begline_loc_p (), at_endline_loc_p ();
+static boolean group_in_compile_stack ();
+static reg_errcode_t compile_range ();
+
+/* Fetch the next character in the uncompiled pattern---translating it
+   if necessary.  Also cast from a signed character in the constant
+   string passed to us by the user to an unsigned char that we can use
+   as an array index (in, e.g., `translate').  */
+#define PATFETCH(c)                                                    \
+  do {if (p == pend) return REG_EEND;                                  \
+    c = (unsigned char) *p++;                                          \
+    if (translate) c = translate[c];                                   \
+  } while (0)
+
+/* Fetch the next character in the uncompiled pattern, with no
+   translation.  */
+#define PATFETCH_RAW(c)                                                        \
+  do {if (p == pend) return REG_EEND;                                  \
+    c = (unsigned char) *p++;                                          \
+  } while (0)
+
+/* Go backwards one character in the pattern.  */
+#define PATUNFETCH p--
+
+
+/* If `translate' is non-null, return translate[D], else just D.  We
+   cast the subscript to translate because some data is declared as
+   `char *', to avoid warnings when a string constant is passed.  But
+   when we use a character as a subscript we must make it unsigned.  */
+#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d))
+
+
+/* Macros for outputting the compiled pattern into `buffer'.  */
+
+/* If the buffer isn't allocated when it comes in, use this.  */
+#define INIT_BUF_SIZE  32
+
+/* Make sure we have at least N more bytes of space in buffer.  */
+#define GET_BUFFER_SPACE(n)                                            \
+    while (b - bufp->buffer + (n) > bufp->allocated)                   \
+      EXTEND_BUFFER ()
+
+/* Make sure we have one more byte of buffer space and then add C to it.  */
+#define BUF_PUSH(c)                                                    \
+  do {                                                                 \
+    GET_BUFFER_SPACE (1);                                              \
+    *b++ = (unsigned char) (c);                                                \
+  } while (0)
+
+
+/* Ensure we have two more bytes of buffer space and then append C1 and C2.  */
+#define BUF_PUSH_2(c1, c2)                                             \
+  do {                                                                 \
+    GET_BUFFER_SPACE (2);                                              \
+    *b++ = (unsigned char) (c1);                                       \
+    *b++ = (unsigned char) (c2);                                       \
+  } while (0)
+
+
+/* As with BUF_PUSH_2, except for three bytes.  */
+#define BUF_PUSH_3(c1, c2, c3)                                         \
+  do {                                                                 \
+    GET_BUFFER_SPACE (3);                                              \
+    *b++ = (unsigned char) (c1);                                       \
+    *b++ = (unsigned char) (c2);                                       \
+    *b++ = (unsigned char) (c3);                                       \
+  } while (0)
+
+
+/* Store a jump with opcode OP at LOC to location TO.  We store a
+   relative address offset by the three bytes the jump itself occupies.  */
+#define STORE_JUMP(op, loc, to) \
+  store_op1 (op, loc, (to) - (loc) - 3)
+
+/* Likewise, for a two-argument jump.  */
+#define STORE_JUMP2(op, loc, to, arg) \
+  store_op2 (op, loc, (to) - (loc) - 3, arg)
+
+/* Like `STORE_JUMP', but for inserting.  Assume `b' is the buffer end.  */
+#define INSERT_JUMP(op, loc, to) \
+  insert_op1 (op, loc, (to) - (loc) - 3, b)
+
+/* Like `STORE_JUMP2', but for inserting.  Assume `b' is the buffer end.  */
+#define INSERT_JUMP2(op, loc, to, arg) \
+  insert_op2 (op, loc, (to) - (loc) - 3, arg, b)
+
+
+/* This is not an arbitrary limit: the arguments which represent offsets
+   into the pattern are two bytes long.  So if 2^16 bytes turns out to
+   be too small, many things would have to change.  */
+#define MAX_BUF_SIZE (1L << 16)
+
+
+/* Extend the buffer by twice its current size via realloc and
+   reset the pointers that pointed into the old block to point to the
+   correct places in the new one.  If extending the buffer results in it
+   being larger than MAX_BUF_SIZE, then flag memory exhausted.  */
+#define EXTEND_BUFFER()                                                        \
+  do {                                                                         \
+    unsigned char *old_buffer = bufp->buffer;                          \
+    if (bufp->allocated == MAX_BUF_SIZE)                               \
+      return REG_ESIZE;                                                        \
+    bufp->allocated <<= 1;                                             \
+    if (bufp->allocated > MAX_BUF_SIZE)                                        \
+      bufp->allocated = MAX_BUF_SIZE;                                  \
+    bufp->buffer = (unsigned char *) realloc (bufp->buffer, bufp->allocated);\
+    if (bufp->buffer == NULL)                                          \
+      return REG_ESPACE;                                               \
+    /* If the buffer moved, move all the pointers into it.  */         \
+    if (old_buffer != bufp->buffer)                                    \
+      {                                                                        \
+       b = (b - old_buffer) + bufp->buffer;                            \
+       begalt = (begalt - old_buffer) + bufp->buffer;                  \
+       if (fixup_alt_jump)                                             \
+         fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\
+       if (laststart)                                                  \
+         laststart = (laststart - old_buffer) + bufp->buffer;          \
+       if (pending_exact)                                              \
+         pending_exact = (pending_exact - old_buffer) + bufp->buffer;  \
+      }                                                                        \
+  } while (0)
+
+
+/* Since we have one byte reserved for the register number argument to
+   {start,stop}_memory, the maximum number of groups we can report
+   things about is what fits in that byte.  */
+#define MAX_REGNUM 255
+
+/* But patterns can have more than `MAX_REGNUM' registers.  We just
+   ignore the excess.  */
+typedef unsigned regnum_t;
+
+
+/* Macros for the compile stack.  */
+
+/* Since offsets can go either forwards or backwards, this type needs to
+   be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1.  */
+typedef int pattern_offset_t;
+
+typedef struct
+{
+  pattern_offset_t begalt_offset;
+  pattern_offset_t fixup_alt_jump;
+  pattern_offset_t inner_group_offset;
+  pattern_offset_t laststart_offset;
+  regnum_t regnum;
+} compile_stack_elt_t;
+
+
+typedef struct
+{
+  compile_stack_elt_t *stack;
+  unsigned size;
+  unsigned avail;                      /* Offset of next open position.  */
+} compile_stack_type;
+
+
+#define INIT_COMPILE_STACK_SIZE 32
+
+#define COMPILE_STACK_EMPTY  (compile_stack.avail == 0)
+#define COMPILE_STACK_FULL  (compile_stack.avail == compile_stack.size)
+
+/* The next available element.  */
+#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
+
+
+/* Set the bit for character C in a list.  */
+#define SET_LIST_BIT(c)                               \
+  (b[((unsigned char) (c)) / BYTEWIDTH]               \
+   |= 1 << (((unsigned char) c) % BYTEWIDTH))
+
+
+/* Get the next unsigned number in the uncompiled pattern.  */
+#define GET_UNSIGNED_NUMBER(num)                                       \
+  { if (p != pend)                                                     \
+     {                                                                 \
+       PATFETCH (c);                                                   \
+       while (ISDIGIT (c))                                             \
+        {                                                              \
+          if (num < 0)                                                 \
+             num = 0;                                                  \
+          num = num * 10 + c - '0';                                    \
+          if (p == pend)                                               \
+             break;                                                    \
+          PATFETCH (c);                                                \
+        }                                                              \
+       }                                                               \
+    }
+
+#define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
+
+#define IS_CHAR_CLASS(string)                                          \
+   (STREQ (string, "alpha") || STREQ (string, "upper")                 \
+    || STREQ (string, "lower") || STREQ (string, "digit")              \
+    || STREQ (string, "alnum") || STREQ (string, "xdigit")             \
+    || STREQ (string, "space") || STREQ (string, "print")              \
+    || STREQ (string, "punct") || STREQ (string, "graph")              \
+    || STREQ (string, "cntrl") || STREQ (string, "blank"))
+\f
+/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
+   Returns one of error codes defined in `regex.h', or zero for success.
+
+   Assumes the `allocated' (and perhaps `buffer') and `translate'
+   fields are set in BUFP on entry.
+
+   If it succeeds, results are put in BUFP (if it returns an error, the
+   contents of BUFP are undefined):
+     `buffer' is the compiled pattern;
+     `syntax' is set to SYNTAX;
+     `used' is set to the length of the compiled pattern;
+     `fastmap_accurate' is zero;
+     `re_nsub' is the number of subexpressions in PATTERN;
+     `not_bol' and `not_eol' are zero;
+
+   The `fastmap' and `newline_anchor' fields are neither
+   examined nor set.  */
+
+static reg_errcode_t
+regex_compile (pattern, size, syntax, bufp)
+     const char *pattern;
+     int size;
+     reg_syntax_t syntax;
+     struct re_pattern_buffer *bufp;
+{
+  /* We fetch characters from PATTERN here.  Even though PATTERN is
+     `char *' (i.e., signed), we declare these variables as unsigned, so
+     they can be reliably used as array indices.  */
+  register unsigned char c, c1;
+
+  /* A random tempory spot in PATTERN.  */
+  const char *p1;
+
+  /* Points to the end of the buffer, where we should append.  */
+  register unsigned char *b;
+
+  /* Keeps track of unclosed groups.  */
+  compile_stack_type compile_stack;
+
+  /* Points to the current (ending) position in the pattern.  */
+  const char *p = pattern;
+  const char *pend = pattern + size;
+
+  /* How to translate the characters in the pattern.  */
+  char *translate = bufp->translate;
+
+  /* Address of the count-byte of the most recently inserted `exactn'
+     command.  This makes it possible to tell if a new exact-match
+     character can be added to that command or if the character requires
+     a new `exactn' command.  */
+  unsigned char *pending_exact = 0;
+
+  /* Address of start of the most recently finished expression.
+     This tells, e.g., postfix * where to find the start of its
+     operand.  Reset at the beginning of groups and alternatives.  */
+  unsigned char *laststart = 0;
+
+  /* Address of beginning of regexp, or inside of last group.  */
+  unsigned char *begalt;
+
+  /* Place in the uncompiled pattern (i.e., the {) to
+     which to go back if the interval is invalid.  */
+  const char *beg_interval;
+
+  /* Address of the place where a forward jump should go to the end of
+     the containing expression.  Each alternative of an `or' -- except the
+     last -- ends with a forward jump of this sort.  */
+  unsigned char *fixup_alt_jump = 0;
+
+  /* Counts open-groups as they are encountered.  Remembered for the
+     matching close-group on the compile stack, so the same register
+     number is put in the stop_memory as the start_memory.  */
+  regnum_t regnum = 0;
+
+#ifdef DEBUG
+  DEBUG_PRINT1 ("\nCompiling pattern: ");
+  if (debug)
+    {
+      unsigned debug_count;
+
+      for (debug_count = 0; debug_count < size; debug_count++)
+       printchar (pattern[debug_count]);
+      putchar ('\n');
+    }
+#endif /* DEBUG */
+
+  /* Initialize the compile stack.  */
+  compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t);
+  if (compile_stack.stack == NULL)
+    return REG_ESPACE;
+
+  compile_stack.size = INIT_COMPILE_STACK_SIZE;
+  compile_stack.avail = 0;
+
+  /* Initialize the pattern buffer.  */
+  bufp->syntax = syntax;
+  bufp->fastmap_accurate = 0;
+  bufp->not_bol = bufp->not_eol = 0;
+
+  /* Set `used' to zero, so that if we return an error, the pattern
+     printer (for debugging) will think there's no pattern.  We reset it
+     at the end.  */
+  bufp->used = 0;
+
+  /* Always count groups, whether or not bufp->no_sub is set.  */
+  bufp->re_nsub = 0;
+
+#if !defined (emacs) && !defined (SYNTAX_TABLE)
+  /* Initialize the syntax table.  */
+   init_syntax_once ();
+#endif
+
+  if (bufp->allocated == 0)
+    {
+      if (bufp->buffer)
+       { /* If zero allocated, but buffer is non-null, try to realloc
+            enough space.  This loses if buffer's address is bogus, but
+            that is the user's responsibility.  */
+         RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char);
+       }
+      else
+       { /* Caller did not allocate a buffer.  Do it for them.  */
+         bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char);
+       }
+      if (!bufp->buffer) return REG_ESPACE;
+
+      bufp->allocated = INIT_BUF_SIZE;
+    }
+
+  begalt = b = bufp->buffer;
+
+  /* Loop through the uncompiled pattern until we're at the end.  */
+  while (p != pend)
+    {
+      PATFETCH (c);
+
+      switch (c)
+       {
+       case '^':
+         {
+           if (   /* If at start of pattern, it's an operator.  */
+                  p == pattern + 1
+                  /* If context independent, it's an operator.  */
+               || syntax & RE_CONTEXT_INDEP_ANCHORS
+                  /* Otherwise, depends on what's come before.  */
+               || at_begline_loc_p (pattern, p, syntax))
+             BUF_PUSH (begline);
+           else
+             goto normal_char;
+         }
+         break;
+
+
+       case '$':
+         {
+           if (   /* If at end of pattern, it's an operator.  */
+                  p == pend
+                  /* If context independent, it's an operator.  */
+               || syntax & RE_CONTEXT_INDEP_ANCHORS
+                  /* Otherwise, depends on what's next.  */
+               || at_endline_loc_p (p, pend, syntax))
+              BUF_PUSH (endline);
+            else
+              goto normal_char;
+          }
+          break;
+
+
+       case '+':
+       case '?':
+         if ((syntax & RE_BK_PLUS_QM)
+             || (syntax & RE_LIMITED_OPS))
+           goto normal_char;
+       handle_plus:
+       case '*':
+         /* If there is no previous pattern... */
+         if (!laststart)
+           {
+             if (syntax & RE_CONTEXT_INVALID_OPS)
+               return REG_BADRPT;
+             else if (!(syntax & RE_CONTEXT_INDEP_OPS))
+               goto normal_char;
+           }
+
+         {
+           /* Are we optimizing this jump?  */
+           boolean keep_string_p = false;
+
+           /* 1 means zero (many) matches is allowed.  */
+           char zero_times_ok = 0, many_times_ok = 0;
+
+           /* If there is a sequence of repetition chars, collapse it
+              down to just one (the right one).  We can't combine
+              interval operators with these because of, e.g., `a{2}*',
+              which should only match an even number of `a's.  */
+
+           for (;;)
+             {
+               zero_times_ok |= c != '+';
+               many_times_ok |= c != '?';
+
+               if (p == pend)
+                 break;
+
+               PATFETCH (c);
+
+               if (c == '*'
+                   || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
+                 ;
+
+               else if (syntax & RE_BK_PLUS_QM  &&  c == '\\')
+                 {
+                   if (p == pend) return REG_EESCAPE;
+
+                   PATFETCH (c1);
+                   if (!(c1 == '+' || c1 == '?'))
+                     {
+                       PATUNFETCH;
+                       PATUNFETCH;
+                       break;
+                     }
+
+                   c = c1;
+                 }
+               else
+                 {
+                   PATUNFETCH;
+                   break;
+                 }
+
+               /* If we get here, we found another repeat character.  */
+              }
+
+           /* Star, etc. applied to an empty pattern is equivalent
+              to an empty pattern.  */
+           if (!laststart)
+             break;
+
+           /* Now we know whether or not zero matches is allowed
+              and also whether or not two or more matches is allowed.  */
+           if (many_times_ok)
+             { /* More than one repetition is allowed, so put in at the
+                  end a backward relative jump from `b' to before the next
+                  jump we're going to put in below (which jumps from
+                  laststart to after this jump).
+
+                  But if we are at the `*' in the exact sequence `.*\n',
+                  insert an unconditional jump backwards to the .,
+                  instead of the beginning of the loop.  This way we only
+                  push a failure point once, instead of every time
+                  through the loop.  */
+               assert (p - 1 > pattern);
+
+               /* Allocate the space for the jump.  */
+               GET_BUFFER_SPACE (3);
+
+               /* We know we are not at the first character of the pattern,
+                  because laststart was nonzero.  And we've already
+                  incremented `p', by the way, to be the character after
+                  the `*'.  Do we have to do something analogous here
+                  for null bytes, because of RE_DOT_NOT_NULL?  */
+               if (TRANSLATE (*(p - 2)) == TRANSLATE ('.')
+                   && zero_times_ok
+                   && p < pend && TRANSLATE (*p) == TRANSLATE ('\n')
+                   && !(syntax & RE_DOT_NEWLINE))
+                 { /* We have .*\n.  */
+                   STORE_JUMP (jump, b, laststart);
+                   keep_string_p = true;
+                 }
+               else
+                 /* Anything else.  */
+                 STORE_JUMP (maybe_pop_jump, b, laststart - 3);
+
+               /* We've added more stuff to the buffer.  */
+               b += 3;
+             }
+
+           /* On failure, jump from laststart to b + 3, which will be the
+              end of the buffer after this jump is inserted.  */
+           GET_BUFFER_SPACE (3);
+           INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump
+                                      : on_failure_jump,
+                        laststart, b + 3);
+           pending_exact = 0;
+           b += 3;
+
+           if (!zero_times_ok)
+             {
+               /* At least one repetition is required, so insert a
+                  `dummy_failure_jump' before the initial
+                  `on_failure_jump' instruction of the loop. This
+                  effects a skip over that instruction the first time
+                  we hit that loop.  */
+               GET_BUFFER_SPACE (3);
+               INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6);
+               b += 3;
+             }
+           }
+         break;
+
+
+       case '.':
+         laststart = b;
+         BUF_PUSH (anychar);
+         break;
+
+
+       case '[':
+         {
+           boolean had_char_class = false;
+
+           if (p == pend) return REG_EBRACK;
+
+           /* Ensure that we have enough space to push a charset: the
+              opcode, the length count, and the bitset; 34 bytes in all.  */
+           GET_BUFFER_SPACE (34);
+
+           laststart = b;
+
+           /* We test `*p == '^' twice, instead of using an if
+              statement, so we only need one BUF_PUSH.  */
+           BUF_PUSH (*p == '^' ? charset_not : charset);
+           if (*p == '^')
+             p++;
+
+           /* Remember the first position in the bracket expression.  */
+           p1 = p;
+
+           /* Push the number of bytes in the bitmap.  */
+           BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
+
+           /* Clear the whole map.  */
+           bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
+
+           /* charset_not matches newline according to a syntax bit.  */
+           if ((re_opcode_t) b[-2] == charset_not
+               && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
+             SET_LIST_BIT ('\n');
+
+           /* Read in characters and ranges, setting map bits.  */
+           for (;;)
+             {
+               if (p == pend) return REG_EBRACK;
+
+               PATFETCH (c);
+
+               /* \ might escape characters inside [...] and [^...].  */
+               if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
+                 {
+                   if (p == pend) return REG_EESCAPE;
+
+                   PATFETCH (c1);
+                   SET_LIST_BIT (c1);
+                   continue;
+                 }
+
+               /* Could be the end of the bracket expression.  If it's
+                  not (i.e., when the bracket expression is `[]' so
+                  far), the ']' character bit gets set way below.  */
+               if (c == ']' && p != p1 + 1)
+                 break;
+
+               /* Look ahead to see if it's a range when the last thing
+                  was a character class.  */
+               if (had_char_class && c == '-' && *p != ']')
+                 return REG_ERANGE;
+
+               /* Look ahead to see if it's a range when the last thing
+                  was a character: if this is a hyphen not at the
+                  beginning or the end of a list, then it's the range
+                  operator.  */
+               if (c == '-'
+                   && !(p - 2 >= pattern && p[-2] == '[')
+                   && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
+                   && *p != ']')
+                 {
+                   reg_errcode_t ret
+                     = compile_range (&p, pend, translate, syntax, b);
+                   if (ret != REG_NOERROR) return ret;
+                 }
+
+               else if (p[0] == '-' && p[1] != ']')
+                 { /* This handles ranges made up of characters only.  */
+                   reg_errcode_t ret;
+
+                   /* Move past the `-'.  */
+                   PATFETCH (c1);
+
+                   ret = compile_range (&p, pend, translate, syntax, b);
+                   if (ret != REG_NOERROR) return ret;
+                 }
+
+               /* See if we're at the beginning of a possible character
+                  class.  */
+
+               else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
+                 { /* Leave room for the null.  */
+                   char str[CHAR_CLASS_MAX_LENGTH + 1];
+
+                   PATFETCH (c);
+                   c1 = 0;
+
+                   /* If pattern is `[[:'.  */
+                   if (p == pend) return REG_EBRACK;
+
+                   for (;;)
+                     {
+                       PATFETCH (c);
+                       if (c == ':' || c == ']' || p == pend
+                           || c1 == CHAR_CLASS_MAX_LENGTH)
+                         break;
+                       str[c1++] = c;
+                     }
+                   str[c1] = '\0';
+
+                   /* If isn't a word bracketed by `[:' and:`]':
+                      undo the ending character, the letters, and leave
+                      the leading `:' and `[' (but set bits for them).  */
+                   if (c == ':' && *p == ']')
+                     {
+                       int ch;
+                       boolean is_alnum = STREQ (str, "alnum");
+                       boolean is_alpha = STREQ (str, "alpha");
+                       boolean is_blank = STREQ (str, "blank");
+                       boolean is_cntrl = STREQ (str, "cntrl");
+                       boolean is_digit = STREQ (str, "digit");
+                       boolean is_graph = STREQ (str, "graph");
+                       boolean is_lower = STREQ (str, "lower");
+                       boolean is_print = STREQ (str, "print");
+                       boolean is_punct = STREQ (str, "punct");
+                       boolean is_space = STREQ (str, "space");
+                       boolean is_upper = STREQ (str, "upper");
+                       boolean is_xdigit = STREQ (str, "xdigit");
+
+                       if (!IS_CHAR_CLASS (str)) return REG_ECTYPE;
+
+                       /* Throw away the ] at the end of the character
+                          class.  */
+                       PATFETCH (c);
+
+                       if (p == pend) return REG_EBRACK;
+
+                       for (ch = 0; ch < 1 << BYTEWIDTH; ch++)
+                         {
+                           if (   (is_alnum  && ISALNUM (ch))
+                               || (is_alpha  && ISALPHA (ch))
+                               || (is_blank  && ISBLANK (ch))
+                               || (is_cntrl  && ISCNTRL (ch))
+                               || (is_digit  && ISDIGIT (ch))
+                               || (is_graph  && ISGRAPH (ch))
+                               || (is_lower  && ISLOWER (ch))
+                               || (is_print  && ISPRINT (ch))
+                               || (is_punct  && ISPUNCT (ch))
+                               || (is_space  && ISSPACE (ch))
+                               || (is_upper  && ISUPPER (ch))
+                               || (is_xdigit && ISXDIGIT (ch)))
+                           SET_LIST_BIT (ch);
+                         }
+                       had_char_class = true;
+                     }
+                   else
+                     {
+                       c1++;
+                       while (c1--)
+                         PATUNFETCH;
+                       SET_LIST_BIT ('[');
+                       SET_LIST_BIT (':');
+                       had_char_class = false;
+                     }
+                 }
+               else
+                 {
+                   had_char_class = false;
+                   SET_LIST_BIT (c);
+                 }
+             }
+
+           /* Discard any (non)matching list bytes that are all 0 at the
+              end of the map.  Decrease the map-length byte too.  */
+           while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
+             b[-1]--;
+           b += b[-1];
+         }
+         break;
+
+
+       case '(':
+         if (syntax & RE_NO_BK_PARENS)
+           goto handle_open;
+         else
+           goto normal_char;
+
+
+       case ')':
+         if (syntax & RE_NO_BK_PARENS)
+           goto handle_close;
+         else
+           goto normal_char;
+
+
+       case '\n':
+         if (syntax & RE_NEWLINE_ALT)
+           goto handle_alt;
+         else
+           goto normal_char;
+
+
+       case '|':
+         if (syntax & RE_NO_BK_VBAR)
+           goto handle_alt;
+         else
+           goto normal_char;
+
+
+       case '{':
+          if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES)
+            goto handle_interval;
+          else
+            goto normal_char;
+
+
+       case '\\':
+         if (p == pend) return REG_EESCAPE;
+
+         /* Do not translate the character after the \, so that we can
+            distinguish, e.g., \B from \b, even if we normally would
+            translate, e.g., B to b.  */
+         PATFETCH_RAW (c);
+
+         switch (c)
+           {
+           case '(':
+             if (syntax & RE_NO_BK_PARENS)
+               goto normal_backslash;
+
+           handle_open:
+             bufp->re_nsub++;
+             regnum++;
+
+             if (COMPILE_STACK_FULL)
+               {
+                 RETALLOC (compile_stack.stack, compile_stack.size << 1,
+                           compile_stack_elt_t);
+                 if (compile_stack.stack == NULL) return REG_ESPACE;
+
+                 compile_stack.size <<= 1;
+               }
+
+             /* These are the values to restore when we hit end of this
+                group.  They are all relative offsets, so that if the
+                whole pattern moves because of realloc, they will still
+                be valid.  */
+             COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer;
+             COMPILE_STACK_TOP.fixup_alt_jump
+               = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0;
+             COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer;
+             COMPILE_STACK_TOP.regnum = regnum;
+
+             /* We will eventually replace the 0 with the number of
+                groups inner to this one.  But do not push a
+                start_memory for groups beyond the last one we can
+                represent in the compiled pattern.  */
+             if (regnum <= MAX_REGNUM)
+               {
+                 COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2;
+                 BUF_PUSH_3 (start_memory, regnum, 0);
+               }
+
+             compile_stack.avail++;
+
+             fixup_alt_jump = 0;
+             laststart = 0;
+             begalt = b;
+             /* If we've reached MAX_REGNUM groups, then this open
+                won't actually generate any code, so we'll have to
+                clear pending_exact explicitly.  */
+             pending_exact = 0;
+             break;
+
+
+           case ')':
+             if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
+
+             if (COMPILE_STACK_EMPTY)
+             {
+               if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+                 goto normal_backslash;
+               else
+                 return REG_ERPAREN;
+             }
+
+           handle_close:
+             if (fixup_alt_jump)
+               { /* Push a dummy failure point at the end of the
+                    alternative for a possible future
+                    `pop_failure_jump' to pop.  See comments at
+                    `push_dummy_failure' in `re_match_2'.  */
+                 BUF_PUSH (push_dummy_failure);
+
+                 /* We allocated space for this jump when we assigned
+                    to `fixup_alt_jump', in the `handle_alt' case below.  */
+                 STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1);
+               }
+
+             /* See similar code for backslashed left paren above.  */
+             if (COMPILE_STACK_EMPTY)
+             {
+               if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+                 goto normal_char;
+               else
+                 return REG_ERPAREN;
+             }
+
+             /* Since we just checked for an empty stack above, this
+                ``can't happen''.  */
+             assert (compile_stack.avail != 0);
+             {
+               /* We don't just want to restore into `regnum', because
+                  later groups should continue to be numbered higher,
+                  as in `(ab)c(de)' -- the second group is #2.  */
+               regnum_t this_group_regnum;
+
+               compile_stack.avail--;
+               begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset;
+               fixup_alt_jump
+                 = COMPILE_STACK_TOP.fixup_alt_jump
+                   ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1
+                   : 0;
+               laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset;
+               this_group_regnum = COMPILE_STACK_TOP.regnum;
+               /* If we've reached MAX_REGNUM groups, then this open
+                  won't actually generate any code, so we'll have to
+                  clear pending_exact explicitly.  */
+               pending_exact = 0;
+
+               /* We're at the end of the group, so now we know how many
+                  groups were inside this one.  */
+               if (this_group_regnum <= MAX_REGNUM)
+                 {
+                   unsigned char *inner_group_loc
+                     = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset;
+
+                   *inner_group_loc = regnum - this_group_regnum;
+                   BUF_PUSH_3 (stop_memory, this_group_regnum,
+                               regnum - this_group_regnum);
+                 }
+             }
+             break;
+
+
+           case '|':                                   /* `\|'.  */
+             if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR)
+               goto normal_backslash;
+           handle_alt:
+             if (syntax & RE_LIMITED_OPS)
+               goto normal_char;
+
+             /* Insert before the previous alternative a jump which
+                jumps to this alternative if the former fails.  */
+             GET_BUFFER_SPACE (3);
+             INSERT_JUMP (on_failure_jump, begalt, b + 6);
+             pending_exact = 0;
+             b += 3;
+
+             /* The alternative before this one has a jump after it
+                which gets executed if it gets matched.  Adjust that
+                jump so it will jump to this alternative's analogous
+                jump (put in below, which in turn will jump to the next
+                (if any) alternative's such jump, etc.).  The last such
+                jump jumps to the correct final destination.  A picture:
+                         _____ _____
+                         |   | |   |
+                         |   v |   v
+                        a | b   | c
+
+                If we are at `b', then fixup_alt_jump right now points to a
+                three-byte space after `a'.  We'll put in the jump, set
+                fixup_alt_jump to right after `b', and leave behind three
+                bytes which we'll fill in when we get to after `c'.  */
+
+             if (fixup_alt_jump)
+               STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+             /* Mark and leave space for a jump after this alternative,
+                to be filled in later either by next alternative or
+                when know we're at the end of a series of alternatives.  */
+             fixup_alt_jump = b;
+             GET_BUFFER_SPACE (3);
+             b += 3;
+
+             laststart = 0;
+             begalt = b;
+             break;
+
+
+           case '{':
+             /* If \{ is a literal.  */
+             if (!(syntax & RE_INTERVALS)
+                    /* If we're at `\{' and it's not the open-interval
+                       operator.  */
+                 || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+                 || (p - 2 == pattern  &&  p == pend))
+               goto normal_backslash;
+
+           handle_interval:
+             {
+               /* If got here, then the syntax allows intervals.  */
+
+               /* At least (most) this many matches must be made.  */
+               int lower_bound = -1, upper_bound = -1;
+
+               beg_interval = p - 1;
+
+               if (p == pend)
+                 {
+                   if (syntax & RE_NO_BK_BRACES)
+                     goto unfetch_interval;
+                   else
+                     return REG_EBRACE;
+                 }
+
+               GET_UNSIGNED_NUMBER (lower_bound);
+
+               if (c == ',')
+                 {
+                   GET_UNSIGNED_NUMBER (upper_bound);
+                   if (upper_bound < 0) upper_bound = RE_DUP_MAX;
+                 }
+               else
+                 /* Interval such as `{1}' => match exactly once. */
+                 upper_bound = lower_bound;
+
+               if (lower_bound < 0 || upper_bound > RE_DUP_MAX
+                   || lower_bound > upper_bound)
+                 {
+                   if (syntax & RE_NO_BK_BRACES)
+                     goto unfetch_interval;
+                   else
+                     return REG_BADBR;
+                 }
+
+               if (!(syntax & RE_NO_BK_BRACES))
+                 {
+                   if (c != '\\') return REG_EBRACE;
+
+                   PATFETCH (c);
+                 }
+
+               if (c != '}')
+                 {
+                   if (syntax & RE_NO_BK_BRACES)
+                     goto unfetch_interval;
+                   else
+                     return REG_BADBR;
+                 }
+
+               /* We just parsed a valid interval.  */
+
+               /* If it's invalid to have no preceding re.  */
+               if (!laststart)
+                 {
+                   if (syntax & RE_CONTEXT_INVALID_OPS)
+                     return REG_BADRPT;
+                   else if (syntax & RE_CONTEXT_INDEP_OPS)
+                     laststart = b;
+                   else
+                     goto unfetch_interval;
+                 }
+
+               /* If the upper bound is zero, don't want to succeed at
+                  all; jump from `laststart' to `b + 3', which will be
+                  the end of the buffer after we insert the jump.  */
+                if (upper_bound == 0)
+                  {
+                    GET_BUFFER_SPACE (3);
+                    INSERT_JUMP (jump, laststart, b + 3);
+                    b += 3;
+                  }
+
+                /* Otherwise, we have a nontrivial interval.  When
+                   we're all done, the pattern will look like:
+                     set_number_at <jump count> <upper bound>
+                     set_number_at <succeed_n count> <lower bound>
+                     succeed_n <after jump addr> <succed_n count>
+                     <body of loop>
+                     jump_n <succeed_n addr> <jump count>
+                   (The upper bound and `jump_n' are omitted if
+                   `upper_bound' is 1, though.)  */
+                else
+                  { /* If the upper bound is > 1, we need to insert
+                       more at the end of the loop.  */
+                    unsigned nbytes = 10 + (upper_bound > 1) * 10;
+
+                    GET_BUFFER_SPACE (nbytes);
+
+                    /* Initialize lower bound of the `succeed_n', even
+                       though it will be set during matching by its
+                       attendant `set_number_at' (inserted next),
+                       because `re_compile_fastmap' needs to know.
+                       Jump to the `jump_n' we might insert below.  */
+                    INSERT_JUMP2 (succeed_n, laststart,
+                                  b + 5 + (upper_bound > 1) * 5,
+                                  lower_bound);
+                    b += 5;
+
+                    /* Code to initialize the lower bound.  Insert
+                       before the `succeed_n'.  The `5' is the last two
+                       bytes of this `set_number_at', plus 3 bytes of
+                       the following `succeed_n'.  */
+                    insert_op2 (set_number_at, laststart, 5, lower_bound, b);
+                    b += 5;
+
+                    if (upper_bound > 1)
+                      { /* More than one repetition is allowed, so
+                           append a backward jump to the `succeed_n'
+                           that starts this interval.
+
+                           When we've reached this during matching,
+                           we'll have matched the interval once, so
+                           jump back only `upper_bound - 1' times.  */
+                        STORE_JUMP2 (jump_n, b, laststart + 5,
+                                     upper_bound - 1);
+                        b += 5;
+
+                        /* The location we want to set is the second
+                           parameter of the `jump_n'; that is `b-2' as
+                           an absolute address.  `laststart' will be
+                           the `set_number_at' we're about to insert;
+                           `laststart+3' the number to set, the source
+                           for the relative address.  But we are
+                           inserting into the middle of the pattern --
+                           so everything is getting moved up by 5.
+                           Conclusion: (b - 2) - (laststart + 3) + 5,
+                           i.e., b - laststart.
+
+                           We insert this at the beginning of the loop
+                           so that if we fail during matching, we'll
+                           reinitialize the bounds.  */
+                        insert_op2 (set_number_at, laststart, b - laststart,
+                                    upper_bound - 1, b);
+                        b += 5;
+                      }
+                  }
+               pending_exact = 0;
+               beg_interval = NULL;
+             }
+             break;
+
+           unfetch_interval:
+             /* If an invalid interval, match the characters as literals.  */
+              assert (beg_interval);
+              p = beg_interval;
+              beg_interval = NULL;
+
+              /* normal_char and normal_backslash need `c'.  */
+              PATFETCH (c);
+
+              if (!(syntax & RE_NO_BK_BRACES))
+                {
+                  if (p > pattern  &&  p[-1] == '\\')
+                    goto normal_backslash;
+                }
+              goto normal_char;
+
+#ifdef emacs
+           /* There is no way to specify the before_dot and after_dot
+              operators.  rms says this is ok.  --karl  */
+           case '=':
+             BUF_PUSH (at_dot);
+             break;
+
+           case 's':
+             laststart = b;
+             PATFETCH (c);
+             BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]);
+             break;
+
+           case 'S':
+             laststart = b;
+             PATFETCH (c);
+             BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
+             break;
+#endif /* emacs */
+
+
+           case 'w':
+             laststart = b;
+             BUF_PUSH (wordchar);
+             break;
+
+
+           case 'W':
+             laststart = b;
+             BUF_PUSH (notwordchar);
+             break;
+
+
+           case '<':
+             BUF_PUSH (wordbeg);
+             break;
+
+           case '>':
+             BUF_PUSH (wordend);
+             break;
+
+           case 'b':
+             BUF_PUSH (wordbound);
+             break;
+
+           case 'B':
+             BUF_PUSH (notwordbound);
+             break;
+
+           case '`':
+             BUF_PUSH (begbuf);
+             break;
+
+           case '\'':
+             BUF_PUSH (endbuf);
+             break;
+
+           case '1': case '2': case '3': case '4': case '5':
+           case '6': case '7': case '8': case '9':
+             if (syntax & RE_NO_BK_REFS)
+               goto normal_char;
+
+             c1 = c - '0';
+
+             if (c1 > regnum)
+               return REG_ESUBREG;
+
+             /* Can't back reference to a subexpression if inside of it.  */
+             if (group_in_compile_stack (compile_stack, c1))
+               goto normal_char;
+
+             laststart = b;
+             BUF_PUSH_2 (duplicate, c1);
+             break;
+
+
+           case '+':
+           case '?':
+             if (syntax & RE_BK_PLUS_QM)
+               goto handle_plus;
+             else
+               goto normal_backslash;
+
+           default:
+           normal_backslash:
+             /* You might think it would be useful for \ to mean
+                not to translate; but if we don't translate it
+                it will never match anything.  */
+             c = TRANSLATE (c);
+             goto normal_char;
+           }
+         break;
+
+
+       default:
+       /* Expects the character in `c'.  */
+       normal_char:
+             /* If no exactn currently being built.  */
+         if (!pending_exact
+
+             /* If last exactn not at current position.  */
+             || pending_exact + *pending_exact + 1 != b
+
+             /* We have only one byte following the exactn for the count.  */
+             || *pending_exact == (1 << BYTEWIDTH) - 1
+
+             /* If followed by a repetition operator.  */
+             || *p == '*' || *p == '^'
+             || ((syntax & RE_BK_PLUS_QM)
+                 ? *p == '\\' && (p[1] == '+' || p[1] == '?')
+                 : (*p == '+' || *p == '?'))
+             || ((syntax & RE_INTERVALS)
+                 && ((syntax & RE_NO_BK_BRACES)
+                     ? *p == '{'
+                     : (p[0] == '\\' && p[1] == '{'))))
+           {
+             /* Start building a new exactn.  */
+
+             laststart = b;
+
+             BUF_PUSH_2 (exactn, 0);
+             pending_exact = b - 1;
+           }
+
+         BUF_PUSH (c);
+         (*pending_exact)++;
+         break;
+       } /* switch (c) */
+    } /* while p != pend */
+
+
+  /* Through the pattern now.  */
+
+  if (fixup_alt_jump)
+    STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+  if (!COMPILE_STACK_EMPTY)
+    return REG_EPAREN;
+
+  free (compile_stack.stack);
+
+  /* We have succeeded; set the length of the buffer.  */
+  bufp->used = b - bufp->buffer;
+
+#ifdef DEBUG
+  if (debug)
+    {
+      DEBUG_PRINT1 ("\nCompiled pattern: ");
+      print_compiled_pattern (bufp);
+    }
+#endif /* DEBUG */
+
+  return REG_NOERROR;
+} /* regex_compile */
+\f
+/* Subroutines for `regex_compile'.  */
+
+/* Store OP at LOC followed by two-byte integer parameter ARG.  */
+
+static void
+store_op1 (op, loc, arg)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg;
+{
+  *loc = (unsigned char) op;
+  STORE_NUMBER (loc + 1, arg);
+}
+
+
+/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2.  */
+
+static void
+store_op2 (op, loc, arg1, arg2)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg1, arg2;
+{
+  *loc = (unsigned char) op;
+  STORE_NUMBER (loc + 1, arg1);
+  STORE_NUMBER (loc + 3, arg2);
+}
+
+
+/* Copy the bytes from LOC to END to open up three bytes of space at LOC
+   for OP followed by two-byte integer parameter ARG.  */
+
+static void
+insert_op1 (op, loc, arg, end)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg;
+    unsigned char *end;
+{
+  register unsigned char *pfrom = end;
+  register unsigned char *pto = end + 3;
+
+  while (pfrom != loc)
+    *--pto = *--pfrom;
+
+  store_op1 (op, loc, arg);
+}
+
+
+/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2.  */
+
+static void
+insert_op2 (op, loc, arg1, arg2, end)
+    re_opcode_t op;
+    unsigned char *loc;
+    int arg1, arg2;
+    unsigned char *end;
+{
+  register unsigned char *pfrom = end;
+  register unsigned char *pto = end + 5;
+
+  while (pfrom != loc)
+    *--pto = *--pfrom;
+
+  store_op2 (op, loc, arg1, arg2);
+}
+
+
+/* P points to just after a ^ in PATTERN.  Return true if that ^ comes
+   after an alternative or a begin-subexpression.  We assume there is at
+   least one character before the ^.  */
+
+static boolean
+at_begline_loc_p (pattern, p, syntax)
+    const char *pattern, *p;
+    reg_syntax_t syntax;
+{
+  const char *prev = p - 2;
+  boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
+
+  return
+       /* After a subexpression?  */
+       (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash))
+       /* After an alternative?  */
+    || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash));
+}
+
+
+/* The dual of at_begline_loc_p.  This one is for $.  We assume there is
+   at least one character after the $, i.e., `P < PEND'.  */
+
+static boolean
+at_endline_loc_p (p, pend, syntax)
+    const char *p, *pend;
+    int syntax;
+{
+  const char *next = p;
+  boolean next_backslash = *next == '\\';
+  const char *next_next = p + 1 < pend ? p + 1 : NULL;
+
+  return
+       /* Before a subexpression?  */
+       (syntax & RE_NO_BK_PARENS ? *next == ')'
+       : next_backslash && next_next && *next_next == ')')
+       /* Before an alternative?  */
+    || (syntax & RE_NO_BK_VBAR ? *next == '|'
+       : next_backslash && next_next && *next_next == '|');
+}
+
+
+/* Returns true if REGNUM is in one of COMPILE_STACK's elements and
+   false if it's not.  */
+
+static boolean
+group_in_compile_stack (compile_stack, regnum)
+    compile_stack_type compile_stack;
+    regnum_t regnum;
+{
+  int this_element;
+
+  for (this_element = compile_stack.avail - 1;
+       this_element >= 0;
+       this_element--)
+    if (compile_stack.stack[this_element].regnum == regnum)
+      return true;
+
+  return false;
+}
+
+
+/* Read the ending character of a range (in a bracket expression) from the
+   uncompiled pattern *P_PTR (which ends at PEND).  We assume the
+   starting character is in `P[-2]'.  (`P[-1]' is the character `-'.)
+   Then we set the translation of all bits between the starting and
+   ending characters (inclusive) in the compiled pattern B.
+
+   Return an error code.
+
+   We use these short variable names so we can use the same macros as
+   `regex_compile' itself.  */
+
+static reg_errcode_t
+compile_range (p_ptr, pend, translate, syntax, b)
+    const char **p_ptr, *pend;
+    char *translate;
+    reg_syntax_t syntax;
+    unsigned char *b;
+{
+  unsigned this_char;
+
+  const char *p = *p_ptr;
+  int range_start, range_end;
+
+  if (p == pend)
+    return REG_ERANGE;
+
+  /* Even though the pattern is a signed `char *', we need to fetch
+     with unsigned char *'s; if the high bit of the pattern character
+     is set, the range endpoints will be negative if we fetch using a
+     signed char *.
+
+     We also want to fetch the endpoints without translating them; the
+     appropriate translation is done in the bit-setting loop below.  */
+  range_start = ((unsigned char *) p)[-2];
+  range_end   = ((unsigned char *) p)[0];
+
+  /* Have to increment the pointer into the pattern string, so the
+     caller isn't still at the ending character.  */
+  (*p_ptr)++;
+
+  /* If the start is after the end, the range is empty.  */
+  if (range_start > range_end)
+    return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
+
+  /* Here we see why `this_char' has to be larger than an `unsigned
+     char' -- the range is inclusive, so if `range_end' == 0xff
+     (assuming 8-bit characters), we would otherwise go into an infinite
+     loop, since all characters <= 0xff.  */
+  for (this_char = range_start; this_char <= range_end; this_char++)
+    {
+      SET_LIST_BIT (TRANSLATE (this_char));
+    }
+
+  return REG_NOERROR;
+}
+\f
+/* Failure stack declarations and macros; both re_compile_fastmap and
+   re_match_2 use a failure stack.  These have to be macros because of
+   REGEX_ALLOCATE.  */
+
+
+/* Number of failure points for which to initially allocate space
+   when matching.  If this number is exceeded, we allocate more
+   space, so it is not a hard limit.  */
+#ifndef INIT_FAILURE_ALLOC
+#define INIT_FAILURE_ALLOC 5
+#endif
+
+/* Roughly the maximum number of failure points on the stack.  Would be
+   exactly that if always used MAX_FAILURE_SPACE each time we failed.
+   This is a variable only so users of regex can assign to it; we never
+   change it ourselves.  */
+int re_max_failures = 2000;
+
+typedef const unsigned char *fail_stack_elt_t;
+
+typedef struct
+{
+  fail_stack_elt_t *stack;
+  unsigned size;
+  unsigned avail;                      /* Offset of next open position.  */
+} fail_stack_type;
+
+#define FAIL_STACK_EMPTY()     (fail_stack.avail == 0)
+#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0)
+#define FAIL_STACK_FULL()      (fail_stack.avail == fail_stack.size)
+#define FAIL_STACK_TOP()       (fail_stack.stack[fail_stack.avail])
+
+
+/* Initialize `fail_stack'.  Do `return -2' if the alloc fails.  */
+
+#define INIT_FAIL_STACK()                                              \
+  do {                                                                 \
+    fail_stack.stack = (fail_stack_elt_t *)                            \
+      REGEX_ALLOCATE (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \
+                                                                       \
+    if (fail_stack.stack == NULL)                                      \
+      return -2;                                                       \
+                                                                       \
+    fail_stack.size = INIT_FAILURE_ALLOC;                              \
+    fail_stack.avail = 0;                                              \
+  } while (0)
+
+
+/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items.
+
+   Return 1 if succeeds, and 0 if either ran out of memory
+   allocating space for it or it was already too large.
+
+   REGEX_REALLOCATE requires `destination' be declared.   */
+
+#define DOUBLE_FAIL_STACK(fail_stack)                                  \
+  ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS             \
+   ? 0                                                                 \
+   : ((fail_stack).stack = (fail_stack_elt_t *)                                \
+       REGEX_REALLOCATE ((fail_stack).stack,                           \
+         (fail_stack).size * sizeof (fail_stack_elt_t),                \
+         ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)),        \
+                                                                       \
+      (fail_stack).stack == NULL                                       \
+      ? 0                                                              \
+      : ((fail_stack).size <<= 1,                                      \
+        1)))
+
+
+/* Push PATTERN_OP on FAIL_STACK.
+
+   Return 1 if was able to do so and 0 if ran out of memory allocating
+   space to do so.  */
+#define PUSH_PATTERN_OP(pattern_op, fail_stack)                                \
+  ((FAIL_STACK_FULL ()                                                 \
+    && !DOUBLE_FAIL_STACK (fail_stack))                                        \
+    ? 0                                                                        \
+    : ((fail_stack).stack[(fail_stack).avail++] = pattern_op,          \
+       1))
+
+/* This pushes an item onto the failure stack.  Must be a four-byte
+   value.  Assumes the variable `fail_stack'.  Probably should only
+   be called from within `PUSH_FAILURE_POINT'.  */
+#define PUSH_FAILURE_ITEM(item)                                                \
+  fail_stack.stack[fail_stack.avail++] = (fail_stack_elt_t) item
+
+/* The complement operation.  Assumes `fail_stack' is nonempty.  */
+#define POP_FAILURE_ITEM() fail_stack.stack[--fail_stack.avail]
+
+/* Used to omit pushing failure point id's when we're not debugging.  */
+#ifdef DEBUG
+#define DEBUG_PUSH PUSH_FAILURE_ITEM
+#define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_ITEM ()
+#else
+#define DEBUG_PUSH(item)
+#define DEBUG_POP(item_addr)
+#endif
+
+
+/* Push the information about the state we will need
+   if we ever fail back to it.
+
+   Requires variables fail_stack, regstart, regend, reg_info, and
+   num_regs be declared.  DOUBLE_FAIL_STACK requires `destination' be
+   declared.
+
+   Does `return FAILURE_CODE' if runs out of memory.  */
+
+#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code)  \
+  do {                                                                 \
+    char *destination;                                                 \
+    /* Must be int, so when we don't save any registers, the arithmetic        \
+       of 0 + -1 isn't done as unsigned.  */                           \
+    int this_reg;                                                      \
+                                                                       \
+    DEBUG_STATEMENT (failure_id++);                                    \
+    DEBUG_STATEMENT (nfailure_points_pushed++);                                \
+    DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id);          \
+    DEBUG_PRINT2 ("  Before push, next avail: %d\n", (fail_stack).avail);\
+    DEBUG_PRINT2 ("                     size: %d\n", (fail_stack).size);\
+                                                                       \
+    DEBUG_PRINT2 ("  slots needed: %d\n", NUM_FAILURE_ITEMS);          \
+    DEBUG_PRINT2 ("     available: %d\n", REMAINING_AVAIL_SLOTS);      \
+                                                                       \
+    /* Ensure we have enough space allocated for what we will push.  */        \
+    while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS)                  \
+      {                                                                        \
+       if (!DOUBLE_FAIL_STACK (fail_stack))                    \
+         return failure_code;                                          \
+                                                                       \
+       DEBUG_PRINT2 ("\n  Doubled stack; size now: %d\n",              \
+                      (fail_stack).size);                              \
+       DEBUG_PRINT2 ("  slots available: %d\n", REMAINING_AVAIL_SLOTS);\
+      }                                                                        \
+                                                                       \
+    /* Push the info, starting with the registers.  */                 \
+    DEBUG_PRINT1 ("\n");                                               \
+                                                                       \
+    for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \
+        this_reg++)                                                    \
+      {                                                                        \
+       DEBUG_PRINT2 ("  Pushing reg: %d\n", this_reg);                 \
+       DEBUG_STATEMENT (num_regs_pushed++);                            \
+                                                                       \
+       DEBUG_PRINT2 ("    start: 0x%x\n", regstart[this_reg]);         \
+       PUSH_FAILURE_ITEM (regstart[this_reg]);                         \
+                                                                       \
+       DEBUG_PRINT2 ("    end: 0x%x\n", regend[this_reg]);             \
+       PUSH_FAILURE_ITEM (regend[this_reg]);                           \
+                                                                       \
+       DEBUG_PRINT2 ("    info: 0x%x\n      ", reg_info[this_reg]);    \
+       DEBUG_PRINT2 (" match_null=%d",                                 \
+                     REG_MATCH_NULL_STRING_P (reg_info[this_reg]));    \
+       DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg]));    \
+       DEBUG_PRINT2 (" matched_something=%d",                          \
+                     MATCHED_SOMETHING (reg_info[this_reg]));          \
+       DEBUG_PRINT2 (" ever_matched=%d",                               \
+                     EVER_MATCHED_SOMETHING (reg_info[this_reg]));     \
+       DEBUG_PRINT1 ("\n");                                            \
+       PUSH_FAILURE_ITEM (reg_info[this_reg].word);                    \
+      }                                                                        \
+                                                                       \
+    DEBUG_PRINT2 ("  Pushing  low active reg: %d\n", lowest_active_reg);\
+    PUSH_FAILURE_ITEM (lowest_active_reg);                             \
+                                                                       \
+    DEBUG_PRINT2 ("  Pushing high active reg: %d\n", highest_active_reg);\
+    PUSH_FAILURE_ITEM (highest_active_reg);                            \
+                                                                       \
+    DEBUG_PRINT2 ("  Pushing pattern 0x%x: ", pattern_place);          \
+    DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend);          \
+    PUSH_FAILURE_ITEM (pattern_place);                                 \
+                                                                       \
+    DEBUG_PRINT2 ("  Pushing string 0x%x: `", string_place);           \
+    DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2,   \
+                                size2);                                \
+    DEBUG_PRINT1 ("'\n");                                              \
+    PUSH_FAILURE_ITEM (string_place);                                  \
+                                                                       \
+    DEBUG_PRINT2 ("  Pushing failure id: %u\n", failure_id);           \
+    DEBUG_PUSH (failure_id);                                           \
+  } while (0)
+
+/* This is the number of items that are pushed and popped on the stack
+   for each register.  */
+#define NUM_REG_ITEMS  3
+
+/* Individual items aside from the registers.  */
+#ifdef DEBUG
+#define NUM_NONREG_ITEMS 5 /* Includes failure point id.  */
+#else
+#define NUM_NONREG_ITEMS 4
+#endif
+
+/* We push at most this many items on the stack.  */
+#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
+
+/* We actually push this many items.  */
+#define NUM_FAILURE_ITEMS                                              \
+  ((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS        \
+    + NUM_NONREG_ITEMS)
+
+/* How many items can still be added to the stack without overflowing it.  */
+#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
+
+
+/* Pops what PUSH_FAIL_STACK pushes.
+
+   We restore into the parameters, all of which should be lvalues:
+     STR -- the saved data position.
+     PAT -- the saved pattern position.
+     LOW_REG, HIGH_REG -- the highest and lowest active registers.
+     REGSTART, REGEND -- arrays of string positions.
+     REG_INFO -- array of information about each subexpression.
+
+   Also assumes the variables `fail_stack' and (if debugging), `bufp',
+   `pend', `string1', `size1', `string2', and `size2'.  */
+
+#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\
+{                                                                      \
+  DEBUG_STATEMENT (fail_stack_elt_t failure_id;)                       \
+  int this_reg;                                                                \
+  const unsigned char *string_temp;                                    \
+                                                                       \
+  assert (!FAIL_STACK_EMPTY ());                                       \
+                                                                       \
+  /* Remove failure points and point to how many regs pushed.  */      \
+  DEBUG_PRINT1 ("POP_FAILURE_POINT:\n");                               \
+  DEBUG_PRINT2 ("  Before pop, next avail: %d\n", fail_stack.avail);   \
+  DEBUG_PRINT2 ("                    size: %d\n", fail_stack.size);    \
+                                                                       \
+  assert (fail_stack.avail >= NUM_NONREG_ITEMS);                       \
+                                                                       \
+  DEBUG_POP (&failure_id);                                             \
+  DEBUG_PRINT2 ("  Popping failure id: %u\n", failure_id);             \
+                                                                       \
+  /* If the saved string location is NULL, it came from an             \
+     on_failure_keep_string_jump opcode, and we want to throw away the \
+     saved NULL, thus retaining our current position in the string.  */        \
+  string_temp = POP_FAILURE_ITEM ();                                   \
+  if (string_temp != NULL)                                             \
+    str = (const char *) string_temp;                                  \
+                                                                       \
+  DEBUG_PRINT2 ("  Popping string 0x%x: `", str);                      \
+  DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2);     \
+  DEBUG_PRINT1 ("'\n");                                                        \
+                                                                       \
+  pat = (unsigned char *) POP_FAILURE_ITEM ();                         \
+  DEBUG_PRINT2 ("  Popping pattern 0x%x: ", pat);                      \
+  DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend);                      \
+                                                                       \
+  /* Restore register info.  */                                                \
+  high_reg = (unsigned) POP_FAILURE_ITEM ();                           \
+  DEBUG_PRINT2 ("  Popping high active reg: %d\n", high_reg);          \
+                                                                       \
+  low_reg = (unsigned) POP_FAILURE_ITEM ();                            \
+  DEBUG_PRINT2 ("  Popping  low active reg: %d\n", low_reg);           \
+                                                                       \
+  for (this_reg = high_reg; this_reg >= low_reg; this_reg--)           \
+    {                                                                  \
+      DEBUG_PRINT2 ("    Popping reg: %d\n", this_reg);                        \
+                                                                       \
+      reg_info[this_reg].word = POP_FAILURE_ITEM ();                   \
+      DEBUG_PRINT2 ("      info: 0x%x\n", reg_info[this_reg]);         \
+                                                                       \
+      regend[this_reg] = (const char *) POP_FAILURE_ITEM ();           \
+      DEBUG_PRINT2 ("      end: 0x%x\n", regend[this_reg]);            \
+                                                                       \
+      regstart[this_reg] = (const char *) POP_FAILURE_ITEM ();         \
+      DEBUG_PRINT2 ("      start: 0x%x\n", regstart[this_reg]);                \
+    }                                                                  \
+                                                                       \
+  DEBUG_STATEMENT (nfailure_points_popped++);                          \
+} /* POP_FAILURE_POINT */
+\f
+/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in
+   BUFP.  A fastmap records which of the (1 << BYTEWIDTH) possible
+   characters can start a string that matches the pattern.  This fastmap
+   is used by re_search to skip quickly over impossible starting points.
+
+   The caller must supply the address of a (1 << BYTEWIDTH)-byte data
+   area as BUFP->fastmap.
+
+   We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in
+   the pattern buffer.
+
+   Returns 0 if we succeed, -2 if an internal error.   */
+
+int
+re_compile_fastmap (bufp)
+     struct re_pattern_buffer *bufp;
+{
+  int j, k;
+  fail_stack_type fail_stack;
+#ifndef REGEX_MALLOC
+  char *destination;
+#endif
+  /* We don't push any register information onto the failure stack.  */
+  unsigned num_regs = 0;
+
+  register char *fastmap = bufp->fastmap;
+  unsigned char *pattern = bufp->buffer;
+  unsigned long size = bufp->used;
+  const unsigned char *p = pattern;
+  register unsigned char *pend = pattern + size;
+
+  /* Assume that each path through the pattern can be null until
+     proven otherwise.  We set this false at the bottom of switch
+     statement, to which we get only if a particular path doesn't
+     match the empty string.  */
+  boolean path_can_be_null = true;
+
+  /* We aren't doing a `succeed_n' to begin with.  */
+  boolean succeed_n_p = false;
+
+  assert (fastmap != NULL && p != NULL);
+
+  INIT_FAIL_STACK ();
+  bzero (fastmap, 1 << BYTEWIDTH);  /* Assume nothing's valid.  */
+  bufp->fastmap_accurate = 1;      /* It will be when we're done.  */
+  bufp->can_be_null = 0;
+
+  while (p != pend || !FAIL_STACK_EMPTY ())
+    {
+      if (p == pend)
+       {
+         bufp->can_be_null |= path_can_be_null;
+
+         /* Reset for next path.  */
+         path_can_be_null = true;
+
+         p = fail_stack.stack[--fail_stack.avail];
+       }
+
+      /* We should never be about to go beyond the end of the pattern.  */
+      assert (p < pend);
+
+#ifdef SWITCH_ENUM_BUG
+      switch ((int) ((re_opcode_t) *p++))
+#else
+      switch ((re_opcode_t) *p++)
+#endif
+       {
+
+       /* I guess the idea here is to simply not bother with a fastmap
+          if a backreference is used, since it's too hard to figure out
+          the fastmap for the corresponding group.  Setting
+          `can_be_null' stops `re_search_2' from using the fastmap, so
+          that is all we do.  */
+       case duplicate:
+         bufp->can_be_null = 1;
+         return 0;
+
+
+      /* Following are the cases which match a character.  These end
+        with `break'.  */
+
+       case exactn:
+         fastmap[p[1]] = 1;
+         break;
+
+
+       case charset:
+         for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+           if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
+             fastmap[j] = 1;
+         break;
+
+
+       case charset_not:
+         /* Chars beyond end of map must be allowed.  */
+         for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
+           fastmap[j] = 1;
+
+         for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+           if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
+             fastmap[j] = 1;
+         break;
+
+
+       case wordchar:
+         for (j = 0; j < (1 << BYTEWIDTH); j++)
+           if (SYNTAX (j) == Sword)
+             fastmap[j] = 1;
+         break;
+
+
+       case notwordchar:
+         for (j = 0; j < (1 << BYTEWIDTH); j++)
+           if (SYNTAX (j) != Sword)
+             fastmap[j] = 1;
+         break;
+
+
+       case anychar:
+         /* `.' matches anything ...  */
+         for (j = 0; j < (1 << BYTEWIDTH); j++)
+           fastmap[j] = 1;
+
+         /* ... except perhaps newline.  */
+         if (!(bufp->syntax & RE_DOT_NEWLINE))
+           fastmap['\n'] = 0;
+
+         /* Return if we have already set `can_be_null'; if we have,
+            then the fastmap is irrelevant.  Something's wrong here.  */
+         else if (bufp->can_be_null)
+           return 0;
+
+         /* Otherwise, have to check alternative paths.  */
+         break;
+
+
+#ifdef emacs
+       case syntaxspec:
+         k = *p++;
+         for (j = 0; j < (1 << BYTEWIDTH); j++)
+           if (SYNTAX (j) == (enum syntaxcode) k)
+             fastmap[j] = 1;
+         break;
+
+
+       case notsyntaxspec:
+         k = *p++;
+         for (j = 0; j < (1 << BYTEWIDTH); j++)
+           if (SYNTAX (j) != (enum syntaxcode) k)
+             fastmap[j] = 1;
+         break;
+
+
+      /* All cases after this match the empty string.  These end with
+        `continue'.  */
+
+
+       case before_dot:
+       case at_dot:
+       case after_dot:
+         continue;
+#endif /* not emacs */
+
+
+       case no_op:
+       case begline:
+       case endline:
+       case begbuf:
+       case endbuf:
+       case wordbound:
+       case notwordbound:
+       case wordbeg:
+       case wordend:
+       case push_dummy_failure:
+         continue;
+
+
+       case jump_n:
+       case pop_failure_jump:
+       case maybe_pop_jump:
+       case jump:
+       case jump_past_alt:
+       case dummy_failure_jump:
+         EXTRACT_NUMBER_AND_INCR (j, p);
+         p += j;
+         if (j > 0)
+           continue;
+
+         /* Jump backward implies we just went through the body of a
+            loop and matched nothing.  Opcode jumped to should be
+            `on_failure_jump' or `succeed_n'.  Just treat it like an
+            ordinary jump.  For a * loop, it has pushed its failure
+            point already; if so, discard that as redundant.  */
+         if ((re_opcode_t) *p != on_failure_jump
+             && (re_opcode_t) *p != succeed_n)
+           continue;
+
+         p++;
+         EXTRACT_NUMBER_AND_INCR (j, p);
+         p += j;
+
+         /* If what's on the stack is where we are now, pop it.  */
+         if (!FAIL_STACK_EMPTY ()
+             && fail_stack.stack[fail_stack.avail - 1] == p)
+           fail_stack.avail--;
+
+         continue;
+
+
+       case on_failure_jump:
+       case on_failure_keep_string_jump:
+       handle_on_failure_jump:
+         EXTRACT_NUMBER_AND_INCR (j, p);
+
+         /* For some patterns, e.g., `(a?)?', `p+j' here points to the
+            end of the pattern.  We don't want to push such a point,
+            since when we restore it above, entering the switch will
+            increment `p' past the end of the pattern.  We don't need
+            to push such a point since we obviously won't find any more
+            fastmap entries beyond `pend'.  Such a pattern can match
+            the null string, though.  */
+         if (p + j < pend)
+           {
+             if (!PUSH_PATTERN_OP (p + j, fail_stack))
+               return -2;
+           }
+         else
+           bufp->can_be_null = 1;
+
+         if (succeed_n_p)
+           {
+             EXTRACT_NUMBER_AND_INCR (k, p);   /* Skip the n.  */
+             succeed_n_p = false;
+           }
+
+         continue;
+
+
+       case succeed_n:
+         /* Get to the number of times to succeed.  */
+         p += 2;
+
+         /* Increment p past the n for when k != 0.  */
+         EXTRACT_NUMBER_AND_INCR (k, p);
+         if (k == 0)
+           {
+             p -= 4;
+             succeed_n_p = true;  /* Spaghetti code alert.  */
+             goto handle_on_failure_jump;
+           }
+         continue;
+
+
+       case set_number_at:
+         p += 4;
+         continue;
+
+
+       case start_memory:
+       case stop_memory:
+         p += 2;
+         continue;
+
+
+       default:
+         abort (); /* We have listed all the cases.  */
+       } /* switch *p++ */
+
+      /* Getting here means we have found the possible starting
+        characters for one path of the pattern -- and that the empty
+        string does not match.  We need not follow this path further.
+        Instead, look at the next alternative (remembered on the
+        stack), or quit if no more.  The test at the top of the loop
+        does these things.  */
+      path_can_be_null = false;
+      p = pend;
+    } /* while p */
+
+  /* Set `can_be_null' for the last path (also the first path, if the
+     pattern is empty).  */
+  bufp->can_be_null |= path_can_be_null;
+  return 0;
+} /* re_compile_fastmap */
+\f
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+   ENDS.  Subsequent matches using PATTERN_BUFFER and REGS will use
+   this memory for recording register information.  STARTS and ENDS
+   must be allocated using the malloc library routine, and must each
+   be at least NUM_REGS * sizeof (regoff_t) bytes long.
+
+   If NUM_REGS == 0, then subsequent matches should allocate their own
+   register data.
+
+   Unless this function is called, the first search or match using
+   PATTERN_BUFFER will allocate its own register data, without
+   freeing the old data.  */
+
+void
+re_set_registers (bufp, regs, num_regs, starts, ends)
+    struct re_pattern_buffer *bufp;
+    struct re_registers *regs;
+    unsigned num_regs;
+    regoff_t *starts, *ends;
+{
+  if (num_regs)
+    {
+      bufp->regs_allocated = REGS_REALLOCATE;
+      regs->num_regs = num_regs;
+      regs->start = starts;
+      regs->end = ends;
+    }
+  else
+    {
+      bufp->regs_allocated = REGS_UNALLOCATED;
+      regs->num_regs = 0;
+      regs->start = regs->end = (regoff_t) 0;
+    }
+}
+\f
+/* Searching routines.  */
+
+/* Like re_search_2, below, but only one string is specified, and
+   doesn't let you say where to stop matching. */
+
+int
+re_search (bufp, string, size, startpos, range, regs)
+     struct re_pattern_buffer *bufp;
+     const char *string;
+     int size, startpos, range;
+     struct re_registers *regs;
+{
+  return re_search_2 (bufp, NULL, 0, string, size, startpos, range,
+                     regs, size);
+}
+
+
+/* Using the compiled pattern in BUFP->buffer, first tries to match the
+   virtual concatenation of STRING1 and STRING2, starting first at index
+   STARTPOS, then at STARTPOS + 1, and so on.
+
+   STRING1 and STRING2 have length SIZE1 and SIZE2, respectively.
+
+   RANGE is how far to scan while trying to match.  RANGE = 0 means try
+   only at STARTPOS; in general, the last start tried is STARTPOS +
+   RANGE.
+
+   In REGS, return the indices of the virtual concatenation of STRING1
+   and STRING2 that matched the entire BUFP->buffer and its contained
+   subexpressions.
+
+   Do not consider matching one past the index STOP in the virtual
+   concatenation of STRING1 and STRING2.
+
+   We return either the position in the strings at which the match was
+   found, -1 if no match, or -2 if error (such as failure
+   stack overflow).  */
+
+int
+re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
+     struct re_pattern_buffer *bufp;
+     const char *string1, *string2;
+     int size1, size2;
+     int startpos;
+     int range;
+     struct re_registers *regs;
+     int stop;
+{
+  int val;
+  register char *fastmap = bufp->fastmap;
+  register char *translate = bufp->translate;
+  int total_size = size1 + size2;
+  int endpos = startpos + range;
+
+  /* Check for out-of-range STARTPOS.  */
+  if (startpos < 0 || startpos > total_size)
+    return -1;
+
+  /* Fix up RANGE if it might eventually take us outside
+     the virtual concatenation of STRING1 and STRING2.  */
+  if (endpos < -1)
+    range = -1 - startpos;
+  else if (endpos > total_size)
+    range = total_size - startpos;
+
+  /* If the search isn't to be a backwards one, don't waste time in a
+     search for a pattern that must be anchored.  */
+  if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0)
+    {
+      if (startpos > 0)
+       return -1;
+      else
+       range = 1;
+    }
+
+  /* Update the fastmap now if not correct already.  */
+  if (fastmap && !bufp->fastmap_accurate)
+    if (re_compile_fastmap (bufp) == -2)
+      return -2;
+
+  /* Loop through the string, looking for a place to start matching.  */
+  for (;;)
+    {
+      /* If a fastmap is supplied, skip quickly over characters that
+        cannot be the start of a match.  If the pattern can match the
+        null string, however, we don't need to skip characters; we want
+        the first null string.  */
+      if (fastmap && startpos < total_size && !bufp->can_be_null)
+       {
+         if (range > 0)        /* Searching forwards.  */
+           {
+             register const char *d;
+             register int lim = 0;
+             int irange = range;
+
+             if (startpos < size1 && startpos + range >= size1)
+               lim = range - (size1 - startpos);
+
+             d = (startpos >= size1 ? string2 - size1 : string1) + startpos;
+
+             /* Written out as an if-else to avoid testing `translate'
+                inside the loop.  */
+             if (translate)
+               while (range > lim
+                      && !fastmap[(unsigned char)
+                                  translate[(unsigned char) *d++]])
+                 range--;
+             else
+               while (range > lim && !fastmap[(unsigned char) *d++])
+                 range--;
+
+             startpos += irange - range;
+           }
+         else                          /* Searching backwards.  */
+           {
+             register char c = (size1 == 0 || startpos >= size1
+                                ? string2[startpos - size1]
+                                : string1[startpos]);
+
+             if (!fastmap[(unsigned char) TRANSLATE (c)])
+               goto advance;
+           }
+       }
+
+      /* If can't match the null string, and that's all we have left, fail.  */
+      if (range >= 0 && startpos == total_size && fastmap
+         && !bufp->can_be_null)
+       return -1;
+
+      val = re_match_2 (bufp, string1, size1, string2, size2,
+                       startpos, regs, stop);
+      if (val >= 0)
+       return startpos;
+
+      if (val == -2)
+       return -2;
+
+    advance:
+      if (!range)
+       break;
+      else if (range > 0)
+       {
+         range--;
+         startpos++;
+       }
+      else
+       {
+         range++;
+         startpos--;
+       }
+    }
+  return -1;
+} /* re_search_2 */
+\f
+/* Declarations and macros for re_match_2.  */
+
+static int bcmp_translate ();
+static boolean alt_match_null_string_p (),
+              common_op_match_null_string_p (),
+              group_match_null_string_p ();
+
+/* Structure for per-register (a.k.a. per-group) information.
+   This must not be longer than one word, because we push this value
+   onto the failure stack.  Other register information, such as the
+   starting and ending positions (which are addresses), and the list of
+   inner groups (which is a bits list) are maintained in separate
+   variables.
+
+   We are making a (strictly speaking) nonportable assumption here: that
+   the compiler will pack our bit fields into something that fits into
+   the type of `word', i.e., is something that fits into one item on the
+   failure stack.  */
+typedef union
+{
+  fail_stack_elt_t word;
+  struct
+  {
+      /* This field is one if this group can match the empty string,
+        zero if not.  If not yet determined,  `MATCH_NULL_UNSET_VALUE'.  */
+#define MATCH_NULL_UNSET_VALUE 3
+    unsigned match_null_string_p : 2;
+    unsigned is_active : 1;
+    unsigned matched_something : 1;
+    unsigned ever_matched_something : 1;
+  } bits;
+} register_info_type;
+
+#define REG_MATCH_NULL_STRING_P(R)  ((R).bits.match_null_string_p)
+#define IS_ACTIVE(R)  ((R).bits.is_active)
+#define MATCHED_SOMETHING(R)  ((R).bits.matched_something)
+#define EVER_MATCHED_SOMETHING(R)  ((R).bits.ever_matched_something)
+
+
+/* Call this when have matched a real character; it sets `matched' flags
+   for the subexpressions which we are currently inside.  Also records
+   that those subexprs have matched.  */
+#define SET_REGS_MATCHED()                                             \
+  do                                                                   \
+    {                                                                  \
+      unsigned r;                                                      \
+      for (r = lowest_active_reg; r <= highest_active_reg; r++)                \
+       {                                                               \
+         MATCHED_SOMETHING (reg_info[r])                               \
+           = EVER_MATCHED_SOMETHING (reg_info[r])                      \
+           = 1;                                                        \
+       }                                                               \
+    }                                                                  \
+  while (0)
+
+
+/* This converts PTR, a pointer into one of the search strings `string1'
+   and `string2' into an offset from the beginning of that string.  */
+#define POINTER_TO_OFFSET(ptr)                                         \
+  (FIRST_STRING_P (ptr) ? (ptr) - string1 : (ptr) - string2 + size1)
+
+/* Registers are set to a sentinel when they haven't yet matched.  */
+#define REG_UNSET_VALUE ((char *) -1)
+#define REG_UNSET(e) ((e) == REG_UNSET_VALUE)
+
+
+/* Macros for dealing with the split strings in re_match_2.  */
+
+#define MATCHING_IN_FIRST_STRING  (dend == end_match_1)
+
+/* Call before fetching a character with *d.  This switches over to
+   string2 if necessary.  */
+#define PREFETCH()                                                     \
+  while (d == dend)                                                    \
+    {                                                                  \
+      /* End of string2 => fail.  */                                   \
+      if (dend == end_match_2)                                                 \
+       goto fail;                                                      \
+      /* End of string1 => advance to string2.  */                     \
+      d = string2;                                                     \
+      dend = end_match_2;                                              \
+    }
+
+
+/* Test if at very beginning or at very end of the virtual concatenation
+   of `string1' and `string2'.  If only one string, it's `string2'.  */
+#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2)
+#define AT_STRINGS_END(d) ((d) == end2)
+
+
+/* Test if D points to a character which is word-constituent.  We have
+   two special cases to check for: if past the end of string1, look at
+   the first character in string2; and if before the beginning of
+   string2, look at the last character in string1.  */
+#define WORDCHAR_P(d)                                                  \
+  (SYNTAX ((d) == end1 ? *string2                                      \
+          : (d) == string2 - 1 ? *(end1 - 1) : *(d))                   \
+   == Sword)
+
+/* Test if the character before D and the one at D differ with respect
+   to being word-constituent.  */
+#define AT_WORD_BOUNDARY(d)                                            \
+  (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)                            \
+   || WORDCHAR_P (d - 1) != WORDCHAR_P (d))
+
+
+/* Free everything we malloc.  */
+#ifdef REGEX_MALLOC
+#define FREE_VAR(var) if (var) free (var); var = NULL
+#define FREE_VARIABLES()                                               \
+  do {                                                                 \
+    FREE_VAR (fail_stack.stack);                                       \
+    FREE_VAR (regstart);                                               \
+    FREE_VAR (regend);                                                 \
+    FREE_VAR (old_regstart);                                           \
+    FREE_VAR (old_regend);                                             \
+    FREE_VAR (best_regstart);                                          \
+    FREE_VAR (best_regend);                                            \
+    FREE_VAR (reg_info);                                               \
+    FREE_VAR (reg_dummy);                                              \
+    FREE_VAR (reg_info_dummy);                                         \
+  } while (0)
+#else /* not REGEX_MALLOC */
+/* Some MIPS systems (at least) want this to free alloca'd storage.  */
+#define FREE_VARIABLES() alloca (0)
+#endif /* not REGEX_MALLOC */
+
+
+/* These values must meet several constraints.  They must not be valid
+   register values; since we have a limit of 255 registers (because
+   we use only one byte in the pattern for the register number), we can
+   use numbers larger than 255.  They must differ by 1, because of
+   NUM_FAILURE_ITEMS above.  And the value for the lowest register must
+   be larger than the value for the highest register, so we do not try
+   to actually save any registers when none are active.  */
+#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH)
+#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1)
+\f
+/* Matching routines.  */
+
+#ifndef emacs   /* Emacs never uses this.  */
+/* re_match is like re_match_2 except it takes only a single string.  */
+
+int
+re_match (bufp, string, size, pos, regs)
+     struct re_pattern_buffer *bufp;
+     const char *string;
+     int size, pos;
+     struct re_registers *regs;
+ {
+  return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size);
+}
+#endif /* not emacs */
+
+
+/* re_match_2 matches the compiled pattern in BUFP against the
+   the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
+   and SIZE2, respectively).  We start matching at POS, and stop
+   matching at STOP.
+
+   If REGS is non-null and the `no_sub' field of BUFP is nonzero, we
+   store offsets for the substring each group matched in REGS.  See the
+   documentation for exactly how many groups we fill.
+
+   We return -1 if no match, -2 if an internal error (such as the
+   failure stack overflowing).  Otherwise, we return the length of the
+   matched substring.  */
+
+int
+re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
+     struct re_pattern_buffer *bufp;
+     const char *string1, *string2;
+     int size1, size2;
+     int pos;
+     struct re_registers *regs;
+     int stop;
+{
+  /* General temporaries.  */
+  int mcnt;
+  unsigned char *p1;
+
+  /* Just past the end of the corresponding string.  */
+  const char *end1, *end2;
+
+  /* Pointers into string1 and string2, just past the last characters in
+     each to consider matching.  */
+  const char *end_match_1, *end_match_2;
+
+  /* Where we are in the data, and the end of the current string.  */
+  const char *d, *dend;
+
+  /* Where we are in the pattern, and the end of the pattern.  */
+  unsigned char *p = bufp->buffer;
+  register unsigned char *pend = p + bufp->used;
+
+  /* We use this to map every character in the string.  */
+  char *translate = bufp->translate;
+
+  /* Failure point stack.  Each place that can handle a failure further
+     down the line pushes a failure point on this stack.  It consists of
+     restart, regend, and reg_info for all registers corresponding to
+     the subexpressions we're currently inside, plus the number of such
+     registers, and, finally, two char *'s.  The first char * is where
+     to resume scanning the pattern; the second one is where to resume
+     scanning the strings.  If the latter is zero, the failure point is
+     a ``dummy''; if a failure happens and the failure point is a dummy,
+     it gets discarded and the next next one is tried.  */
+  fail_stack_type fail_stack;
+#ifdef DEBUG
+  static unsigned failure_id = 0;
+  unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
+#endif
+
+  /* We fill all the registers internally, independent of what we
+     return, for use in backreferences.  The number here includes
+     an element for register zero.  */
+  unsigned num_regs = bufp->re_nsub + 1;
+
+  /* The currently active registers.  */
+  unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+  unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+
+  /* Information on the contents of registers. These are pointers into
+     the input strings; they record just what was matched (on this
+     attempt) by a subexpression part of the pattern, that is, the
+     regnum-th regstart pointer points to where in the pattern we began
+     matching and the regnum-th regend points to right after where we
+     stopped matching the regnum-th subexpression.  (The zeroth register
+     keeps track of what the whole pattern matches.)  */
+  const char **regstart = NULL, **regend = NULL;
+
+  /* If a group that's operated upon by a repetition operator fails to
+     match anything, then the register for its start will need to be
+     restored because it will have been set to wherever in the string we
+     are when we last see its open-group operator.  Similarly for a
+     register's end.  */
+  const char **old_regstart = NULL, **old_regend = NULL;
+
+  /* The is_active field of reg_info helps us keep track of which (possibly
+     nested) subexpressions we are currently in. The matched_something
+     field of reg_info[reg_num] helps us tell whether or not we have
+     matched any of the pattern so far this time through the reg_num-th
+     subexpression.  These two fields get reset each time through any
+     loop their register is in.  */
+  register_info_type *reg_info = NULL;
+
+  /* The following record the register info as found in the above
+     variables when we find a match better than any we've seen before.
+     This happens as we backtrack through the failure points, which in
+     turn happens only if we have not yet matched the entire string. */
+  unsigned best_regs_set = false;
+  const char **best_regstart = NULL, **best_regend = NULL;
+
+  /* Logically, this is `best_regend[0]'.  But we don't want to have to
+     allocate space for that if we're not allocating space for anything
+     else (see below).  Also, we never need info about register 0 for
+     any of the other register vectors, and it seems rather a kludge to
+     treat `best_regend' differently than the rest.  So we keep track of
+     the end of the best match so far in a separate variable.  We
+     initialize this to NULL so that when we backtrack the first time
+     and need to test it, it's not garbage.  */
+  const char *match_end = NULL;
+
+  /* Used when we pop values we don't care about.  */
+  const char **reg_dummy = NULL;
+  register_info_type *reg_info_dummy = NULL;
+
+#ifdef DEBUG
+  /* Counts the total number of registers pushed.  */
+  unsigned num_regs_pushed = 0;
+#endif
+
+  DEBUG_PRINT1 ("\n\nEntering re_match_2.\n");
+
+  INIT_FAIL_STACK ();
+
+  /* Do not bother to initialize all the register variables if there are
+     no groups in the pattern, as it takes a fair amount of time.  If
+     there are groups, we include space for register 0 (the whole
+     pattern), even though we never use it, since it simplifies the
+     array indexing.  We should fix this.  */
+  if (bufp->re_nsub)
+    {
+      regstart = REGEX_TALLOC (num_regs, const char *);
+      regend = REGEX_TALLOC (num_regs, const char *);
+      old_regstart = REGEX_TALLOC (num_regs, const char *);
+      old_regend = REGEX_TALLOC (num_regs, const char *);
+      best_regstart = REGEX_TALLOC (num_regs, const char *);
+      best_regend = REGEX_TALLOC (num_regs, const char *);
+      reg_info = REGEX_TALLOC (num_regs, register_info_type);
+      reg_dummy = REGEX_TALLOC (num_regs, const char *);
+      reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type);
+
+      if (!(regstart && regend && old_regstart && old_regend && reg_info
+           && best_regstart && best_regend && reg_dummy && reg_info_dummy))
+       {
+         FREE_VARIABLES ();
+         return -2;
+       }
+    }
+#ifdef REGEX_MALLOC
+  else
+    {
+      /* We must initialize all our variables to NULL, so that
+        `FREE_VARIABLES' doesn't try to free them.  */
+      regstart = regend = old_regstart = old_regend = best_regstart
+       = best_regend = reg_dummy = NULL;
+      reg_info = reg_info_dummy = (register_info_type *) NULL;
+    }
+#endif /* REGEX_MALLOC */
+
+  /* The starting position is bogus.  */
+  if (pos < 0 || pos > size1 + size2)
+    {
+      FREE_VARIABLES ();
+      return -1;
+    }
+
+  /* Initialize subexpression text positions to -1 to mark ones that no
+     start_memory/stop_memory has been seen for. Also initialize the
+     register information struct.  */
+  for (mcnt = 1; mcnt < num_regs; mcnt++)
+    {
+      regstart[mcnt] = regend[mcnt]
+       = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE;
+
+      REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE;
+      IS_ACTIVE (reg_info[mcnt]) = 0;
+      MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+      EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+    }
+
+  /* We move `string1' into `string2' if the latter's empty -- but not if
+     `string1' is null.  */
+  if (size2 == 0 && string1 != NULL)
+    {
+      string2 = string1;
+      size2 = size1;
+      string1 = 0;
+      size1 = 0;
+    }
+  end1 = string1 + size1;
+  end2 = string2 + size2;
+
+  /* Compute where to stop matching, within the two strings.  */
+  if (stop <= size1)
+    {
+      end_match_1 = string1 + stop;
+      end_match_2 = string2;
+    }
+  else
+    {
+      end_match_1 = end1;
+      end_match_2 = string2 + stop - size1;
+    }
+
+  /* `p' scans through the pattern as `d' scans through the data.
+     `dend' is the end of the input string that `d' points within.  `d'
+     is advanced into the following input string whenever necessary, but
+     this happens before fetching; therefore, at the beginning of the
+     loop, `d' can be pointing at the end of a string, but it cannot
+     equal `string2'.  */
+  if (size1 > 0 && pos <= size1)
+    {
+      d = string1 + pos;
+      dend = end_match_1;
+    }
+  else
+    {
+      d = string2 + pos - size1;
+      dend = end_match_2;
+    }
+
+  DEBUG_PRINT1 ("The compiled pattern is: ");
+  DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend);
+  DEBUG_PRINT1 ("The string to match is: `");
+  DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2);
+  DEBUG_PRINT1 ("'\n");
+
+  /* This loops over pattern commands.  It exits by returning from the
+     function if the match is complete, or it drops through if the match
+     fails at this starting point in the input data.  */
+  for (;;)
+    {
+      DEBUG_PRINT2 ("\n0x%x: ", p);
+
+      if (p == pend)
+       { /* End of pattern means we might have succeeded.  */
+         DEBUG_PRINT1 ("end of pattern ... ");
+
+         /* If we haven't matched the entire string, and we want the
+            longest match, try backtracking.  */
+         if (d != end_match_2)
+           {
+             DEBUG_PRINT1 ("backtracking.\n");
+
+             if (!FAIL_STACK_EMPTY ())
+               { /* More failure points to try.  */
+                 boolean same_str_p = (FIRST_STRING_P (match_end)
+                                       == MATCHING_IN_FIRST_STRING);
+
+                 /* If exceeds best match so far, save it.  */
+                 if (!best_regs_set
+                     || (same_str_p && d > match_end)
+                     || (!same_str_p && !MATCHING_IN_FIRST_STRING))
+                   {
+                     best_regs_set = true;
+                     match_end = d;
+
+                     DEBUG_PRINT1 ("\nSAVING match as best so far.\n");
+
+                     for (mcnt = 1; mcnt < num_regs; mcnt++)
+                       {
+                         best_regstart[mcnt] = regstart[mcnt];
+                         best_regend[mcnt] = regend[mcnt];
+                       }
+                   }
+                 goto fail;
+               }
+
+             /* If no failure points, don't restore garbage.  */
+             else if (best_regs_set)
+               {
+               restore_best_regs:
+                 /* Restore best match.  It may happen that `dend ==
+                    end_match_1' while the restored d is in string2.
+                    For example, the pattern `x.*y.*z' against the
+                    strings `x-' and `y-z-', if the two strings are
+                    not consecutive in memory.  */
+                 DEBUG_PRINT1 ("Restoring best registers.\n");
+
+                 d = match_end;
+                 dend = ((d >= string1 && d <= end1)
+                          ? end_match_1 : end_match_2);
+
+                 for (mcnt = 1; mcnt < num_regs; mcnt++)
+                   {
+                     regstart[mcnt] = best_regstart[mcnt];
+                     regend[mcnt] = best_regend[mcnt];
+                   }
+               }
+           } /* d != end_match_2 */
+
+         DEBUG_PRINT1 ("Accepting match.\n");
+
+         /* If caller wants register contents data back, do it.  */
+         if (regs && !bufp->no_sub)
+           {
+             /* Have the register data arrays been allocated?  */
+             if (bufp->regs_allocated == REGS_UNALLOCATED)
+               { /* No.  So allocate them with malloc.  We need one
+                    extra element beyond `num_regs' for the `-1' marker
+                    GNU code uses.  */
+                 regs->num_regs = MAX (RE_NREGS, num_regs + 1);
+                 regs->start = TALLOC (regs->num_regs, regoff_t);
+                 regs->end = TALLOC (regs->num_regs, regoff_t);
+                 if (regs->start == NULL || regs->end == NULL)
+                   return -2;
+                 bufp->regs_allocated = REGS_REALLOCATE;
+               }
+             else if (bufp->regs_allocated == REGS_REALLOCATE)
+               { /* Yes.  If we need more elements than were already
+                    allocated, reallocate them.  If we need fewer, just
+                    leave it alone.  */
+                 if (regs->num_regs < num_regs + 1)
+                   {
+                     regs->num_regs = num_regs + 1;
+                     RETALLOC (regs->start, regs->num_regs, regoff_t);
+                     RETALLOC (regs->end, regs->num_regs, regoff_t);
+                     if (regs->start == NULL || regs->end == NULL)
+                       return -2;
+                   }
+               }
+             else
+               assert (bufp->regs_allocated == REGS_FIXED);
+
+             /* Convert the pointer data in `regstart' and `regend' to
+                indices.  Register zero has to be set differently,
+                since we haven't kept track of any info for it.  */
+             if (regs->num_regs > 0)
+               {
+                 regs->start[0] = pos;
+                 regs->end[0] = (MATCHING_IN_FIRST_STRING ? d - string1
+                                 : d - string2 + size1);
+               }
+
+             /* Go through the first `min (num_regs, regs->num_regs)'
+                registers, since that is all we initialized.  */
+             for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++)
+               {
+                 if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt]))
+                   regs->start[mcnt] = regs->end[mcnt] = -1;
+                 else
+                   {
+                     regs->start[mcnt] = POINTER_TO_OFFSET (regstart[mcnt]);
+                     regs->end[mcnt] = POINTER_TO_OFFSET (regend[mcnt]);
+                   }
+               }
+
+             /* If the regs structure we return has more elements than
+                were in the pattern, set the extra elements to -1.  If
+                we (re)allocated the registers, this is the case,
+                because we always allocate enough to have at least one
+                -1 at the end.  */
+             for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++)
+               regs->start[mcnt] = regs->end[mcnt] = -1;
+           } /* regs && !bufp->no_sub */
+
+         FREE_VARIABLES ();
+         DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
+                       nfailure_points_pushed, nfailure_points_popped,
+                       nfailure_points_pushed - nfailure_points_popped);
+         DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
+
+         mcnt = d - pos - (MATCHING_IN_FIRST_STRING
+                           ? string1
+                           : string2 - size1);
+
+         DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
+
+         return mcnt;
+       }
+
+      /* Otherwise match next pattern command.  */
+#ifdef SWITCH_ENUM_BUG
+      switch ((int) ((re_opcode_t) *p++))
+#else
+      switch ((re_opcode_t) *p++)
+#endif
+       {
+       /* Ignore these.  Used to ignore the n of succeed_n's which
+          currently have n == 0.  */
+       case no_op:
+         DEBUG_PRINT1 ("EXECUTING no_op.\n");
+         break;
+
+
+       /* Match the next n pattern characters exactly.  The following
+          byte in the pattern defines n, and the n bytes after that
+          are the characters to match.  */
+       case exactn:
+         mcnt = *p++;
+         DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt);
+
+         /* This is written out as an if-else so we don't waste time
+            testing `translate' inside the loop.  */
+         if (translate)
+           {
+             do
+               {
+                 PREFETCH ();
+                 if (translate[(unsigned char) *d++] != (char) *p++)
+                   goto fail;
+               }
+             while (--mcnt);
+           }
+         else
+           {
+             do
+               {
+                 PREFETCH ();
+                 if (*d++ != (char) *p++) goto fail;
+               }
+             while (--mcnt);
+           }
+         SET_REGS_MATCHED ();
+         break;
+
+
+       /* Match any character except possibly a newline or a null.  */
+       case anychar:
+         DEBUG_PRINT1 ("EXECUTING anychar.\n");
+
+         PREFETCH ();
+
+         if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n')
+             || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000'))
+           goto fail;
+
+         SET_REGS_MATCHED ();
+         DEBUG_PRINT2 ("  Matched `%d'.\n", *d);
+         d++;
+         break;
+
+
+       case charset:
+       case charset_not:
+         {
+           register unsigned char c;
+           boolean not = (re_opcode_t) *(p - 1) == charset_not;
+
+           DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : "");
+
+           PREFETCH ();
+           c = TRANSLATE (*d); /* The character to match.  */
+
+           /* Cast to `unsigned' instead of `unsigned char' in case the
+              bit list is a full 32 bytes long.  */
+           if (c < (unsigned) (*p * BYTEWIDTH)
+               && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+             not = !not;
+
+           p += 1 + *p;
+
+           if (!not) goto fail;
+
+           SET_REGS_MATCHED ();
+           d++;
+           break;
+         }
+
+
+       /* The beginning of a group is represented by start_memory.
+          The arguments are the register number in the next byte, and the
+          number of groups inner to this one in the next.  The text
+          matched within the group is recorded (in the internal
+          registers data structure) under the register number.  */
+       case start_memory:
+         DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]);
+
+         /* Find out if this group can match the empty string.  */
+         p1 = p;               /* To send to group_match_null_string_p.  */
+
+         if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE)
+           REG_MATCH_NULL_STRING_P (reg_info[*p])
+             = group_match_null_string_p (&p1, pend, reg_info);
+
+         /* Save the position in the string where we were the last time
+            we were at this open-group operator in case the group is
+            operated upon by a repetition operator, e.g., with `(a*)*b'
+            against `ab'; then we want to ignore where we are now in
+            the string in case this attempt to match fails.  */
+         old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+                            ? REG_UNSET (regstart[*p]) ? d : regstart[*p]
+                            : regstart[*p];
+         DEBUG_PRINT2 ("  old_regstart: %d\n",
+                        POINTER_TO_OFFSET (old_regstart[*p]));
+
+         regstart[*p] = d;
+         DEBUG_PRINT2 ("  regstart: %d\n", POINTER_TO_OFFSET (regstart[*p]));
+
+         IS_ACTIVE (reg_info[*p]) = 1;
+         MATCHED_SOMETHING (reg_info[*p]) = 0;
+
+         /* This is the new highest active register.  */
+         highest_active_reg = *p;
+
+         /* If nothing was active before, this is the new lowest active
+            register.  */
+         if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+           lowest_active_reg = *p;
+
+         /* Move past the register number and inner group count.  */
+         p += 2;
+         break;
+
+
+       /* The stop_memory opcode represents the end of a group.  Its
+          arguments are the same as start_memory's: the register
+          number, and the number of inner groups.  */
+       case stop_memory:
+         DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]);
+
+         /* We need to save the string position the last time we were at
+            this close-group operator in case the group is operated
+            upon by a repetition operator, e.g., with `((a*)*(b*)*)*'
+            against `aba'; then we want to ignore where we are now in
+            the string in case this attempt to match fails.  */
+         old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+                          ? REG_UNSET (regend[*p]) ? d : regend[*p]
+                          : regend[*p];
+         DEBUG_PRINT2 ("      old_regend: %d\n",
+                        POINTER_TO_OFFSET (old_regend[*p]));
+
+         regend[*p] = d;
+         DEBUG_PRINT2 ("      regend: %d\n", POINTER_TO_OFFSET (regend[*p]));
+
+         /* This register isn't active anymore.  */
+         IS_ACTIVE (reg_info[*p]) = 0;
+
+         /* If this was the only register active, nothing is active
+            anymore.  */
+         if (lowest_active_reg == highest_active_reg)
+           {
+             lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+             highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+           }
+         else
+           { /* We must scan for the new highest active register, since
+                it isn't necessarily one less than now: consider
+                (a(b)c(d(e)f)g).  When group 3 ends, after the f), the
+                new highest active register is 1.  */
+             unsigned char r = *p - 1;
+             while (r > 0 && !IS_ACTIVE (reg_info[r]))
+               r--;
+
+             /* If we end up at register zero, that means that we saved
+                the registers as the result of an `on_failure_jump', not
+                a `start_memory', and we jumped to past the innermost
+                `stop_memory'.  For example, in ((.)*) we save
+                registers 1 and 2 as a result of the *, but when we pop
+                back to the second ), we are at the stop_memory 1.
+                Thus, nothing is active.  */
+             if (r == 0)
+               {
+                 lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+                 highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+               }
+             else
+               highest_active_reg = r;
+           }
+
+         /* If just failed to match something this time around with a
+            group that's operated on by a repetition operator, try to
+            force exit from the ``loop'', and restore the register
+            information for this group that we had before trying this
+            last match.  */
+         if ((!MATCHED_SOMETHING (reg_info[*p])
+              || (re_opcode_t) p[-3] == start_memory)
+             && (p + 2) < pend)
+           {
+             boolean is_a_jump_n = false;
+
+             p1 = p + 2;
+             mcnt = 0;
+             switch ((re_opcode_t) *p1++)
+               {
+                 case jump_n:
+                   is_a_jump_n = true;
+                 case pop_failure_jump:
+                 case maybe_pop_jump:
+                 case jump:
+                 case dummy_failure_jump:
+                   EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                   if (is_a_jump_n)
+                     p1 += 2;
+                   break;
+
+                 default:
+                   /* do nothing */ ;
+               }
+             p1 += mcnt;
+
+             /* If the next operation is a jump backwards in the pattern
+                to an on_failure_jump right before the start_memory
+                corresponding to this stop_memory, exit from the loop
+                by forcing a failure after pushing on the stack the
+                on_failure_jump's jump in the pattern, and d.  */
+             if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump
+                 && (re_opcode_t) p1[3] == start_memory && p1[4] == *p)
+               {
+                 /* If this group ever matched anything, then restore
+                    what its registers were before trying this last
+                    failed match, e.g., with `(a*)*b' against `ab' for
+                    regstart[1], and, e.g., with `((a*)*(b*)*)*'
+                    against `aba' for regend[3].
+
+                    Also restore the registers for inner groups for,
+                    e.g., `((a*)(b*))*' against `aba' (register 3 would
+                    otherwise get trashed).  */
+
+                 if (EVER_MATCHED_SOMETHING (reg_info[*p]))
+                   {
+                     unsigned r;
+
+                     EVER_MATCHED_SOMETHING (reg_info[*p]) = 0;
+
+                     /* Restore this and inner groups' (if any) registers.  */
+                     for (r = *p; r < *p + *(p + 1); r++)
+                       {
+                         regstart[r] = old_regstart[r];
+
+                         /* xx why this test?  */
+                         if ((int) old_regend[r] >= (int) regstart[r])
+                           regend[r] = old_regend[r];
+                       }
+                   }
+                 p1++;
+                 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                 PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
+
+                 goto fail;
+               }
+           }
+
+         /* Move past the register number and the inner group count.  */
+         p += 2;
+         break;
+
+
+       /* \<digit> has been turned into a `duplicate' command which is
+          followed by the numeric value of <digit> as the register number.  */
+       case duplicate:
+         {
+           register const char *d2, *dend2;
+           int regno = *p++;   /* Get which register to match against.  */
+           DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
+
+           /* Can't back reference a group which we've never matched.  */
+           if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno]))
+             goto fail;
+
+           /* Where in input to try to start matching.  */
+           d2 = regstart[regno];
+
+           /* Where to stop matching; if both the place to start and
+              the place to stop matching are in the same string, then
+              set to the place to stop, otherwise, for now have to use
+              the end of the first string.  */
+
+           dend2 = ((FIRST_STRING_P (regstart[regno])
+                     == FIRST_STRING_P (regend[regno]))
+                    ? regend[regno] : end_match_1);
+           for (;;)
+             {
+               /* If necessary, advance to next segment in register
+                  contents.  */
+               while (d2 == dend2)
+                 {
+                   if (dend2 == end_match_2) break;
+                   if (dend2 == regend[regno]) break;
+
+                   /* End of string1 => advance to string2. */
+                   d2 = string2;
+                   dend2 = regend[regno];
+                 }
+               /* At end of register contents => success */
+               if (d2 == dend2) break;
+
+               /* If necessary, advance to next segment in data.  */
+               PREFETCH ();
+
+               /* How many characters left in this segment to match.  */
+               mcnt = dend - d;
+
+               /* Want how many consecutive characters we can match in
+                  one shot, so, if necessary, adjust the count.  */
+               if (mcnt > dend2 - d2)
+                 mcnt = dend2 - d2;
+
+               /* Compare that many; failure if mismatch, else move
+                  past them.  */
+               if (translate
+                   ? bcmp_translate (d, d2, mcnt, translate)
+                   : bcmp (d, d2, mcnt))
+                 goto fail;
+               d += mcnt, d2 += mcnt;
+             }
+         }
+         break;
+
+
+       /* begline matches the empty string at the beginning of the string
+          (unless `not_bol' is set in `bufp'), and, if
+          `newline_anchor' is set, after newlines.  */
+       case begline:
+         DEBUG_PRINT1 ("EXECUTING begline.\n");
+
+         if (AT_STRINGS_BEG (d))
+           {
+             if (!bufp->not_bol) break;
+           }
+         else if (d[-1] == '\n' && bufp->newline_anchor)
+           {
+             break;
+           }
+         /* In all other cases, we fail.  */
+         goto fail;
+
+
+       /* endline is the dual of begline.  */
+       case endline:
+         DEBUG_PRINT1 ("EXECUTING endline.\n");
+
+         if (AT_STRINGS_END (d))
+           {
+             if (!bufp->not_eol) break;
+           }
+
+         /* We have to ``prefetch'' the next character.  */
+         else if ((d == end1 ? *string2 : *d) == '\n'
+                  && bufp->newline_anchor)
+           {
+             break;
+           }
+         goto fail;
+
+
+       /* Match at the very beginning of the data.  */
+       case begbuf:
+         DEBUG_PRINT1 ("EXECUTING begbuf.\n");
+         if (AT_STRINGS_BEG (d))
+           break;
+         goto fail;
+
+
+       /* Match at the very end of the data.  */
+       case endbuf:
+         DEBUG_PRINT1 ("EXECUTING endbuf.\n");
+         if (AT_STRINGS_END (d))
+           break;
+         goto fail;
+
+
+       /* on_failure_keep_string_jump is used to optimize `.*\n'.  It
+          pushes NULL as the value for the string on the stack.  Then
+          `pop_failure_point' will keep the current value for the
+          string, instead of restoring it.  To see why, consider
+          matching `foo\nbar' against `.*\n'.  The .* matches the foo;
+          then the . fails against the \n.  But the next thing we want
+          to do is match the \n against the \n; if we restored the
+          string value, we would be back at the foo.
+
+          Because this is used only in specific cases, we don't need to
+          check all the things that `on_failure_jump' does, to make
+          sure the right things get saved on the stack.  Hence we don't
+          share its code.  The only reason to push anything on the
+          stack at all is that otherwise we would have to change
+          `anychar's code to do something besides goto fail in this
+          case; that seems worse than this.  */
+       case on_failure_keep_string_jump:
+         DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump");
+
+         EXTRACT_NUMBER_AND_INCR (mcnt, p);
+         DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt);
+
+         PUSH_FAILURE_POINT (p + mcnt, NULL, -2);
+         break;
+
+
+       /* Uses of on_failure_jump:
+
+          Each alternative starts with an on_failure_jump that points
+          to the beginning of the next alternative.  Each alternative
+          except the last ends with a jump that in effect jumps past
+          the rest of the alternatives.  (They really jump to the
+          ending jump of the following alternative, because tensioning
+          these jumps is a hassle.)
+
+          Repeats start with an on_failure_jump that points past both
+          the repetition text and either the following jump or
+          pop_failure_jump back to this on_failure_jump.  */
+       case on_failure_jump:
+       on_failure:
+         DEBUG_PRINT1 ("EXECUTING on_failure_jump");
+
+         EXTRACT_NUMBER_AND_INCR (mcnt, p);
+         DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt);
+
+         /* If this on_failure_jump comes right before a group (i.e.,
+            the original * applied to a group), save the information
+            for that group and all inner ones, so that if we fail back
+            to this point, the group's information will be correct.
+            For example, in \(a*\)*\1, we need the preceding group,
+            and in \(\(a*\)b*\)\2, we need the inner group.  */
+
+         /* We can't use `p' to check ahead because we push
+            a failure point to `p + mcnt' after we do this.  */
+         p1 = p;
+
+         /* We need to skip no_op's before we look for the
+            start_memory in case this on_failure_jump is happening as
+            the result of a completed succeed_n, as in \(a\)\{1,3\}b\1
+            against aba.  */
+         while (p1 < pend && (re_opcode_t) *p1 == no_op)
+           p1++;
+
+         if (p1 < pend && (re_opcode_t) *p1 == start_memory)
+           {
+             /* We have a new highest active register now.  This will
+                get reset at the start_memory we are about to get to,
+                but we will have saved all the registers relevant to
+                this repetition op, as described above.  */
+             highest_active_reg = *(p1 + 1) + *(p1 + 2);
+             if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+               lowest_active_reg = *(p1 + 1);
+           }
+
+         DEBUG_PRINT1 (":\n");
+         PUSH_FAILURE_POINT (p + mcnt, d, -2);
+         break;
+
+
+       /* A smart repeat ends with `maybe_pop_jump'.
+          We change it to either `pop_failure_jump' or `jump'.  */
+       case maybe_pop_jump:
+         EXTRACT_NUMBER_AND_INCR (mcnt, p);
+         DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt);
+         {
+           register unsigned char *p2 = p;
+
+           /* Compare the beginning of the repeat with what in the
+              pattern follows its end. If we can establish that there
+              is nothing that they would both match, i.e., that we
+              would have to backtrack because of (as in, e.g., `a*a')
+              then we can change to pop_failure_jump, because we'll
+              never have to backtrack.
+
+              This is not true in the case of alternatives: in
+              `(a|ab)*' we do need to backtrack to the `ab' alternative
+              (e.g., if the string was `ab').  But instead of trying to
+              detect that here, the alternative has put on a dummy
+              failure point which is what we will end up popping.  */
+
+           /* Skip over open/close-group commands.  */
+           while (p2 + 2 < pend
+                  && ((re_opcode_t) *p2 == stop_memory
+                      || (re_opcode_t) *p2 == start_memory))
+             p2 += 3;                  /* Skip over args, too.  */
+
+           /* If we're at the end of the pattern, we can change.  */
+           if (p2 == pend)
+             {
+               /* Consider what happens when matching ":\(.*\)"
+                  against ":/".  I don't really understand this code
+                  yet.  */
+               p[-3] = (unsigned char) pop_failure_jump;
+               DEBUG_PRINT1
+                 ("  End of pattern: change to `pop_failure_jump'.\n");
+             }
+
+           else if ((re_opcode_t) *p2 == exactn
+                    || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
+             {
+               register unsigned char c
+                 = *p2 == (unsigned char) endline ? '\n' : p2[2];
+               p1 = p + mcnt;
+
+               /* p1[0] ... p1[2] are the `on_failure_jump' corresponding
+                  to the `maybe_finalize_jump' of this case.  Examine what
+                  follows.  */
+               if ((re_opcode_t) p1[3] == exactn && p1[5] != c)
+                 {
+                   p[-3] = (unsigned char) pop_failure_jump;
+                   DEBUG_PRINT3 ("  %c != %c => pop_failure_jump.\n",
+                                 c, p1[5]);
+                 }
+
+               else if ((re_opcode_t) p1[3] == charset
+                        || (re_opcode_t) p1[3] == charset_not)
+                 {
+                   int not = (re_opcode_t) p1[3] == charset_not;
+
+                   if (c < (unsigned char) (p1[4] * BYTEWIDTH)
+                       && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+                     not = !not;
+
+                   /* `not' is equal to 1 if c would match, which means
+                       that we can't change to pop_failure_jump.  */
+                   if (!not)
+                     {
+                       p[-3] = (unsigned char) pop_failure_jump;
+                       DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
+                     }
+                 }
+             }
+         }
+         p -= 2;               /* Point at relative address again.  */
+         if ((re_opcode_t) p[-1] != pop_failure_jump)
+           {
+             p[-1] = (unsigned char) jump;
+             DEBUG_PRINT1 ("  Match => jump.\n");
+             goto unconditional_jump;
+           }
+       /* Note fall through.  */
+
+
+       /* The end of a simple repeat has a pop_failure_jump back to
+          its matching on_failure_jump, where the latter will push a
+          failure point.  The pop_failure_jump takes off failure
+          points put on by this pop_failure_jump's matching
+          on_failure_jump; we got through the pattern to here from the
+          matching on_failure_jump, so didn't fail.  */
+       case pop_failure_jump:
+         {
+           /* We need to pass separate storage for the lowest and
+              highest registers, even though we don't care about the
+              actual values.  Otherwise, we will restore only one
+              register from the stack, since lowest will == highest in
+              `pop_failure_point'.  */
+           unsigned dummy_low_reg, dummy_high_reg;
+           unsigned char *pdummy;
+           const char *sdummy;
+
+           DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
+           POP_FAILURE_POINT (sdummy, pdummy,
+                              dummy_low_reg, dummy_high_reg,
+                              reg_dummy, reg_dummy, reg_info_dummy);
+         }
+         /* Note fall through.  */
+
+
+       /* Unconditionally jump (without popping any failure points).  */
+       case jump:
+       unconditional_jump:
+         EXTRACT_NUMBER_AND_INCR (mcnt, p);    /* Get the amount to jump.  */
+         DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
+         p += mcnt;                            /* Do the jump.  */
+         DEBUG_PRINT2 ("(to 0x%x).\n", p);
+         break;
+
+
+       /* We need this opcode so we can detect where alternatives end
+          in `group_match_null_string_p' et al.  */
+       case jump_past_alt:
+         DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n");
+         goto unconditional_jump;
+
+
+       /* Normally, the on_failure_jump pushes a failure point, which
+          then gets popped at pop_failure_jump.  We will end up at
+          pop_failure_jump, also, and with a pattern of, say, `a+', we
+          are skipping over the on_failure_jump, so we have to push
+          something meaningless for pop_failure_jump to pop.  */
+       case dummy_failure_jump:
+         DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n");
+         /* It doesn't matter what we push for the string here.  What
+            the code at `fail' tests is the value for the pattern.  */
+         PUSH_FAILURE_POINT (0, 0, -2);
+         goto unconditional_jump;
+
+
+       /* At the end of an alternative, we need to push a dummy failure
+          point in case we are followed by a `pop_failure_jump', because
+          we don't want the failure point for the alternative to be
+          popped.  For example, matching `(a|ab)*' against `aab'
+          requires that we match the `ab' alternative.  */
+       case push_dummy_failure:
+         DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n");
+         /* See comments just above at `dummy_failure_jump' about the
+            two zeroes.  */
+         PUSH_FAILURE_POINT (0, 0, -2);
+         break;
+
+       /* Have to succeed matching what follows at least n times.
+          After that, handle like `on_failure_jump'.  */
+       case succeed_n:
+         EXTRACT_NUMBER (mcnt, p + 2);
+         DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
+
+         assert (mcnt >= 0);
+         /* Originally, this is how many times we HAVE to succeed.  */
+         if (mcnt > 0)
+           {
+              mcnt--;
+              p += 2;
+              STORE_NUMBER_AND_INCR (p, mcnt);
+              DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p, mcnt);
+           }
+         else if (mcnt == 0)
+           {
+             DEBUG_PRINT2 ("  Setting two bytes from 0x%x to no_op.\n", p+2);
+             p[2] = (unsigned char) no_op;
+             p[3] = (unsigned char) no_op;
+             goto on_failure;
+           }
+         break;
+
+       case jump_n:
+         EXTRACT_NUMBER (mcnt, p + 2);
+         DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt);
+
+         /* Originally, this is how many times we CAN jump.  */
+         if (mcnt)
+           {
+              mcnt--;
+              STORE_NUMBER (p + 2, mcnt);
+              goto unconditional_jump;
+           }
+         /* If don't have to jump any more, skip over the rest of command.  */
+         else
+           p += 4;
+         break;
+
+       case set_number_at:
+         {
+           DEBUG_PRINT1 ("EXECUTING set_number_at.\n");
+
+           EXTRACT_NUMBER_AND_INCR (mcnt, p);
+           p1 = p + mcnt;
+           EXTRACT_NUMBER_AND_INCR (mcnt, p);
+           DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p1, mcnt);
+           STORE_NUMBER (p1, mcnt);
+           break;
+         }
+
+       case wordbound:
+         DEBUG_PRINT1 ("EXECUTING wordbound.\n");
+         if (AT_WORD_BOUNDARY (d))
+           break;
+         goto fail;
+
+       case notwordbound:
+         DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
+         if (AT_WORD_BOUNDARY (d))
+           goto fail;
+         break;
+
+       case wordbeg:
+         DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
+         if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
+           break;
+         goto fail;
+
+       case wordend:
+         DEBUG_PRINT1 ("EXECUTING wordend.\n");
+         if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
+             && (!WORDCHAR_P (d) || AT_STRINGS_END (d)))
+           break;
+         goto fail;
+
+#ifdef emacs
+#ifdef emacs19
+       case before_dot:
+         DEBUG_PRINT1 ("EXECUTING before_dot.\n");
+         if (PTR_CHAR_POS ((unsigned char *) d) >= point)
+           goto fail;
+         break;
+
+       case at_dot:
+         DEBUG_PRINT1 ("EXECUTING at_dot.\n");
+         if (PTR_CHAR_POS ((unsigned char *) d) != point)
+           goto fail;
+         break;
+
+       case after_dot:
+         DEBUG_PRINT1 ("EXECUTING after_dot.\n");
+         if (PTR_CHAR_POS ((unsigned char *) d) <= point)
+           goto fail;
+         break;
+#else /* not emacs19 */
+       case at_dot:
+         DEBUG_PRINT1 ("EXECUTING at_dot.\n");
+         if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point)
+           goto fail;
+         break;
+#endif /* not emacs19 */
+
+       case syntaxspec:
+         DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
+         mcnt = *p++;
+         goto matchsyntax;
+
+       case wordchar:
+         DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
+         mcnt = (int) Sword;
+       matchsyntax:
+         PREFETCH ();
+         if (SYNTAX (*d++) != (enum syntaxcode) mcnt)
+           goto fail;
+         SET_REGS_MATCHED ();
+         break;
+
+       case notsyntaxspec:
+         DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt);
+         mcnt = *p++;
+         goto matchnotsyntax;
+
+       case notwordchar:
+         DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n");
+         mcnt = (int) Sword;
+       matchnotsyntax:
+         PREFETCH ();
+         if (SYNTAX (*d++) == (enum syntaxcode) mcnt)
+           goto fail;
+         SET_REGS_MATCHED ();
+         break;
+
+#else /* not emacs */
+       case wordchar:
+         DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
+         PREFETCH ();
+         if (!WORDCHAR_P (d))
+           goto fail;
+         SET_REGS_MATCHED ();
+         d++;
+         break;
+
+       case notwordchar:
+         DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
+         PREFETCH ();
+         if (WORDCHAR_P (d))
+           goto fail;
+         SET_REGS_MATCHED ();
+         d++;
+         break;
+#endif /* not emacs */
+
+       default:
+         abort ();
+       }
+      continue;  /* Successfully executed one pattern command; keep going.  */
+
+
+    /* We goto here if a matching operation fails. */
+    fail:
+      if (!FAIL_STACK_EMPTY ())
+       { /* A restart point is known.  Restore to that state.  */
+         DEBUG_PRINT1 ("\nFAIL:\n");
+         POP_FAILURE_POINT (d, p,
+                            lowest_active_reg, highest_active_reg,
+                            regstart, regend, reg_info);
+
+         /* If this failure point is a dummy, try the next one.  */
+         if (!p)
+           goto fail;
+
+         /* If we failed to the end of the pattern, don't examine *p.  */
+         assert (p <= pend);
+         if (p < pend)
+           {
+             boolean is_a_jump_n = false;
+
+             /* If failed to a backwards jump that's part of a repetition
+                loop, need to pop this failure point and use the next one.  */
+             switch ((re_opcode_t) *p)
+               {
+               case jump_n:
+                 is_a_jump_n = true;
+               case maybe_pop_jump:
+               case pop_failure_jump:
+               case jump:
+                 p1 = p + 1;
+                 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                 p1 += mcnt;
+
+                 if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n)
+                     || (!is_a_jump_n
+                         && (re_opcode_t) *p1 == on_failure_jump))
+                   goto fail;
+                 break;
+               default:
+                 /* do nothing */ ;
+               }
+           }
+
+         if (d >= string1 && d <= end1)
+           dend = end_match_1;
+       }
+      else
+       break;   /* Matching at this starting point really fails.  */
+    } /* for (;;) */
+
+  if (best_regs_set)
+    goto restore_best_regs;
+
+  FREE_VARIABLES ();
+
+  return -1;                           /* Failure to match.  */
+} /* re_match_2 */
+\f
+/* Subroutine definitions for re_match_2.  */
+
+
+/* We are passed P pointing to a register number after a start_memory.
+
+   Return true if the pattern up to the corresponding stop_memory can
+   match the empty string, and false otherwise.
+
+   If we find the matching stop_memory, sets P to point to one past its number.
+   Otherwise, sets P to an undefined byte less than or equal to END.
+
+   We don't handle duplicates properly (yet).  */
+
+static boolean
+group_match_null_string_p (p, end, reg_info)
+    unsigned char **p, *end;
+    register_info_type *reg_info;
+{
+  int mcnt;
+  /* Point to after the args to the start_memory.  */
+  unsigned char *p1 = *p + 2;
+
+  while (p1 < end)
+    {
+      /* Skip over opcodes that can match nothing, and return true or
+        false, as appropriate, when we get to one that can't, or to the
+        matching stop_memory.  */
+
+      switch ((re_opcode_t) *p1)
+       {
+       /* Could be either a loop or a series of alternatives.  */
+       case on_failure_jump:
+         p1++;
+         EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+
+         /* If the next operation is not a jump backwards in the
+            pattern.  */
+
+         if (mcnt >= 0)
+           {
+             /* Go through the on_failure_jumps of the alternatives,
+                seeing if any of the alternatives cannot match nothing.
+                The last alternative starts with only a jump,
+                whereas the rest start with on_failure_jump and end
+                with a jump, e.g., here is the pattern for `a|b|c':
+
+                /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6
+                /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3
+                /exactn/1/c
+
+                So, we have to first go through the first (n-1)
+                alternatives and then deal with the last one separately.  */
+
+
+             /* Deal with the first (n-1) alternatives, which start
+                with an on_failure_jump (see above) that jumps to right
+                past a jump_past_alt.  */
+
+             while ((re_opcode_t) p1[mcnt-3] == jump_past_alt)
+               {
+                 /* `mcnt' holds how many bytes long the alternative
+                    is, including the ending `jump_past_alt' and
+                    its number.  */
+
+                 if (!alt_match_null_string_p (p1, p1 + mcnt - 3,
+                                                     reg_info))
+                   return false;
+
+                 /* Move to right after this alternative, including the
+                    jump_past_alt.  */
+                 p1 += mcnt;
+
+                 /* Break if it's the beginning of an n-th alternative
+                    that doesn't begin with an on_failure_jump.  */
+                 if ((re_opcode_t) *p1 != on_failure_jump)
+                   break;
+
+                 /* Still have to check that it's not an n-th
+                    alternative that starts with an on_failure_jump.  */
+                 p1++;
+                 EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+                 if ((re_opcode_t) p1[mcnt-3] != jump_past_alt)
+                   {
+                     /* Get to the beginning of the n-th alternative.  */
+                     p1 -= 3;
+                     break;
+                   }
+               }
+
+             /* Deal with the last alternative: go back and get number
+                of the `jump_past_alt' just before it.  `mcnt' contains
+                the length of the alternative.  */
+             EXTRACT_NUMBER (mcnt, p1 - 2);
+
+             if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info))
+               return false;
+
+             p1 += mcnt;       /* Get past the n-th alternative.  */
+           } /* if mcnt > 0 */
+         break;
+
+
+       case stop_memory:
+         assert (p1[1] == **p);
+         *p = p1 + 2;
+         return true;
+
+
+       default:
+         if (!common_op_match_null_string_p (&p1, end, reg_info))
+           return false;
+       }
+    } /* while p1 < end */
+
+  return false;
+} /* group_match_null_string_p */
+
+
+/* Similar to group_match_null_string_p, but doesn't deal with alternatives:
+   It expects P to be the first byte of a single alternative and END one
+   byte past the last. The alternative can contain groups.  */
+
+static boolean
+alt_match_null_string_p (p, end, reg_info)
+    unsigned char *p, *end;
+    register_info_type *reg_info;
+{
+  int mcnt;
+  unsigned char *p1 = p;
+
+  while (p1 < end)
+    {
+      /* Skip over opcodes that can match nothing, and break when we get
+        to one that can't.  */
+
+      switch ((re_opcode_t) *p1)
+       {
+       /* It's a loop.  */
+       case on_failure_jump:
+         p1++;
+         EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+         p1 += mcnt;
+         break;
+
+       default:
+         if (!common_op_match_null_string_p (&p1, end, reg_info))
+           return false;
+       }
+    }  /* while p1 < end */
+
+  return true;
+} /* alt_match_null_string_p */
+
+
+/* Deals with the ops common to group_match_null_string_p and
+   alt_match_null_string_p.
+
+   Sets P to one after the op and its arguments, if any.  */
+
+static boolean
+common_op_match_null_string_p (p, end, reg_info)
+    unsigned char **p, *end;
+    register_info_type *reg_info;
+{
+  int mcnt;
+  boolean ret;
+  int reg_no;
+  unsigned char *p1 = *p;
+
+  switch ((re_opcode_t) *p1++)
+    {
+    case no_op:
+    case begline:
+    case endline:
+    case begbuf:
+    case endbuf:
+    case wordbeg:
+    case wordend:
+    case wordbound:
+    case notwordbound:
+#ifdef emacs
+    case before_dot:
+    case at_dot:
+    case after_dot:
+#endif
+      break;
+
+    case start_memory:
+      reg_no = *p1;
+      assert (reg_no > 0 && reg_no <= MAX_REGNUM);
+      ret = group_match_null_string_p (&p1, end, reg_info);
+
+      /* Have to set this here in case we're checking a group which
+        contains a group and a back reference to it.  */
+
+      if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE)
+       REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret;
+
+      if (!ret)
+       return false;
+      break;
+
+    /* If this is an optimized succeed_n for zero times, make the jump.  */
+    case jump:
+      EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+      if (mcnt >= 0)
+       p1 += mcnt;
+      else
+       return false;
+      break;
+
+    case succeed_n:
+      /* Get to the number of times to succeed.  */
+      p1 += 2;
+      EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+
+      if (mcnt == 0)
+       {
+         p1 -= 4;
+         EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+         p1 += mcnt;
+       }
+      else
+       return false;
+      break;
+
+    case duplicate:
+      if (!REG_MATCH_NULL_STRING_P (reg_info[*p1]))
+       return false;
+      break;
+
+    case set_number_at:
+      p1 += 4;
+
+    default:
+      /* All other opcodes mean we cannot match the empty string.  */
+      return false;
+  }
+
+  *p = p1;
+  return true;
+} /* common_op_match_null_string_p */
+
+
+/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN
+   bytes; nonzero otherwise.  */
+
+static int
+bcmp_translate(
+     unsigned char *s1,
+     unsigned char *s2,
+     int len,
+     char *translate
+)
+{
+  register unsigned char *p1 = s1, *p2 = s2;
+  while (len)
+    {
+      if (translate[*p1++] != translate[*p2++]) return 1;
+      len--;
+    }
+  return 0;
+}
+\f
+/* Entry points for GNU code.  */
+
+/* re_compile_pattern is the GNU regular expression compiler: it
+   compiles PATTERN (of length SIZE) and puts the result in BUFP.
+   Returns 0 if the pattern was valid, otherwise an error string.
+
+   Assumes the `allocated' (and perhaps `buffer') and `translate' fields
+   are set in BUFP on entry.
+
+   We call regex_compile to do the actual compilation.  */
+
+const char *
+re_compile_pattern (pattern, length, bufp)
+     const char *pattern;
+     int length;
+     struct re_pattern_buffer *bufp;
+{
+  reg_errcode_t ret;
+
+  /* GNU code is written to assume at least RE_NREGS registers will be set
+     (and at least one extra will be -1).  */
+  bufp->regs_allocated = REGS_UNALLOCATED;
+
+  /* And GNU code determines whether or not to get register information
+     by passing null for the REGS argument to re_match, etc., not by
+     setting no_sub.  */
+  bufp->no_sub = 0;
+
+  /* Match anchors at newline.  */
+  bufp->newline_anchor = 1;
+
+  ret = regex_compile (pattern, length, re_syntax_options, bufp);
+
+  return re_error_msg[(int) ret];
+}
+\f
+/* Entry points compatible with 4.2 BSD regex library.  We don't define
+   them if this is an Emacs or POSIX compilation.  */
+
+#if !defined (emacs) && !defined (_POSIX_SOURCE)
+
+/* BSD has one and only one pattern buffer.  */
+static struct re_pattern_buffer re_comp_buf;
+
+char *
+re_comp (s)
+    const char *s;
+{
+  reg_errcode_t ret;
+
+  if (!s)
+    {
+      if (!re_comp_buf.buffer)
+       return "No previous regular expression";
+      return 0;
+    }
+
+  if (!re_comp_buf.buffer)
+    {
+      re_comp_buf.buffer = (unsigned char *) malloc (200);
+      if (re_comp_buf.buffer == NULL)
+       return "Memory exhausted";
+      re_comp_buf.allocated = 200;
+
+      re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH);
+      if (re_comp_buf.fastmap == NULL)
+       return "Memory exhausted";
+    }
+
+  /* Since `re_exec' always passes NULL for the `regs' argument, we
+     don't need to initialize the pattern buffer fields which affect it.  */
+
+  /* Match anchors at newlines.  */
+  re_comp_buf.newline_anchor = 1;
+
+  ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
+
+  /* Yes, we're discarding `const' here.  */
+  return (char *) re_error_msg[(int) ret];
+}
+
+
+int
+re_exec (s)
+    const char *s;
+{
+  const int len = strlen (s);
+  return
+    0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0);
+}
+#endif /* not emacs and not _POSIX_SOURCE */
+\f
+/* POSIX.2 functions.  Don't define these for Emacs.  */
+
+#ifndef emacs
+
+/* regcomp takes a regular expression as a string and compiles it.
+
+   PREG is a regex_t *.  We do not expect any fields to be initialized,
+   since POSIX says we shouldn't.  Thus, we set
+
+     `buffer' to the compiled pattern;
+     `used' to the length of the compiled pattern;
+     `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
+       REG_EXTENDED bit in CFLAGS is set; otherwise, to
+       RE_SYNTAX_POSIX_BASIC;
+     `newline_anchor' to REG_NEWLINE being set in CFLAGS;
+     `fastmap' and `fastmap_accurate' to zero;
+     `re_nsub' to the number of subexpressions in PATTERN.
+
+   PATTERN is the address of the pattern string.
+
+   CFLAGS is a series of bits which affect compilation.
+
+     If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
+     use POSIX basic syntax.
+
+     If REG_NEWLINE is set, then . and [^...] don't match newline.
+     Also, regexec will try a match beginning after every newline.
+
+     If REG_ICASE is set, then we considers upper- and lowercase
+     versions of letters to be equivalent when matching.
+
+     If REG_NOSUB is set, then when PREG is passed to regexec, that
+     routine will report only success or failure, and nothing about the
+     registers.
+
+   It returns 0 if it succeeds, nonzero if it doesn't.  (See regex.h for
+   the return codes and their meanings.)  */
+
+int
+regcomp (preg, pattern, cflags)
+    regex_t *preg;
+    const char *pattern;
+    int cflags;
+{
+  reg_errcode_t ret;
+  unsigned syntax
+    = (cflags & REG_EXTENDED) ?
+      RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
+
+  /* regex_compile will allocate the space for the compiled pattern.  */
+  preg->buffer = 0;
+  preg->allocated = 0;
+
+  /* Don't bother to use a fastmap when searching.  This simplifies the
+     REG_NEWLINE case: if we used a fastmap, we'd have to put all the
+     characters after newlines into the fastmap.  This way, we just try
+     every character.  */
+  preg->fastmap = 0;
+
+  if (cflags & REG_ICASE)
+    {
+      unsigned i;
+
+      preg->translate = (char *) malloc (CHAR_SET_SIZE);
+      if (preg->translate == NULL)
+       return (int) REG_ESPACE;
+
+      /* Map uppercase characters to corresponding lowercase ones.  */
+      for (i = 0; i < CHAR_SET_SIZE; i++)
+       preg->translate[i] = ISUPPER (i) ? tolower (i) : i;
+    }
+  else
+    preg->translate = NULL;
+
+  /* If REG_NEWLINE is set, newlines are treated differently.  */
+  if (cflags & REG_NEWLINE)
+    { /* REG_NEWLINE implies neither . nor [^...] match newline.  */
+      syntax &= ~RE_DOT_NEWLINE;
+      syntax |= RE_HAT_LISTS_NOT_NEWLINE;
+      /* It also changes the matching behavior.  */
+      preg->newline_anchor = 1;
+    }
+  else
+    preg->newline_anchor = 0;
+
+  preg->no_sub = !!(cflags & REG_NOSUB);
+
+  /* POSIX says a null character in the pattern terminates it, so we
+     can use strlen here in compiling the pattern.  */
+  ret = regex_compile (pattern, strlen (pattern), syntax, preg);
+
+  /* POSIX doesn't distinguish between an unmatched open-group and an
+     unmatched close-group: both are REG_EPAREN.  */
+  if (ret == REG_ERPAREN) ret = REG_EPAREN;
+
+  return (int) ret;
+}
+
+
+/* regexec searches for a given pattern, specified by PREG, in the
+   string STRING.
+
+   If NMATCH is zero or REG_NOSUB was set in the cflags argument to
+   `regcomp', we ignore PMATCH.  Otherwise, we assume PMATCH has at
+   least NMATCH elements, and we set them to the offsets of the
+   corresponding matched substrings.
+
+   EFLAGS specifies `execution flags' which affect matching: if
+   REG_NOTBOL is set, then ^ does not match at the beginning of the
+   string; if REG_NOTEOL is set, then $ does not match at the end.
+
+   We return 0 if we find a match and REG_NOMATCH if not.  */
+
+int
+regexec (preg, string, nmatch, pmatch, eflags)
+    const regex_t *preg;
+    const char *string;
+    size_t nmatch;
+    regmatch_t pmatch[];
+    int eflags;
+{
+  int ret;
+  struct re_registers regs;
+  regex_t private_preg;
+  int len = strlen (string);
+  boolean want_reg_info = !preg->no_sub && nmatch > 0;
+
+  private_preg = *preg;
+
+  private_preg.not_bol = !!(eflags & REG_NOTBOL);
+  private_preg.not_eol = !!(eflags & REG_NOTEOL);
+
+  /* The user has told us exactly how many registers to return
+     information about, via `nmatch'.  We have to pass that on to the
+     matching routines.  */
+  private_preg.regs_allocated = REGS_FIXED;
+
+  if (want_reg_info)
+    {
+      regs.num_regs = nmatch;
+      regs.start = TALLOC (nmatch, regoff_t);
+      regs.end = TALLOC (nmatch, regoff_t);
+      if (regs.start == NULL || regs.end == NULL)
+       return (int) REG_NOMATCH;
+    }
+
+  /* Perform the searching operation.  */
+  ret = re_search (&private_preg, string, len,
+                  /* start: */ 0, /* range: */ len,
+                  want_reg_info ? &regs : (struct re_registers *) 0);
+
+  /* Copy the register information to the POSIX structure.  */
+  if (want_reg_info)
+    {
+      if (ret >= 0)
+       {
+         unsigned r;
+
+         for (r = 0; r < nmatch; r++)
+           {
+             pmatch[r].rm_so = regs.start[r];
+             pmatch[r].rm_eo = regs.end[r];
+           }
+       }
+
+      /* If we needed the temporary register info, free the space now.  */
+      free (regs.start);
+      free (regs.end);
+    }
+
+  /* We want zero return to mean success, unlike `re_search'.  */
+  return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
+}
+
+
+/* Returns a message corresponding to an error code, ERRCODE, returned
+   from either regcomp or regexec.   We don't use PREG here.  */
+
+size_t
+regerror (errcode, preg, errbuf, errbuf_size)
+    int errcode;
+    const regex_t *preg;
+    char *errbuf;
+    size_t errbuf_size;
+{
+  const char *msg;
+  size_t msg_size;
+
+  if (errcode < 0
+      || errcode >= (sizeof (re_error_msg) / sizeof (re_error_msg[0])))
+    /* Only error codes returned by the rest of the code should be passed
+       to this routine.  If we are given anything else, or if other regex
+       code generates an invalid error code, then the program has a bug.
+       Dump core so we can fix it.  */
+    abort ();
+
+  msg = re_error_msg[errcode];
+
+  /* POSIX doesn't require that we do anything in this case, but why
+     not be nice.  */
+  if (! msg)
+    msg = "Success";
+
+  msg_size = strlen (msg) + 1; /* Includes the null.  */
+
+  if (errbuf_size != 0)
+    {
+      if (msg_size > errbuf_size)
+       {
+         strncpy (errbuf, msg, errbuf_size - 1);
+         errbuf[errbuf_size - 1] = 0;
+       }
+      else
+       strcpy (errbuf, msg);
+    }
+
+  return msg_size;
+}
+
+
+/* Free dynamically allocated space used by PREG.  */
+
+void
+regfree (preg)
+    regex_t *preg;
+{
+  if (preg->buffer != NULL)
+    free (preg->buffer);
+  preg->buffer = NULL;
+
+  preg->allocated = 0;
+  preg->used = 0;
+
+  if (preg->fastmap != NULL)
+    free (preg->fastmap);
+  preg->fastmap = NULL;
+  preg->fastmap_accurate = 0;
+
+  if (preg->translate != NULL)
+    free (preg->translate);
+  preg->translate = NULL;
+}
+
+#endif /* not emacs  */
+\f
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
diff --git a/compat/regex/regex.h b/compat/regex/regex.h
new file mode 100644 (file)
index 0000000..6eb64f1
--- /dev/null
@@ -0,0 +1,490 @@
+/* Definitions for data structures and routines for the regular
+   expression library, version 0.12.
+
+   Copyright (C) 1985, 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+#ifndef __REGEXP_LIBRARY_H__
+#define __REGEXP_LIBRARY_H__
+
+/* POSIX says that <sys/types.h> must be included (by the caller) before
+   <regex.h>.  */
+
+#ifdef VMS
+/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
+   should be there.  */
+#include <stddef.h>
+#endif
+
+
+/* The following bits are used to determine the regexp syntax we
+   recognize.  The set/not-set meanings are chosen so that Emacs syntax
+   remains the value 0.  The bits are given in alphabetical order, and
+   the definitions shifted by one from the previous bit; thus, when we
+   add or remove a bit, only one other definition need change.  */
+typedef unsigned reg_syntax_t;
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+   If set, then such a \ quotes the following character.  */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+     literals.
+   If set, then \+ and \? are operators and + and ? are literals.  */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
+
+/* If this bit is set, then character classes are supported.  They are:
+     [:alpha:], [:upper:], [:lower:],  [:digit:], [:alnum:], [:xdigit:],
+     [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
+   If not set, then character classes are not supported.  */
+#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+     expressions, of course).
+   If this bit is not set, then it depends:
+       ^  is an anchor if it is at the beginning of a regular
+          expression or after an open-group or an alternation operator;
+       $  is an anchor if it is at the end of a regular expression, or
+          before a close-group or an alternation operator.
+
+   This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+   POSIX draft 11.2 says that * etc. in leading positions is undefined.
+   We already implemented a previous draft which made those constructs
+   invalid, though, so we haven't changed the code back.  */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+     regardless of where they are in the pattern.
+   If this bit is not set, then special characters are special only in
+     some contexts; otherwise they are ordinary.  Specifically,
+     * + ? and intervals are only special when not after the beginning,
+     open-group, or alternation operator.  */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+     immediately after an alternation or begin-group operator.  */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+   If not set, then it doesn't.  */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+   If not set, then it does.  */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+   If not set, they do.  */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+     interval, depending on RE_NO_BK_BRACES.
+   If not set, \{, \}, {, and } are literals.  */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+   If not set, they are.  */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+   If not set, newline is literal.  */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+     are literals.
+  If not set, then `\{...\}' defines an interval.  */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+   If not set, \(...\) defines a group, and ( and ) are literals.  */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+   If not set, then \<digit> is a back-reference.  */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal.
+   If not set, then \| is an alternation operator, and | is literal.  */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then an ending range point collating higher
+     than the starting range point, as in [z-a], is invalid.
+   If not set, then when ending range point collates higher than the
+     starting range point, the range is ignored.  */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+   If not set, then an unmatched ) is invalid.  */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+   some interfaces).  When a regexp is compiled, the syntax used is
+   stored in the pattern buffer, so changing this does not affect
+   already-compiled regexps.  */
+extern reg_syntax_t re_syntax_options;
+\f
+/* Define combinations of the above bits for the standard possibilities.
+   (The [[[ comments delimit what gets put into the Texinfo file, so
+   don't delete them!)  */
+/* [[[begin syntaxes]]] */
+#define RE_SYNTAX_EMACS 0
+
+#define RE_SYNTAX_AWK                                                  \
+  (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL                      \
+   | RE_NO_BK_PARENS            | RE_NO_BK_REFS                                \
+   | RE_NO_BK_VBAR               | RE_NO_EMPTY_RANGES                  \
+   | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+#define RE_SYNTAX_POSIX_AWK                                            \
+  (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
+
+#define RE_SYNTAX_GREP                                                 \
+  (RE_BK_PLUS_QM              | RE_CHAR_CLASSES                                \
+   | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS                           \
+   | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP                                                        \
+  (RE_CHAR_CLASSES        | RE_CONTEXT_INDEP_ANCHORS                   \
+   | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE                   \
+   | RE_NEWLINE_ALT       | RE_NO_BK_PARENS                            \
+   | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP                                          \
+  (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
+
+/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff.  */
+#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax.  */
+#define _RE_SYNTAX_POSIX_COMMON                                                \
+  (RE_CHAR_CLASSES | RE_DOT_NEWLINE      | RE_DOT_NOT_NULL             \
+   | RE_INTERVALS  | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC                                          \
+  (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+   RE_LIMITED_OPS, i.e., \? \+ \| are not recognized.  Actually, this
+   isn't minimal, since other operators, such as \`, aren't disabled.  */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC                                  \
+  (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED                                       \
+  (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS                  \
+   | RE_CONTEXT_INDEP_OPS  | RE_NO_BK_BRACES                           \
+   | RE_NO_BK_PARENS       | RE_NO_BK_VBAR                             \
+   | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
+   replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added.  */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED                               \
+  (_RE_SYNTAX_POSIX_COMMON  | RE_CONTEXT_INDEP_ANCHORS                 \
+   | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES                          \
+   | RE_NO_BK_PARENS        | RE_NO_BK_REFS                            \
+   | RE_NO_BK_VBAR         | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+\f
+/* Maximum number of duplicates an interval can allow.  Some systems
+   (erroneously) define this in other header files, but we want our
+   value, so remove any previous define.  */
+#ifdef RE_DUP_MAX
+#undef RE_DUP_MAX
+#endif
+#define RE_DUP_MAX ((1 << 15) - 1)
+
+
+/* POSIX `cflags' bits (i.e., information for `regcomp').  */
+
+/* If this bit is set, then use extended regular expression syntax.
+   If not set, then use basic regular expression syntax.  */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+   If not set, then case is significant.  */
+#define REG_ICASE (REG_EXTENDED << 1)
+
+/* If this bit is set, then anchors do not match at newline
+     characters in the string.
+   If not set, then anchors do match at newlines.  */
+#define REG_NEWLINE (REG_ICASE << 1)
+
+/* If this bit is set, then report only success or fail in regexec.
+   If not set, then returns differ between not matching and errors.  */
+#define REG_NOSUB (REG_NEWLINE << 1)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec).  */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+     the beginning of the string (presumably because it's not the
+     beginning of a line).
+   If not set, then the beginning-of-line operator does match the
+     beginning of the string.  */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line.  */
+#define REG_NOTEOL (1 << 1)
+
+
+/* If any error codes are removed, changed, or added, update the
+   `re_error_msg' table in regex.c.  */
+typedef enum
+{
+  REG_NOERROR = 0,     /* Success.  */
+  REG_NOMATCH,         /* Didn't find a match (for regexec).  */
+
+  /* POSIX regcomp return error codes.  (In the order listed in the
+     standard.)  */
+  REG_BADPAT,          /* Invalid pattern.  */
+  REG_ECOLLATE,                /* Not implemented.  */
+  REG_ECTYPE,          /* Invalid character class name.  */
+  REG_EESCAPE,         /* Trailing backslash.  */
+  REG_ESUBREG,         /* Invalid back reference.  */
+  REG_EBRACK,          /* Unmatched left bracket.  */
+  REG_EPAREN,          /* Parenthesis imbalance.  */
+  REG_EBRACE,          /* Unmatched \{.  */
+  REG_BADBR,           /* Invalid contents of \{\}.  */
+  REG_ERANGE,          /* Invalid range end.  */
+  REG_ESPACE,          /* Ran out of memory.  */
+  REG_BADRPT,          /* No preceding re for repetition op.  */
+
+  /* Error codes we've added.  */
+  REG_EEND,            /* Premature end.  */
+  REG_ESIZE,           /* Compiled pattern bigger than 2^16 bytes.  */
+  REG_ERPAREN          /* Unmatched ) or \); not returned from regcomp.  */
+} reg_errcode_t;
+\f
+/* This data structure represents a compiled pattern.  Before calling
+   the pattern compiler, the fields `buffer', `allocated', `fastmap',
+   `translate', and `no_sub' can be set.  After the pattern has been
+   compiled, the `re_nsub' field is available.  All other fields are
+   private to the regex routines.  */
+
+struct re_pattern_buffer
+{
+/* [[[begin pattern_buffer]]] */
+       /* Space that holds the compiled pattern.  It is declared as
+         `unsigned char *' because its elements are
+          sometimes used as array indexes.  */
+  unsigned char *buffer;
+
+       /* Number of bytes to which `buffer' points.  */
+  unsigned long allocated;
+
+       /* Number of bytes actually used in `buffer'.  */
+  unsigned long used;
+
+       /* Syntax setting with which the pattern was compiled.  */
+  reg_syntax_t syntax;
+
+       /* Pointer to a fastmap, if any, otherwise zero.  re_search uses
+          the fastmap, if there is one, to skip over impossible
+          starting points for matches.  */
+  char *fastmap;
+
+       /* Either a translate table to apply to all characters before
+          comparing them, or zero for no translation.  The translation
+          is applied to a pattern when it is compiled and to a string
+          when it is matched.  */
+  char *translate;
+
+       /* Number of subexpressions found by the compiler.  */
+  size_t re_nsub;
+
+       /* Zero if this pattern cannot match the empty string, one else.
+          Well, in truth it's used only in `re_search_2', to see
+          whether or not we should use the fastmap, so we don't set
+          this absolutely perfectly; see `re_compile_fastmap' (the
+          `duplicate' case).  */
+  unsigned can_be_null : 1;
+
+       /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+            for `max (RE_NREGS, re_nsub + 1)' groups.
+          If REGS_REALLOCATE, reallocate space if necessary.
+          If REGS_FIXED, use what's there.  */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+  unsigned regs_allocated : 2;
+
+       /* Set to zero when `regex_compile' compiles a pattern; set to one
+          by `re_compile_fastmap' if it updates the fastmap.  */
+  unsigned fastmap_accurate : 1;
+
+       /* If set, `re_match_2' does not return information about
+          subexpressions.  */
+  unsigned no_sub : 1;
+
+       /* If set, a beginning-of-line anchor doesn't match at the
+          beginning of the string.  */
+  unsigned not_bol : 1;
+
+       /* Similarly for an end-of-line anchor.  */
+  unsigned not_eol : 1;
+
+       /* If true, an anchor at a newline matches.  */
+  unsigned newline_anchor : 1;
+
+/* [[[end pattern_buffer]]] */
+};
+
+typedef struct re_pattern_buffer regex_t;
+
+
+/* search.c (search_buffer) in Emacs needs this one opcode value.  It is
+   defined both in `regex.c' and here.  */
+#define RE_EXACTN_VALUE 1
+\f
+/* Type for byte offsets within the string.  POSIX mandates this.  */
+typedef int regoff_t;
+
+
+/* This is the structure we store register match data in.  See
+   regex.texinfo for a full description of what registers match.  */
+struct re_registers
+{
+  unsigned num_regs;
+  regoff_t *start;
+  regoff_t *end;
+};
+
+
+/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
+   `re_match_2' returns information about at least this many registers
+   the first time a `regs' structure is passed.  */
+#ifndef RE_NREGS
+#define RE_NREGS 30
+#endif
+
+
+/* POSIX specification for registers.  Aside from the different names than
+   `re_registers', POSIX uses an array of structures, instead of a
+   structure of arrays.  */
+typedef struct
+{
+  regoff_t rm_so;  /* Byte offset from string's start to substring's start.  */
+  regoff_t rm_eo;  /* Byte offset from string's start to substring's end.  */
+} regmatch_t;
+\f
+/* Declarations for routines.  */
+
+/* To avoid duplicating every routine declaration -- once with a
+   prototype (if we are ANSI), and once without (if we aren't) -- we
+   use the following macro to declare argument types.  This
+   unfortunately clutters up the declarations a bit, but I think it's
+   worth it.  */
+
+#if __STDC__
+
+#define _RE_ARGS(args) args
+
+#else /* not __STDC__ */
+
+#define _RE_ARGS(args) ()
+
+#endif /* not __STDC__ */
+
+/* Sets the current default syntax to SYNTAX, and return the old syntax.
+   You can also simply assign to the `re_syntax_options' variable.  */
+extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
+
+/* Compile the regular expression PATTERN, with length LENGTH
+   and syntax given by the global `re_syntax_options', into the buffer
+   BUFFER.  Return NULL if successful, and an error string if not.  */
+extern const char *re_compile_pattern
+  _RE_ARGS ((const char *pattern, int length,
+            struct re_pattern_buffer *buffer));
+
+
+/* Compile a fastmap for the compiled pattern in BUFFER; used to
+   accelerate searches.  Return 0 if successful and -2 if was an
+   internal error.  */
+extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
+
+
+/* Search in the string STRING (with length LENGTH) for the pattern
+   compiled into BUFFER.  Start searching at position START, for RANGE
+   characters.  Return the starting position of the match, -1 for no
+   match, or -2 for an internal error.  Also return register
+   information in REGS (if REGS and BUFFER->no_sub are nonzero).  */
+extern int re_search
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+           int length, int start, int range, struct re_registers *regs));
+
+
+/* Like `re_search', but search in the concatenation of STRING1 and
+   STRING2.  Also, stop searching at index START + STOP.  */
+extern int re_search_2
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+            int length1, const char *string2, int length2,
+            int start, int range, struct re_registers *regs, int stop));
+
+
+/* Like `re_search', but return how many characters in STRING the regexp
+   in BUFFER matched, starting at position START.  */
+extern int re_match
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+            int length, int start, struct re_registers *regs));
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'.  */
+extern int re_match_2
+  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+            int length1, const char *string2, int length2,
+            int start, struct re_registers *regs, int stop));
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+   ENDS.  Subsequent matches using BUFFER and REGS will use this memory
+   for recording register information.  STARTS and ENDS must be
+   allocated with malloc, and must each be at least `NUM_REGS * sizeof
+   (regoff_t)' bytes long.
+
+   If NUM_REGS == 0, then subsequent matches should allocate their own
+   register data.
+
+   Unless this function is called, the first search or match using
+   PATTERN_BUFFER will allocate its own register data, without
+   freeing the old data.  */
+extern void re_set_registers
+  _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
+            unsigned num_regs, regoff_t *starts, regoff_t *ends));
+
+/* 4.2 bsd compatibility.  */
+extern char *re_comp _RE_ARGS ((const char *));
+extern int re_exec _RE_ARGS ((const char *));
+
+/* POSIX compatibility.  */
+extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags));
+extern int regexec
+  _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch,
+            regmatch_t pmatch[], int eflags));
+extern size_t regerror
+  _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf,
+            size_t errbuf_size));
+extern void regfree _RE_ARGS ((regex_t *preg));
+
+#endif /* not __REGEXP_LIBRARY_H__ */
+\f
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
index 580966e56a3455b9970b7eef33143c1e9c57d41c..357e733074ea7c85f880fa577ad65dfb3787fec7 100644 (file)
@@ -17,6 +17,8 @@ int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap)
 
        if (maxsize > 0) {
                ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap);
+               if (ret == maxsize-1)
+                       ret = -1;
                /* Windows does not NUL-terminate if result fills buffer */
                str[maxsize-1] = 0;
        }
@@ -34,6 +36,8 @@ int git_vsnprintf(char *str, size_t maxsize, const char *format, va_list ap)
                        break;
                s = str;
                ret = vsnprintf(str, maxsize-SNPRINTF_SIZE_CORR, format, ap);
+               if (ret == maxsize-1)
+                       ret = -1;
        }
        free(s);
        return ret;
index b776149531025c85f5665d971e6e072f0cc64893..17e9861c0634133ec5e07af99191cff99f8a40ad 100644 (file)
@@ -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
index 7c2856efc92ca55e3cf03fcf1c72ffb70318f7c3..27bab00a454c1a29946bbbc0a573ae83f83ee07f 100644 (file)
@@ -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])
index 574f42fa47ffa69328217eb25afee6f85db9595e..dd96f8e0435ded892001783b69fba6a6fb3be288 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -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)
index 30d870187e64e33ed430dc1fab1ea37036a07f58..d3fb6ae5073c2b298eee37d566abf6a7cf834377 100755 (executable)
@@ -271,15 +271,17 @@ __git_merge_strategies ()
                echo "$__git_merge_strategylist"
                return
        fi
-       sed -n "/^all_strategies='/{
-               s/^all_strategies='//
-               s/'//
+       git merge -s help 2>&1 |
+       sed -n -e '/[Aa]vailable strategies are: /,/^$/{
+               s/\.$//
+               s/.*://
+               s/^[    ]*//
+               s/[     ]*$//
                p
-               q
-               }" "$(git --exec-path)/git-merge"
+       }'
 }
 __git_merge_strategylist=
-__git_merge_strategylist="$(__git_merge_strategies 2>/dev/null)"
+__git_merge_strategylist=$(__git_merge_strategies 2>/dev/null)
 
 __git_complete_file ()
 {
@@ -384,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;;
@@ -393,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;;
@@ -402,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;;
@@ -426,6 +435,7 @@ __git_porcelain_commands ()
                runstatus)        : plumbing;;
                sh-setup)         : internal;;
                shell)            : daemon;;
+               show-ref)         : plumbing;;
                send-pack)        : plumbing;;
                show-index)       : plumbing;;
                ssh-*)            : transport;;
@@ -440,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
@@ -501,7 +513,7 @@ __git_has_doubledash ()
        return 1
 }
 
-__git_whitespacelist="nowarn warn error error-all strip"
+__git_whitespacelist="nowarn warn error error-all fix"
 
 _git_am ()
 {
@@ -561,6 +573,29 @@ _git_add ()
        COMPREPLY=()
 }
 
+_git_archive ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --format=*)
+               __gitcomp "$(git archive --list)" "" "${cur##--format=}"
+               return
+               ;;
+       --remote=*)
+               __gitcomp "$(__git_remotes)" "" "${cur##--remote=}"
+               return
+               ;;
+       --*)
+               __gitcomp "
+                       --format= --list --verbose
+                       --prefix= --remote= --exec=
+                       "
+               return
+               ;;
+       esac
+       __git_complete_file
+}
+
 _git_bisect ()
 {
        __git_has_doubledash && return
@@ -667,6 +702,45 @@ _git_cherry_pick ()
        esac
 }
 
+_git_clean ()
+{
+       __git_has_doubledash && return
+
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --*)
+               __gitcomp "--dry-run --quiet"
+               return
+               ;;
+       esac
+       COMPREPLY=()
+}
+
+_git_clone ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --*)
+               __gitcomp "
+                       --local
+                       --no-hardlinks
+                       --shared
+                       --reference
+                       --quiet
+                       --no-checkout
+                       --bare
+                       --mirror
+                       --origin
+                       --upload-pack
+                       --template=
+                       --depth
+                       "
+               return
+               ;;
+       esac
+       COMPREPLY=()
+}
+
 _git_commit ()
 {
        __git_has_doubledash && return
@@ -707,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
@@ -721,11 +795,6 @@ _git_diff ()
        __git_complete_file
 }
 
-_git_diff_tree ()
-{
-       __gitcomp "$(__git_refs)"
-}
-
 _git_fetch ()
 {
        local cur="${COMP_WORDS[COMP_CWORD]}"
@@ -796,6 +865,29 @@ _git_gc ()
        COMPREPLY=()
 }
 
+_git_grep ()
+{
+       __git_has_doubledash && return
+
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --*)
+               __gitcomp "
+                       --cached
+                       --text --ignore-case --word-regexp --invert-match
+                       --full-name
+                       --extended-regexp --basic-regexp --fixed-strings
+                       --files-with-matches --name-only
+                       --files-without-match
+                       --count
+                       --and --or --not --all-match
+                       "
+               return
+               ;;
+       esac
+       COMPREPLY=()
+}
+
 _git_help ()
 {
        local cur="${COMP_WORDS[COMP_CWORD]}"
@@ -805,7 +897,49 @@ _git_help ()
                return
                ;;
        esac
-       __gitcomp "$(__git_all_commands)"
+       __gitcomp "$(__git_all_commands)
+               attributes cli core-tutorial cvs-migration
+               diffcore gitk glossary hooks ignore modules
+               repository-layout tutorial tutorial-2
+               "
+}
+
+_git_init ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --shared=*)
+               __gitcomp "
+                       false true umask group all world everybody
+                       " "" "${cur##--shared=}"
+               return
+               ;;
+       --*)
+               __gitcomp "--quiet --bare --template= --shared --shared="
+               return
+               ;;
+       esac
+       COMPREPLY=()
+}
+
+_git_ls_files ()
+{
+       __git_has_doubledash && return
+
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --*)
+               __gitcomp "--cached --deleted --modified --others --ignored
+                       --stage --directory --no-empty-directory --unmerged
+                       --killed --exclude= --exclude-from=
+                       --exclude-per-directory= --exclude-standard
+                       --error-unmatch --with-tree= --full-name
+                       --abbrev --ignored --exclude-per-directory
+                       "
+               return
+               ;;
+       esac
+       COMPREPLY=()
 }
 
 _git_ls_remote ()
@@ -853,6 +987,8 @@ _git_log ()
                        --stat --numstat --shortstat
                        --decorate --diff-filter=
                        --color-words --walk-reflogs
+                       --parents --children --full-history
+                       --merge
                        "
                return
                ;;
@@ -882,11 +1018,42 @@ _git_merge ()
        __gitcomp "$(__git_refs)"
 }
 
+_git_mergetool ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --tool=*)
+               __gitcomp "
+                       kdiff3 tkdiff meld xxdiff emerge
+                       vimdiff gvimdiff ecmerge opendiff
+                       " "" "${cur##--tool=}"
+               return
+               ;;
+       --*)
+               __gitcomp "--tool="
+               return
+               ;;
+       esac
+       COMPREPLY=()
+}
+
 _git_merge_base ()
 {
        __gitcomp "$(__git_refs)"
 }
 
+_git_mv ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --*)
+               __gitcomp "--dry-run"
+               return
+               ;;
+       esac
+       COMPREPLY=()
+}
+
 _git_name_rev ()
 {
        __gitcomp "--tags --all --stdin"
@@ -1211,6 +1378,18 @@ _git_reset ()
        __gitcomp "$(__git_refs)"
 }
 
+_git_revert ()
+{
+       local cur="${COMP_WORDS[COMP_CWORD]}"
+       case "$cur" in
+       --*)
+               __gitcomp "--edit --mainline --no-edit --no-commit --signoff"
+               return
+               ;;
+       esac
+       COMPREPLY=()
+}
+
 _git_rm ()
 {
        __git_has_doubledash && return
@@ -1283,7 +1462,7 @@ _git_show_branch ()
 
 _git_stash ()
 {
-       local subcommands='save list show apply clear drop pop create'
+       local subcommands='save list show apply clear drop pop create branch'
        local subcommand="$(__git_find_subcommand "$subcommands")"
        if [ -z "$subcommand" ]; then
                __gitcomp "$subcommands"
@@ -1293,6 +1472,16 @@ _git_stash ()
                save,--*)
                        __gitcomp "--keep-index"
                        ;;
+               apply,--*)
+                       __gitcomp "--index"
+                       ;;
+               show,--*|drop,--*|pop,--*|branch,--*)
+                       COMPREPLY=()
+                       ;;
+               show,*|apply,*|drop,*|pop,*|branch,*)
+                       __gitcomp "$(git --git-dir="$(__gitdir)" stash list \
+                                       | sed -n -e 's/:.*//p')"
+                       ;;
                *)
                        COMPREPLY=()
                        ;;
@@ -1304,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
@@ -1473,12 +1662,15 @@ _git ()
        am)          _git_am ;;
        add)         _git_add ;;
        apply)       _git_apply ;;
+       archive)     _git_archive ;;
        bisect)      _git_bisect ;;
        bundle)      _git_bundle ;;
        branch)      _git_branch ;;
        checkout)    _git_checkout ;;
        cherry)      _git_cherry ;;
        cherry-pick) _git_cherry_pick ;;
+       clean)       _git_clean ;;
+       clone)       _git_clone ;;
        commit)      _git_commit ;;
        config)      _git_config ;;
        describe)    _git_describe ;;
@@ -1486,18 +1678,24 @@ _git ()
        fetch)       _git_fetch ;;
        format-patch) _git_format_patch ;;
        gc)          _git_gc ;;
+       grep)        _git_grep ;;
        help)        _git_help ;;
+       init)        _git_init ;;
        log)         _git_log ;;
+       ls-files)    _git_ls_files ;;
        ls-remote)   _git_ls_remote ;;
        ls-tree)     _git_ls_tree ;;
        merge)       _git_merge;;
+       mergetool)   _git_mergetool;;
        merge-base)  _git_merge_base ;;
+       mv)          _git_mv ;;
        name-rev)    _git_name_rev ;;
        pull)        _git_pull ;;
        push)        _git_push ;;
        rebase)      _git_rebase ;;
        remote)      _git_remote ;;
        reset)       _git_reset ;;
+       revert)      _git_revert ;;
        rm)          _git_rm ;;
        send-email)  _git_send_email ;;
        shortlog)    _git_shortlog ;;
index 6ae0429c2dde435f8ae33991ad10f40485aefdc6..2216cacba79ad7171b7b5abbd1ff27e7b1ef84a1 100755 (executable)
@@ -16,6 +16,46 @@ from sets import Set;
 
 verbose = False
 
+
+def p4_build_cmd(cmd):
+    """Build a suitable p4 command line.
+
+    This consolidates building and returning a p4 command line into one
+    location. It means that hooking into the environment, or other configuration
+    can be done more easily.
+    """
+    real_cmd = "%s " % "p4"
+
+    user = gitConfig("git-p4.user")
+    if len(user) > 0:
+        real_cmd += "-u %s " % user
+
+    password = gitConfig("git-p4.password")
+    if len(password) > 0:
+        real_cmd += "-P %s " % password
+
+    port = gitConfig("git-p4.port")
+    if len(port) > 0:
+        real_cmd += "-p %s " % port
+
+    host = gitConfig("git-p4.host")
+    if len(host) > 0:
+        real_cmd += "-h %s " % host
+
+    client = gitConfig("git-p4.client")
+    if len(client) > 0:
+        real_cmd += "-c %s " % client
+
+    real_cmd += "%s" % (cmd)
+    if verbose:
+        print real_cmd
+    return real_cmd
+
+def chdir(dir):
+    if os.name == 'nt':
+        os.environ['PWD']=dir
+    os.chdir(dir)
+
 def die(msg):
     if verbose:
         raise Exception(msg)
@@ -34,6 +74,10 @@ def write_pipe(c, str):
 
     return val
 
+def p4_write_pipe(c, str):
+    real_cmd = p4_build_cmd(c)
+    return write_pipe(real_cmd, str)
+
 def read_pipe(c, ignore_error=False):
     if verbose:
         sys.stderr.write('Reading pipe: %s\n' % c)
@@ -45,6 +89,9 @@ def read_pipe(c, ignore_error=False):
 
     return val
 
+def p4_read_pipe(c, ignore_error=False):
+    real_cmd = p4_build_cmd(c)
+    return read_pipe(real_cmd, ignore_error)
 
 def read_pipe_lines(c):
     if verbose:
@@ -57,12 +104,22 @@ def read_pipe_lines(c):
 
     return val
 
+def p4_read_pipe_lines(c):
+    """Specifically invoke p4 on the command supplied. """
+    real_cmd = p4_build_cmd(c)
+    return read_pipe_lines(real_cmd)
+
 def system(cmd):
     if verbose:
         sys.stderr.write("executing %s\n" % cmd)
     if os.system(cmd) != 0:
         die("command failed: %s" % cmd)
 
+def p4_system(cmd):
+    """Specifically invoke p4 as the system command. """
+    real_cmd = p4_build_cmd(cmd)
+    return system(real_cmd)
+
 def isP4Exec(kind):
     """Determine if a Perforce 'kind' should have execute permission
 
@@ -84,12 +141,12 @@ def setP4ExecBit(file, mode):
         if p4Type[-1] == "+":
             p4Type = p4Type[0:-1]
 
-    system("p4 reopen -t %s %s" % (p4Type, file))
+    p4_system("reopen -t %s %s" % (p4Type, file))
 
 def getP4OpenedType(file):
     # Returns the perforce file type for the given file.
 
-    result = read_pipe("p4 opened %s" % file)
+    result = p4_read_pipe("opened %s" % file)
     match = re.match(".*\((.+)\)\r?$", result)
     if match:
         return match.group(1)
@@ -145,7 +202,7 @@ def isModeExecChanged(src_mode, dst_mode):
     return isModeExec(src_mode) != isModeExec(dst_mode)
 
 def p4CmdList(cmd, stdin=None, stdin_mode='w+b'):
-    cmd = "p4 -G %s" % cmd
+    cmd = p4_build_cmd("-G %s" % (cmd))
     if verbose:
         sys.stderr.write("Opening pipe: %s\n" % cmd)
 
@@ -364,7 +421,7 @@ def originP4BranchesExist():
 
 def p4ChangesForPaths(depotPaths, changeRange):
     assert depotPaths
-    output = read_pipe_lines("p4 changes " + ' '.join (["%s...%s" % (p, changeRange)
+    output = p4_read_pipe_lines("changes " + ' '.join (["%s...%s" % (p, changeRange)
                                                         for p in depotPaths]))
 
     changes = []
@@ -512,7 +569,7 @@ class P4Submit(Command):
         # remove lines in the Files section that show changes to files outside the depot path we're committing into
         template = ""
         inFilesSection = False
-        for line in read_pipe_lines("p4 change -o"):
+        for line in p4_read_pipe_lines("change -o"):
             if line.endswith("\r\n"):
                 line = line[:-2] + "\n"
             if inFilesSection:
@@ -547,7 +604,7 @@ class P4Submit(Command):
             modifier = diff['status']
             path = diff['src']
             if modifier == "M":
-                system("p4 edit \"%s\"" % path)
+                p4_system("edit \"%s\"" % path)
                 if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
                     filesToChangeExecBit[path] = diff['dst_mode']
                 editedFiles.add(path)
@@ -562,8 +619,8 @@ class P4Submit(Command):
                     filesToAdd.remove(path)
             elif modifier == "R":
                 src, dest = diff['src'], diff['dst']
-                system("p4 integrate -Dt \"%s\" \"%s\"" % (src, dest))
-                system("p4 edit \"%s\"" % (dest))
+                p4_system("integrate -Dt \"%s\" \"%s\"" % (src, dest))
+                p4_system("edit \"%s\"" % (dest))
                 if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
                     filesToChangeExecBit[dest] = diff['dst_mode']
                 os.unlink(dest)
@@ -587,7 +644,7 @@ class P4Submit(Command):
             if response == "s":
                 print "Skipping! Good luck with the next patches..."
                 for f in editedFiles:
-                    system("p4 revert \"%s\"" % f);
+                    p4_system("revert \"%s\"" % f);
                 for f in filesToAdd:
                     system("rm %s" %f)
                 return
@@ -610,10 +667,10 @@ class P4Submit(Command):
         system(applyPatchCmd)
 
         for f in filesToAdd:
-            system("p4 add \"%s\"" % f)
+            p4_system("add \"%s\"" % f)
         for f in filesToDelete:
-            system("p4 revert \"%s\"" % f)
-            system("p4 delete \"%s\"" % f)
+            p4_system("revert \"%s\"" % f)
+            p4_system("delete \"%s\"" % f)
 
         # Set/clear executable bits
         for f in filesToChangeExecBit.keys():
@@ -629,7 +686,7 @@ class P4Submit(Command):
             submitTemplate = self.prepareLogMessage(template, logMessage)
             if os.environ.has_key("P4DIFF"):
                 del(os.environ["P4DIFF"])
-            diff = read_pipe("p4 diff -du ...")
+            diff = p4_read_pipe("diff -du ...")
 
             newdiff = ""
             for newFile in filesToAdd:
@@ -651,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"
@@ -659,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")
 
-            write_pipe("p4 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+")
@@ -712,9 +784,9 @@ class P4Submit(Command):
         print "Perforce checkout for depot path %s located at %s" % (self.depotPath, self.clientPath)
         self.oldWorkingDirectory = os.getcwd()
 
-        os.chdir(self.clientPath)
+        chdir(self.clientPath)
         print "Syncronizing p4 checkout..."
-        system("p4 sync ...")
+        p4_system("sync ...")
 
         self.check()
 
@@ -732,7 +804,7 @@ class P4Submit(Command):
 
         if len(commits) == 0:
             print "All changes applied!"
-            os.chdir(self.oldWorkingDirectory)
+            chdir(self.oldWorkingDirectory)
 
             sync = P4Sync()
             sync.run([])
@@ -1399,7 +1471,7 @@ class P4Sync(Command):
             if not gitBranchExists(self.refPrefix + "HEAD") and self.importIntoRemotes and gitBranchExists(self.branch):
                 system("git symbolic-ref %sHEAD %s" % (self.refPrefix, self.branch))
 
-        if self.useClientSpec or gitConfig("p4.useclientspec") == "true":
+        if self.useClientSpec or gitConfig("git-p4.useclientspec") == "true":
             self.getClientSpec()
 
         # TODO: should always look at previous commits,
@@ -1670,14 +1742,18 @@ class P4Clone(P4Sync):
         print "Importing from %s into %s" % (', '.join(depotPaths), self.cloneDestination)
         if not os.path.exists(self.cloneDestination):
             os.makedirs(self.cloneDestination)
-        os.chdir(self.cloneDestination)
+        chdir(self.cloneDestination)
         system("git init")
         self.gitdir = os.getcwd() + "/.git"
         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."
@@ -1782,7 +1858,7 @@ def main():
                 if os.path.exists(cmd.gitdir):
                     cdup = read_pipe("git rev-parse --show-cdup").strip()
                     if len(cdup) > 0:
-                        os.chdir(cdup);
+                        chdir(cdup);
 
         if not isValidGitDir(cmd.gitdir):
             if isValidGitDir(cmd.gitdir + "/.git"):
index b16a8384bcfbfe33dc33e1076c64f5d36e75e803..49b335921a3871d82a2c0110170a6e66d71561ee 100644 (file)
@@ -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,43 +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
+==============
 
-A useful setup may be that you have a periodically updated git repository
-somewhere that contains a complete import of a Perforce project. That git
-repository can be used to clone the working repository from and one would
-import from Perforce directly after cloning using git-p4. If the connection to
-the Perforce server is slow and the working repository hasn't been synced for a
-while it may be desirable to fetch changes from the origin git repository using
-the efficient git protocol. git-p4 supports this setup by calling "git fetch origin"
-by default if there is an origin branch. You can disable this using
+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.
 
-  git config git-p4.syncFromOrigin false
+This behaviour can be disabled by setting the "git-p4.syncFromOrigin" git
+configuration variable to "false".
 
 Updating
 ========
@@ -91,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
 
@@ -109,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
 =======
 
@@ -140,6 +135,62 @@ Example
   git-p4 rebase
 
 
+Configuration parameters
+========================
+
+git-p4.user ($P4USER)
+
+Allows you to specify the username to use to connect to the Perforce repository.
+
+  git config [--global] git-p4.user public
+
+git-p4.password ($P4PASS)
+
+Allows you to specify the password to use to connect to the Perforce repository.
+Warning this password will be visible on the command-line invocation of the p4 binary.
+
+  git config [--global] git-p4.password public1234
+
+git-p4.port ($P4PORT)
+
+Specify the port to be used to contact the Perforce server. As this will be passed
+directly to the p4 binary, it may be in the format host:port as well.
+
+  git config [--global] git-p4.port codes.zimbra.com:2666
+
+git-p4.host ($P4HOST)
+
+Specify the host to contact for a Perforce repository.
+
+  git config [--global] git-p4.host perforce.example.com
+
+git-p4.client ($P4CLIENT)
+
+Specify the client name to use
+
+  git config [--global] git-p4.client public-view
+
+git-p4.allowSubmit
+
+  git config [--global] git-p4.allowSubmit false
+
+git-p4.syncFromOrigin
+
+A useful setup may be that you have a periodically updated git repository
+somewhere that contains a complete import of a Perforce project. That git
+repository can be used to clone the working repository from and one would
+import from Perforce directly after cloning using git-p4. If the connection to
+the Perforce server is slow and the working repository hasn't been synced for a
+while it may be desirable to fetch changes from the origin git repository using
+the efficient git protocol. git-p4 supports this setup by calling "git fetch origin"
+by default if there is an origin branch. You can disable this using:
+
+  git config [--global] git-p4.syncFromOrigin false
+
+git-p4.useclientspec
+
+  git config [--global] git-p4.useclientspec false
+
 Implementation Details...
 =========================
 
index ace64f165e4a01fb99892e9b89e7df791a7f4ca1..28389541a32454f2d988bb02e4268ffe12755bbc 100644 (file)
@@ -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);
diff --git a/ctype.c b/ctype.c
index ee06eb7f48f1d3e818b3037369b4e056fe7e5be7..9208d674dbc081878532f08d2eddfc66c6a2e327 100644 (file)
--- a/ctype.c
+++ b/ctype.c
@@ -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 */
index 4540e8df5ab8bc8ff66549144d7db2928e12199b..0e026f65ecc089c869979069b33aabc1008d3f68 100644 (file)
--- a/daemon.c
+++ b/daemon.c
 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)
-{
-       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)
+static void kill_some_child(void)
 {
-       unsigned spawned, reaped, deleted;
-
-       spawned = children_spawned;
-       reaped = children_reaped;
-       deleted = children_deleted;
-
-       while (deleted < reaped) {
-               pid_t pid = dead_child[deleted % MAX_CHILDREN];
-               const char *dead = pid < 0 ? " (with error)" : "";
+       const struct child *blanket, *next;
 
-               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,12 @@ 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);
 }
 
 static int set_reuse_addr(int sockfd)
@@ -835,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;
                }
@@ -935,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) {
@@ -1021,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));
 }
 
@@ -1054,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];
 
@@ -1104,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;
@@ -1177,9 +1080,11 @@ 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
+               /* avoid splitting a message in the middle */
+               setvbuf(stderr, NULL, _IOLBF, 0);
 
        if (inetd_mode && (group_name || user_name))
                die("--user and --group are incompatible with --inetd");
@@ -1232,8 +1137,10 @@ int main(int argc, char **argv)
                return execute(peer);
        }
 
-       if (detach)
+       if (detach) {
                daemonize();
+               loginfo("Ready to rumble");
+       }
        else
                sanitize_stdfds();
 
index d9668d2ef94c73e4a7a5602011ff13a9fd9d8c6a..82d9e221eabab53acc418d0db6327e480836a5ed 100644 (file)
@@ -6,13 +6,13 @@
 #include "object.h"
 #include "decorate.h"
 
-static unsigned int hash_obj(struct object *obj, unsigned int n)
+static unsigned int hash_obj(const struct object *obj, unsigned int n)
 {
        unsigned int hash = *(unsigned int *)obj->sha1;
        return hash % n;
 }
 
-static void *insert_decoration(struct decoration *n, struct object *base, void *decoration)
+static void *insert_decoration(struct decoration *n, const struct object *base, void *decoration)
 {
        int size = n->size;
        struct object_decoration *hash = n->hash;
@@ -44,7 +44,7 @@ static void grow_decoration(struct decoration *n)
        n->nr = 0;
 
        for (i = 0; i < old_size; i++) {
-               struct object *base = old_hash[i].base;
+               const struct object *base = old_hash[i].base;
                void *decoration = old_hash[i].decoration;
 
                if (!base)
@@ -55,7 +55,8 @@ static void grow_decoration(struct decoration *n)
 }
 
 /* Add a decoration pointer, return any old one */
-void *add_decoration(struct decoration *n, struct object *obj, void *decoration)
+void *add_decoration(struct decoration *n, const struct object *obj,
+               void *decoration)
 {
        int nr = n->nr + 1;
 
@@ -65,7 +66,7 @@ void *add_decoration(struct decoration *n, struct object *obj, void *decoration)
 }
 
 /* Lookup a decoration pointer */
-void *lookup_decoration(struct decoration *n, struct object *obj)
+void *lookup_decoration(struct decoration *n, const struct object *obj)
 {
        int j;
 
index 1fa4ad9beb08f23888814b99183487ab85378bfd..e7328044ff84a4acaaa7f5f4bc5f85375dc7a07a 100644 (file)
@@ -2,7 +2,7 @@
 #define DECORATE_H
 
 struct object_decoration {
-       struct object *base;
+       const struct object *base;
        void *decoration;
 };
 
@@ -12,7 +12,7 @@ struct decoration {
        struct object_decoration *hash;
 };
 
-extern void *add_decoration(struct decoration *n, struct object *obj, void *decoration);
-extern void *lookup_decoration(struct decoration *n, struct object *obj);
+extern void *add_decoration(struct decoration *n, const struct object *obj, void *decoration);
+extern void *lookup_decoration(struct decoration *n, const struct object *obj);
 
 #endif
diff --git a/diff.c b/diff.c
index cbf25473c594abfd1fc13473108dc9c15e2f1d15..998dcaa5edd25d35047749fd6892beb1e829a08b 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -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;
@@ -131,10 +132,6 @@ static int parse_funcname_pattern(const char *var, const char *ep, const char *v
  */
 int git_diff_ui_config(const char *var, const char *value, void *cb)
 {
-       if (!strcmp(var, "diff.renamelimit")) {
-               diff_rename_limit_default = git_config_int(var, value);
-               return 0;
-       }
        if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) {
                diff_use_color_default = git_config_colorbool(var, value, -1);
                return 0;
@@ -167,6 +164,11 @@ int git_diff_ui_config(const char *var, const char *value, void *cb)
 
 int git_diff_basic_config(const char *var, const char *value, void *cb)
 {
+       if (!strcmp(var, "diff.renamelimit")) {
+               diff_rename_limit_default = git_config_int(var, value);
+               return 0;
+       }
+
        if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
                int slot = parse_diff_color_slot(var, 11);
                if (!value)
@@ -175,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) {
@@ -368,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;
 };
@@ -458,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;
@@ -476,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;
@@ -510,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);
 }
@@ -579,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.
         */
@@ -707,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 {
@@ -1053,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;
@@ -1064,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++) {
@@ -1112,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);
 }
 
@@ -1130,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;
@@ -1375,12 +1396,23 @@ 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"
                        "^[     ]*\\(\\([       ]*"
                        "[A-Za-z_][A-Za-z_0-9]*\\)\\{2,\\}"
                        "[      ]*([^;]*\\)$" },
-       { "tex", "^\\(\\\\\\(sub\\)*section{.*\\)$" },
+       { "pascal", "^\\(\\(procedure\\|function\\|constructor\\|"
+                       "destructor\\|interface\\|implementation\\|"
+                       "initialization\\|finalization\\)[ \t]*.*\\)$"
+                       "\\|"
+                       "^\\(.*=[ \t]*\\(class\\|record\\).*\\)$"
+                       },
+       { "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)
@@ -1512,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);
        }
@@ -1571,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:
@@ -1594,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;
@@ -1618,12 +1646,13 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
                xdemitcb_t ecb;
 
                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.trailing_blanks_start) {
+               if ((data.ws_rule & WS_TRAILING_SPACE) &&
+                   data.trailing_blanks_start) {
                        fprintf(o->file, "%s:%d: ends with blank lines.\n",
                                data.filename, data.trailing_blanks_start);
                        data.status = 1; /* report errors */
@@ -2279,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;
@@ -2373,13 +2403,6 @@ int diff_setup_done(struct diff_options *options)
                DIFF_OPT_SET(options, EXIT_WITH_STATUS);
        }
 
-       /*
-        * If we postprocess in diffcore, we cannot simply return
-        * upon the first hit.  We need to run diff as usual.
-        */
-       if (options->pickaxe || options->filter)
-               DIFF_OPT_CLR(options, QUIET);
-
        return 0;
 }
 
@@ -2451,8 +2474,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"))
@@ -3008,7 +3033,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;
 };
@@ -3053,7 +3077,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;
@@ -3118,9 +3141,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);
@@ -3197,7 +3219,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))
@@ -3369,10 +3390,7 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
 
 void diffcore_std(struct diff_options *options)
 {
-       if (DIFF_OPT_TST(options, QUIET))
-               return;
-
-       if (options->skip_stat_unmatch && !DIFF_OPT_TST(options, FIND_COPIES_HARDER))
+       if (options->skip_stat_unmatch)
                diffcore_skip_stat_unmatch(options);
        if (options->break_opt != -1)
                diffcore_break(options->break_opt);
diff --git a/diff.h b/diff.h
index 50fb5ddb0bec02b0cd5498d6ecc37d44bf874476..7f53bebf335148a5f623b5fcbe6142e6c4b53282 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -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)
diff --git a/dir.c b/dir.c
index 29d1d5ba31def46ba8b55905dc60773cc6cc167e..acf1001c4f9dd51587e3b07e52d4101ff3f1cb66 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -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 == '?';
-}
-
 /*
  * 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);
diff --git a/entry.c b/entry.c
index 222aaa374b8268828e9d529a8afacb8830acc281..aa2ee46a84033585d8e07a585610c5a697af82c2 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -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) {
index 7089e6f9e6c5fa9142f468e54afe7d33a6d2eec7..ccdf2e57b0cf1846996bcda8e89d7d8575a031f6 100644 (file)
@@ -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());
 
index 8f91a97eb3a07908b35de086d555822c928fd2e9..aa602618e6caedbfdd2d54ad4bb8375356cc55f6 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -10,7 +10,7 @@ git am [options] (--resolved | --skip | --abort)
 --
 d,dotest=       (removed -- do not use)
 i,interactive   run interactively
-b,binary        pass --allow-binary-replacement to git-apply
+b,binary        (historical option -- no-op)
 3,3way          allow fall back on 3way merging if needed
 s,signoff       add a Signed-off-by line to the commit message
 u,utf8          recode into utf8 (default)
@@ -87,7 +87,7 @@ fall_back_3way () {
 
     echo Using index info to reconstruct a base tree...
     if GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
-       git apply $binary --cached <"$dotest/patch"
+       git apply --cached <"$dotest/patch"
     then
        mv "$dotest/patch-merge-base+" "$dotest/patch-merge-base"
        mv "$dotest/patch-merge-tmp-index" "$dotest/patch-merge-index"
@@ -121,7 +121,7 @@ It does not apply to blobs recorded in its index."
 
 prec=4
 dotest="$GIT_DIR/rebase-apply"
-sign= utf8=t keep= skip= interactive= resolved= binary= rebasing= abort=
+sign= utf8=t keep= skip= interactive= resolved= rebasing= abort=
 resolvemsg= resume=
 git_apply_opt=
 
@@ -131,7 +131,7 @@ do
        -i|--interactive)
                interactive=t ;;
        -b|--binary)
-               binary=t ;;
+               : ;;
        -3|--3way)
                threeway=t ;;
        -s|--signoff)
@@ -149,7 +149,7 @@ do
        --abort)
                abort=t ;;
        --rebasing)
-               rebasing=t threeway=t keep=t binary=t ;;
+               rebasing=t threeway=t keep=t ;;
        -d|--dotest)
                die "-d option is no longer supported.  Do not use."
                ;;
@@ -247,10 +247,9 @@ else
                exit 1
        }
 
-       # -b, -s, -u, -k and --whitespace flags are kept for the
+       # -s, -u, -k and --whitespace flags are kept for the
        # resuming session after a patch failure.
        # -3 and -i can and must be given when resuming.
-       echo "$binary" >"$dotest/binary"
        echo " $ws" >"$dotest/whitespace"
        echo "$sign" >"$dotest/sign"
        echo "$utf8" >"$dotest/utf8"
@@ -274,10 +273,6 @@ case "$resolved" in
        fi
 esac
 
-if test "$(cat "$dotest/binary")" = t
-then
-       binary=--allow-binary-replacement
-fi
 if test "$(cat "$dotest/utf8")" = t
 then
        utf8=-u
@@ -459,7 +454,7 @@ do
 
        case "$resolved" in
        '')
-               git apply $git_apply_opt $binary --index "$dotest/patch"
+               git apply $git_apply_opt --index "$dotest/patch"
                apply_status=$?
                ;;
        t)
index 3cac20db79e1e408a321b0e9d272501985a3c49b..79de7017e88b746971f5a730b8615290bba2890d 100755 (executable)
@@ -172,6 +172,25 @@ bisect_write() {
        test -n "$nolog" || echo "git bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
 }
 
+is_expected_rev() {
+       test -f "$GIT_DIR/BISECT_EXPECTED_REV" &&
+       test "$1" = $(cat "$GIT_DIR/BISECT_EXPECTED_REV")
+}
+
+mark_expected_rev() {
+       echo "$1" > "$GIT_DIR/BISECT_EXPECTED_REV"
+}
+
+check_expected_revs() {
+       for _rev in "$@"; do
+               if ! is_expected_rev "$_rev"; then
+                       rm -f "$GIT_DIR/BISECT_ANCESTORS_OK"
+                       rm -f "$GIT_DIR/BISECT_EXPECTED_REV"
+                       return
+               fi
+       done
+}
+
 bisect_state() {
        bisect_autostart
        state=$1
@@ -181,7 +200,8 @@ bisect_state() {
        1,bad|1,good|1,skip)
                rev=$(git rev-parse --verify HEAD) ||
                        die "Bad rev input: HEAD"
-               bisect_write "$state" "$rev" ;;
+               bisect_write "$state" "$rev"
+               check_expected_revs "$rev" ;;
        2,bad|*,good|*,skip)
                shift
                eval=''
@@ -191,7 +211,8 @@ bisect_state() {
                                die "Bad rev input: $rev"
                        eval="$eval bisect_write '$state' '$sha'; "
                done
-               eval "$eval" ;;
+               eval "$eval"
+               check_expected_revs "$@" ;;
        *,bad)
                die "'git bisect bad' can take only one argument." ;;
        *)
@@ -220,7 +241,8 @@ bisect_next_check() {
                if test -t 0
                then
                        printf >&2 'Are you sure [Y/n]? '
-                       case "$(read yesno)" in [Nn]*) exit 1 ;; esac
+                       read yesno
+                       case "$yesno" in [Nn]*) exit 1 ;; esac
                fi
                : bisect without good...
                ;;
@@ -242,33 +264,18 @@ bisect_auto_next() {
        bisect_next_check && bisect_next || :
 }
 
-eval_rev_list() {
-       _eval="$1"
-
-       eval $_eval
-       res=$?
-
-       if [ $res -ne 0 ]; then
-               echo >&2 "'git rev-list --bisect-vars' failed:"
-               echo >&2 "maybe you mistake good and bad revs?"
-               exit $res
-       fi
-
-       return $res
-}
-
 filter_skipped() {
        _eval="$1"
        _skip="$2"
 
        if [ -z "$_skip" ]; then
-               eval_rev_list "$_eval"
+               eval "$_eval"
                return
        fi
 
        # Let's parse the output of:
        # "git rev-list --bisect-vars --bisect-all ..."
-       eval_rev_list "$_eval" | while read hash line
+       eval "$_eval" | while read hash line
        do
                case "$VARS,$FOUND,$TRIED,$hash" in
                        # We display some vars.
@@ -331,20 +338,133 @@ exit_if_skipped_commits () {
        fi
 }
 
+bisect_checkout() {
+       _rev="$1"
+       _msg="$2"
+       echo "Bisecting: $_msg"
+       mark_expected_rev "$_rev"
+       git checkout -q "$_rev" || exit
+       git show-branch "$_rev"
+}
+
+is_among() {
+       _rev="$1"
+       _list="$2"
+       case "$_list" in *$_rev*) return 0 ;; esac
+       return 1
+}
+
+handle_bad_merge_base() {
+       _badmb="$1"
+       _good="$2"
+       if is_expected_rev "$_badmb"; then
+               cat >&2 <<EOF
+The merge base $_badmb is bad.
+This means the bug has been fixed between $_badmb and [$_good].
+EOF
+               exit 3
+       else
+               cat >&2 <<EOF
+Some good revs are not ancestor of the bad rev.
+git bisect cannot work properly in this case.
+Maybe you mistake good and bad revs?
+EOF
+               exit 1
+       fi
+}
+
+handle_skipped_merge_base() {
+       _mb="$1"
+       _bad="$2"
+       _good="$3"
+       cat >&2 <<EOF
+Warning: the merge base between $_bad and [$_good] must be skipped.
+So we cannot be sure the first bad commit is between $_mb and $_bad.
+We continue anyway.
+EOF
+}
+
+#
+# "check_merge_bases" checks that merge bases are not "bad".
+#
+# - If one is "good", that's good, we have nothing to do.
+# - If one is "bad", it means the user assumed something wrong
+# and we must exit.
+# - If one is "skipped", we can't know but we should warn.
+# - If we don't know, we should check it out and ask the user to test.
+#
+# In the last case we will return 1, and otherwise 0.
+#
+check_merge_bases() {
+       _bad="$1"
+       _good="$2"
+       _skip="$3"
+       for _mb in $(git merge-base --all $_bad $_good)
+       do
+               if is_among "$_mb" "$_good"; then
+                       continue
+               elif test "$_mb" = "$_bad"; then
+                       handle_bad_merge_base "$_bad" "$_good"
+               elif is_among "$_mb" "$_skip"; then
+                       handle_skipped_merge_base "$_mb" "$_bad" "$_good"
+               else
+                       bisect_checkout "$_mb" "a merge base must be tested"
+                       return 1
+               fi
+       done
+       return 0
+}
+
+#
+# "check_good_are_ancestors_of_bad" checks that all "good" revs are
+# ancestor of the "bad" rev.
+#
+# If that's not the case, we need to check the merge bases.
+# If a merge base must be tested by the user we return 1 and
+# otherwise 0.
+#
+check_good_are_ancestors_of_bad() {
+       test -f "$GIT_DIR/BISECT_ANCESTORS_OK" &&
+               return
+
+       _bad="$1"
+       _good=$(echo $2 | sed -e 's/\^//g')
+       _skip="$3"
+
+       # Bisecting with no good rev is ok
+       test -z "$_good" && return
+
+       _side=$(git rev-list $_good ^$_bad)
+       if test -n "$_side"; then
+               # Return if a checkout was done
+               check_merge_bases "$_bad" "$_good" "$_skip" || return
+       fi
+
+       : > "$GIT_DIR/BISECT_ANCESTORS_OK"
+
+       return 0
+}
+
 bisect_next() {
        case "$#" in 0) ;; *) usage ;; esac
        bisect_autostart
        bisect_next_check good
 
+       # Get bad, good and skipped revs
+       bad=$(git rev-parse --verify refs/bisect/bad) &&
+       good=$(git for-each-ref --format='^%(objectname)' \
+               "refs/bisect/good-*" | tr '\012' ' ') &&
        skip=$(git for-each-ref --format='%(objectname)' \
-               "refs/bisect/skip-*" | tr '\012' ' ') || exit
+               "refs/bisect/skip-*" | tr '\012' ' ') &&
+
+       # Maybe some merge bases must be tested first
+       check_good_are_ancestors_of_bad "$bad" "$good" "$skip"
+       # Return now if a checkout has already been done
+       test "$?" -eq "1" && return
 
+       # Get bisection information
        BISECT_OPT=''
        test -n "$skip" && BISECT_OPT='--bisect-all'
-
-       bad=$(git rev-parse --verify refs/bisect/bad) &&
-       good=$(git for-each-ref --format='^%(objectname)' \
-               "refs/bisect/good-*" | tr '\012' ' ') &&
        eval="git rev-list --bisect-vars $BISECT_OPT $good $bad --" &&
        eval="$eval $(cat "$GIT_DIR/BISECT_NAMES")" &&
        eval=$(filter_skipped "$eval" "$skip") &&
@@ -365,9 +485,7 @@ bisect_next() {
        # commit is also a "skip" commit (see above).
        exit_if_skipped_commits "$bisect_rev"
 
-       echo "Bisecting: $bisect_nr revisions left to test after this"
-       git checkout -q "$bisect_rev" || exit
-       git show-branch "$bisect_rev"
+       bisect_checkout "$bisect_rev" "$bisect_nr revisions left to test after this"
 }
 
 bisect_visualize() {
@@ -414,6 +532,8 @@ bisect_clean_state() {
        do
                git update-ref -d $ref $hash || exit
        done
+       rm -f "$GIT_DIR/BISECT_EXPECTED_REV" &&
+       rm -f "$GIT_DIR/BISECT_ANCESTORS_OK" &&
        rm -f "$GIT_DIR/BISECT_LOG" &&
        rm -f "$GIT_DIR/BISECT_NAMES" &&
        rm -f "$GIT_DIR/BISECT_RUN" &&
index cf89cdf4598b3796724a85aa707f740245155cdc..db2836fbdee6c1e069e6f5955031087d778cddf5 100644 (file)
 #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)
 
index e2664ef01308fd0fb65d47b25e0ae73a65aa6262..e43920296182f320dac31b5832a30844ffaef38f 100755 (executable)
@@ -952,7 +952,7 @@ sub commit {
        } elsif (/^-+$/) { # end of unknown-line processing
                $state = 1;
        } elsif ($state != 11) { # ignore stuff when skipping
-               print "* UNKNOWN LINE * $_\n";
+               print STDERR "* UNKNOWN LINE * $_\n";
        }
 }
 commit() if $branch and $state != 11;
index 182822a24e214fe7e93a2df68fdda3dd40b5896d..81392add0b852f51f63a470727c33e0c306260d8 100755 (executable)
@@ -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
 
@@ -361,9 +357,17 @@ do
        ;;
        $_x40)
                echo "Ref '$ref' was rewritten"
-               git update-ref -m "filter-branch: rewrite" \
-                               "$ref" $rewritten $sha1 ||
-                       die "Could not rewrite $ref"
+               if ! git update-ref -m "filter-branch: rewrite" \
+                                       "$ref" $rewritten $sha1 2>/dev/null; then
+                       if test $(git cat-file -t "$ref") = tag; then
+                               if test -z "$filter_tag_name"; then
+                                       warn "WARNING: You said to rewrite tagged commits, but not the corresponding tag."
+                                       warn "WARNING: Perhaps use '--tag-name-filter cat' to rewrite the tag."
+                               fi
+                       else
+                               die "Could not rewrite $ref"
+                       fi
+               fi
        ;;
        *)
                # NEEDSWORK: possibly add -Werror, making this an error
@@ -408,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" | \
index 0ab478ef90aba9048a2de785d538da16e1bae431..4e709ebe776f722ff5509c8bf1b9cfaf9d7923b4 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=0.10.GITGUI
+DEF_VER=0.11.GITGUI
 
 LF='
 '
index 14b2d9aacd1d28084f195365b434747df2ddc95d..10d8a4422f151eda78a24ff533eb20c3d775d099 100755 (executable)
@@ -52,7 +52,11 @@ catch {rename send {}} ; # What an evil concept...
 set oguilib {@@GITGUI_LIBDIR@@}
 set oguirel {@@GITGUI_RELATIVE@@}
 if {$oguirel eq {1}} {
-       set oguilib [file dirname [file dirname [file normalize $argv0]]]
+       set oguilib [file dirname [file normalize $argv0]]
+       if {[file tail $oguilib] eq {git-core}} {
+               set oguilib [file dirname $oguilib]
+       }
+       set oguilib [file dirname $oguilib]
        set oguilib [file join $oguilib share git-gui lib]
        set oguimsg [file join $oguilib msgs]
 } elseif {[string match @@* $oguirel]} {
@@ -653,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
@@ -664,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) {}
@@ -1319,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
 }
 
@@ -1615,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
 
@@ -1623,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 {
@@ -1639,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"}}
@@ -1648,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]} {
@@ -1792,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} {
@@ -1819,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" \
@@ -1928,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
        }
@@ -2109,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]
@@ -2277,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]} {
@@ -2294,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
@@ -2325,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
@@ -2340,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
@@ -2456,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}
@@ -2685,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 \
@@ -2698,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
 #
@@ -2838,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
index b6e42cbc8fe0a49c301335f78cc2941bd9d59870..827c85d67f0b0f18d22b1399624e6819cf93f23f 100644 (file)
@@ -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
index ab470d12648c1dd3560b411e70ea210cc4381e3e..0410cc68df186d6e8e0080058be94126243fd4d3 100644 (file)
@@ -151,7 +151,7 @@ method _enter {} {
                                append p [lindex $n 1]
                        }
                        append p $name
-                       blame::new $browser_commit $p
+                       blame::new $browser_commit $p {}
                }
                }
        }
index 40a710355751836e78b65101592b753266f507ca..2977315624fc5deeecff275d8dc8b3f2e3210a70 100644 (file)
@@ -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)}
index 52b79e4a1f476c2ee9b65087f66a352a25ed0903..a30c80a935b58ce0c783dfffde196a85eadca9a2 100644 (file)
@@ -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
        }
 }
 
index 3c1fce7475d362d1880d915ff4bdf168fda28593..b045219a1cca6bf46218bf211c0c88b8d699e144 100644 (file)
@@ -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 (file)
index 0000000..79c58bc
--- /dev/null
@@ -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
+       }
+}
index ffb3f00ff0a992254804cc047b5a63ce82aa5bd9..9b865f6a754aeb0933e1696ae1c9ffaee899e936 100644 (file)
@@ -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"}}
                } {
index 5e77a7d7d2d9e82311c1573035fa020c8d08b38c..595bbf5dee97e34eeab46b742225fce2f95ab052 100644 (file)
@@ -101,7 +101,7 @@ matching msgid lines.  A few tips:
    "printf()"-like functions.  Make sure "%s", "%d", and "%%" in your
    translated messages match the original.
 
-   When you have to change the order of words, you can add "<number>\$"
+   When you have to change the order of words, you can add "<number>$"
    between '%' and the conversion ('s', 'd', etc.) to say "<number>-th
    parameter to the format string is used at this point".  For example,
    if the original message is like this:
@@ -111,12 +111,17 @@ matching msgid lines.  A few tips:
    and if for whatever reason your translation needs to say weight first
    and then length, you can say something like:
 
-       "WEIGHT IS %2\$d, LENGTH IS %1\$d"
+       "WEIGHT IS %2$d, LENGTH IS %1$d"
 
-   The reason you need a backslash before dollar sign is because
-   this is a double quoted string in Tcl language, and without
-   it the letter introduces a variable interpolation, which you
-   do not want here.
+   A format specification with a '*' (asterisk) refers to *two* arguments
+   instead of one, hence the succeeding argument number is two higher
+   instead of one. So, a message like this
+
+       "%s ... %*i of %*i %s (%3i%%)"
+
+   is equivalent to
+
+       "%1$s ... %2$*i of %4$*i %6$s (%7$3i%%)"
 
  - A long message can be split across multiple lines by ending the
    string with a double quote, and starting another string on the next
index f20955c18520bf2b0cc8826da9e1dc93a5624ac3..fa43947ad0cb43867545316d9a978bc1d67a88a2 100644 (file)
@@ -7,8 +7,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: git-gui\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-03-14 07:18+0100\n"
-"PO-Revision-Date: 2008-05-01 11:51+0200\n"
+"POT-Creation-Date: 2008-08-02 08:58+0200\n"
+"PO-Revision-Date: 2008-08-02 09:09+0200\n"
 "Last-Translator: Christian Stimming <stimming@tuhh.de>\n"
 "Language-Team: German\n"
 "MIME-Version: 1.0\n"
@@ -134,18 +134,11 @@ msgstr "Konfliktauflösung nötig"
 msgid "Starting gitk... please wait..."
 msgstr "Gitk wird gestartet... bitte warten."
 
-#: git-gui.sh:1653
-#, tcl-format
-msgid ""
-"Unable to start gitk:\n"
-"\n"
-"%s does not exist"
-msgstr ""
-"Gitk kann nicht gestartet werden:\n"
-"\n"
-"%s existiert nicht"
+#: git-gui.sh:1698
+msgid "Couldn't find gitk in PATH"
+msgstr "Gitk kann im PATH nicht gefunden werden."
 
-#: git-gui.sh:1860 lib/choose_repository.tcl:36
+#: git-gui.sh:1948 lib/choose_repository.tcl:36
 msgid "Repository"
 msgstr "Projektarchiv"
 
@@ -294,7 +287,15 @@ msgstr "Aus der Bereitstellung herausnehmen"
 msgid "Revert Changes"
 msgstr "Änderungen verwerfen"
 
-#: 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 "Weniger Zeilen anzeigen"
+
+#: git-gui.sh:2145 git-gui.sh:2706
+msgid "Show More Context"
+msgstr "Mehr Zeilen anzeigen"
+
+#: git-gui.sh:2151 git-gui.sh:2470 git-gui.sh:2569
 msgid "Sign Off"
 msgstr "Abzeichnen"
 
@@ -314,11 +315,7 @@ msgstr "Zusammenführen abbrechen..."
 msgid "Push..."
 msgstr "Versenden..."
 
-#: git-gui.sh:2092 lib/choose_repository.tcl:41
-msgid "Apple"
-msgstr "Apple"
-
-#: 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"
@@ -403,15 +400,11 @@ msgstr "Datei:"
 msgid "Apply/Reverse Hunk"
 msgstr "Kontext anwenden/umkehren"
 
-#: git-gui.sh:2595
-msgid "Show Less Context"
-msgstr "Weniger Zeilen anzeigen"
+#: git-gui.sh:2696
+msgid "Apply/Reverse Line"
+msgstr "Zeile anwenden/umkehren"
 
-#: git-gui.sh:2602
-msgid "Show More Context"
-msgstr "Mehr Zeilen anzeigen"
-
-#: git-gui.sh:2610
+#: git-gui.sh:2711
 msgid "Refresh"
 msgstr "Aktualisieren"
 
@@ -427,11 +420,19 @@ msgstr "Schriftgröße vergrößern"
 msgid "Unstage Hunk From Commit"
 msgstr "Kontext aus Bereitstellung herausnehmen"
 
-#: git-gui.sh:2648
+#: git-gui.sh:2748
+msgid "Unstage Line From Commit"
+msgstr "Zeile aus der Bereitstellung herausnehmen"
+
+#: git-gui.sh:2750
 msgid "Stage Hunk For Commit"
 msgstr "Kontext zur Bereitstellung hinzufügen"
 
-#: git-gui.sh:2667
+#: git-gui.sh:2751
+msgid "Stage Line For Commit"
+msgstr "Zeile zur Bereitstellung hinzufügen"
+
+#: git-gui.sh:2771
 msgid "Initializing..."
 msgstr "Initialisieren..."
 
@@ -493,7 +494,11 @@ msgstr "Version:"
 msgid "Copy Commit"
 msgstr "Version kopieren"
 
-#: lib/blame.tcl:384
+#: lib/blame.tcl:260
+msgid "Do Full Copy Detection"
+msgstr "Volle Kopie-Erkennung"
+
+#: lib/blame.tcl:388
 #, tcl-format
 msgid "Reading %s..."
 msgstr "%s lesen..."
@@ -514,7 +519,19 @@ msgstr "Annotierungen für ursprünglichen Ort werden geladen..."
 msgid "Annotation complete."
 msgstr "Annotierung vollständig."
 
-#: lib/blame.tcl:746
+#: lib/blame.tcl:737
+msgid "Busy"
+msgstr "Verarbeitung läuft"
+
+#: lib/blame.tcl:738
+msgid "Annotation process is already running."
+msgstr "Annotierung läuft bereits."
+
+#: lib/blame.tcl:777
+msgid "Running thorough copy detection..."
+msgstr "Intensive Kopie-Erkennung läuft..."
+
+#: lib/blame.tcl:827
 msgid "Loading annotation..."
 msgstr "Annotierung laden..."
 
@@ -759,7 +776,12 @@ msgstr "Schließen"
 msgid "Branch '%s' does not exist."
 msgstr "Zweig »%s« existiert nicht."
 
-#: lib/checkout_op.tcl:206
+#: lib/checkout_op.tcl:193
+#, tcl-format
+msgid "Failed to configure simplified git-pull for '%s'."
+msgstr "Fehler beim Einrichten der vereinfachten git-pull für »%s«."
+
+#: lib/checkout_op.tcl:228
 #, tcl-format
 msgid ""
 "Branch '%s' already exists.\n"
@@ -1485,6 +1507,14 @@ msgstr ""
 msgid "Failed to stage selected hunk."
 msgstr "Fehler beim Bereitstellen des gewählten Kontexts."
 
+#: lib/diff.tcl:386
+msgid "Failed to unstage selected line."
+msgstr "Fehler beim Herausnehmen der gewählten Zeile aus der Bereitstellung."
+
+#: lib/diff.tcl:394
+msgid "Failed to stage selected line."
+msgstr "Fehler beim Bereitstellen der gewählten Zeile."
+
 #: lib/error.tcl:20 lib/error.tcl:114
 msgid "error"
 msgstr "Fehler"
@@ -1750,6 +1780,14 @@ msgid "Match Tracking Branches"
 msgstr "Passend zu Übernahmezweig"
 
 #: lib/option.tcl:126
+msgid "Blame Copy Only On Changed Files"
+msgstr "Kopie-Annotieren nur bei geänderten Dateien"
+
+#: lib/option.tcl:127
+msgid "Minimum Letters To Blame Copy On"
+msgstr "Mindestzahl Zeichen für Kopie-Annotieren"
+
+#: lib/option.tcl:128
 msgid "Number of Diff Context Lines"
 msgstr "Anzahl der Kontextzeilen beim Vergleich"
 
index 89b6d51ea011d5b0fc8a343ffdda078d659571cb..26b866f5510788fd0dac1df1d7f59114713ce53a 100644 (file)
@@ -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)"
 
index 813199f782968cb0949d24119145e8b3e4a174cd..e295000e778afaaf5ddf3fcbaf067fa0dfb10fbb 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-03-14 07:18+0100\n"
+"POT-Creation-Date: 2008-08-02 14:45-0700\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,33 +16,33 @@ msgstr ""
 "Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\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.sh:593
+#: git-gui.sh:644
 #, tcl-format
 msgid "Invalid font specified in %s:"
 msgstr ""
 
-#: git-gui.sh:620
+#: git-gui.sh:674
 msgid "Main Font"
 msgstr ""
 
-#: git-gui.sh:621
+#: git-gui.sh:675
 msgid "Diff/Console Font"
 msgstr ""
 
-#: git-gui.sh:635
+#: git-gui.sh:689
 msgid "Cannot find git in PATH."
 msgstr ""
 
-#: git-gui.sh:662
+#: git-gui.sh:716
 msgid "Cannot parse Git version string:"
 msgstr ""
 
-#: git-gui.sh:680
+#: git-gui.sh:734
 #, tcl-format
 msgid ""
 "Git version cannot be determined.\n"
@@ -54,375 +54,379 @@ msgid ""
 "Assume '%s' is version 1.5.0?\n"
 msgstr ""
 
-#: git-gui.sh:918
+#: git-gui.sh:972
 msgid "Git directory not found:"
 msgstr ""
 
-#: git-gui.sh:925
+#: git-gui.sh:979
 msgid "Cannot move to top of working directory:"
 msgstr ""
 
-#: git-gui.sh:932
+#: git-gui.sh:986
 msgid "Cannot use funny .git directory:"
 msgstr ""
 
-#: git-gui.sh:937
+#: git-gui.sh:991
 msgid "No working directory"
 msgstr ""
 
-#: git-gui.sh:1084 lib/checkout_op.tcl:283
+#: git-gui.sh:1138 lib/checkout_op.tcl:305
 msgid "Refreshing file status..."
 msgstr ""
 
-#: git-gui.sh:1149
+#: git-gui.sh:1194
 msgid "Scanning for modified files ..."
 msgstr ""
 
-#: git-gui.sh:1324 lib/browser.tcl:246
+#: git-gui.sh:1369 lib/browser.tcl:246
 msgid "Ready."
 msgstr ""
 
-#: git-gui.sh:1590
+#: git-gui.sh:1635
 msgid "Unmodified"
 msgstr ""
 
-#: git-gui.sh:1592
+#: git-gui.sh:1637
 msgid "Modified, not staged"
 msgstr ""
 
-#: git-gui.sh:1593 git-gui.sh:1598
+#: git-gui.sh:1638 git-gui.sh:1643
 msgid "Staged for commit"
 msgstr ""
 
-#: git-gui.sh:1594 git-gui.sh:1599
+#: git-gui.sh:1639 git-gui.sh:1644
 msgid "Portions staged for commit"
 msgstr ""
 
-#: git-gui.sh:1595 git-gui.sh:1600
+#: git-gui.sh:1640 git-gui.sh:1645
 msgid "Staged for commit, missing"
 msgstr ""
 
-#: git-gui.sh:1597
+#: git-gui.sh:1642
 msgid "Untracked, not staged"
 msgstr ""
 
-#: git-gui.sh:1602
+#: git-gui.sh:1647
 msgid "Missing"
 msgstr ""
 
-#: git-gui.sh:1603
+#: git-gui.sh:1648
 msgid "Staged for removal"
 msgstr ""
 
-#: git-gui.sh:1604
+#: git-gui.sh:1649
 msgid "Staged for removal, still present"
 msgstr ""
 
-#: 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 ""
 
-#: git-gui.sh:1644
+#: git-gui.sh:1689
 msgid "Starting gitk... please wait..."
 msgstr ""
 
-#: git-gui.sh:1653
-#, tcl-format
-msgid ""
-"Unable to start gitk:\n"
-"\n"
-"%s does not exist"
+#: git-gui.sh:1698
+msgid "Couldn't find gitk in PATH"
 msgstr ""
 
-#: git-gui.sh:1860 lib/choose_repository.tcl:36
+#: git-gui.sh:1948 lib/choose_repository.tcl:36
 msgid "Repository"
 msgstr ""
 
-#: git-gui.sh:1861
+#: git-gui.sh:1949
 msgid "Edit"
 msgstr ""
 
-#: git-gui.sh:1863 lib/choose_rev.tcl:561
+#: git-gui.sh:1951 lib/choose_rev.tcl:561
 msgid "Branch"
 msgstr ""
 
-#: git-gui.sh:1866 lib/choose_rev.tcl:548
+#: git-gui.sh:1954 lib/choose_rev.tcl:548
 msgid "Commit@@noun"
 msgstr ""
 
-#: 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 ""
 
-#: git-gui.sh:1870 lib/choose_rev.tcl:557
+#: git-gui.sh:1958 lib/choose_rev.tcl:557
 msgid "Remote"
 msgstr ""
 
-#: git-gui.sh:1879
+#: git-gui.sh:1967
 msgid "Browse Current Branch's Files"
 msgstr ""
 
-#: git-gui.sh:1883
+#: git-gui.sh:1971
 msgid "Browse Branch Files..."
 msgstr ""
 
-#: git-gui.sh:1888
+#: git-gui.sh:1976
 msgid "Visualize Current Branch's History"
 msgstr ""
 
-#: git-gui.sh:1892
+#: git-gui.sh:1980
 msgid "Visualize All Branch History"
 msgstr ""
 
-#: git-gui.sh:1899
+#: git-gui.sh:1987
 #, tcl-format
 msgid "Browse %s's Files"
 msgstr ""
 
-#: git-gui.sh:1901
+#: git-gui.sh:1989
 #, tcl-format
 msgid "Visualize %s's History"
 msgstr ""
 
-#: 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 ""
 
-#: git-gui.sh:1909 lib/database.tcl:34
+#: git-gui.sh:1997 lib/database.tcl:34
 msgid "Compress Database"
 msgstr ""
 
-#: git-gui.sh:1912
+#: git-gui.sh:2000
 msgid "Verify Database"
 msgstr ""
 
-#: 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 ""
 
-#: 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 ""
 
-#: git-gui.sh:1939
+#: git-gui.sh:2031
 msgid "Undo"
 msgstr ""
 
-#: git-gui.sh:1942
+#: git-gui.sh:2034
 msgid "Redo"
 msgstr ""
 
-#: git-gui.sh:1946 git-gui.sh:2443
+#: git-gui.sh:2038 git-gui.sh:2545
 msgid "Cut"
 msgstr ""
 
-#: 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 ""
 
-#: git-gui.sh:1952 git-gui.sh:2449
+#: git-gui.sh:2044 git-gui.sh:2551
 msgid "Paste"
 msgstr ""
 
-#: 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 ""
 
-#: 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 ""
 
-#: git-gui.sh:1968
+#: git-gui.sh:2060
 msgid "Create..."
 msgstr ""
 
-#: git-gui.sh:1974
+#: git-gui.sh:2066
 msgid "Checkout..."
 msgstr ""
 
-#: git-gui.sh:1980
+#: git-gui.sh:2072
 msgid "Rename..."
 msgstr ""
 
-#: git-gui.sh:1985 git-gui.sh:2085
+#: git-gui.sh:2077 git-gui.sh:2187
 msgid "Delete..."
 msgstr ""
 
-#: git-gui.sh:1990
+#: git-gui.sh:2082
 msgid "Reset..."
 msgstr ""
 
-#: git-gui.sh:2002 git-gui.sh:2389
+#: git-gui.sh:2094 git-gui.sh:2491
 msgid "New Commit"
 msgstr ""
 
-#: git-gui.sh:2010 git-gui.sh:2396
+#: git-gui.sh:2102 git-gui.sh:2498
 msgid "Amend Last Commit"
 msgstr ""
 
-#: 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 ""
 
-#: git-gui.sh:2025
+#: git-gui.sh:2117
 msgid "Stage To Commit"
 msgstr ""
 
-#: git-gui.sh:2031
+#: git-gui.sh:2123
 msgid "Stage Changed Files To Commit"
 msgstr ""
 
-#: git-gui.sh:2037
+#: git-gui.sh:2129
 msgid "Unstage From Commit"
 msgstr ""
 
-#: git-gui.sh:2042 lib/index.tcl:395
+#: git-gui.sh:2134 lib/index.tcl:395
 msgid "Revert Changes"
 msgstr ""
 
-#: 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 ""
+
+#: git-gui.sh:2145 git-gui.sh:2706
+msgid "Show More Context"
+msgstr ""
+
+#: git-gui.sh:2151 git-gui.sh:2470 git-gui.sh:2569
 msgid "Sign Off"
 msgstr ""
 
-#: git-gui.sh:2053 git-gui.sh:2372
+#: git-gui.sh:2155 git-gui.sh:2474
 msgid "Commit@@verb"
 msgstr ""
 
-#: git-gui.sh:2064
+#: git-gui.sh:2166
 msgid "Local Merge..."
 msgstr ""
 
-#: git-gui.sh:2069
+#: git-gui.sh:2171
 msgid "Abort Merge..."
 msgstr ""
 
-#: git-gui.sh:2081
+#: git-gui.sh:2183
 msgid "Push..."
 msgstr ""
 
-#: git-gui.sh:2092 lib/choose_repository.tcl:41
-msgid "Apple"
-msgstr ""
-
-#: 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 ""
 
-#: git-gui.sh:2099
+#: git-gui.sh:2201
 msgid "Preferences..."
 msgstr ""
 
-#: git-gui.sh:2107 git-gui.sh:2639
+#: git-gui.sh:2209 git-gui.sh:2740
 msgid "Options..."
 msgstr ""
 
-#: git-gui.sh:2113 lib/choose_repository.tcl:47
+#: git-gui.sh:2215 lib/choose_repository.tcl:47
 msgid "Help"
 msgstr ""
 
-#: git-gui.sh:2154
+#: git-gui.sh:2256
 msgid "Online Documentation"
 msgstr ""
 
-#: git-gui.sh:2238
+#: git-gui.sh:2340
 #, tcl-format
 msgid "fatal: cannot stat path %s: No such file or directory"
 msgstr ""
 
-#: git-gui.sh:2271
+#: git-gui.sh:2373
 msgid "Current Branch:"
 msgstr ""
 
-#: git-gui.sh:2292
+#: git-gui.sh:2394
 msgid "Staged Changes (Will Commit)"
 msgstr ""
 
-#: git-gui.sh:2312
+#: git-gui.sh:2414
 msgid "Unstaged Changes"
 msgstr ""
 
-#: git-gui.sh:2362
+#: git-gui.sh:2464
 msgid "Stage Changed"
 msgstr ""
 
-#: 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 ""
 
-#: git-gui.sh:2408
+#: git-gui.sh:2510
 msgid "Initial Commit Message:"
 msgstr ""
 
-#: git-gui.sh:2409
+#: git-gui.sh:2511
 msgid "Amended Commit Message:"
 msgstr ""
 
-#: git-gui.sh:2410
+#: git-gui.sh:2512
 msgid "Amended Initial Commit Message:"
 msgstr ""
 
-#: git-gui.sh:2411
+#: git-gui.sh:2513
 msgid "Amended Merge Commit Message:"
 msgstr ""
 
-#: git-gui.sh:2412
+#: git-gui.sh:2514
 msgid "Merge Commit Message:"
 msgstr ""
 
-#: git-gui.sh:2413
+#: git-gui.sh:2515
 msgid "Commit Message:"
 msgstr ""
 
-#: 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 ""
 
-#: git-gui.sh:2483 lib/blame.tcl:107
+#: git-gui.sh:2585 lib/blame.tcl:100
 msgid "File:"
 msgstr ""
 
-#: git-gui.sh:2589
+#: git-gui.sh:2691
 msgid "Apply/Reverse Hunk"
 msgstr ""
 
-#: git-gui.sh:2595
-msgid "Show Less Context"
-msgstr ""
-
-#: git-gui.sh:2602
-msgid "Show More Context"
+#: git-gui.sh:2696
+msgid "Apply/Reverse Line"
 msgstr ""
 
-#: git-gui.sh:2610
+#: git-gui.sh:2711
 msgid "Refresh"
 msgstr ""
 
-#: git-gui.sh:2631
+#: git-gui.sh:2732
 msgid "Decrease Font Size"
 msgstr ""
 
-#: git-gui.sh:2635
+#: git-gui.sh:2736
 msgid "Increase Font Size"
 msgstr ""
 
-#: git-gui.sh:2646
+#: git-gui.sh:2747
 msgid "Unstage Hunk From Commit"
 msgstr ""
 
-#: git-gui.sh:2648
+#: git-gui.sh:2748
+msgid "Unstage Line From Commit"
+msgstr ""
+
+#: git-gui.sh:2750
 msgid "Stage Hunk For Commit"
 msgstr ""
 
-#: git-gui.sh:2667
+#: git-gui.sh:2751
+msgid "Stage Line For Commit"
+msgstr ""
+
+#: git-gui.sh:2771
 msgid "Initializing..."
 msgstr ""
 
-#: git-gui.sh:2762
+#: git-gui.sh:2876
 #, tcl-format
 msgid ""
 "Possible environment issues exist.\n"
@@ -433,14 +437,14 @@ msgid ""
 "\n"
 msgstr ""
 
-#: git-gui.sh:2792
+#: git-gui.sh:2906
 msgid ""
 "\n"
 "This is due to a known issue with the\n"
 "Tcl binary distributed by Cygwin."
 msgstr ""
 
-#: git-gui.sh:2797
+#: git-gui.sh:2911
 #, tcl-format
 msgid ""
 "\n"
@@ -455,64 +459,80 @@ msgstr ""
 msgid "git-gui - a graphical user interface for Git."
 msgstr ""
 
-#: lib/blame.tcl:77
+#: lib/blame.tcl:70
 msgid "File Viewer"
 msgstr ""
 
-#: lib/blame.tcl:81
+#: lib/blame.tcl:74
 msgid "Commit:"
 msgstr ""
 
-#: lib/blame.tcl:264
+#: lib/blame.tcl:257
 msgid "Copy Commit"
 msgstr ""
 
-#: lib/blame.tcl:384
+#: lib/blame.tcl:260
+msgid "Do Full Copy Detection"
+msgstr ""
+
+#: lib/blame.tcl:388
 #, tcl-format
 msgid "Reading %s..."
 msgstr ""
 
-#: lib/blame.tcl:488
+#: lib/blame.tcl:492
 msgid "Loading copy/move tracking annotations..."
 msgstr ""
 
-#: lib/blame.tcl:508
+#: lib/blame.tcl:512
 msgid "lines annotated"
 msgstr ""
 
-#: lib/blame.tcl:689
+#: lib/blame.tcl:704
 msgid "Loading original location annotations..."
 msgstr ""
 
-#: lib/blame.tcl:692
+#: lib/blame.tcl:707
 msgid "Annotation complete."
 msgstr ""
 
-#: lib/blame.tcl:746
+#: lib/blame.tcl:737
+msgid "Busy"
+msgstr ""
+
+#: lib/blame.tcl:738
+msgid "Annotation process is already running."
+msgstr ""
+
+#: lib/blame.tcl:777
+msgid "Running thorough copy detection..."
+msgstr ""
+
+#: lib/blame.tcl:827
 msgid "Loading annotation..."
 msgstr ""
 
-#: lib/blame.tcl:802
+#: lib/blame.tcl:883
 msgid "Author:"
 msgstr ""
 
-#: lib/blame.tcl:806
+#: lib/blame.tcl:887
 msgid "Committer:"
 msgstr ""
 
-#: lib/blame.tcl:811
+#: lib/blame.tcl:892
 msgid "Original File:"
 msgstr ""
 
-#: lib/blame.tcl:925
+#: lib/blame.tcl:1006
 msgid "Originally By:"
 msgstr ""
 
-#: lib/blame.tcl:931
+#: lib/blame.tcl:1012
 msgid "In File:"
 msgstr ""
 
-#: lib/blame.tcl:936
+#: lib/blame.tcl:1017
 msgid "Copied Or Moved Here By:"
 msgstr ""
 
@@ -526,7 +546,7 @@ msgstr ""
 
 #: 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 ""
@@ -535,7 +555,7 @@ msgstr ""
 msgid "Revision"
 msgstr ""
 
-#: 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 ""
 
@@ -587,7 +607,7 @@ msgstr ""
 msgid "Fast Forward Only"
 msgstr ""
 
-#: lib/branch_create.tcl:85 lib/checkout_op.tcl:514
+#: lib/branch_create.tcl:85 lib/checkout_op.tcl:536
 msgid "Reset"
 msgstr ""
 
@@ -672,7 +692,7 @@ msgstr ""
 msgid "Please select a branch to rename."
 msgstr ""
 
-#: 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 ""
@@ -704,31 +724,36 @@ msgid "Browse Branch Files"
 msgstr ""
 
 #: 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 ""
 
-#: lib/checkout_op.tcl:79
+#: lib/checkout_op.tcl:84
 #, tcl-format
 msgid "Fetching %s from %s"
 msgstr ""
 
-#: lib/checkout_op.tcl:127
+#: lib/checkout_op.tcl:132
 #, tcl-format
 msgid "fatal: Cannot resolve %s"
 msgstr ""
 
-#: 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 ""
 
-#: lib/checkout_op.tcl:169
+#: lib/checkout_op.tcl:174
 #, tcl-format
 msgid "Branch '%s' does not exist."
 msgstr ""
 
-#: lib/checkout_op.tcl:206
+#: lib/checkout_op.tcl:193
+#, tcl-format
+msgid "Failed to configure simplified git-pull for '%s'."
+msgstr ""
+
+#: lib/checkout_op.tcl:228
 #, tcl-format
 msgid ""
 "Branch '%s' already exists.\n"
@@ -737,21 +762,21 @@ msgid ""
 "A merge is required."
 msgstr ""
 
-#: lib/checkout_op.tcl:220
+#: lib/checkout_op.tcl:242
 #, tcl-format
 msgid "Merge strategy '%s' not supported."
 msgstr ""
 
-#: lib/checkout_op.tcl:239
+#: lib/checkout_op.tcl:261
 #, tcl-format
 msgid "Failed to update '%s'."
 msgstr ""
 
-#: lib/checkout_op.tcl:251
+#: lib/checkout_op.tcl:273
 msgid "Staging area (index) is already locked."
 msgstr ""
 
-#: lib/checkout_op.tcl:266
+#: lib/checkout_op.tcl:288
 msgid ""
 "Last scanned state does not match repository state.\n"
 "\n"
@@ -761,30 +786,30 @@ msgid ""
 "The rescan will be automatically started now.\n"
 msgstr ""
 
-#: lib/checkout_op.tcl:322
+#: lib/checkout_op.tcl:344
 #, tcl-format
 msgid "Updating working directory to '%s'..."
 msgstr ""
 
-#: lib/checkout_op.tcl:323
+#: lib/checkout_op.tcl:345
 msgid "files checked out"
 msgstr ""
 
-#: lib/checkout_op.tcl:353
+#: lib/checkout_op.tcl:375
 #, tcl-format
 msgid "Aborted checkout of '%s' (file level merging is required)."
 msgstr ""
 
-#: lib/checkout_op.tcl:354
+#: lib/checkout_op.tcl:376
 msgid "File level merge required."
 msgstr ""
 
-#: lib/checkout_op.tcl:358
+#: lib/checkout_op.tcl:380
 #, tcl-format
 msgid "Staying on branch '%s'."
 msgstr ""
 
-#: lib/checkout_op.tcl:429
+#: lib/checkout_op.tcl:451
 msgid ""
 "You are no longer on a local branch.\n"
 "\n"
@@ -792,30 +817,30 @@ msgid ""
 "Checkout'."
 msgstr ""
 
-#: 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 ""
 
-#: lib/checkout_op.tcl:478
+#: lib/checkout_op.tcl:500
 #, tcl-format
 msgid "Resetting '%s' to '%s' will lose the following commits:"
 msgstr ""
 
-#: lib/checkout_op.tcl:500
+#: lib/checkout_op.tcl:522
 msgid "Recovering lost commits may not be easy."
 msgstr ""
 
-#: lib/checkout_op.tcl:505
+#: lib/checkout_op.tcl:527
 #, tcl-format
 msgid "Reset '%s'?"
 msgstr ""
 
-#: lib/checkout_op.tcl:510 lib/merge.tcl:163
+#: lib/checkout_op.tcl:532 lib/merge.tcl:163
 msgid "Visualize"
 msgstr ""
 
-#: lib/checkout_op.tcl:578
+#: lib/checkout_op.tcl:600
 #, tcl-format
 msgid ""
 "Failed to set current branch.\n"
@@ -860,7 +885,7 @@ msgstr ""
 msgid "New..."
 msgstr ""
 
-#: 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 ""
 
@@ -868,7 +893,7 @@ msgstr ""
 msgid "Clone..."
 msgstr ""
 
-#: 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 ""
 
@@ -890,183 +915,183 @@ msgstr ""
 msgid "Failed to create repository %s:"
 msgstr ""
 
-#: lib/choose_repository.tcl:381 lib/choose_repository.tcl:478
+#: lib/choose_repository.tcl:381 lib/choose_repository.tcl:476
 msgid "Directory:"
 msgstr ""
 
-#: 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 ""
 
-#: lib/choose_repository.tcl:437
+#: lib/choose_repository.tcl:435
 #, tcl-format
 msgid "Directory %s already exists."
 msgstr ""
 
-#: lib/choose_repository.tcl:441
+#: lib/choose_repository.tcl:439
 #, tcl-format
 msgid "File %s already exists."
 msgstr ""
 
-#: lib/choose_repository.tcl:455
+#: lib/choose_repository.tcl:453
 msgid "Clone"
 msgstr ""
 
-#: lib/choose_repository.tcl:468
+#: lib/choose_repository.tcl:466
 msgid "URL:"
 msgstr ""
 
-#: lib/choose_repository.tcl:489
+#: lib/choose_repository.tcl:487
 msgid "Clone Type:"
 msgstr ""
 
-#: lib/choose_repository.tcl:495
+#: lib/choose_repository.tcl:493
 msgid "Standard (Fast, Semi-Redundant, Hardlinks)"
 msgstr ""
 
-#: lib/choose_repository.tcl:501
+#: lib/choose_repository.tcl:499
 msgid "Full Copy (Slower, Redundant Backup)"
 msgstr ""
 
-#: lib/choose_repository.tcl:507
+#: lib/choose_repository.tcl:505
 msgid "Shared (Fastest, Not Recommended, No Backup)"
 msgstr ""
 
-#: 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 ""
 
-#: lib/choose_repository.tcl:579
+#: lib/choose_repository.tcl:577
 msgid "Standard only available for local repository."
 msgstr ""
 
-#: lib/choose_repository.tcl:583
+#: lib/choose_repository.tcl:581
 msgid "Shared only available for local repository."
 msgstr ""
 
-#: lib/choose_repository.tcl:604
+#: lib/choose_repository.tcl:602
 #, tcl-format
 msgid "Location %s already exists."
 msgstr ""
 
-#: lib/choose_repository.tcl:615
+#: lib/choose_repository.tcl:613
 msgid "Failed to configure origin"
 msgstr ""
 
-#: lib/choose_repository.tcl:627
+#: lib/choose_repository.tcl:625
 msgid "Counting objects"
 msgstr ""
 
-#: lib/choose_repository.tcl:628
+#: lib/choose_repository.tcl:626
 msgid "buckets"
 msgstr ""
 
-#: lib/choose_repository.tcl:652
+#: lib/choose_repository.tcl:650
 #, tcl-format
 msgid "Unable to copy objects/info/alternates: %s"
 msgstr ""
 
-#: lib/choose_repository.tcl:688
+#: lib/choose_repository.tcl:686
 #, tcl-format
 msgid "Nothing to clone from %s."
 msgstr ""
 
-#: 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 ""
 
-#: lib/choose_repository.tcl:703
+#: lib/choose_repository.tcl:701
 msgid "Hardlinks are unavailable.  Falling back to copying."
 msgstr ""
 
-#: lib/choose_repository.tcl:715
+#: lib/choose_repository.tcl:713
 #, tcl-format
 msgid "Cloning from %s"
 msgstr ""
 
-#: lib/choose_repository.tcl:746
+#: lib/choose_repository.tcl:744
 msgid "Copying objects"
 msgstr ""
 
-#: lib/choose_repository.tcl:747
+#: lib/choose_repository.tcl:745
 msgid "KiB"
 msgstr ""
 
-#: lib/choose_repository.tcl:771
+#: lib/choose_repository.tcl:769
 #, tcl-format
 msgid "Unable to copy object: %s"
 msgstr ""
 
-#: lib/choose_repository.tcl:781
+#: lib/choose_repository.tcl:779
 msgid "Linking objects"
 msgstr ""
 
-#: lib/choose_repository.tcl:782
+#: lib/choose_repository.tcl:780
 msgid "objects"
 msgstr ""
 
-#: lib/choose_repository.tcl:790
+#: lib/choose_repository.tcl:788
 #, tcl-format
 msgid "Unable to hardlink object: %s"
 msgstr ""
 
-#: lib/choose_repository.tcl:845
+#: lib/choose_repository.tcl:843
 msgid "Cannot fetch branches and objects.  See console output for details."
 msgstr ""
 
-#: lib/choose_repository.tcl:856
+#: lib/choose_repository.tcl:854
 msgid "Cannot fetch tags.  See console output for details."
 msgstr ""
 
-#: lib/choose_repository.tcl:880
+#: lib/choose_repository.tcl:878
 msgid "Cannot determine HEAD.  See console output for details."
 msgstr ""
 
-#: lib/choose_repository.tcl:889
+#: lib/choose_repository.tcl:887
 #, tcl-format
 msgid "Unable to cleanup %s"
 msgstr ""
 
-#: lib/choose_repository.tcl:895
+#: lib/choose_repository.tcl:893
 msgid "Clone failed."
 msgstr ""
 
-#: lib/choose_repository.tcl:902
+#: lib/choose_repository.tcl:900
 msgid "No default branch obtained."
 msgstr ""
 
-#: lib/choose_repository.tcl:913
+#: lib/choose_repository.tcl:911
 #, tcl-format
 msgid "Cannot resolve %s as a commit."
 msgstr ""
 
-#: lib/choose_repository.tcl:925
+#: lib/choose_repository.tcl:923
 msgid "Creating working directory"
 msgstr ""
 
-#: 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 ""
 
-#: lib/choose_repository.tcl:955
+#: lib/choose_repository.tcl:953
 msgid "Initial file checkout failed."
 msgstr ""
 
-#: lib/choose_repository.tcl:971
+#: lib/choose_repository.tcl:969
 msgid "Open"
 msgstr ""
 
-#: lib/choose_repository.tcl:981
+#: lib/choose_repository.tcl:979
 msgid "Repository:"
 msgstr ""
 
-#: lib/choose_repository.tcl:1031
+#: lib/choose_repository.tcl:1027
 #, tcl-format
 msgid "Failed to open repository %s:"
 msgstr ""
@@ -1314,7 +1339,7 @@ msgstr ""
 msgid "Invalid date from Git: %s"
 msgstr ""
 
-#: lib/diff.tcl:42
+#: lib/diff.tcl:44
 #, tcl-format
 msgid ""
 "No differences detected.\n"
@@ -1328,40 +1353,48 @@ msgid ""
 "the same state."
 msgstr ""
 
-#: lib/diff.tcl:81
+#: lib/diff.tcl:83
 #, tcl-format
 msgid "Loading diff of %s..."
 msgstr ""
 
-#: lib/diff.tcl:114 lib/diff.tcl:184
+#: lib/diff.tcl:116 lib/diff.tcl:190
 #, tcl-format
 msgid "Unable to display %s"
 msgstr ""
 
-#: lib/diff.tcl:115
+#: lib/diff.tcl:117
 msgid "Error loading file:"
 msgstr ""
 
-#: lib/diff.tcl:122
+#: lib/diff.tcl:124
 msgid "Git Repository (subproject)"
 msgstr ""
 
-#: lib/diff.tcl:134
+#: lib/diff.tcl:136
 msgid "* Binary file (not showing content)."
 msgstr ""
 
-#: lib/diff.tcl:185
+#: lib/diff.tcl:191
 msgid "Error loading diff:"
 msgstr ""
 
-#: lib/diff.tcl:303
+#: lib/diff.tcl:313
 msgid "Failed to unstage selected hunk."
 msgstr ""
 
-#: lib/diff.tcl:310
+#: lib/diff.tcl:320
 msgid "Failed to stage selected hunk."
 msgstr ""
 
+#: lib/diff.tcl:386
+msgid "Failed to unstage selected line."
+msgstr ""
+
+#: lib/diff.tcl:394
+msgid "Failed to stage selected line."
+msgstr ""
+
 #: lib/error.tcl:20 lib/error.tcl:114
 msgid "error"
 msgstr ""
@@ -1527,11 +1560,11 @@ msgstr ""
 msgid "files reset"
 msgstr ""
 
-#: lib/merge.tcl:265
+#: lib/merge.tcl:266
 msgid "Abort failed."
 msgstr ""
 
-#: lib/merge.tcl:267
+#: lib/merge.tcl:268
 msgid "Abort completed.  Ready."
 msgstr ""
 
@@ -1585,42 +1618,62 @@ msgid "Match Tracking Branches"
 msgstr ""
 
 #: lib/option.tcl:126
-msgid "Number of Diff Context Lines"
+msgid "Blame Copy Only On Changed Files"
 msgstr ""
 
 #: lib/option.tcl:127
-msgid "Commit Message Text Width"
+msgid "Minimum Letters To Blame Copy On"
 msgstr ""
 
 #: lib/option.tcl:128
+msgid "Number of Diff Context Lines"
+msgstr ""
+
+#: lib/option.tcl:129
+msgid "Commit Message Text Width"
+msgstr ""
+
+#: lib/option.tcl:130
 msgid "New Branch Name Template"
 msgstr ""
 
-#: lib/option.tcl:192
+#: lib/option.tcl:194
 msgid "Spelling Dictionary:"
 msgstr ""
 
-#: lib/option.tcl:216
+#: lib/option.tcl:218
 msgid "Change Font"
 msgstr ""
 
-#: lib/option.tcl:220
+#: lib/option.tcl:222
 #, tcl-format
 msgid "Choose %s"
 msgstr ""
 
-#: lib/option.tcl:226
+#: lib/option.tcl:228
 msgid "pt."
 msgstr ""
 
-#: lib/option.tcl:240
+#: lib/option.tcl:242
 msgid "Preferences"
 msgstr ""
 
-#: lib/option.tcl:275
+#: lib/option.tcl:277
 msgid "Failed to completely save options:"
 msgstr ""
 
+#: lib/remote.tcl:165
+msgid "Prune from"
+msgstr ""
+
+#: lib/remote.tcl:170
+msgid "Fetch from"
+msgstr ""
+
+#: lib/remote.tcl:213
+msgid "Push to"
+msgstr ""
+
 #: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34
 msgid "Delete Remote Branch"
 msgstr ""
@@ -1697,18 +1750,6 @@ msgstr ""
 msgid "Scanning %s..."
 msgstr ""
 
-#: lib/remote.tcl:165
-msgid "Prune from"
-msgstr ""
-
-#: lib/remote.tcl:170
-msgid "Fetch from"
-msgstr ""
-
-#: lib/remote.tcl:213
-msgid "Push to"
-msgstr ""
-
 #: lib/shortcut.tcl:20 lib/shortcut.tcl:61
 msgid "Cannot write shortcut:"
 msgstr ""
@@ -1742,15 +1783,15 @@ msgstr ""
 msgid "Unrecognized spell checker"
 msgstr ""
 
-#: lib/spellcheck.tcl:180
+#: lib/spellcheck.tcl:186
 msgid "No Suggestions"
 msgstr ""
 
-#: lib/spellcheck.tcl:381
+#: lib/spellcheck.tcl:387
 msgid "Unexpected EOF from spell checker"
 msgstr ""
 
-#: lib/spellcheck.tcl:385
+#: lib/spellcheck.tcl:391
 msgid "Spell Checker Failed"
 msgstr ""
 
index 11cc79bb5ec9c8f1a158ceb457157705b04d4adf..3db4fb68c526e522019e2edd302014652c306eb7 100644 (file)
@@ -3,47 +3,47 @@
 # This file is distributed under the same license as the git-gui package.
 # Paolo Ciarrocchi <paolo.ciarrocchi@gmail.com>, 2007
 # Michele Ballabio <barra_cuda@katamail.com>, 2007.
-# 
-# 
+#
+#
 msgid ""
 msgstr ""
 "Project-Id-Version: git-gui\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-03-14 07:18+0100\n"
-"PO-Revision-Date: 2008-03-12 22:12+0100\n"
+"POT-Creation-Date: 2008-08-02 14:45-0700\n"
+"PO-Revision-Date: 2008-08-03 16:04+0200\n"
 "Last-Translator: Michele Ballabio <barra_cuda@katamail.com>\n"
 "Language-Team: Italian <tp@lists.linux.it>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\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: errore grave"
 
-#: git-gui.sh:593
+#: git-gui.sh:644
 #, tcl-format
 msgid "Invalid font specified in %s:"
 msgstr "Caratteri non validi specificati in %s:"
 
-#: git-gui.sh:620
+#: git-gui.sh:674
 msgid "Main Font"
 msgstr "Caratteri principali"
 
-#: git-gui.sh:621
+#: git-gui.sh:675
 msgid "Diff/Console Font"
 msgstr "Caratteri per confronti e terminale"
 
-#: git-gui.sh:635
+#: git-gui.sh:689
 msgid "Cannot find git in PATH."
 msgstr "Impossibile trovare git nel PATH"
 
-#: git-gui.sh:662
+#: git-gui.sh:716
 msgid "Cannot parse Git version string:"
 msgstr "Impossibile determinare la versione di Git:"
 
-#: git-gui.sh:680
+#: git-gui.sh:734
 #, tcl-format
 msgid ""
 "Git version cannot be determined.\n"
@@ -62,380 +62,381 @@ msgstr ""
 "\n"
 "Assumere che '%s' sia alla versione 1.5.0?\n"
 
-#: git-gui.sh:918
+#: git-gui.sh:972
 msgid "Git directory not found:"
 msgstr "Non trovo la directory di git: "
 
-#: git-gui.sh:925
+#: git-gui.sh:979
 msgid "Cannot move to top of working directory:"
 msgstr "Impossibile spostarsi sulla directory principale del progetto:"
 
-#: git-gui.sh:932
+#: git-gui.sh:986
 msgid "Cannot use funny .git directory:"
 msgstr "Impossibile usare una .git directory strana:"
 
-#: git-gui.sh:937
+#: git-gui.sh:991
 msgid "No working directory"
 msgstr "Nessuna directory di lavoro"
 
-#: git-gui.sh:1084 lib/checkout_op.tcl:283
+#: git-gui.sh:1138 lib/checkout_op.tcl:305
 msgid "Refreshing file status..."
 msgstr "Controllo dello stato dei file in corso..."
 
-#: git-gui.sh:1149
+#: git-gui.sh:1194
 msgid "Scanning for modified files ..."
 msgstr "Ricerca di file modificati in corso..."
 
-#: git-gui.sh:1324 lib/browser.tcl:246
+#: git-gui.sh:1369 lib/browser.tcl:246
 msgid "Ready."
 msgstr "Pronto."
 
-#: git-gui.sh:1590
+#: git-gui.sh:1635
 msgid "Unmodified"
 msgstr "Non modificato"
 
-#: git-gui.sh:1592
+#: git-gui.sh:1637
 msgid "Modified, not staged"
 msgstr "Modificato, non preparato per una nuova revisione"
 
-#: git-gui.sh:1593 git-gui.sh:1598
+#: git-gui.sh:1638 git-gui.sh:1643
 msgid "Staged for commit"
 msgstr "Preparato per una nuova revisione"
 
-#: git-gui.sh:1594 git-gui.sh:1599
+#: git-gui.sh:1639 git-gui.sh:1644
 msgid "Portions staged for commit"
 msgstr "Parti preparate per una nuova revisione"
 
-#: git-gui.sh:1595 git-gui.sh:1600
+#: git-gui.sh:1640 git-gui.sh:1645
 msgid "Staged for commit, missing"
 msgstr "Preparato per una nuova revisione, mancante"
 
-#: git-gui.sh:1597
+#: git-gui.sh:1642
 msgid "Untracked, not staged"
 msgstr "Non tracciato, non preparato per una nuova revisione"
 
-#: git-gui.sh:1602
+#: git-gui.sh:1647
 msgid "Missing"
 msgstr "Mancante"
 
-#: git-gui.sh:1603
+#: git-gui.sh:1648
 msgid "Staged for removal"
 msgstr "Preparato per la rimozione"
 
-#: git-gui.sh:1604
+#: git-gui.sh:1649
 msgid "Staged for removal, still present"
 msgstr "Preparato alla rimozione, ancora presente"
 
-#: 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 "Richiede risoluzione dei conflitti"
 
-#: git-gui.sh:1644
+#: git-gui.sh:1689
 msgid "Starting gitk... please wait..."
 msgstr "Avvio di gitk... attendere..."
 
-#: git-gui.sh:1653
-#, tcl-format
-msgid ""
-"Unable to start gitk:\n"
-"\n"
-"%s does not exist"
-msgstr ""
-"Impossibile avviare gitk:\n"
-"\n"
-"%s non esiste"
+#: git-gui.sh:1698
+msgid "Couldn't find gitk in PATH"
+msgstr "Impossibile trovare gitk nel PATH"
 
-#: git-gui.sh:1860 lib/choose_repository.tcl:36
+#: git-gui.sh:1948 lib/choose_repository.tcl:36
 msgid "Repository"
 msgstr "Archivio"
 
-#: git-gui.sh:1861
+#: git-gui.sh:1949
 msgid "Edit"
 msgstr "Modifica"
 
-#: git-gui.sh:1863 lib/choose_rev.tcl:561
+#: git-gui.sh:1951 lib/choose_rev.tcl:561
 msgid "Branch"
 msgstr "Ramo"
 
-#: git-gui.sh:1866 lib/choose_rev.tcl:548
+#: git-gui.sh:1954 lib/choose_rev.tcl:548
 msgid "Commit@@noun"
 msgstr "Revisione"
 
-#: 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 "Fusione (Merge)"
 
-#: git-gui.sh:1870 lib/choose_rev.tcl:557
+#: git-gui.sh:1958 lib/choose_rev.tcl:557
 msgid "Remote"
 msgstr "Remoto"
 
-#: git-gui.sh:1879
+#: git-gui.sh:1967
 msgid "Browse Current Branch's Files"
 msgstr "Esplora i file del ramo attuale"
 
-#: git-gui.sh:1883
+#: git-gui.sh:1971
 msgid "Browse Branch Files..."
 msgstr "Esplora i file del ramo..."
 
-#: git-gui.sh:1888
+#: git-gui.sh:1976
 msgid "Visualize Current Branch's History"
 msgstr "Visualizza la cronologia del ramo attuale"
 
-#: git-gui.sh:1892
+#: git-gui.sh:1980
 msgid "Visualize All Branch History"
 msgstr "Visualizza la cronologia di tutti i rami"
 
-#: git-gui.sh:1899
+#: git-gui.sh:1987
 #, tcl-format
 msgid "Browse %s's Files"
 msgstr "Esplora i file di %s"
 
-#: git-gui.sh:1901
+#: git-gui.sh:1989
 #, tcl-format
 msgid "Visualize %s's History"
 msgstr "Visualizza la cronologia di %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 "Statistiche dell'archivio"
 
-#: git-gui.sh:1909 lib/database.tcl:34
+#: git-gui.sh:1997 lib/database.tcl:34
 msgid "Compress Database"
 msgstr "Comprimi l'archivio"
 
-#: git-gui.sh:1912
+#: git-gui.sh:2000
 msgid "Verify Database"
 msgstr "Verifica l'archivio"
 
-#: 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 "Crea icona desktop"
 
-#: 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 "Esci"
 
-#: git-gui.sh:1939
+#: git-gui.sh:2031
 msgid "Undo"
 msgstr "Annulla"
 
-#: git-gui.sh:1942
+#: git-gui.sh:2034
 msgid "Redo"
 msgstr "Ripeti"
 
-#: git-gui.sh:1946 git-gui.sh:2443
+#: git-gui.sh:2038 git-gui.sh:2545
 msgid "Cut"
 msgstr "Taglia"
 
-#: 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 "Copia"
 
-#: git-gui.sh:1952 git-gui.sh:2449
+#: git-gui.sh:2044 git-gui.sh:2551
 msgid "Paste"
 msgstr "Incolla"
 
-#: 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 "Elimina"
 
-#: 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 "Seleziona tutto"
 
-#: git-gui.sh:1968
+#: git-gui.sh:2060
 msgid "Create..."
 msgstr "Crea..."
 
-#: git-gui.sh:1974
+#: git-gui.sh:2066
 msgid "Checkout..."
 msgstr "Attiva..."
 
-#: git-gui.sh:1980
+#: git-gui.sh:2072
 msgid "Rename..."
 msgstr "Rinomina"
 
-#: git-gui.sh:1985 git-gui.sh:2085
+#: git-gui.sh:2077 git-gui.sh:2187
 msgid "Delete..."
 msgstr "Elimina..."
 
-#: git-gui.sh:1990
+#: git-gui.sh:2082
 msgid "Reset..."
 msgstr "Ripristina..."
 
-#: git-gui.sh:2002 git-gui.sh:2389
+#: git-gui.sh:2094 git-gui.sh:2491
 msgid "New Commit"
 msgstr "Nuova revisione"
 
-#: git-gui.sh:2010 git-gui.sh:2396
+#: git-gui.sh:2102 git-gui.sh:2498
 msgid "Amend Last Commit"
 msgstr "Correggi l'ultima revisione"
 
-#: 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 "Analizza nuovamente"
 
-#: git-gui.sh:2025
+#: git-gui.sh:2117
 msgid "Stage To Commit"
 msgstr "Prepara per una nuova revisione"
 
-#: git-gui.sh:2031
+#: git-gui.sh:2123
 msgid "Stage Changed Files To Commit"
 msgstr "Prepara i file modificati per una nuova revisione"
 
-#: git-gui.sh:2037
+#: git-gui.sh:2129
 msgid "Unstage From Commit"
 msgstr "Annulla preparazione"
 
-#: git-gui.sh:2042 lib/index.tcl:395
+#: git-gui.sh:2134 lib/index.tcl:395
 msgid "Revert Changes"
 msgstr "Annulla modifiche"
 
-#: 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 "Mostra meno contesto"
+
+#: git-gui.sh:2145 git-gui.sh:2706
+msgid "Show More Context"
+msgstr "Mostra più contesto"
+
+#: git-gui.sh:2151 git-gui.sh:2470 git-gui.sh:2569
 msgid "Sign Off"
 msgstr "Sign Off"
 
-#: git-gui.sh:2053 git-gui.sh:2372
+#: git-gui.sh:2155 git-gui.sh:2474
 msgid "Commit@@verb"
 msgstr "Nuova revisione"
 
-#: git-gui.sh:2064
+#: git-gui.sh:2166
 msgid "Local Merge..."
 msgstr "Fusione locale..."
 
-#: git-gui.sh:2069
+#: git-gui.sh:2171
 msgid "Abort Merge..."
 msgstr "Interrompi fusione..."
 
-#: git-gui.sh:2081
+#: git-gui.sh:2183
 msgid "Push..."
 msgstr "Propaga..."
 
-#: git-gui.sh:2092 lib/choose_repository.tcl:41
-msgid "Apple"
-msgstr "Apple"
-
-#: 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 "Informazioni su %s"
 
-#: git-gui.sh:2099
+#: git-gui.sh:2201
 msgid "Preferences..."
 msgstr "Preferenze..."
 
-#: git-gui.sh:2107 git-gui.sh:2639
+#: git-gui.sh:2209 git-gui.sh:2740
 msgid "Options..."
 msgstr "Opzioni..."
 
-#: git-gui.sh:2113 lib/choose_repository.tcl:47
+#: git-gui.sh:2215 lib/choose_repository.tcl:47
 msgid "Help"
 msgstr "Aiuto"
 
-#: git-gui.sh:2154
+#: git-gui.sh:2256
 msgid "Online Documentation"
 msgstr "Documentazione sul web"
 
-#: git-gui.sh:2238
+#: git-gui.sh:2340
 #, tcl-format
 msgid "fatal: cannot stat path %s: No such file or directory"
 msgstr ""
 "errore grave: impossibile effettuare lo stat del path %s: file o directory "
 "non trovata"
 
-#: git-gui.sh:2271
+#: git-gui.sh:2373
 msgid "Current Branch:"
 msgstr "Ramo attuale:"
 
-#: git-gui.sh:2292
+#: git-gui.sh:2394
 msgid "Staged Changes (Will Commit)"
 msgstr "Modifiche preparate (saranno nella nuova revisione)"
 
-#: git-gui.sh:2312
+#: git-gui.sh:2414
 msgid "Unstaged Changes"
 msgstr "Modifiche non preparate"
 
-#: git-gui.sh:2362
+#: git-gui.sh:2464
 msgid "Stage Changed"
 msgstr "Prepara modificati"
 
-#: 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 "Propaga (Push)"
 
-#: git-gui.sh:2408
+#: git-gui.sh:2510
 msgid "Initial Commit Message:"
 msgstr "Messaggio di revisione iniziale:"
 
-#: git-gui.sh:2409
+#: git-gui.sh:2511
 msgid "Amended Commit Message:"
 msgstr "Messaggio di revisione corretto:"
 
-#: git-gui.sh:2410
+#: git-gui.sh:2512
 msgid "Amended Initial Commit Message:"
 msgstr "Messaggio iniziale di revisione corretto:"
 
-#: git-gui.sh:2411
+#: git-gui.sh:2513
 msgid "Amended Merge Commit Message:"
 msgstr "Messaggio di fusione corretto:"
 
-#: git-gui.sh:2412
+#: git-gui.sh:2514
 msgid "Merge Commit Message:"
 msgstr "Messaggio di fusione:"
 
-#: git-gui.sh:2413
+#: git-gui.sh:2515
 msgid "Commit Message:"
 msgstr "Messaggio di revisione:"
 
-#: 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 "Copia tutto"
 
-#: git-gui.sh:2483 lib/blame.tcl:107
+#: git-gui.sh:2585 lib/blame.tcl:100
 msgid "File:"
 msgstr "File:"
 
-#: git-gui.sh:2589
+#: git-gui.sh:2691
 msgid "Apply/Reverse Hunk"
 msgstr "Applica/Inverti sezione"
 
-#: git-gui.sh:2595
-msgid "Show Less Context"
-msgstr "Mostra meno contesto"
-
-#: git-gui.sh:2602
-msgid "Show More Context"
-msgstr "Mostra più contesto"
+#: git-gui.sh:2696
+msgid "Apply/Reverse Line"
+msgstr "Applica/Inverti riga"
 
-#: git-gui.sh:2610
+#: git-gui.sh:2711
 msgid "Refresh"
 msgstr "Rinfresca"
 
-#: git-gui.sh:2631
+#: git-gui.sh:2732
 msgid "Decrease Font Size"
 msgstr "Diminuisci dimensione caratteri"
 
-#: git-gui.sh:2635
+#: git-gui.sh:2736
 msgid "Increase Font Size"
 msgstr "Aumenta dimensione caratteri"
 
-#: git-gui.sh:2646
+#: git-gui.sh:2747
 msgid "Unstage Hunk From Commit"
-msgstr "Sezione non preparata per una nuova revisione"
+msgstr "Annulla preparazione della sezione per una nuova revisione"
+
+#: git-gui.sh:2748
+msgid "Unstage Line From Commit"
+msgstr "Annulla preparazione della linea per una nuova revisione"
 
-#: git-gui.sh:2648
+#: git-gui.sh:2750
 msgid "Stage Hunk For Commit"
 msgstr "Prepara sezione per una nuova revisione"
 
-#: git-gui.sh:2667
+#: git-gui.sh:2751
+msgid "Stage Line For Commit"
+msgstr "Prepara linea per una nuova revisione"
+
+#: git-gui.sh:2771
 msgid "Initializing..."
 msgstr "Inizializzazione..."
 
-#: git-gui.sh:2762
+#: git-gui.sh:2876
 #, tcl-format
 msgid ""
 "Possible environment issues exist.\n"
@@ -452,7 +453,7 @@ msgstr ""
 "da %s:\n"
 "\n"
 
-#: git-gui.sh:2792
+#: git-gui.sh:2906
 msgid ""
 "\n"
 "This is due to a known issue with the\n"
@@ -462,7 +463,7 @@ msgstr ""
 "Ciò è dovuto a un problema conosciuto\n"
 "causato dall'eseguibile Tcl distribuito da Cygwin."
 
-#: git-gui.sh:2797
+#: git-gui.sh:2911
 #, tcl-format
 msgid ""
 "\n"
@@ -482,64 +483,80 @@ msgstr ""
 msgid "git-gui - a graphical user interface for Git."
 msgstr "git-gui - un'interfaccia grafica per Git."
 
-#: lib/blame.tcl:77
+#: lib/blame.tcl:70
 msgid "File Viewer"
 msgstr "Mostra file"
 
-#: lib/blame.tcl:81
+#: lib/blame.tcl:74
 msgid "Commit:"
 msgstr "Revisione:"
 
-#: lib/blame.tcl:264
+#: lib/blame.tcl:257
 msgid "Copy Commit"
 msgstr "Copia revisione"
 
-#: lib/blame.tcl:384
+#: lib/blame.tcl:260
+msgid "Do Full Copy Detection"
+msgstr "Ricerca accurata delle copie"
+
+#: lib/blame.tcl:388
 #, tcl-format
 msgid "Reading %s..."
 msgstr "Lettura di %s..."
 
-#: lib/blame.tcl:488
+#: lib/blame.tcl:492
 msgid "Loading copy/move tracking annotations..."
 msgstr "Caricamento annotazioni per copie/spostamenti..."
 
-#: lib/blame.tcl:508
+#: lib/blame.tcl:512
 msgid "lines annotated"
 msgstr "linee annotate"
 
-#: lib/blame.tcl:689
+#: lib/blame.tcl:704
 msgid "Loading original location annotations..."
 msgstr "Caricamento annotazioni per posizione originaria..."
 
-#: lib/blame.tcl:692
+#: lib/blame.tcl:707
 msgid "Annotation complete."
 msgstr "Annotazione completata."
 
-#: lib/blame.tcl:746
+#: lib/blame.tcl:737
+msgid "Busy"
+msgstr "Occupato"
+
+#: lib/blame.tcl:738
+msgid "Annotation process is already running."
+msgstr "Il processo di annotazione è già in corso."
+
+#: lib/blame.tcl:777
+msgid "Running thorough copy detection..."
+msgstr "Ricerca accurata delle copie in corso..."
+
+#: lib/blame.tcl:827
 msgid "Loading annotation..."
 msgstr "Caricamento annotazioni..."
 
-#: lib/blame.tcl:802
+#: lib/blame.tcl:883
 msgid "Author:"
 msgstr "Autore:"
 
-#: lib/blame.tcl:806
+#: lib/blame.tcl:887
 msgid "Committer:"
 msgstr "Revisione creata da:"
 
-#: lib/blame.tcl:811
+#: lib/blame.tcl:892
 msgid "Original File:"
 msgstr "File originario:"
 
-#: lib/blame.tcl:925
+#: lib/blame.tcl:1006
 msgid "Originally By:"
 msgstr "In origine da:"
 
-#: lib/blame.tcl:931
+#: lib/blame.tcl:1012
 msgid "In File:"
 msgstr "Nel file:"
 
-#: lib/blame.tcl:936
+#: lib/blame.tcl:1017
 msgid "Copied Or Moved Here By:"
 msgstr "Copiato o spostato qui da:"
 
@@ -553,7 +570,7 @@ msgstr "Attiva"
 
 #: 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 "Annulla"
@@ -562,7 +579,7 @@ msgstr "Annulla"
 msgid "Revision"
 msgstr "Revisione"
 
-#: 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 "Opzioni"
 
@@ -614,7 +631,7 @@ msgstr "No"
 msgid "Fast Forward Only"
 msgstr "Solo 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 "Ripristina"
 
@@ -705,7 +722,7 @@ msgstr "Nuovo Nome:"
 msgid "Please select a branch to rename."
 msgstr "Scegliere un ramo da rinominare."
 
-#: 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 "Il ramo '%s' esiste già."
@@ -737,31 +754,36 @@ msgid "Browse Branch Files"
 msgstr "Esplora i file del ramo"
 
 #: 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 "Esplora"
 
-#: lib/checkout_op.tcl:79
+#: lib/checkout_op.tcl:84
 #, tcl-format
 msgid "Fetching %s from %s"
 msgstr "Recupero %s da %s"
 
-#: lib/checkout_op.tcl:127
+#: lib/checkout_op.tcl:132
 #, tcl-format
 msgid "fatal: Cannot resolve %s"
 msgstr "errore grave: impossibile risolvere %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 "Chiudi"
 
-#: lib/checkout_op.tcl:169
+#: lib/checkout_op.tcl:174
 #, tcl-format
 msgid "Branch '%s' does not exist."
 msgstr "Il ramo '%s' non esiste."
 
-#: lib/checkout_op.tcl:206
+#: lib/checkout_op.tcl:193
+#, tcl-format
+msgid "Failed to configure simplified git-pull for '%s'."
+msgstr "Impossibile configurare git-pull semplificato per '%s'."
+
+#: lib/checkout_op.tcl:228
 #, tcl-format
 msgid ""
 "Branch '%s' already exists.\n"
@@ -774,22 +796,22 @@ msgstr ""
 "Non può effettuare un 'fast-forward' a %s.\n"
 "E' necessaria una fusione."
 
-#: lib/checkout_op.tcl:220
+#: lib/checkout_op.tcl:242
 #, tcl-format
 msgid "Merge strategy '%s' not supported."
 msgstr "La strategia di fusione '%s' non è supportata."
 
-#: lib/checkout_op.tcl:239
+#: lib/checkout_op.tcl:261
 #, tcl-format
 msgid "Failed to update '%s'."
 msgstr "Impossibile aggiornare '%s'."
 
-#: lib/checkout_op.tcl:251
+#: lib/checkout_op.tcl:273
 msgid "Staging area (index) is already locked."
 msgstr ""
 "L'area di preparazione per una nuova revisione (indice) è già bloccata."
 
-#: lib/checkout_op.tcl:266
+#: lib/checkout_op.tcl:288
 msgid ""
 "Last scanned state does not match repository state.\n"
 "\n"
@@ -806,30 +828,30 @@ msgstr ""
 "\n"
 "La nuova analisi comincerà ora.\n"
 
-#: lib/checkout_op.tcl:322
+#: lib/checkout_op.tcl:344
 #, tcl-format
 msgid "Updating working directory to '%s'..."
 msgstr "Aggiornamento della directory di lavoro a '%s' in corso..."
 
-#: lib/checkout_op.tcl:323
+#: lib/checkout_op.tcl:345
 msgid "files checked out"
 msgstr "file presenti nella directory di lavoro"
 
-#: lib/checkout_op.tcl:353
+#: lib/checkout_op.tcl:375
 #, tcl-format
 msgid "Aborted checkout of '%s' (file level merging is required)."
 msgstr "Attivazione di '%s' fallita (richiesta una fusione a livello file)."
 
-#: lib/checkout_op.tcl:354
+#: lib/checkout_op.tcl:376
 msgid "File level merge required."
 msgstr "E' richiesta una fusione a livello file."
 
-#: lib/checkout_op.tcl:358
+#: lib/checkout_op.tcl:380
 #, tcl-format
 msgid "Staying on branch '%s'."
 msgstr "Si rimarrà sul ramo '%s'."
 
-#: lib/checkout_op.tcl:429
+#: lib/checkout_op.tcl:451
 msgid ""
 "You are no longer on a local branch.\n"
 "\n"
@@ -841,31 +863,31 @@ msgstr ""
 "Se si vuole rimanere su un ramo, crearne uno ora a partire da 'Questa "
 "revisione attiva staccata'."
 
-#: 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 "Attivazione di '%s' completata."
 
-#: lib/checkout_op.tcl:478
+#: lib/checkout_op.tcl:500
 #, tcl-format
 msgid "Resetting '%s' to '%s' will lose the following commits:"
 msgstr ""
 "Ripristinare '%s' a '%s' comporterà la perdita delle seguenti revisioni:"
 
-#: lib/checkout_op.tcl:500
+#: lib/checkout_op.tcl:522
 msgid "Recovering lost commits may not be easy."
 msgstr "Ricomporre le revisioni perdute potrebbe non essere semplice."
 
-#: lib/checkout_op.tcl:505
+#: lib/checkout_op.tcl:527
 #, tcl-format
 msgid "Reset '%s'?"
 msgstr "Ripristinare '%s'?"
 
-#: lib/checkout_op.tcl:510 lib/merge.tcl:163
+#: lib/checkout_op.tcl:532 lib/merge.tcl:163
 msgid "Visualize"
 msgstr "Visualizza"
 
-#: lib/checkout_op.tcl:578
+#: lib/checkout_op.tcl:600
 #, tcl-format
 msgid ""
 "Failed to set current branch.\n"
@@ -919,7 +941,7 @@ msgstr "Crea nuovo archivio"
 msgid "New..."
 msgstr "Nuovo..."
 
-#: 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 "Clona archivio esistente"
 
@@ -927,7 +949,7 @@ msgstr "Clona archivio esistente"
 msgid "Clone..."
 msgstr "Clona..."
 
-#: 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 "Apri archivio esistente"
 
@@ -949,188 +971,188 @@ msgstr "Apri archivio recente:"
 msgid "Failed to create repository %s:"
 msgstr "Impossibile creare l'archivio %s:"
 
-#: lib/choose_repository.tcl:381 lib/choose_repository.tcl:478
+#: lib/choose_repository.tcl:381 lib/choose_repository.tcl:476
 msgid "Directory:"
 msgstr "Directory:"
 
-#: 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 "Archivio Git"
 
-#: lib/choose_repository.tcl:437
+#: lib/choose_repository.tcl:435
 #, tcl-format
 msgid "Directory %s already exists."
 msgstr "La directory %s esiste già."
 
-#: lib/choose_repository.tcl:441
+#: lib/choose_repository.tcl:439
 #, tcl-format
 msgid "File %s already exists."
 msgstr "Il file %s esiste già."
 
-#: lib/choose_repository.tcl:455
+#: lib/choose_repository.tcl:453
 msgid "Clone"
 msgstr "Clona"
 
-#: 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 "Tipo di clone:"
 
-#: lib/choose_repository.tcl:495
+#: lib/choose_repository.tcl:493
 msgid "Standard (Fast, Semi-Redundant, Hardlinks)"
 msgstr "Standard (veloce, semi-ridondante, con hardlink)"
 
-#: lib/choose_repository.tcl:501
+#: lib/choose_repository.tcl:499
 msgid "Full Copy (Slower, Redundant Backup)"
 msgstr "Copia completa (più lento, backup ridondante)"
 
-#: lib/choose_repository.tcl:507
+#: lib/choose_repository.tcl:505
 msgid "Shared (Fastest, Not Recommended, No Backup)"
 msgstr "Shared (il più veloce, non raccomandato, nessun backup)"
 
-#: 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 non è un archivio Git."
 
-#: lib/choose_repository.tcl:579
+#: lib/choose_repository.tcl:577
 msgid "Standard only available for local repository."
 msgstr "Standard è disponibile solo per archivi locali."
 
-#: lib/choose_repository.tcl:583
+#: lib/choose_repository.tcl:581
 msgid "Shared only available for local repository."
 msgstr "Shared è disponibile solo per archivi locali."
 
-#: lib/choose_repository.tcl:604
+#: lib/choose_repository.tcl:602
 #, tcl-format
 msgid "Location %s already exists."
 msgstr "Il file/directory %s esiste già."
 
-#: lib/choose_repository.tcl:615
+#: lib/choose_repository.tcl:613
 msgid "Failed to configure origin"
 msgstr "Impossibile configurare origin"
 
-#: lib/choose_repository.tcl:627
+#: lib/choose_repository.tcl:625
 msgid "Counting objects"
 msgstr "Calcolo oggetti"
 
-#: lib/choose_repository.tcl:628
+#: lib/choose_repository.tcl:626
 msgid "buckets"
 msgstr ""
 
-#: lib/choose_repository.tcl:652
+#: lib/choose_repository.tcl:650
 #, tcl-format
 msgid "Unable to copy objects/info/alternates: %s"
 msgstr "Impossibile copiare oggetti/info/alternate: %s"
 
-#: lib/choose_repository.tcl:688
+#: lib/choose_repository.tcl:686
 #, tcl-format
 msgid "Nothing to clone from %s."
 msgstr "Niente da clonare da %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 "Il ramo 'master' non è stato inizializzato."
 
-#: lib/choose_repository.tcl:703
+#: lib/choose_repository.tcl:701
 msgid "Hardlinks are unavailable.  Falling back to copying."
 msgstr "Impossibile utilizzare gli hardlink. Si ricorrerà alla copia."
 
-#: lib/choose_repository.tcl:715
+#: lib/choose_repository.tcl:713
 #, tcl-format
 msgid "Cloning from %s"
 msgstr "Clonazione da %s"
 
-#: lib/choose_repository.tcl:746
+#: lib/choose_repository.tcl:744
 msgid "Copying objects"
 msgstr "Copia degli oggetti"
 
-#: 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 "Impossibile copiare oggetto: %s"
 
-#: lib/choose_repository.tcl:781
+#: lib/choose_repository.tcl:779
 msgid "Linking objects"
 msgstr "Collegamento oggetti"
 
-#: lib/choose_repository.tcl:782
+#: lib/choose_repository.tcl:780
 msgid "objects"
 msgstr "oggetti"
 
-#: lib/choose_repository.tcl:790
+#: lib/choose_repository.tcl:788
 #, tcl-format
 msgid "Unable to hardlink object: %s"
 msgstr "Hardlink impossibile sull'oggetto: %s"
 
-#: lib/choose_repository.tcl:845
+#: lib/choose_repository.tcl:843
 msgid "Cannot fetch branches and objects.  See console output for details."
 msgstr ""
 "Impossibile recuperare rami e oggetti. Controllare i dettagli forniti dalla "
 "console."
 
-#: lib/choose_repository.tcl:856
+#: lib/choose_repository.tcl:854
 msgid "Cannot fetch tags.  See console output for details."
 msgstr ""
 "Impossibile recuperare le etichette. Controllare i dettagli forniti dalla "
 "console."
 
-#: lib/choose_repository.tcl:880
+#: lib/choose_repository.tcl:878
 msgid "Cannot determine HEAD.  See console output for details."
 msgstr ""
 "Impossibile determinare HEAD. Controllare i dettagli forniti dalla console."
 
-#: lib/choose_repository.tcl:889
+#: lib/choose_repository.tcl:887
 #, tcl-format
 msgid "Unable to cleanup %s"
 msgstr "Impossibile ripulire %s"
 
-#: lib/choose_repository.tcl:895
+#: lib/choose_repository.tcl:893
 msgid "Clone failed."
 msgstr "Clonazione non riuscita."
 
-#: lib/choose_repository.tcl:902
+#: lib/choose_repository.tcl:900
 msgid "No default branch obtained."
 msgstr "Non è stato trovato un ramo predefinito."
 
-#: lib/choose_repository.tcl:913
+#: lib/choose_repository.tcl:911
 #, tcl-format
 msgid "Cannot resolve %s as a commit."
 msgstr "Impossibile risolvere %s come una revisione."
 
-#: lib/choose_repository.tcl:925
+#: lib/choose_repository.tcl:923
 msgid "Creating working directory"
 msgstr "Creazione directory di lavoro"
 
-#: 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 "file"
 
-#: lib/choose_repository.tcl:955
+#: lib/choose_repository.tcl:953
 msgid "Initial file checkout failed."
 msgstr "Attivazione iniziale non riuscita."
 
-#: lib/choose_repository.tcl:971
+#: lib/choose_repository.tcl:969
 msgid "Open"
 msgstr "Apri"
 
-#: lib/choose_repository.tcl:981
+#: lib/choose_repository.tcl:979
 msgid "Repository:"
 msgstr "Archivio:"
 
-#: lib/choose_repository.tcl:1031
+#: lib/choose_repository.tcl:1027
 #, tcl-format
 msgid "Failed to open repository %s:"
 msgstr "Impossibile accedere all'archivio %s:"
@@ -1423,7 +1445,7 @@ msgstr ""
 msgid "Invalid date from Git: %s"
 msgstr "Git ha restituito una data non valida: %s"
 
-#: lib/diff.tcl:42
+#: lib/diff.tcl:44
 #, tcl-format
 msgid ""
 "No differences detected.\n"
@@ -1446,40 +1468,48 @@ msgstr ""
 "Si procederà automaticamente ad una nuova analisi per trovare altri file che "
 "potrebbero avere lo stesso stato."
 
-#: lib/diff.tcl:81
+#: lib/diff.tcl:83
 #, tcl-format
 msgid "Loading diff of %s..."
 msgstr "Caricamento delle differenze di %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 "Impossibile visualizzare %s"
 
-#: lib/diff.tcl:115
+#: lib/diff.tcl:117
 msgid "Error loading file:"
 msgstr "Errore nel caricamento del file:"
 
-#: lib/diff.tcl:122
+#: lib/diff.tcl:124
 msgid "Git Repository (subproject)"
 msgstr "Archivio Git (sottoprogetto)"
 
-#: lib/diff.tcl:134
+#: lib/diff.tcl:136
 msgid "* Binary file (not showing content)."
 msgstr "* File binario (il contenuto non sarà mostrato)."
 
-#: lib/diff.tcl:185
+#: lib/diff.tcl:191
 msgid "Error loading diff:"
 msgstr "Errore nel caricamento delle differenze:"
 
-#: lib/diff.tcl:303
+#: lib/diff.tcl:313
 msgid "Failed to unstage selected hunk."
 msgstr "Impossibile rimuovere la sezione scelta dalla nuova revisione."
 
-#: lib/diff.tcl:310
+#: lib/diff.tcl:320
 msgid "Failed to stage selected hunk."
 msgstr "Impossibile preparare la sezione scelta per una nuova revisione."
 
+#: lib/diff.tcl:386
+msgid "Failed to unstage selected line."
+msgstr "Impossibile rimuovere la riga scelta dalla nuova revisione."
+
+#: lib/diff.tcl:394
+msgid "Failed to stage selected line."
+msgstr "Impossibile preparare la riga scelta per una nuova revisione."
+
 #: lib/error.tcl:20 lib/error.tcl:114
 msgid "error"
 msgstr "errore"
@@ -1689,11 +1719,11 @@ msgstr "Interruzione"
 msgid "files reset"
 msgstr "ripristino file"
 
-#: lib/merge.tcl:265
+#: lib/merge.tcl:266
 msgid "Abort failed."
 msgstr "Interruzione non riuscita."
 
-#: lib/merge.tcl:267
+#: lib/merge.tcl:268
 msgid "Abort completed.  Ready."
 msgstr "Interruzione completata. Pronto."
 
@@ -1748,42 +1778,62 @@ msgid "Match Tracking Branches"
 msgstr "Appaia duplicati locali di rami remoti"
 
 #: lib/option.tcl:126
+msgid "Blame Copy Only On Changed Files"
+msgstr "Ricerca copie solo nei file modificati"
+
+#: lib/option.tcl:127
+msgid "Minimum Letters To Blame Copy On"
+msgstr "Numero minimo di lettere che attivano la ricerca delle copie"
+
+#: lib/option.tcl:128
 msgid "Number of Diff Context Lines"
 msgstr "Numero di linee di contesto nelle differenze"
 
-#: lib/option.tcl:127
+#: lib/option.tcl:129
 msgid "Commit Message Text Width"
 msgstr "Larghezza del messaggio di revisione"
 
-#: lib/option.tcl:128
+#: lib/option.tcl:130
 msgid "New Branch Name Template"
 msgstr "Modello per il nome di un nuovo ramo"
 
-#: lib/option.tcl:192
+#: lib/option.tcl:194
 msgid "Spelling Dictionary:"
 msgstr "Lingua dizionario:"
 
-#: lib/option.tcl:216
+#: lib/option.tcl:218
 msgid "Change Font"
 msgstr "Cambia caratteri"
 
-#: lib/option.tcl:220
+#: lib/option.tcl:222
 #, tcl-format
 msgid "Choose %s"
 msgstr "Scegli %s"
 
-#: lib/option.tcl:226
+#: lib/option.tcl:228
 msgid "pt."
 msgstr "pt."
 
-#: lib/option.tcl:240
+#: lib/option.tcl:242
 msgid "Preferences"
 msgstr "Preferenze"
 
-#: lib/option.tcl:275
+#: lib/option.tcl:277
 msgid "Failed to completely save options:"
 msgstr "Impossibile salvare completamente le opzioni:"
 
+#: lib/remote.tcl:165
+msgid "Prune from"
+msgstr "Effettua potatura da"
+
+#: lib/remote.tcl:170
+msgid "Fetch from"
+msgstr "Recupera da"
+
+#: lib/remote.tcl:213
+msgid "Push to"
+msgstr "Propaga verso"
+
 #: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34
 msgid "Delete Remote Branch"
 msgstr "Cancella ramo remoto"
@@ -1868,18 +1918,6 @@ msgstr "Nessun archivio selezionato."
 msgid "Scanning %s..."
 msgstr "Analisi in corso %s..."
 
-#: lib/remote.tcl:165
-msgid "Prune from"
-msgstr "Effettua potatura da"
-
-#: lib/remote.tcl:170
-msgid "Fetch from"
-msgstr "Recupera da"
-
-#: lib/remote.tcl:213
-msgid "Push to"
-msgstr "Propaga verso"
-
 #: lib/shortcut.tcl:20 lib/shortcut.tcl:61
 msgid "Cannot write shortcut:"
 msgstr "Impossibile scrivere shortcut:"
@@ -1911,17 +1949,17 @@ msgstr "Il correttore ortografico ha riportato un errore all'avvio"
 
 #: lib/spellcheck.tcl:80
 msgid "Unrecognized spell checker"
-msgstr "Correttore ortografico sconosciuto"
+msgstr "Correttore ortografico non riconosciuto"
 
-#: lib/spellcheck.tcl:180
+#: lib/spellcheck.tcl:186
 msgid "No Suggestions"
 msgstr "Nessun suggerimento"
 
-#: lib/spellcheck.tcl:381
+#: lib/spellcheck.tcl:387
 msgid "Unexpected EOF from spell checker"
 msgstr "Il correttore ortografico ha mandato un EOF inaspettato"
 
-#: lib/spellcheck.tcl:385
+#: lib/spellcheck.tcl:391
 msgid "Spell Checker Failed"
 msgstr "Errore nel correttore ortografico"
 
index 28e6d6246b5a07bc0dfe29dde4727be0cf0ba40c..5db44a4ada05ad5c883adca30c3c3dd8d775698d 100644 (file)
@@ -8,41 +8,41 @@ msgid ""
 msgstr ""
 "Project-Id-Version: git-gui\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-03-14 07:18+0100\n"
-"PO-Revision-Date: 2008-03-15 20:12+0900\n"
-"Last-Translator: しらいし ななこ <nanako3@bluebottle.com>\n"
+"POT-Creation-Date: 2008-08-02 14:45-0700\n"
+"PO-Revision-Date: 2008-08-03 17:00+0900\n"
+"Last-Translator: しらいし ななこ <nanako3@lavabit.com>\n"
 "Language-Team: Japanese\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\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: 致命的なエラー"
 
-#: git-gui.sh:593
+#: git-gui.sh:644
 #, tcl-format
 msgid "Invalid font specified in %s:"
 msgstr "%s に無効なフォントが指定されています:"
 
-#: git-gui.sh:620
+#: git-gui.sh:674
 msgid "Main Font"
 msgstr "主フォント"
 
-#: git-gui.sh:621
+#: git-gui.sh:675
 msgid "Diff/Console Font"
 msgstr "diff/コンソール・フォント"
 
-#: git-gui.sh:635
+#: git-gui.sh:689
 msgid "Cannot find git in PATH."
 msgstr "PATH 中に git が見つかりません"
 
-#: git-gui.sh:662
+#: git-gui.sh:716
 msgid "Cannot parse Git version string:"
 msgstr "Git バージョン名が理解できません:"
 
-#: git-gui.sh:680
+#: git-gui.sh:734
 #, tcl-format
 msgid ""
 "Git version cannot be determined.\n"
@@ -61,380 +61,381 @@ msgstr ""
 "\n"
 "'%s' はバージョン 1.5.0 と思って良いですか?\n"
 
-#: git-gui.sh:918
+#: git-gui.sh:972
 msgid "Git directory not found:"
 msgstr "Git ディレクトリが見つかりません:"
 
-#: git-gui.sh:925
+#: git-gui.sh:979
 msgid "Cannot move to top of working directory:"
 msgstr "作業ディレクトリの最上位に移動できません"
 
-#: git-gui.sh:932
+#: git-gui.sh:986
 msgid "Cannot use funny .git directory:"
 msgstr "変な .git ディレクトリは使えません"
 
-#: git-gui.sh:937
+#: git-gui.sh:991
 msgid "No working directory"
 msgstr "作業ディレクトリがありません"
 
-#: git-gui.sh:1084 lib/checkout_op.tcl:283
+#: git-gui.sh:1138 lib/checkout_op.tcl:305
 msgid "Refreshing file status..."
 msgstr "ファイル状態を更新しています…"
 
-#: git-gui.sh:1149
+#: git-gui.sh:1194
 msgid "Scanning for modified files ..."
 msgstr "変更されたファイルをスキャンしています…"
 
-#: git-gui.sh:1324 lib/browser.tcl:246
+#: git-gui.sh:1369 lib/browser.tcl:246
 msgid "Ready."
 msgstr "準備完了"
 
-#: git-gui.sh:1590
+#: git-gui.sh:1635
 msgid "Unmodified"
 msgstr "変更無し"
 
-#: git-gui.sh:1592
+#: git-gui.sh:1637
 msgid "Modified, not staged"
 msgstr "変更あり、コミット未予定"
 
-#: git-gui.sh:1593 git-gui.sh:1598
+#: git-gui.sh:1638 git-gui.sh:1643
 msgid "Staged for commit"
 msgstr "コミット予定済"
 
-#: git-gui.sh:1594 git-gui.sh:1599
+#: git-gui.sh:1639 git-gui.sh:1644
 msgid "Portions staged for commit"
 msgstr "部分的にコミット予定済"
 
-#: git-gui.sh:1595 git-gui.sh:1600
+#: git-gui.sh:1640 git-gui.sh:1645
 msgid "Staged for commit, missing"
 msgstr "コミット予定済、ファイル無し"
 
-#: git-gui.sh:1597
+#: git-gui.sh:1642
 msgid "Untracked, not staged"
 msgstr "管理外、コミット未予定"
 
-#: git-gui.sh:1602
+#: git-gui.sh:1647
 msgid "Missing"
 msgstr "ファイル無し"
 
-#: git-gui.sh:1603
+#: git-gui.sh:1648
 msgid "Staged for removal"
 msgstr "削除予定済"
 
-#: git-gui.sh:1604
+#: git-gui.sh:1649
 msgid "Staged for removal, still present"
 msgstr "削除予定済、ファイル未削除"
 
-#: 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 "要マージ解決"
 
-#: git-gui.sh:1644
+#: git-gui.sh:1689
 msgid "Starting gitk... please wait..."
 msgstr "gitk を起動中…お待ち下さい…"
 
-#: git-gui.sh:1653
-#, tcl-format
-msgid ""
-"Unable to start gitk:\n"
-"\n"
-"%s does not exist"
-msgstr ""
-"gitk を起動できません:\n"
-"\n"
-"%s がありません"
+#: git-gui.sh:1698
+msgid "Couldn't find gitk in PATH"
+msgstr "PATH 中に gitk が見つかりません"
 
-#: git-gui.sh:1860 lib/choose_repository.tcl:36
+#: git-gui.sh:1948 lib/choose_repository.tcl:36
 msgid "Repository"
 msgstr "リポジトリ"
 
-#: git-gui.sh:1861
+#: git-gui.sh:1949
 msgid "Edit"
 msgstr "編集"
 
-#: git-gui.sh:1863 lib/choose_rev.tcl:561
+#: git-gui.sh:1951 lib/choose_rev.tcl:561
 msgid "Branch"
 msgstr "ブランチ"
 
-#: git-gui.sh:1866 lib/choose_rev.tcl:548
+#: git-gui.sh:1954 lib/choose_rev.tcl:548
 msgid "Commit@@noun"
 msgstr "コミット"
 
-#: 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 "マージ"
 
-#: git-gui.sh:1870 lib/choose_rev.tcl:557
+#: git-gui.sh:1958 lib/choose_rev.tcl:557
 msgid "Remote"
 msgstr "リモート"
 
-#: git-gui.sh:1879
+#: git-gui.sh:1967
 msgid "Browse Current Branch's Files"
 msgstr "現在のブランチのファイルを見る"
 
-#: git-gui.sh:1883
+#: git-gui.sh:1971
 msgid "Browse Branch Files..."
 msgstr "ブランチのファイルを見る…"
 
-#: git-gui.sh:1888
+#: git-gui.sh:1976
 msgid "Visualize Current Branch's History"
 msgstr "現在のブランチの履歴を見る"
 
-#: git-gui.sh:1892
+#: git-gui.sh:1980
 msgid "Visualize All Branch History"
 msgstr "全てのブランチの履歴を見る"
 
-#: git-gui.sh:1899
+#: git-gui.sh:1987
 #, tcl-format
 msgid "Browse %s's Files"
 msgstr "ブランチ %s のファイルを見る"
 
-#: git-gui.sh:1901
+#: git-gui.sh:1989
 #, tcl-format
 msgid "Visualize %s's History"
 msgstr "ブランチ %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 "データベース統計"
 
-#: git-gui.sh:1909 lib/database.tcl:34
+#: git-gui.sh:1997 lib/database.tcl:34
 msgid "Compress Database"
 msgstr "データベース圧縮"
 
-#: git-gui.sh:1912
+#: git-gui.sh:2000
 msgid "Verify Database"
 msgstr "データベース検証"
 
-#: 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 "デスクトップ・アイコンを作る"
 
-#: 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 "終了"
 
-#: git-gui.sh:1939
+#: git-gui.sh:2031
 msgid "Undo"
 msgstr "元に戻す"
 
-#: git-gui.sh:1942
+#: git-gui.sh:2034
 msgid "Redo"
 msgstr "やり直し"
 
-#: git-gui.sh:1946 git-gui.sh:2443
+#: git-gui.sh:2038 git-gui.sh:2545
 msgid "Cut"
 msgstr "切り取り"
 
-#: 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 "コピー"
 
-#: git-gui.sh:1952 git-gui.sh:2449
+#: git-gui.sh:2044 git-gui.sh:2551
 msgid "Paste"
 msgstr "貼り付け"
 
-#: 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 "削除"
 
-#: 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 "全て選択"
 
-#: git-gui.sh:1968
+#: git-gui.sh:2060
 msgid "Create..."
 msgstr "作成…"
 
-#: git-gui.sh:1974
+#: git-gui.sh:2066
 msgid "Checkout..."
 msgstr "チェックアウト"
 
-#: git-gui.sh:1980
+#: git-gui.sh:2072
 msgid "Rename..."
 msgstr "名前変更…"
 
-#: git-gui.sh:1985 git-gui.sh:2085
+#: git-gui.sh:2077 git-gui.sh:2187
 msgid "Delete..."
 msgstr "削除…"
 
-#: git-gui.sh:1990
+#: git-gui.sh:2082
 msgid "Reset..."
 msgstr "リセット…"
 
-#: git-gui.sh:2002 git-gui.sh:2389
+#: git-gui.sh:2094 git-gui.sh:2491
 msgid "New Commit"
 msgstr "新規コミット"
 
-#: git-gui.sh:2010 git-gui.sh:2396
+#: git-gui.sh:2102 git-gui.sh:2498
 msgid "Amend Last Commit"
 msgstr "最新コミットを訂正"
 
-#: 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 "再スキャン"
 
-#: git-gui.sh:2025
+#: git-gui.sh:2117
 msgid "Stage To Commit"
 msgstr "コミット予定する"
 
-#: git-gui.sh:2031
+#: git-gui.sh:2123
 msgid "Stage Changed Files To Commit"
 msgstr "変更されたファイルをコミット予定"
 
-#: git-gui.sh:2037
+#: git-gui.sh:2129
 msgid "Unstage From Commit"
 msgstr "コミットから降ろす"
 
-#: git-gui.sh:2042 lib/index.tcl:395
+#: git-gui.sh:2134 lib/index.tcl:395
 msgid "Revert Changes"
 msgstr "変更を元に戻す"
 
-#: 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 "文脈を少なく"
+
+#: git-gui.sh:2145 git-gui.sh:2706
+msgid "Show More Context"
+msgstr "文脈を多く"
+
+#: git-gui.sh:2151 git-gui.sh:2470 git-gui.sh:2569
 msgid "Sign Off"
 msgstr "署名"
 
-#: git-gui.sh:2053 git-gui.sh:2372
+#: git-gui.sh:2155 git-gui.sh:2474
 msgid "Commit@@verb"
 msgstr "コミット"
 
-#: git-gui.sh:2064
+#: git-gui.sh:2166
 msgid "Local Merge..."
 msgstr "ローカル・マージ…"
 
-#: git-gui.sh:2069
+#: git-gui.sh:2171
 msgid "Abort Merge..."
 msgstr "マージ中止…"
 
-#: git-gui.sh:2081
+#: git-gui.sh:2183
 msgid "Push..."
 msgstr "プッシュ…"
 
-#: git-gui.sh:2092 lib/choose_repository.tcl:41
-msgid "Apple"
-msgstr "りんご"
-
-#: 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 "%s について"
 
-#: git-gui.sh:2099
+#: git-gui.sh:2201
 msgid "Preferences..."
 msgstr "設定…"
 
-#: git-gui.sh:2107 git-gui.sh:2639
+#: git-gui.sh:2209 git-gui.sh:2740
 msgid "Options..."
 msgstr "オプション…"
 
-#: git-gui.sh:2113 lib/choose_repository.tcl:47
+#: git-gui.sh:2215 lib/choose_repository.tcl:47
 msgid "Help"
 msgstr "ヘルプ"
 
-#: git-gui.sh:2154
+#: git-gui.sh:2256
 msgid "Online Documentation"
 msgstr "オンライン・ドキュメント"
 
-#: git-gui.sh:2238
+#: git-gui.sh:2340
 #, tcl-format
 msgid "fatal: cannot stat path %s: No such file or directory"
 msgstr ""
 "致命的: パス %s が stat できません。そのようなファイルやディレクトリはありま"
 "せん"
 
-#: git-gui.sh:2271
+#: git-gui.sh:2373
 msgid "Current Branch:"
 msgstr "現在のブランチ"
 
-#: git-gui.sh:2292
+#: git-gui.sh:2394
 msgid "Staged Changes (Will Commit)"
 msgstr "ステージングされた(コミット予定済の)変更"
 
-#: git-gui.sh:2312
+#: git-gui.sh:2414
 msgid "Unstaged Changes"
 msgstr "コミット予定に入っていない変更"
 
-#: git-gui.sh:2362
+#: git-gui.sh:2464
 msgid "Stage Changed"
 msgstr "変更をコミット予定に入れる"
 
-#: 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 "プッシュ"
 
-#: git-gui.sh:2408
+#: git-gui.sh:2510
 msgid "Initial Commit Message:"
 msgstr "最初のコミットメッセージ:"
 
-#: git-gui.sh:2409
+#: git-gui.sh:2511
 msgid "Amended Commit Message:"
 msgstr "訂正したコミットメッセージ:"
 
-#: git-gui.sh:2410
+#: git-gui.sh:2512
 msgid "Amended Initial Commit Message:"
 msgstr "訂正した最初のコミットメッセージ:"
 
-#: git-gui.sh:2411
+#: git-gui.sh:2513
 msgid "Amended Merge Commit Message:"
 msgstr "訂正したマージコミットメッセージ:"
 
-#: git-gui.sh:2412
+#: git-gui.sh:2514
 msgid "Merge Commit Message:"
 msgstr "マージコミットメッセージ:"
 
-#: git-gui.sh:2413
+#: git-gui.sh:2515
 msgid "Commit Message:"
 msgstr "コミットメッセージ:"
 
-#: 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 "全てコピー"
 
-#: git-gui.sh:2483 lib/blame.tcl:107
+#: git-gui.sh:2585 lib/blame.tcl:100
 msgid "File:"
 msgstr "ファイル:"
 
-#: git-gui.sh:2589
+#: git-gui.sh:2691
 msgid "Apply/Reverse Hunk"
 msgstr "パッチを適用/取り消す"
 
-#: git-gui.sh:2595
-msgid "Show Less Context"
-msgstr "文脈を少なく"
-
-#: git-gui.sh:2602
-msgid "Show More Context"
-msgstr "文脈を多く"
+#: git-gui.sh:2696
+msgid "Apply/Reverse Line"
+msgstr "パッチ行を適用/取り消す"
 
-#: git-gui.sh:2610
+#: git-gui.sh:2711
 msgid "Refresh"
 msgstr "再読み込み"
 
-#: git-gui.sh:2631
+#: git-gui.sh:2732
 msgid "Decrease Font Size"
 msgstr "フォントを小さく"
 
-#: git-gui.sh:2635
+#: git-gui.sh:2736
 msgid "Increase Font Size"
 msgstr "フォントを大きく"
 
-#: git-gui.sh:2646
+#: git-gui.sh:2747
 msgid "Unstage Hunk From Commit"
 msgstr "パッチをコミット予定から外す"
 
-#: git-gui.sh:2648
+#: git-gui.sh:2748
+msgid "Unstage Line From Commit"
+msgstr "コミット予定から行を外す"
+
+#: git-gui.sh:2750
 msgid "Stage Hunk For Commit"
 msgstr "パッチをコミット予定に加える"
 
-#: git-gui.sh:2667
+#: git-gui.sh:2751
+msgid "Stage Line For Commit"
+msgstr "パッチ行をコミット予定に加える"
+
+#: git-gui.sh:2771
 msgid "Initializing..."
 msgstr "初期化しています…"
 
-#: git-gui.sh:2762
+#: git-gui.sh:2876
 #, tcl-format
 msgid ""
 "Possible environment issues exist.\n"
@@ -449,7 +450,7 @@ msgstr ""
 "以下の環境変数は %s が起動する Git サブプロセスによって無視されるでしょう:\n"
 "\n"
 
-#: git-gui.sh:2792
+#: git-gui.sh:2906
 msgid ""
 "\n"
 "This is due to a known issue with the\n"
@@ -459,7 +460,7 @@ msgstr ""
 "これは Cygwin で配布されている Tcl バイナリに\n"
 "関しての既知の問題によります"
 
-#: git-gui.sh:2797
+#: git-gui.sh:2911
 #, tcl-format
 msgid ""
 "\n"
@@ -478,64 +479,80 @@ msgstr ""
 msgid "git-gui - a graphical user interface for Git."
 msgstr "Git のグラフィカルUI git-gui"
 
-#: lib/blame.tcl:77
+#: lib/blame.tcl:70
 msgid "File Viewer"
 msgstr "ファイルピューワ"
 
-#: lib/blame.tcl:81
+#: lib/blame.tcl:74
 msgid "Commit:"
 msgstr "コミット:"
 
-#: lib/blame.tcl:264
+#: lib/blame.tcl:257
 msgid "Copy Commit"
 msgstr "コミットをコピー"
 
-#: lib/blame.tcl:384
+#: lib/blame.tcl:260
+msgid "Do Full Copy Detection"
+msgstr "コピー検知"
+
+#: lib/blame.tcl:388
 #, tcl-format
 msgid "Reading %s..."
 msgstr "%s を読んでいます…"
 
-#: lib/blame.tcl:488
+#: lib/blame.tcl:492
 msgid "Loading copy/move tracking annotations..."
 msgstr "コピー・移動追跡データを読んでいます…"
 
-#: lib/blame.tcl:508
+#: lib/blame.tcl:512
 msgid "lines annotated"
 msgstr "行を注釈しました"
 
-#: lib/blame.tcl:689
+#: lib/blame.tcl:704
 msgid "Loading original location annotations..."
 msgstr "元位置行の注釈データを読んでいます…"
 
-#: lib/blame.tcl:692
+#: lib/blame.tcl:707
 msgid "Annotation complete."
 msgstr "注釈完了しました"
 
-#: lib/blame.tcl:746
+#: lib/blame.tcl:737
+msgid "Busy"
+msgstr "実行中"
+
+#: lib/blame.tcl:738
+msgid "Annotation process is already running."
+msgstr "すでに blame プロセスを実行中です。"
+
+#: lib/blame.tcl:777
+msgid "Running thorough copy detection..."
+msgstr "コピー検知を実行中…"
+
+#: lib/blame.tcl:827
 msgid "Loading annotation..."
 msgstr "注釈を読み込んでいます…"
 
-#: lib/blame.tcl:802
+#: lib/blame.tcl:883
 msgid "Author:"
 msgstr "作者:"
 
-#: lib/blame.tcl:806
+#: lib/blame.tcl:887
 msgid "Committer:"
 msgstr "コミット者:"
 
-#: lib/blame.tcl:811
+#: lib/blame.tcl:892
 msgid "Original File:"
 msgstr "元ファイル"
 
-#: lib/blame.tcl:925
+#: lib/blame.tcl:1006
 msgid "Originally By:"
 msgstr "原作者:"
 
-#: lib/blame.tcl:931
+#: lib/blame.tcl:1012
 msgid "In File:"
 msgstr "ファイル:"
 
-#: lib/blame.tcl:936
+#: lib/blame.tcl:1017
 msgid "Copied Or Moved Here By:"
 msgstr "複写・移動者:"
 
@@ -549,7 +566,7 @@ msgstr "チェックアウト"
 
 #: 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 "中止"
@@ -558,7 +575,7 @@ msgstr "中止"
 msgid "Revision"
 msgstr "リビジョン"
 
-#: 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 "オプション"
 
@@ -610,7 +627,7 @@ msgstr "いいえ"
 msgid "Fast Forward Only"
 msgstr "早送りのみ"
 
-#: lib/branch_create.tcl:85 lib/checkout_op.tcl:514
+#: lib/branch_create.tcl:85 lib/checkout_op.tcl:536
 msgid "Reset"
 msgstr "リセット"
 
@@ -700,7 +717,7 @@ msgstr "新しい名前:"
 msgid "Please select a branch to rename."
 msgstr "名前を変更するブランチを選んで下さい。"
 
-#: 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 "'%s'というブランチは既に存在します。"
@@ -732,31 +749,36 @@ msgid "Browse Branch Files"
 msgstr "現在のブランチのファイルを見る"
 
 #: 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 "ブラウズ"
 
-#: lib/checkout_op.tcl:79
+#: lib/checkout_op.tcl:84
 #, tcl-format
 msgid "Fetching %s from %s"
 msgstr "%s から %s をフェッチしています"
 
-#: lib/checkout_op.tcl:127
+#: lib/checkout_op.tcl:132
 #, tcl-format
 msgid "fatal: Cannot resolve %s"
 msgstr "致命的エラー: %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 "閉じる"
 
-#: lib/checkout_op.tcl:169
+#: lib/checkout_op.tcl:174
 #, tcl-format
 msgid "Branch '%s' does not exist."
 msgstr "ブランチ'%s'は存在しません。"
 
-#: lib/checkout_op.tcl:206
+#: lib/checkout_op.tcl:193
+#, tcl-format
+msgid "Failed to configure simplified git-pull for '%s'."
+msgstr "'%s' に簡易 git-pull を設定できませんでした"
+
+#: lib/checkout_op.tcl:228
 #, tcl-format
 msgid ""
 "Branch '%s' already exists.\n"
@@ -769,21 +791,21 @@ msgstr ""
 "%s に早送りできません。\n"
 "マージが必要です。"
 
-#: lib/checkout_op.tcl:220
+#: lib/checkout_op.tcl:242
 #, tcl-format
 msgid "Merge strategy '%s' not supported."
 msgstr "'%s' マージ戦略はサポートされていません。"
 
-#: lib/checkout_op.tcl:239
+#: lib/checkout_op.tcl:261
 #, tcl-format
 msgid "Failed to update '%s'."
 msgstr "'%s' の更新に失敗しました。"
 
-#: lib/checkout_op.tcl:251
+#: lib/checkout_op.tcl:273
 msgid "Staging area (index) is already locked."
 msgstr "インデックスは既にロックされています。"
 
-#: lib/checkout_op.tcl:266
+#: lib/checkout_op.tcl:288
 msgid ""
 "Last scanned state does not match repository state.\n"
 "\n"
@@ -799,30 +821,30 @@ msgstr ""
 "\n"
 "自動的に再スキャンを開始します。\n"
 
-#: lib/checkout_op.tcl:322
+#: lib/checkout_op.tcl:344
 #, tcl-format
 msgid "Updating working directory to '%s'..."
 msgstr "作業ディレクトリを '%s' に更新しています…"
 
-#: lib/checkout_op.tcl:323
+#: lib/checkout_op.tcl:345
 msgid "files checked out"
 msgstr "チェックアウトされたファイル"
 
-#: lib/checkout_op.tcl:353
+#: lib/checkout_op.tcl:375
 #, tcl-format
 msgid "Aborted checkout of '%s' (file level merging is required)."
 msgstr "'%s' のチェックアウトを中止しました(ファイル毎のマージが必要です)。"
 
-#: lib/checkout_op.tcl:354
+#: lib/checkout_op.tcl:376
 msgid "File level merge required."
 msgstr "ファイル毎のマージが必要です。"
 
-#: lib/checkout_op.tcl:358
+#: lib/checkout_op.tcl:380
 #, tcl-format
 msgid "Staying on branch '%s'."
 msgstr "ブランチ '%s' に滞まります。"
 
-#: lib/checkout_op.tcl:429
+#: lib/checkout_op.tcl:451
 msgid ""
 "You are no longer on a local branch.\n"
 "\n"
@@ -834,30 +856,30 @@ msgstr ""
 "ブランチ上に滞まりたいときは、この「分離されたチェックアウト」から新規ブラン"
 "チを開始してください。"
 
-#: 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' をチェックアウトしました"
 
-#: lib/checkout_op.tcl:478
+#: lib/checkout_op.tcl:500
 #, tcl-format
 msgid "Resetting '%s' to '%s' will lose the following commits:"
 msgstr "'%s' を '%s' にリセットすると、以下のコミットが失なわれます:"
 
-#: lib/checkout_op.tcl:500
+#: lib/checkout_op.tcl:522
 msgid "Recovering lost commits may not be easy."
 msgstr "失なわれたコミットを回復するのは簡単ではありません。"
 
-#: lib/checkout_op.tcl:505
+#: lib/checkout_op.tcl:527
 #, tcl-format
 msgid "Reset '%s'?"
 msgstr "'%s' をリセットしますか?"
 
-#: lib/checkout_op.tcl:510 lib/merge.tcl:163
+#: lib/checkout_op.tcl:532 lib/merge.tcl:163
 msgid "Visualize"
 msgstr "可視化"
 
-#: lib/checkout_op.tcl:578
+#: lib/checkout_op.tcl:600
 #, tcl-format
 msgid ""
 "Failed to set current branch.\n"
@@ -909,7 +931,7 @@ msgstr "新しいリポジトリを作る"
 msgid "New..."
 msgstr "新規…"
 
-#: 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 "既存リポジトリを複製する"
 
@@ -917,7 +939,7 @@ msgstr "既存リポジトリを複製する"
 msgid "Clone..."
 msgstr "複製…"
 
-#: 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 "既存リポジトリを開く"
 
@@ -939,183 +961,183 @@ msgstr "最近使ったリポジトリを開く"
 msgid "Failed to create repository %s:"
 msgstr "リポジトリ %s を作製できません:"
 
-#: lib/choose_repository.tcl:381 lib/choose_repository.tcl:478
+#: lib/choose_repository.tcl:381 lib/choose_repository.tcl:476
 msgid "Directory:"
 msgstr "ディレクトリ:"
 
-#: 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 "GIT リポジトリ"
 
-#: lib/choose_repository.tcl:437
+#: lib/choose_repository.tcl:435
 #, tcl-format
 msgid "Directory %s already exists."
 msgstr "ディレクトリ '%s' は既に存在します。"
 
-#: lib/choose_repository.tcl:441
+#: lib/choose_repository.tcl:439
 #, tcl-format
 msgid "File %s already exists."
 msgstr "ファイル '%s' は既に存在します。"
 
-#: lib/choose_repository.tcl:455
+#: lib/choose_repository.tcl:453
 msgid "Clone"
 msgstr "複製"
 
-#: 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 "複製方式:"
 
-#: lib/choose_repository.tcl:495
+#: lib/choose_repository.tcl:493
 msgid "Standard (Fast, Semi-Redundant, Hardlinks)"
 msgstr "標準(高速・中冗長度・ハードリンク)"
 
-#: lib/choose_repository.tcl:501
+#: lib/choose_repository.tcl:499
 msgid "Full Copy (Slower, Redundant Backup)"
 msgstr "全複写(低速・冗長バックアップ)"
 
-#: lib/choose_repository.tcl:507
+#: lib/choose_repository.tcl:505
 msgid "Shared (Fastest, Not Recommended, No Backup)"
 msgstr "共有(最高速・非推奨・バックアップ無し)"
 
-#: 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 "Git リポジトリではありません: %s"
 
-#: lib/choose_repository.tcl:579
+#: lib/choose_repository.tcl:577
 msgid "Standard only available for local repository."
 msgstr "標準方式は同一計算機上のリポジトリにのみ使えます。"
 
-#: lib/choose_repository.tcl:583
+#: lib/choose_repository.tcl:581
 msgid "Shared only available for local repository."
 msgstr "共有方式は同一計算機上のリポジトリにのみ使えます。"
 
-#: lib/choose_repository.tcl:604
+#: lib/choose_repository.tcl:602
 #, tcl-format
 msgid "Location %s already exists."
 msgstr "'%s' は既に存在します。"
 
-#: lib/choose_repository.tcl:615
+#: lib/choose_repository.tcl:613
 msgid "Failed to configure origin"
 msgstr "origin を設定できませんでした"
 
-#: lib/choose_repository.tcl:627
+#: lib/choose_repository.tcl:625
 msgid "Counting objects"
 msgstr "オブジェクトを数えています"
 
-#: lib/choose_repository.tcl:628
+#: lib/choose_repository.tcl:626
 msgid "buckets"
 msgstr "バケツ"
 
-#: lib/choose_repository.tcl:652
+#: lib/choose_repository.tcl:650
 #, tcl-format
 msgid "Unable to copy objects/info/alternates: %s"
 msgstr "objects/info/alternates を複写できません: %s"
 
-#: lib/choose_repository.tcl:688
+#: lib/choose_repository.tcl:686
 #, tcl-format
 msgid "Nothing to clone from %s."
 msgstr "%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 "'master' ブランチが初期化されていません"
 
-#: lib/choose_repository.tcl:703
+#: lib/choose_repository.tcl:701
 msgid "Hardlinks are unavailable.  Falling back to copying."
 msgstr "ハードリンクが作れないので、コピーします"
 
-#: lib/choose_repository.tcl:715
+#: lib/choose_repository.tcl:713
 #, tcl-format
 msgid "Cloning from %s"
 msgstr "%s から複製しています"
 
-#: lib/choose_repository.tcl:746
+#: lib/choose_repository.tcl:744
 msgid "Copying objects"
 msgstr "オブジェクトを複写しています"
 
-#: 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 "オブジェクトを複写できません: %s"
 
-#: lib/choose_repository.tcl:781
+#: lib/choose_repository.tcl:779
 msgid "Linking objects"
 msgstr "オブジェクトを連結しています"
 
-#: lib/choose_repository.tcl:782
+#: lib/choose_repository.tcl:780
 msgid "objects"
 msgstr "オブジェクト"
 
-#: lib/choose_repository.tcl:790
+#: lib/choose_repository.tcl:788
 #, tcl-format
 msgid "Unable to hardlink object: %s"
 msgstr "オブジェクトをハードリンクできません: %s"
 
-#: lib/choose_repository.tcl:845
+#: lib/choose_repository.tcl:843
 msgid "Cannot fetch branches and objects.  See console output for details."
 msgstr "ブランチやオブジェクトを取得できません。コンソール出力を見て下さい"
 
-#: lib/choose_repository.tcl:856
+#: lib/choose_repository.tcl:854
 msgid "Cannot fetch tags.  See console output for details."
 msgstr "タグを取得できません。コンソール出力を見て下さい"
 
-#: lib/choose_repository.tcl:880
+#: lib/choose_repository.tcl:878
 msgid "Cannot determine HEAD.  See console output for details."
 msgstr "HEAD を確定できません。コンソール出力を見て下さい"
 
-#: lib/choose_repository.tcl:889
+#: lib/choose_repository.tcl:887
 #, tcl-format
 msgid "Unable to cleanup %s"
 msgstr "%s を掃除できません"
 
-#: lib/choose_repository.tcl:895
+#: lib/choose_repository.tcl:893
 msgid "Clone failed."
 msgstr "複写に失敗しました。"
 
-#: lib/choose_repository.tcl:902
+#: lib/choose_repository.tcl:900
 msgid "No default branch obtained."
 msgstr "デフォールト・ブランチが取得されませんでした"
 
-#: lib/choose_repository.tcl:913
+#: lib/choose_repository.tcl:911
 #, tcl-format
 msgid "Cannot resolve %s as a commit."
 msgstr "%s をコミットとして解釈できません"
 
-#: lib/choose_repository.tcl:925
+#: lib/choose_repository.tcl:923
 msgid "Creating working directory"
 msgstr "作業ディレクトリを作成しています"
 
-#: 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 "ファイル"
 
-#: lib/choose_repository.tcl:955
+#: lib/choose_repository.tcl:953
 msgid "Initial file checkout failed."
 msgstr "初期チェックアウトに失敗しました"
 
-#: lib/choose_repository.tcl:971
+#: lib/choose_repository.tcl:969
 msgid "Open"
 msgstr "開く"
 
-#: lib/choose_repository.tcl:981
+#: lib/choose_repository.tcl:979
 msgid "Repository:"
 msgstr "リポジトリ:"
 
-#: lib/choose_repository.tcl:1031
+#: lib/choose_repository.tcl:1027
 #, tcl-format
 msgid "Failed to open repository %s:"
 msgstr "リポジトリ %s を開けません:"
@@ -1405,7 +1427,7 @@ msgstr ""
 msgid "Invalid date from Git: %s"
 msgstr "Git から出た無効な日付: %s"
 
-#: lib/diff.tcl:42
+#: lib/diff.tcl:44
 #, tcl-format
 msgid ""
 "No differences detected.\n"
@@ -1427,40 +1449,48 @@ msgstr ""
 "\n"
 "同様な状態のファイルを探すために、自動的に再スキャンを開始します。"
 
-#: lib/diff.tcl:81
+#: lib/diff.tcl:83
 #, tcl-format
 msgid "Loading diff of %s..."
 msgstr "%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 "%s を表示できません"
 
-#: lib/diff.tcl:115
+#: lib/diff.tcl:117
 msgid "Error loading file:"
 msgstr "ファイルを読む際のエラーです:"
 
-#: lib/diff.tcl:122
+#: lib/diff.tcl:124
 msgid "Git Repository (subproject)"
 msgstr "Git リポジトリ(サブプロジェクト)"
 
-#: lib/diff.tcl:134
+#: lib/diff.tcl:136
 msgid "* Binary file (not showing content)."
 msgstr "* バイナリファイル(内容は表示しません)"
 
-#: lib/diff.tcl:185
+#: lib/diff.tcl:191
 msgid "Error loading diff:"
 msgstr "diff を読む際のエラーです:"
 
-#: lib/diff.tcl:303
+#: lib/diff.tcl:313
 msgid "Failed to unstage selected hunk."
 msgstr "選択されたパッチをコミット予定から外せません。"
 
-#: lib/diff.tcl:310
+#: lib/diff.tcl:320
 msgid "Failed to stage selected hunk."
 msgstr "選択されたパッチをコミット予定に加えられません。"
 
+#: lib/diff.tcl:386
+msgid "Failed to unstage selected line."
+msgstr "選択されたパッチ行をコミット予定から外せません。"
+
+#: lib/diff.tcl:394
+msgid "Failed to stage selected line."
+msgstr "選択されたパッチ行をコミット予定に加えられません。"
+
 #: lib/error.tcl:20 lib/error.tcl:114
 msgid "error"
 msgstr "エラー"
@@ -1662,11 +1692,11 @@ msgstr "中断しています"
 msgid "files reset"
 msgstr "リセットしたファイル"
 
-#: lib/merge.tcl:265
+#: lib/merge.tcl:266
 msgid "Abort failed."
 msgstr "中断に失敗しました。"
 
-#: lib/merge.tcl:267
+#: lib/merge.tcl:268
 msgid "Abort completed.  Ready."
 msgstr "中断完了。"
 
@@ -1720,42 +1750,62 @@ msgid "Match Tracking Branches"
 msgstr "トラッキングブランチを合わせる"
 
 #: lib/option.tcl:126
+msgid "Blame Copy Only On Changed Files"
+msgstr "変更されたファイルのみコピー検知を行なう"
+
+#: lib/option.tcl:127
+msgid "Minimum Letters To Blame Copy On"
+msgstr "コピーを検知する最少文字数"
+
+#: lib/option.tcl:128
 msgid "Number of Diff Context Lines"
 msgstr "diff の文脈行数"
 
-#: lib/option.tcl:127
+#: lib/option.tcl:129
 msgid "Commit Message Text Width"
 msgstr "コミットメッセージのテキスト幅"
 
-#: lib/option.tcl:128
+#: lib/option.tcl:130
 msgid "New Branch Name Template"
 msgstr "新しいブランチ名のテンプレート"
 
-#: lib/option.tcl:192
+#: lib/option.tcl:194
 msgid "Spelling Dictionary:"
 msgstr "スペルチェック辞書"
 
-#: lib/option.tcl:216
+#: lib/option.tcl:218
 msgid "Change Font"
 msgstr "フォントを変更"
 
-#: lib/option.tcl:220
+#: lib/option.tcl:222
 #, tcl-format
 msgid "Choose %s"
 msgstr "%s を選択"
 
-#: lib/option.tcl:226
+#: lib/option.tcl:228
 msgid "pt."
 msgstr "ポイント"
 
-#: lib/option.tcl:240
+#: lib/option.tcl:242
 msgid "Preferences"
 msgstr "設定"
 
-#: lib/option.tcl:275
+#: lib/option.tcl:277
 msgid "Failed to completely save options:"
 msgstr "完全にオプションを保存できません:"
 
+#: lib/remote.tcl:165
+msgid "Prune from"
+msgstr "から刈込む…"
+
+#: lib/remote.tcl:170
+msgid "Fetch from"
+msgstr "取得元"
+
+#: lib/remote.tcl:213
+msgid "Push to"
+msgstr "プッシュ先"
+
 #: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34
 msgid "Delete Remote Branch"
 msgstr "リモート・ブランチを削除"
@@ -1840,18 +1890,6 @@ msgstr "リポジトリが選択されていません。"
 msgid "Scanning %s..."
 msgstr "%s をスキャンしています…"
 
-#: lib/remote.tcl:165
-msgid "Prune from"
-msgstr "から刈込む…"
-
-#: lib/remote.tcl:170
-msgid "Fetch from"
-msgstr "取得元"
-
-#: lib/remote.tcl:213
-msgid "Push to"
-msgstr "プッシュ先"
-
 #: lib/shortcut.tcl:20 lib/shortcut.tcl:61
 msgid "Cannot write shortcut:"
 msgstr "ショートカットが書けません:"
@@ -1885,15 +1923,15 @@ msgstr "スペルチェッカーの起動に失敗しました"
 msgid "Unrecognized spell checker"
 msgstr "スペルチェッカーが判別できません"
 
-#: lib/spellcheck.tcl:180
+#: lib/spellcheck.tcl:186
 msgid "No Suggestions"
 msgstr "提案なし"
 
-#: lib/spellcheck.tcl:381
+#: lib/spellcheck.tcl:387
 msgid "Unexpected EOF from spell checker"
 msgstr "スペルチェッカーが予想外の EOF を返しました"
 
-#: lib/spellcheck.tcl:385
+#: lib/spellcheck.tcl:391
 msgid "Spell Checker Failed"
 msgstr "スペルチェック失敗"
 
@@ -1964,6 +2002,3 @@ msgstr "Thin Pack を使う(遅いネットワーク接続)"
 #: lib/transport.tcl:168
 msgid "Include tags"
 msgstr "タグを含める"
-
-#~ msgid "Not connected to aspell"
-#~ msgstr "aspell に接続していません"
index b7c4bf3fdffb3d04b8c01b25e99a706e499de0d1..1e9f992528153fa62c167db8f8e8c184e7df86bd 100644 (file)
@@ -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
index 4da687bb41f5471eaa6dd49c2ffae1eaa053ec68..0196ba8cefdb5a4867a5f08586d9cb47dfe05e7e 100644 (file)
@@ -3,45 +3,46 @@
 # This file is distributed under the same license as the git-gui package.
 #
 # Peter Karlsson <peter@softwolves.pp.se>, 2007-2008.
+# Mikael Magnusson <mikachu@gmail.com>, 2008.
 msgid ""
 msgstr ""
 "Project-Id-Version: sv\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-03-14 07:18+0100\n"
-"PO-Revision-Date: 2008-03-14 07:23+0100\n"
-"Last-Translator: Peter Karlsson <peter@softwolves.pp.se>\n"
+"POT-Creation-Date: 2008-08-03 01:34+0200\n"
+"PO-Revision-Date: 2008-08-03 01:45+0200\n"
+"Last-Translator: Mikael Magnusson <mikachu@gmail.com>\n"
 "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit"
+"Content-Transfer-Encoding: 8bit\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: ödesdigert fel"
 
-#: git-gui.sh:593
+#: git-gui.sh:644
 #, tcl-format
 msgid "Invalid font specified in %s:"
 msgstr "Ogiltigt teckensnitt angivet i %s:"
 
-#: git-gui.sh:620
+#: git-gui.sh:674
 msgid "Main Font"
 msgstr "Huvudteckensnitt"
 
-#: git-gui.sh:621
+#: git-gui.sh:675
 msgid "Diff/Console Font"
 msgstr "Diff/konsolteckensnitt"
 
-#: git-gui.sh:635
+#: git-gui.sh:689
 msgid "Cannot find git in PATH."
 msgstr "Hittar inte git i PATH."
 
-#: git-gui.sh:662
+#: git-gui.sh:716
 msgid "Cannot parse Git version string:"
 msgstr "Kan inte tolka versionssträng från Git:"
 
-#: git-gui.sh:680
+#: git-gui.sh:734
 #, tcl-format
 msgid ""
 "Git version cannot be determined.\n"
@@ -60,379 +61,380 @@ msgstr ""
 "\n"
 "Anta att \"%s\" är version 1.5.0?\n"
 
-#: git-gui.sh:918
+#: git-gui.sh:972
 msgid "Git directory not found:"
 msgstr "Git-katalogen hittades inte:"
 
-#: git-gui.sh:925
+#: git-gui.sh:979
 msgid "Cannot move to top of working directory:"
 msgstr "Kan inte gå till början på arbetskatalogen:"
 
-#: git-gui.sh:932
+#: git-gui.sh:986
 msgid "Cannot use funny .git directory:"
 msgstr "Kan inte använda underlig .git-katalog:"
 
-#: git-gui.sh:937
+#: git-gui.sh:991
 msgid "No working directory"
 msgstr "Ingen arbetskatalog"
 
-#: git-gui.sh:1084 lib/checkout_op.tcl:283
+#: git-gui.sh:1138 lib/checkout_op.tcl:305
 msgid "Refreshing file status..."
 msgstr "Uppdaterar filstatus..."
 
-#: git-gui.sh:1149
+#: git-gui.sh:1194
 msgid "Scanning for modified files ..."
 msgstr "Söker efter ändrade filer..."
 
-#: git-gui.sh:1324 lib/browser.tcl:246
+#: git-gui.sh:1369 lib/browser.tcl:246
 msgid "Ready."
 msgstr "Klar."
 
-#: git-gui.sh:1590
+#: git-gui.sh:1635
 msgid "Unmodified"
 msgstr "Oförändrade"
 
-#: git-gui.sh:1592
+#: git-gui.sh:1637
 msgid "Modified, not staged"
 msgstr "Förändrade, ej köade"
 
-#: git-gui.sh:1593 git-gui.sh:1598
+#: git-gui.sh:1638 git-gui.sh:1643
 msgid "Staged for commit"
 msgstr "Köade för incheckning"
 
-#: git-gui.sh:1594 git-gui.sh:1599
+#: git-gui.sh:1639 git-gui.sh:1644
 msgid "Portions staged for commit"
 msgstr "Delar köade för incheckning"
 
-#: git-gui.sh:1595 git-gui.sh:1600
+#: git-gui.sh:1640 git-gui.sh:1645
 msgid "Staged for commit, missing"
 msgstr "Köade för incheckning, saknade"
 
-#: git-gui.sh:1597
+#: git-gui.sh:1642
 msgid "Untracked, not staged"
 msgstr "Ej spårade, ej köade"
 
-#: git-gui.sh:1602
+#: git-gui.sh:1647
 msgid "Missing"
 msgstr "Saknade"
 
-#: git-gui.sh:1603
+#: git-gui.sh:1648
 msgid "Staged for removal"
 msgstr "Köade för borttagning"
 
-#: git-gui.sh:1604
+#: git-gui.sh:1649
 msgid "Staged for removal, still present"
 msgstr "Köade för borttagning, fortfarande närvarande"
 
-#: 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 "Kräver konflikthantering efter sammanslagning"
 
-#: git-gui.sh:1644
+#: git-gui.sh:1689
 msgid "Starting gitk... please wait..."
 msgstr "Startar gitk... vänta..."
 
-#: git-gui.sh:1653
-#, tcl-format
-msgid ""
-"Unable to start gitk:\n"
-"\n"
-"%s does not exist"
-msgstr ""
-"Kan inte starta gitk:\n"
-"\n"
-"%s finns inte"
+#: git-gui.sh:1698
+msgid "Couldn't find gitk in PATH"
+msgstr "Hittar inte gitk i PATH."
 
-#: git-gui.sh:1860 lib/choose_repository.tcl:36
+#: git-gui.sh:1948 lib/choose_repository.tcl:36
 msgid "Repository"
 msgstr "Arkiv"
 
-#: git-gui.sh:1861
+#: git-gui.sh:1949
 msgid "Edit"
 msgstr "Redigera"
 
-#: git-gui.sh:1863 lib/choose_rev.tcl:561
+#: git-gui.sh:1951 lib/choose_rev.tcl:561
 msgid "Branch"
 msgstr "Gren"
 
-#: git-gui.sh:1866 lib/choose_rev.tcl:548
+#: git-gui.sh:1954 lib/choose_rev.tcl:548
 msgid "Commit@@noun"
 msgstr "Incheckning"
 
-#: 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 "Slå ihop"
 
-#: git-gui.sh:1870 lib/choose_rev.tcl:557
+#: git-gui.sh:1958 lib/choose_rev.tcl:557
 msgid "Remote"
 msgstr "Fjärr"
 
-#: git-gui.sh:1879
+#: git-gui.sh:1967
 msgid "Browse Current Branch's Files"
 msgstr "Bläddra i grenens filer"
 
-#: git-gui.sh:1883
+#: git-gui.sh:1971
 msgid "Browse Branch Files..."
 msgstr "Bläddra filer på gren..."
 
-#: git-gui.sh:1888
+#: git-gui.sh:1976
 msgid "Visualize Current Branch's History"
 msgstr "Visualisera grenens historik"
 
-#: git-gui.sh:1892
+#: git-gui.sh:1980
 msgid "Visualize All Branch History"
 msgstr "Visualisera alla grenars historik"
 
-#: git-gui.sh:1899
+#: git-gui.sh:1987
 #, tcl-format
 msgid "Browse %s's Files"
 msgstr "Bläddra i filer för %s"
 
-#: git-gui.sh:1901
+#: git-gui.sh:1989
 #, tcl-format
 msgid "Visualize %s's History"
 msgstr "Visualisera historik för %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 "Databasstatistik"
 
-#: git-gui.sh:1909 lib/database.tcl:34
+#: git-gui.sh:1997 lib/database.tcl:34
 msgid "Compress Database"
 msgstr "Komprimera databas"
 
-#: git-gui.sh:1912
+#: git-gui.sh:2000
 msgid "Verify Database"
 msgstr "Verifiera databas"
 
-#: 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 "Skapa skrivbordsikon"
 
-#: 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 "Avsluta"
 
-#: git-gui.sh:1939
+#: git-gui.sh:2031
 msgid "Undo"
 msgstr "Ångra"
 
-#: git-gui.sh:1942
+#: git-gui.sh:2034
 msgid "Redo"
 msgstr "Gör om"
 
-#: git-gui.sh:1946 git-gui.sh:2443
+#: git-gui.sh:2038 git-gui.sh:2545
 msgid "Cut"
 msgstr "Klipp ut"
 
-#: 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 "Kopiera"
 
-#: git-gui.sh:1952 git-gui.sh:2449
+#: git-gui.sh:2044 git-gui.sh:2551
 msgid "Paste"
 msgstr "Klistra in"
 
-#: 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 "Ta bort"
 
-#: 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 "Markera alla"
 
-#: git-gui.sh:1968
+#: git-gui.sh:2060
 msgid "Create..."
 msgstr "Skapa..."
 
-#: git-gui.sh:1974
+#: git-gui.sh:2066
 msgid "Checkout..."
 msgstr "Checka ut..."
 
-#: git-gui.sh:1980
+#: git-gui.sh:2072
 msgid "Rename..."
 msgstr "Byt namn..."
 
-#: git-gui.sh:1985 git-gui.sh:2085
+#: git-gui.sh:2077 git-gui.sh:2187
 msgid "Delete..."
 msgstr "Ta bort..."
 
-#: git-gui.sh:1990
+#: git-gui.sh:2082
 msgid "Reset..."
 msgstr "Återställ..."
 
-#: git-gui.sh:2002 git-gui.sh:2389
+#: git-gui.sh:2094 git-gui.sh:2491
 msgid "New Commit"
 msgstr "Ny incheckning"
 
-#: git-gui.sh:2010 git-gui.sh:2396
+#: git-gui.sh:2102 git-gui.sh:2498
 msgid "Amend Last Commit"
 msgstr "Lägg till föregående incheckning"
 
-#: 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 "Sök på nytt"
 
-#: git-gui.sh:2025
+#: git-gui.sh:2117
 msgid "Stage To Commit"
 msgstr "Köa för incheckning"
 
-#: git-gui.sh:2031
+#: git-gui.sh:2123
 msgid "Stage Changed Files To Commit"
 msgstr "Köa ändrade filer för incheckning"
 
-#: git-gui.sh:2037
+#: git-gui.sh:2129
 msgid "Unstage From Commit"
 msgstr "Ta bort från incheckningskö"
 
-#: git-gui.sh:2042 lib/index.tcl:395
+#: git-gui.sh:2134 lib/index.tcl:395
 msgid "Revert Changes"
 msgstr "Återställ ändringar"
 
-#: 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 "Visa mindre sammanhang"
+
+#: git-gui.sh:2145 git-gui.sh:2706
+msgid "Show More Context"
+msgstr "Visa mer sammanhang"
+
+#: git-gui.sh:2151 git-gui.sh:2470 git-gui.sh:2569
 msgid "Sign Off"
 msgstr "Skriv under"
 
-#: git-gui.sh:2053 git-gui.sh:2372
+#: git-gui.sh:2155 git-gui.sh:2474
 msgid "Commit@@verb"
 msgstr "Checka in"
 
-#: git-gui.sh:2064
+#: git-gui.sh:2166
 msgid "Local Merge..."
 msgstr "Lokal sammanslagning..."
 
-#: git-gui.sh:2069
+#: git-gui.sh:2171
 msgid "Abort Merge..."
 msgstr "Avbryt sammanslagning..."
 
-#: git-gui.sh:2081
+#: git-gui.sh:2183
 msgid "Push..."
 msgstr "Sänd..."
 
-#: git-gui.sh:2092 lib/choose_repository.tcl:41
-msgid "Apple"
-msgstr "Äpple"
-
-#: 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 "Om %s"
 
-#: git-gui.sh:2099
+#: git-gui.sh:2201
 msgid "Preferences..."
 msgstr "Inställningar..."
 
-#: git-gui.sh:2107 git-gui.sh:2639
+#: git-gui.sh:2209 git-gui.sh:2740
 msgid "Options..."
 msgstr "Alternativ..."
 
-#: git-gui.sh:2113 lib/choose_repository.tcl:47
+#: git-gui.sh:2215 lib/choose_repository.tcl:47
 msgid "Help"
 msgstr "Hjälp"
 
-#: git-gui.sh:2154
+#: git-gui.sh:2256
 msgid "Online Documentation"
 msgstr "Webbdokumentation"
 
-#: git-gui.sh:2238
+#: git-gui.sh:2340
 #, tcl-format
 msgid "fatal: cannot stat path %s: No such file or directory"
 msgstr ""
 "ödesdigert: kunde inte ta status på sökvägen %s: Fil eller katalog saknas"
 
-#: git-gui.sh:2271
+#: git-gui.sh:2373
 msgid "Current Branch:"
 msgstr "Aktuell gren:"
 
-#: git-gui.sh:2292
+#: git-gui.sh:2394
 msgid "Staged Changes (Will Commit)"
 msgstr "Köade ändringar (kommer att checkas in)"
 
-#: git-gui.sh:2312
+#: git-gui.sh:2414
 msgid "Unstaged Changes"
 msgstr "Oköade ändringar"
 
-#: git-gui.sh:2362
+#: git-gui.sh:2464
 msgid "Stage Changed"
 msgstr "Köa ändrade"
 
-#: 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 "Sänd"
 
-#: git-gui.sh:2408
+#: git-gui.sh:2510
 msgid "Initial Commit Message:"
 msgstr "Inledande incheckningsmeddelande:"
 
-#: git-gui.sh:2409
+#: git-gui.sh:2511
 msgid "Amended Commit Message:"
 msgstr "Utökat incheckningsmeddelande:"
 
-#: git-gui.sh:2410
+#: git-gui.sh:2512
 msgid "Amended Initial Commit Message:"
 msgstr "Utökat inledande incheckningsmeddelande:"
 
-#: git-gui.sh:2411
+#: git-gui.sh:2513
 msgid "Amended Merge Commit Message:"
 msgstr "Utökat incheckningsmeddelande för sammanslagning:"
 
-#: git-gui.sh:2412
+#: git-gui.sh:2514
 msgid "Merge Commit Message:"
 msgstr "Incheckningsmeddelande för sammanslagning:"
 
-#: git-gui.sh:2413
+#: git-gui.sh:2515
 msgid "Commit Message:"
 msgstr "Incheckningsmeddelande:"
 
-#: 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 "Kopiera alla"
 
-#: git-gui.sh:2483 lib/blame.tcl:107
+#: git-gui.sh:2585 lib/blame.tcl:100
 msgid "File:"
 msgstr "Fil:"
 
-#: git-gui.sh:2589
+#: git-gui.sh:2691
 msgid "Apply/Reverse Hunk"
 msgstr "Använd/återställ del"
 
-#: git-gui.sh:2595
-msgid "Show Less Context"
-msgstr "Visa mindre sammanhang"
-
-#: git-gui.sh:2602
-msgid "Show More Context"
-msgstr "Visa mer sammanhang"
+#: git-gui.sh:2696
+msgid "Apply/Reverse Line"
+msgstr "Använd/återställ rad"
 
-#: git-gui.sh:2610
+#: git-gui.sh:2711
 msgid "Refresh"
 msgstr "Uppdatera"
 
-#: git-gui.sh:2631
+#: git-gui.sh:2732
 msgid "Decrease Font Size"
 msgstr "Minska teckensnittsstorlek"
 
-#: git-gui.sh:2635
+#: git-gui.sh:2736
 msgid "Increase Font Size"
 msgstr "Öka teckensnittsstorlek"
 
-#: git-gui.sh:2646
+#: git-gui.sh:2747
 msgid "Unstage Hunk From Commit"
 msgstr "Ta bort del ur incheckningskö"
 
-#: git-gui.sh:2648
+#: git-gui.sh:2748
+msgid "Unstage Line From Commit"
+msgstr "Ta bort rad ur incheckningskö"
+
+#: git-gui.sh:2750
 msgid "Stage Hunk For Commit"
 msgstr "Ställ del i incheckningskö"
 
-#: git-gui.sh:2667
+#: git-gui.sh:2751
+msgid "Stage Line For Commit"
+msgstr "Ställ rad i incheckningskö"
+
+#: git-gui.sh:2771
 msgid "Initializing..."
 msgstr "Initierar..."
 
-#: git-gui.sh:2762
+#: git-gui.sh:2876
 #, tcl-format
 msgid ""
 "Possible environment issues exist.\n"
@@ -449,7 +451,7 @@ msgstr ""
 "av %s:\n"
 "\n"
 
-#: git-gui.sh:2792
+#: git-gui.sh:2906
 msgid ""
 "\n"
 "This is due to a known issue with the\n"
@@ -459,7 +461,7 @@ msgstr ""
 "Detta beror på ett känt problem med\n"
 "Tcl-binären som följer med Cygwin."
 
-#: git-gui.sh:2797
+#: git-gui.sh:2911
 #, tcl-format
 msgid ""
 "\n"
@@ -480,64 +482,80 @@ msgstr ""
 msgid "git-gui - a graphical user interface for Git."
 msgstr "git-gui - ett grafiskt användargränssnitt för Git."
 
-#: lib/blame.tcl:77
+#: lib/blame.tcl:70
 msgid "File Viewer"
 msgstr "Filvisare"
 
-#: lib/blame.tcl:81
+#: lib/blame.tcl:74
 msgid "Commit:"
 msgstr "Incheckning:"
 
-#: lib/blame.tcl:264
+#: lib/blame.tcl:257
 msgid "Copy Commit"
 msgstr "Kopiera incheckning"
 
-#: lib/blame.tcl:384
+#: lib/blame.tcl:260
+msgid "Do Full Copy Detection"
+msgstr "Gör full kopieringsigenkänning"
+
+#: lib/blame.tcl:388
 #, tcl-format
 msgid "Reading %s..."
 msgstr "Läser %s..."
 
-#: lib/blame.tcl:488
+#: lib/blame.tcl:492
 msgid "Loading copy/move tracking annotations..."
 msgstr "Läser annoteringar för kopiering/flyttning..."
 
-#: lib/blame.tcl:508
+#: lib/blame.tcl:512
 msgid "lines annotated"
 msgstr "rader annoterade"
 
-#: lib/blame.tcl:689
+#: lib/blame.tcl:704
 msgid "Loading original location annotations..."
 msgstr "Läser in annotering av originalplacering..."
 
-#: lib/blame.tcl:692
+#: lib/blame.tcl:707
 msgid "Annotation complete."
 msgstr "Annotering fullbordad."
 
-#: lib/blame.tcl:746
+#: lib/blame.tcl:737
+msgid "Busy"
+msgstr "Upptagen"
+
+#: lib/blame.tcl:738
+msgid "Annotation process is already running."
+msgstr "Annoteringsprocess körs redan."
+
+#: lib/blame.tcl:777
+msgid "Running thorough copy detection..."
+msgstr "Kör grundlig kopieringsigenkänning..."
+
+#: lib/blame.tcl:827
 msgid "Loading annotation..."
 msgstr "Läser in annotering..."
 
-#: lib/blame.tcl:802
+#: lib/blame.tcl:883
 msgid "Author:"
 msgstr "Författare:"
 
-#: lib/blame.tcl:806
+#: lib/blame.tcl:887
 msgid "Committer:"
 msgstr "Incheckare:"
 
-#: lib/blame.tcl:811
+#: lib/blame.tcl:892
 msgid "Original File:"
 msgstr "Ursprunglig fil:"
 
-#: lib/blame.tcl:925
+#: lib/blame.tcl:1006
 msgid "Originally By:"
 msgstr "Ursprungligen av:"
 
-#: lib/blame.tcl:931
+#: lib/blame.tcl:1012
 msgid "In File:"
 msgstr "I filen:"
 
-#: lib/blame.tcl:936
+#: lib/blame.tcl:1017
 msgid "Copied Or Moved Here By:"
 msgstr "Kopierad eller flyttad hit av:"
 
@@ -551,7 +569,7 @@ msgstr "Checka ut"
 
 #: 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 "Avbryt"
@@ -560,7 +578,7 @@ msgstr "Avbryt"
 msgid "Revision"
 msgstr "Revision"
 
-#: 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 "Alternativ"
 
@@ -612,7 +630,7 @@ msgstr "Nej"
 msgid "Fast Forward Only"
 msgstr "Endast snabbspolning"
 
-#: lib/branch_create.tcl:85 lib/checkout_op.tcl:514
+#: lib/branch_create.tcl:85 lib/checkout_op.tcl:536
 msgid "Reset"
 msgstr "Återställ"
 
@@ -702,7 +720,7 @@ msgstr "Nytt namn:"
 msgid "Please select a branch to rename."
 msgstr "Välj en gren att byta namn på."
 
-#: 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 "Grenen \"%s\" finns redan."
@@ -734,31 +752,36 @@ msgid "Browse Branch Files"
 msgstr "Bläddra filer på grenen"
 
 #: 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 "Bläddra"
 
-#: lib/checkout_op.tcl:79
+#: lib/checkout_op.tcl:84
 #, tcl-format
 msgid "Fetching %s from %s"
 msgstr "Hämtar %s från %s"
 
-#: lib/checkout_op.tcl:127
+#: lib/checkout_op.tcl:132
 #, tcl-format
 msgid "fatal: Cannot resolve %s"
 msgstr "ödesdigert: Kunde inte slå upp %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 "Stäng"
 
-#: lib/checkout_op.tcl:169
+#: lib/checkout_op.tcl:174
 #, tcl-format
 msgid "Branch '%s' does not exist."
 msgstr "Grenen \"%s\" finns inte."
 
-#: lib/checkout_op.tcl:206
+#: lib/checkout_op.tcl:193
+#, tcl-format
+msgid "Failed to configure simplified git-pull for '%s'."
+msgstr "Kunde inte konfigurera förenklad git-pull för '%s'."
+
+#: lib/checkout_op.tcl:228
 #, tcl-format
 msgid ""
 "Branch '%s' already exists.\n"
@@ -771,21 +794,21 @@ msgstr ""
 "Den kan inte snabbspolas till %s.\n"
 "En sammanslagning krävs."
 
-#: lib/checkout_op.tcl:220
+#: lib/checkout_op.tcl:242
 #, tcl-format
 msgid "Merge strategy '%s' not supported."
 msgstr "Sammanslagningsstrategin \"%s\" stöds inte."
 
-#: lib/checkout_op.tcl:239
+#: lib/checkout_op.tcl:261
 #, tcl-format
 msgid "Failed to update '%s'."
 msgstr "Misslyckades med att uppdatera \"%s\"."
 
-#: lib/checkout_op.tcl:251
+#: lib/checkout_op.tcl:273
 msgid "Staging area (index) is already locked."
 msgstr "Köområdet (index) är redan låst."
 
-#: lib/checkout_op.tcl:266
+#: lib/checkout_op.tcl:288
 msgid ""
 "Last scanned state does not match repository state.\n"
 "\n"
@@ -801,30 +824,30 @@ msgstr ""
 "\n"
 "Sökningen kommer att startas automatiskt nu.\n"
 
-#: lib/checkout_op.tcl:322
+#: lib/checkout_op.tcl:344
 #, tcl-format
 msgid "Updating working directory to '%s'..."
 msgstr "Uppdaterar arbetskatalogen till \"%s\"..."
 
-#: lib/checkout_op.tcl:323
+#: lib/checkout_op.tcl:345
 msgid "files checked out"
 msgstr "filer utcheckade"
 
-#: lib/checkout_op.tcl:353
+#: lib/checkout_op.tcl:375
 #, tcl-format
 msgid "Aborted checkout of '%s' (file level merging is required)."
 msgstr "Avbryter utcheckning av \"%s\" (sammanslagning på filnivå krävs)."
 
-#: lib/checkout_op.tcl:354
+#: lib/checkout_op.tcl:376
 msgid "File level merge required."
 msgstr "Sammanslagning på filnivå krävs."
 
-#: lib/checkout_op.tcl:358
+#: lib/checkout_op.tcl:380
 #, tcl-format
 msgid "Staying on branch '%s'."
 msgstr "Stannar på grenen \"%s\"."
 
-#: lib/checkout_op.tcl:429
+#: lib/checkout_op.tcl:451
 msgid ""
 "You are no longer on a local branch.\n"
 "\n"
@@ -836,31 +859,31 @@ msgstr ""
 "Om du ville vara på en gren skapar du en nu, baserad på \"Denna frånkopplade "
 "utcheckning\"."
 
-#: 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 "Checkade ut \"%s\"."
 
-#: lib/checkout_op.tcl:478
+#: lib/checkout_op.tcl:500
 #, tcl-format
 msgid "Resetting '%s' to '%s' will lose the following commits:"
 msgstr ""
 "Om du återställer \"%s\" till \"%s\" går följande incheckningar förlorade:"
 
-#: lib/checkout_op.tcl:500
+#: lib/checkout_op.tcl:522
 msgid "Recovering lost commits may not be easy."
 msgstr "Det kanske inte är så enkelt att återskapa förlorade incheckningar."
 
-#: lib/checkout_op.tcl:505
+#: lib/checkout_op.tcl:527
 #, tcl-format
 msgid "Reset '%s'?"
 msgstr "Återställa \"%s\"?"
 
-#: lib/checkout_op.tcl:510 lib/merge.tcl:163
+#: lib/checkout_op.tcl:532 lib/merge.tcl:163
 msgid "Visualize"
 msgstr "Visualisera"
 
-#: lib/checkout_op.tcl:578
+#: lib/checkout_op.tcl:600
 #, tcl-format
 msgid ""
 "Failed to set current branch.\n"
@@ -913,7 +936,7 @@ msgstr "Skapa nytt arkiv"
 msgid "New..."
 msgstr "Nytt..."
 
-#: 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 "Klona befintligt arkiv"
 
@@ -921,7 +944,7 @@ msgstr "Klona befintligt arkiv"
 msgid "Clone..."
 msgstr "Klona..."
 
-#: 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 "Öppna befintligt arkiv"
 
@@ -943,183 +966,183 @@ msgstr "Öppna tidigare arkiv:"
 msgid "Failed to create repository %s:"
 msgstr "Kunde inte skapa arkivet %s:"
 
-#: lib/choose_repository.tcl:381 lib/choose_repository.tcl:478
+#: lib/choose_repository.tcl:381 lib/choose_repository.tcl:476
 msgid "Directory:"
 msgstr "Katalog:"
 
-#: 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 "Gitarkiv"
 
-#: lib/choose_repository.tcl:437
+#: lib/choose_repository.tcl:435
 #, tcl-format
 msgid "Directory %s already exists."
 msgstr "Katalogen %s finns redan."
 
-#: lib/choose_repository.tcl:441
+#: lib/choose_repository.tcl:439
 #, tcl-format
 msgid "File %s already exists."
 msgstr "Filen %s finns redan."
 
-#: lib/choose_repository.tcl:455
+#: lib/choose_repository.tcl:453
 msgid "Clone"
 msgstr "Klona"
 
-#: lib/choose_repository.tcl:468
+#: lib/choose_repository.tcl:466
 msgid "URL:"
 msgstr "Webbadress:"
 
-#: lib/choose_repository.tcl:489
+#: lib/choose_repository.tcl:487
 msgid "Clone Type:"
 msgstr "Typ av klon:"
 
-#: lib/choose_repository.tcl:495
+#: lib/choose_repository.tcl:493
 msgid "Standard (Fast, Semi-Redundant, Hardlinks)"
 msgstr "Standard (snabb, semiredundant, hårda länkar)"
 
-#: lib/choose_repository.tcl:501
+#: lib/choose_repository.tcl:499
 msgid "Full Copy (Slower, Redundant Backup)"
 msgstr "Full kopia (långsammare, redundant säkerhetskopia)"
 
-#: lib/choose_repository.tcl:507
+#: lib/choose_repository.tcl:505
 msgid "Shared (Fastest, Not Recommended, No Backup)"
 msgstr "Delad (snabbast, rekommenderas ej, ingen säkerhetskopia)"
 
-#: 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 "Inte ett Gitarkiv: %s"
 
-#: lib/choose_repository.tcl:579
+#: lib/choose_repository.tcl:577
 msgid "Standard only available for local repository."
 msgstr "Standard är endast tillgängligt för lokala arkiv."
 
-#: lib/choose_repository.tcl:583
+#: lib/choose_repository.tcl:581
 msgid "Shared only available for local repository."
 msgstr "Delat är endast tillgängligt för lokala arkiv."
 
-#: lib/choose_repository.tcl:604
+#: lib/choose_repository.tcl:602
 #, tcl-format
 msgid "Location %s already exists."
 msgstr "Platsen %s finns redan."
 
-#: lib/choose_repository.tcl:615
+#: lib/choose_repository.tcl:613
 msgid "Failed to configure origin"
 msgstr "Kunde inte konfigurera ursprung"
 
-#: lib/choose_repository.tcl:627
+#: lib/choose_repository.tcl:625
 msgid "Counting objects"
 msgstr "Räknar objekt"
 
-#: lib/choose_repository.tcl:628
+#: lib/choose_repository.tcl:626
 msgid "buckets"
 msgstr "hinkar"
 
-#: lib/choose_repository.tcl:652
+#: lib/choose_repository.tcl:650
 #, tcl-format
 msgid "Unable to copy objects/info/alternates: %s"
 msgstr "Kunde inte kopiera objekt/info/alternativ: %s"
 
-#: lib/choose_repository.tcl:688
+#: lib/choose_repository.tcl:686
 #, tcl-format
 msgid "Nothing to clone from %s."
 msgstr "Ingenting att klona från %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 "Grenen \"master\" har inte initierats."
 
-#: lib/choose_repository.tcl:703
+#: lib/choose_repository.tcl:701
 msgid "Hardlinks are unavailable.  Falling back to copying."
 msgstr "Hårda länkar är inte tillgängliga. Faller tillbaka på kopiering."
 
-#: lib/choose_repository.tcl:715
+#: lib/choose_repository.tcl:713
 #, tcl-format
 msgid "Cloning from %s"
 msgstr "Klonar från %s"
 
-#: lib/choose_repository.tcl:746
+#: lib/choose_repository.tcl:744
 msgid "Copying objects"
 msgstr "Kopierar objekt"
 
-#: 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 "Kunde inte kopiera objekt: %s"
 
-#: lib/choose_repository.tcl:781
+#: lib/choose_repository.tcl:779
 msgid "Linking objects"
 msgstr "Länkar objekt"
 
-#: lib/choose_repository.tcl:782
+#: lib/choose_repository.tcl:780
 msgid "objects"
 msgstr "objekt"
 
-#: lib/choose_repository.tcl:790
+#: lib/choose_repository.tcl:788
 #, tcl-format
 msgid "Unable to hardlink object: %s"
 msgstr "Kunde inte hårdlänka objekt: %s"
 
-#: lib/choose_repository.tcl:845
+#: lib/choose_repository.tcl:843
 msgid "Cannot fetch branches and objects.  See console output for details."
 msgstr "Kunde inte hämta grenar och objekt. Se konsolutdata för detaljer."
 
-#: lib/choose_repository.tcl:856
+#: lib/choose_repository.tcl:854
 msgid "Cannot fetch tags.  See console output for details."
 msgstr "Kunde inte hämta taggar. Se konsolutdata för detaljer."
 
-#: lib/choose_repository.tcl:880
+#: lib/choose_repository.tcl:878
 msgid "Cannot determine HEAD.  See console output for details."
 msgstr "Kunde inte avgöra HEAD. Se konsolutdata för detaljer."
 
-#: lib/choose_repository.tcl:889
+#: lib/choose_repository.tcl:887
 #, tcl-format
 msgid "Unable to cleanup %s"
 msgstr "Kunde inte städa upp %s"
 
-#: lib/choose_repository.tcl:895
+#: lib/choose_repository.tcl:893
 msgid "Clone failed."
 msgstr "Kloning misslyckades."
 
-#: lib/choose_repository.tcl:902
+#: lib/choose_repository.tcl:900
 msgid "No default branch obtained."
 msgstr "Hämtade ingen standardgren."
 
-#: lib/choose_repository.tcl:913
+#: lib/choose_repository.tcl:911
 #, tcl-format
 msgid "Cannot resolve %s as a commit."
 msgstr "Kunde inte slå upp %s till någon incheckning."
 
-#: lib/choose_repository.tcl:925
+#: lib/choose_repository.tcl:923
 msgid "Creating working directory"
 msgstr "Skapar arbetskatalog"
 
-#: 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 "filer"
 
-#: lib/choose_repository.tcl:955
+#: lib/choose_repository.tcl:953
 msgid "Initial file checkout failed."
 msgstr "Inledande filutcheckning misslyckades."
 
-#: lib/choose_repository.tcl:971
+#: lib/choose_repository.tcl:969
 msgid "Open"
 msgstr "Öppna"
 
-#: lib/choose_repository.tcl:981
+#: lib/choose_repository.tcl:979
 msgid "Repository:"
 msgstr "Arkiv:"
 
-#: lib/choose_repository.tcl:1031
+#: lib/choose_repository.tcl:1027
 #, tcl-format
 msgid "Failed to open repository %s:"
 msgstr "Kunde inte öppna arkivet %s:"
@@ -1410,7 +1433,7 @@ msgstr ""
 msgid "Invalid date from Git: %s"
 msgstr "Ogiltigt datum från Git: %s"
 
-#: lib/diff.tcl:42
+#: lib/diff.tcl:44
 #, tcl-format
 msgid ""
 "No differences detected.\n"
@@ -1433,40 +1456,48 @@ msgstr ""
 "En sökning kommer automatiskt att startas för att hitta andra filer som kan "
 "vara i samma tillstånd."
 
-#: lib/diff.tcl:81
+#: lib/diff.tcl:83
 #, tcl-format
 msgid "Loading diff of %s..."
 msgstr "Läser differens för %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 "Kan inte visa %s"
 
-#: lib/diff.tcl:115
+#: lib/diff.tcl:117
 msgid "Error loading file:"
 msgstr "Fel vid läsning av fil:"
 
-#: lib/diff.tcl:122
+#: lib/diff.tcl:124
 msgid "Git Repository (subproject)"
 msgstr "Gitarkiv (underprojekt)"
 
-#: lib/diff.tcl:134
+#: lib/diff.tcl:136
 msgid "* Binary file (not showing content)."
 msgstr "* Binärfil (visar inte innehållet)."
 
-#: lib/diff.tcl:185
+#: lib/diff.tcl:191
 msgid "Error loading diff:"
 msgstr "Fel vid inläsning av differens:"
 
-#: lib/diff.tcl:303
+#: lib/diff.tcl:313
 msgid "Failed to unstage selected hunk."
 msgstr "Kunde inte ta bort den valda delen från kön."
 
-#: lib/diff.tcl:310
+#: lib/diff.tcl:320
 msgid "Failed to stage selected hunk."
 msgstr "Kunde inte lägga till den valda delen till kön."
 
+#: lib/diff.tcl:386
+msgid "Failed to unstage selected line."
+msgstr "Kunde inte ta bort den valda raden från kön."
+
+#: lib/diff.tcl:394
+msgid "Failed to stage selected line."
+msgstr "Kunde inte lägga till den valda raden till kön."
+
 #: lib/error.tcl:20 lib/error.tcl:114
 msgid "error"
 msgstr "fel"
@@ -1673,11 +1704,11 @@ msgstr "Avbryter"
 msgid "files reset"
 msgstr "filer återställda"
 
-#: lib/merge.tcl:265
+#: lib/merge.tcl:266
 msgid "Abort failed."
 msgstr "Misslyckades avbryta."
 
-#: lib/merge.tcl:267
+#: lib/merge.tcl:268
 msgid "Abort completed.  Ready."
 msgstr "Avbrytning fullbordad. Redo."
 
@@ -1731,39 +1762,47 @@ msgid "Match Tracking Branches"
 msgstr "Matcha spårade grenar"
 
 #: lib/option.tcl:126
+msgid "Blame Copy Only On Changed Files"
+msgstr "Klandra kopiering bara i ändrade filer"
+
+#: lib/option.tcl:127
+msgid "Minimum Letters To Blame Copy On"
+msgstr "Minsta antal tecken att klandra kopiering för"
+
+#: lib/option.tcl:128
 msgid "Number of Diff Context Lines"
 msgstr "Antal rader sammanhang i differenser"
 
-#: lib/option.tcl:127
+#: lib/option.tcl:129
 msgid "Commit Message Text Width"
 msgstr "Textbredd för incheckningsmeddelande"
 
-#: lib/option.tcl:128
+#: lib/option.tcl:130
 msgid "New Branch Name Template"
 msgstr "Mall för namn på nya grenar"
 
-#: lib/option.tcl:192
+#: lib/option.tcl:194
 msgid "Spelling Dictionary:"
 msgstr "Stavningsordlista:"
 
-#: lib/option.tcl:216
+#: lib/option.tcl:218
 msgid "Change Font"
 msgstr "Byt teckensnitt"
 
-#: lib/option.tcl:220
+#: lib/option.tcl:222
 #, tcl-format
 msgid "Choose %s"
 msgstr "Välj %s"
 
-#: lib/option.tcl:226
+#: lib/option.tcl:228
 msgid "pt."
 msgstr "p."
 
-#: lib/option.tcl:240
+#: lib/option.tcl:242
 msgid "Preferences"
 msgstr "Inställningar"
 
-#: lib/option.tcl:275
+#: lib/option.tcl:277
 msgid "Failed to completely save options:"
 msgstr "Misslyckades med att helt spara alternativ:"
 
@@ -1896,15 +1935,15 @@ msgstr "Stavningskontroll misslyckades tyst vid start"
 msgid "Unrecognized spell checker"
 msgstr "Stavningskontrollprogrammet känns inte igen"
 
-#: lib/spellcheck.tcl:180
+#: lib/spellcheck.tcl:186
 msgid "No Suggestions"
 msgstr "Inga förslag"
 
-#: lib/spellcheck.tcl:381
+#: lib/spellcheck.tcl:387
 msgid "Unexpected EOF from spell checker"
 msgstr "Oväntat filslut från stavningskontroll"
 
-#: lib/spellcheck.tcl:385
+#: lib/spellcheck.tcl:391
 msgid "Spell Checker Failed"
 msgstr "Stavningskontroll misslyckades"
 
@@ -1976,5 +2015,17 @@ msgstr "Använd tunt paket (för långsamma nätverksanslutningar)"
 msgid "Include tags"
 msgstr "Ta med taggar"
 
+#~ msgid ""
+#~ "Unable to start gitk:\n"
+#~ "\n"
+#~ "%s does not exist"
+#~ msgstr ""
+#~ "Kan inte starta gitk:\n"
+#~ "\n"
+#~ "%s finns inte"
+
+#~ msgid "Apple"
+#~ msgstr "Äpple"
+
 #~ msgid "Not connected to aspell"
 #~ msgstr "Inte ansluten till aspell"
index 645e1147dc886f2b1ca6d2020b44db746b082bf0..1dadbb49666c6d796df76babbfd291a2de4357e4 100755 (executable)
@@ -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
 
index 4e334ba41dad3067394b79c15ebfe610b2d3e178..edb6ec6ed00b74764764802d0ebae56d223a2ac6 100755 (executable)
@@ -145,7 +145,16 @@ pick_one () {
 }
 
 pick_one_preserving_merges () {
-       case "$1" in -n) sha1=$2 ;; *) sha1=$1 ;; esac
+       fast_forward=t
+       case "$1" in
+       -n)
+               fast_forward=f
+               sha1=$2
+               ;;
+       *)
+               sha1=$1
+               ;;
+       esac
        sha1=$(git rev-parse $sha1)
 
        if test -f "$DOTEST"/current-commit
@@ -156,15 +165,14 @@ pick_one_preserving_merges () {
                die "Cannot write current commit's replacement sha1"
        fi
 
+       echo $sha1 > "$DOTEST"/current-commit
+
        # rewrite parents; if none were rewritten, we can fast-forward.
-       fast_forward=t
-       preserve=t
        new_parents=
        for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-)
        do
                if test -f "$REWRITTEN"/$p
                then
-                       preserve=f
                        new_p=$(cat "$REWRITTEN"/$p)
                        test $p != $new_p && fast_forward=f
                        case "$new_parents" in
@@ -181,7 +189,8 @@ pick_one_preserving_merges () {
        case $fast_forward in
        t)
                output warn "Fast forward to $sha1"
-               test $preserve = f || echo $sha1 > "$REWRITTEN"/$sha1
+               output git reset --hard $sha1 ||
+                       die "Cannot fast forward to $sha1"
                ;;
        f)
                test "a$1" = a-n && die "Refusing to squash a merge: $sha1"
@@ -191,7 +200,6 @@ pick_one_preserving_merges () {
                output git checkout $first_parent 2> /dev/null ||
                        die "Cannot move HEAD to $first_parent"
 
-               echo $sha1 > "$DOTEST"/current-commit
                case "$new_parents" in
                ' '*' '*)
                        # redo merge
@@ -276,7 +284,7 @@ do_next () {
                pick_one $sha1 ||
                        die_with_patch $sha1 "Could not apply $sha1... $rest"
                make_patch $sha1
-               : > "$DOTEST"/amend
+               git rev-parse --verify HEAD > "$DOTEST"/amend
                warn "Stopped at $sha1... $rest"
                warn "You can amend the commit now, with"
                warn
@@ -419,14 +427,22 @@ do
                else
                        . "$DOTEST"/author-script ||
                                die "Cannot find the author identity"
+                       amend=
                        if test -f "$DOTEST"/amend
                        then
+                               amend=$(git rev-parse --verify HEAD)
+                               test "$amend" = $(cat "$DOTEST"/amend) ||
+                               die "\
+You have uncommitted changes in your working tree. Please, commit them
+first and then run 'git rebase --continue' again."
                                git reset --soft HEAD^ ||
                                die "Cannot rewind the HEAD"
                        fi
                        export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE &&
-                       git commit --no-verify -F "$DOTEST"/message -e ||
-                       die "Could not commit staged changes."
+                       git commit --no-verify -F "$DOTEST"/message -e || {
+                               test -n "$amend" && git reset --soft $amend
+                               die "Could not commit staged changes."
+                       }
                fi
 
                require_clean_work_tree
index 412e135c3ae88d76b5bdf3f08083b153da220a95..528b604cd57a774030c5f5830d3d78b5a04454cf 100755 (executable)
@@ -144,8 +144,19 @@ is_interactive () {
        done && test -n "$1"
 }
 
+test -f "$GIT_DIR"/rebase-apply/applying &&
+       die 'It looks like git-am is in progress. Cannot rebase.'
+
 is_interactive "$@" && exec git-rebase--interactive "$@"
 
+if test $# -eq 0
+then
+       test -d "$dotest" -o -d "$GIT_DIR"/rebase-apply || usage
+       test -d "$dotest" -o -f "$GIT_DIR"/rebase-apply/rebasing &&
+               die 'A rebase is in progress, try --continue, --skip or --abort.'
+       die "No arguments given and $GIT_DIR/rebase-apply already exists."
+fi
+
 while test $# != 0
 do
        case "$1" in
@@ -268,16 +279,16 @@ done
 # Make sure we do not have $GIT_DIR/rebase-apply
 if test -z "$do_merge"
 then
-       if mkdir "$GIT_DIR"/rebase-apply
+       if mkdir "$GIT_DIR"/rebase-apply 2>/dev/null
        then
                rmdir "$GIT_DIR"/rebase-apply
        else
                echo >&2 '
-It seems that I cannot create a '"$GIT_DIR"'/rebase-apply directory,
-and I wonder if you are in the middle of patch application or another
+It seems that I cannot create a rebase-apply directory, and
+I wonder if you are in the middle of patch application or another
 rebase.  If that is not the case, please
        rm -fr '"$GIT_DIR"'/rebase-apply
- and run me again.  I am stopping in case you still have something
+and run me again.  I am stopping in case you still have something
 valuable there.'
                exit 1
        fi
@@ -285,7 +296,7 @@ else
        if test -d "$dotest"
        then
                die "previous rebase directory $dotest still exists." \
-                       'try git-rebase < --continue | --abort >'
+                       'Try git rebase (--continue | --abort | --skip)'
        fi
 fi
 
index d4609ed66e56dc6021c800d60286bec38615ff39..d799c763788ecd64b2508668f04c329b2de0c391 100755 (executable)
@@ -1,7 +1,13 @@
 #!/bin/sh
 # Copyright (c) 2007, Nanako Shiraishi
 
-USAGE='[  | save | list | show | apply | clear | drop | pop | create ]'
+dashless=$(basename "$0" | sed -e 's/-/ /')
+USAGE="list [<options>]
+   or: $dashless (show | drop | pop ) [<stash>]
+   or: $dashless apply [--index] [<stash>]
+   or: $dashless branch <branchname> [<stash>]
+   or: $dashless [save [--keep-index] [<message>]]
+   or: $dashless clear"
 
 SUBDIRECTORY_OK=Yes
 OPTIONS_SPEC=
@@ -33,6 +39,7 @@ clear_stash () {
 create_stash () {
        stash_msg="$1"
 
+       git update-index -q --refresh
        if no_changes
        then
                exit 0
@@ -95,6 +102,7 @@ save_stash () {
 
        stash_msg="$*"
 
+       git update-index -q --refresh
        if no_changes
        then
                echo 'No local changes to save'
@@ -144,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'
 
index b40f876a2ca9fe985cedc622ab28a9f461edc5ab..1c39b593a628cc94d24d227cc5d92e00ac5e71ed 100755 (executable)
@@ -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 '
 }
 
 #
@@ -198,6 +207,26 @@ cmd_add()
        die "Failed to register submodule '$path'"
 }
 
+#
+# 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
 #
@@ -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)
index cf6dbbc42773fef394c27cd87109b69c3144753c..88066c9a7561c45e59d8fc425382d5d86fc3281f 100755 (executable)
@@ -66,7 +66,7 @@ BEGIN
        $_version, $_fetch_all, $_no_rebase,
        $_merge, $_strategy, $_dry_run, $_local,
        $_prefix, $_no_checkout, $_url, $_verbose,
-       $_git_format);
+       $_git_format, $_commit_url);
 $Git::SVN::_follow_parent = 1;
 my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
                     'config-dir=s' => \$Git::SVN::Ra::config_dir,
@@ -127,6 +127,8 @@ BEGIN
                          'verbose|v' => \$_verbose,
                          'dry-run|n' => \$_dry_run,
                          'fetch-all|all' => \$_fetch_all,
+                         'commit-url=s' => \$_commit_url,
+                         'revision|r=i' => \$_revision,
                          'no-rebase' => \$_no_rebase,
                        %cmt_opts, %fc_opts } ],
        'set-tree' => [ \&cmd_set_tree,
@@ -169,7 +171,8 @@ BEGIN
                          'color' => \$Git::SVN::Log::color,
                          'pager=s' => \$Git::SVN::Log::pager
                        } ],
-       'find-rev' => [ \&cmd_find_rev, "Translate between SVN revision numbers and tree-ish",
+       'find-rev' => [ \&cmd_find_rev,
+                       "Translate between SVN revision numbers and tree-ish",
                        {} ],
        'rebase' => [ \&cmd_rebase, "Fetch and rebase your working directory",
                        { 'merge|m|M' => \$_merge,
@@ -229,7 +232,9 @@ BEGIN
 my %opts = %{$cmd{$cmd}->[2]} if (defined $cmd);
 
 read_repo_config(\%opts);
-Getopt::Long::Configure('pass_through') if ($cmd && ($cmd eq 'log' || $cmd eq 'blame'));
+if ($cmd && ($cmd eq 'log' || $cmd eq 'blame')) {
+       Getopt::Long::Configure('pass_through');
+}
 my $rv = GetOptions(%opts, 'help|H|h' => \$_help, 'version|V' => \$_version,
                     'minimize-connections' => \$Git::SVN::Migration::_minimize,
                     'id|i=s' => \$Git::SVN::default_ref_id,
@@ -416,14 +421,15 @@ sub cmd_dcommit {
        $head ||= 'HEAD';
        my @refs;
        my ($url, $rev, $uuid, $gs) = working_head_info($head, \@refs);
-       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 $last_rev;
+       $url = defined $_commit_url ? $_commit_url : $gs->full_url;
+       my $last_rev = $_revision if defined $_revision;
+       if ($url) {
+               print "Committing to $url ...\n";
+       }
        my ($linear_refs, $parents) = linearize_history($gs, \@refs);
        if ($_no_rebase && scalar(@$linear_refs) > 1) {
                warn "Attempting to commit more than one change while ",
@@ -431,6 +437,8 @@ sub cmd_dcommit {
                     "If these changes depend on each other, re-running ",
                     "without --no-rebase may be required."
        }
+       my $expect_url = $url;
+       Git::SVN::remove_username($expect_url);
        while (1) {
                my $d = shift @$linear_refs or last;
                unless (defined $last_rev) {
@@ -446,7 +454,7 @@ sub cmd_dcommit {
                        my $cmt_rev;
                        my %ed_opts = ( r => $last_rev,
                                        log => get_commit_entry($d)->{log},
-                                       ra => Git::SVN::Ra->new($gs->full_url),
+                                       ra => Git::SVN::Ra->new($url),
                                        config => SVN::Core::config_get_config(
                                                $Git::SVN::Ra::config_dir
                                        ),
@@ -505,9 +513,9 @@ sub cmd_dcommit {
                                          $gs->refname,
                                          "\nBefore dcommitting";
                                }
-                               if ($url_ ne $url) {
+                               if ($url_ ne $expect_url) {
                                        fatal "URL mismatch after rebase: ",
-                                             "$url_ != $url";
+                                             "$url_ != $expect_url";
                                }
                                if ($uuid_ ne $uuid) {
                                        fatal "uuid mismatch after rebase: ",
@@ -795,17 +803,37 @@ 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(shift or ".");
-       unless (scalar(@_) == 0) {
+       my $path = canonicalize_path(defined($_[0]) ? $_[0] : ".");
+       my $fullpath = canonicalize_path($cmd_dir_prefix . $path);
+       if (exists $_[1]) {
                die "Too many arguments specified\n";
        }
 
        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');
@@ -813,21 +841,25 @@ sub cmd_info {
                die "Unable to determine upstream SVN information from ",
                    "working tree history\n";
        }
-       my $full_url = $url . ($path eq "." ? "" : "/$path");
+
+       # canonicalize_path() will return "" to make libsvn 1.5.x happy,
+       $path = "." if $path eq "";
+
+       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";
@@ -849,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>) {
@@ -980,8 +1012,10 @@ sub complete_url_ls_init {
        if (length $pfx && $pfx !~ m#/$#) {
                die "--prefix='$pfx' must have a trailing slash '/'\n";
        }
-       command_noisy('config', "svn-remote.$gs->{repo_id}.$n",
-                               "$remote_path:refs/remotes/$pfx*");
+       command_noisy('config',
+                     "svn-remote.$gs->{repo_id}.$n",
+                     "$remote_path:refs/remotes/$pfx*" .
+                       ('/*' x (($remote_path =~ tr/*/*/) - 1)) );
 }
 
 sub verify_ref {
@@ -1253,7 +1287,7 @@ sub md5sum {
        my $arg = shift;
        my $ref = ref $arg;
        my $md5 = Digest::MD5->new();
-        if ($ref eq 'GLOB' || $ref eq 'IO::File') {
+        if ($ref eq 'GLOB' || $ref eq 'IO::File' || $ref eq 'File::Temp') {
                $md5->addfile($arg) or croak $!;
        } elsif ($ref eq 'SCALAR') {
                $md5->add($$arg) or croak $!;
@@ -1316,6 +1350,7 @@ BEGIN
        }
 }
 
+
 my (%LOCKFILES, %INDEX_FILES);
 END {
        unlink keys %LOCKFILES if %LOCKFILES;
@@ -1420,8 +1455,12 @@ sub read_all_remotes {
            svn.useSvmProps/) };
        $use_svm_props = $use_svm_props eq 'true' if $use_svm_props;
        foreach (grep { s/^svn-remote\.// } command(qw/config -l/)) {
-               if (m!^(.+)\.fetch=\s*(.*)\s*:\s*refs/remotes/(.+)\s*$!) {
-                       my ($remote, $local_ref, $remote_ref) = ($1, $2, $3);
+               if (m!^(.+)\.fetch=\s*(.*)\s*:\s*(.+)\s*$!) {
+                       my ($remote, $local_ref, $_remote_ref) = ($1, $2, $3);
+                       die("svn-remote.$remote: remote ref '$_remote_ref' "
+                           . "must start with 'refs/remotes/'\n")
+                               unless $_remote_ref =~ m{^refs/remotes/(.+)};
+                       my $remote_ref = $1;
                        $local_ref =~ s{^/}{};
                        $r->{$remote}->{fetch}->{$local_ref} = $remote_ref;
                        $r->{$remote}->{svm} = {} if $use_svm_props;
@@ -3214,13 +3253,11 @@ sub change_file_prop {
 
 sub apply_textdelta {
        my ($self, $fb, $exp) = @_;
-       my $fh = IO::File->new_tmpfile;
-       $fh->autoflush(1);
+       my $fh = Git::temp_acquire('svn_delta');
        # $fh gets auto-closed() by SVN::TxDelta::apply(),
        # (but $base does not,) so dup() it for reading in close_file
        open my $dup, '<&', $fh or croak $!;
-       my $base = IO::File->new_tmpfile;
-       $base->autoflush(1);
+       my $base = Git::temp_acquire('git_blob');
        if ($fb->{blob}) {
                print $base 'link ' if ($fb->{mode_a} == 120000);
                my $size = $::_repository->cat_blob($fb->{blob}, $base);
@@ -3235,9 +3272,9 @@ sub apply_textdelta {
                }
        }
        seek $base, 0, 0 or croak $!;
-       $fb->{fh} = $dup;
+       $fb->{fh} = $fh;
        $fb->{base} = $base;
-       [ SVN::TxDelta::apply($base, $fh, undef, $fb->{path}, $fb->{pool}) ];
+       [ SVN::TxDelta::apply($base, $dup, undef, $fb->{path}, $fb->{pool}) ];
 }
 
 sub close_file {
@@ -3253,35 +3290,36 @@ sub close_file {
                                    "expected: $exp\n    got: $got\n";
                        }
                }
-               sysseek($fh, 0, 0) or croak $!;
                if ($fb->{mode_b} == 120000) {
-                       eval {
-                               sysread($fh, my $buf, 5) == 5 or croak $!;
-                               $buf eq 'link ' or die "$path has mode 120000",
-                                                      " but is not a link";
-                       };
-                       if ($@) {
-                               warn "$@\n";
-                               sysseek($fh, 0, 0) or croak $!;
-                       }
-               }
+                       sysseek($fh, 0, 0) or croak $!;
+                       sysread($fh, my $buf, 5) == 5 or croak $!;
 
-               my ($tmp_fh, $tmp_filename) = File::Temp::tempfile(UNLINK => 1);
-               my $result;
-               while ($result = sysread($fh, my $string, 1024)) {
-                       my $wrote = syswrite($tmp_fh, $string, $result);
-                       defined($wrote) && $wrote == $result
-                               or croak("write $tmp_filename: $!\n");
-               }
-               defined $result or croak $!;
-               close $tmp_fh or croak $!;
+                       unless ($buf eq 'link ') {
+                               warn "$path has mode 120000",
+                                               " but is not a link\n";
+                       } else {
+                               my $tmp_fh = Git::temp_acquire('svn_hash');
+                               my $res;
+                               while ($res = sysread($fh, my $str, 1024)) {
+                                       my $out = syswrite($tmp_fh, $str, $res);
+                                       defined($out) && $out == $res
+                                               or croak("write ",
+                                                       Git::temp_path($tmp_fh),
+                                                       ": $!\n");
+                               }
+                               defined $res or croak $!;
 
-               close $fh or croak $!;
+                               ($fh, $tmp_fh) = ($tmp_fh, $fh);
+                               Git::temp_release($tmp_fh, 1);
+                       }
+               }
 
-               $hash = $::_repository->hash_and_insert_object($tmp_filename);
-               unlink($tmp_filename);
+               $hash = $::_repository->hash_and_insert_object(
+                               Git::temp_path($fh));
                $hash =~ /^[a-f\d]{40}$/ or die "not a sha1: $hash\n";
-               close $fb->{base} or croak $!;
+
+               Git::temp_release($fb->{base}, 1);
+               Git::temp_release($fh, 1);
        } else {
                $hash = $fb->{blob} or die "no blob information\n";
        }
@@ -3362,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';
@@ -3618,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});
 
@@ -3644,35 +3684,53 @@ 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 = IO::File->new_tmpfile or croak $!;
-       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);
+       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;
-
-       close $fh or croak $!;
 }
 
 sub D {
@@ -3967,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);
@@ -4113,16 +4172,38 @@ sub gs_fetch_loop_common {
        Git::SVN::gc();
 }
 
+sub get_dir_globbed {
+       my ($self, $left, $depth, $r) = @_;
+
+       my @x = eval { $self->get_dir($left, $r) };
+       return unless scalar @x == 3;
+       my $dirents = $x[0];
+       my @finalents;
+       foreach my $de (keys %$dirents) {
+               next if $dirents->{$de}->{kind} != $SVN::Node::dir;
+               if ($depth > 1) {
+                       my @args = ("$left/$de", $depth - 1, $r);
+                       foreach my $dir ($self->get_dir_globbed(@args)) {
+                               push @finalents, "$de/$dir";
+                       }
+               } else {
+                       push @finalents, $de;
+               }
+       }
+       @finalents;
+}
+
 sub match_globs {
        my ($self, $exists, $paths, $globs, $r) = @_;
 
        sub get_dir_check {
                my ($self, $exists, $g, $r) = @_;
-               my @x = eval { $self->get_dir($g->{path}->{left}, $r) };
-               return unless scalar @x == 3;
-               my $dirents = $x[0];
-               foreach my $de (keys %$dirents) {
-                       next if $dirents->{$de}->{kind} != $SVN::Node::dir;
+
+               my @dirs = $self->get_dir_globbed($g->{path}->{left},
+                                                 $g->{path}->{depth},
+                                                 $r);
+
+               foreach my $de (@dirs) {
                        my $p = $g->{path}->full_path($de);
                        next if $exists->{$p};
                        next if (length $g->{path}->{right} &&
@@ -4344,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
@@ -4904,15 +4985,20 @@ sub new {
        my ($class, $glob) = @_;
        my $re = $glob;
        $re =~ s!/+$!!g; # no need for trailing slashes
-       my $nr = ($re =~ s!^(.*)\*(.*)$!\(\[^/\]+\)!g);
-       my ($left, $right) = ($1, $2);
-       if ($nr > 1) {
-               die "Only one '*' wildcard expansion ",
-                   "is supported (got $nr): '$glob'\n";
-       } elsif ($nr == 0) {
+       $re =~ m!^([^*]*)(\*(?:/\*)*)([^*]*)$!;
+       my $temp = $re;
+       my ($left, $right) = ($1, $3);
+       $re = $2;
+       my $depth = $re =~ tr/*/*/;
+       if ($depth != $temp =~ tr/*/*/) {
+               die "Only one set of wildcard directories " .
+                       "(e.g. '*' or '*/*/*') is supported: '$glob'\n";
+       }
+       if ($depth == 0) {
                die "One '*' is needed for glob: '$glob'\n";
        }
-       $re = quotemeta($left) . $re . quotemeta($right);
+       $re =~ s!\*!\[^/\]*!g;
+       $re = quotemeta($left) . "($re)" . quotemeta($right);
        if (length $left && !($left =~ s!/+$!!g)) {
                die "Missing trailing '/' on left side of: '$glob' ($left)\n";
        }
@@ -4921,7 +5007,7 @@ sub new {
        }
        my $left_re = qr/^\/\Q$left\E(\/|$)/;
        bless { left => $left, right => $right, left_regex => $left_re,
-               regex => qr/$re/, glob => $glob }, $class;
+               regex => qr/$re/, glob => $glob, depth => $depth }, $class;
 }
 
 sub full_path {
diff --git a/git.c b/git.c
index 37b1d76a08ca59f3de54e11890dce962403cf8d3..905acc2f2cd591bd3bd65008f7a72a5642a21f35 100644 (file)
--- a/git.c
+++ b/git.c
@@ -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",
index c6492e5be2763eab81358424ff625a34a5ff2fba..6733b6f5551e43835fcf46793142d9d7ffbe27f9 100644 (file)
@@ -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.
 
index fddcb45817ed6839ba95965d7e57e9a2e04ae30a..2eaa2ae7d6f692f6063ebbd211eaab30212c2eae 100644 (file)
@@ -22,11 +22,11 @@ proc gitdir {} {
 # run before X event handlers, so reading from a fast source can
 # make the GUI completely unresponsive.
 proc run args {
-    global isonrunq runq
+    global isonrunq runq currunq
 
     set script $args
     if {[info exists isonrunq($script)]} return
-    if {$runq eq {}} {
+    if {$runq eq {} && ![info exists currunq]} {
        after idle dorunq
     }
     lappend runq [list {} $script]
@@ -38,10 +38,10 @@ proc filerun {fd script} {
 }
 
 proc filereadable {fd script} {
-    global runq
+    global runq currunq
 
     fileevent $fd readable {}
-    if {$runq eq {}} {
+    if {$runq eq {} && ![info exists currunq]} {
        after idle dorunq
     }
     lappend runq [list $fd $script]
@@ -60,17 +60,19 @@ proc nukefile {fd} {
 }
 
 proc dorunq {} {
-    global isonrunq runq
+    global isonrunq runq currunq
 
     set tstart [clock clicks -milliseconds]
     set t0 $tstart
     while {[llength $runq] > 0} {
        set fd [lindex $runq 0 0]
        set script [lindex $runq 0 1]
+       set currunq [lindex $runq 0]
+       set runq [lrange $runq 1 end]
        set repeat [eval $script]
+       unset currunq
        set t1 [clock clicks -milliseconds]
        set t [expr {$t1 - $t0}]
-       set runq [lrange $runq 1 end]
        if {$repeat ne {} && $repeat} {
            if {$fd eq {} || $repeat == 2} {
                # script returns 1 if it wants to be readded
@@ -90,6 +92,15 @@ proc dorunq {} {
     }
 }
 
+proc reg_instance {fd} {
+    global commfd leftover loginstance
+
+    set i [incr loginstance]
+    set commfd($i) $fd
+    set leftover($i) {}
+    return $i
+}
+
 proc unmerged_files {files} {
     global nr_unmerged
 
@@ -294,11 +305,11 @@ proc parseviewrevs {view revs} {
 # Start off a git log process and arrange to read its output
 proc start_rev_list {view} {
     global startmsecs commitidx viewcomplete curview
-    global commfd leftover tclencoding
+    global tclencoding
     global viewargs viewargscmd viewfiles vfilelimit
     global showlocalchanges commitinterest
-    global viewactive loginstance viewinstances vmergeonly
-    global pending_select mainheadid
+    global viewactive viewinstances vmergeonly
+    global mainheadid
     global vcanopt vflags vrevs vorigargs
 
     set startmsecs [clock clicks -milliseconds]
@@ -354,10 +365,8 @@ proc start_rev_list {view} {
        error_popup "[mc "Error executing git log:"] $err"
        return 0
     }
-    set i [incr loginstance]
+    set i [reg_instance $fd]
     set viewinstances($view) [list $i]
-    set commfd($i) $fd
-    set leftover($i) {}
     if {$showlocalchanges && $mainheadid ne {}} {
        lappend commitinterest($mainheadid) {dodiffindex}
     }
@@ -367,36 +376,65 @@ proc start_rev_list {view} {
     }
     filerun $fd [list getcommitlines $fd $i $view 0]
     nowbusy $view [mc "Reading"]
-    if {$view == $curview} {
-       set pending_select $mainheadid
-    }
     set viewcomplete($view) 0
     set viewactive($view) 1
     return 1
 }
 
-proc stop_rev_list {view} {
-    global commfd viewinstances leftover
+proc stop_instance {inst} {
+    global commfd leftover
 
-    foreach inst $viewinstances($view) {
-       set fd $commfd($inst)
-       catch {
-           set pid [pid $fd]
+    set fd $commfd($inst)
+    catch {
+       set pid [pid $fd]
+
+       if {$::tcl_platform(platform) eq {windows}} {
+           exec kill -f $pid
+       } else {
            exec kill $pid
        }
-       catch {close $fd}
-       nukefile $fd
-       unset commfd($inst)
-       unset leftover($inst)
+    }
+    catch {close $fd}
+    nukefile $fd
+    unset commfd($inst)
+    unset leftover($inst)
+}
+
+proc stop_backends {} {
+    global commfd
+
+    foreach inst [array names commfd] {
+       stop_instance $inst
+    }
+}
+
+proc stop_rev_list {view} {
+    global viewinstances
+
+    foreach inst $viewinstances($view) {
+       stop_instance $inst
     }
     set viewinstances($view) {}
 }
 
-proc getcommits {} {
+proc reset_pending_select {selid} {
+    global pending_select mainheadid selectheadid
+
+    if {$selid ne {}} {
+       set pending_select $selid
+    } elseif {$selectheadid ne {}} {
+       set pending_select $selectheadid
+    } else {
+       set pending_select $mainheadid
+    }
+}
+
+proc getcommits {selid} {
     global canv curview need_redisplay viewactive
 
     initlayout
     if {[start_rev_list $curview]} {
+       reset_pending_select $selid
        show_status [mc "Reading commits..."]
        set need_redisplay 1
     } else {
@@ -406,8 +444,8 @@ proc getcommits {} {
 
 proc updatecommits {} {
     global curview vcanopt vorigargs vfilelimit viewinstances
-    global viewactive viewcomplete loginstance tclencoding
-    global startmsecs commfd showneartags showlocalchanges leftover
+    global viewactive viewcomplete tclencoding
+    global startmsecs showneartags showlocalchanges
     global mainheadid pending_select
     global isworktree
     global varcid vposids vnegids vflags vrevs
@@ -468,10 +506,8 @@ proc updatecommits {} {
     if {$viewactive($view) == 0} {
        set startmsecs [clock clicks -milliseconds]
     }
-    set i [incr loginstance]
+    set i [reg_instance $fd]
     lappend viewinstances($view) $i
-    set commfd($i) $fd
-    set leftover($i) {}
     fconfigure $fd -blocking 0 -translation lf -eofchar {}
     if {$tclencoding != {}} {
        fconfigure $fd -encoding $tclencoding
@@ -479,7 +515,7 @@ proc updatecommits {} {
     filerun $fd [list getcommitlines $fd $i $view 1]
     incr viewactive($view)
     set viewcomplete($view) 0
-    set pending_select $mainheadid
+    reset_pending_select {}
     nowbusy $view "Reading"
     if {$showneartags} {
        getallcommits
@@ -491,6 +527,11 @@ proc reloadcommits {} {
     global showneartags treediffs commitinterest cached_commitrow
     global targetid
 
+    set selid {}
+    if {$selectedline ne {}} {
+       set selid $currentid
+    }
+
     if {!$viewcomplete($curview)} {
        stop_rev_list $curview
     }
@@ -509,7 +550,7 @@ proc reloadcommits {} {
     catch {unset cached_commitrow}
     catch {unset targetid}
     setcanvscroll
-    getcommits
+    getcommits $selid
     return 0
 }
 
@@ -1469,8 +1510,15 @@ proc chewcommits {} {
        global numcommits startmsecs
 
        if {[info exists pending_select]} {
-           set row [first_real_row]
-           selectline $row 1
+           update
+           reset_pending_select {}
+
+           if {[commitinview $pending_select $curview]} {
+               selectline [rowofcommit $pending_select] 1
+           } else {
+               set row [first_real_row]
+               selectline $row 1
+           }
        }
        if {$commitidx($curview) > 0} {
            #set ms [expr {[clock clicks -milliseconds] - $startmsecs}]
@@ -1563,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}
@@ -1609,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
@@ -2103,6 +2158,7 @@ proc makewindow {} {
     bind . <$M1B-minus> {incrfont -1}
     bind . <$M1B-KP_Subtract> {incrfont -1}
     wm protocol . WM_DELETE_WINDOW doquit
+    bind . <Destroy> {stop_backends}
     bind . <Button-1> "click %W"
     bind $fstring <Key-Return> {dofind 1 1}
     bind $sha1entry <Key-Return> gotocommit
@@ -2158,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
@@ -2965,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} {}
@@ -3300,10 +3379,7 @@ proc showview {n} {
 
     run refill_reflist
     if {![info exists viewcomplete($n)]} {
-       if {$selid ne {}} {
-           set pending_select $selid
-       }
-       getcommits
+       getcommits $selid
        return
     }
 
@@ -3337,18 +3413,18 @@ proc showview {n} {
     drawvisible
     if {$row ne {}} {
        selectline $row 0
-    } elseif {$mainheadid ne {} && [commitinview $mainheadid $curview]} {
-       selectline [rowofcommit $mainheadid] 1
     } elseif {!$viewcomplete($n)} {
-       if {$selid ne {}} {
-           set pending_select $selid
-       } else {
-           set pending_select $mainheadid
-       }
+       reset_pending_select $selid
     } else {
-       set row [first_real_row]
-       if {$row < $numcommits} {
-           selectline $row 0
+       reset_pending_select {}
+
+       if {[commitinview $pending_select $curview]} {
+           selectline [rowofcommit $pending_select] 1
+       } else {
+           set row [first_real_row]
+           if {$row < $numcommits} {
+               selectline $row 0
+           }
        }
     }
     if {!$viewcomplete($n)} {
@@ -4011,6 +4087,7 @@ proc layoutmore {} {
     }
     if {[info exists pending_select] &&
        [commitinview $pending_select $curview]} {
+       update
        selectline [rowofcommit $pending_select] 1
     }
     drawvisible
@@ -4048,10 +4125,11 @@ proc dodiffindex {} {
     incr lserial
     set fd [open "|git diff-index --cached HEAD" r]
     fconfigure $fd -blocking 0
-    filerun $fd [list readdiffindex $fd $lserial]
+    set i [reg_instance $fd]
+    filerun $fd [list readdiffindex $fd $lserial $i]
 }
 
-proc readdiffindex {fd serial} {
+proc readdiffindex {fd serial inst} {
     global mainheadid nullid nullid2 curview commitinfo commitdata lserial
 
     set isdiff 1
@@ -4062,7 +4140,7 @@ proc readdiffindex {fd serial} {
        set isdiff 0
     }
     # we only need to see one line and we don't really care what it says...
-    close $fd
+    stop_instance $inst
 
     if {$serial != $lserial} {
        return 0
@@ -4071,7 +4149,8 @@ proc readdiffindex {fd serial} {
     # now see if there are any local changes not checked in to the index
     set fd [open "|git diff-files" r]
     fconfigure $fd -blocking 0
-    filerun $fd [list readdifffiles $fd $serial]
+    set i [reg_instance $fd]
+    filerun $fd [list readdifffiles $fd $serial $i]
 
     if {$isdiff && ![commitinview $nullid2 $curview]} {
        # add the line for the changes in the index to the graph
@@ -4088,7 +4167,7 @@ proc readdiffindex {fd serial} {
     return 0
 }
 
-proc readdifffiles {fd serial} {
+proc readdifffiles {fd serial inst} {
     global mainheadid nullid nullid2 curview
     global commitinfo commitdata lserial
 
@@ -4100,7 +4179,7 @@ proc readdifffiles {fd serial} {
        set isdiff 0
     }
     # we only need to see one line and we don't really care what it says...
-    close $fd
+    stop_instance $inst
 
     if {$serial != $lserial} {
        return 0
@@ -6430,9 +6509,10 @@ proc diffcmd {ids flags} {
 proc gettreediffs {ids} {
     global treediff treepending
 
+    if {[catch {set gdtf [open [diffcmd $ids {--no-commit-id}] r]}]} return
+
     set treepending $ids
     set treediff {}
-    if {[catch {set gdtf [open [diffcmd $ids {--no-commit-id}] r]}]} return
     fconfigure $gdtf -blocking 0
     filerun $gdtf [list gettreediffline $gdtf $ids]
 }
@@ -9817,6 +9897,9 @@ if {![file isdirectory $gitdir]} {
     exit 1
 }
 
+set selecthead {}
+set selectheadid {}
+
 set revtreeargs {}
 set cmdline_files {}
 set i 0
@@ -9828,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]
        }
@@ -9838,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 {
@@ -9945,4 +10035,4 @@ if {[info exists permviews]} {
        addviewmenu $n
     }
 }
-getcommits
+getcommits {}
index b9867bf8e05d06f7effb9919f00879f77690e185..04ee5709951b4ea4c63b495fd222fcf4b5397afc 100644 (file)
@@ -7,19 +7,37 @@ msgid ""
 msgstr ""
 "Project-Id-Version: git-gui\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-05-01 11:54+0200\n"
-"PO-Revision-Date: 2008-05-02 21:12+0200\n"
+"POT-Creation-Date: 2008-05-24 22:32+0200\n"
+"PO-Revision-Date: 2008-05-24 22:40+0200\n"
 "Last-Translator: Christian Stimming <stimming@tuhh.de>\n"
 "Language-Team: German\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: gitk:111
-msgid "Error executing git rev-list:"
-msgstr "Fehler beim Ausführen von git-rev-list:"
+#: gitk:102
+msgid "Couldn't get list of unmerged files:"
+msgstr "Liste der nicht-zusammengeführten Dateien nicht gefunden:"
+
+#: gitk:329
+msgid "No files selected: --merge specified but no files are unmerged."
+msgstr ""
+"Keine Dateien ausgewählt: --merge angegeben, es existieren aber keine nicht-"
+"zusammengeführten Dateien."
+
+#: gitk:332
+msgid ""
+"No files selected: --merge specified but no unmerged files are within file "
+"limit."
+msgstr ""
+"Keine Dateien ausgewähle: --merge angegeben, aber keine nicht-"
+"zusammengeführten Dateien sind in der Dateiauswahl."
 
-#: gitk:124
+#: gitk:354
+msgid "Error executing git log:"
+msgstr "Fehler beim Ausführen von git-log:"
+
+#: gitk:369
 msgid "Reading"
 msgstr "Lesen"
 
@@ -56,7 +74,11 @@ msgstr "Datei"
 msgid "Update"
 msgstr "Aktualisieren"
 
-#: gitk:664
+#: gitk:1722
+msgid "Reload"
+msgstr "Neu laden"
+
+#: gitk:1723
 msgid "Reread references"
 msgstr "Zweige neu laden"
 
@@ -112,7 +134,11 @@ msgstr "Tastenkürzel"
 msgid "SHA1 ID: "
 msgstr "SHA1:"
 
-#: gitk:791
+#: gitk:1831
+msgid "Row"
+msgstr "Zeile"
+
+#: gitk:1862
 msgid "Find"
 msgstr "Suche"
 
@@ -126,19 +152,19 @@ msgstr "vorige"
 
 #: gitk:794
 msgid "commit"
-msgstr "Version"
+msgstr "Version nach"
 
 #: gitk:797 gitk:799 gitk:2356 gitk:2379 gitk:2403 gitk:4306 gitk:4369
 msgid "containing:"
-msgstr "enthaltend:"
+msgstr "Beschreibung:"
 
 #: gitk:800 gitk:1778 gitk:1783 gitk:2431
 msgid "touching paths:"
-msgstr "Pfad betreffend:"
+msgstr "Dateien:"
 
 #: gitk:801 gitk:2436
 msgid "adding/removing string:"
-msgstr "Zeichenkette ändernd:"
+msgstr "Änderungen:"
 
 #: gitk:810 gitk:812
 msgid "Exact"
@@ -253,23 +279,25 @@ msgstr "Diesen auch hervorheben"
 msgid "Highlight this only"
 msgstr "Nur diesen hervorheben"
 
-#: gitk:1318
+#: gitk:2162
+msgid "External diff"
+msgstr "Externer Vergleich"
+
+#: gitk:2403
 msgid ""
 "\n"
 "Gitk - a commit viewer for git\n"
 "\n"
-"Copyright © 2005-2006 Paul Mackerras\n"
+"Copyright © 2005-2008 Paul Mackerras\n"
 "\n"
 "Use and redistribute under the terms of the GNU General Public License"
 msgstr ""
 "\n"
 "Gitk - eine Visualisierung der Git Historie\n"
 "\n"
-"Copyright © 2005-2006 Paul Mackerras\n"
+"Copyright © 2005-2008 Paul Mackerras\n"
 "\n"
-"Benutzung und Weiterverbreitung gemäß den Bedingungen der GNU General Public "
-"License\n"
-"        "
+"Benutzung und Weiterverbreitung gemäß den Bedingungen der GNU General Public License"
 
 #: gitk:1326 gitk:1387 gitk:6582
 msgid "Close"
@@ -450,11 +478,11 @@ msgstr "Name"
 msgid "Remember this view"
 msgstr "Diese Ansicht speichern"
 
-#: gitk:1928
-msgid "Commits to include (arguments to git rev-list):"
-msgstr "Versionen anzeigen (Argumente von git-rev-list):"
+#: gitk:3126
+msgid "Commits to include (arguments to git log):"
+msgstr "Versionen anzeigen (Argumente von git-log):"
 
-#: gitk:1935
+#: gitk:3133
 msgid "Command to generate more commits to include:"
 msgstr "Versionsliste durch folgendes Kommando erzeugen lassen:"
 
@@ -566,7 +594,11 @@ msgstr "Kinder"
 msgid "Reset %s branch to here"
 msgstr "Zweig »%s« hierher zurücksetzen"
 
-#: gitk:6050
+#: gitk:7204
+msgid "Detached head: can't reset"
+msgstr "Zweigspitze ist abgetrennt: Zurücksetzen nicht möglich"
+
+#: gitk:7236
 msgid "Top"
 msgstr "Oben"
 
@@ -798,7 +830,15 @@ msgstr "Naheliegende Überschriften anzeigen"
 msgid "Limit diffs to listed paths"
 msgstr "Vergleich nur für angezeigte Pfade"
 
-#: gitk:8045
+#: gitk:9264
+msgid "External diff tool"
+msgstr "Externes Vergleich-(Diff-)Programm"
+
+#: gitk:9266
+msgid "Choose..."
+msgstr "Wählen..."
+
+#: gitk:9271
 msgid "Colors: press to choose"
 msgstr "Farben: Klicken zum Wählen"
 
@@ -873,22 +913,6 @@ msgstr "Mehrdeutige Angabe »%s«: Sowohl Version als auch Dateiname existiert."
 msgid "Bad arguments to gitk:"
 msgstr "Falsche Kommandozeilen-Parameter für gitk:"
 
-#: gitk:8637
-msgid "Couldn't get list of unmerged files:"
-msgstr "Liste der nicht-zusammengeführten Dateien nicht gefunden:"
-
-#: gitk:8653
-msgid "No files selected: --merge specified but no files are unmerged."
-msgstr "Keine Dateien ausgewählt: --merge angegeben, es existieren aber keine nicht-zusammengeführten Dateien."
-
-#: gitk:8656
-msgid ""
-"No files selected: --merge specified but no unmerged files are within file "
-"limit."
-msgstr ""
-"Keine Dateien ausgewähle: --merge angegeben, aber keine nicht-"
-"zusammengeführten Dateien sind in der Dateiauswahl."
-
-#: gitk:8717
+#: gitk:9915
 msgid "Command line"
 msgstr "Kommandozeile"
index f6b080df4cf313edaba241eb54c232e9f282a38c..e1ecfb75861b9135aecdfc4773bca5a8c41d9626 100644 (file)
 # This file is distributed under the same license as the gitk package.
 #
 # Peter Karlsson <peter@softwolves.pp.se>, 2008.
+# Mikael Magnusson <mikachu@gmail.com>, 2008.
 msgid ""
 msgstr ""
 "Project-Id-Version: sv\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2008-03-14 15:03+0100\n"
-"PO-Revision-Date: 2008-03-14 16:06CET-1\n"
-"Last-Translator: Peter Karlsson <peter@softwolves.pp.se>\n"
+"POT-Creation-Date: 2008-08-03 18:58+0200\n"
+"PO-Revision-Date: 2008-08-03 19:03+0200\n"
+"Last-Translator: Mikael Magnusson <mikachu@gmail.com>\n"
 "Language-Team: Swedish <sv@li.org>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit"
+"Content-Transfer-Encoding: 8bit\n"
 
-#: gitk:111
-msgid "Error executing git rev-list:"
-msgstr "Fel vid körning av git rev-list:"
+#: gitk:102
+msgid "Couldn't get list of unmerged files:"
+msgstr "Kunde inta hämta lista över ej sammanslagna filer:"
+
+#: gitk:329
+msgid "No files selected: --merge specified but no files are unmerged."
+msgstr ""
+"Inga filer valdes: --merge angavs men det finns inga filer som inte har "
+"slagits samman."
+
+#: gitk:332
+msgid ""
+"No files selected: --merge specified but no unmerged files are within file "
+"limit."
+msgstr ""
+"Inga filer valdes: --merge angavs men det finns inga filer inom "
+"filbegränsningen."
+
+#: gitk:354
+msgid "Error executing git log:"
+msgstr "Fel vid körning av git log:"
 
-#: gitk:124
+#: gitk:369
 msgid "Reading"
 msgstr "Läser"
 
-#: gitk:151 gitk:2191
+#: gitk:400 gitk:3356
 msgid "Reading commits..."
 msgstr "Läser incheckningar..."
 
-#: gitk:275
-msgid "Can't parse git log output:"
-msgstr "Kan inte tolka utdata från git log:"
-
-#: gitk:386 gitk:2195
+#: gitk:403 gitk:1480 gitk:3359
 msgid "No commits selected"
 msgstr "Inga incheckningar markerade"
 
-#: gitk:500
+#: gitk:1358
+msgid "Can't parse git log output:"
+msgstr "Kan inte tolka utdata från git log:"
+
+#: gitk:1557
 msgid "No commit information available"
 msgstr "Ingen incheckningsinformation är tillgänglig"
 
-#: gitk:599 gitk:621 gitk:1955 gitk:6423 gitk:7923 gitk:8082
+#: gitk:1654 gitk:1676 gitk:3150 gitk:7620 gitk:9149 gitk:9317
 msgid "OK"
 msgstr "OK"
 
-#: gitk:623 gitk:1956 gitk:6107 gitk:6178 gitk:6275 gitk:6321 gitk:6425
-#: gitk:7924 gitk:8083
+#: gitk:1678 gitk:3151 gitk:7296 gitk:7367 gitk:7470 gitk:7516 gitk:7622
+#: gitk:9150 gitk:9318
 msgid "Cancel"
 msgstr "Avbryt"
 
-#: gitk:661
+#: gitk:1716
 msgid "File"
 msgstr "Arkiv"
 
-#: gitk:663
+#: gitk:1718
 msgid "Update"
 msgstr "Uppdatera"
 
-#: gitk:664
+#: gitk:1719
+msgid "Reload"
+msgstr "Ladda om"
+
+#: gitk:1720
 msgid "Reread references"
 msgstr "Läs om referenser"
 
-#: gitk:665
+#: gitk:1721
 msgid "List references"
 msgstr "Visa referenser"
 
-#: gitk:666
+#: gitk:1722
 msgid "Quit"
 msgstr "Avsluta"
 
-#: gitk:668
+#: gitk:1724
 msgid "Edit"
 msgstr "Redigera"
 
-#: gitk:669
+#: gitk:1725
 msgid "Preferences"
 msgstr "Inställningar"
 
-#: gitk:672 gitk:1892
+#: gitk:1728 gitk:3087
 msgid "View"
 msgstr "Visa"
 
-#: gitk:673
+#: gitk:1729
 msgid "New view..."
 msgstr "Ny vy..."
 
-#: gitk:674 gitk:2133 gitk:8722
+#: gitk:1730 gitk:3298 gitk:9932
 msgid "Edit view..."
 msgstr "Ändra vy..."
 
-#: gitk:676 gitk:2134 gitk:8723
+#: gitk:1732 gitk:3299 gitk:9933
 msgid "Delete view"
 msgstr "Ta bort vy"
 
-#: gitk:678
+#: gitk:1734
 msgid "All files"
 msgstr "Alla filer"
 
-#: gitk:682
+#: gitk:1738
 msgid "Help"
 msgstr "Hjälp"
 
-#: gitk:683 gitk:1317
+#: gitk:1739 gitk:2399
 msgid "About gitk"
 msgstr "Om gitk"
 
-#: gitk:684
+#: gitk:1740
 msgid "Key bindings"
 msgstr "Tangentbordsbindningar"
 
-#: gitk:741
+#: gitk:1797
 msgid "SHA1 ID: "
 msgstr "SHA1-id: "
 
-#: gitk:791
+#: gitk:1828
+msgid "Row"
+msgstr "Rad"
+
+#: gitk:1859
 msgid "Find"
 msgstr "Sök"
 
-#: gitk:792
+#: gitk:1860
 msgid "next"
 msgstr "nästa"
 
-#: gitk:793
+#: gitk:1861
 msgid "prev"
 msgstr "föreg"
 
-#: gitk:794
+#: gitk:1862
 msgid "commit"
 msgstr "incheckning"
 
-#: gitk:797 gitk:799 gitk:2356 gitk:2379 gitk:2403 gitk:4306 gitk:4369
+#: gitk:1865 gitk:1867 gitk:3511 gitk:3534 gitk:3558 gitk:5441 gitk:5512
 msgid "containing:"
 msgstr "som innehåller:"
 
-#: gitk:800 gitk:1778 gitk:1783 gitk:2431
+#: gitk:1868 gitk:2866 gitk:2871 gitk:3586
 msgid "touching paths:"
 msgstr "som rör sökväg:"
 
-#: gitk:801 gitk:2436
+#: gitk:1869 gitk:3591
 msgid "adding/removing string:"
 msgstr "som lägger/till tar bort sträng:"
 
-#: gitk:810 gitk:812
+#: gitk:1878 gitk:1880
 msgid "Exact"
 msgstr "Exakt"
 
-#: gitk:812 gitk:2514 gitk:4274
+#: gitk:1880 gitk:3667 gitk:5409
 msgid "IgnCase"
 msgstr "IgnVersaler"
 
-#: gitk:812 gitk:2405 gitk:2512 gitk:4270
+#: gitk:1880 gitk:3560 gitk:3665 gitk:5405
 msgid "Regexp"
 msgstr "Reg.uttr."
 
-#: gitk:814 gitk:815 gitk:2533 gitk:2563 gitk:2570 gitk:4380 gitk:4436
+#: gitk:1882 gitk:1883 gitk:3686 gitk:3716 gitk:3723 gitk:5532 gitk:5599
 msgid "All fields"
 msgstr "Alla fält"
 
-#: gitk:815 gitk:2531 gitk:2563 gitk:4336
+#: gitk:1883 gitk:3684 gitk:3716 gitk:5471
 msgid "Headline"
 msgstr "Rubrik"
 
-#: gitk:816 gitk:2531 gitk:4336 gitk:4436 gitk:4827
+#: gitk:1884 gitk:3684 gitk:5471 gitk:5599 gitk:6000
 msgid "Comments"
 msgstr "Kommentarer"
 
-#: gitk:816 gitk:2531 gitk:2535 gitk:2570 gitk:4336 gitk:4763 gitk:5956
-#: gitk:5971
+#: gitk:1884 gitk:3684 gitk:3688 gitk:3723 gitk:5471 gitk:5936 gitk:7142
+#: gitk:7157
 msgid "Author"
 msgstr "Författare"
 
-#: gitk:816 gitk:2531 gitk:4336 gitk:4765
+#: gitk:1884 gitk:3684 gitk:5471 gitk:5938
 msgid "Committer"
 msgstr "Incheckare"
 
-#: gitk:845
+#: gitk:1913
 msgid "Search"
 msgstr "Sök"
 
-#: gitk:852
+#: gitk:1920
 msgid "Diff"
 msgstr "Diff"
 
-#: gitk:854
+#: gitk:1922
 msgid "Old version"
 msgstr "Gammal version"
 
-#: gitk:856
+#: gitk:1924
 msgid "New version"
 msgstr "Ny version"
 
-#: gitk:858
+#: gitk:1926
 msgid "Lines of context"
 msgstr "Rader sammanhang"
 
-#: gitk:868
+#: gitk:1936
 msgid "Ignore space change"
 msgstr "Ignorera ändringar i blanksteg"
 
-#: gitk:926
+#: gitk:1994
 msgid "Patch"
 msgstr "Patch"
 
-#: gitk:928
+#: gitk:1996
 msgid "Tree"
 msgstr "Träd"
 
-#: gitk:1053 gitk:1068 gitk:6022
+#: gitk:2121 gitk:2136 gitk:7211
 msgid "Diff this -> selected"
 msgstr "Diff denna -> markerad"
 
-#: gitk:1055 gitk:1070 gitk:6023
+#: gitk:2123 gitk:2138 gitk:7212
 msgid "Diff selected -> this"
 msgstr "Diff markerad -> denna"
 
-#: gitk:1057 gitk:1072 gitk:6024
+#: gitk:2125 gitk:2140 gitk:7213
 msgid "Make patch"
 msgstr "Skapa patch"
 
-#: gitk:1058 gitk:6162
+#: gitk:2126 gitk:7351
 msgid "Create tag"
 msgstr "Skapa tagg"
 
-#: gitk:1059 gitk:6255
+#: gitk:2127 gitk:7450
 msgid "Write commit to file"
 msgstr "Skriv incheckning till fil"
 
-#: gitk:1060 gitk:6309
+#: gitk:2128 gitk:7504
 msgid "Create new branch"
 msgstr "Skapa ny gren"
 
-#: gitk:1061
+#: gitk:2129
 msgid "Cherry-pick this commit"
 msgstr "Plocka denna incheckning"
 
-#: gitk:1063
+#: gitk:2131
 msgid "Reset HEAD branch to here"
 msgstr "Återställ HEAD-grenen hit"
 
-#: gitk:1079
+#: gitk:2147
 msgid "Check out this branch"
 msgstr "Checka ut denna gren"
 
-#: gitk:1081
+#: gitk:2149
 msgid "Remove this branch"
 msgstr "Ta bort denna gren"
 
-#: gitk:1087
+#: gitk:2155
 msgid "Highlight this too"
 msgstr "Markera även detta"
 
-#: gitk:1089
+#: gitk:2157
 msgid "Highlight this only"
 msgstr "Markera bara detta"
 
-#: gitk:1318
+#: gitk:2159
+msgid "External diff"
+msgstr "Extern diff"
+
+#: gitk:2400
 msgid ""
 "\n"
 "Gitk - a commit viewer for git\n"
 "\n"
-"Copyright © 2005-2006 Paul Mackerras\n"
+"Copyright © 2005-2008 Paul Mackerras\n"
 "\n"
 "Use and redistribute under the terms of the GNU General Public License"
 msgstr ""
 "\n"
 "Gitk - en incheckningsvisare för git\n"
 "\n"
-"Copyright © 2005-2006 Paul Mackerras\n"
+"Copyright © 2005-2008 Paul Mackerras\n"
 "\n"
 "Använd och vidareförmedla enligt villkoren i GNU General Public License"
 
-#: gitk:1326 gitk:1387 gitk:6581
+#: gitk:2408 gitk:2469 gitk:7799
 msgid "Close"
 msgstr "Stäng"
 
-#: gitk:1345
+#: gitk:2427
 msgid "Gitk key bindings"
 msgstr "Tangentbordsbindningar för Gitk"
 
-#: gitk:1347
+#: gitk:2429
 msgid "Gitk key bindings:"
 msgstr "Tangentbordsbindningar för Gitk:"
 
-#: gitk:1349
+#: gitk:2431
 #, tcl-format
 msgid "<%s-Q>\t\tQuit"
 msgstr "<%s-Q>\t\tAvsluta"
 
-#: gitk:1350
+#: gitk:2432
 msgid "<Home>\t\tMove to first commit"
 msgstr "<Home>\t\tGå till första incheckning"
 
-#: gitk:1351
+#: gitk:2433
 msgid "<End>\t\tMove to last commit"
 msgstr "<End>\t\tGå till sista incheckning"
 
-#: gitk:1352
+#: gitk:2434
 msgid "<Up>, p, i\tMove up one commit"
 msgstr "<Upp>, p, i\tGå en incheckning upp"
 
-#: gitk:1353
+#: gitk:2435
 msgid "<Down>, n, k\tMove down one commit"
 msgstr "<Ned>, n, k\tGå en incheckning ned"
 
-#: gitk:1354
+#: gitk:2436
 msgid "<Left>, z, j\tGo back in history list"
 msgstr "<Vänster>, z, j\tGå bakåt i historiken"
 
-#: gitk:1355
+#: gitk:2437
 msgid "<Right>, x, l\tGo forward in history list"
 msgstr "<Höger>, x, l\tGå framåt i historiken"
 
-#: gitk:1356
+#: gitk:2438
 msgid "<PageUp>\tMove up one page in commit list"
 msgstr "<PageUp>\tGå upp en sida i incheckningslistan"
 
-#: gitk:1357
+#: gitk:2439
 msgid "<PageDown>\tMove down one page in commit list"
 msgstr "<PageDown>\tGå ned en sida i incheckningslistan"
 
-#: gitk:1358
+#: gitk:2440
 #, tcl-format
 msgid "<%s-Home>\tScroll to top of commit list"
 msgstr "<%s-Home>\tRulla till början av incheckningslistan"
 
-#: gitk:1359
+#: gitk:2441
 #, tcl-format
 msgid "<%s-End>\tScroll to bottom of commit list"
 msgstr "<%s-End>\tRulla till slutet av incheckningslistan"
 
-#: gitk:1360
+#: gitk:2442
 #, tcl-format
 msgid "<%s-Up>\tScroll commit list up one line"
 msgstr "<%s-Upp>\tRulla incheckningslistan upp ett steg"
 
-#: gitk:1361
+#: gitk:2443
 #, tcl-format
 msgid "<%s-Down>\tScroll commit list down one line"
 msgstr "<%s-Ned>\tRulla incheckningslistan ned ett steg"
 
-#: gitk:1362
+#: gitk:2444
 #, tcl-format
 msgid "<%s-PageUp>\tScroll commit list up one page"
 msgstr "<%s-PageUp>\tRulla incheckningslistan upp en sida"
 
-#: gitk:1363
+#: gitk:2445
 #, tcl-format
 msgid "<%s-PageDown>\tScroll commit list down one page"
 msgstr "<%s-PageDown>\tRulla incheckningslistan ned en sida"
 
-#: gitk:1364
+#: gitk:2446
 msgid "<Shift-Up>\tFind backwards (upwards, later commits)"
 msgstr "<Skift-Upp>\tSök bakåt (uppåt, senare incheckningar)"
 
-#: gitk:1365
+#: gitk:2447
 msgid "<Shift-Down>\tFind forwards (downwards, earlier commits)"
 msgstr "<Skift-Ned>\tSök framåt (nedåt, tidigare incheckningar)"
 
-#: gitk:1366
+#: gitk:2448
 msgid "<Delete>, b\tScroll diff view up one page"
 msgstr "<Delete>, b\tRulla diffvisningen upp en sida"
 
-#: gitk:1367
+#: gitk:2449
 msgid "<Backspace>\tScroll diff view up one page"
 msgstr "<Baksteg>\tRulla diffvisningen upp en sida"
 
-#: gitk:1368
+#: gitk:2450
 msgid "<Space>\t\tScroll diff view down one page"
 msgstr "<Blanksteg>\tRulla diffvisningen ned en sida"
 
-#: gitk:1369
+#: gitk:2451
 msgid "u\t\tScroll diff view up 18 lines"
 msgstr "u\t\tRulla diffvisningen upp 18 rader"
 
-#: gitk:1370
+#: gitk:2452
 msgid "d\t\tScroll diff view down 18 lines"
 msgstr "d\t\tRulla diffvisningen ned 18 rader"
 
-#: gitk:1371
+#: gitk:2453
 #, tcl-format
 msgid "<%s-F>\t\tFind"
 msgstr "<%s-F>\t\tSök"
 
-#: gitk:1372
+#: gitk:2454
 #, tcl-format
 msgid "<%s-G>\t\tMove to next find hit"
 msgstr "<%s-G>\t\tGå till nästa sökträff"
 
-#: gitk:1373
+#: gitk:2455
 msgid "<Return>\tMove to next find hit"
 msgstr "<Return>\t\tGå till nästa sökträff"
 
-#: gitk:1374
+#: gitk:2456
 msgid "/\t\tMove to next find hit, or redo find"
 msgstr "/\t\tGå till nästa sökträff, eller sök på nytt"
 
-#: gitk:1375
+#: gitk:2457
 msgid "?\t\tMove to previous find hit"
 msgstr "?\t\tGå till föregående sökträff"
 
-#: gitk:1376
+#: gitk:2458
 msgid "f\t\tScroll diff view to next file"
 msgstr "f\t\tRulla diffvisningen till nästa fil"
 
-#: gitk:1377
+#: gitk:2459
 #, tcl-format
 msgid "<%s-S>\t\tSearch for next hit in diff view"
 msgstr "<%s-S>\t\tGå till nästa sökträff i diffvisningen"
 
-#: gitk:1378
+#: gitk:2460
 #, tcl-format
 msgid "<%s-R>\t\tSearch for previous hit in diff view"
 msgstr "<%s-R>\t\tGå till föregående sökträff i diffvisningen"
 
-#: gitk:1379
+#: gitk:2461
 #, tcl-format
 msgid "<%s-KP+>\tIncrease font size"
 msgstr "<%s-Num+>\tÖka teckenstorlek"
 
-#: gitk:1380
+#: gitk:2462
 #, tcl-format
 msgid "<%s-plus>\tIncrease font size"
 msgstr "<%s-plus>\tÖka teckenstorlek"
 
-#: gitk:1381
+#: gitk:2463
 #, tcl-format
 msgid "<%s-KP->\tDecrease font size"
 msgstr "<%s-Num->\tMinska teckenstorlek"
 
-#: gitk:1382
+#: gitk:2464
 #, tcl-format
 msgid "<%s-minus>\tDecrease font size"
 msgstr "<%s-minus>\tMinska teckenstorlek"
 
-#: gitk:1383
+#: gitk:2465
 msgid "<F5>\t\tUpdate"
 msgstr "<F5>\t\tUppdatera"
 
-#: gitk:1896
+#: gitk:3091
 msgid "Gitk view definition"
 msgstr "Definition av Gitk-vy"
 
-#: gitk:1921
+#: gitk:3116
 msgid "Name"
 msgstr "Namn"
 
-#: gitk:1924
+#: gitk:3119
 msgid "Remember this view"
 msgstr "Spara denna vy"
 
-#: gitk:1928
-msgid "Commits to include (arguments to git rev-list):"
-msgstr "Incheckningar att ta med (argument till git rev-list):"
+#: gitk:3123
+msgid "Commits to include (arguments to git log):"
+msgstr "Incheckningar att ta med (argument till git log):"
 
-#: gitk:1935
+#: gitk:3130
 msgid "Command to generate more commits to include:"
 msgstr "Kommando för att generera fler incheckningar att ta med:"
 
-#: gitk:1942
+#: gitk:3137
 msgid "Enter files and directories to include, one per line:"
 msgstr "Ange filer och kataloger att ta med, en per rad:"
 
-#: gitk:1989
+#: gitk:3184
 msgid "Error in commit selection arguments:"
 msgstr "Fel i argument för val av incheckningar:"
 
-#: gitk:2043 gitk:2127 gitk:2583 gitk:2597 gitk:3781 gitk:8688 gitk:8689
+#: gitk:3238 gitk:3290 gitk:3736 gitk:3750 gitk:4951 gitk:9896 gitk:9897
 msgid "None"
 msgstr "Inget"
 
-#: gitk:2531 gitk:4336 gitk:5958 gitk:5973
+#: gitk:3684 gitk:5471 gitk:7144 gitk:7159
 msgid "Date"
 msgstr "Datum"
 
-#: gitk:2531 gitk:4336
+#: gitk:3684 gitk:5471
 msgid "CDate"
 msgstr "Skapat datum"
 
-#: gitk:2680 gitk:2685
+#: gitk:3833 gitk:3838
 msgid "Descendant"
 msgstr "Avkomling"
 
-#: gitk:2681
+#: gitk:3834
 msgid "Not descendant"
 msgstr "Inte avkomling"
 
-#: gitk:2688 gitk:2693
+#: gitk:3841 gitk:3846
 msgid "Ancestor"
 msgstr "Förfader"
 
-#: gitk:2689
+#: gitk:3842
 msgid "Not ancestor"
 msgstr "Inte förfader"
 
-#: gitk:2924
+#: gitk:4078
 msgid "Local changes checked in to index but not committed"
 msgstr "Lokala ändringar sparade i indexet men inte incheckade"
 
-#: gitk:2954
+#: gitk:4111
 msgid "Local uncommitted changes, not checked in to index"
 msgstr "Lokala ändringar, ej sparade i indexet"
 
-#: gitk:4305
+#: gitk:5440
 msgid "Searching"
 msgstr "Söker"
 
-#: gitk:4767
+#: gitk:5940
 msgid "Tags:"
 msgstr "Taggar:"
 
-#: gitk:4784 gitk:4790 gitk:5951
+#: gitk:5957 gitk:5963 gitk:7137
 msgid "Parent"
 msgstr "Förälder"
 
-#: gitk:4795
+#: gitk:5968
 msgid "Child"
 msgstr "Barn"
 
-#: gitk:4804
+#: gitk:5977
 msgid "Branch"
 msgstr "Gren"
 
-#: gitk:4807
+#: gitk:5980
 msgid "Follows"
 msgstr "Följer"
 
-#: gitk:4810
+#: gitk:5983
 msgid "Precedes"
 msgstr "Föregår"
 
-#: gitk:5093
+#: gitk:6267
 msgid "Error getting merge diffs:"
 msgstr "Fel vid hämtning av sammanslagningsdiff:"
 
-#: gitk:5778
+#: gitk:6970
 msgid "Goto:"
 msgstr "Gå till:"
 
-#: gitk:5780
+#: gitk:6972
 msgid "SHA1 ID:"
 msgstr "SHA1-id:"
 
-#: gitk:5805
+#: gitk:6991
 #, tcl-format
 msgid "Short SHA1 id %s is ambiguous"
 msgstr "Förkortat SHA1-id %s är tvetydigt"
 
-#: gitk:5817
+#: gitk:7003
 #, tcl-format
 msgid "SHA1 id %s is not known"
 msgstr "SHA-id:t %s är inte känt"
 
-#: gitk:5819
+#: gitk:7005
 #, tcl-format
 msgid "Tag/Head %s is not known"
 msgstr "Tagg/huvud %s är okänt"
 
-#: gitk:5961
+#: gitk:7147
 msgid "Children"
 msgstr "Barn"
 
-#: gitk:6018
+#: gitk:7204
 #, tcl-format
 msgid "Reset %s branch to here"
 msgstr "Återställ grenen %s hit"
 
-#: gitk:6049
+#: gitk:7206
+msgid "Detached head: can't reset"
+msgstr "Frånkopplad head: kan inte återställa"
+
+#: gitk:7238
 msgid "Top"
 msgstr "Topp"
 
-#: gitk:6050
+#: gitk:7239
 msgid "From"
 msgstr "Från"
 
-#: gitk:6055
+#: gitk:7244
 msgid "To"
 msgstr "Till"
 
-#: gitk:6078
+#: gitk:7267
 msgid "Generate patch"
 msgstr "Generera patch"
 
-#: gitk:6080
+#: gitk:7269
 msgid "From:"
 msgstr "Från:"
 
-#: gitk:6089
+#: gitk:7278
 msgid "To:"
 msgstr "Till:"
 
-#: gitk:6098
+#: gitk:7287
 msgid "Reverse"
 msgstr "Vänd"
 
-#: gitk:6100 gitk:6269
+#: gitk:7289 gitk:7464
 msgid "Output file:"
 msgstr "Utdatafil:"
 
-#: gitk:6106
+#: gitk:7295
 msgid "Generate"
 msgstr "Generera"
 
-#: gitk:6142
+#: gitk:7331
 msgid "Error creating patch:"
 msgstr "Fel vid generering av patch:"
 
-#: gitk:6164 gitk:6257 gitk:6311
+#: gitk:7353 gitk:7452 gitk:7506
 msgid "ID:"
 msgstr "Id:"
 
-#: gitk:6173
+#: gitk:7362
 msgid "Tag name:"
 msgstr "Taggnamn:"
 
-#: gitk:6177 gitk:6320
+#: gitk:7366 gitk:7515
 msgid "Create"
 msgstr "Skapa"
 
-#: gitk:6192
+#: gitk:7381
 msgid "No tag name specified"
 msgstr "Inget taggnamn angavs"
 
-#: gitk:6196
+#: gitk:7385
 #, tcl-format
 msgid "Tag \"%s\" already exists"
 msgstr "Taggen \"%s\" finns redan"
 
-#: gitk:6202
+#: gitk:7391
 msgid "Error creating tag:"
 msgstr "Fel vid skapande av tagg:"
 
-#: gitk:6266
+#: gitk:7461
 msgid "Command:"
 msgstr "Kommando:"
 
-#: gitk:6274
+#: gitk:7469
 msgid "Write"
 msgstr "Skriv"
 
-#: gitk:6290
+#: gitk:7485
 msgid "Error writing commit:"
 msgstr "Fel vid skrivning av incheckning:"
 
-#: gitk:6316
+#: gitk:7511
 msgid "Name:"
 msgstr "Namn:"
 
-#: gitk:6335
+#: gitk:7530
 msgid "Please specify a name for the new branch"
 msgstr "Ange ett namn för den nya grenen"
 
-#: gitk:6364
+#: gitk:7559
 #, tcl-format
 msgid "Commit %s is already included in branch %s -- really re-apply it?"
-msgstr "Incheckningen %s finns redan på grenen %s -- skall den verkligen appliceras på nytt?"
+msgstr ""
+"Incheckningen %s finns redan på grenen %s -- skall den verkligen appliceras "
+"på nytt?"
 
-#: gitk:6369
+#: gitk:7564
 msgid "Cherry-picking"
 msgstr "Plockar"
 
-#: gitk:6381
+#: gitk:7576
 msgid "No changes committed"
 msgstr "Inga ändringar incheckade"
 
-#: gitk:6404
+#: gitk:7601
 msgid "Confirm reset"
 msgstr "Bekräfta återställning"
 
-#: gitk:6406
+#: gitk:7603
 #, tcl-format
 msgid "Reset branch %s to %s?"
 msgstr "Återställa grenen %s till %s?"
 
-#: gitk:6410
+#: gitk:7607
 msgid "Reset type:"
 msgstr "Typ av återställning:"
 
-#: gitk:6414
+#: gitk:7611
 msgid "Soft: Leave working tree and index untouched"
 msgstr "Mjuk: Rör inte utcheckning och index"
 
-#: gitk:6417
+#: gitk:7614
 msgid "Mixed: Leave working tree untouched, reset index"
 msgstr "Blandad: Rör inte utcheckning, återställ index"
 
-#: gitk:6420
+#: gitk:7617
 msgid ""
 "Hard: Reset working tree and index\n"
 "(discard ALL local changes)"
@@ -691,19 +728,19 @@ msgstr ""
 "Hård: Återställ utcheckning och index\n"
 "(förkastar ALLA lokala ändringar)"
 
-#: gitk:6436
+#: gitk:7633
 msgid "Resetting"
 msgstr "Återställer"
 
-#: gitk:6493
+#: gitk:7690
 msgid "Checking out"
 msgstr "Checkar ut"
 
-#: gitk:6523
+#: gitk:7741
 msgid "Cannot delete the currently checked-out branch"
 msgstr "Kan inte ta bort den just nu utcheckade grenen"
 
-#: gitk:6529
+#: gitk:7747
 #, tcl-format
 msgid ""
 "The commits on branch %s aren't on any other branch.\n"
@@ -712,16 +749,16 @@ msgstr ""
 "Incheckningarna på grenen %s existerar inte på någon annan gren.\n"
 "Vill du verkligen ta bort grenen %s?"
 
-#: gitk:6560
+#: gitk:7778
 #, tcl-format
 msgid "Tags and heads: %s"
 msgstr "Taggar och huvuden: %s"
 
-#: gitk:6574
+#: gitk:7792
 msgid "Filter"
 msgstr "Filter"
 
-#: gitk:6868
+#: gitk:8086
 msgid ""
 "Error reading commit topology information; branch and preceding/following "
 "tag information will be incomplete."
@@ -729,117 +766,125 @@ msgstr ""
 "Fel vid läsning av information om incheckningstopologi; information om "
 "grenar och föregående/senare taggar kommer inte vara komplett."
 
-#: gitk:7852
+#: gitk:9072
 msgid "Tag"
 msgstr "Tagg"
 
-#: gitk:7852
+#: gitk:9072
 msgid "Id"
 msgstr "Id"
 
-#: gitk:7892
+#: gitk:9118
 msgid "Gitk font chooser"
 msgstr "Teckensnittsväljare för Gitk"
 
-#: gitk:7909
+#: gitk:9135
 msgid "B"
 msgstr "F"
 
-#: gitk:7912
+#: gitk:9138
 msgid "I"
 msgstr "K"
 
-#: gitk:8005
+#: gitk:9231
 msgid "Gitk preferences"
 msgstr "Inställningar för Gitk"
 
-#: gitk:8006
+#: gitk:9232
 msgid "Commit list display options"
 msgstr "Alternativ för incheckningslistvy"
 
-#: gitk:8009
+#: gitk:9235
 msgid "Maximum graph width (lines)"
 msgstr "Maximal grafbredd (rader)"
 
-#: gitk:8013
+#: gitk:9239
 #, tcl-format
 msgid "Maximum graph width (% of pane)"
 msgstr "Maximal grafbredd (% av ruta)"
 
-#: gitk:8018
+#: gitk:9244
 msgid "Show local changes"
 msgstr "Visa lokala ändringar"
 
-#: gitk:8023
+#: gitk:9249
 msgid "Auto-select SHA1"
 msgstr "Välj SHA1 automatiskt"
 
-#: gitk:8028
+#: gitk:9254
 msgid "Diff display options"
 msgstr "Alternativ för diffvy"
 
-#: gitk:8030
+#: gitk:9256
 msgid "Tab spacing"
 msgstr "Blanksteg för tabulatortecken"
 
-#: gitk:8034
+#: gitk:9260
 msgid "Display nearby tags"
 msgstr "Visa närliggande taggar"
 
-#: gitk:8039
+#: gitk:9265
 msgid "Limit diffs to listed paths"
 msgstr "Begränsa diff till listade sökvägar"
 
-#: gitk:8044
+#: gitk:9272
+msgid "External diff tool"
+msgstr "Externt diff-verktyg"
+
+#: gitk:9274
+msgid "Choose..."
+msgstr "Välj..."
+
+#: gitk:9279
 msgid "Colors: press to choose"
 msgstr "Färger: tryck för att välja"
 
-#: gitk:8047
+#: gitk:9282
 msgid "Background"
 msgstr "Bakgrund"
 
-#: gitk:8051
+#: gitk:9286
 msgid "Foreground"
 msgstr "Förgrund"
 
-#: gitk:8055
+#: gitk:9290
 msgid "Diff: old lines"
 msgstr "Diff: gamla rader"
 
-#: gitk:8060
+#: gitk:9295
 msgid "Diff: new lines"
 msgstr "Diff: nya rader"
 
-#: gitk:8065
+#: gitk:9300
 msgid "Diff: hunk header"
 msgstr "Diff: delhuvud"
 
-#: gitk:8071
+#: gitk:9306
 msgid "Select bg"
 msgstr "Markerad bakgrund"
 
-#: gitk:8075
+#: gitk:9310
 msgid "Fonts: press to choose"
 msgstr "Teckensnitt: tryck för att välja"
 
-#: gitk:8077
+#: gitk:9312
 msgid "Main font"
 msgstr "Huvudteckensnitt"
 
-#: gitk:8078
+#: gitk:9313
 msgid "Diff display font"
 msgstr "Teckensnitt för diffvisning"
 
-#: gitk:8079
+#: gitk:9314
 msgid "User interface font"
 msgstr "Teckensnitt för användargränssnitt"
 
-#: gitk:8095
+#: gitk:9339
 #, tcl-format
 msgid "Gitk: choose color for %s"
 msgstr "Gitk: välj färg för %s"
 
-#: gitk:8476
+#: gitk:9720
 msgid ""
 "Sorry, gitk cannot run with this version of Tcl/Tk.\n"
 " Gitk requires at least Tcl/Tk 8.4."
@@ -847,41 +892,24 @@ msgstr ""
 "Gitk kan tyvärr inte köra med denna version av Tcl/Tk.\n"
 " Gitk kräver åtminstone Tcl/Tk 8.4."
 
-#: gitk:8565
+#: gitk:9812
 msgid "Cannot find a git repository here."
 msgstr "Hittar inget gitk-arkiv här."
 
-#: gitk:8569
+#: gitk:9816
 #, tcl-format
 msgid "Cannot find the git directory \"%s\"."
 msgstr "Hittar inte git-katalogen \"%s\"."
 
-#: gitk:8612
+#: gitk:9853
 #, tcl-format
 msgid "Ambiguous argument '%s': both revision and filename"
 msgstr "Tvetydigt argument \"%s\": både revision och filnamn"
 
-#: gitk:8624
+#: gitk:9865
 msgid "Bad arguments to gitk:"
 msgstr "Felaktiga argument till gitk:"
 
-#: gitk:8636
-msgid "Couldn't get list of unmerged files:"
-msgstr "Kunde inta hämta lista över ej sammanslagna filer:"
-
-#: gitk:8652
-msgid "No files selected: --merge specified but no files are unmerged."
-msgstr "Inga filer valdes: --merge angavs men det finns inga filer som inte har slagits samman."
-
-#: gitk:8655
-msgid ""
-"No files selected: --merge specified but no unmerged files are within file "
-"limit."
-msgstr ""
-"Inga filer valdes: --merge angavs men det finns inga filer inom "
-"filbegränsningen."
-
-#: gitk:8716
+#: gitk:9925
 msgid "Command line"
 msgstr "Kommandorad"
-
index aa0eeca24786dbd5143354fc3bb5e8cdb3ef831f..07f5b5378805a520e22b0f1b598aed7af4235538 100644 (file)
@@ -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;
index 90cd99bf916135e5c0a9e1bd7d5e9ff45555c489..29e21564c8e7b2dd711af2e96e03b811b2c1a268 100755 (executable)
@@ -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 {
diff --git a/grep.c b/grep.c
index f67d6716ea5f42c3384a7a4cb2eb973b02785fba..706351197fc26efa10c4666d38433f8fbdf1d6b5 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -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;
 }
 
diff --git a/grep.h b/grep.h
index d252dd25f81526d9b8663b4d3c9585d69a901397..59b3f871ea63619f8d3caae74c41b4da1e9a2b9f 100644 (file)
--- a/grep.h
+++ b/grep.h
@@ -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);
index 46c06a9552dac5475afc607c3fe2bf00801eb055..a4d127cf78013ca43339c5493b7f7ef90b2145a8 100644 (file)
@@ -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;
 }
diff --git a/help.c b/help.c
index 3cb19628965685ce59a5377b81bef975851996e8..300cd38a9fc2afa61d4390a8fee590997bb6e590 100644 (file)
--- a/help.c
+++ b/help.c
@@ -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 (file)
index 0000000..56bc154
--- /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 */
index 68052888570af7d09535db8831b8cf3ef2881589..c9dd9a1f6475cc8772b1e0f528a9f54751d6445a 100644 (file)
@@ -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;
diff --git a/http.c b/http.c
index 1108ab4a3101fb4768cad420ccfdb52d87890a18..ed59b79709b11dc6f6d85e86d75a1a8883799f21 100644 (file)
--- a/http.c
+++ b/http.c
@@ -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;
index 1ec131092109aa3fbed3cd20f10b56a864584a94..af7e08c0943ada9a650f80fd5b5fc1df23c04b88 100644 (file)
  */
 
 #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;
 }
index 52064befdbbbdf671bd08e369a133d4f1fee03c1..a6e91fe3ba47e3b0837648180bb7d47acd3e7dc7 100644 (file)
@@ -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 (file)
index 0000000..db52f2c
--- /dev/null
@@ -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 (file)
index 0000000..0173abe
--- /dev/null
@@ -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
index bd8b9e45ab46b8664c8b7016b33bee22f86c9e0d..30cd5bb22800f5e897c1170e97721a4dcdb9c9d2 100644 (file)
@@ -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? */
index 7491c56ad25332fb4aae6a075bf0577a1d800c3b..7827e87a928586226570132fc8922991b1cb6c8a 100644 (file)
@@ -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);
        }
index 036bd66fe9b6591e959e6df51160e636ab1a682e..d962ff11d1b2f810e21b049c7dbfed104cc199cb 100644 (file)
--- a/object.h
+++ b/object.h
@@ -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);
index cd300bdff5b524a4d509ba5276e9ef21f443013d..6096b6224ad551086afa346617eb714c15a51f78 100644 (file)
@@ -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;
+       }
+}
index 36a514a6cf600e7e77794e50998a9d160e30c8e9..8d5027ad917224f689e786e9a0b4e9a387e59dfe 100644 (file)
@@ -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
index a8f02699366c87de960d7637e9f69c26c2241693..939ed56362d3c29bfc64e8cca91032df9a57961e 100644 (file)
@@ -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)
diff --git a/pack.h b/pack.h
index 76e6aa2aad06545e7c44fc2c1e117ea668356ccf..a883334b269c76d8de1395adf2b8f3d0d7e8564f 100644 (file)
--- a/pack.h
+++ b/pack.h
@@ -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)
diff --git a/pager.c b/pager.c
index 6b5c9e44b4ded338ddb344ae454d83a685b7569a..aa0966c9c55566382bf32c946c0a1846f004125a 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -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)
index 71a7acf4e22bd12c0919f277410d6ec52dd5efc8..fd08bb425c241a0861588ec0aedd15041095a95f 100644 (file)
@@ -483,3 +483,15 @@ int parse_opt_approxidate_cb(const struct option *opt, const char *arg,
        *(unsigned long *)(opt->value) = approxidate(arg);
        return 0;
 }
+
+/*
+ * This should really be OPTION_FILENAME type as a part of
+ * parse_options that take prefix to do this while parsing.
+ */
+extern const char *parse_options_fix_filename(const char *prefix, const char *file)
+{
+       if (!file || !prefix || is_absolute_path(file) || !strcmp("-", file))
+               return file;
+       return prefix_filename(prefix, strlen(prefix), file);
+}
+
index bc317e7512af7a1cc86641a651ae5415d28e71c4..5199950c006df4625355ce227970cc3e8a72ed41 100644 (file)
@@ -159,4 +159,6 @@ extern int parse_opt_approxidate_cb(const struct option *, const char *, int);
          "use <n> digits to display SHA-1s", \
          PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
 
+extern const char *parse_options_fix_filename(const char *prefix, const char *file);
+
 #endif
diff --git a/path.c b/path.c
index 9df447bd6dcfaddf7f05fe5f0b624700ff1f40d7..76e8872622e435b050f77198ef6eef6e6ff6869e 100644 (file)
--- a/path.c
+++ b/path.c
@@ -365,7 +365,7 @@ int normalize_absolute_path(char *buf, const char *path)
  * path = Canonical absolute path
  * prefix_list = Colon-separated list of absolute paths
  *
- * Determines, for each path in parent_list, whether the "prefix" really
+ * Determines, for each path in prefix_list, whether the "prefix" really
  * is an ancestor directory of path.  Returns the length of the longest
  * ancestor directory, excluding any trailing slashes, or -1 if no prefix
  * is an ancestor.  (Note that this means 0 is returned if prefix_list is
index 087d3d0e829ce0e9b39c581bc9f088f0d72e36f3..6aab712e6ac6513b0b46958d93d536ef975276b4 100644 (file)
@@ -57,7 +57,8 @@ =head1 SYNOPSIS
                 command_output_pipe command_input_pipe command_close_pipe
                 command_bidi_pipe command_close_bidi_pipe
                 version exec_path hash_object git_cmd_try
-                remote_refs);
+                remote_refs
+                temp_acquire temp_release temp_reset temp_path);
 
 
 =head1 DESCRIPTION
@@ -90,7 +91,7 @@ =head1 DESCRIPTION
 Currently, the module merely wraps calls to external Git tools. In the future,
 it will provide a much faster way to interact with Git by linking directly
 to libgit. This should be completely opaque to the user, though (performance
-increate nonwithstanding).
+increase notwithstanding).
 
 =cut
 
@@ -99,7 +100,7 @@ =head1 DESCRIPTION
 use Error qw(:try);
 use Cwd qw(abs_path);
 use IPC::Open2 qw(open2);
-
+use Fcntl qw(SEEK_SET SEEK_CUR);
 }
 
 
@@ -417,6 +418,7 @@ sub command_bidi_pipe {
 =cut
 
 sub command_close_bidi_pipe {
+       local $?;
        my ($pid, $in, $out, $ctx) = @_;
        foreach my $fh ($in, $out) {
                unless (close $fh) {
@@ -839,8 +841,8 @@ sub _close_hash_and_insert_object {
 
        my @vars = map { 'hash_object_' . $_ } qw(pid in out ctx);
 
-       command_close_bidi_pipe($self->{@vars});
-       delete $self->{@vars};
+       command_close_bidi_pipe(@$self{@vars});
+       delete @$self{@vars};
 }
 
 =item cat_blob ( SHA1, FILEHANDLE )
@@ -928,10 +930,153 @@ sub _close_cat_blob {
 
        my @vars = map { 'cat_blob_' . $_ } qw(pid in out ctx);
 
-       command_close_bidi_pipe($self->{@vars});
-       delete $self->{@vars};
+       command_close_bidi_pipe(@$self{@vars});
+       delete @$self{@vars};
+}
+
+
+{ # %TEMP_* Lexical Context
+
+my (%TEMP_FILEMAP, %TEMP_FILES);
+
+=item temp_acquire ( NAME )
+
+Attempts to retreive the temporary file mapped to the string C<NAME>. If an
+associated temp file has not been created this session or was closed, it is
+created, cached, and set for autoflush and binmode.
+
+Internally locks the file mapped to C<NAME>. This lock must be released with
+C<temp_release()> when the temp file is no longer needed. Subsequent attempts
+to retrieve temporary files mapped to the same C<NAME> while still locked will
+cause an error. This locking mechanism provides a weak guarantee and is not
+threadsafe. It does provide some error checking to help prevent temp file refs
+writing over one another.
+
+In general, the L<File::Handle> returned should not be closed by consumers as
+it defeats the purpose of this caching mechanism. If you need to close the temp
+file handle, then you should use L<File::Temp> or another temp file faculty
+directly. If a handle is closed and then requested again, then a warning will
+issue.
+
+=cut
+
+sub temp_acquire {
+       my ($self, $name) = _maybe_self(@_);
+
+       my $temp_fd = _temp_cache($name);
+
+       $TEMP_FILES{$temp_fd}{locked} = 1;
+       $temp_fd;
+}
+
+=item temp_release ( NAME )
+
+=item temp_release ( FILEHANDLE )
+
+Releases a lock acquired through C<temp_acquire()>. Can be called either with
+the C<NAME> mapping used when acquiring the temp file or with the C<FILEHANDLE>
+referencing a locked temp file.
+
+Warns if an attempt is made to release a file that is not locked.
+
+The temp file will be truncated before being released. This can help to reduce
+disk I/O where the system is smart enough to detect the truncation while data
+is in the output buffers. Beware that after the temp file is released and
+truncated, any operations on that file may fail miserably until it is
+re-acquired. All contents are lost between each release and acquire mapped to
+the same string.
+
+=cut
+
+sub temp_release {
+       my ($self, $temp_fd, $trunc) = _maybe_self(@_);
+
+       if (exists $TEMP_FILEMAP{$temp_fd}) {
+               $temp_fd = $TEMP_FILES{$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_FILES{$temp_fd}{locked} = 0;
+       undef;
+}
+
+sub _temp_cache {
+       my ($name) = @_;
+
+       _verify_require();
+
+       my $temp_fd = \$TEMP_FILEMAP{$name};
+       if (defined $$temp_fd and $$temp_fd->opened) {
+               if ($TEMP_FILES{$$temp_fd}{locked}) {
+                       throw Error::Simple("Temp file with moniker '",
+                               $name, "' already in use");
+               }
+       } else {
+               if (defined $$temp_fd) {
+                       # then we're here because of a closed handle.
+                       carp "Temp file '", $name,
+                               "' was closed. Opening replacement.";
+               }
+               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;
+}
+
+sub _verify_require {
+       eval { require File::Temp; require File::Spec; };
+       $@ and throw Error::Simple($@);
+}
+
+=item temp_reset ( FILEHANDLE )
+
+Truncates and resets the position of the C<FILEHANDLE>.
+
+=cut
+
+sub temp_reset {
+       my ($self, $temp_fd) = _maybe_self(@_);
+
+       truncate $temp_fd, 0
+               or throw Error::Simple("couldn't truncate file");
+       sysseek($temp_fd, 0, SEEK_SET) and seek($temp_fd, 0, SEEK_SET)
+               or throw Error::Simple("couldn't seek to beginning of file");
+       sysseek($temp_fd, 0, SEEK_CUR) == 0 and tell($temp_fd) == 0
+               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_FILEMAP if %TEMP_FILEMAP;
+}
+
+} # %TEMP_* Lexical Context
+
 =back
 
 =head1 ERROR HANDLING
index b8547db2c64ac1242725b5f71fb646b5bca38ef3..e3dd1a5547c471208c445d77263ee46e64b37451 100644 (file)
@@ -29,11 +29,11 @@ $(makfile): ../GIT-CFLAGS Makefile
        '$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \
        echo '  cp private-Error.pm blib/lib/Error.pm' >> $@
        echo install: >> $@
-       echo '  mkdir -p $(instdir_SQ)' >> $@
-       echo '  $(RM) $(instdir_SQ)/Git.pm; cp Git.pm $(instdir_SQ)' >> $@
-       echo '  $(RM) $(instdir_SQ)/Error.pm' >> $@
+       echo '  mkdir -p "$(instdir_SQ)"' >> $@
+       echo '  $(RM) "$(instdir_SQ)/Git.pm"; cp Git.pm "$(instdir_SQ)"' >> $@
+       echo '  $(RM) "$(instdir_SQ)/Error.pm"' >> $@
        '$(PERL_PATH_SQ)' -MError -e 'exit($$Error::VERSION < 0.15009)' || \
-       echo '  cp private-Error.pm $(instdir_SQ)/Error.pm' >> $@
+       echo '  cp private-Error.pm "$(instdir_SQ)/Error.pm"' >> $@
        echo instlibdir: >> $@
        echo '  echo $(instdir_SQ)' >> $@
 else
index 33ef34a4119812674726254fee3f391fb5734fdb..a29c290009587a12cdc6aec335d508d29481e697 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -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;
        }
 
index 2c03ec3069decb20f7557af4ac7dbe295f2dcf9c..5b1b3ad03b6d7294ca06b5b1053799958ad831c7 100644 (file)
@@ -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;
@@ -1243,10 +1253,12 @@ int discard_index(struct index_state *istate)
        istate->cache_nr = 0;
        istate->cache_changed = 0;
        istate->timestamp = 0;
+       istate->name_hash_initialized = 0;
        free_hash(&istate->name_hash);
        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;
@@ -1477,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;
+}
+
index d44c19e6b577023dcbaa188a0e67130ff4e5bd9a..b81678a9705c3f4bb7a6ff47e2af87db70e0ef66 100644 (file)
@@ -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");
 
diff --git a/refs.c b/refs.c
index 39a3b23804d2da715c564459bf320be23d41c1bf..b6807505e243fd26cae50460bc003254406ae7e5 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -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) {
index f61a3ab399aa6960fb8eba050321cea4a3b05344..3f3c789653a23e829369429da093c1193b53b015 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -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,8 +604,7 @@ int valid_fetch_refspec(const char *fetch_refspec_str)
        struct refspec *refspec;
 
        refspec = parse_refspec_internal(1, fetch_refspec, 1, 1);
-       if (refspec)
-               free(refspec);
+       free_refspecs(refspec, 1);
        return !!refspec;
 }
 
index 091b1d041f8a4d255f59bfc001e098e692dbc15c..2601f6e76d52c6a201e3952fb8b2c988eed33700 100644 (file)
--- a/remote.h
+++ b/remote.h
@@ -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);
index d797f05c93abebddee4ca599f72841231b1426aa..2f646deab09c423143185b7f7928ae46ab9f4c97 100644 (file)
@@ -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)
@@ -1163,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"))
@@ -1354,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");
@@ -1408,16 +1385,34 @@ static int remove_duplicate_parents(struct commit *commit)
        return surviving_parents;
 }
 
-static struct commit_list **simplify_one(struct commit *commit, struct commit_list **tail)
+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);
+
        /*
-        * We store which commit each one simplifies to in its util field.
         * Have we handled this one?
         */
-       if (commit->util)
+       if (st->simplified)
                return tail;
 
        /*
@@ -1426,7 +1421,7 @@ static struct commit_list **simplify_one(struct commit *commit, struct commit_li
         * anyway.
         */
        if ((commit->object.flags & UNINTERESTING) || !commit->parents) {
-               commit->util = commit;
+               st->simplified = commit;
                return tail;
        }
 
@@ -1435,19 +1430,24 @@ static struct commit_list **simplify_one(struct commit *commit, struct commit_li
         * Otherwise we are not ready to rewrite this one yet.
         */
        for (cnt = 0, p = commit->parents; p; p = p->next) {
-               if (!p->item->util) {
+               pst = locate_simplify_state(revs, p->item);
+               if (!pst->simplified) {
                        tail = &commit_list_insert(p->item, tail)->next;
                        cnt++;
                }
        }
-       if (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)
-               p->item = p->item->util;
+       for (p = commit->parents; p; p = p->next) {
+               pst = locate_simplify_state(revs, p->item);
+               p->item = pst->simplified;
+       }
        cnt = remove_duplicate_parents(commit);
 
        /*
@@ -1482,9 +1482,11 @@ static struct commit_list **simplify_one(struct commit *commit, struct commit_li
            (commit->object.flags & UNINTERESTING) ||
            !(commit->object.flags & TREESAME) ||
            (1 < cnt))
-               commit->util = commit;
-       else
-               commit->util = commit->parents->item->util;
+               st->simplified = commit;
+       else {
+               pst = locate_simplify_state(revs, commit->parents->item);
+               st->simplified = pst->simplified;
+       }
        return tail;
 }
 
@@ -1493,7 +1495,10 @@ static void simplify_merges(struct rev_info *revs)
        struct commit_list *list;
        struct commit_list *yet_to_do, **tail;
 
-       sort_in_topological_order(&revs->commits, revs->lifo);
+       if (!revs->topo_order)
+               sort_in_topological_order(&revs->commits, revs->lifo);
+       if (!revs->prune)
+               return;
 
        /* feed the list reversed */
        yet_to_do = NULL;
@@ -1508,7 +1513,7 @@ static void simplify_merges(struct rev_info *revs)
                        struct commit_list *next = list->next;
                        free(list);
                        list = next;
-                       tail = simplify_one(commit, tail);
+                       tail = simplify_one(revs, commit, tail);
                }
        }
 
@@ -1519,9 +1524,11 @@ static void simplify_merges(struct rev_info *revs)
        while (list) {
                struct commit *commit = list->item;
                struct commit_list *next = list->next;
+               struct merge_simplify_state *st;
                free(list);
                list = next;
-               if (commit->util == commit)
+               st = locate_simplify_state(revs, commit);
+               if (st->simplified == commit)
                        tail = &commit_list_insert(commit, tail)->next;
        }
 }
@@ -1622,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));
 }
index b818cea76bd31004888ff4c7eecaa798533c508f..2fdb2dd0ff3425b68b47aa8fd11155aa881d4a4a 100644 (file)
@@ -2,6 +2,7 @@
 #define REVISION_H
 
 #include "parse-options.h"
+#include "grep.h"
 
 #define SEEN           (1u<<0)
 #define UNINTERESTING   (1u<<1)
@@ -94,7 +95,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;
@@ -111,6 +112,7 @@ struct rev_info {
 
        struct reflog_walk_info *reflog_info;
        struct decoration children;
+       struct decoration merge_simplification;
 };
 
 #define REV_TREE_SAME          0
@@ -121,7 +123,7 @@ struct rev_info {
 void read_revisions_from_stdin(struct rev_info *revs);
 
 typedef void (*show_early_output_fn_t)(struct rev_info *, struct commit_list *);
-volatile show_early_output_fn_t show_early_output;
+extern volatile show_early_output_fn_t show_early_output;
 
 extern void init_revisions(struct rev_info *revs, const char *prefix);
 extern int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def);
index a3b28a64dc2d1b888b0ba2a135be10fe04651201..caab374577e02e9a33cd8095b8da9234acb065f8 100644 (file)
@@ -68,6 +68,7 @@ int start_command(struct child_process *cmd)
        trace_argv_printf(cmd->argv, "trace: run_command:");
 
 #ifndef __MINGW32__
+       fflush(NULL);
        cmd->pid = fork();
        if (!cmd->pid) {
                if (cmd->no_stdin)
@@ -110,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 {
@@ -304,6 +307,9 @@ int start_async(struct async *async)
        async->out = pipe_out[0];
 
 #ifndef __MINGW32__
+       /* Flush stdio before fork() to avoid cloning buffers */
+       fflush(NULL);
+
        async->pid = fork();
        if (async->pid < 0) {
                error("fork (async) failed: %s", strerror(errno));
index 5203a9ebb10b14bd06862abafed0ab73d7514a3d..4f2b7d7d403ee6d87fea5ba2dc32da7596965e5e 100644 (file)
@@ -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 *);
diff --git a/setup.c b/setup.c
index 6cf909463d4ad3681a2f35269db9dc944f4389c2..2e3248a0c4958f31001213470a88d1154b5947fc 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -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;
        }
 
index e281c14f01d37ab7623998c2990914aca49a7a3b..9ee1ed16ad2df8847bd5008a5d61c807c145357a 100644 (file)
@@ -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();
 }
@@ -1929,11 +1930,18 @@ static int sha1_loose_object_info(const unsigned char *sha1, unsigned long *size
 int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
 {
        struct pack_entry e;
+       int status;
 
        if (!find_pack_entry(sha1, &e, NULL)) {
+               /* Most likely it's a loose object. */
+               status = sha1_loose_object_info(sha1, sizep);
+               if (status >= 0)
+                       return status;
+
+               /* Not a loose object; someone else may have just packed it. */
                reprepare_packed_git();
                if (!find_pack_entry(sha1, &e, NULL))
-                       return sha1_loose_object_info(sha1, sizep);
+                       return status;
        }
        return packed_object_info(e.p, e.offset, sizep);
 }
@@ -2353,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)
-{
-       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)
+static int index_mem(unsigned char *sha1, void *buf, size_t size,
+                    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;
                }
@@ -2407,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;
 }
 
index 4fb77f8863ec075de38b84171d3ef039a00cee4c..41b680915d7348bf622397da8b1465d3769a361a 100644 (file)
@@ -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);
diff --git a/shell.c b/shell.c
index 6a48de05ff80f86050715ef3dab87a48b0a86ac9..e3393690dd3b79af80e6b95710583e744fd574d4 100644 (file)
--- a/shell.c
+++ b/shell.c
@@ -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
index b6777812cb92c1c169ee395164d53a0c2e6eceb2..cca3360546dabf9f018b882f690bd1dea9de534d 100644 (file)
@@ -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);
index b27e280083867ac03c4abc188f0f37291eb123a0..7dcbb232cd876cb7b976443cc586f60a94ab92bf 100644 (file)
@@ -1,2 +1,2 @@
-/trash directory
+/trash directory*
 /test-results
index 0d65cedaa6566a6dd654753cb574c9ee64b1c90b..ed49c20b16b520da1b460960dbadd5d31c4927ba 100644 (file)
@@ -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:
index a841df2a9e3a9ed64e81ab7b9778e59cfc714cad..c526eedd622558275b48fee35fb8382b2c815b9b 100644 (file)
@@ -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"
index dc473dfb53d5ffafee72738a55caf21732fa4fb1..6ac312b9059394b44cd6e106f9da6394674ee54a 100644 (file)
@@ -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
 
index 7d1ce2d0563b3734d754c171d21580075264bbb2..f1e1d48869a25c6ab1d0b570eb4c0e28afc5fa05 100755 (executable)
@@ -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/\$/\r/" ../t0022-crlf-rename.sh >elpmas &&
+       sed -e "s/\$/\r/" "$TEST_DIRECTORY"/t0022-crlf-rename.sh >elpmas &&
        git add elpmas &&
        rm -f sample &&
 
index 6f8a4347d5397b8b396db800c12c6e045a0d2b7c..aaed7254023b86a30c499db7c4b069c9d08b1085 100755 (executable)
@@ -36,7 +36,7 @@ test_expect_success 'setup' '
 
 test_expect_success 'am' '
 
-       git am --binary -3 <patchfile &&
+       git am -3 <patchfile &&
        git diff-files --name-status --exit-code
 
 '
index b177174ef53e7689cc8c18b134afdbe90be72744..7edf49db3c37982a6d599a39b98ce60ceeb0039b 100755 (executable)
@@ -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 (executable)
index 0000000..b29c37a
--- /dev/null
@@ -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
index 807fb83af8c65304f1dae2ee35ba0f2909ddf465..22ba7a5442c587f4536aad5668df43661231de56 100755 (executable)
@@ -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
index aa9dd580a658ffd980ec9689b01f7964580661f2..5e40cec530df07a8b7c088d31b28ac2d39abdc1b 100755 (executable)
@@ -14,6 +14,8 @@ _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"
 compare_change () {
        sed >current \
+           -e '1{/^diff --git /d;}' \
+           -e '2{/^index /d;}' \
            -e '/^--- /d; /^+++ /d; /^@@ /d;' \
            -e 's/^\(.[0-7][0-7][0-7][0-7][0-7][0-7]\) '"$_x40"' /\1 X /' "$1"
        test_cmp expected current
@@ -75,7 +77,7 @@ test_expect_success \
      git update-index --add yomin &&
      git read-tree -m -u $treeH $treeM &&
      git ls-files --stage >4.out || return 1
-     diff -U0 M.out 4.out >4diff.out
+     git diff -U0 --no-index M.out 4.out >4diff.out
      compare_change 4diff.out expected &&
      check_cache_at yomin clean &&
      sum bozbar frotz nitfol >actual4.sum &&
@@ -94,7 +96,7 @@ test_expect_success \
      echo yomin yomin >yomin &&
      git read-tree -m -u $treeH $treeM &&
      git ls-files --stage >5.out || return 1
-     diff -U0 M.out 5.out >5diff.out
+     git diff -U0 --no-index M.out 5.out >5diff.out
      compare_change 5diff.out expected &&
      check_cache_at yomin dirty &&
      sum bozbar frotz nitfol >actual5.sum &&
@@ -206,7 +208,7 @@ test_expect_success \
      git update-index --add nitfol &&
      git read-tree -m -u $treeH $treeM &&
      git ls-files --stage >14.out || return 1
-     diff -U0 M.out 14.out >14diff.out
+     git diff -U0 --no-index M.out 14.out >14diff.out
      compare_change 14diff.out expected &&
      sum bozbar frotz >actual14.sum &&
      grep -v nitfol M.sum > expected14.sum &&
@@ -227,7 +229,7 @@ test_expect_success \
      echo nitfol nitfol nitfol >nitfol &&
      git read-tree -m -u $treeH $treeM &&
      git ls-files --stage >15.out || return 1
-     diff -U0 M.out 15.out >15diff.out
+     git diff -U0 --no-index M.out 15.out >15diff.out
      compare_change 15diff.out expected &&
      check_cache_at nitfol dirty &&
      sum bozbar frotz >actual15.sum &&
index 1ec0535138c72bbd1e497c35c21bc5ea46b0315f..fd98e445bf2e74284709df54d2cd2d3f0006b19c 100755 (executable)
@@ -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
index 09a8199335cbdf96f8aba75d47a321f0cfb828d9..67e637b7810190e1b7d12dab70cd41d83db0e442 100755 (executable)
@@ -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'
index f98f4c51796e6f7a7181568a134e21ecd9dc2c4f..1983076c753ea12a4f69d2a98eda3c1621daed59 100755 (executable)
@@ -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
 '
index b31e4b1ac66e56d67ba48ab213c4ef9c32f05ea8..04c2b164bcba0bdead45a50bbb14ceff19e8411f 100755 (executable)
@@ -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
 
index 73f830db2374e751fb46e25b345e860979b9dd05..5b24f05573221afb3dc472e78a443ba718db3c60 100755 (executable)
@@ -188,16 +188,30 @@ test_expect_success 'delete' '
        test_tick &&
        git commit -m tiger C &&
 
-       test 5 = $(git reflog | wc -l) &&
+       HEAD_entry_count=$(git reflog | wc -l)
+       master_entry_count=$(git reflog show master | wc -l)
+
+       test $HEAD_entry_count = 5 &&
+       test $master_entry_count = 5 &&
+
 
        git reflog delete master@{1} &&
        git reflog show master > output &&
-       test 4 = $(wc -l < output) &&
+       test $(($master_entry_count - 1)) = $(wc -l < output) &&
+       test $HEAD_entry_count = $(git reflog | wc -l) &&
        ! grep ox < output &&
 
+       master_entry_count=$(wc -l < output)
+
+       git reflog delete HEAD@{1} &&
+       test $(($HEAD_entry_count -1)) = $(git reflog | wc -l) &&
+       test $master_entry_count = $(git reflog show master | wc -l) &&
+
+       HEAD_entry_count=$(git reflog | wc -l)
+
        git reflog delete master@{07.04.2005.15:15:00.-0700} &&
        git reflog show master > output &&
-       test 3 = $(wc -l < output) &&
+       test $(($master_entry_count - 1)) = $(wc -l < output) &&
        ! grep dragon < output
 
 '
index 2ee88d8a069288d0d9f6931231162e04d6b0917a..c039ee3fd86fc30a551a301066528a8574c34c1e 100755 (executable)
@@ -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
index 95244c9bcf54de8cb3584b4022e53a84051d496f..cc6539494737fff8a02460b6cdca3fccad8f770f 100755 (executable)
@@ -23,7 +23,7 @@ add_line_into_file()
     fi
 
     test_tick
-    git-commit --quiet -m "$MSG" $_file
+    git commit --quiet -m "$MSG" $_file
 }
 
 HASH1=
index a84c5a6af9e69ffec7689827ce1ba653a658a73f..ed12c4d78298dec9c5f1bf83f4f877b07d2659c0 100755 (executable)
@@ -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
index 88f268b9d7a696a06f5ce560c1e8ed0f3d8dc3a3..b7131d8c08daf20f328dd7f9ce7a1118a734516b 100755 (executable)
@@ -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}"
 '
 
index 59b560bfdf240e87516aadd6a31a2fe84e85d49a..648184fd983512be57b46fb5903b42e4de5e4704 100755 (executable)
@@ -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
index 19d0894d260787d37a43199d7a3f6c3aa37d32aa..f195aefe3a207fa5bac447b59f16423da25abc21 100755 (executable)
@@ -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 \
index f57a6e077c3b85dcdedc3f4813150feebc8e647d..cd9231cf614c4326518632e514ccc68a5dc59223 100755 (executable)
@@ -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' '
index 1caeacafa7ae70506e626498d274dbfa25f1b036..8666946b025097d3e93c7853d39265429da81578 100755 (executable)
@@ -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)' '
index af8c4121abfc28b7e289b39936df45bd5b82cf22..f4066cbc090a8fd0f6a528eed65d16d705c1bb18 100755 (executable)
@@ -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.' \
index aff360303ae2a304bff4799def6906defdb85843..de0cdb1cf4e4dbb6395619bdd2f56c0b027fdea7 100755 (executable)
@@ -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)
index 7a83fbfe4f6b47dc5dbaa3df59c8633ae5c2c8f8..2147eacc5057128facc08816a2980646bed28ec5 100755 (executable)
@@ -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 &&
index c2dec1c6320a0f9b555e3cd38d164c4e3efcb51e..087ef75061f4d56fcb6350284d91820485249087 100755 (executable)
@@ -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 &&
index 0574ef1f101df172a30755726b0ea1b6c2ef5f7d..db46d53e8271c0410a0dbf53a3560a8b635e2853 100755 (executable)
@@ -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" || {
index 91bb5e1d9eea0b2f1ff7a1120d97ca2876a8f277..b7a670ef401429a50eb97e5f874c9e2c3897fd7d 100755 (executable)
@@ -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 &&
index 166ddb1447db4c33a79f0e9aea21cb00e8a151f2..aea6685984b9f0e132d34842c3ac99d7ea044905 100755 (executable)
@@ -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
index 0d33c71daa557e68268dfb2279a02fe2afca1ed7..64446e3db3afed68e970de6fc3c0780db25c85d1 100755 (executable)
@@ -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 '
index ffe3dd97b7b1c056d854e28795e1313ce1633452..e0ded197ecabce712ac1eeaa4c959c714f0e9d34 100755 (executable)
@@ -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)
@@ -202,6 +202,9 @@ test_expect_success 'retain authorship when squashing' '
 test_expect_success '-p handles "no changes" gracefully' '
        HEAD=$(git rev-parse HEAD) &&
        git rebase -i -p HEAD^ &&
+       git update-index --refresh &&
+       git diff-files --quiet &&
+       git diff-index --quiet --cached HEAD -- &&
        test $HEAD = $(git rev-parse HEAD)
 '
 
@@ -235,6 +238,9 @@ test_expect_success 'preserve merges with -p' '
        git checkout -b to-be-rebased &&
        test_tick &&
        git rebase -i -p --onto branch1 master &&
+       git update-index --refresh &&
+       git diff-files --quiet &&
+       git diff-index --quiet --cached HEAD -- &&
        test $(git rev-parse HEAD~6) = $(git rev-parse branch1) &&
        test $(git rev-parse HEAD~4^2) = $(git rev-parse to-be-preserved) &&
        test $(git rev-parse HEAD^^2^) = $(git rev-parse HEAD^^^) &&
@@ -244,6 +250,18 @@ test_expect_success 'preserve merges with -p' '
        test $(git show HEAD:unrelated-file) = 1
 '
 
+test_expect_success 'edit ancestor with -p' '
+       FAKE_LINES="1 edit 2 3 4" git rebase -i -p HEAD~3 &&
+       echo 2 > unrelated-file &&
+       test_tick &&
+       git commit -m L2-modified --amend unrelated-file &&
+       git rebase --continue &&
+       git update-index --refresh &&
+       git diff-files --quiet &&
+       git diff-index --quiet --cached HEAD -- &&
+       test $(git show HEAD:unrelated-file) = 2
+'
+
 test_expect_success '--continue tries to commit' '
        test_tick &&
        test_must_fail git rebase -i --onto new-branch1 HEAD^ &&
index 4de550a632e6ead08c9629e80901e4735c53f55c..2999e78937f31a45e9e2ea925f69ac00f157503f 100755 (executable)
@@ -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"
        '
index 4911c48378a137471d2ad56747ceed11d0115be5..dadbbc2a9f9b70a4e33f5aa825b8f9fe14eec124 100755 (executable)
@@ -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 (executable)
index 0000000..f7b3518
--- /dev/null
@@ -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
index 79c06adf1f035cf727771974b2f9713da9d2fb8c..558c80edbfa5c0c90566a0be94723e2783d6df9b 100755 (executable)
@@ -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
index 7d123d17fc156c61a8e85a399c3762e8075485de..2ac93a346d016c65614f2bf6142049e7bdc39bd1 100755 (executable)
@@ -222,4 +222,12 @@ test_expect_success 'git add (add.ignore-errors = false)' '
        ! ( git ls-files foo1 | grep foo1 )
 '
 
+test_expect_success 'git add '\''fo\[ou\]bar'\'' ignores foobar' '
+       git reset --hard &&
+       touch fo\[ou\]bar foobar &&
+       git add '\''fo\[ou\]bar'\'' &&
+       git ls-files fo\[ou\]bar | grep -F fo\[ou\]bar &&
+       ! ( git ls-files foobar | grep foobar )
+'
+
 test_done
index c851db8ca9373a890ede7c230710690d5b4b4165..6fb027ba57eeb328ac48ec78ff5f685fd94a6f4b 100755 (executable)
@@ -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
index 883281dbd6c02ea7b2d90336c2629eafacee0257..784c31aec99d90b69186079ddb66350d9f4a8827 100755 (executable)
@@ -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
 
index 235f372832cb32aefff0a00c4f2ac0e19de2e55d..7655da3f8d5e68f293ae5afe2d58dd41b1396f37 100755 (executable)
@@ -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
 '
index fe4fb5116ac4c482c357f0af3f0a34da27cee237..58680524258037eb0c17f7e2929d58ed1c16b574 100755 (executable)
@@ -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.'
index 8d4804b65818f7fc55f0c0736fde673ac7512a8a..7484cbede6ccd3ecb56a3ebff734740cb543c0a4 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2007 Johannes E Schindelin
 #
 
-test_description='Test git-stash'
+test_description='Test git stash'
 
 . ./test-lib.sh
 
index c44b27aeb24816a346f0aa84d70546a0ffd83b2a..6ddd46915d2757bb5a40057e6850a4f72cd4dafb 100755 (executable)
@@ -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
index a32692417db73444dbdc143e6908b7371be79d42..71bac83dd5e42a19e3b1a7e869df0e7143371c99 100755 (executable)
@@ -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
index a4cfde6b2927a4655f582d7e92dad4568f7b5f89..cc3681f16118ca70ae9f65a27ccd6f354a6deee1 100755 (executable)
@@ -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
@@ -168,6 +168,20 @@ test_expect_success \
     'git diff-tree -r $tree_A $tree_B >.test-a &&
      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 &&
index 8b1f875286b25b5fc1a527b5b0281f866724a82d..c6130c40198ad5ed5ec8a0342341a4ec5cc49d7d 100755 (executable)
@@ -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,
index 3d25be7a6709cdd23e0d583a8f1a3e19a3927cd8..b35af9b42d318904bd12649562be309fd49977a3 100755 (executable)
@@ -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' \
index 66300173124eee8480e7214322faf8bc493ad940..1ba359d478e3d3491aed5f622932382767c8f4dc 100755 (executable)
@@ -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
index 104a4e1492b65a64d061e1ce1df0b0a2a49fb20e..42072d724ef67c51e6a9adcf9bf8e3ca1757e053 100755 (executable)
@@ -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'
index 26c2e4aa65c539c527ae8e2d71b5abb40c21fbbd..7e343a9cd130a73547ed1df9a4d9cd364e60bf9f 100755 (executable)
@@ -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"'
index d2b45e7b8fb3902cb740e0df582f92195a295f24..de3f17478efcaf008340a7ab81cb049f9a9e9a3a 100755 (executable)
@@ -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
index ad3d9e48454d2e72afce682df009cdaaee9ba3c5..9322298ecc6cb79f0123dea4e329317c5bfbfd11 100755 (executable)
@@ -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 \
index c6d13693ba45b594704c2ef55d40540ee3f9c25f..02efecae3ad06e5a62553e990fc0934dd0c65eab 100755 (executable)
@@ -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
index eced1f30fb8475739aef52230bbb79946a0f76d8..b8ec6e90afb970b1b2540e30901b2f058522544e 100755 (executable)
@@ -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"'
index 9337b81064bbdbe4e7f590830b458c48226c4a17..1a6b52234d8df70e5ddcb28c0ddde582d8310d43 100755 (executable)
@@ -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" '
index 7fe853c20d1111e40371a3796d82bb8485f5ebcf..9d99dc28879d4f7f35001e0785f97f319fe13b40 100755 (executable)
@@ -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
index a27fccc8dce431169ce41f7137fb75f44149719c..fc2307eaa3b4e8b1481fd7aa5ae0f93d085338af 100755 (executable)
@@ -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
 
@@ -341,4 +341,31 @@ test_expect_success 'checkdiff detects trailing blank lines' '
        git diff --check | grep "ends with blank"
 '
 
+test_expect_success 'checkdiff allows new blank lines' '
+       git checkout x &&
+       mv x y &&
+       (
+               echo "/* This is new */" &&
+               echo "" &&
+               cat y
+       ) >x &&
+       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
index f07035ab7ec72557be7a0cba9ea286bcbaa79da9..55eb5f83f17c0ebfb537d390fd3913b7c89d65f4 100755 (executable)
@@ -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
 }
 
index 833d6cbcfc063f336d97689ae4e547cf5e956b69..18bcd9713d4e7a1446639dece4b8bc0173c57b22 100755 (executable)
@@ -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
index 0d9cbb62615c0d94da784f63907989988b0e8151..84a1fe31151c2af38554eaca8f03e2c1e2e7848f 100755 (executable)
@@ -13,7 +13,8 @@ test_expect_success setup '
        echo "  HT and SP indent" >>F &&
        echo "With trailing SP " >>F &&
        echo "Carriage ReturnQ" | tr Q "\015" >>F &&
-       echo "No problem" >>F
+       echo "No problem" >>F &&
+       echo >>F
 
 '
 
@@ -160,4 +161,33 @@ test_expect_success 'with cr-at-eol (attribute)' '
 
 '
 
+test_expect_success 'trailing empty lines (1)' '
+
+       rm -f .gitattributes &&
+       test_must_fail git diff --check >output &&
+       grep "ends with blank lines." output &&
+       grep "trailing whitespace" output
+
+'
+
+test_expect_success 'trailing empty lines (2)' '
+
+       echo "F -whitespace" >.gitattributes &&
+       git diff --check >output &&
+       ! test -s output
+
+'
+
+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
index 637b4e19d52e81cf1472a4ed9dcfb0c9ff00da2b..dfe3fbc74b96fff50160c032f0a65ba54f9ad1b2 100755 (executable)
@@ -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
index bf996fc414d3b5ea16488a8b274973a8347b29cb..2a537a21e8e6793e6ffa2fe1522e30f877b209fe 100755 (executable)
@@ -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
 
 '
 
index 4dbfc6e8b751a6c93b1f9dfee8ce649235c98c93..297ddb5a25b682412851aed70370771aa5a15976 100755 (executable)
@@ -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
index ba6679c6e4032bb12e4206226f95770946ece8cc..1c2edebb09bd6e1d7581365011c8500da57942c5 100755 (executable)
@@ -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 (executable)
index 0000000..4ca65e0
--- /dev/null
@@ -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
index e0c67740a5ef85aaa3edc9a4514da72c92ce30ec..9b433de83630774206fb89dfae1a4396264390cc 100755 (executable)
@@ -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
index da8abcf36418dbd2e9d8ec85871c245991f96fda..e3443d004d026c86fd783cb8e6e3d03f22676778 100755 (executable)
@@ -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
 
index 7da0b4bb8bfa96765b9f6eaa1693e2e24e82d335..ad4cc1a7576d41131d291426d80c329ff838aa26 100755 (executable)
@@ -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.' \
index e7e2913de745cc9f7639103757933f6238fdd564..0e3ce3611d9e83ab290ce034f2439961864ce30a 100755 (executable)
@@ -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 /" \
index 85f3da2b98a881647837323e3af0378ce59a9db5..f83322e513b96bb90e71ce39340515c6be0db186 100755 (executable)
@@ -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
 
index 1f859dd908cb298bf89a13822e8fc19882060689..3a8202ea9311b1c90158ad0d115dda985060fdeb 100755 (executable)
@@ -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
 '
 
index 6e6aaf59364456e21bb1deda960edb5295a71131..1be5fb3f9dfab6d4fcd79f65de6b85ae05f373cd 100755 (executable)
@@ -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"
 '
 
index 7d86cdff64522f588a3d3e781cf2b272087cfd88..4448aba7e0727b70a4e525e57ad21cd7e226c1f8 100755 (executable)
@@ -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 &&
index 4c8af45f834d034529c2a627768a0a3e6f1aac8d..0ab925c4e4710a560f0d35e47ccdda8ddb2b8212 100755 (executable)
@@ -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
 
index e9f3e72c7ee5584d956d46126956c641a7d53905..fe14589427643b9bb7759c597935da724adf1a64 100755 (executable)
@@ -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` = 10'
+       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,21 @@ 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
+
+'
+
+test_expect_success 'mailinfo on from header without name works' '
+
+       mkdir info-from &&
+       git mailsplit -oinfo-from "$TEST_DIRECTORY"/t5100/info-from.in &&
+       test_cmp "$TEST_DIRECTORY"/t5100/info-from.in info-from/0001 &&
+       git mailinfo info-from/msg info-from/patch \
+         <info-from/0001 >info-from/out &&
+       test_cmp "$TEST_DIRECTORY"/t5100/info-from.expect info-from/out
 
 '
 
diff --git a/t/t5100/info-from.expect b/t/t5100/info-from.expect
new file mode 100644 (file)
index 0000000..c31d2eb
--- /dev/null
@@ -0,0 +1,5 @@
+Author: bare@example.com
+Email: bare@example.com
+Subject: testing bare address in from header
+Date: Sun, 25 May 2008 00:38:18 -0700
+
diff --git a/t/t5100/info-from.in b/t/t5100/info-from.in
new file mode 100644 (file)
index 0000000..4f08209
--- /dev/null
@@ -0,0 +1,8 @@
+From 667d8940e719cddee1cfe237cbbe215e20270b09 Mon Sep 17 00:00:00 2001
+From: bare@example.com
+Date: Sun, 25 May 2008 00:38:18 -0700
+Subject: [PATCH] testing bare address in from header
+
+commit message
+---
+patch
diff --git a/t/t5100/info0011 b/t/t5100/info0011
new file mode 100644 (file)
index 0000000..da5a605
--- /dev/null
@@ -0,0 +1,5 @@
+Author: A U Thor
+Email: a.u.thor@example.com
+Subject: Xyzzy
+Date: Fri, 8 Aug 2008 13:08:37 +0200 (CEST)
+
diff --git a/t/t5100/msg0011 b/t/t5100/msg0011
new file mode 100644 (file)
index 0000000..4667f21
--- /dev/null
@@ -0,0 +1,2 @@
+Here comes a commit log message, and
+its second line is here.
diff --git a/t/t5100/patch0011 b/t/t5100/patch0011
new file mode 100644 (file)
index 0000000..8841d3c
--- /dev/null
@@ -0,0 +1,22 @@
+---
+ builtin-mailinfo.c  |    4 ++--
+
+diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
+index 3e5fe51..aabfe5c 100644
+--- a/builtin-mailinfo.c
++++ b/builtin-mailinfo.c
+@@ -758,8 +758,8 @@ static void handle_body(void)
+               /* process any boundary lines */
+               if (*content_top && is_multipart_boundary(&line)) {
+                       /* flush any leftover */
+-                      if (line.len)
+-                              handle_filter(&line);
++                      if (prev.len)
++                              handle_filter(&prev);
+                       if (!handle_boundary())
+                               goto handle_body_out;
+-- 
+1.6.0.rc2
+
+
index aba57f922b33b6ab708afbbf82c7e56f6e37bb8d..4bf7947b418963e9b15e393fc738e515b3d2141d 100644 (file)
@@ -465,3 +465,39 @@ index 962aa34..2d1520f 100644
 -- 
 1.5.6.2.455.g1efb2
 
+From nobody Fri Aug  8 22:24:03 2008
+Date: Fri, 8 Aug 2008 13:08:37 +0200 (CEST)
+From: A U Thor <a.u.thor@example.com>
+Subject: [PATCH 3/3 v2] Xyzzy
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary="=-=-="
+
+--=-=-=
+Content-Type: text/plain; charset=iso-8859-15
+Content-Transfer-Encoding: quoted-printable
+
+Here comes a commit log message, and
+its second line is here.
+---
+ builtin-mailinfo.c  |    4 ++--
+
+diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
+index 3e5fe51..aabfe5c 100644
+--- a/builtin-mailinfo.c
++++ b/builtin-mailinfo.c
+@@ -758,8 +758,8 @@ static void handle_body(void)
+               /* process any boundary lines */
+               if (*content_top && is_multipart_boundary(&line)) {
+                       /* flush any leftover */
+-                      if (line.len)
+-                              handle_filter(&line);
++                      if (prev.len)
++                              handle_filter(&prev);
+=20
+                       if (!handle_boundary())
+                               goto handle_body_out;
+--=20
+1.6.0.rc2
+
+--=-=-=--
+
index 645583f9d729cb04ea7bd9638b0c49c48128822e..3a0ef8759c9d7a55b95c56ca38cd3c37ac2432fa 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-pack-object
+test_description='git pack-object
 
 '
 . ./test-lib.sh
@@ -186,6 +186,12 @@ test_expect_success \
                        test-2-${packname_2}.idx \
                        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 &&
@@ -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' \
index 073ac0c6f9dd3d06474b1b81c8c7b622dcfee663..0a24e61ff942ee91dfb25fe490330a0272480ac2 100755 (executable)
@@ -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"
index 0639772ac4e1e2c6563e793b16c2c10faf06758a..6424db1f28e11c3ac6eb629ba4db7380812eab72 100755 (executable)
@@ -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 \
index 9fd9d0700033027921c90290cedc0a31d71c7733..771c0a06a4bd01cf40628ffae379b5d992802ef6 100755 (executable)
@@ -21,7 +21,7 @@ test_expect_success 'prune stale packs' '
        orig_pack=$(echo .git/objects/pack/*.pack) &&
        : > .git/objects/tmp_1.pack &&
        : > .git/objects/tmp_2.pack &&
-       test-chmtime -86501 .git/objects/tmp_1.pack &&
+       test-chmtime =-86501 .git/objects/tmp_1.pack &&
        git prune --expire 1.day &&
        test -f $orig_pack &&
        test -f .git/objects/tmp_2.pack &&
@@ -39,7 +39,7 @@ test_expect_success 'prune --expire' '
        git prune --expire=1.hour.ago &&
        test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
        test -f $BLOB_FILE &&
-       test-chmtime -86500 $BLOB_FILE &&
+       test-chmtime =-86500 $BLOB_FILE &&
        git prune --expire 1.day &&
        test $before = $(git count-objects | sed "s/ .*//") &&
        ! test -f $BLOB_FILE
@@ -53,11 +53,11 @@ test_expect_success 'gc: implicit prune --expire' '
        BLOB_FILE=.git/objects/$(echo $BLOB | sed "s/^../&\//") &&
        test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
        test -f $BLOB_FILE &&
-       test-chmtime -$((86400*14-30)) $BLOB_FILE &&
+       test-chmtime =-$((86400*14-30)) $BLOB_FILE &&
        git gc &&
        test $((1 + $before)) = $(git count-objects | sed "s/ .*//") &&
        test -f $BLOB_FILE &&
-       test-chmtime -$((86400*14+1)) $BLOB_FILE &&
+       test-chmtime =-$((86400*14+1)) $BLOB_FILE &&
        git gc &&
        test $before = $(git count-objects | sed "s/ .*//") &&
        ! test -f $BLOB_FILE
index fb471a08c698b431cd2440e9d4f0e77e2fef6b08..b061864a8743636ae7759ff4e8ff2694410617a1 100755 (executable)
@@ -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 (executable)
index 0000000..f4931c0
--- /dev/null
@@ -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
index 68c2ae688c2b7ff96ec927622f92fd512e7beefe..544771d8fa98ec70d84e5083c2bfc0ebdf45f9a1 100755 (executable)
@@ -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
 '
 
index ee769d6695ee91120671c485924d804f14c80424..64f66c94f36538b1c7d20045fc4233aa0b9d9a0d 100755 (executable)
@@ -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
 '
 
index 1394047a8dc3e87476e223db42936d59845f803b..6eb2ffd6ecabb9125d06e76a17d0821d7e907dfd 100755 (executable)
@@ -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
 '
 
index 823239a251f9ba9607649382d595db1b6cc6dcb2..9b2e1a94c5fb5aa094853a169cbdf2f7dc56e152 100755 (executable)
@@ -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 &&
index 362cf7e928090fb3752936317f78a4d128810127..c450f33f333e6f1c367f8f350dfd78f8f44a0fee 100755 (executable)
@@ -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)" '
index be9ee9326fc4590dcc875e31b6cf64b800451bc5..c4496635dfba85b0e9fc105c4516096d433881a4 100755 (executable)
@@ -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
 
index 13d1d826c20293c26c739c70c0a36ed48bbb41d1..de26c203270522983f9ffae4e0bde64a61898567 100755 (executable)
@@ -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 &&
index 8becbc3f38fde02371ebbcd9a39a320a1c00c290..1f4608d8ba4748a2bd5c7a3d5a75a04364e8f646 100755 (executable)
@@ -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" '
index 1a15817cd5f8e838812723ad14dbec59a108680c..f5102b902a4fa0505fee13aa18d38a211cdb42cb 100755 (executable)
@@ -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
 '
 
index f8c17cd96cc86ca8f2db2ff51467f712d65f8956..da9588645cd9d0054440e5ed3ba14f630c44f506 100755 (executable)
@@ -19,7 +19,7 @@ then
        exit
 fi
 
-. ../lib-httpd.sh
+. "$TEST_DIRECTORY"/lib-httpd.sh
 
 if ! start_httpd >&3 2>&4
 then
@@ -41,7 +41,7 @@ test_expect_success 'setup remote repository' '
        git clone --bare test_repo test_repo.git &&
        cd test_repo.git &&
        git --bare update-server-info &&
-       chmod +x hooks/post-update &&
+       mv hooks/post-update.sample hooks/post-update &&
        cd - &&
        mv test_repo.git "$HTTPD_DOCUMENT_ROOT_PATH"
 '
index 3c013e2b6aa5c659c80134baf43c99e0d89e2e38..ee06d2864949de71b000402fda4378c9b483fe72 100755 (executable)
@@ -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' \
index d785b3df78e8507d81ffa03ff694846791edfc87..78a3fa639c97b7dce054d89c74c67a855d0d7954 100755 (executable)
@@ -31,6 +31,12 @@ test_expect_success 'clone with excess parameters (2)' '
 
 '
 
+test_expect_success 'output from clone' '
+       rm -fr dst &&
+       git clone -n "file://$(pwd)/src" dst >output &&
+       test $(grep Initialized output | wc -l) = 1
+'
+
 test_expect_success 'clone does not keep pack' '
 
        rm -fr dst &&
@@ -70,4 +76,53 @@ test_expect_success 'clone creates intermediate directories for bare repo' '
 
 '
 
+test_expect_success 'clone --mirror' '
+
+       git clone --mirror src mirror &&
+       test -f mirror/HEAD &&
+       test ! -f mirror/file &&
+       FETCH="$(cd mirror && git config remote.origin.fetch)" &&
+       test "+refs/*:refs/*" = "$FETCH" &&
+       MIRROR="$(cd mirror && git config --bool remote.origin.mirror)" &&
+       test "$MIRROR" = true
+
+'
+
+test_expect_success 'clone --bare names the local repository <name>.git' '
+
+       git clone --bare src &&
+       test -d src.git
+
+'
+
+test_expect_success 'clone --mirror does not repeat tags' '
+
+       (cd src &&
+        git tag some-tag HEAD) &&
+       git clone --mirror src mirror2 &&
+       (cd mirror2 &&
+        git show-ref 2> clone.err > clone.out) &&
+       test_must_fail grep Duplicate mirror2/clone.err &&
+       grep some-tag mirror2/clone.out
+
+'
+
+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
index 8367a6845f6ea3cdbc2f4f0e096144975fa3aef2..82b1d1e2b3f6704cf08540f0e6f4cecf0981cb7d 100755 (executable)
@@ -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
index 8f5de097ecd703ae5f6f889ecb735f7277f361be..b4e8fbaa5e6f2a56094c05ca505630669a51e101 100755 (executable)
@@ -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...
 #
index 5daa0be8cc856bff513905bc6583854e0b5ae53a..2c73f2da7b0a1f560bfd41376b587d1c91b18615 100755 (executable)
@@ -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()
 {
index 9176484db2f78122f71c0f11889e01382effcfb9..86bf7e14ba5bb9a76ef00cb5a3564e326f674a18 100755 (executable)
@@ -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) &&
index b6e57b2426728cce308a57315247cd2a66cabf4a..04e4b7c5c2aa4f7c6922ebc5c9236962ab5d175c 100755 (executable)
@@ -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
index f674c48cab3e80d63b5a5831c667b8e08b542905..5e18d68c97dc52537365adce5c3c84d291fe20be 100755 (executable)
@@ -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' '
 
index fc58456a11eef7ecb4cf60d37a9e9d5cbe13f970..53892a555ce2e4a51db15066771f217a135e15e9 100755 (executable)
@@ -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' '
index 56fc34176859b81137b4d88af90398b9a74a18f7..4b423e937dbd259e5b2311051907a54309e0edb9 100755 (executable)
@@ -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 &&
index 92ca1f0f8ccabe6f01159ea3e4a73683387ec4a3..b519626ca09255a433b0d1cb32780a6feafa09f6 100755 (executable)
@@ -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 &&
index 244fda62a5cd34d778cf0789961654eaa37fe589..85fa39cf0b80d6e3d12a3894f752b9e094345958 100755 (executable)
@@ -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=
@@ -350,6 +350,120 @@ test_expect_success 'bisect does not create a "bisect" branch' '
        git branch -D bisect
 '
 
+# This creates a "side" branch to test "siblings" cases.
+#
+# H1-H2-H3-H4-H5-H6-H7  <--other
+#            \
+#             S5-S6-S7  <--side
+#
+test_expect_success 'side branch creation' '
+       git bisect reset &&
+       git checkout -b side $HASH4 &&
+       add_line_into_file "5(side): first line on a side branch" hello2 &&
+       SIDE_HASH5=$(git rev-parse --verify HEAD) &&
+       add_line_into_file "6(side): second line on a side branch" hello2 &&
+       SIDE_HASH6=$(git rev-parse --verify HEAD) &&
+       add_line_into_file "7(side): third line on a side branch" hello2 &&
+       SIDE_HASH7=$(git rev-parse --verify HEAD)
+'
+
+test_expect_success 'good merge base when good and bad are siblings' '
+       git bisect start "$HASH7" "$SIDE_HASH7" > my_bisect_log.txt &&
+       grep "merge base must be tested" my_bisect_log.txt &&
+       grep $HASH4 my_bisect_log.txt &&
+       git bisect good > my_bisect_log.txt &&
+       test_must_fail grep "merge base must be tested" my_bisect_log.txt &&
+       grep $HASH6 my_bisect_log.txt &&
+       git bisect reset
+'
+test_expect_success 'skipped merge base when good and bad are siblings' '
+       git bisect start "$SIDE_HASH7" "$HASH7" > my_bisect_log.txt &&
+       grep "merge base must be tested" my_bisect_log.txt &&
+       grep $HASH4 my_bisect_log.txt &&
+       git bisect skip > my_bisect_log.txt 2>&1 &&
+       grep "Warning" my_bisect_log.txt &&
+       grep $SIDE_HASH6 my_bisect_log.txt &&
+       git bisect reset
+'
+
+test_expect_success 'bad merge base when good and bad are siblings' '
+       git bisect start "$HASH7" HEAD > my_bisect_log.txt &&
+       grep "merge base must be tested" my_bisect_log.txt &&
+       grep $HASH4 my_bisect_log.txt &&
+       test_must_fail git bisect bad > my_bisect_log.txt 2>&1 &&
+       grep "merge base $HASH4 is bad" my_bisect_log.txt &&
+       grep "fixed between $HASH4 and \[$SIDE_HASH7\]" my_bisect_log.txt &&
+       git bisect reset
+'
+
+# This creates a few more commits (A and B) to test "siblings" cases
+# when a good and a bad rev have many merge bases.
+#
+# We should have the following:
+#
+# H1-H2-H3-H4-H5-H6-H7
+#            \  \     \
+#             S5-A     \
+#              \        \
+#               S6-S7----B
+#
+# And there A and B have 2 merge bases (S5 and H5) that should be
+# reported by "git merge-base --all A B".
+#
+test_expect_success 'many merge bases creation' '
+       git checkout "$SIDE_HASH5" &&
+       git merge -m "merge HASH5 and SIDE_HASH5" "$HASH5" &&
+       A_HASH=$(git rev-parse --verify HEAD) &&
+       git checkout side &&
+       git merge -m "merge HASH7 and SIDE_HASH7" "$HASH7" &&
+       B_HASH=$(git rev-parse --verify HEAD) &&
+       git merge-base --all "$A_HASH" "$B_HASH" > merge_bases.txt &&
+       test $(wc -l < merge_bases.txt) = "2" &&
+       grep "$HASH5" merge_bases.txt &&
+       grep "$SIDE_HASH5" merge_bases.txt
+'
+
+test_expect_success 'good merge bases when good and bad are siblings' '
+       git bisect start "$B_HASH" "$A_HASH" > my_bisect_log.txt &&
+       grep "merge base must be tested" my_bisect_log.txt &&
+       git bisect good > my_bisect_log2.txt &&
+       grep "merge base must be tested" my_bisect_log2.txt &&
+       {
+               {
+                       grep "$SIDE_HASH5" my_bisect_log.txt &&
+                       grep "$HASH5" my_bisect_log2.txt
+               } || {
+                       grep "$SIDE_HASH5" my_bisect_log2.txt &&
+                       grep "$HASH5" my_bisect_log.txt
+               }
+       } &&
+       git bisect reset
+'
+
+check_trace() {
+       grep "$1" "$GIT_TRACE" | grep "\^$2" | grep "$3" >/dev/null
+}
+
+test_expect_success 'optimized merge base checks' '
+       GIT_TRACE="$(pwd)/trace.log" &&
+       export GIT_TRACE &&
+       git bisect start "$HASH7" "$SIDE_HASH7" > my_bisect_log.txt &&
+       grep "merge base must be tested" my_bisect_log.txt &&
+       grep "$HASH4" my_bisect_log.txt &&
+       check_trace "rev-list" "$HASH7" "$SIDE_HASH7" &&
+       git bisect good > my_bisect_log2.txt &&
+       test -f ".git/BISECT_ANCESTORS_OK" &&
+       test "$HASH6" = $(git rev-parse --verify HEAD) &&
+       : > "$GIT_TRACE" &&
+       git bisect bad > my_bisect_log3.txt &&
+       test_must_fail check_trace "rev-list" "$HASH6" "$SIDE_HASH7" &&
+       git bisect good "$A_HASH" > my_bisect_log4.txt &&
+       grep "merge base must be tested" my_bisect_log4.txt &&
+       test_must_fail test -f ".git/BISECT_ANCESTORS_OK" &&
+       check_trace "rev-list" "$HASH6" "$A_HASH" &&
+       unset GIT_TRACE
+'
+
 #
 #
 test_done
index 919552a2fc5544c130268befca322a6e6a8081c3..f105fab98e2d493ab489d345676101fc13096c22 100755 (executable)
@@ -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
index 2fb672c3b43a9efe4cb9c85465f6b33f23724e48..16cc63581383360d6dc92a69f646890eb00e580a 100755 (executable)
@@ -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
 
 '
 
index bc74349416d858834c43f6c648daa95c8b9f3a7a..8f5a06f7dd8383722022eb7a8abd0ff9bafa6f45 100755 (executable)
@@ -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
index a3c8941c726d77fd993a3cfcd7fde4e9aa43da74..26995b3cdda32b34b2ecf428e5bbf5ef2ff2fc8a 100755 (executable)
@@ -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
 '
 
@@ -262,4 +262,14 @@ for i in "--perl --shell" "-s --python" "--python --tcl" "--tcl --perl"; do
        "
 done
 
+test_expect_success 'an unusual tag with an incomplete line' '
+
+       git tag -m "bogo" bogo &&
+       bogo=$(git cat-file tag bogo) &&
+       bogo=$(printf "%s" "$bogo" | git mktag) &&
+       git tag -f bogo "$bogo" &&
+       git for-each-ref --format "%(body)" refs/tags/bogo
+
+'
+
 test_done
index 910a28c7e29b6dd8bd30d1ccb156681b44e51bca..575ef5beb2bdd3a0814fb45010ae7889b936f543 100755 (executable)
@@ -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' \
index c8b4f65f380f3941c75bd6ed52975777d2b28d67..5e359cb561b6d6f7c1bae678b7b823ed2ce34cf1 100755 (executable)
@@ -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
index a0ab096c8fdee153a89a1428f85c9bf107badada..b0a9d7d536314ec842b141c09ba0d6f8b06b6288 100755 (executable)
@@ -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
index bc7ce2cbbb712f890245688da03be96146a1d9ed..f0edbf1a76739177943006461b853ec17e8bbb2b 100755 (executable)
@@ -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)
 '
 
@@ -1070,4 +1070,24 @@ test_expect_success \
        test_cmp expect actual
 '
 
+test_expect_success 'filename for the message is relative to cwd' '
+       mkdir subdir &&
+       echo "Tag message in top directory" >msgfile-5 &&
+       echo "Tag message in sub directory" >subdir/msgfile-5 &&
+       (
+               cd subdir &&
+               git tag -a -F msgfile-5 tag-from-subdir
+       ) &&
+       git cat-file tag tag-from-subdir | grep "in sub directory"
+'
+
+test_expect_success 'filename for the message is relative to cwd' '
+       echo "Tag message in sub directory" >subdir/msgfile-6 &&
+       (
+               cd subdir &&
+               git tag -a -F msgfile-6 tag-from-subdir-2
+       ) &&
+       git cat-file tag tag-from-subdir-2 | grep "in sub directory"
+'
+
 test_done
index 0d9874bfd7082f9ef16c1f6b3ff8a848a19d8937..96e163f084f471ea75e6d5b927a5edc6462e54d4 100755 (executable)
@@ -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' \
index 29f5678b4c93485ad492fa865a5da58a3cc05b7c..e637c7d4dbdce337b4d005719c4aa86d447a70d9 100755 (executable)
@@ -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
 
index cdecebe456c7a9cf30465b112a24ce7bcf76f344..42bf518c68e6ef07c8be1af714723b2f900a573c 100755 (executable)
@@ -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' '
index 9ad5d635a2881c920fff8e524aea0ed931f68e6c..25181388f8a8f1730d05fce128e0e1fc66eb3c0e 100755 (executable)
@@ -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
index 2b51c0d7d8ab727a5fb0be8338938f1d3b2eb6a3..1636fac2a43e30a99674df98ff4544ee04612cc5 100755 (executable)
@@ -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 &&
index cbc0c34ce2487959ef0e8f89f7c2a5d4a68be826..be73f7b60ac0c8857cbe34c9e0bf8dd43a3dec39 100755 (executable)
@@ -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) &&
index bf12dbdeef6e307850a91eb6be5ebe537b2de0c8..61498293b99e1cbbb4bfb4de45b6d14488aaddd0 100755 (executable)
@@ -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
index d89f91a6fb7fa12d41cc4a346829bff7cbd3e76b..6e18a96319bef5c4ddfbc86ce79b02b364f04387 100755 (executable)
@@ -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,41 @@ 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)' '
+       mkdir subdir &&
+       echo "Log in top directory" >log &&
+       echo "Log in sub directory" >subdir/log &&
+       (
+               cd subdir &&
+               git commit --allow-empty -F log
+       ) &&
+       commit_msg_is "Log in sub directory"
+'
+
+test_expect_success 'commit message from file (2)' '
+       rm -f log &&
+       echo "Log in sub directory" >subdir/log &&
+       (
+               cd subdir &&
+               git commit --allow-empty -F log
+       ) &&
+       commit_msg_is "Log in sub directory"
+'
+
+test_expect_success 'commit message from stdin' '
+       (
+               cd subdir &&
+               echo "Log with foo word" | git commit --allow-empty -F -
+       ) &&
+       commit_msg_is "Log with foo word"
 '
 
 test_done
index 0edd9ddf73b7053c21595ce1ac1dd157c77d1bca..63bfc6d8b3f6917cad1b51a73a84ba61762b220d 100755 (executable)
@@ -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
 
 '
 
index 38a48b57c70a888838cfa114be843e1d4aea00d8..c8e4c2e7b452c5e8db3958a85195c8cc5f6918f5 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2007 Johannes E. Schindelin
 #
 
-test_description='git-status'
+test_description='git status'
 
 . ./test-lib.sh
 
index cd6c7c834218fd4c46c49396b79da1ddeef42772..ff189624d48fb9f68997395d121d4e7056511245 100755 (executable)
@@ -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
index a75130cdbb55be157c915f4fc1397227a78441ec..d9a08aac56f8edf002a126cba83172abf5015034 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='git-status for submodule'
+test_description='git status for submodule'
 
 . ./test-lib.sh
 
index 5eeb6c2b2708d582a6e86cd2e06e2b00b7b7b391..9516f541e9c47f83fed2fc8d3baa065a9bb206de 100755 (executable)
@@ -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 &&
@@ -488,4 +492,23 @@ test_expect_success 'merge c1 with c1 and c2' '
 
 test_debug 'gitk --all'
 
+test_expect_success 'merge fast-forward in a dirty tree' '
+       git reset --hard c0 &&
+       mv file file1 &&
+       cat file1 >file &&
+       rm -f file1 &&
+       git merge c2
+'
+
+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
index 55aa6b5f2716255b2b5aa74f1cac9d285de6d6a8..7ba94ea99bc0785da5b398e494d23469ba44992d 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='git-merge
+test_description='git merge
 
 Testing pull.* configuration parsing.'
 
index fcb8285746420ed721713d9c8e527d23cafb05cf..01e5415e943f3e16154f2f4d999f85a9d8b6ae49 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='git-merge
+test_description='git merge
 
 Testing octopus merge with more than 25 refs.'
 
index 17b19dc11f2b1a5d26a16f447733880f3cf30d26..b47b7b9757dffe2d3d41127b43ffa929505c0e77 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='git-merge
+test_description='git merge
 
 Testing octopus merge when reducing parents to independent branches.'
 
index 6081677d234f1fcb88b6b9160f707ebf0274f38a..de977c5e2f0b270c57bbea9daaf8e22eefdf8560 100755 (executable)
@@ -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.'
 
index ee21a107fd99e35b9d6325a040b7549b7a6c2502..0cb9d11f2171de19b260391017310f0ee792f89b 100755 (executable)
@@ -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 (executable)
index 0000000..52a451d
--- /dev/null
@@ -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
index 9285071c473dcfe7d37845d01ba20226b5ab585d..09fa5f115c9fabe1fec60a5597439b2c7f9ded6d 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2008 Charles Bailey
 #
 
-test_description='git-mergetool
+test_description='git mergetool
 
 Testing basic merge tool invocation'
 
index 31c340fd389ed2688bb94a29acbf892be6f0c564..531dac060a761f3383b3bee15444345a66e2f13b 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='git-repack works correctly'
+test_description='git repack works correctly'
 
 . ./test-lib.sh
 
index eabec2e06e2f97fc1790cd4ce30a80e402d4a205..45cb60ea4b167676b07ae1c847c0467f2a5e3d69 100755 (executable)
@@ -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' \
index 92ece30fa94784bdad8ae50fc370487e60bbcb5c..597cf0486fbe1034594d3eec821f5278d9648d43 100755 (executable)
@@ -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
index 1c857cf4ab6e359d7009d2c6b5018bb61c916e93..d098a01ba30fa08ae696085164e7b77453f8715a 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='git-send-email'
+test_description='git send-email'
 . ./test-lib.sh
 
 PROG='git send-email'
index 843a5013b96c675a629bd7f738eca220861e6ff8..9b238c329b87d98dca4d0e66839df97c5c3a0673 100755 (executable)
@@ -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\`\"
        "
 
index f420796c31db2746b71ba9d7090f37363eba214a..1e31d6ea7253ee4216347fd707d1408f97af32fa 100755 (executable)
@@ -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
index 0e7ce34b9b1e254873a2700cf58095318b49b15c..e2232180158cfb0e523c8ffdd3ac10bf61c8f4ee 100755 (executable)
@@ -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
        '
 
index 9ffd8458ef9d58fa5d3c42fd61f4629219b4d80a..963dd95e4a71ccefa64b9500c490f44ea6d7c789 100755 (executable)
@@ -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' '
index 4d964e2db7cc3c96fc64911bd58c4f2f9679a6cd..0a091e048e1f94eac751ba2b5c22fb8bf436e717 100755 (executable)
@@ -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 &'
index 63230367bb1566384e66e1b5ddd6a68e1ae98c8f..ba99abb6d975351cf2725e757a588a26109a9723 100755 (executable)
@@ -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
        '
index 83896e96876d8cca24496c7cb278732a308e3d92..6eb0fd85c86ec194062af7da8c7002f0819bcc07 100755 (executable)
@@ -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' &&
index bc37db9d62071ba92463276524675964c3e91593..fd185011b73a8e45b7863bc336f884dee8d4f980 100755 (executable)
@@ -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' '
index d9b553ad55b1f7024af0689a450a9c6c65dcb034..acad16a6f0f9b3b45b4766474e15ee5019ec2ce2 100755 (executable)
@@ -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"
index f6f71d0545c869a7216eb0e81f260085f6ffdec1..d8582b1aa5d178778623bfb4386a66f58e165c17 100755 (executable)
@@ -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
@@ -16,7 +16,8 @@ test_expect_success 'test refspec globbing' '
        echo "goodbye world" > trunk/src/b/readme &&
        svn import -m "initial" trunk "$svnrepo"/trunk &&
        svn co "$svnrepo" tmp &&
-       cd tmp &&
+       (
+               cd tmp &&
                mkdir branches tags &&
                svn add branches tags &&
                svn cp trunk branches/start &&
@@ -37,7 +38,7 @@ test_expect_success 'test refspec globbing' '
                echo "byebye" >> tags/end/src/b/readme &&
                poke tags/end/src/b/readme &&
                svn commit -m "nothing to see here"
-               cd .. &&
+       ) &&
        git config --add svn-remote.svn.url "$svnrepo" &&
        git config --add svn-remote.svn.fetch \
                         "trunk/src/a:refs/remotes/trunk" &&
@@ -45,14 +46,15 @@ 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 &&
-       cmp expect.end output.end &&
+       test_cmp expect.end output.end &&
        test "`git rev-parse refs/remotes/tags/end~1`" = \
                "`git rev-parse refs/remotes/branches/start`" &&
        test "`git rev-parse refs/remotes/branches/start~2`" = \
-               "`git rev-parse refs/remotes/trunk`"
+               "`git rev-parse refs/remotes/trunk`" &&
+       test_must_fail git rev-parse refs/remotes/tags/end@3
        '
 
 echo try to try > expect.two
@@ -66,12 +68,13 @@ test_expect_success 'test left-hand-side only globbing' '
                         "branches/*:refs/remotes/two/branches/*" &&
        git config --add svn-remote.two.tags \
                         "tags/*:refs/remotes/two/tags/*" &&
-       cd tmp &&
+       (
+               cd tmp &&
                echo "try try" >> tags/end/src/b/readme &&
                poke tags/end/src/b/readme &&
                svn commit -m "try to try"
-               cd .. &&
-       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` = \
@@ -80,7 +83,29 @@ test_expect_success 'test left-hand-side only globbing' '
             `git rev-parse refs/remotes/two/branches/start` &&
        git log --pretty=oneline refs/remotes/two/tags/end | \
            sed -e "s/^.\{41\}//" > output.two &&
-       cmp expect.two output.two
+       test_cmp expect.two output.two
+       '
+
+echo "Only one set of wildcard directories" \
+     "(e.g. '*' or '*/*/*') is supported: 'branches/*/t/*'" > expect.three
+echo "" >> expect.three
+
+test_expect_success 'test disallow multi-globs' '
+       git config --add svn-remote.three.url "$svnrepo" &&
+       git config --add svn-remote.three.fetch \
+                        trunk:refs/remotes/three/trunk &&
+       git config --add svn-remote.three.branches \
+                        "branches/*/t/*:refs/remotes/three/branches/*" &&
+       git config --add svn-remote.three.tags \
+                        "tags/*/*:refs/remotes/three/tags/*" &&
+       (
+               cd tmp &&
+               echo "try try" >> tags/end/src/b/readme &&
+               poke tags/end/src/b/readme &&
+               svn commit -m "try to try"
+       ) &&
+       test_must_fail git svn fetch three 2> stderr.three &&
+       test_cmp expect.three stderr.three
        '
 
 test_done
diff --git a/t/t9108-git-svn-multi-glob.sh b/t/t9108-git-svn-multi-glob.sh
new file mode 100755 (executable)
index 0000000..8f79c3f
--- /dev/null
@@ -0,0 +1,160 @@
+#!/bin/sh
+# Copyright (c) 2007 Eric Wong
+test_description='git svn globbing refspecs'
+. ./lib-git-svn.sh
+
+cat > expect.end <<EOF
+the end
+hi
+start a new branch
+initial
+EOF
+
+test_expect_success 'test refspec globbing' '
+       mkdir -p trunk/src/a trunk/src/b trunk/doc &&
+       echo "hello world" > trunk/src/a/readme &&
+       echo "goodbye world" > trunk/src/b/readme &&
+       svn import -m "initial" trunk "$svnrepo"/trunk &&
+       svn co "$svnrepo" tmp &&
+       (
+               cd tmp &&
+               mkdir branches branches/v1 tags &&
+               svn add branches tags &&
+               svn cp trunk branches/v1/start &&
+               svn commit -m "start a new branch" &&
+               svn up &&
+               echo "hi" >> branches/v1/start/src/b/readme &&
+               poke branches/v1/start/src/b/readme &&
+               echo "hey" >> branches/v1/start/src/a/readme &&
+               poke branches/v1/start/src/a/readme &&
+               svn commit -m "hi" &&
+               svn up &&
+               svn cp branches/v1/start tags/end &&
+               echo "bye" >> tags/end/src/b/readme &&
+               poke tags/end/src/b/readme &&
+               echo "aye" >> tags/end/src/a/readme &&
+               poke tags/end/src/a/readme &&
+               svn commit -m "the end" &&
+               echo "byebye" >> tags/end/src/b/readme &&
+               poke tags/end/src/b/readme &&
+               svn commit -m "nothing to see here"
+       ) &&
+       git config --add svn-remote.svn.url "$svnrepo" &&
+       git config --add svn-remote.svn.fetch \
+                        "trunk/src/a:refs/remotes/trunk" &&
+       git config --add svn-remote.svn.branches \
+                        "branches/*/*/src/a:refs/remotes/branches/*/*" &&
+       git config --add svn-remote.svn.tags\
+                        "tags/*/src/a:refs/remotes/tags/*" &&
+       git svn multi-fetch &&
+       git log --pretty=oneline refs/remotes/tags/end | \
+           sed -e "s/^.\{41\}//" > output.end &&
+       test_cmp expect.end output.end &&
+       test "`git rev-parse refs/remotes/tags/end~1`" = \
+               "`git rev-parse refs/remotes/branches/v1/start`" &&
+       test "`git rev-parse refs/remotes/branches/v1/start~2`" = \
+               "`git rev-parse refs/remotes/trunk`" &&
+       test_must_fail git rev-parse refs/remotes/tags/end@3
+       '
+
+echo try to try > expect.two
+echo nothing to see here >> expect.two
+cat expect.end >> expect.two
+
+test_expect_success 'test left-hand-side only globbing' '
+       git config --add svn-remote.two.url "$svnrepo" &&
+       git config --add svn-remote.two.fetch trunk:refs/remotes/two/trunk &&
+       git config --add svn-remote.two.branches \
+                        "branches/*/*:refs/remotes/two/branches/*/*" &&
+       git config --add svn-remote.two.tags \
+                        "tags/*:refs/remotes/two/tags/*" &&
+       (
+               cd tmp &&
+               echo "try try" >> tags/end/src/b/readme &&
+               poke tags/end/src/b/readme &&
+               svn commit -m "try to try"
+       ) &&
+       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` = \
+            `git rev-parse refs/remotes/two/trunk` &&
+       test `git rev-parse refs/remotes/two/tags/end~3` = \
+            `git rev-parse refs/remotes/two/branches/v1/start` &&
+       git log --pretty=oneline refs/remotes/two/tags/end | \
+           sed -e "s/^.\{41\}//" > output.two &&
+       test_cmp expect.two output.two
+       '
+cat > expect.four <<EOF
+adios
+adding more
+Changed 2 in v2/start
+Another versioned branch
+initial
+EOF
+
+test_expect_success 'test another branch' '
+       (
+               cd tmp &&
+               mkdir branches/v2 &&
+               svn add branches/v2 &&
+               svn cp trunk branches/v2/start &&
+               svn commit -m "Another versioned branch" &&
+               svn up &&
+               echo "hello" >> branches/v2/start/src/b/readme &&
+               poke branches/v2/start/src/b/readme &&
+               echo "howdy" >> branches/v2/start/src/a/readme &&
+               poke branches/v2/start/src/a/readme &&
+               svn commit -m "Changed 2 in v2/start" &&
+               svn up &&
+               svn cp branches/v2/start tags/next &&
+               echo "bye" >> tags/next/src/b/readme &&
+               poke tags/next/src/b/readme &&
+               echo "aye" >> tags/next/src/a/readme &&
+               poke tags/next/src/a/readme &&
+               svn commit -m "adding more" &&
+               echo "byebye" >> tags/next/src/b/readme &&
+               poke tags/next/src/b/readme &&
+               svn commit -m "adios"
+       ) &&
+       git config --add svn-remote.four.url "$svnrepo" &&
+       git config --add svn-remote.four.fetch trunk:refs/remotes/four/trunk &&
+       git config --add svn-remote.four.branches \
+                        "branches/*/*:refs/remotes/four/branches/*/*" &&
+       git config --add svn-remote.four.tags \
+                        "tags/*:refs/remotes/four/tags/*" &&
+       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` = \
+            `git rev-parse refs/remotes/four/trunk` &&
+       test `git rev-parse refs/remotes/four/tags/next~2` = \
+            `git rev-parse refs/remotes/four/branches/v2/start` &&
+       git log --pretty=oneline refs/remotes/four/tags/next | \
+           sed -e "s/^.\{41\}//" > output.four &&
+       test_cmp expect.four output.four
+       '
+
+echo "Only one set of wildcard directories" \
+     "(e.g. '*' or '*/*/*') is supported: 'branches/*/t/*'" > expect.three
+echo "" >> expect.three
+
+test_expect_success 'test disallow multiple globs' '
+       git config --add svn-remote.three.url "$svnrepo" &&
+       git config --add svn-remote.three.fetch \
+                        trunk:refs/remotes/three/trunk &&
+       git config --add svn-remote.three.branches \
+                        "branches/*/t/*:refs/remotes/three/branches/*/*" &&
+       git config --add svn-remote.three.tags \
+                        "tags/*:refs/remotes/three/tags/*" &&
+       (
+               cd tmp &&
+               echo "try try" >> tags/end/src/b/readme &&
+               poke tags/end/src/b/readme &&
+               svn commit -m "try to try"
+       ) &&
+       test_must_fail git svn fetch three 2> stderr.three &&
+       test_cmp expect.three stderr.three
+       '
+
+test_done
index 04d2a65c087de78fa8126b68774673532497276e..a06e4c5b8e3fa5d5c0c14afede47c630ccb07712 100755 (executable)
@@ -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
index a8d74dcd3aba7c462d46ea33c722d4307d24bded..bd081c2ec39686196e7b2873610df9a6466355b3 100755 (executable)
@@ -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
index d470a920e4864ab0c494da1261fe835ff80474eb..a61d6716d294a460c195ca36d33a9bed17aa5e33 100755 (executable)
@@ -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
index 8da8ce58eb1b29210a6ac95fdd3a3fcb547ca36f..250c53022b6a217890593ecb95c86e81ac61c669 100755 (executable)
@@ -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
 
@@ -28,6 +28,7 @@ start_svnserve () {
 
 test_expect_success 'start tracking an empty repo' '
        svn mkdir -m "empty dir" "$svnrepo"/empty-dir &&
+       echo "[general]" > "$rawsvnrepo"/conf/svnserve.conf &&
        echo anon-access = write >> "$rawsvnrepo"/conf/svnserve.conf &&
        start_svnserve &&
        git svn init svn://127.0.0.1:$SVNSERVE_PORT &&
index 61d7781616eed4374c014cabd75a297c2baa348d..17b2855c4f308d463ea239f355549120dab4f80f 100755 (executable)
@@ -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
 
index f0fbd3aff7e63f64f8ba388db805013c43b4b22c..9be7aefaeea0af4d988ca656b3df0008f04a58d3 100755 (executable)
@@ -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 &&
index 4b2cc878f685e65b2ccd5d8153efb533320d6ee9..fd6d1d20463f2a4de1bd8ed739c0e977921e037c 100755 (executable)
@@ -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 &&
index 7a689bb1cd1d9daa1f17c0dcaaafa4d68ebd78fa..dde46cd92fba24221393b15233ed248997161caf 100755 (executable)
@@ -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
 
index 3281cbd3472a8da58c4f6f0f3965b5810705b0e9..7a7c12868758d6e3bd9d1f8ec4fe32c0663115f4 100755 (executable)
@@ -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
index cc619115931cb74a85a171ade915ca2c47639c9b..27dd7c273a4a1ae77a8e48b2e4b4ce1a3ae19a56 100755 (executable)
@@ -2,23 +2,41 @@
 #
 # Copyright (c) 2007 David D. Kilzer
 
-test_description='git-svn info'
+test_description='git svn info'
 
 . ./lib-git-svn.sh
-say 'skipping svn-info test (has a race undiagnosed yet)'
-test_done
+
+# Tested with: svn, version 1.4.4 (r25188)
+v=`svn --version | sed -n -e 's/^svn, version \(1\.[0-9]*\.[0-9]*\).*$/\1/p'`
+case $v in
+1.[45].*)
+       ;;
+*)
+       say "skipping svn-info test (SVN version: $v not supported)"
+       test_done
+       ;;
+esac
 
 ptouch() {
        perl -w -e '
                use strict;
+               use POSIX qw(mktime);
                die "ptouch requires exactly 2 arguments" if @ARGV != 2;
-               die "$ARGV[0] does not exist" if ! -e $ARGV[0];
-               my @s = stat $ARGV[0];
-               utime $s[8], $s[9], $ARGV[1];
-       ' "$1" "$2"
+               my $text_last_updated = shift @ARGV;
+               my $git_file = shift @ARGV;
+               die "\"$git_file\" does not exist" if ! -e $git_file;
+               if ($text_last_updated
+                   =~ /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/) {
+                       my $mtime = mktime($6, $5, $4, $3, $2 - 1, $1 - 1900);
+                       my $atime = $mtime;
+                       utime $atime, $mtime, $git_file;
+               }
+       ' "`svn info $2 | grep '^Text Last Updated:'`" "$1"
 }
 
-test_expect_success 'setup repository and import' "
+quoted_svnrepo="$(echo $svnrepo | sed 's/ /%20/')"
+
+test_expect_success 'setup repository and import' '
        mkdir info &&
        cd info &&
                echo FIRST > A &&
@@ -27,82 +45,94 @@ test_expect_success 'setup repository and import' "
                mkdir directory &&
                touch directory/.placeholder &&
                ln -s directory symlink-directory &&
-               svn import -m 'initial' . $svnrepo &&
+               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' "
@@ -116,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' "
@@ -137,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' "
@@ -159,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' "
@@ -182,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
@@ -208,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' "
@@ -229,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' "
@@ -250,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' "
@@ -272,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,
@@ -289,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
index 5979e133b9d5b9d85ddca31a40763ed4fb6feba3..ef2c0523cd4566b3d1c4925ba608efc16524546a 100755 (executable)
@@ -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
index 99230b08107102836f752c14e1b0a67804b35ea3..000cad37c63d4d14756deab92a486e96612bce5d 100755 (executable)
@@ -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' '
index 1190576a658d08a680e177b748cfc5e69caa3ddb..1b1cf47281d10c64ac57e96701c727f19f189948 100755 (executable)
@@ -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 &&
index c18878fad16a6565fe846cc958417fea73289dce..cf0415274c2d2abae7a6850818f4de8063cb61a7 100755 (executable)
@@ -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' '
index 8223c5909e6ff6936cb0ccf4d0badfe43491af46..263dbf5fc276ffa052096810f59565a851245b7f 100755 (executable)
@@ -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
new file mode 100755 (executable)
index 0000000..475c751
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Copyright (c) 2008 Marcus Griep
+
+test_description='git svn multi-glob branch names'
+. ./lib-git-svn.sh
+
+test_expect_success 'setup svnrepo' '
+       mkdir project project/trunk project/branches \
+                       project/branches/v14.1 project/tags &&
+       echo foo > project/trunk/foo &&
+       svn import -m "$test_description" project "$svnrepo/project" &&
+       rm -rf project &&
+       svn cp -m "fun" "$svnrepo/project/trunk" \
+                       "$svnrepo/project/branches/v14.1/beta" &&
+       svn cp -m "more fun!" "$svnrepo/project/branches/v14.1/beta" \
+                             "$svnrepo/project/branches/v14.1/gold"
+       '
+
+test_expect_success 'test clone with multi-glob in branch names' '
+       git svn clone -T trunk -b branches/*/* -t tags \
+                     "$svnrepo/project" project &&
+       cd project &&
+               git rev-parse "refs/remotes/v14.1/beta" &&
+               git rev-parse "refs/remotes/v14.1/gold" &&
+       cd ..
+       '
+
+test_expect_success 'test dcommit to multi-globbed branch' "
+       cd project &&
+       git reset --hard 'refs/remotes/v14.1/gold' &&
+       echo hello >> foo &&
+       git commit -m 'hello' -- foo &&
+       git svn dcommit &&
+       cd ..
+       "
+
+test_done
index 3e32e84e6cd32413f98b5189f869bfb8f0a7f354..245a7c36628e955e04852a8c2beb75b8deaf4d7f 100755 (executable)
@@ -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
       )'
index 1fc06c5a23b50d54c33755a9fce4ddd9ed3b9c79..328444a3068f5083e3d64e92e88660c724acffdc 100755 (executable)
@@ -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' '
-    ! 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' '
-    ! git-fast-import <input'
+    test_must_fail git fast-import <input'
 
 test_done
index c19b4a2bab586b21da43c7a838ba85626f913568..6ddd7c19fd22d0092829b861900fe462c5ffe73f 100755 (executable)
@@ -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 &&
index 4b91f8d4c45dad075d69028c9c70aa9cb1959e2b..c1850d29239f8846c42b4552493d2d4898fa221e 100755 (executable)
@@ -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
index ae7082be1d903e1f4d5758610d5166152f2847cc..46ba19be7da754ffa14321eabac9ba0a985e6d94 100755 (executable)
@@ -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'
index 0d7786a8c730d17fa194346f1da2978d23256da9..d2379e7f62a4da76791e65dbc2c70f4dfe14ff3b 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='git-cvsimport basic tests'
+test_description='git cvsimport basic tests'
 . ./test-lib.sh
 
 CVSROOT=$(pwd)/cvsroot
index 9706ee5773692bd8fcfbc9015ef062947c0a2da5..b81d5dfc340e050815ad9b2fd0d0636c529ce8d3 100755 (executable)
@@ -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
index 4d2312548a81762918ac05b9a0014195b08ea532..697daf3ffd33c27654ce00f780acc2c6db5f9985 100755 (executable)
@@ -9,15 +9,11 @@
 
 use Cwd;
 use File::Basename;
-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
@@ -38,7 +34,7 @@
 # Failure cases for config:
 # Save and restore STDERR; we will probably extract this into a
 # "dies_ok" method and possibly move the STDERR handling to Git.pm.
-open our $tmpstderr, ">&", STDERR or die "cannot save STDERR"; close STDERR;
+open our $tmpstderr, ">&STDERR" or die "cannot save STDERR"; close STDERR;
 eval { $r->config("test.dupstring") };
 ok($@, "config: duplicate entry in scalar context fails");
 eval { $r->config_bool("test.boolother") };
 
 # objects and hashes
 ok(our $file1hash = $r->command_oneline('rev-parse', "HEAD:file1"), "(get file hash)");
-our $tmpfile = File::Temp->new;
-is($r->cat_blob($file1hash, $tmpfile), 15, "cat_blob: size");
+my $tmpfile = "file.tmp";
+open TEMPFILE, "+>$tmpfile" or die "Can't open $tmpfile: $!";
+is($r->cat_blob($file1hash, \*TEMPFILE), 15, "cat_blob: size");
 our $blobcontents;
-{ local $/; seek $tmpfile, 0, 0; $blobcontents = <$tmpfile>; }
+{ local $/; seek TEMPFILE, 0, 0; $blobcontents = <TEMPFILE>; }
 is($blobcontents, "changed file 1\n", "cat_blob: data");
-seek $tmpfile, 0, 0;
+close TEMPFILE or die "Failed writing to $tmpfile: $!";
 is(Git::hash_object("blob", $tmpfile), $file1hash, "hash_object: roundtrip");
-$tmpfile = File::Temp->new();
-print $tmpfile my $test_text = "test blob, to be inserted\n";
+open TEMPFILE, ">$tmpfile" or die "Can't open $tmpfile: $!";
+print TEMPFILE my $test_text = "test blob, to be inserted\n";
+close TEMPFILE or die "Failed writing to $tmpfile: $!";
 like(our $newhash = $r->hash_and_insert_object($tmpfile), qr/[0-9a-fA-F]{40}/,
      "hash_and_insert_object: returns hash");
-$tmpfile = File::Temp->new;
-is($r->cat_blob($newhash, $tmpfile), length $test_text, "cat_blob: roundtrip size");
-{ local $/; seek $tmpfile, 0, 0; $blobcontents = <$tmpfile>; }
+open TEMPFILE, "+>$tmpfile" or die "Can't open $tmpfile: $!";
+is($r->cat_blob($newhash, \*TEMPFILE), length $test_text, "cat_blob: roundtrip size");
+{ local $/; seek TEMPFILE, 0, 0; $blobcontents = <TEMPFILE>; }
 is($blobcontents, $test_text, "cat_blob: roundtrip data");
+close TEMPFILE;
+unlink $tmpfile;
 
 # paths
 is($r->repo_path, "./.git", "repo_path");
index 11c027571b44c429b4f6fdca88bff9c3360c7545..e2b106cb6a2337f873a7225670392b376f74c6e7 100644 (file)
@@ -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"
index 9f3f1fc352dea624bd36e55802de190ead0ad9dd..a12c6e214e65d39136b1ed41a8ff0ea25e28f91b 100644 (file)
@@ -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 >$@
 
@@ -48,4 +50,4 @@ clean:
 install: all
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(template_instdir_SQ)'
        (cd blt && $(TAR) cf - .) | \
-       (cd '$(DESTDIR_SQ)$(template_instdir_SQ)' && umask 022 && $(TAR) xf -)
+       (cd '$(DESTDIR_SQ)$(template_instdir_SQ)' && umask 022 && $(TAR) xfo -)
index 6e18083a7d1655e9eabef197c58d92a910d2f67b..61d2c39814529bd0264e4c9e40241131d51d819c 100644 (file)
@@ -15,7 +15,7 @@ int length_callback(const struct option *opt, const char *arg, int unset)
        if (unset)
                return 1; /* do not support unset */
 
-       *(unsigned long *)opt->value = strlen(arg);
+       *(int *)opt->value = strlen(arg);
        return 0;
 }
 
index 6eb65b873afc9dfd457e974b63d88350bb8dc913..71433d99978ddcc53c80fd6de4aee98871c6d8cf 100644 (file)
@@ -463,17 +463,14 @@ static struct ref *get_refs_via_curl(struct transport *transport)
                run_active_slot(slot);
                if (results.curl_result != CURLE_OK) {
                        strbuf_release(&buffer);
-                       if (missing_target(&results)) {
-                               return NULL;
-                       } else {
-                               error("%s", curl_errorstr);
-                               return NULL;
-                       }
+                       if (missing_target(&results))
+                               die("%s not found: did you run git update-server-info on the server?", refs_url);
+                       else
+                               die("%s download error - %s", refs_url, curl_errorstr);
                }
        } else {
                strbuf_release(&buffer);
-               error("Unable to start request");
-               return NULL;
+               die("Unable to start HTTP request");
        }
 
        data = buffer.buf;
index bbb126fc46cfb28a0bc92cc0842c0dc72017751d..9f67af6c1fbb9130962cd373d8e2ebecf543c640 100644 (file)
@@ -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;
 }
index cba0aca062f201c5cd5f8799f2190d4a6f06e7c7..e59d144d28164f2451784513105f6269f0e9167c 100644 (file)
@@ -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;
@@ -940,8 +941,17 @@ int twoway_merge(struct cache_entry **src, struct unpack_trees_options *o)
                        return -1;
                }
        }
-       else if (newtree)
+       else if (newtree) {
+               if (oldtree && !o->initial_checkout) {
+                       /*
+                        * deletion of the path was staged;
+                        */
+                       if (same(oldtree, newtree))
+                               return 1;
+                       return reject_merge(oldtree, o);
+               }
                return merged_entry(newtree, current, o);
+       }
        return deleted_entry(oldtree, current, o);
 }
 
index 94e567265af9a69a30dd5c578439b6444e50004d..0d26f3d73e773230972db86f34a5147ada881e8b 100644 (file)
@@ -26,6 +26,7 @@ struct unpack_trees_options {
                     verbose_update:1,
                     aggressive:1,
                     skip_unmerged:1,
+                    initial_checkout:1,
                     gently:1;
        const char *prefix;
        int pos;
index c911e70c9aa47b70dac41b7f4de2f0b4b6c1f948..e5adbc011e0ab71eeb06a42c4bd40cbea0bf3fa2 100644 (file)
@@ -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,
index 61dc5c547019776b971dc89d009f628bbac134fd..944ad9887f5c94ca0e63f9a6c901447634f871ce 100644 (file)
@@ -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;
index f7f791d96b9a34ef0f08db4b007c5309b9adc3d6..558492ba38c50351a98f80c16e83a058ace849ab 100644 (file)
@@ -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);