Code

Merge branch 'maint'
authorJunio C Hamano <gitster@pobox.com>
Mon, 9 Jul 2007 01:28:31 +0000 (18:28 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 9 Jul 2007 01:28:31 +0000 (18:28 -0700)
* maint:
  user-manual: fix directory name in git-archive example
  user-manual: more explanation of push and pull usage
  tutorial: Fix typo
  user-manual: grammar and style fixes

527 files changed:
.gitignore
.mailmap
Documentation/Makefile
Documentation/RelNotes-1.5.0.4.txt
Documentation/RelNotes-1.5.0.5.txt
Documentation/RelNotes-1.5.0.6.txt
Documentation/RelNotes-1.5.1.3.txt
Documentation/RelNotes-1.5.3.txt [new file with mode: 0644]
Documentation/SubmittingPatches
Documentation/asciidoc.conf
Documentation/cmd-list.perl
Documentation/config.txt
Documentation/core-intro.txt
Documentation/core-tutorial.txt
Documentation/diff-format.txt
Documentation/diff-options.txt
Documentation/diffcore.txt
Documentation/docbook-xsl.css
Documentation/fetch-options.txt
Documentation/git-add.txt
Documentation/git-am.txt
Documentation/git-apply.txt
Documentation/git-applymbox.txt [deleted file]
Documentation/git-applypatch.txt [deleted file]
Documentation/git-archimport.txt
Documentation/git-bisect.txt
Documentation/git-blame.txt
Documentation/git-branch.txt
Documentation/git-cat-file.txt
Documentation/git-check-attr.txt
Documentation/git-checkout-index.txt
Documentation/git-checkout.txt
Documentation/git-cherry-pick.txt
Documentation/git-cherry.txt
Documentation/git-citool.txt [new file with mode: 0644]
Documentation/git-clone.txt
Documentation/git-commit-tree.txt
Documentation/git-config.txt
Documentation/git-convert-objects.txt
Documentation/git-count-objects.txt
Documentation/git-cvsexportcommit.txt
Documentation/git-cvsimport.txt
Documentation/git-cvsserver.txt
Documentation/git-daemon.txt
Documentation/git-describe.txt
Documentation/git-diff-files.txt
Documentation/git-diff-index.txt
Documentation/git-diff-tree.txt
Documentation/git-diff.txt
Documentation/git-fast-import.txt
Documentation/git-fetch.txt
Documentation/git-filter-branch.txt [new file with mode: 0644]
Documentation/git-fmt-merge-msg.txt
Documentation/git-format-patch.txt
Documentation/git-fsck.txt
Documentation/git-gc.txt
Documentation/git-get-tar-commit-id.txt
Documentation/git-grep.txt
Documentation/git-gui.txt [new file with mode: 0644]
Documentation/git-hash-object.txt
Documentation/git-http-fetch.txt
Documentation/git-http-push.txt
Documentation/git-index-pack.txt
Documentation/git-init-db.txt
Documentation/git-init.txt
Documentation/git-instaweb.txt
Documentation/git-local-fetch.txt
Documentation/git-log.txt
Documentation/git-ls-files.txt
Documentation/git-ls-remote.txt
Documentation/git-ls-tree.txt
Documentation/git-mailinfo.txt
Documentation/git-mailsplit.txt
Documentation/git-merge-base.txt
Documentation/git-merge-index.txt
Documentation/git-merge-one-file.txt
Documentation/git-merge-tree.txt
Documentation/git-merge.txt
Documentation/git-mergetool.txt
Documentation/git-mktag.txt
Documentation/git-mktree.txt
Documentation/git-mv.txt
Documentation/git-name-rev.txt
Documentation/git-p4import.txt
Documentation/git-pack-objects.txt
Documentation/git-pack-redundant.txt
Documentation/git-patch-id.txt
Documentation/git-peek-remote.txt
Documentation/git-prune-packed.txt
Documentation/git-prune.txt
Documentation/git-pull.txt
Documentation/git-push.txt
Documentation/git-quiltimport.txt
Documentation/git-read-tree.txt
Documentation/git-rebase.txt
Documentation/git-receive-pack.txt
Documentation/git-reflog.txt
Documentation/git-relink.txt
Documentation/git-remote.txt
Documentation/git-repack.txt
Documentation/git-request-pull.txt
Documentation/git-rerere.txt
Documentation/git-rev-list.txt
Documentation/git-rev-parse.txt
Documentation/git-revert.txt
Documentation/git-rm.txt
Documentation/git-runstatus.txt
Documentation/git-send-email.txt
Documentation/git-sh-setup.txt
Documentation/git-shell.txt
Documentation/git-shortlog.txt
Documentation/git-show-index.txt
Documentation/git-show.txt
Documentation/git-ssh-fetch.txt
Documentation/git-ssh-upload.txt
Documentation/git-stash.txt [new file with mode: 0644]
Documentation/git-status.txt
Documentation/git-stripspace.txt
Documentation/git-submodule.txt [new file with mode: 0644]
Documentation/git-svn.txt
Documentation/git-svnimport.txt
Documentation/git-tag.txt
Documentation/git-tar-tree.txt
Documentation/git-unpack-file.txt
Documentation/git-unpack-objects.txt
Documentation/git-update-index.txt
Documentation/git-update-ref.txt
Documentation/git-update-server-info.txt
Documentation/git-var.txt
Documentation/git-verify-pack.txt
Documentation/git-verify-tag.txt
Documentation/git-whatchanged.txt
Documentation/git-write-tree.txt
Documentation/git.txt
Documentation/gitk.txt
Documentation/gitmodules.txt [new file with mode: 0644]
Documentation/hooks.txt
Documentation/howto/rebase-and-edit.txt
Documentation/howto/rebase-from-internal-branch.txt
Documentation/howto/rebuild-from-update-hook.txt
Documentation/howto/revert-branch-rebase.txt
Documentation/howto/separating-topic-branches.txt
Documentation/howto/use-git-daemon.txt
Documentation/install-doc-quick.sh
Documentation/merge-options.txt
Documentation/pretty-formats.txt
Documentation/pretty-options.txt
Documentation/pull-fetch-param.txt
Documentation/repository-layout.txt
Documentation/technical/pack-format.txt
Documentation/tutorial.txt
Documentation/urls-remotes.txt [new file with mode: 0644]
Documentation/urls.txt
Documentation/user-manual.txt
GIT-VERSION-GEN
INSTALL
Makefile
RelNotes
archive-tar.c
archive-zip.c
arm/sha1.c
arm/sha1_arm.S
builtin-add.c
builtin-annotate.c
builtin-apply.c
builtin-archive.c
builtin-blame.c
builtin-branch.c
builtin-config.c
builtin-count-objects.c
builtin-describe.c
builtin-diff-index.c
builtin-fetch--tool.c
builtin-fmt-merge-msg.c
builtin-fsck.c
builtin-gc.c
builtin-init-db.c
builtin-log.c
builtin-ls-files.c
builtin-ls-tree.c
builtin-mailinfo.c
builtin-mailsplit.c
builtin-merge-file.c
builtin-name-rev.c
builtin-pack-objects.c
builtin-pack-refs.c
builtin-push.c
builtin-read-tree.c
builtin-reflog.c
builtin-rerere.c
builtin-rev-list.c
builtin-rev-parse.c
builtin-revert.c
builtin-shortlog.c
builtin-show-branch.c
builtin-stripspace.c
builtin-update-index.c
builtin-update-ref.c
builtin.h
cache-tree.c
cache.h
combine-diff.c
commit.c
commit.h
compat/mmap.c
config.c
config.mak.in
connect.c
contrib/README
contrib/blameview/README
contrib/completion/git-completion.bash
contrib/emacs/git.el
contrib/examples/git-gc.sh
contrib/examples/git-resolve.sh
contrib/fast-import/git-p4 [new file with mode: 0755]
contrib/fast-import/git-p4.bat [new file with mode: 0644]
contrib/fast-import/git-p4.txt [new file with mode: 0644]
contrib/gitview/gitview
contrib/hooks/post-receive-email
contrib/remotes2config.sh
contrib/workdir/git-new-workdir
convert-objects.c
copy.c
csum-file.c
csum-file.h
ctype.c
daemon.c
date.c
diff-delta.c
diff-lib.c
diff.c
diff.h
diffcore-break.c
diffcore-delta.c
diffcore-pickaxe.c
diffcore-rename.c
diffcore.h
dir.c
dir.h
entry.c
environment.c
fast-import.c
fetch-pack.c
fetch.c
fixup-builtins [new file with mode: 0755]
generate-cmdlist.sh
git-am.sh
git-applymbox.sh [deleted file]
git-applypatch.sh [deleted file]
git-archimport.perl
git-bisect.sh
git-checkout.sh
git-clean.sh
git-clone.sh
git-commit.sh
git-compat-util.h
git-cvsexportcommit.perl
git-cvsimport.perl
git-cvsserver.perl
git-fetch.sh
git-filter-branch.sh [new file with mode: 0755]
git-gui/GIT-VERSION-GEN
git-gui/Makefile
git-gui/git-gui.sh
git-gui/lib/branch_rename.tcl [new file with mode: 0644]
git-gui/lib/option.tcl
git-gui/lib/remote.tcl
git-gui/lib/remote_branch_delete.tcl [new file with mode: 0644]
git-gui/lib/transport.tcl
git-lost-found.sh
git-ls-remote.sh
git-merge-octopus.sh
git-merge-one-file.sh
git-merge-ours.sh
git-merge-resolve.sh
git-merge-stupid.sh
git-merge.sh
git-mergetool.sh
git-p4import.py
git-parse-remote.sh
git-pull.sh
git-quiltimport.sh
git-rebase--interactive.sh [new file with mode: 0755]
git-rebase.sh
git-remote.perl
git-repack.sh
git-request-pull.sh
git-reset.sh
git-send-email.perl
git-sh-setup.sh
git-stash.sh [new file with mode: 0755]
git-submodule.sh [new file with mode: 0755]
git-svn.perl
git-svnimport.perl
git-tag.sh
git-verify-tag.sh
git.c
git.spec.in
gitk
gitweb/README
gitweb/gitweb.css
gitweb/gitweb.perl
help.c
http-fetch.c
http-push.c
http.c
ident.c
imap-send.c
index-pack.c
interpolate.c
interpolate.h
list-objects.c
local-fetch.c
lockfile.c
log-tree.c
mailmap.c
match-trees.c
merge-file.c
merge-index.c
merge-recursive.c
merge-tree.c
mktag.c
mozilla-sha1/sha1.c
mozilla-sha1/sha1.h
object-refs.c
object.h
pack-check.c
pack-redundant.c
pack-write.c
pack.h
pager.c
patch-id.c
path-list.c
path.c
peek-remote.c
perl/Makefile
pkt-line.c
ppc/sha1.c
progress.c
progress.h
quote.c
quote.h
reachable.c
read-cache.c
receive-pack.c
refs.c
refs.h
remote.c [new file with mode: 0644]
remote.h [new file with mode: 0644]
revision.c
revision.h
rsh.h
run-command.c
run-command.h
send-pack.c
setup.c
sha1_file.c
sha1_name.c
shallow.c
ssh-upload.c
strbuf.c
t/Makefile
t/lib-read-tree-m-3way.sh
t/t0000-basic.sh
t/t0022-crlf-rename.sh [new file with mode: 0755]
t/t0030-stripspace.sh [new file with mode: 0755]
t/t1000-read-tree-m-3way.sh
t/t1001-read-tree-m-2way.sh
t/t1002-read-tree-m-u-2way.sh
t/t1003-read-tree-prefix.sh
t/t1004-read-tree-m-u-wf.sh
t/t1020-subdirectory.sh
t/t1100-commit-tree-options.sh
t/t1200-tutorial.sh
t/t1300-repo-config.sh
t/t1400-update-ref.sh
t/t1420-lost-found.sh [new file with mode: 0755]
t/t1500-rev-parse.sh [new file with mode: 0755]
t/t1501-worktree.sh [new file with mode: 0755]
t/t2000-checkout-cache-clash.sh
t/t2001-checkout-cache-clash.sh
t/t2002-checkout-cache-u.sh
t/t2003-checkout-cache-mkdir.sh
t/t2004-checkout-cache-temp.sh
t/t2005-checkout-index-symlinks.sh
t/t2100-update-cache-badpath.sh
t/t2101-update-index-reupdate.sh
t/t2102-update-index-symlinks.sh
t/t2200-add-update.sh
t/t3000-ls-files-others.sh
t/t3001-ls-files-others-exclude.sh
t/t3002-ls-files-dashpath.sh
t/t3010-ls-files-killed-modified.sh
t/t3020-ls-files-error-unmatch.sh
t/t3030-merge-recursive.sh
t/t3100-ls-tree-restrict.sh
t/t3101-ls-tree-dirname.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 [new file with mode: 0755]
t/t3500-cherry.sh
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 [new file with mode: 0755]
t/t3903-stash.sh [new file with mode: 0755]
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/t4006-diff-mode.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/t4013/diff.config_format.subjectprefix_DIFFERENT_PREFIX [new file with mode: 0644]
t/t4013/diff.format-patch_--inline_--stdout_initial..master^^ [new file with mode: 0644]
t/t4015-diff-whitespace.sh
t/t4018-diff-funcname.sh [new file with mode: 0644]
t/t4020-diff-external.sh
t/t4100-apply-stat.sh
t/t4101-apply-nonl.sh
t/t4102-apply-rename.sh
t/t4103-apply-binary.sh
t/t4104-apply-boundary.sh
t/t4109-apply-multifrag.sh
t/t4110-apply-scan.sh
t/t4112-apply-renames.sh
t/t4113-apply-ending.sh
t/t4114-apply-typechange.sh
t/t4115-apply-symlink.sh
t/t4116-apply-reverse.sh
t/t4117-apply-reject.sh
t/t4118-apply-empty-context.sh
t/t4119-apply-config.sh
t/t4120-apply-popt.sh
t/t4121-apply-diffs.sh
t/t4122-apply-symlink-inside.sh
t/t4200-rerere.sh
t/t4201-shortlog.sh
t/t5000-tar-tree.sh
t/t5100-mailinfo.sh
t/t5300-pack-object.sh
t/t5301-sliding-window.sh
t/t5302-pack-index.sh
t/t5400-send-pack.sh
t/t5401-update-hooks.sh
t/t5500-fetch-pack.sh
t/t5516-fetch-push.sh [new file with mode: 0755]
t/t5520-pull.sh
t/t5710-info-alternate.sh
t/t6000lib.sh
t/t6002-rev-list-bisect.sh
t/t6003-rev-list-topo-order.sh
t/t6004-rev-list-path-optim.sh
t/t6005-rev-list-count.sh
t/t6006-rev-list-format.sh
t/t6010-merge-base.sh
t/t6021-merge-criss-cross.sh
t/t6023-merge-file.sh
t/t6024-recursive-merge.sh
t/t6025-merge-symlinks.sh
t/t6030-bisect-porcelain.sh
t/t6101-rev-parse-parents.sh
t/t6120-describe.sh
t/t7001-mv.sh
t/t7003-filter-branch.sh [new file with mode: 0755]
t/t7004-tag.sh [new file with mode: 0755]
t/t7004/pubring.gpg [new file with mode: 0644]
t/t7004/random_seed [new file with mode: 0644]
t/t7004/secring.gpg [new file with mode: 0644]
t/t7004/trustdb.gpg [new file with mode: 0644]
t/t7101-reset.sh
t/t7300-clean.sh
t/t7400-submodule-basic.sh [new file with mode: 0755]
t/t8001-annotate.sh
t/t8002-blame.sh
t/t9100-git-svn-basic.sh
t/t9104-git-svn-follow-parent.sh
t/t9107-git-svn-migrate.sh
t/t9110-git-svn-use-svm-props.sh
t/t9111-git-svn-use-svnsync-props.sh
t/t9111/svnsync.dump
t/t9113-git-svn-dcommit-new-file.sh [new file with mode: 0755]
t/t9114-git-svn-dcommit-merge.sh [new file with mode: 0755]
t/t9300-fast-import.sh
t/t9400-git-cvsserver-server.sh
t/t9500-gitweb-standalone-no-errors.sh [new file with mode: 0755]
t/test-lib.sh
templates/Makefile
templates/hooks--commit-msg
templates/hooks--post-receive
templates/hooks--pre-applypatch
templates/hooks--pre-commit
tree-diff.c
tree-walk.c
tree-walk.h
tree.c
upload-pack.c
var.c
write_or_die.c
wt-status.c
xdiff-interface.c
xdiff-interface.h
xdiff/xdiff.h
xdiff/xdiffi.c
xdiff/xdiffi.h
xdiff/xemit.c
xdiff/xemit.h
xdiff/xinclude.h
xdiff/xmacros.h
xdiff/xprepare.c
xdiff/xprepare.h
xdiff/xtypes.h
xdiff/xutils.c
xdiff/xutils.h

index b7546a5591c7e70f8b0b87f528215cbfdf878da1..20ee642420a82d71a5ed7df6194de87f436bc6de 100644 (file)
@@ -7,8 +7,6 @@ git-add--interactive
 git-am
 git-annotate
 git-apply
-git-applymbox
-git-applypatch
 git-archimport
 git-archive
 git-bisect
@@ -42,6 +40,7 @@ git-fast-import
 git-fetch
 git-fetch--tool
 git-fetch-pack
+git-filter-branch
 git-findtags
 git-fmt-merge-msg
 git-for-each-ref
@@ -97,6 +96,7 @@ git-push
 git-quiltimport
 git-read-tree
 git-rebase
+git-rebase--interactive
 git-receive-pack
 git-reflog
 git-relink
@@ -124,8 +124,10 @@ git-ssh-fetch
 git-ssh-pull
 git-ssh-push
 git-ssh-upload
+git-stash
 git-status
 git-stripspace
+git-submodule
 git-svn
 git-svnimport
 git-symbolic-ref
@@ -152,13 +154,14 @@ test-delta
 test-dump-cache-tree
 test-genrandom
 test-match-trees
+test-sha1
 common-cmds.h
 *.tar.gz
 *.dsc
 *.deb
 git.spec
 *.exe
-*.[ao]
+*.[aos]
 *.py[co]
 config.mak
 autom4te.cache
index 4e0615e9beb06928e9440e3dd60014cc265f9ee5..71ec16acca945eb5c01d4b83c0986214d64a44ff 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -7,6 +7,8 @@
 
 Aneesh Kumar K.V <aneesh.kumar@gmail.com>
 Chris Shoemaker <c.shoemaker@cox.net>
+Dana L. How <danahow@gmail.com>
+Dana L. How <how@deathvalley.cswitch.com>
 Daniel Barkalow <barkalow@iabervon.org>
 David Kågedal <davidk@lysator.liu.se>
 Fredrik Kuivinen <freku045@student.liu.se>
@@ -19,11 +21,12 @@ Jon Loeliger <jdl@freescale.com>
 Jon Seymour <jon@blackcubes.dyndns.org>
 Karl Hasselström <kha@treskal.com>
 Kent Engstrom <kent@lysator.liu.se>
-Lars Doelle <lars.doelle@on-line.de>
 Lars Doelle <lars.doelle@on-line ! de>
+Lars Doelle <lars.doelle@on-line.de>
 Lukas Sandström <lukass@etek.chalmers.se>
 Martin Langhoff <martin@catalyst.net.nz>
 Michele Ballabio <barra_cuda@katamail.com>
+Nanako Shiraishi <nanako3@bluebottle.com>
 Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
 Ramsay Allan Jones <ramsay@ramsay1.demon.co.uk>
 René Scharfe <rene.scharfe@lsrfire.ath.cx>
@@ -34,12 +37,11 @@ Sean Estabrooks <seanlkml@sympatico.ca>
 Shawn O. Pearce <spearce@spearce.org>
 Theodore Ts'o <tytso@mit.edu>
 Tony Luck <tony.luck@intel.com>
-Uwe Kleine-König <zeisberg@informatik.uni-freiburg.de>
 Uwe Kleine-König <Uwe_Zeisberger@digi.com>
-Uwe Kleine-König <uzeisberger@io.fsforth.de>
 Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de>
+Uwe Kleine-König <uzeisberger@io.fsforth.de>
+Uwe Kleine-König <zeisberg@informatik.uni-freiburg.de>
 Ville Skyttä <scop@xemacs.org>
 YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
 anonymous <linux@horizon.com>
 anonymous <linux@horizon.net>
-Dana L. How <how@deathvalley.cswitch.com>
index 4edf788c3a8ddf39638028447ca78624305da778..f3a6c733b662f4e9d06bc69cadc2201ea34f41ce 100644 (file)
@@ -2,7 +2,7 @@ MAN1_TXT= \
        $(filter-out $(addsuffix .txt, $(ARTICLES) $(SP_ARTICLES)), \
                $(wildcard git-*.txt)) \
        gitk.txt
-MAN5_TXT=gitattributes.txt gitignore.txt
+MAN5_TXT=gitattributes.txt gitignore.txt gitmodules.txt
 MAN7_TXT=git.txt
 
 DOC_HTML=$(patsubst %.txt,%.html,$(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT))
@@ -29,7 +29,7 @@ DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT))
 
 prefix?=$(HOME)
 bindir?=$(prefix)/bin
-mandir?=$(prefix)/man
+mandir?=$(prefix)/share/man
 man1dir=$(mandir)/man1
 man5dir=$(mandir)/man5
 man7dir=$(mandir)/man7
index b727a8d1e57cf8fb5a6c591a5f35ceddbbd3f6af..feefa5dfd4eee5f493fcf3091ec0de116d414fc1 100644 (file)
@@ -20,5 +20,3 @@ Fixes since v1.5.0.3
 * Documentation updates
 
 * User manual updates
-
-
index aa86149d4f3649721f206b94c26854ce30dfc101..eeec3d73d01a0e9f61df666bad8a48a4f423438a 100644 (file)
@@ -24,5 +24,3 @@ Fixes since v1.5.0.3
 * Documentation updates
 
 * User manual updates
-
-
index e15447ffdba41ec082e249b13bc31248b6d2dbbe..c02015ad5fdb1953ad1a8cf5b0edd7ef7c04fbac 100644 (file)
@@ -19,4 +19,3 @@ Fixes since v1.5.0.5
   - user-manual has better cross references.
 
   - gitweb installation/deployment procedure is now documented.
-
index 2ddeabd0296848eeb6344b5487f85e9c484eaf0a..876408b65a0e0841567a2c9b97c6f6e62cb86b81 100644 (file)
@@ -43,4 +43,3 @@ Fixes since v1.5.1.2
     description was given by the caller.
 
 Also contains various documentation updates.
-
diff --git a/Documentation/RelNotes-1.5.3.txt b/Documentation/RelNotes-1.5.3.txt
new file mode 100644 (file)
index 0000000..e2e809e
--- /dev/null
@@ -0,0 +1,215 @@
+GIT v1.5.3 Release Notes
+========================
+
+Updates since v1.5.2
+--------------------
+
+* The commit walkers other than http are officially deprecated,
+  but still supported for now.
+
+* The submodule support has Porcelain layer.
+
+* There are a handful pack-objects changes to help you cope better
+  with repositories with pathologically large blobs in them.
+
+* For people who need to import from Perforce, a front-end for
+  fast-import is in contrib/fast-import/.
+
+* Comes with git-gui 0.8.0.
+
+* Comes with updated gitk.
+
+* New commands and options.
+
+  - "git stash" allows you to quickly save away your work in
+    progress and replay it later on an updated state.
+
+  - "git rebase" learned an "interactive" mode that let you
+    pick and reorder which commits to rebuild.
+
+  - "git fsck" can save its findings in $GIT_DIR/lost-found,
+    without a separate invocation of "git lost-found" command.
+
+  - $GIT_WORK_TREE environment variable can be used together with
+    $GIT_DIR to work in a subdirectory of a working tree that is
+    not located at "$GIT_DIR/..".
+
+  - "git log" learned a new option "--follow", to follow
+    renaming history of a single file.
+
+  - "git-filter-branch" lets you rewrite the revision history of
+    the current branch, creating a new branch. You can specify a
+    number of filters to modify the commits, files and trees.
+
+  - "git-cvsserver" learned new options (--base-path, --export-all,
+    --strict-paths) inspired by git-daemon.
+
+  - "git-submodule" command helps you manage the projects from
+    the superproject that contain them.
+
+  - In addition to core.compression configuration option,
+    core.loosecompression and pack.compression options can
+    independently tweak zlib compression levels used for loose
+    and packed objects.
+
+  - "git-ls-tree -l" shows size of blobs pointed at by the
+    tree entries, similar to "/bin/ls -l".
+
+  - "git-rev-list" learned --regexp-ignore-case and
+    --extended-regexp options to tweak its matching logic used
+    for --grep fitering.
+
+  - "git-describe --contains" is a handier way to call more
+    obscure command "git-name-rev --tags".
+
+  - "git gc --aggressive" tells the command to spend more cycles
+    to optimize the repository harder.
+
+  - "git repack" can be told to split resulting packs to avoid
+    exceeding limit specified with "--max-pack-size".
+
+  - "git fsck" gained --verbose option.  This is really really
+    verbose but it might help you identify exact commit that is
+    corrupt in your repository.
+
+  - "git format-patch" learned --numbered-files option.  This
+    may be useful for MH users.
+
+  - "git format-patch" learned format.subjectprefix configuration
+    variable, which serves the same purpose as "--subject-prefix"
+    option.
+
+  - "git tag -n -l" shows tag annotations while listing tags.
+
+  - "git cvsimport" can optionally use the separate-remote layout.
+
+  - "git blame" can be told to see through commits that change
+    whitespaces and indentation levels with "-w" option.
+
+  - "git send-email" can be told not to thread the messages when
+    sending out more than one patches.
+
+  - "git config" learned NUL terminated output format via -z to
+    help scripts.
+
+  - "git init -q" makes the command quieter.
+
+* Updated behavior of existing commands.
+
+  - "git svn dcommit" retains local merge information.
+
+  - "git config" to set values also honors type flags like --bool
+    and --int.
+
+  - core.quotepath configuration can be used to make textual git
+    output to emit most of the characters in the path literally.
+
+  - "git mergetool" chooses its backend more wisely, taking
+    notice of its environment such as use of X, Gnome/KDE, etc.
+
+  - "gitweb" shows merge commits a lot nicer than before.  The
+    default view uses more compact --cc format, while the UI
+    allows to choose normal diff with any parent.
+
+  - snapshot files "gitweb" creates from a repository at
+    $path/$project/.git are more useful.  We use $project part
+    in the filename, which we used to discard.
+
+  - "git cvsimport" creates lightweight tags; there is no
+    interesting information we can record in an annotated tag,
+    and the handcrafted ones the old code created was not
+    properly formed anyway.
+
+  - "git-push" pretends that you immediately fetched back from
+    the remote by updating corresponding remote tracking
+    branches if you have any.
+
+  - The diffstat given after a merge (or a pull) honors the
+    color.diff configuration.
+
+  - "git-apply --whitespace=strip" removes blank lines added at
+    the end of the file.
+
+  - "git-fetch" over git native protocols with "-v" option shows
+    connection status, and the IP address of the other end, to
+    help diagnosing problems.
+
+  - 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
+    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
+    the legacy/traditional format.
+
+  - "--find-copies-harder" option to diff family can now be
+    spelled as "-C -C" for brevity.
+
+  - "git-mailsplit" (hence "git-am") can read from Maildir
+    formatted mailboxes.
+
+  - "git-cvsserver" does not barf upon seeing "cvs login"
+    request.
+
+  - "pack-objects" honors "delta" attribute set in
+    .gitattributes.  It does not attempt to deltify blobs that
+    come from paths with delta attribute set to false.
+
+  - "new-workdir" script (in contrib) can now be used with a
+    bare repository.
+
+  - "git-mergetool" learned to use gvimdiff.
+
+  - "gitview" (in contrib) has a better blame interface.
+
+  - "git log" and friends did not handle a commit log message
+    that is larger than 16kB; they do now.
+
+  - "--pretty=oneline" output format for "git log" and friends
+    deals with "malformed" commit log messages that have more
+    than one lines in the first paragraph better.  We used to
+    show the first line, cutting the title at mid-sentence; we
+    concatenate them into a single line and treat the result as
+    "oneline".
+
+* Builds
+
+  - old-style function definitions (most notably, a function
+    without parameter defined with "func()", not "func(void)")
+    have been eradicated.
+
+* Performance Tweaks
+
+  - git-pack-objects avoids re-deltification cost by caching
+    small enough delta results it creates while looking for the
+    best delta candidates.
+
+  - diff-delta code that is used for packing has been improved
+    to work better on big files.
+
+  - when there are more than one pack files in the repository,
+    the runtime used to try finding an object always from the
+    newest packfile; it now tries the same packfile as we found
+    the object requested the last time, which exploits the
+    locality of references.
+
+  - verifying pack contents done by "git fsck --full" got boost
+    by carefully choosing the order to verify objects in them.
+
+
+Fixes since v1.5.2
+------------------
+
+All of the fixes in v1.5.2 maintenance series are included in
+this release, unless otherwise noted.
+
+* Bugfixes
+
+  - "gitweb" had trouble handling non UTF-8 text with older
+    Encode.pm Perl module.
+
+--
+exec >/var/tmp/1
+O=v1.5.3-rc0
+echo O=`git describe refs/heads/master`
+git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
index b94d9a816664333e0b1767c22d1639b8839cee24..01354c2bb5da56181de3b88052e1d921986f1f95 100644 (file)
@@ -14,6 +14,8 @@ Checklist (and a short version for the impatient):
          commit message (or just use the option "-s" when
          committing) to confirm that you agree to the Developer's
          Certificate of Origin
+       - make sure that you have tests for the bug you are fixing
+       - make sure that the test suite passes after your commit
 
        Patch:
 
@@ -33,6 +35,8 @@ Checklist (and a short version for the impatient):
        - if you change, add, or remove a command line option or
          make some other user interface change, the associated
          documentation should be updated as well.
+       - if your name is not writable in ASCII, make sure that
+         you send off a message in the correct encoding.
 
 Long version:
 
@@ -239,7 +243,7 @@ One test you could do yourself if your MUA is set up correctly is:
     $ git fetch http://kernel.org/pub/scm/git/git.git master:test-apply
     $ git checkout test-apply
     $ git reset --hard
-    $ git applymbox a.patch
+    $ git am a.patch
 
 If it does not apply correctly, there can be various reasons.
 
@@ -247,7 +251,7 @@ If it does not apply correctly, there can be various reasons.
   does not have much to do with your MUA.  Please rebase the
   patch appropriately.
 
-* Your MUA corrupted your patch; applymbox would complain that
+* Your MUA corrupted your patch; "am" would complain that
   the patch does not apply.  Look at .dotest/ subdirectory and
   see what 'patch' file contains and check for the common
   corruption patterns mentioned above.
@@ -292,15 +296,15 @@ diff --git a/pico/pico.c b/pico/pico.c
 --- a/pico/pico.c
 +++ b/pico/pico.c
 @@ -219,7 +219,9 @@ PICO *pm;
-           switch(pico_all_done){      /* prepare for/handle final events */
-             case COMP_EXIT :          /* already confirmed */
-               packheader();
+           switch(pico_all_done){      /* prepare for/handle final events */
+             case COMP_EXIT :          /* already confirmed */
+               packheader();
 +#if 0
-               stripwhitespace();
+               stripwhitespace();
 +#endif
-               c |= COMP_EXIT;
-               break;
+               c |= COMP_EXIT;
+               break;
+
 
 (Daniel Barkalow)
 
index e061f73867bb4d582fb88907b0a11fb2bf7816fd..6b6220dfdbd6cacb8a05be4995279bbd0487fada 100644 (file)
@@ -55,5 +55,3 @@ ifdef::backend-xhtml11[]
 [gitlink-inlinemacro]
 <a href="{target}.html">{target}{0?({0})}</a>
 endif::backend-xhtml11[]
-
-
index 443802a9a3e4982c33f831217602ea600f0f2775..2143995ecef4c6175b6e28b180f433581913aa83 100755 (executable)
@@ -72,8 +72,6 @@ __DATA__
 git-add                                 mainporcelain
 git-am                                  mainporcelain
 git-annotate                            ancillaryinterrogators
-git-applymbox                           ancillaryinterrogators
-git-applypatch                          purehelpers
 git-apply                               plumbingmanipulators
 git-archimport                          foreignscminterface
 git-archive                             mainporcelain
@@ -88,6 +86,7 @@ git-check-attr                          purehelpers
 git-check-ref-format                    purehelpers
 git-cherry                              ancillaryinterrogators
 git-cherry-pick                         mainporcelain
+git-citool                              mainporcelain
 git-clean                               mainporcelain
 git-clone                               mainporcelain
 git-commit                              mainporcelain
@@ -106,6 +105,7 @@ git-diff-tree                           plumbinginterrogators
 git-fast-import                                ancillarymanipulators
 git-fetch                               mainporcelain
 git-fetch-pack                          synchingrepositories
+git-filter-branch                       ancillarymanipulators
 git-fmt-merge-msg                       purehelpers
 git-for-each-ref                        plumbinginterrogators
 git-format-patch                        mainporcelain
@@ -113,6 +113,7 @@ git-fsck                            ancillaryinterrogators
 git-gc                                  mainporcelain
 git-get-tar-commit-id                   ancillaryinterrogators
 git-grep                                mainporcelain
+git-gui                                 mainporcelain
 git-hash-object                         plumbingmanipulators
 git-http-fetch                          synchelpers
 git-http-push                           synchelpers
@@ -178,8 +179,10 @@ git-show-ref                            plumbinginterrogators
 git-sh-setup                            purehelpers
 git-ssh-fetch                           synchingrepositories
 git-ssh-upload                          synchingrepositories
+git-stash                               mainporcelain
 git-status                              mainporcelain
 git-stripspace                          purehelpers
+git-submodule                           mainporcelain
 git-svn                                 foreignscminterface
 git-svnimport                           foreignscminterface
 git-symbolic-ref                        plumbingmanipulators
index a75f7f766442584f06155bb47008d1a4eb5ac640..aeece848a542cd72894f4bf3f1bb9f67d18d5c3d 100644 (file)
@@ -117,6 +117,18 @@ core.fileMode::
        the working copy are ignored; useful on broken filesystems like FAT.
        See gitlink:git-update-index[1]. True by default.
 
+core.quotepath::
+       The commands that output paths (e.g. `ls-files`,
+       `diff`), when not given the `-z` option, will quote
+       "unusual" characters in the pathname by enclosing the
+       pathname in a double-quote pair and with backslashes the
+       same way strings in C source code are quoted.  If this
+       variable is set to false, the bytes higher than 0x80 are
+       not quoted but output as verbatim.  Note that double
+       quote, backslash and control characters are always
+       quoted without `-z` regardless of the setting of this
+       variable.
+
 core.autocrlf::
        If true, makes git convert `CRLF` at the end of lines in text files to
        `LF` when reading from the filesystem, and convert in reverse when
@@ -172,6 +184,13 @@ repository that ends in "/.git" is assumed to be not bare (bare =
 false), while all other repositories are assumed to be bare (bare
 = true).
 
+core.worktree::
+       Set the path to the working tree.  The value will not be
+       used in combination with repositories found automatically in
+       a .git directory (i.e. $GIT_DIR is not set).
+       This can be overriden by the GIT_WORK_TREE environment
+       variable and the '--work-tree' command line option.
+
 core.logAllRefUpdates::
        Updates to a ref <ref> is logged to the file
        "$GIT_DIR/logs/<ref>", by appending the new and old
@@ -204,23 +223,16 @@ core.warnAmbiguousRefs::
        and might match multiple refs in the .git/refs/ tree. True by default.
 
 core.compression::
+       An integer -1..9, indicating a default compression level.
+       -1 is the zlib default. 0 means no compression,
+       and 1..9 are various speed/size tradeoffs, 9 being slowest.
+
+core.loosecompression::
        An integer -1..9, indicating the compression level for objects that
-       are not in a pack file. -1 is the zlib and git default. 0 means no
+       are not in a pack file. -1 is the zlib default. 0 means no
        compression, and 1..9 are various speed/size tradeoffs, 9 being
-       slowest.
-
-core.legacyheaders::
-       A boolean which
-       changes the format of loose objects so that they are more
-       efficient to pack and to send out of the repository over git
-       native protocol, since v1.4.2.  However, loose objects
-       written in the new format cannot be read by git older than
-       that version; people fetching from your repository using
-       older versions of git over dumb transports (e.g. http)
-       will also be affected.
-+
-To let git use the new loose object format, you have to
-set core.legacyheaders to false.
+       slowest.  If not set,  defaults to core.compression.  If that is
+       not set,  defaults to 0 (best speed).
 
 core.packedGitWindowSize::
        Number of bytes of a pack file to map into memory in a
@@ -269,6 +281,10 @@ core.excludesfile::
        of files which are not meant to be tracked.  See
        gitlink:gitignore[5].
 
+core.pager::
+       The command that git will use to paginate output.  Can be overridden
+       with the `GIT_PAGER` environment variable.
+
 alias.*::
        Command aliases for the gitlink:git[1] command wrapper - e.g.
        after defining "alias.last = cat-file commit HEAD", the invocation
@@ -293,7 +309,10 @@ branch.autosetupmerge::
        so that gitlink:git-pull[1] will appropriately merge from that
        remote branch.  Note that even if this option is not set,
        this behavior can be chosen per-branch using the `--track`
-       and `--no-track` options.  This option defaults to false.
+       and `--no-track` options.  This option can have values
+       'false' (never touch the configuration), 'all' (do this
+       for all branches), or 'true' (do this only when
+       branching from a remote tracking branch), and defaults to 'true'.
 
 branch.<name>.remote::
        When in branch <name>, it tells `git fetch` which remote to fetch.
@@ -397,6 +416,11 @@ format.suffix::
        `.patch`. Use this variable to change that suffix (make sure to
        include the dot if you want it).
 
+gc.aggressiveWindow::
+       The window size parameter used in the delta compression
+       algorithm used by 'git gc --aggressive'.  This defaults
+       to 10.
+
 gc.packrefs::
        `git gc` does not run `git pack-refs` in a bare repository by
        default so that older dumb-transport clients can still fetch
@@ -427,6 +451,11 @@ gc.rerereunresolved::
        kept for this many days when `git rerere gc` is run.
        The default is 15 days.  See gitlink:git-rerere[1].
 
+rerere.enabled::
+       Activate recording of resolved conflicts, so that identical
+       conflict hunks can be resolved automatically, should they
+       be encountered again.  See gitlink:git-rerere[1].
+
 gitcvs.enabled::
        Whether the cvs server interface is enabled for this repository.
        See gitlink:git-cvsserver[1].
@@ -533,7 +562,7 @@ merge.summary::
 merge.tool::
        Controls which merge resolution program is used by
        gitlink:git-mergetool[l].  Valid values are: "kdiff3", "tkdiff",
-       "meld", "xxdiff", "emerge", "vimdiff", and "opendiff"
+       "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff", and "opendiff".
 
 merge.verbosity::
        Controls the amount of output shown by the recursive merge
@@ -563,6 +592,22 @@ pack.depth::
        The maximum delta depth used by gitlink:git-pack-objects[1] when no
        maximum depth is given on the command line. Defaults to 50.
 
+pack.compression::
+       An integer -1..9, indicating the compression level for objects
+       in a pack file. -1 is the zlib default. 0 means no
+       compression, and 1..9 are various speed/size tradeoffs, 9 being
+       slowest.  If not set,  defaults to core.compression.  If that is
+       not set,  defaults to -1.
+
+pack.deltaCacheSize::
+       The maxium memory in bytes used for caching deltas in
+       gitlink:git-pack-objects[1].
+       A value of 0 means no limit. Defaults to 0.
+
+pack.deltaCacheLimit::
+       The maxium size of a delta, that is cached in
+       gitlink:git-pack-objects[1]. Defaults to 1000.
+
 pull.octopus::
        The default merge strategy to use when pulling multiple branches
        at once.
@@ -668,5 +713,3 @@ receive.denyNonFastForwards::
 transfer.unpackLimit::
        When `fetch.unpackLimit` or `receive.unpackLimit` are
        not set, the value of this variable is used instead.
-
-
index eea44d9d5613f448b8c2b8f0aae236f917efad39..f3cc2238c72d11e611a756e366d797c9d8056111 100644 (file)
@@ -528,7 +528,7 @@ paths that have been trivially merged.
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 Sadly, many merges aren't trivial. If there are files that have
-been added.moved or removed, or if both branches have modified the
+been addedmoved or removed, or if both branches have modified the
 same file, you will be left with an index tree that contains "merge
 entries" in it. Such an index tree can 'NOT' be written out to a tree
 object, and you will have to resolve any such merge clashes using
index 6b9b9ad7d1083ee09955ddaf46db4fad1a37834b..4fb6f4143cd849fc81f3ee5d2b8e4ee77e21137d 100644 (file)
@@ -9,11 +9,11 @@ repository, mainly because being hands-on and using explicit examples is
 often the best way of explaining what is going on.
 
 In normal life, most people wouldn't use the "core" git programs
-directly, but rather script around them to make them more palatable. 
+directly, but rather script around them to make them more palatable.
 Understanding the core git stuff may help some people get those scripts
 done, though, and it may also be instructive in helping people
 understand what it is that the higher-level helper scripts are actually
-doing. 
+doing.
 
 The core git is often called "plumbing", with the prettier user
 interfaces on top of it called "porcelain". You may not want to use the
@@ -41,7 +41,7 @@ Creating a new git repository couldn't be easier: all git repositories start
 out empty, and the only thing you need to do is find yourself a
 subdirectory that you want to use as a working tree - either an empty
 one for a totally new project, or an existing working tree that you want
-to import into git. 
+to import into git.
 
 For our first example, we're going to start a totally new repository from
 scratch, with no pre-existing files, and we'll call it `git-tutorial`.
@@ -169,7 +169,7 @@ $ ls .git/objects/??/*
 and see two files:
 
 ----------------
-.git/objects/55/7db03de997c86a4a028e1ebd3a1ceb225be238 
+.git/objects/55/7db03de997c86a4a028e1ebd3a1ceb225be238
 .git/objects/f2/4c74a2e500f5ee1332c86b94199f52b1d1d962
 ----------------
 
@@ -220,7 +220,7 @@ you have not actually really "checked in" your files into git so far,
 you've only *told* git about them.
 
 However, since git knows about them, you can now start using some of the
-most basic git commands to manipulate the files or look at their status. 
+most basic git commands to manipulate the files or look at their status.
 
 In particular, let's not even check in the two files into git yet, we'll
 start off by adding another line to `hello` first:
@@ -350,7 +350,7 @@ Making a change
 
 Remember how we did the `git-update-index` on file `hello` and then we
 changed `hello` afterward, and could compare the new state of `hello` with the
-state we saved in the index file? 
+state we saved in the index file?
 
 Further, remember how I said that `git-write-tree` writes the contents
 of the *index* file to the tree, and thus what we just committed was in
@@ -370,7 +370,7 @@ file and the working tree, `git-diff-index` shows the differences
 between a committed *tree* and either the index file or the working
 tree. In other words, `git-diff-index` wants a tree to be diffed
 against, and before we did the commit, we couldn't do that, because we
-didn't have anything to diff against. 
+didn't have anything to diff against.
 
 But now we can do
 
@@ -379,7 +379,7 @@ $ git-diff-index -p HEAD
 ----------------
 
 (where `-p` has the same meaning as it did in `git-diff-files`), and it
-will show us the same difference, but for a totally different reason. 
+will show us the same difference, but for a totally different reason.
 Now we're comparing the working tree not against the index file,
 but against the tree we just wrote. It just so happens that those two
 are obviously the same, so we get the same result.
@@ -398,7 +398,7 @@ working tree, but when given the `\--cached` flag, it is told to
 instead compare against just the index cache contents, and ignore the
 current working tree state entirely. Since we just wrote the index
 file to HEAD, doing `git-diff-index \--cached -p HEAD` should thus return
-an empty set of differences, and that's exactly what it does. 
+an empty set of differences, and that's exactly what it does.
 
 [NOTE]
 ================
@@ -549,7 +549,7 @@ $ git-whatchanged -p --root
 ----------------
 
 and you will see exactly what has changed in the repository over its
-short history. 
+short history.
 
 [NOTE]
 The `\--root` flag is a flag to `git-diff-tree` to tell it to
@@ -637,7 +637,7 @@ So the mental model of "the git information is always tied directly to
 the working tree that it describes" may not be technically 100%
 accurate, but it's a good model for all normal use.
 
-This has two implications: 
+This has two implications:
 
  - if you grow bored with the tutorial repository you created (or you've
    made a mistake and want to start all over), you can just do simple
@@ -705,7 +705,7 @@ Many (most?) public remote repositories will not contain any of
 the checked out files or even an index file, and will *only* contain the
 actual core git files. Such a repository usually doesn't even have the
 `.git` subdirectory, but has all the git files directly in the
-repository. 
+repository.
 
 To create your own local live copy of such a "raw" git repository, you'd
 first create your own subdirectory for the project, and then copy the
@@ -718,7 +718,7 @@ $ cd my-git
 $ rsync -rL rsync://rsync.kernel.org/pub/scm/git/git.git/ .git
 ----------------
 
-followed by 
+followed by
 
 ----------------
 $ git-read-tree HEAD
@@ -738,7 +738,7 @@ up-to-date (so that you don't have to refresh it afterward), and the
 `-a` flag means "check out all files" (if you have a stale copy or an
 older version of a checked out tree you may also need to add the `-f`
 flag first, to tell git-checkout-index to *force* overwriting of any old
-files). 
+files).
 
 Again, this can all be simplified with
 
@@ -751,7 +751,7 @@ $ git checkout
 which will end up doing all of the above for you.
 
 You have now successfully copied somebody else's (mine) remote
-repository, and checked it out. 
+repository, and checked it out.
 
 
 Creating a new branch
@@ -760,14 +760,14 @@ Creating a new branch
 Branches in git are really nothing more than pointers into the git
 object database from within the `.git/refs/` subdirectory, and as we
 already discussed, the `HEAD` branch is nothing but a symlink to one of
-these object pointers. 
+these object pointers.
 
 You can at any time create a new branch by just picking an arbitrary
 point in the project history, and just writing the SHA1 name of that
 object into a file under `.git/refs/heads/`. You can use any filename you
 want (and indeed, subdirectories), but the convention is that the
 "normal" branch is called `master`. That's just a convention, though,
-and nothing enforces it. 
+and nothing enforces it.
 
 To show that as an example, let's go back to the git-tutorial repository we
 used earlier, and create a branch in it. You do that by simply just
@@ -778,7 +778,7 @@ $ git checkout -b mybranch
 ------------
 
 will create a new branch based at the current `HEAD` position, and switch
-to it. 
+to it.
 
 [NOTE]
 ================================================
@@ -825,7 +825,7 @@ checking it out and switching to it. If so, just use the command
 $ git branch <branchname> [startingpoint]
 ------------
 
-which will simply _create_ the branch, but will not do anything further. 
+which will simply _create_ the branch, but will not do anything further.
 You can then later -- once you decide that you want to actually develop
 on that branch -- switch to that branch with a regular `git checkout`
 with the branchname as the argument.
@@ -884,7 +884,7 @@ $ gitk --all
 will show you graphically both of your branches (that's what the `\--all`
 means: normally it will just show you your current `HEAD`) and their
 histories. You can also see exactly how they came to be from a common
-source. 
+source.
 
 Anyway, let's exit `gitk` (`^Q` or the File menu), and decide that we want
 to merge the work we did on the `mybranch` branch into the `master`
@@ -905,8 +905,8 @@ of it as it can automatically (which in this case is just merge the `example`
 file, which had no differences in the `mybranch` branch), and say:
 
 ----------------
-       Auto-merging hello 
-       CONFLICT (content): Merge conflict in hello 
+       Auto-merging hello
+       CONFLICT (content): Merge conflict in hello
        Automatic merge failed; fix up by hand
 ----------------
 
@@ -1387,7 +1387,7 @@ repository. Kernel.org mirror network takes care of the
 propagation to other publicly visible machines:
 
 ------------
-$ git push master.kernel.org:/pub/scm/git/git.git/ 
+$ git push master.kernel.org:/pub/scm/git/git.git/
 ------------
 
 
index e38a1f14056b2e3cfe3c281eb7df7e5b44d520db..001503205b24d5c20ec10792c4ab6c4c7221bcb7 100644 (file)
@@ -1,7 +1,7 @@
 The output format from "git-diff-index", "git-diff-tree" and
 "git-diff-files" are very similar.
 
-These commands all compare two sets of things; what is 
+These commands all compare two sets of things; what is
 compared differs:
 
 git-diff-index <tree-ish>::
@@ -126,6 +126,13 @@ the file that rename/copy produces, respectively.
     If there is need for such substitution then the whole
     pathname is put in double quotes.
 
+The similarity index is the percentage of unchanged lines, and
+the dissimilarity index is the percentage of changed lines.  It
+is a rounded down integer, followed by a percent sign.  The
+similarity index value of 100% is thus reserved for two equal
+files, while 100% dissimilarity means that no line from the old
+file made it into the new one.
+
 
 combined diff format
 --------------------
@@ -139,28 +146,28 @@ index fabadb8,cc95eb0..4866510
 --- a/describe.c
 +++ b/describe.c
 @@@ -98,20 -98,12 +98,20 @@@
-       return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;
+       return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;
   }
-  
+
 - static void describe(char *arg)
  -static void describe(struct commit *cmit, int last_one)
 ++static void describe(char *arg, int last_one)
   {
  +     unsigned char sha1[20];
  +     struct commit *cmit;
-       struct commit_list *list;
-       static int initialized = 0;
-       struct commit_name *n;
-  
+       struct commit_list *list;
+       static int initialized = 0;
+       struct commit_name *n;
+
  +     if (get_sha1(arg, sha1) < 0)
  +             usage(describe_usage);
  +     cmit = lookup_commit_reference(sha1);
  +     if (!cmit)
  +             usage(describe_usage);
  +
-       if (!initialized) {
-               initialized = 1;
-               for_each_ref(get_name);
+       if (!initialized) {
+               initialized = 1;
+               for_each_ref(get_name);
 ------------
 
 1.   It is preceded with a "git diff" header, that looks like
@@ -233,4 +240,3 @@ parents).  When shown by `git diff-files -c`, it compares the
 two unresolved merge parents with the working tree file
 (i.e. file1 is stage 2 aka "our version", file2 is stage 3 aka
 "their version").
-
index 1689c748171a8ff48395cf432aabe0130fc6b8d2..3d2b9d0a06f38c42c0df927fa03a053fa1b45277 100644 (file)
@@ -86,7 +86,7 @@
        Detect renames.
 
 -C::
-       Detect copies as well as renames.
+       Detect copies as well as renames.  See also `--find-copies-harder`.
 
 --diff-filter=[ACDMRTUXB*]::
        Select only files that are Added (`A`), Copied (`C`),
        that matches other criteria, nothing is selected.
 
 --find-copies-harder::
-       For performance reasons, by default, -C option finds copies only 
-       if the original file of the copy was modified in the same 
+       For performance reasons, by default, `-C` option finds copies only
+       if the original file of the copy was modified in the same
        changeset.  This flag makes the command
        inspect unmodified files as candidates for the source of
        copy.  This is a very expensive operation for large
-       projects, so use it with caution.
+       projects, so use it with caution.  Giving more than one
+       `-C` option has the same effect.
 
 -l<num>::
        -M and -C options require O(n^2) processing time where n
 --quiet::
        Disable all output of the program. Implies --exit-code.
 
+--ext-diff::
+       Allow an external diff helper to be executed. If you set an
+       external diff driver with gitlink:gitattributes(5), you need
+       to use this option with gitlink:git-log(1) and friends.
+
+--no-ext-diff::
+       Disallow external diff drivers.
+
 For more detailed explanation on these common options, see also
 link:diffcore.html[diffcore documentation].
index 34cd306bb1ee6ac73986cf3371114381b4165a0d..c6a983a5d54abe2b18d155b6cba520c257da6f59 100644 (file)
@@ -71,7 +71,7 @@ The first transformation in the chain is diffcore-pathspec, and
 is controlled by giving the pathname parameters to the
 git-diff-* commands on the command line.  The pathspec is used
 to limit the world diff operates in.  It removes the filepairs
-outside the specified set of pathnames.  E.g. If the input set 
+outside the specified set of pathnames.  E.g. If the input set
 of filepairs included:
 
 ------------------------------------------------
@@ -269,4 +269,3 @@ Documentation
 *.c
 t
 ------------------------------------------------
-
index 8821e305dd6d5df919e376d2d9c3d0d5716cc074..b878b385c6967f4c64ba30bdfe8f9bd24bef91e3 100644 (file)
-/*\r
-  CSS stylesheet for XHTML produced by DocBook XSL stylesheets.\r
-  Tested with XSL stylesheets 1.61.2, 1.67.2\r
-*/\r
-\r
-span.strong {\r
-  font-weight: bold;\r
-}\r
-\r
-body blockquote {\r
-  margin-top: .75em;\r
-  line-height: 1.5;\r
-  margin-bottom: .75em;\r
-}\r
-\r
-html body {\r
-  margin: 1em 5% 1em 5%;\r
-  line-height: 1.2;\r
-}\r
-\r
-body div {\r
-  margin: 0;\r
-}\r
-\r
-h1, h2, h3, h4, h5, h6,\r
-div.toc p b,\r
-div.list-of-figures p b,\r
-div.list-of-tables p b,\r
-div.abstract p.title\r
-{\r
-  color: #527bbd;\r
-  font-family: tahoma, verdana, sans-serif;\r
-}\r
-\r
-div.toc p:first-child,\r
-div.list-of-figures p:first-child,\r
-div.list-of-tables p:first-child,\r
-div.example p.title\r
-{\r
-  margin-bottom: 0.2em;\r
-}\r
-\r
-body h1 {\r
-  margin: .0em 0 0 -4%;\r
-  line-height: 1.3;\r
-  border-bottom: 2px solid silver;\r
-}\r
-\r
-body h2 {\r
-  margin: 0.5em 0 0 -4%;\r
-  line-height: 1.3;\r
-  border-bottom: 2px solid silver;\r
-}\r
-\r
-body h3 {\r
-  margin: .8em 0 0 -3%;\r
-  line-height: 1.3;\r
-}\r
-\r
-body h4 {\r
-  margin: .8em 0 0 -3%;\r
-  line-height: 1.3;\r
-}\r
-\r
-body h5 {\r
-  margin: .8em 0 0 -2%;\r
-  line-height: 1.3;\r
-}\r
-\r
-body h6 {\r
-  margin: .8em 0 0 -1%;\r
-  line-height: 1.3;\r
-}\r
-\r
-body hr {\r
-  border: none; /* Broken on IE6 */\r
-}\r
-div.footnotes hr {\r
-  border: 1px solid silver;\r
-}\r
-\r
-div.navheader th, div.navheader td, div.navfooter td {\r
-  font-family: sans-serif;\r
-  font-size: 0.9em;\r
-  font-weight: bold;\r
-  color: #527bbd;\r
-}\r
-div.navheader img, div.navfooter img {\r
-  border-style: none;\r
-}\r
-div.navheader a, div.navfooter a {\r
-  font-weight: normal;\r
-}\r
-div.navfooter hr {\r
-  border: 1px solid silver;\r
-}\r
-\r
-body td {\r
-  line-height: 1.2\r
-}\r
-\r
-body th {\r
-  line-height: 1.2;\r
-}\r
-\r
-ol {\r
-  line-height: 1.2;\r
-}\r
-\r
-ul, body dir, body menu {\r
-  line-height: 1.2;\r
-}\r
-\r
-html {\r
-  margin: 0; \r
-  padding: 0;\r
-}\r
-\r
-body h1, body h2, body h3, body h4, body h5, body h6 {\r
-  margin-left: 0\r
-} \r
-\r
-body pre {\r
-  margin: 0.5em 10% 0.5em 1em;\r
-  line-height: 1.0;\r
-  color: navy;\r
-}\r
-\r
-tt.literal, code.literal {\r
-  color: navy;\r
-}\r
-\r
-div.literallayout p {\r
-  padding: 0em;\r
-  margin: 0em;\r
-}\r
-\r
-div.literallayout {\r
-  font-family: monospace;\r
-#  margin: 0.5em 10% 0.5em 1em;\r
-  margin: 0em;\r
-  color: navy;\r
-  border: 1px solid silver;\r
-  background: #f4f4f4;\r
-  padding: 0.5em;\r
-}\r
-\r
-.programlisting, .screen {\r
-  border: 1px solid silver;\r
-  background: #f4f4f4;\r
-  margin: 0.5em 10% 0.5em 0;\r
-  padding: 0.5em 1em;\r
-}\r
-\r
-div.sidebar {\r
-  background: #ffffee;\r
-  margin: 1.0em 10% 0.5em 0;\r
-  padding: 0.5em 1em;\r
-  border: 1px solid silver;\r
-}\r
-div.sidebar * { padding: 0; }\r
-div.sidebar div { margin: 0; }\r
-div.sidebar p.title {\r
-  font-family: sans-serif;\r
-  margin-top: 0.5em;\r
-  margin-bottom: 0.2em;\r
-}\r
-\r
-div.bibliomixed {\r
-  margin: 0.5em 5% 0.5em 1em;\r
-}\r
-\r
-div.glossary dt {\r
-  font-weight: bold;\r
-}\r
-div.glossary dd p {\r
-  margin-top: 0.2em;\r
-}\r
-\r
-dl {\r
-  margin: .8em 0;\r
-  line-height: 1.2;\r
-}\r
-\r
-dt {\r
-  margin-top: 0.5em;\r
-}\r
-\r
-dt span.term {\r
-  font-style: italic;\r
-}\r
-\r
-div.variablelist dd p {\r
-  margin-top: 0;\r
-}\r
-\r
-div.itemizedlist li, div.orderedlist li {\r
-  margin-left: -0.8em;\r
-  margin-top: 0.5em;\r
-}\r
-\r
-ul, ol {\r
-    list-style-position: outside;\r
-}\r
-\r
-div.sidebar ul, div.sidebar ol {\r
-    margin-left: 2.8em;\r
-}\r
-\r
-div.itemizedlist p.title,\r
-div.orderedlist p.title,\r
-div.variablelist p.title\r
-{\r
-  margin-bottom: -0.8em;\r
-}\r
-\r
-div.revhistory table {\r
-  border-collapse: collapse;\r
-  border: none;\r
-}\r
-div.revhistory th {\r
-  border: none;\r
-  color: #527bbd;\r
-  font-family: tahoma, verdana, sans-serif;\r
-}\r
-div.revhistory td {\r
-  border: 1px solid silver;\r
-}\r
-\r
-/* Keep TOC and index lines close together. */\r
-div.toc dl, div.toc dt,\r
-div.list-of-figures dl, div.list-of-figures dt,\r
-div.list-of-tables dl, div.list-of-tables dt,\r
-div.indexdiv dl, div.indexdiv dt\r
-{\r
-  line-height: normal;\r
-  margin-top: 0;\r
-  margin-bottom: 0;\r
-}\r
-\r
-/*\r
-  Table styling does not work because of overriding attributes in\r
-  generated HTML.\r
-*/\r
-div.table table,\r
-div.informaltable table\r
-{\r
-    margin-left: 0;\r
-    margin-right: 5%;\r
-    margin-bottom: 0.8em;\r
-}\r
-div.informaltable table\r
-{\r
-    margin-top: 0.4em\r
-}\r
-div.table thead,\r
-div.table tfoot,\r
-div.table tbody,\r
-div.informaltable thead,\r
-div.informaltable tfoot,\r
-div.informaltable tbody\r
-{\r
-    /* No effect in IE6. */\r
-    border-top: 2px solid #527bbd;\r
-    border-bottom: 2px solid #527bbd;\r
-}\r
-div.table thead, div.table tfoot,\r
-div.informaltable thead, div.informaltable tfoot\r
-{\r
-    font-weight: bold;\r
-}\r
-\r
-div.mediaobject img {\r
-    border: 1px solid silver;\r
-    margin-bottom: 0.8em;\r
-}\r
-div.figure p.title,\r
-div.table p.title\r
-{\r
-  margin-top: 1em;\r
-  margin-bottom: 0.4em;\r
-}\r
-\r
-@media print {\r
-  div.navheader, div.navfooter { display: none; }\r
-}\r
+/*
+  CSS stylesheet for XHTML produced by DocBook XSL stylesheets.
+  Tested with XSL stylesheets 1.61.2, 1.67.2
+*/
+
+span.strong {
+  font-weight: bold;
+}
+
+body blockquote {
+  margin-top: .75em;
+  line-height: 1.5;
+  margin-bottom: .75em;
+}
+
+html body {
+  margin: 1em 5% 1em 5%;
+  line-height: 1.2;
+}
+
+body div {
+  margin: 0;
+}
+
+h1, h2, h3, h4, h5, h6,
+div.toc p b,
+div.list-of-figures p b,
+div.list-of-tables p b,
+div.abstract p.title
+{
+  color: #527bbd;
+  font-family: tahoma, verdana, sans-serif;
+}
+
+div.toc p:first-child,
+div.list-of-figures p:first-child,
+div.list-of-tables p:first-child,
+div.example p.title
+{
+  margin-bottom: 0.2em;
+}
+
+body h1 {
+  margin: .0em 0 0 -4%;
+  line-height: 1.3;
+  border-bottom: 2px solid silver;
+}
+
+body h2 {
+  margin: 0.5em 0 0 -4%;
+  line-height: 1.3;
+  border-bottom: 2px solid silver;
+}
+
+body h3 {
+  margin: .8em 0 0 -3%;
+  line-height: 1.3;
+}
+
+body h4 {
+  margin: .8em 0 0 -3%;
+  line-height: 1.3;
+}
+
+body h5 {
+  margin: .8em 0 0 -2%;
+  line-height: 1.3;
+}
+
+body h6 {
+  margin: .8em 0 0 -1%;
+  line-height: 1.3;
+}
+
+body hr {
+  border: none; /* Broken on IE6 */
+}
+div.footnotes hr {
+  border: 1px solid silver;
+}
+
+div.navheader th, div.navheader td, div.navfooter td {
+  font-family: sans-serif;
+  font-size: 0.9em;
+  font-weight: bold;
+  color: #527bbd;
+}
+div.navheader img, div.navfooter img {
+  border-style: none;
+}
+div.navheader a, div.navfooter a {
+  font-weight: normal;
+}
+div.navfooter hr {
+  border: 1px solid silver;
+}
+
+body td {
+  line-height: 1.2
+}
+
+body th {
+  line-height: 1.2;
+}
+
+ol {
+  line-height: 1.2;
+}
+
+ul, body dir, body menu {
+  line-height: 1.2;
+}
+
+html {
+  margin: 0;
+  padding: 0;
+}
+
+body h1, body h2, body h3, body h4, body h5, body h6 {
+  margin-left: 0
+}
+
+body pre {
+  margin: 0.5em 10% 0.5em 1em;
+  line-height: 1.0;
+  color: navy;
+}
+
+tt.literal, code.literal {
+  color: navy;
+}
+
+div.literallayout p {
+  padding: 0em;
+  margin: 0em;
+}
+
+div.literallayout {
+  font-family: monospace;
+#  margin: 0.5em 10% 0.5em 1em;
+  margin: 0em;
+  color: navy;
+  border: 1px solid silver;
+  background: #f4f4f4;
+  padding: 0.5em;
+}
+
+.programlisting, .screen {
+  border: 1px solid silver;
+  background: #f4f4f4;
+  margin: 0.5em 10% 0.5em 0;
+  padding: 0.5em 1em;
+}
+
+div.sidebar {
+  background: #ffffee;
+  margin: 1.0em 10% 0.5em 0;
+  padding: 0.5em 1em;
+  border: 1px solid silver;
+}
+div.sidebar * { padding: 0; }
+div.sidebar div { margin: 0; }
+div.sidebar p.title {
+  font-family: sans-serif;
+  margin-top: 0.5em;
+  margin-bottom: 0.2em;
+}
+
+div.bibliomixed {
+  margin: 0.5em 5% 0.5em 1em;
+}
+
+div.glossary dt {
+  font-weight: bold;
+}
+div.glossary dd p {
+  margin-top: 0.2em;
+}
+
+dl {
+  margin: .8em 0;
+  line-height: 1.2;
+}
+
+dt {
+  margin-top: 0.5em;
+}
+
+dt span.term {
+  font-style: italic;
+}
+
+div.variablelist dd p {
+  margin-top: 0;
+}
+
+div.itemizedlist li, div.orderedlist li {
+  margin-left: -0.8em;
+  margin-top: 0.5em;
+}
+
+ul, ol {
+    list-style-position: outside;
+}
+
+div.sidebar ul, div.sidebar ol {
+    margin-left: 2.8em;
+}
+
+div.itemizedlist p.title,
+div.orderedlist p.title,
+div.variablelist p.title
+{
+  margin-bottom: -0.8em;
+}
+
+div.revhistory table {
+  border-collapse: collapse;
+  border: none;
+}
+div.revhistory th {
+  border: none;
+  color: #527bbd;
+  font-family: tahoma, verdana, sans-serif;
+}
+div.revhistory td {
+  border: 1px solid silver;
+}
+
+/* Keep TOC and index lines close together. */
+div.toc dl, div.toc dt,
+div.list-of-figures dl, div.list-of-figures dt,
+div.list-of-tables dl, div.list-of-tables dt,
+div.indexdiv dl, div.indexdiv dt
+{
+  line-height: normal;
+  margin-top: 0;
+  margin-bottom: 0;
+}
+
+/*
+  Table styling does not work because of overriding attributes in
+  generated HTML.
+*/
+div.table table,
+div.informaltable table
+{
+    margin-left: 0;
+    margin-right: 5%;
+    margin-bottom: 0.8em;
+}
+div.informaltable table
+{
+    margin-top: 0.4em
+}
+div.table thead,
+div.table tfoot,
+div.table tbody,
+div.informaltable thead,
+div.informaltable tfoot,
+div.informaltable tbody
+{
+    /* No effect in IE6. */
+    border-top: 2px solid #527bbd;
+    border-bottom: 2px solid #527bbd;
+}
+div.table thead, div.table tfoot,
+div.informaltable thead, div.informaltable tfoot
+{
+    font-weight: bold;
+}
+
+div.mediaobject img {
+    border: 1px solid silver;
+    margin-bottom: 0.8em;
+}
+div.figure p.title,
+div.table p.title
+{
+  margin-top: 1em;
+  margin-bottom: 0.4em;
+}
+
+@media print {
+  div.navheader, div.navfooter { display: none; }
+}
index bdc7332c7b11c25957ee170b0582f9fe182755eb..da034223f3a0c07bc3451814ae8d087423f1e2f5 100644 (file)
@@ -52,4 +52,3 @@
        Deepen the history of a 'shallow' repository created by
        `git clone` with `--depth=<depth>` option (see gitlink:git-clone[1])
        by the specified number of commits.
-
index a0c9f68580594f785aaec0472ca8404701d4d86d..76d2b05854ccc742105c374fae33c676795d29f1 100644 (file)
@@ -228,4 +228,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index ba79773f79fc8823f1c611e51b163866ada26306..e4a6b3a6f0fc258e8a2052d1d56a71fb57667d39 100644 (file)
@@ -12,7 +12,7 @@ SYNOPSIS
 'git-am' [--signoff] [--dotest=<dir>] [--keep] [--utf8 | --no-utf8]
          [--3way] [--interactive] [--binary]
          [--whitespace=<option>] [-C<n>] [-p<n>]
-         <mbox>...
+         <mbox>|<Maildir>...
 'git-am' [--skip | --resolved]
 
 DESCRIPTION
@@ -23,9 +23,10 @@ current branch.
 
 OPTIONS
 -------
-<mbox>...::
+<mbox>|<Maildir>...::
        The list of mailbox files to read patches from. If you do not
-       supply this argument, reads from the standard input.
+       supply this argument, reads from the standard input. If you supply
+       directories, they'll be treated as Maildirs.
 
 -s, --signoff::
        Add `Signed-off-by:` line to the commit message, using
@@ -126,8 +127,7 @@ is terminated before the first occurrence of such a line.
 
 When initially invoking it, you give it names of the mailboxes
 to crunch.  Upon seeing the first patch that does not apply, it
-aborts in the middle, just like 'git-applymbox' does.  You can
-recover from this in one of two ways:
+aborts in the middle,.  You can recover from this in one of two ways:
 
 . skip the current patch by re-running the command with '--skip'
   option.
@@ -144,7 +144,7 @@ names.
 
 SEE ALSO
 --------
-gitlink:git-applymbox[1], gitlink:git-applypatch[1], gitlink:git-apply[1].
+gitlink:git-apply[1].
 
 
 Author
@@ -158,4 +158,3 @@ Documentation by Petr Baudis, Junio C Hamano and the git-list <git@vger.kernel.o
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 3bd2c995da7d65977481837486dc15e5e96baf91..f03f661652814d0900f3564c1914b217dc465a01 100644 (file)
@@ -183,4 +183,3 @@ Documentation by Junio C Hamano
 GIT
 ---
 Part of the gitlink:git[7] suite
-
diff --git a/Documentation/git-applymbox.txt b/Documentation/git-applymbox.txt
deleted file mode 100644 (file)
index ea919ba..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-git-applymbox(1)
-================
-
-NAME
-----
-git-applymbox - Apply a series of patches in a mailbox
-
-
-SYNOPSIS
---------
-'git-applymbox' [-u] [-k] [-q] [-m] ( -c .dotest/<num> | <mbox> ) [ <signoff> ]
-
-DESCRIPTION
------------
-Splits mail messages in a mailbox into commit log message,
-authorship information and patches, and applies them to the
-current branch.
-
-
-OPTIONS
--------
--q::
-       Apply patches interactively.  The user will be given
-       opportunity to edit the log message and the patch before
-       attempting to apply it.
-
--k::
-       Usually the program 'cleans up' the Subject: header line
-       to extract the title line for the commit log message,
-       among which (1) remove 'Re:' or 're:', (2) leading
-       whitespaces, (3) '[' up to ']', typically '[PATCH]', and
-       then prepends "[PATCH] ".  This flag forbids this
-       munging, and is most useful when used to read back 'git
-       format-patch -k' output.
-
--m::
-       Patches are applied with `git-apply` command, and unless
-       it cleanly applies without fuzz, the processing fails.
-       With this flag, if a tree that the patch applies cleanly
-       is found in a repository, the patch is applied to the
-       tree and then a 3-way merge between the resulting tree
-       and the current tree.
-
--u::
-       Pass `-u` flag to `git-mailinfo` (see gitlink:git-mailinfo[1]).
-       The proposed commit log message taken from the e-mail
-       are re-coded into UTF-8 encoding (configuration variable
-       `i18n.commitencoding` can be used to specify project's
-       preferred encoding if it is not UTF-8).  This used to be
-       optional but now it is the default.
-+
-Note that the patch is always used as-is without charset
-conversion, even with this flag.
-
--n::
-       Pass `-n` flag to `git-mailinfo` (see
-       gitlink:git-mailinfo[1]).
-
--c .dotest/<num>::
-       When the patch contained in an e-mail does not cleanly
-       apply, the command exits with an error message. The
-       patch and extracted message are found in .dotest/, and
-       you could re-run 'git applymbox' with '-c .dotest/<num>'
-       flag to restart the process after inspecting and fixing
-       them.
-
-<mbox>::
-       The name of the file that contains the e-mail messages
-       with patches.  This file should be in the UNIX mailbox
-       format.  See 'SubmittingPatches' document to learn about
-       the formatting convention for e-mail submission.
-
-<signoff>::
-       The name of the file that contains your "Signed-off-by"
-       line.  See 'SubmittingPatches' document to learn what
-       "Signed-off-by" line means.  You can also just say
-       'yes', 'true', 'me', or 'please' to use an automatically
-       generated "Signed-off-by" line based on your committer
-       identity.
-
-
-SEE ALSO
---------
-gitlink:git-am[1], gitlink:git-applypatch[1].
-
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
-GIT
----
-Part of the gitlink:git[7] suite
-
diff --git a/Documentation/git-applypatch.txt b/Documentation/git-applypatch.txt
deleted file mode 100644 (file)
index 451434a..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-git-applypatch(1)
-=================
-
-NAME
-----
-git-applypatch - Apply one patch extracted from an e-mail
-
-
-SYNOPSIS
---------
-'git-applypatch' <msg> <patch> <info> [<signoff>]
-
-DESCRIPTION
------------
-This is usually not what an end user wants to run directly.  See
-gitlink:git-am[1] instead.
-
-Takes three files <msg>, <patch>, and <info> prepared from an
-e-mail message by 'git-mailinfo', and creates a commit.  It is
-usually not necessary to use this command directly.
-
-This command can run `applypatch-msg`, `pre-applypatch`, and
-`post-applypatch` hooks.  See link:hooks.html[hooks] for more
-information.
-
-
-OPTIONS
--------
-<msg>::
-       Commit log message (sans the first line, which comes
-       from e-mail Subject stored in <info>).
-
-<patch>::
-       The patch to apply.
-
-<info>::
-       Author and subject information extracted from e-mail,
-       used on "author" line and as the first line of the
-       commit log message.
-
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
-GIT
----
-Part of the gitlink:git[7] suite
-
index 82cb41d2791abbd32bd8209660e9879b9f2b8f32..7091b8d61cf4871e2cecc7b18bc6997ea42b4ef9 100644 (file)
@@ -17,26 +17,26 @@ DESCRIPTION
 Imports a project from one or more Arch repositories. It will follow branches
 and repositories within the namespaces defined by the <archive/branch>
 parameters supplied. If it cannot find the remote branch a merge comes from
-it will just import it as a regular commit. If it can find it, it will mark it 
-as a merge whenever possible (see discussion below). 
+it will just import it as a regular commit. If it can find it, it will mark it
+as a merge whenever possible (see discussion below).
 
-The script expects you to provide the key roots where it can start the import 
-from an 'initial import' or 'tag' type of Arch commit. It will follow and 
-import new branches within the provided roots. 
+The script expects you to provide the key roots where it can start the import
+from an 'initial import' or 'tag' type of Arch commit. It will follow and
+import new branches within the provided roots.
 
-It expects to be dealing with one project only. If it sees 
-branches that have different roots, it will refuse to run. In that case, 
-edit your <archive/branch> parameters to define clearly the scope of the 
-import. 
+It expects to be dealing with one project only. If it sees
+branches that have different roots, it will refuse to run. In that case,
+edit your <archive/branch> parameters to define clearly the scope of the
+import.
 
-`git-archimport` uses `tla` extensively in the background to access the 
+`git-archimport` uses `tla` extensively in the background to access the
 Arch repository.
 Make sure you have a recent version of `tla` available in the path. `tla` must
-know about the repositories you pass to `git-archimport`. 
+know about the repositories you pass to `git-archimport`.
 
-For the initial import `git-archimport` expects to find itself in an empty 
-directory. To follow the development of a project that uses Arch, rerun 
-`git-archimport` with the same parameters as the initial import to perform 
+For the initial import `git-archimport` expects to find itself in an empty
+directory. To follow the development of a project that uses Arch, rerun
+`git-archimport` with the same parameters as the initial import to perform
 incremental imports.
 
 While git-archimport will try to create sensible branch names for the
@@ -54,15 +54,15 @@ convert Arch repositories that had been rotated periodically.
 
 MERGES
 ------
-Patch merge data from Arch is used to mark merges in git as well. git 
+Patch merge data from Arch is used to mark merges in git as well. git
 does not care much about tracking patches, and only considers a merge when a
 branch incorporates all the commits since the point they forked. The end result
-is that git will have a good idea of how far branches have diverged. So the 
+is that git will have a good idea of how far branches have diverged. So the
 import process does lose some patch-trading metadata.
 
-Fortunately, when you try and merge branches imported from Arch, 
-git will find a good merge base, and it has a good chance of identifying 
-patches that have been traded out-of-sequence between the branches. 
+Fortunately, when you try and merge branches imported from Arch,
+git will find a good merge base, and it has a good chance of identifying
+patches that have been traded out-of-sequence between the branches.
 
 OPTIONS
 -------
@@ -71,10 +71,10 @@ OPTIONS
        Display usage.
 
 -v::
-       Verbose output. 
+       Verbose output.
 
 -T::
-       Many tags. Will create a tag for every commit, reflecting the commit 
+       Many tags. Will create a tag for every commit, reflecting the commit
        name in the Arch repository.
 
 -f::
@@ -104,7 +104,7 @@ OPTIONS
 
 
 <archive/branch>::
-       Archive/branch identifier in a format that `tla log` understands. 
+       Archive/branch identifier in a format that `tla log` understands.
 
 
 Author
@@ -118,4 +118,3 @@ Documentation by Junio C Hamano, Martin Langhoff and the git-list <git@vger.kern
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 5f68ee1584b294a9395f2a3d4f29e0b1208f5913..1072fb87d1fe38a74dc38e2d6886acfb44d9262b 100644 (file)
@@ -8,7 +8,7 @@ git-bisect - Find the change that introduced a bug by binary search
 
 SYNOPSIS
 --------
-'git bisect' <subcommand> <options> 
+'git bisect' <subcommand> <options>
 
 DESCRIPTION
 -----------
@@ -200,4 +200,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 44678b0c3601512df024e3670aadeabd5317b0c9..66f1203701350f42cb028c6971c169ac129332ec 100644 (file)
@@ -8,7 +8,7 @@ git-blame - Show what revision and author last modified each line of a file
 SYNOPSIS
 --------
 [verse]
-'git-blame' [-c] [-b] [--root] [-s] [-l] [-t] [-f] [-n] [-p] [--incremental] [-L n,m]
+'git-blame' [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-p] [-w] [--incremental] [-L n,m]
             [-S <revs-file>] [-M] [-C] [-C] [--since=<date>]
             [<rev> | --contents <file>] [--] <file>
 
@@ -63,6 +63,11 @@ include::blame-options.txt[]
 -s::
        Suppress author name and timestamp from the output.
 
+-w::
+       Ignore whitespace when comparing parent's version and
+       child's to find where the lines came from.
+
+
 THE PORCELAIN FORMAT
 --------------------
 
index 8dc5171f5e685ab18d466751710f44e8aba104b7..bb6b57dc2d00e38fc1d0128fe02fc771a1f83086 100644 (file)
@@ -41,7 +41,7 @@ to happen.
 
 With a `-d` or `-D` option, `<branchname>` will be deleted.  You may
 specify more than one branch for deletion.  If the branch currently
-has a ref log then the ref log will also be deleted. Use -r together with -d
+has a reflog then the reflog will also be deleted. Use -r together with -d
 to delete remote-tracking branches.
 
 
@@ -54,9 +54,9 @@ OPTIONS
        Delete a branch irrespective of its index status.
 
 -l::
-       Create the branch's ref log.  This activates recording of
-       all changes to made the branch ref, enabling use of date
-       based sha1 expressions such as "<branchname>@{yesterday}".
+       Create the branch's reflog.  This activates recording of
+       all changes made to the branch ref, enabling use of date
+       based sha1 expressions such as "<branchname>@\{yesterday}".
 
 -f::
        Force the creation of a new branch even if it means deleting
@@ -158,4 +158,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 075c0d05efca85c2357e09aa640aa4b7f0305419..afa095c79529dc92d5db6c54effd435c57f5eb7a 100644 (file)
@@ -71,4 +71,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index ceb51959b1d28a7298ddd42b0e3e968c568195a7..856d2af2ed9c1ccfcd819191060447b62e49b8b6 100644 (file)
@@ -34,4 +34,3 @@ Documentation by James Bowes.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 6dd6db04bb91ae97472ce40d6b76ff8d409b99f7..b1a8ce110cd3caa641a53e7944479bb8f84bec44 100644 (file)
@@ -182,4 +182,3 @@ Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 918d8ee720a573f91ec6efa654da5c2cdc05d7b0..82929523c7166f9e5beb08689cef65cfa20c9a8c 100644 (file)
@@ -52,8 +52,9 @@ OPTIONS
        set up configuration so that git-pull will automatically
        retrieve data from the remote branch.  Set the
        branch.autosetupmerge configuration variable to true if you
-       want git-checkout and git-branch to always behave as if
-       '--track' were given.
+       want git-checkout and git-branch to behave as if
+       '--track' were given when you branch from a remote
+       tracking branch.
 
 --no-track::
        When -b is given and a branch is created off a remote branch,
@@ -62,9 +63,9 @@ OPTIONS
        configuration variable.
 
 -l::
-       Create the new branch's ref log.  This activates recording of
-       all changes to made the branch ref, enabling use of date
-       based sha1 expressions such as "<branchname>@{yesterday}".
+       Create the new branch's reflog.  This activates recording of
+       all changes made to the branch ref, enabling use of date
+       based sha1 expressions such as "<branchname>@\{yesterday}".
 
 -m::
        If you have local modifications to one or more files that
@@ -215,4 +216,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 68bba982606b5e17b730f0e5d4d201923231c235..47b1e8c2fcd567b7e9d673f2d3ff30c9c32a1b83 100644 (file)
@@ -68,4 +68,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 8c7d9670d3b31353cd0b5a9bc76e63f7a4a7d7a1..e6943822cd1c003d666178ea26f7b24e56ad210f 100644 (file)
@@ -67,4 +67,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
diff --git a/Documentation/git-citool.txt b/Documentation/git-citool.txt
new file mode 100644 (file)
index 0000000..5217ab2
--- /dev/null
@@ -0,0 +1,32 @@
+git-citool(1)
+=============
+
+NAME
+----
+git-citool - Graphical alternative to git-commit
+
+SYNOPSIS
+--------
+'git citool'
+
+DESCRIPTION
+-----------
+A Tcl/Tk based graphical interface to review modified files, stage
+them into the index, enter a commit message and record the new
+commit onto the current branch.  This interface is an alternative
+to the less interactive gitlink:git-commit[1] program.
+
+git-citool is actually a standard alias for 'git gui citool'.
+See gitlink:git-gui[1] for more details.
+
+Author
+------
+Written by Shawn O. Pearce <spearce@spearce.org>.
+
+Documentation
+--------------
+Documentation by Shawn O. Pearce <spearce@spearce.org>.
+
+GIT
+---
+Part of the gitlink:git[7] suite
index ac938d39df7a4b5b5ea3e4ca8cb2cf505fc49752..2f39864b8e0637f94ccd6104c7651de110a5fe4f 100644 (file)
@@ -106,8 +106,9 @@ OPTIONS
        as patches.
 
 <repository>::
-       The (possibly remote) repository to clone from.  It can
-       be any URL git-fetch supports.
+       The (possibly remote) repository to clone from.  See the
+       <<URLS,URLS>> section below for more information on specifying
+       repositories.
 
 <directory>::
        The name of a new directory to clone into.  The "humanish"
@@ -116,6 +117,8 @@ OPTIONS
        for "host.xz:foo/.git").  Cloning into an existing directory
        is not allowed.
 
+include::urls.txt[]
+
 Examples
 --------
 
@@ -175,4 +178,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 504a3aa1b460ffac9308bec4ff72cf657f8fec30..9586b9729151efd64b3cf5f5d511dd39b664e08e 100644 (file)
@@ -40,7 +40,7 @@ OPTIONS
 
 -p <parent commit>::
        Each '-p' indicates the id of a parent commit object.
-       
+
 
 Commit Information
 ------------------
@@ -107,4 +107,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 387d7bc84123d7a4e694104b5e59fa7535fceda7..5f66a7fcd5907b26ff6bdf94b53c2619c1eff509 100644 (file)
@@ -9,17 +9,17 @@ git-config - Get and set repository or global options
 SYNOPSIS
 --------
 [verse]
-'git-config' [--system | --global] name [value [value_regex]]
-'git-config' [--system | --global] --add name value
-'git-config' [--system | --global] --replace-all name [value [value_regex]]
-'git-config' [--system | --global] [type] --get name [value_regex]
-'git-config' [--system | --global] [type] --get-all name [value_regex]
-'git-config' [--system | --global] [type] --get-regexp name_regex [value_regex]
+'git-config' [--system | --global] [type] [-z|--null] name [value [value_regex]]
+'git-config' [--system | --global] [type] --add name value
+'git-config' [--system | --global] [type] --replace-all name [value [value_regex]]
+'git-config' [--system | --global] [type] [-z|--null] --get name [value_regex]
+'git-config' [--system | --global] [type] [-z|--null] --get-all name [value_regex]
+'git-config' [--system | --global] [type] [-z|--null] --get-regexp name_regex [value_regex]
 'git-config' [--system | --global] --unset name [value_regex]
 'git-config' [--system | --global] --unset-all name [value_regex]
 'git-config' [--system | --global] --rename-section old_name new_name
 'git-config' [--system | --global] --remove-section name
-'git-config' [--system | --global] -l | --list
+'git-config' [--system | --global] [-z|--null] -l | --list
 
 DESCRIPTION
 -----------
@@ -37,8 +37,7 @@ prepend a single exclamation mark in front (see also <<EXAMPLES>>).
 The type specifier can be either '--int' or '--bool', which will make
 'git-config' ensure that the variable(s) are of the given type and
 convert the value to the canonical form (simple decimal number for int,
-a "true" or "false" string for bool).  Type specifiers currently only
-take effect for reading operations.  If no type specifier is passed,
+a "true" or "false" string for bool).  If no type specifier is passed,
 no checks or transformations are performed on the value.
 
 This command will fail if:
@@ -118,6 +117,14 @@ See also <<FILES>>.
        in the config file will cause the value to be multiplied
        by 1024, 1048576, or 1073741824 prior to output.
 
+-z, --null::
+       For all options that output values and/or keys, always
+       end values with with the null character (instead of a
+       newline). Use newline instead as a delimiter between
+       key and value. This allows for secure parsing of the
+       output without getting confused e.g. by values that
+       contain line breaks.
+
 
 [[FILES]]
 FILES
@@ -293,4 +300,3 @@ Documentation by Johannes Schindelin, Petr Baudis and the git-list <git@vger.ker
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index b1220c06e193ddf3942da6e5e0faf91368d0886a..9718abf86d8cd36ddae1eae8cf2337e35b927959 100644 (file)
@@ -26,4 +26,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 91c8c92c76648ed5bfdaab6b991e7cb1ce519733..81614111a4bb3bf8ab62650876189ceee5bd6c9e 100644 (file)
@@ -35,4 +35,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index f3590dee04f801f79cf6400a30a0d9c6f4169154..6c423e3a2f1c69e523eeb9cc092126adc2691803 100644 (file)
@@ -8,25 +8,25 @@ git-cvsexportcommit - Export a single commit to a CVS checkout
 
 SYNOPSIS
 --------
-'git-cvsexportcommit' [-h] [-v] [-c] [-P] [-p] [-a] [-d cvsroot] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
+'git-cvsexportcommit' [-h] [-u] [-v] [-c] [-P] [-p] [-a] [-d cvsroot] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
 
 
 DESCRIPTION
 -----------
 Exports a commit from GIT to a CVS checkout, making it easier
-to merge patches from a git repository into a CVS repository. 
+to merge patches from a git repository into a CVS repository.
 
-Execute it from the root of the CVS working copy. GIT_DIR must be defined. 
+Execute it from the root of the CVS working copy. GIT_DIR must be defined.
 See examples below.
 
-It does its best to do the safe thing, it will check that the files are 
-unchanged and up to date in the CVS checkout, and it will not autocommit 
+It does its best to do the safe thing, it will check that the files are
+unchanged and up to date in the CVS checkout, and it will not autocommit
 by default.
 
 Supports file additions, removals, and commits that affect binary files.
 
 If the commit is a merge commit, you must tell git-cvsexportcommit what parent
-should the changeset be done against. 
+should the changeset be done against.
 
 OPTIONS
 -------
@@ -55,9 +55,12 @@ OPTIONS
        Force the parent commit, even if it is not a direct parent.
 
 -m::
-       Prepend the commit message with the provided prefix. 
+       Prepend the commit message with the provided prefix.
        Useful for patch series and the like.
 
+-u::
+       Update affected files from cvs repository before attempting export.
+
 -v::
        Verbose.
 
@@ -70,7 +73,7 @@ Merge one patch into CVS::
 $ export GIT_DIR=~/project/.git
 $ cd ~/project_cvs_checkout
 $ git-cvsexportcommit -v <commit-sha1>
-$ cvs commit -F .mgs <files> 
+$ cvs commit -F .mgs <files>
 ------------
 
 Merge pending patches into CVS automatically -- only if you really know what you are doing::
@@ -92,4 +95,3 @@ Documentation by Martin Langhoff <martin@catalyst.net.nz>
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index e0be8565468c0b278147abc3e83eb7d19f481a40..fdd7ec7edd8d655a1f660db7eca90ee8cfa9ffc2 100644 (file)
@@ -13,7 +13,7 @@ SYNOPSIS
              [-A <author-conv-file>] [-p <options-for-cvsps>] [-P <file>]
              [-C <git_repository>] [-z <fuzz>] [-i] [-k] [-u] [-s <subst>]
              [-a] [-m] [-M <regex>] [-S <regex>] [-L <commitlimit>]
-             [<CVS_module>]
+             [-r <remote>] [<CVS_module>]
 
 
 DESCRIPTION
@@ -25,10 +25,12 @@ Splitting the CVS log into patch sets is done by 'cvsps'.
 At least version 2.1 is required.
 
 You should *never* do any work of your own on the branches that are
-created by git-cvsimport. The initial import will create and populate a
+created by git-cvsimport.  By default initial import will create and populate a
 "master" branch from the CVS repository's main branch which you're free
 to work with; after that, you need to 'git merge' incremental imports, or
-any CVS branches, yourself.
+any CVS branches, yourself.  It is advisable to specify a named remote via
+-r to separate and protect the incoming branches.
+
 
 OPTIONS
 -------
@@ -37,7 +39,7 @@ OPTIONS
 
 -d <CVSROOT>::
        The root of the CVS archive. May be local (a simple path) or remote;
-       currently, only the :local:, :ext: and :pserver: access methods 
+       currently, only the :local:, :ext: and :pserver: access methods
        are supported. If not given, git-cvsimport will try to read it
        from `CVS/Root`. If no such file exists, it checks for the
        `CVSROOT` environment variable.
@@ -51,10 +53,19 @@ OPTIONS
         The git repository to import to.  If the directory doesn't
         exist, it will be created.  Default is the current directory.
 
+-r <remote>::
+       The git remote to import this CVS repository into.
+       Moves all CVS branches into remotes/<remote>/<branch>
+       akin to the git-clone --use-separate-remote option.
+
 -o <branch-for-HEAD>::
-       The 'HEAD' branch from CVS is imported to the 'origin' branch within
-       the git repository, as 'HEAD' already has a special meaning for git.
-       Use this option if you want to import into a different branch.
+       When no remote is specified (via -r) the 'HEAD' branch
+       from CVS is imported to the 'origin' branch within the git
+       repository, as 'HEAD' already has a special meaning for git.
+       When a remote is specified the 'HEAD' branch is named
+       remotes/<remote>/master mirroring git-clone behaviour.
+       Use this option if you want to import into a different
+       branch.
 +
 Use '-o master' for continuing an import that was initially done by
 the old cvs2git tool.
@@ -67,7 +78,7 @@ the old cvs2git tool.
 -k::
        Kill keywords: will extract files with '-kk' from the CVS archive
        to avoid noisy changesets. Highly recommended, but off by default
-       to preserve compatibility with early imported trees. 
+       to preserve compatibility with early imported trees.
 
 -u::
        Convert underscores in tag and branch names to dots.
@@ -89,15 +100,15 @@ If you need to pass multiple options, separate them with a comma.
        Instead of calling cvsps, read the provided cvsps output file. Useful
        for debugging or when cvsps is being handled outside cvsimport.
 
--m::    
+-m::
        Attempt to detect merges based on the commit message. This option
-       will enable default regexes that try to capture the name source 
-       branch name from the commit message. 
+       will enable default regexes that try to capture the name source
+       branch name from the commit message.
 
 -M <regex>::
        Attempt to detect merges based on the commit message with a custom
        regex. It can be used with '-m' to also see the default regexes.
-       You must escape forward slashes. 
+       You must escape forward slashes.
 
 -S <regex>::
        Skip paths matching the regex.
@@ -156,4 +167,3 @@ Documentation by Matthias Urlichs <smurf@smurf.noris.de>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index e5005f02f997437da3251f6c52c6efbdf06557b4..60d0bcf0f31e6b4da6e56d7726ed942744704cbb 100644 (file)
@@ -7,10 +7,53 @@ git-cvsserver - A CVS server emulator for git
 
 SYNOPSIS
 --------
+
+SSH:
+
 [verse]
 export CVS_SERVER=git-cvsserver
 'cvs' -d :ext:user@server/path/repo.git co <HEAD_name>
 
+pserver (/etc/inetd.conf):
+
+[verse]
+cvspserver stream tcp nowait nobody /usr/bin/git-cvsserver git-cvsserver pserver
+
+Usage:
+
+[verse]
+'git-cvsserver' [options] [pserver|server] [<directory> ...]
+
+OPTIONS
+-------
+
+All these options obviously only make sense if enforced by the server side.
+They have been implemented to resemble the gitlink:git-daemon[1] options as
+closely as possible.
+
+--base-path <path>::
+Prepend 'path' to requested CVSROOT
+
+--strict-paths::
+Don't allow recursing into subdirectories
+
+--export-all::
+Don't check for `gitcvs.enabled` in config. You also have to specify a list
+of allowed directories (see below) if you want to use this option.
+
+--version, -V::
+Print version information and exit
+
+--help, -h, -H::
+Print usage information and exit
+
+<directory>::
+You can specify a list of allowed directories. If no directories
+are given, all are allowed. This is an additional restriction, gitcvs
+access still needs to be enabled by the `gitcvs.enabled` config option
+unless '--export-all' was given, too.
+
+
 DESCRIPTION
 -----------
 
index 9ddab712031cc2b71ccfc83dd5b6b475b5bfc809..4b30b18b427c6f4922ce44eee68042c036a6e806 100644 (file)
@@ -235,4 +235,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 47a583d3a605d95fb860e6ea7142cebf374ec5aa..ac23e28f2759222bb67fcf2445c229e918d96211 100644 (file)
@@ -8,7 +8,7 @@ git-describe - Show the most recent tag that is reachable from a commit
 
 SYNOPSIS
 --------
-'git-describe' [--all] [--tags] [--abbrev=<n>] <committish>...
+'git-describe' [--all] [--tags] [--contains] [--abbrev=<n>] <committish>...
 
 DESCRIPTION
 -----------
@@ -31,6 +31,11 @@ OPTIONS
        Instead of using only the annotated tags, use any tag
        found in `.git/refs/tags`.
 
+--contains::
+       Instead of finding the tag that predates the commit, find
+       the tag that comes after the commit, and thus contains it.
+       Automatically implies --tags.
+
 --abbrev=<n>::
        Instead of using the default 8 hexadecimal digits as the
        abbreviated object name, use <n> digits.
@@ -119,4 +124,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 2e1e29ef5ae633a005e35f656f30ce66e343de7a..d8a0a86022b805eabe3516fe980d6c626abfa68e 100644 (file)
@@ -26,7 +26,7 @@ include::diff-options.txt[]
        branch" respectively.  With these options, diffs for
        merged entries are not shown.
 +
-The default is to diff against our branch (-2) and the 
+The default is to diff against our branch (-2) and the
 cleanly resolved paths.  The option -0 can be given to
 omit diff output for unmerged entries and just show "Unmerged".
 
@@ -58,4 +58,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 2df581c2c9e598c676fcb95c35c91209d15562ca..7bd262cefd68efe84ff0c405af5eabcdc6f01be8 100644 (file)
@@ -75,7 +75,7 @@ actually doing a "git-write-tree" and comparing that. Except this one is much
 nicer for the case where you just want to check where you are.
 
 So doing a "git-diff-index --cached" is basically very useful when you are
-asking yourself "what have I already marked for being committed, and 
+asking yourself "what have I already marked for being committed, and
 what's the difference to a previous tree".
 
 Non-cached Mode
@@ -130,4 +130,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 6e660e2d08c2d9d795b5ccfb91f755160cf58930..6b3f74efe7405b2b1c2d92a975aadb4363a67be0 100644 (file)
@@ -166,4 +166,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 044cee9b425bedc7addd9a4418b553557902711b..639b969315d4c9c6ece95cdeb10c2f92bd17adab 100644 (file)
@@ -138,4 +138,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 8d06775a6bd5f4ac8bd5a20fba67f76c121380ee..5eacab08dc2141360209534bc38a5fc8b7a05b75 100644 (file)
@@ -908,4 +908,3 @@ Documentation by Shawn O. Pearce <spearce@spearce.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 5fbeab76b7214f871865eaefd5dbe744036676b0..900347359645846dd1b501828e77c5e55cb4bfaf 100644 (file)
@@ -35,7 +35,7 @@ include::fetch-options.txt[]
 
 include::pull-fetch-param.txt[]
 
-include::urls.txt[]
+include::urls-remotes.txt[]
 
 SEE ALSO
 --------
diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
new file mode 100644 (file)
index 0000000..eaea82d
--- /dev/null
@@ -0,0 +1,273 @@
+git-filter-branch(1)
+====================
+
+NAME
+----
+git-filter-branch - Rewrite branches
+
+SYNOPSIS
+--------
+[verse]
+'git-filter-branch' [--env-filter <command>] [--tree-filter <command>]
+       [--index-filter <command>] [--parent-filter <command>]
+       [--msg-filter <command>] [--commit-filter <command>]
+       [--tag-name-filter <command>] [--subdirectory-filter <directory>]
+       [-d <directory>] <new-branch-name> [<rev-list options>...]
+
+DESCRIPTION
+-----------
+Lets you rewrite git revision history by creating a new branch from
+your current branch, applying custom filters on each revision.
+Those filters can modify each tree (e.g. removing a file or running
+a perl rewrite on all files) or information about each commit.
+Otherwise, all information (including original commit times or merge
+information) will be preserved.
+
+The command takes the new branch name as a mandatory argument and
+the filters as optional arguments.  If you specify no filters, the
+commits will be recommitted without any changes, which would normally
+have no effect and result in the new branch pointing to the same
+branch as your current branch.  Nevertheless, this may be useful in
+the future for compensating for some git bugs or such, therefore
+such a usage is permitted.
+
+*WARNING*! The rewritten history will have different object names for all
+the objects and will not converge with the original branch.  You will not
+be able to easily push and distribute the rewritten branch on top of the
+original branch.  Please do not use this command if you do not know the
+full implications, and avoid using it anyway, if a simple single commit
+would suffice to fix your problem.
+
+Always verify that the rewritten version is correct before disposing
+the original branch.
+
+Note that since this operation is extensively I/O expensive, it might
+be a good idea to redirect the temporary directory off-disk, e.g. on
+tmpfs.  Reportedly the speedup is very noticeable.
+
+
+Filters
+~~~~~~~
+
+The filters are applied in the order as listed below.  The <command>
+argument is always evaluated in shell using the 'eval' command (with the
+notable exception of the commit filter, for technical reasons).
+Prior to that, the $GIT_COMMIT environment variable will be set to contain
+the id of the commit being rewritten.  Also, GIT_AUTHOR_NAME,
+GIT_AUTHOR_EMAIL, GIT_AUTHOR_DATE, GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL,
+and GIT_COMMITTER_DATE are set according to the current commit.
+
+A 'map' function is available that takes an "original sha1 id" argument
+and outputs a "rewritten sha1 id" if the commit has been already
+rewritten, and "original sha1 id" otherwise; the 'map' function can
+return several ids on separate lines if your commit filter emitted
+multiple commits.
+
+
+OPTIONS
+-------
+
+--env-filter <command>::
+       This is the filter for modifying the environment in which
+       the commit will be performed.  Specifically, you might want
+       to rewrite the author/committer name/email/time environment
+       variables (see gitlink:git-commit[1] for details).  Do not forget
+       to re-export the variables.
+
+--tree-filter <command>::
+       This is the filter for rewriting the tree and its contents.
+       The argument is evaluated in shell with the working
+       directory set to the root of the checked out tree.  The new tree
+       is then used as-is (new files are auto-added, disappeared files
+       are auto-removed - neither .gitignore files nor any other ignore
+       rules *HAVE ANY EFFECT*!).
+
+--index-filter <command>::
+       This is the filter for rewriting the index.  It is similar to the
+       tree filter but does not check out the tree, which makes it much
+       faster.  For hairy cases, see gitlink:git-update-index[1].
+
+--parent-filter <command>::
+       This is the filter for rewriting the commit's parent list.
+       It will receive the parent string on stdin and shall output
+       the new parent string on stdout.  The parent string is in
+       a format accepted by gitlink:git-commit-tree[1]: empty for
+       the initial commit, "-p parent" for a normal commit and
+       "-p parent1 -p parent2 -p parent3 ..." for a merge commit.
+
+--msg-filter <command>::
+       This is the filter for rewriting the commit messages.
+       The argument is evaluated in the shell with the original
+       commit message on standard input; its standard output is
+       used as the new commit message.
+
+--commit-filter <command>::
+       This is the filter for performing the commit.
+       If this filter is specified, it will be called instead of the
+       gitlink:git-commit-tree[1] command, with arguments of the form
+       "<TREE_ID> [-p <PARENT_COMMIT_ID>]..." and the log message on
+       stdin.  The commit id is expected on stdout.
++
+As a special extension, the commit filter may emit multiple
+commit ids; in that case, ancestors of the original commit will
+have all of them as parents.
+
+--tag-name-filter <command>::
+       This is the filter for rewriting tag names. When passed,
+       it will be called for every tag ref that points to a rewritten
+       object (or to a tag object which points to a rewritten object).
+       The original tag name is passed via standard input, and the new
+       tag name is expected on standard output.
++
+The original tags are not deleted, but can be overwritten;
+use "--tag-name-filter=cat" to simply update the tags.  In this
+case, be very careful and make sure you have the old tags
+backed up in case the conversion has run afoul.
++
+Note that there is currently no support for proper rewriting of
+tag objects; in layman terms, if the tag has a message or signature
+attached, the rewritten tag won't have it.  Sorry.  (It is by
+definition impossible to preserve signatures at any rate.)
+
+--subdirectory-filter <directory>::
+       Only look at the history which touches the given subdirectory.
+       The result will contain that directory (and only that) as its
+       project root.
+
+-d <directory>::
+       Use this option to set the path to the temporary directory used for
+       rewriting.  When applying a tree filter, the command needs to
+       temporary checkout the tree to some directory, which may consume
+       considerable space in case of large projects.  By default it
+       does this in the '.git-rewrite/' directory but you can override
+       that choice by this parameter.
+
+<rev-list-options>::
+       When options are given after the new branch name, they will
+       be passed to gitlink:git-rev-list[1].  Only commits in the resulting
+       output will be filtered, although the filtered commits can still
+       reference parents which are outside of that set.
+
+
+Examples
+--------
+
+Suppose you want to remove a file (containing confidential information
+or copyright violation) from all commits:
+
+-------------------------------------------------------
+git filter-branch --tree-filter 'rm filename' newbranch
+-------------------------------------------------------
+
+A significantly faster version:
+
+-------------------------------------------------------------------------------
+git filter-branch --index-filter 'git update-index --remove filename' newbranch
+-------------------------------------------------------------------------------
+
+Now, you will get the rewritten history saved in the branch 'newbranch'
+(your current branch is left untouched).
+
+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:
+
+------------------------------------------------------------------------
+git filter-branch --parent-filter 'sed "s/^\$/-p <graft-id>/"' newbranch
+------------------------------------------------------------------------
+
+(if the parent string is empty - therefore we are dealing with the
+initial commit - add graftcommit as a parent).  Note that this assumes
+history with a single root (that is, no merge without common ancestors
+happened).  If this is not the case, use:
+
+-------------------------------------------------------------------------------
+git filter-branch --parent-filter \
+       'cat; test $GIT_COMMIT = <commit-id> && echo "-p <graft-id>"' newbranch
+-------------------------------------------------------------------------------
+
+or even simpler:
+
+-----------------------------------------------
+echo "$commit-id $graft-id" >> .git/info/grafts
+git filter-branch newbranch $graft-id..
+-----------------------------------------------
+
+To remove commits authored by "Darl McBribe" from the history:
+
+------------------------------------------------------------------------------
+git filter-branch --commit-filter '
+       if [ "$GIT_AUTHOR_NAME" = "Darl McBribe" ];
+       then
+               shift;
+               while [ -n "$1" ];
+               do
+                       shift;
+                       echo "$1";
+                       shift;
+               done;
+       else
+               git commit-tree "$@";
+       fi' newbranch
+------------------------------------------------------------------------------
+
+The shift magic first throws away the tree id and then the -p
+parameters.  Note that this handles merges properly! In case Darl
+committed a merge between P1 and P2, it will be propagated properly
+and all children of the merge will become merge commits with P1,P2
+as their parents instead of the merge commit.
+
+To restrict rewriting to only part of the history, specify a revision
+range in addition to the new branch name.  The new branch name will
+point to the top-most revision that a 'git rev-list' of this range
+will print.
+
+Note that the changes introduced by the commits, and not reverted by
+subsequent commits, will still be in the rewritten branch. If you want
+to throw out _changes_ together with the commits, you should use the
+interactive mode of gitlink:git-rebase[1].
+
+Consider this history:
+
+------------------
+     D--E--F--G--H
+    /     /
+A--B-----C
+------------------
+
+To rewrite only commits D,E,F,G,H, but leave A, B and C alone, use:
+
+--------------------------------
+git filter-branch ... new-H C..H
+--------------------------------
+
+To rewrite commits E,F,G,H, use one of these:
+
+----------------------------------------
+git filter-branch ... new-H C..H --not D
+git filter-branch ... new-H D..H --not C
+----------------------------------------
+
+To move the whole tree into a subdirectory, or remove it from there:
+
+---------------------------------------------------------------
+git filter-branch --index-filter \
+       'git ls-files -s | sed "s-\t-&newsubdir/-" |
+               GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
+                       git update-index --index-info &&
+        mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' directorymoved
+---------------------------------------------------------------
+
+
+Author
+------
+Written by Petr "Pasky" Baudis <pasky@suse.cz>,
+and the git list <git@vger.kernel.org>
+
+Documentation
+--------------
+Documentation by Petr Baudis and the git list.
+
+GIT
+---
+Part of the gitlink:git[7] suite
index 4913c2552f9a092dbd982b55c7e7cb2ffc986570..6affc5bb4d1730805e1704af1045bb71ca896dbb 100644 (file)
@@ -60,4 +60,3 @@ Documentation by Petr Baudis, Junio C Hamano and the git-list <git@vger.kernel.o
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 0ca58a7eb36fb4b29ea485a098a12660360a2252..6cbcf937bcd3128b27fbce673d8500590a3f66ce 100644 (file)
@@ -11,7 +11,8 @@ SYNOPSIS
 [verse]
 'git-format-patch' [-n | -k] [-o <dir> | --stdout] [--thread]
                    [--attach[=<boundary>] | --inline[=<boundary>]]
-                   [-s | --signoff] [<common diff options>] [--start-number <n>]
+                   [-s | --signoff] [<common diff options>]
+                   [--start-number <n>] [--numbered-files]
                    [--in-reply-to=Message-Id] [--suffix=.<sfx>]
                    [--ignore-if-in-upstream]
                    [--subject-prefix=Subject-Prefix]
@@ -30,9 +31,11 @@ gitlink:git-rev-parse[1].
 The output of this command is convenient for e-mail submission or
 for use with gitlink:git-am[1].
 
-Each output file is numbered sequentially from 1, and uses the
+By default, each output file is numbered sequentially from 1, and uses the
 first line of the commit message (massaged for pathname safety) as
-the filename. The names of the output files are printed to standard
+the filename. With the --numbered-files option, the output file names
+will only be numbers, without the first line of the commit appended.
+The names of the output files are printed to standard
 output, unless the --stdout option is specified.
 
 If -o is specified, output files are created in <dir>.  Otherwise
@@ -63,6 +66,11 @@ include::diff-options.txt[]
 --start-number <n>::
        Start numbering the patches at <n> instead of 1.
 
+--numbered-files::
+       Output file names will be a simple number sequence
+       without the default first line of the commit appended.
+       Mutually exclusive with the --stdout option.
+
 -k|--keep-subject::
        Do not strip/add '[PATCH]' from the first line of the
        commit log message.
@@ -121,12 +129,13 @@ not add any suffix.
 CONFIGURATION
 -------------
 You can specify extra mail header lines to be added to each
-message in the repository configuration.  Also you can specify
-the default suffix different from the built-in one:
+message in the repository configuration.  You can also specify
+new defaults for the subject prefix and file suffix.
 
 ------------
 [format]
         headers = "Organization: git-foo\n"
+        subjectprefix = CHANGE
         suffix = .txt
 ------------
 
@@ -173,4 +182,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 8c68cf037259b3abc7ea16952d232b2fb2f07a25..1a432f231970e4eb06ee9bad0cc7a4b550d17762 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 --------
 [verse]
 'git-fsck' [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]
-                [--full] [--strict] [<object>*]
+        [--full] [--strict] [--verbose] [--lost-found] [<object>*]
 
 DESCRIPTION
 -----------
@@ -61,6 +61,13 @@ index file and all SHA1 references in .git/refs/* as heads.
        objects that triggers this check, but it is recommended
        to check new projects with this flag.
 
+--verbose::
+       Be chatty.
+
+--lost-found::
+       Write dangling refs into .git/lost-found/commit/ or
+       .git/lost-found/other/, depending on type.
+
 It tests SHA1 and general object sanity, and it does full tracking of
 the resulting reachability and everything else. It prints out any
 corruption it finds (missing or bad objects), and if you use the
@@ -142,4 +149,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index bc1658434a61bdba41699859f103a3c8e0802d95..c7742ca9630b13d1eeef16d175f8ca840ddff4b0 100644 (file)
@@ -8,7 +8,7 @@ git-gc - Cleanup unnecessary files and optimize the local repository
 
 SYNOPSIS
 --------
-'git-gc' [--prune]
+'git-gc' [--prune] [--aggressive]
 
 DESCRIPTION
 -----------
@@ -35,6 +35,13 @@ OPTIONS
        repository at the same time (e.g. never use this option
        in a cron script).
 
+--aggressive::
+       Usually 'git-gc' runs very quickly while providing good disk
+       space utilization and performance.  This option will cause
+       git-gc to more aggressively optimize the repository at the expense
+       of taking much more time.  The effects of this optimization are
+       persistent, so this option only needs to be used occasionally; every
+       few hundred changesets or so.
 
 Configuration
 -------------
@@ -67,6 +74,13 @@ The optional configuration variable 'gc.packrefs' determines if
 is not run in bare repositories by default, to allow older dumb-transport
 clients fetch from the repository,  but this will change in the future.
 
+The optional configuration variable 'gc.aggressiveWindow' controls how
+much time is spent optimizing the delta compression of the objects in
+the repository when the --aggressive option is specified.  The larger
+the value, the more time is spent optimizing the delta compression.  See
+the documentation for the --window' option in gitlink:git-repack[1] for
+more details.  This defaults to 10.
+
 See Also
 --------
 gitlink:git-prune[1]
index 48805b651ca8161a87448f307b45c9e9d4df3c0f..9b5f86fc30aecc5e1183e514d5d0f81d14a751c3 100644 (file)
@@ -34,4 +34,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index c5a5dad1ce27dde6c3846beaf7ab2f7aa8ed81c8..97faaa1d3a9d8c7025ab33c3126ba10e4c5ed708 100644 (file)
@@ -144,4 +144,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
diff --git a/Documentation/git-gui.txt b/Documentation/git-gui.txt
new file mode 100644 (file)
index 0000000..bd613b2
--- /dev/null
@@ -0,0 +1,115 @@
+git-gui(1)
+==========
+
+NAME
+----
+git-gui - A portable graphical interface to Git
+
+SYNOPSIS
+--------
+'git gui' [<command>] [arguments]
+
+DESCRIPTION
+-----------
+A Tcl/Tk based graphical user interface to Git.  git-gui focuses
+on allowing users to make changes to their repository by making
+new commits, amending existing ones, creating branches, performing
+local merges, and fetching/pushing to remote repositories.
+
+Unlike gitlink:gitk[1], git-gui focuses on commit generation
+and single file annotation, and does not show project history.
+It does however supply menu actions to start a gitk session from
+within git-gui.
+
+git-gui is known to work on all popular UNIX systems, Mac OS X,
+and Windows (under both Cygwin and MSYS).  To the extent possible
+OS specific user interface guidelines are followed, making git-gui
+a fairly native interface for users.
+
+COMMANDS
+--------
+blame::
+       Start a blame viewer on the specified file on the given
+       version (or working directory if not specified).
+
+browser::
+       Start a tree browser showing all files in the specified
+       commit (or 'HEAD' by default).  Files selected through the
+       browser are opened in the blame viewer.
+
+citool::
+       Start git-gui and arrange to make exactly one commit before
+       exiting and returning to the shell.  The interface is limited
+       to only commit actions, slightly reducing the application's
+       startup time and simplifying the menubar.
+
+version::
+       Display the currently running version of git-gui.
+
+
+Examples
+--------
+git gui blame Makefile::
+
+       Show the contents of the file 'Makefile' in the current
+       working directory, and provide annotations for both the
+       original author of each line, and who moved the line to its
+       current location.  The uncommitted file is annotated, and
+       uncommitted changes (if any) are explicitly attributed to
+       'Not Yet Committed'.
+
+git gui blame v0.99.8 Makefile::
+
+       Show the contents of 'Makefile' in revision 'v0.99.8'
+       and provide annotations for each line.  Unlike the above
+       example the file is read from the object database and not
+       the working directory.
+
+git gui citool::
+
+       Make one commit and return to the shell when it is complete.
+
+git citool::
+
+       Same as 'git gui citool' (above).
+
+git gui browser maint::
+
+       Show a browser for the tree of the 'maint' branch.  Files
+       selected in the browser can be viewed with the internal
+       blame viewer.
+
+See Also
+--------
+'gitk(1)'::
+       The git repository browser.  Shows branches, commit history
+       and file differences.  gitk is the utility started by
+       git-gui's Repository Visualize actions.
+
+Other
+-----
+git-gui is actually maintained as an independent project, but stable
+versions are distributed as part of the Git suite for the convience
+of end users.
+
+A git-gui development repository can be obtained from:
+
+  git clone git://repo.or.cz/git-gui.git
+
+or
+
+  git clone http://repo.or.cz/r/git-gui.git
+
+or browsed online at http://repo.or.cz/w/git-gui.git/[].
+
+Author
+------
+Written by Shawn O. Pearce <spearce@spearce.org>.
+
+Documentation
+--------------
+Documentation by Shawn O. Pearce <spearce@spearce.org>.
+
+GIT
+---
+Part of the gitlink:git[7] suite
index 5edc36f060f7cf6444dd016cbb7e073af923f5db..616f196d81ca54595dc67f4846bace5880b9b90d 100644 (file)
@@ -18,7 +18,7 @@ work tree), and optionally writes the resulting object into the
 object database.  Reports its object ID to its standard output.
 This is used by "git-cvsimport" to update the index
 without modifying files in the work tree.  When <type> is not
-specified, it defaults to "blob". 
+specified, it defaults to "blob".
 
 OPTIONS
 -------
@@ -43,4 +43,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 4deabc376c6698408bee032409434bd7e32740a4..45e48453a17d70c559cbc65477cad6610abc5928 100644 (file)
@@ -54,4 +54,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index a15cf5b2a30a6ed2c207622c767d131346936a06..9afb860381369767a0a3f5295f588b75f559ff22 100644 (file)
@@ -52,7 +52,7 @@ Specifying the Refs
 
 A '<ref>' specification can be either a single pattern, or a pair
 of such patterns separated by a colon ":" (this means that a ref name
-cannot have a colon in it).  A single pattern '<name>' is just a 
+cannot have a colon in it).  A single pattern '<name>' is just a
 shorthand for '<name>:<name>'.
 
 Each pattern pair consists of the source side (before the colon)
index 226926964e5f3e6620f20b23b74c0299a168d07f..a8a7f6f04bf5b95a5b325dc2df0adf9d94532bc5 100644 (file)
@@ -98,4 +98,3 @@ Documentation by Sergey Vlasov
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 5412135d763af3a8c68e18441b774654f07eadfd..d4e01cb325150b72a30bde67ba55461d8062fb83 100644 (file)
@@ -8,7 +8,7 @@ git-init-db - Creates an empty git repository
 
 SYNOPSIS
 --------
-'git-init-db' [--template=<template_directory>] [--shared[=<permissions>]]
+'git-init-db' [-q | --quiet] [--template=<template_directory>] [--shared[=<permissions>]]
 
 
 DESCRIPTION
@@ -16,4 +16,3 @@ DESCRIPTION
 
 This is a synonym for gitlink:git-init[1].  Please refer to the
 documentation of that command.
-
index 1b64d3ab03c2e13807e24833823193021559d947..07484a4fd065b639bbf33832cbf642eb8399757e 100644 (file)
@@ -8,7 +8,7 @@ git-init - Create an empty git repository or reinitialize an existing one
 
 SYNOPSIS
 --------
-'git-init' [--template=<template_directory>] [--shared[=<permissions>]]
+'git-init' [-q | --quiet] [--template=<template_directory>] [--shared[=<permissions>]]
 
 
 OPTIONS
@@ -16,6 +16,10 @@ OPTIONS
 
 --
 
+-q, \--quiet::
+
+Only print error and warning messages, all other output will be suppressed.
+
 --template=<template_directory>::
 
 Provide the directory from which templates will be used.  The default template
@@ -108,4 +112,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 9df0ab2d76f6f024a138a84a7fd3c442342c1b88..cec60ee78075aa4411cd637aece93fc38080b0c5 100644 (file)
@@ -82,4 +82,3 @@ Documentation by Eric Wong <normalperson@yhbt.net>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 51389ef37da443c981f3bb5d46f819e90c3d2980..141b76768c61c42e6d876ddb840897cb8805dc96 100644 (file)
@@ -14,6 +14,8 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
+THIS COMMAND IS DEPRECATED.
+
 Duplicates another git repository on a local system.
 
 OPTIONS
@@ -62,4 +64,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 0f353f6558e5843b1534f4cb9acd75746c313510..7adcdefacfd681729317c59ebacfd4a27db1effd 100644 (file)
@@ -52,7 +52,14 @@ include::pretty-options.txt[]
        See also gitlink:git-reflog[1].
 
 --decorate::
-    Print out the ref names of any commits that are shown.
+       Print out the ref names of any commits that are shown.
+
+--full-diff::
+       Without this flag, "git log -p <paths>..." shows commits that
+       touch the specified paths, and diffs about the same specified
+       paths.  With this, the full diff is shown for commits that touch
+       the specified paths; this means that "<paths>..." limits only
+       commits, and doesn't limit diff for those commits.
 
 <paths>...::
        Show only commits that affect the specified paths.
@@ -101,4 +108,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index a78a9ff1b85d1c8cf003ddab63b8412cf3083657..997594549fbf5a1e50a7d187c3cebcbe93461455 100644 (file)
@@ -180,4 +180,3 @@ Documentation by David Greaves, Junio C Hamano, Josh Triplett, and the git-list
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index c254005ca39e6872b8ec7b729246d18757df31d1..93e9a60330797070fc50c0df6c0767b7b81f79c0 100644 (file)
@@ -70,4 +70,3 @@ Written by Junio C Hamano <junkio@cox.net>
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 78993940811c96752e87f7b9e7c1381066056950..7b7859967326acaff157eab01da16b83c1342fcc 100644 (file)
@@ -9,7 +9,7 @@ git-ls-tree - List the contents of a tree object
 SYNOPSIS
 --------
 [verse]
-'git-ls-tree' [-d] [-r] [-t] [-z]
+'git-ls-tree' [-d] [-r] [-t] [-l] [-z]
            [--name-only] [--name-status] [--full-name] [--abbrev=[<n>]]
            <tree-ish> [paths...]
 
@@ -36,6 +36,10 @@ OPTIONS
        Show tree entries even when going to recurse them. Has no effect
        if '-r' was not passed. '-d' implies '-t'.
 
+-l::
+--long::
+       Show object size of blob (file) entries.
+
 -z::
        \0 line termination on output.
 
@@ -65,6 +69,14 @@ Output Format
 When the `-z` option is not used, TAB, LF, and backslash characters
 in pathnames are represented as `\t`, `\n`, and `\\`, respectively.
 
+When the `-l` option is used, format changes to
+
+        <mode> SP <type> SP <object> SP <object size> TAB <file>
+
+Object size identified by <object> is given in bytes, and right-justified
+with minimum width of 7 characters.  Object size is given only for blobs
+(file) entries; for other entries `-` character is used in place of size.
+
 
 Author
 ------
@@ -80,4 +92,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 8eadcebfcf5c26c599cde0d939d1046de69f2335..64aa6a1ea6bca248e7078efcecb3d582cf8a0f5f 100644 (file)
@@ -16,7 +16,7 @@ DESCRIPTION
 Reading a single e-mail message from the standard input, and
 writes the commit log message in <msg> file, and the patches in
 <patch> file.  The author name, e-mail and e-mail subject are
-written out to the standard output to be used by git-applypatch
+written out to the standard output to be used by git-am
 to create a commit.  It is usually not necessary to use this
 command directly.  See gitlink:git-am[1] instead.
 
@@ -67,4 +67,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index c11d6a530f67857bb28a5b3cee48bc5b01f5cb92..c4f4cabbdcdaae18491c301d44fd68ae89b18352 100644 (file)
@@ -7,12 +7,15 @@ git-mailsplit - Simple UNIX mbox splitter program
 
 SYNOPSIS
 --------
-'git-mailsplit' [-b] [-f<nn>] [-d<prec>] -o<directory> [--] [<mbox>...]
+'git-mailsplit' [-b] [-f<nn>] [-d<prec>] -o<directory> [--] [<mbox>|<Maildir>...]
 
 DESCRIPTION
 -----------
-Splits a mbox file into a list of files: "0001" "0002" ..  in the specified
-directory so you can process them further from there.
+Splits a mbox file or a Maildir into a list of files: "0001" "0002" ..  in the
+specified directory so you can process them further from there.
+
+IMPORTANT: Maildir splitting relies upon filenames being sorted to output
+patches in the correct order.
 
 OPTIONS
 -------
@@ -20,6 +23,10 @@ OPTIONS
        Mbox file to split.  If not given, the mbox is read from
        the standard input.
 
+<Maildir>::
+       Root of the Maildir to split. This directory should contain the cur, tmp
+       and new subdirectories.
+
 <directory>::
        Directory in which to place the individual messages.
 
@@ -49,4 +56,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 3190aed10885b5f3471dfc30922c141835d6c4f1..6b71880ec45455b1e62c3e1582d4cf78f2ed4852 100644 (file)
@@ -40,4 +40,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index b8ee1ff2b0681ea9fbc83618b1d09d95f3a902ff..17e9f10c659844e55e56b0d3a005e5f250f43c20 100644 (file)
@@ -59,7 +59,7 @@ Examples:
   This is modified MM in the branch B.                 # merge2
   This is modified MM in the branch B.                 # current contents
 
-or 
+or
 
   torvalds@ppc970:~/merge-test> git-merge-index cat AA MM
   cat: : No such file or directory
@@ -85,4 +85,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index f80ab3b8c479d787e116298f5446d1ff57ff2774..f35d0e1b4560a4970e7423011b585e1ff7d538c1 100644 (file)
@@ -27,4 +27,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 35fb4fb713bac225c665b6d7701efc9f105b9c16..6892fdac3df054e87019318c524185109ea16200 100644 (file)
@@ -34,4 +34,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 9c08efa53abc2797a7b7ca0e589d83b9a4387987..d285cba033325f8652996ea71a06d53c22424dae 100644 (file)
@@ -9,7 +9,7 @@ git-merge - Join two or more development histories together
 SYNOPSIS
 --------
 [verse]
-'git-merge' [-n] [--no-commit] [--squash] [-s <strategy>]...
+'git-merge' [-n] [--summary] [--no-commit] [--squash] [-s <strategy>]...
        [-m <msg>] <remote> <remote>...
 
 DESCRIPTION
@@ -95,7 +95,7 @@ When things cleanly merge, these things happen:
 1. the results are updated both in the index file and in your
    working tree,
 2. index file is written out as a tree,
-3. the tree gets committed, and 
+3. the tree gets committed, and
 4. the `HEAD` pointer gets advanced.
 
 Because of 2., we require that the original state of the index
index add01e855a09c34b6aa9c83af6efcd17f24f3c9d..6c32c6d18ead2047ce590e2853bbc1a5a2dd1e7c 100644 (file)
@@ -25,7 +25,7 @@ OPTIONS
 -t or --tool=<tool>::
        Use the merge resolution program specified by <tool>.
        Valid merge tools are:
-       kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, and opendiff
+       kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, and opendiff
 +
 If a merge resolution program is not specified, 'git mergetool'
 will use the configuration variable merge.tool.  If the
@@ -43,4 +43,3 @@ Documentation by Theodore Y Ts'o.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 2860a3d1ba54c712bb30febfa37693f3efbdb7bf..ea7a75234a91b0dade03b8e19d4ba7d0d1a82f63 100644 (file)
@@ -19,18 +19,18 @@ The output is the new tag's <object> identifier.
 
 Tag Format
 ----------
-A tag signature file has a very simple fixed format: three lines of
+A tag signature file has a very simple fixed format: four lines of
 
   object <sha1>
   type <typename>
   tag <tagname>
+  tagger <tagger>
 
-followed by some 'optional' free-form signature that git itself
-doesn't care about, but that can be verified with gpg or similar.
-
-The size of the full object is artificially limited to 8kB.  (Just
-because I'm a lazy bastard, and if you can't fit a signature in that
-size, you're doing something wrong)
+followed by some 'optional' free-form message (some tags created
+by older git may not have `tagger` line).  The message, when
+exists, is separated by a blank line from the header.  The
+message part may contain a signature that git itself doesn't
+care about, but that can be verified with gpg.
 
 
 Author
@@ -44,4 +44,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 5f9ee603b758ea251a438399a642fa60d364aca2..638abc7d0f7425749339b1519cab5c0586e96138 100644 (file)
@@ -32,4 +32,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 6756b76bb11bc17279c3f20c16d7b4ba131f5832..2c9cf743c7a097ab955938d023e347e866fbc13e 100644 (file)
@@ -51,4 +51,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index d6c8bf800f4456ea63ff7d9b0c01b2d4f0d9d179..91eede120e5e192ac8ce3a483dd6a88dce414333 100644 (file)
@@ -34,6 +34,13 @@ OPTIONS
        Read from stdin, append "(<rev_name>)" to all sha1's of nameable
        commits, and pass to stdout
 
+--name-only::
+       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 ommitted from the name, matching the output
+       of gitlink::git-describe[1] more closely.  This option
+       cannot be combined with --stdin.
+
 EXAMPLE
 -------
 
@@ -69,4 +76,3 @@ Documentation by Johannes Schindelin.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 714abbe28ecfef592d0a7892dccbe88c8f66967c..9967587fe6bef0cf7cc3e93467bd179f6f58b032 100644 (file)
@@ -165,4 +165,3 @@ Written by Sean Estabrooks <seanlkml@sympatico.ca>
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index bd3ee456e336add5d880d6a1192646220e7c34d7..e3549b50442bea1734812ec40331adb7e3d41ef7 100644 (file)
@@ -85,6 +85,11 @@ base-name::
        times to get to the necessary object.
        The default value for --window is 10 and --depth is 50.
 
+--max-pack-size=<n>::
+       Maximum size of each output packfile, expressed in MiB.
+       If specified,  multiple packfiles may be created.
+       The default is unlimited.
+
 --incremental::
        This flag causes an object already in a pack ignored
        even if it appears in the standard input.
@@ -127,6 +132,25 @@ base-name::
        This flag tells the command not to reuse existing deltas
        but compute them from scratch.
 
+--no-reuse-object::
+       This flag tells the command not to reuse existing object data at all,
+       including non deltified object, forcing recompression of everything.
+       This implies --no-reuse-delta. Useful only in the obscure case where
+       wholesale enforcement of a different compression level on the
+       packed data is desired.
+
+--compression=[N]::
+       Specifies compression level for newly-compressed data in the
+       generated pack.  If not specified,  pack compression level is
+       determined first by pack.compression,  then by core.compression,
+       and defaults to -1,  the zlib default,  if neither is set.
+       Data copied from loose objects will be recompressed
+       if core.legacyheaders was true when they were created or if
+       the loose compression level (see core.loosecompression and
+       core.compression) is now a different value than the pack
+       compression level.  Add --no-reuse-object if you want to force
+       a uniform compression level on all data no matter the source.
+
 --delta-base-offset::
        A packed archive can express base object of a delta as
        either 20-byte object name or as an offset in the
@@ -161,4 +185,3 @@ gitlink:git-prune-packed[1]
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 94bbea0db2caf32635cfa8fc199e8150b1cd05f2..f2ceebac4ba57a07d2d9bf2ae1e9f54d003b2d7f 100644 (file)
@@ -17,7 +17,7 @@ are redundant. The output is suitable for piping to
 'xargs rm' if you are in the root of the repository.
 
 git-pack-redundant accepts a list of objects on standard input. Any objects
-given will be ignored when checking which packs are required. This makes the 
+given will be ignored when checking which packs are required. This makes the
 following command useful when wanting to remove packs which contain unreachable
 objects.
 
@@ -55,4 +55,3 @@ gitlink:git-prune-packed[1]
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index a7e9fd021a4cc1e467b2df7dd7e06d79a5182c7a..ad528a922487be06207bdcc38a03fe55fd0f2a5d 100644 (file)
@@ -40,4 +40,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 74f37bd9040200c0dbc82c67b45540e873d4649e..abc171266a35299159308d0653bb0c659b8bdc77 100644 (file)
@@ -52,4 +52,3 @@ Documentation by Junio C Hamano.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 310033e4605d20b99c21a769e79b25b64abbb618..3800edb7bb7d9062dddb3393eaf1a80e5a44596d 100644 (file)
@@ -50,4 +50,3 @@ gitlink:git-repack[1]
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index b8166a210fe5f0a6c5ade480640146684d2517cb..0ace233d18383f53ca4d31baaa8e3c230ddb874b 100644 (file)
@@ -58,4 +58,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 94478ed94d70c597c8a024afe79b456a66d40a35..e1eb2c1d0037f06dbf2b5cc0bde84918157ee2bf 100644 (file)
@@ -29,7 +29,7 @@ include::fetch-options.txt[]
 
 include::pull-fetch-param.txt[]
 
-include::urls.txt[]
+include::urls-remotes.txt[]
 
 include::merge-strategies.txt[]
 
@@ -165,4 +165,3 @@ Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index e9ad10672a7f045f25937ca85caec548fcb4327f..74a0da1ed49f5b3742e97a1475dc671496f481ea 100644 (file)
@@ -53,9 +53,8 @@ side are updated.
 +
 `tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`.
 +
-A parameter <ref> without a colon is equivalent to
-<ref>`:`<ref>, hence updates <ref> in the destination from <ref>
-in the source.
+A parameter <ref> without a colon pushes the <ref> from the source
+repository to the destination repository under the same name.
 +
 Pushing an empty <src> allows you to delete the <dst> ref from
 the remote repository.
@@ -96,7 +95,27 @@ the remote repository.
 -v::
        Run verbosely.
 
-include::urls.txt[]
+include::urls-remotes.txt[]
+
+
+Examples
+--------
+
+git push origin master::
+       Find a ref that matches `master` in the source repository
+       (most likely, it would find `refs/heads/master`), and update
+       the same ref (e.g. `refs/heads/master`) in `origin` repository
+       with it.
+
+git push origin :experimental::
+       Find a ref that matches `experimental` in the `origin` repository
+       (e.g. `refs/heads/experimental`), and delete it.
+
+git push origin master:satellite/master::
+       Find a ref that matches `master` in the source repository
+       (most likely, it would find `refs/heads/master`), and update
+       the ref that matches `satellite/master` (most likely, it would
+       be `refs/remotes/satellite/master`) in `origin` repository with it.
 
 Author
 ------
@@ -110,4 +129,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 296937a4167dc2e4c93cfcafca9fea14090cb108..1c3ef4c59362a1ccc8e44a54738c788f710201be 100644 (file)
@@ -58,4 +58,3 @@ Documentation by Eric Biederman <ebiederm@lnxi.com>
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index acb57447a864a54b3b531b7ef7403563fd20f886..74c5478ba18763de1703f0c8c08c20f1aac02ac0 100644 (file)
@@ -8,7 +8,7 @@ git-read-tree - Reads tree information into the index
 
 SYNOPSIS
 --------
-'git-read-tree' (<tree-ish> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <tree-ish1> [<tree-ish2> [<tree-ish3>]])
+'git-read-tree' (<tree-ish> | [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <tree-ish1> [<tree-ish2> [<tree-ish3>]])
 
 
 DESCRIPTION
@@ -50,6 +50,12 @@ OPTIONS
        trees that are not directly related to the current
        working tree status into a temporary index file.
 
+--trivial::
+       Restrict three-way merge by `git-read-tree` to happen
+       only if there is no file-level merging required, instead
+       of resolving merge for trivial cases and leaving
+       conflicting files unresolved in the index.
+
 --aggressive::
        Usually a three-way merge by `git-read-tree` resolves
        the merge for really trivial cases and leaves other
@@ -356,4 +362,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 753b275a0f79d88ef439a4c235452bd17f81ce2e..96907d48632be36d0d8c66f6a0b4d937b7a38cb6 100644 (file)
@@ -8,7 +8,8 @@ git-rebase - Forward-port local commits to the updated upstream head
 SYNOPSIS
 --------
 [verse]
-'git-rebase' [-v] [--merge] [-C<n>] [--onto <newbase>] <upstream> [<branch>]
+'git-rebase' [-i | --interactive] [-v | --verbose] [--merge] [-C<n>]
+       [-p | --preserve-merges] [--onto <newbase>] <upstream> [<branch>]
 'git-rebase' --continue | --skip | --abort
 
 DESCRIPTION
@@ -208,6 +209,14 @@ OPTIONS
        context exist they all must match.  By default no context is
        ever ignored.
 
+-i, \--interactive::
+       Make a list of the commits which are about to be rebased.  Let the
+       user edit that list before rebasing.
+
+-p, \--preserve-merges::
+       Instead of ignoring merges, try to recreate them.  This option
+       only works in interactive mode.
+
 include::merge-strategies.txt[]
 
 NOTES
@@ -226,9 +235,100 @@ pre-rebase hook script for an example.
 You must be in the top directory of your project to start (or continue)
 a rebase.  Upon completion, <branch> will be the current branch.
 
-Author
+INTERACTIVE MODE
+----------------
+
+Rebasing interactively means that you have a chance to edit the commits
+which are rebased.  You can reorder the commits, and you can
+remove them (weeding out bad or otherwise unwanted patches).
+
+The interactive mode is meant for this type of workflow:
+
+1. have a wonderful idea
+2. hack on the code
+3. prepare a series for submission
+4. submit
+
+where point 2. consists of several instances of
+
+a. regular use
+ 1. finish something worthy of a commit
+ 2. commit
+b. independent fixup
+ 1. realize that something does not work
+ 2. fix that
+ 3. commit it
+
+Sometimes the thing fixed in b.2. cannot be amended to the not-quite
+perfect commit it fixes, because that commit is buried deeply in a
+patch series.  That is exactly what interactive rebase is for: use it
+after plenty of "a"s and "b"s, by rearranging and editing
+commits, and squashing multiple commits into one.
+
+Start it with the last commit you want to retain as-is:
+
+       git rebase -i <after-this-commit>
+
+An editor will be fired up with all the commits in your current branch
+(ignoring merge commits), which come after the given commit.  You can
+reorder the commits in this list to your heart's content, and you can
+remove them.  The list looks more or less like this:
+
+-------------------------------------------
+pick deadbee The oneline of this commit
+pick fa1afe1 The oneline of the next commit
+...
+-------------------------------------------
+
+The oneline descriptions are purely for your pleasure; `git-rebase` will
+not look at them but at the commit names ("deadbee" and "fa1afe1" in this
+example), so do not delete or edit the names.
+
+By replacing the command "pick" with the command "edit", you can tell
+`git-rebase` to stop after applying that commit, so that you can edit
+the files and/or the commit message, amend the commit, and continue
+rebasing.
+
+If you want to fold two or more commits into one, replace the command
+"pick" with "squash" for the second and subsequent commit.  If the
+commits had different authors, it will attribute the squashed commit to
+the author of the last commit.
+
+In both cases, or when a "pick" does not succeed (because of merge
+errors), the loop will stop to let you fix things, and you can continue
+the loop with `git rebase --continue`.
+
+For example, if you want to reorder the last 5 commits, such that what
+was HEAD~4 becomes the new HEAD. To achieve that, you would call
+`git-rebase` like this:
+
+----------------------
+$ git rebase -i HEAD~5
+----------------------
+
+And move the first patch to the end of the list.
+
+You might want to preserve merges, if you have a history like this:
+
+------------------
+           X
+            \
+         A---M---B
+        /
+---o---O---P---Q
+------------------
+
+Suppose you want to rebase the side branch starting at "A" to "Q". Make
+sure that the current HEAD is "B", and call
+
+-----------------------------
+$ git rebase -i -p --onto Q O
+-----------------------------
+
+Authors
 ------
-Written by Junio C Hamano <junkio@cox.net>
+Written by Junio C Hamano <junkio@cox.net> and
+Johannes E. Schindelin <johannes.schindelin@gmx.de>
 
 Documentation
 --------------
@@ -237,4 +337,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 6914aa59c3ae6b8174e865e3c46b68bef4d375ca..4ef18404722e045bbc0b010545b3a34cac2d6586 100644 (file)
@@ -48,8 +48,8 @@ standard input of the hook will be one line per ref to be updated:
 The refname value is relative to $GIT_DIR; e.g. for the master
 head this is "refs/heads/master".  The two sha1 values before
 each refname are the object names for the refname before and after
-the update.  Refs to be created will have sha1-old equal to 0{40},
-while refs to be deleted will have sha1-new equal to 0{40}, otherwise
+the update.  Refs to be created will have sha1-old equal to 0\{40},
+while refs to be deleted will have sha1-new equal to 0\{40}, otherwise
 sha1-old and sha1-new should be valid objects in the repository.
 
 This hook is called before any refname is updated and before any
@@ -71,7 +71,7 @@ The refname parameter is relative to $GIT_DIR; e.g. for the master
 head this is "refs/heads/master".  The two sha1 arguments are
 the object names for the refname before and after the update.
 Note that the hook is called before the refname is updated,
-so either sha1-old is 0{40} (meaning there is no such ref yet),
+so either sha1-old is 0\{40} (meaning there is no such ref yet),
 or it should match what is recorded in refname.
 
 The hook should exit with non-zero status if it wants to disallow
@@ -96,8 +96,8 @@ The refname value is relative to $GIT_DIR; e.g. for the master
 head this is "refs/heads/master".  The two sha1 values before
 each refname are the object names for the refname before and after
 the update.  Refs that were created will have sha1-old equal to
-0{40}, while refs that were deleted will have sha1-new equal to
-0{40}, otherwise sha1-old and sha1-new should be valid objects in
+0\{40}, while refs that were deleted will have sha1-new equal to
+0\{40}, otherwise sha1-old and sha1-new should be valid objects in
 the repository.
 
 Using this hook, it is easy to generate mails describing the updates
index 1e343bcdcdd4c1998b9887866507639bb31d030c..89bc9c51ea13630f6556b12637ce8b1cc483d2fd 100644 (file)
@@ -39,6 +39,19 @@ the current branch. It is basically an alias for 'git log -g --abbrev-commit
 OPTIONS
 -------
 
+--stale-fix::
+       This revamps the logic -- the definition of "broken commit"
+       becomes: a commit that is not reachable from any of the refs and
+       there is a missing object among the commit, tree, or blob
+       objects reachable from it that is not reachable from any of the
+       refs.
++
+This computation involves traversing all the reachable objects, i.e. it
+has the same cost as 'git prune'.  Fortunately, once this is run, we
+should not have to ever worry about missing objects, because the current
+prune and pack-objects know about reflogs and protect objects referred by
+them.
+
 --expire=<time>::
        Entries older than this time are pruned.  Without the
        option it is taken from configuration `gc.reflogExpire`,
@@ -65,4 +78,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index aca60120c8a671465bb83127bde080b94c0bb782..fe631bb3dd9096e831087511202e2771ebb85df4 100644 (file)
@@ -34,4 +34,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index b35c65ba3b7307d6dff600d9d4b4907596ecbe5a..61a6022ce8a0fc7aac8b1e9bd08587817ef0d69c 100644 (file)
@@ -135,4 +135,3 @@ Documentation by J. Bruce Fields and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index c57013b9537f68fafdb1c1d90491ff5d556ed326..28949397ca7434471f1e9c1552ecae1ade9b8313 100644 (file)
@@ -68,6 +68,11 @@ OPTIONS
        to be applied that many times to get to the necessary object.
        The default value for --window is 10 and --depth is 50.
 
+--max-pack-size=<n>::
+       Maximum size of each output packfile, expressed in MiB.
+       If specified,  multiple packfiles may be created.
+       The default is unlimited.
+
 
 Configuration
 -------------
@@ -99,4 +104,3 @@ gitlink:git-prune-packed[1]
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 478a5fd6b74ddbcbf279339a5c3ae5eefb039cb4..087eeb7cc22552b8903e54fc52f08eeb56fb1a0d 100644 (file)
@@ -37,4 +37,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 7ff9b05e680cabc6513f9d8a6aa80eb7eccda82d..c4d4263238e5b7c6dff705de5d8552a577fc35d6 100644 (file)
@@ -23,7 +23,7 @@ initial manual merge, and later by noticing the same automerge
 results and applying the previously recorded hand resolution.
 
 [NOTE]
-You need to create `$GIT_DIR/rr-cache` directory to enable this
+You need to set the config variable rerere.enabled to enable this
 command.
 
 
@@ -171,7 +171,7 @@ records it if it is a new conflict, or reuses the earlier hand
 resolve when it is not.  `git-commit` also invokes `git-rerere`
 when recording a merge result.  What this means is that you do
 not have to do anything special yourself (Note: you still have
-to create `$GIT_DIR/rr-cache` directory to enable this command).
+to set the config variable rerere.enabled to enable this command).
 
 In our example, when you did the test merge, the manual
 resolution is recorded, and it will be reused when you do the
index c3c2043d183e0e6c7292f5af7c28af57958c4dcd..20dcac625204869cf6c426d338f2fafd567368b9 100644 (file)
@@ -16,15 +16,18 @@ SYNOPSIS
             [ \--sparse ]
             [ \--no-merges ]
             [ \--remove-empty ]
+            [ \--full-history ]
             [ \--not ]
             [ \--all ]
             [ \--stdin ]
             [ \--topo-order ]
             [ \--parents ]
+            [ \--timestamp ]
             [ \--left-right ]
             [ \--cherry-pick ]
             [ \--encoding[=<encoding>] ]
             [ \--(author|committer|grep)=<pattern> ]
+            [ \--regexp-ignore-case ] [ \--extended-regexp ]
             [ \--date={local|relative|default} ]
             [ [\--objects | \--objects-edge] [ \--unpacked ] ]
             [ \--pretty | \--header ]
@@ -115,6 +118,9 @@ e.g. "2 hours ago".
 
        Print the parents of the commit.
 
+--timestamp::
+       Print the raw commit timestamp.
+
 --left-right::
 
        Mark which side of a symmetric diff a commit is reachable from.
@@ -214,10 +220,27 @@ limiting may be applied.
        Limit the commits output to ones with log message that
        matches the specified pattern (regular expression).
 
+--regexp-ignore-case::
+
+       Match the regexp limiting patterns without regard to letters case.
+
+--extended-regexp::
+
+       Consider the limiting patterns to be extended regular expressions
+       instead of the default basic regular expressions.
+
 --remove-empty::
 
        Stop when a given path disappears from the tree.
 
+--full-history::
+
+       Show also parts of history irrelevant to current state of a given
+       path. 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.
+
 --no-merges::
 
        Do not print commits with more than one parent.
@@ -261,9 +284,9 @@ excluded from the output.
 +
 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
+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.
 
index 7757abe62190a066b6ad8b57214b70ff3fa0f12a..eea9c9cfe9ec9320b328c37eefb6c7100edab913 100644 (file)
@@ -89,6 +89,17 @@ OPTIONS
 --git-dir::
        Show `$GIT_DIR` if defined else show the path to the .git directory.
 
+--is-inside-git-dir::
+       When the current working directory is below the repository
+       directory print "true", otherwise "false".
+
+--is-inside-work-tree::
+       When the current working directory is inside the work tree of the
+       repository print "true", otherwise "false".
+
+--is-bare-repository::
+       When the repository is bare print "true", otherwise "false".
+
 --short, --short=number::
        Instead of outputting the full SHA1 values of object names try to
        abbreviate them to a shorter unique name. When no length is specified
@@ -286,4 +297,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 8081bbaffa8d3710b644c744b9f81d459938a20e..69db4984473fae7928797bcfb13baf1f0e39d851 100644 (file)
@@ -56,4 +56,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index a65f24a0f698eb801ac43bba5aa7dc746e96edc0..78f45dca2e37415cbeafb02db559edc6ca511d51 100644 (file)
@@ -95,4 +95,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 8bb52f46872194783148851ca2fe81dfb9d13bf7..dee5d0da9db0e8e88f7f2f237fcfe3ca7f5c28ec 100644 (file)
@@ -66,4 +66,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 7ae39fd5a20a869db8c2be101d7001c1c48ff198..293686c31f9c80074d7b6d34fa303f56e19d8113 100644 (file)
@@ -59,9 +59,11 @@ The --cc option must be repeated for each user you want on the cc list.
        Only necessary if --compose is also set.  If --compose
        is not set, this will be prompted for.
 
---no-signed-off-by-cc::
-       Do not add emails found in Signed-off-by: or Cc: lines to the
-       cc list.
+--signed-off-by-cc, --no-signed-off-by-cc::
+        If this is set, add emails found in Signed-off-by: or Cc: lines to the
+        cc list.
+        Default is the value of 'sendemail.signedoffbycc' configuration value;
+        if that is unspecified, default to --signed-off-by-cc.
 
 --quiet::
        Make git-send-email less verbose.  One line per email should be
@@ -78,13 +80,22 @@ The --cc option must be repeated for each user you want on the cc list.
        `localhost` otherwise.
 
 --subject::
-       Specify the initial subject of the email thread.
+       Specify the initial subject of the email thread.
        Only necessary if --compose is also set.  If --compose
        is not set, this will be prompted for.
 
---suppress-from::
-       Do not add the From: address to the cc: list, if it shows up in a From:
-       line.
+--suppress-from, --no-suppress-from::
+        If this is set, do not add the From: address to the cc: list, if it
+        shows up in a From: line.
+        Default is the value of 'sendemail.suppressfrom' configuration value;
+        if that is unspecified, default to --no-supress-from.
+
+--thread, --no-thread::
+       If this is set, the In-Reply-To header will be set on each email sent.
+       If disabled with "--no-thread", no emails will have the In-Reply-To
+       header set.
+       Default is the value of the 'sendemail.thread' configuration value;
+       if that is unspecified, default to --thread.
 
 --dry-run::
        Do everything except actually send the emails.
@@ -137,4 +148,3 @@ Documentation by Ryan Anderson
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 2b2abebd608be337db35a3de4b83d37d43061acb..1ea1faa1b57adecea4269fa6d0c2c4afdee9b3da 100644 (file)
@@ -69,4 +69,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 228b9f14f3530b9ec28e603a3ef2327c7039c440..48f2d57b7b48fa9c8fb0cbc5fcb547d6aed32cbb 100644 (file)
@@ -32,4 +32,3 @@ Documentation by Petr Baudis and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 15cc6f77c1e9b8a77c8396fab99cf9d9fda98ef3..2220ef6ea8d3bfa58f3c1279dfcf4f735c2dae0a 100644 (file)
@@ -56,4 +56,3 @@ Documentation by Junio C Hamano.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index be09b62bebb2b98fa8b0f39e47d29267126fa2a6..764d99356bcefb40a16d3c27bc41e881f87b396a 100644 (file)
@@ -32,4 +32,3 @@ Documentation by Junio C Hamano
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 34c5caf2d08324cc1595013cbdcd40d89d7a1968..a42e1211500a6a6ecdf1d9e1ddbf6712869ceb79 100644 (file)
@@ -84,4 +84,3 @@ This manual page is a stub. You can help the git documentation by expanding it.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 192b1f15a9ca75351623d32e4373d65c6501b465..8d3e2ffb2c907376a485888a3497c938427c27a1 100644 (file)
@@ -13,6 +13,8 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
+THIS COMMAND IS DEPRECATED.
+
 Pulls from a remote repository over ssh connection, invoking
 git-ssh-upload on the other end. It functions identically to
 git-ssh-upload, aside from which end you run it on.
@@ -48,4 +50,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index a9b7e9f974c13252456309c7053537853dc7ea9b..5e2ca8dccfb291bc4c50df3b0a8dfe2f28d07b59 100644 (file)
@@ -12,6 +12,8 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
+THIS COMMAND IS DEPRECATED.
+
 Pushes from a remote repository over ssh connection, invoking
 git-ssh-fetch on the other end. It functions identically to
 git-ssh-fetch, aside from which end you run it on.
@@ -44,4 +46,3 @@ Documentation by Daniel Barkalow
 GIT
 ---
 Part of the gitlink:git[7] suite
-
diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
new file mode 100644 (file)
index 0000000..ad95ed9
--- /dev/null
@@ -0,0 +1,162 @@
+git-stash(1)
+============
+
+NAME
+----
+git-stash - Stash the changes in a dirty working directory away
+
+SYNOPSIS
+--------
+[verse]
+'git-stash' (save | list | show [<stash>] | apply [<stash>] | clear)
+
+DESCRIPTION
+-----------
+
+Use 'git-stash' when you want to record the current state of the
+working directory and the index, but want to go back to a clean
+working directory.  The command saves your local modifications away
+and reverts the working directory to match the `HEAD` commit.
+
+The modifications stashed away by this command can be listed with
+`git-stash list`, inspected with `git-stash show`, and restored
+(potentially on top of a different commit) with `git-stash apply`.
+Calling git-stash without any arguments is equivalent to `git-stash
+save`.
+
+The latest stash you created is stored in `$GIT_DIR/refs/stash`; older
+stashes are found in the reflog of this reference and can be named using
+the usual reflog syntax (e.g. `stash@\{1}` is the most recently
+created stash, `stash@\{2}` is the one before it, `stash@\{2.hours.ago}`
+is also possible).
+
+OPTIONS
+-------
+
+save::
+
+       Save your local modifications to a new 'stash', and run `git-reset
+       --hard` to revert them.  This is the default action when no
+       subcommand is given.
+
+list::
+
+       List the stashes that you currently have.  Each 'stash' is listed
+       with its name (e.g. `stash@\{0}` is the latest stash, `stash@\{1} is
+       the one before, etc.), the name of the branch that was current when the
+       stash was made, and a short description of the commit the stash was
+       based on.
++
+----------------------------------------------------------------
+stash@{0}: submit: 6ebd0e2... Add git-stash
+stash@{1}: master: 9cc0589... Merge branch 'master' of gfi
+----------------------------------------------------------------
+
+show [<stash>]::
+
+       Show the changes recorded in the stash as a diff between the the
+       stashed state and its original parent. When no `<stash>` is given,
+       shows the latest one. By default, the command shows the diffstat, but
+       it will accept any format known to `git-diff` (e.g., `git-stash show
+       -p stash@\{2}` to view the second most recent stash in patch form).
+
+apply [<stash>]::
+
+       Restore the changes recorded in the stash on top of the current
+       working tree state.  When no `<stash>` is given, applies the latest
+       one.  The working directory must match the index.
++
+This operation can fail with conflicts; you need to resolve them
+by hand in the working tree.
+
+clear::
+       Remove all the stashed states. Note that those states will then
+       be subject to pruning, and may be difficult or impossible to recover.
+
+
+DISCUSSION
+----------
+
+A stash is represented as a commit whose tree records the state of the
+working directory, and its first parent is the commit at `HEAD` when
+the stash was created.  The tree of the second parent records the
+state of the index when the stash is made, and it is made a child of
+the `HEAD` commit.  The ancestry graph looks like this:
+
+            .----W
+           /    /
+     -----H----I
+
+where `H` is the `HEAD` commit, `I` is a commit that records the state
+of the index, and `W` is a commit that records the state of the working
+tree.
+
+
+EXAMPLES
+--------
+
+Pulling into a dirty tree::
+
+When you are in the middle of something, you learn that there are
+upstream changes that are possibly relevant to what you are
+doing.  When your local changes do not conflict with the changes in
+the upstream, a simple `git pull` will let you move forward.
++
+However, there are cases in which your local changes do conflict with
+the upstream changes, and `git pull` refuses to overwrite your
+changes.  In such a case, you can stash your changes away,
+perform a pull, and then unstash, like this:
++
+----------------------------------------------------------------
+$ git pull
+...
+file foobar not up to date, cannot merge.
+$ git stash
+$ git pull
+$ git stash apply
+----------------------------------------------------------------
+
+Interrupted workflow::
+
+When you are in the middle of something, your boss comes in and
+demands that you fix something immediately.  Traditionally, you would
+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 ...
+$ git checkout -b my_wip
+$ git commit -a -m "WIP"
+$ git checkout master
+$ edit emergency fix
+$ git commit -a -m "Fix in a hurry"
+$ git checkout my_wip
+$ git reset --soft HEAD^
+... continue hacking ...
+----------------------------------------------------------------
++
+You can use `git-stash` to simplify the above, like this:
++
+----------------------------------------------------------------
+... hack hack hack ...
+$ git stash
+$ edit emergency fix
+$ git commit -a -m "Fix in a hurry"
+$ git stash apply
+... continue hacking ...
+----------------------------------------------------------------
+
+SEE ALSO
+--------
+gitlink:git-checkout[1],
+gitlink:git-commit[1],
+gitlink:git-reflog[1],
+gitlink:git-reset[1]
+
+AUTHOR
+------
+Written by Nanako Shiraishi <nanako3@bluebottle.com>
+
+GIT
+---
+Part of the gitlink:git[7] suite
index 1fd1af102ae948ca008bbd35675d859340e46dbd..6f16eb0328f754b5f5019ff5dac51604de7d535f 100644 (file)
@@ -58,4 +58,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 3a03dd04106d45cc3c233230d1773874f3ca1cef..1306d7bab70efb57cba62a98ebd2d67b06677c97 100644 (file)
@@ -30,4 +30,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
new file mode 100644 (file)
index 0000000..2c48936
--- /dev/null
@@ -0,0 +1,77 @@
+git-submodule(1)
+================
+
+NAME
+----
+git-submodule - Initialize, update or inspect submodules
+
+
+SYNOPSIS
+--------
+[verse]
+'git-submodule' [--quiet] [-b branch] add <repository> [<path>]
+'git-submodule' [--quiet] [--cached] [status|init|update] [--] [<path>...]
+
+
+COMMANDS
+--------
+add::
+       Add the given repository as a submodule at the given path
+       to the changeset to be committed next.  In particular, the
+       repository is cloned at the specified path, added to the
+       changeset and registered in .gitmodules.   If no path is
+       specified, the path is deduced from the repository specification.
+
+status::
+       Show the status of the submodules. This will print the SHA-1 of the
+       currently checked out commit for each submodule, along with the
+       submodule path and the output of gitlink:git-describe[1] for the
+       SHA-1. Each SHA-1 will be prefixed with `-` if the submodule is not
+       initialized and `+` if the currently checked out submodule commit
+       does not match the SHA-1 found in the index of the containing
+       repository. This command is the default command for git-submodule.
+
+init::
+       Initialize the submodules, i.e. register in .git/config each submodule
+       name and url found in .gitmodules. The key used in .git/config is
+       `submodule.$name.url`. This command does not alter existing information
+       in .git/config.
+
+update::
+       Update the registered submodules, i.e. clone missing submodules and
+       checkout the commit specified in the index of the containing repository.
+       This will make the submodules HEAD be detached.
+
+
+OPTIONS
+-------
+-q, --quiet::
+       Only print error messages.
+
+-b, --branch::
+       Branch of repository to add as submodule.
+
+--cached::
+       Display the SHA-1 stored in the index, not the SHA-1 of the currently
+       checked out submodule commit. This option is only valid for the
+       status command.
+
+<path>::
+       Path to submodule(s). When specified this will restrict the command
+       to only operate on the submodules found at the specified paths.
+
+FILES
+-----
+When initializing submodules, a .gitmodules file in the top-level directory
+of the containing repository is used to find the url of each submodule.
+This file should be formatted in the same way as $GIR_DIR/config. The key
+to each submodule url is "submodule.$name.url".
+
+
+AUTHOR
+------
+Written by Lars Hjemli <hjemli@gmail.com>
+
+GIT
+---
+Part of the gitlink:git[7] suite
index c0d7d9597b8f569a1e996072bef667f517e74bd2..0a210e4bea49d49e9d38de402cc355ed4acc6a71 100644 (file)
@@ -66,9 +66,10 @@ COMMANDS
        to the names of remotes if trunk/branches/tags are
        specified.  The prefix does not automatically include a
        trailing slash, so be sure you include one in the
-       argument if that is what you want.  This is useful if
-       you wish to track multiple projects that share a common
-       repository.
+       argument if that is what you want.  If --branches/-b is
+       specified, the prefix must include a trailing slash.
+       Setting a prefix is useful if you wish to track multiple
+       projects that share a common repository.
 
 'fetch'::
        Fetch unfetched revisions from the Subversion remote we are
index bdae7d87dce5d07d0d31b45f127fa43a239a6632..e97d15e8f237e969b76cdda9a90f6740aab77f13 100644 (file)
@@ -174,4 +174,3 @@ Documentation by Matthias Urlichs <smurf@smurf.noris.de>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 4e3e02756c8863dbc6fe1d745e1a8c9a97c18919..aee2c1bdc785259c3f587323b557f5c575f3c797 100644 (file)
@@ -11,7 +11,7 @@ SYNOPSIS
 [verse]
 'git-tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]  <name> [<head>]
 'git-tag' -d <name>...
-'git-tag' -l [<pattern>]
+'git-tag' [-n [<num>]] -l [<pattern>]
 'git-tag' -v <name>
 
 DESCRIPTION
@@ -38,8 +38,8 @@ GnuPG key for signing.
 
 `-v <tag>` verifies the gpg signature of the tag.
 
-`-l <pattern>` lists tags that match the given pattern (or all
-if no pattern is given).
+`-l <pattern>` lists tags with names that match the given pattern
+(or all if no pattern is given).
 
 OPTIONS
 -------
@@ -61,8 +61,13 @@ OPTIONS
 -v::
        Verify the gpg signature of given the tag
 
+-n <num>::
+       <num> specifies how many lines from the annotation, if any,
+       are printed when using -l.
+       The default is not to print any annotation lines.
+
 -l <pattern>::
-       List tags that match the given pattern (or all if no pattern is given).
+       List tags with names that match the given pattern (or all if no pattern is given).
 
 -m <msg>::
        Use the given tag message (instead of prompting)
index 7bde73b1b85df03893fa15b99b17c5aff09ae574..2d01d9666fd2ab5f53ab2265ca701d56ea370f8b 100644 (file)
@@ -90,4 +90,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 213dc8196b90170cc14e35f7c637815b39a7ff8d..20bb6a7800c43c6613aaeda2a86cd3311213bfbe 100644 (file)
@@ -33,4 +33,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index b1b3ec9772b7e689a4a3d42e78be68df34de40ac..d529a43f55ed6356f88fc6410f3fe00dfc01359d 100644 (file)
@@ -52,4 +52,3 @@ Documentation by Junio C Hamano
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 6cfbd9a842f0601cf81f8780ecf6b7939b25dccb..0a1953803e48947f6eeae385550ac2cd4e838411 100644 (file)
@@ -56,7 +56,7 @@ OPTIONS
 
 --unmerged::
         If --refresh finds unmerged changes in the index, the default
-        behavior is to error out.  This option makes git-update-index 
+        behavior is to error out.  This option makes git-update-index
         continue anyway.
 
 --ignore-missing::
@@ -64,12 +64,12 @@ OPTIONS
 
 --cacheinfo <mode> <object> <path>::
        Directly insert the specified info into the index.
-       
+
 --index-info::
         Read index information from stdin.
 
 --chmod=(+|-)x::
-        Set the execute permissions on the updated files.        
+        Set the execute permissions on the updated files.
 
 --assume-unchanged, --no-assume-unchanged::
        When these flags are specified, the object name recorded
@@ -126,7 +126,7 @@ OPTIONS
 <file>::
        Files to act on.
        Note that files beginning with '.' are discarded. This includes
-       `./file` and `dir/./file`. If you don't want this, then use     
+       `./file` and `dir/./file`. If you don't want this, then use
        cleaner names.
        The same applies to directories ending '/' and paths with '//'
 
@@ -324,4 +324,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 9424feab320afcaa5a44bd2c2c6c86728bd8d004..f222616591f157beada3c5355ee0e56d68171761 100644 (file)
@@ -7,7 +7,7 @@ git-update-ref - Update the object name stored in a ref safely
 
 SYNOPSIS
 --------
-'git-update-ref' [-m <reason>] (-d <ref> <oldvalue> | <ref> <newvalue> [<oldvalue>])
+'git-update-ref' [-m <reason>] (-d <ref> <oldvalue> | [--no-deref] <ref> <newvalue> [<oldvalue>])
 
 DESCRIPTION
 -----------
@@ -36,6 +36,9 @@ them and update them as a regular file (i.e. it will allow the
 filesystem to follow them, but will overwrite such a symlink to
 somewhere else with a regular filename).
 
+If --no-deref is given, <ref> itself is overwritten, rather than
+the result of following the symbolic pointers.
+
 In general, using
 
        git-update-ref HEAD "$head"
index 88a03c7c5ed4935fc10764d0f56326f0436a6f26..e7e82a31ea58a0515ed3a294140fd361577c07ce 100644 (file)
@@ -55,4 +55,3 @@ Documentation by Junio C Hamano.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 9b0de1c111d7b58cb8d431d90814d1f1530f5e0d..813942368b31a9eccb1c06b67e1a4303d3b62ede 100644 (file)
@@ -62,4 +62,3 @@ Documentation by Eric Biederman and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 7a6132b016903801fd1070e062381a41ec52536a..f4c540f39bffe5bda536445dc1556ff4c6bfa60a 100644 (file)
@@ -51,4 +51,3 @@ Documentation by Junio C Hamano
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 0f9bdb58dcc3cf7ee549f483164a708f536d2bd5..48d17fd9c44acc3192987d818f3505c56d2eddb4 100644 (file)
@@ -29,4 +29,3 @@ Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 399bff3bbcab89be96039c373cf1120dcab0efe1..607df48f09254f2c93ad41e75ed976b092711dff 100644 (file)
@@ -78,4 +78,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 96d5e07b112aa2a87eb6433f7cbeb8ce5f10205a..cb8d6aadeb3fc3b55c58bd40b96461a07a124260 100644 (file)
@@ -47,4 +47,3 @@ Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 98860af0455ebb5290e7225e6ac677dc7ab3268c..10c7bb3f459cedfadf64fcb99114ceaf6b961358 100644 (file)
@@ -10,7 +10,8 @@ SYNOPSIS
 --------
 [verse]
 'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate]
-    [--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]
+    [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]
+    [--help] COMMAND [ARGS]
 
 DESCRIPTION
 -----------
@@ -41,9 +42,12 @@ 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.2/git.html[documentation for release 1.5.2]
+* link:v1.5.2.3/git.html[documentation for release 1.5.2.3]
 
 * release notes for
+  link:RelNotes-1.5.2.3.txt[1.5.2.3],
+  link:RelNotes-1.5.2.2.txt[1.5.2.2],
+  link:RelNotes-1.5.2.1.txt[1.5.2.1],
   link:RelNotes-1.5.2.txt[1.5.2].
 
 * link:v1.5.1.6/git.html[documentation for release 1.5.1.6]
@@ -101,6 +105,14 @@ OPTIONS
        Set the path to the repository. This can also be controlled by
        setting the GIT_DIR environment variable.
 
+--work-tree=<path>::
+       Set the path to the working tree.  The value will not be
+       used in combination with repositories found automatically in
+       a .git directory (i.e. $GIT_DIR is not set).
+       This can also be controlled by setting the GIT_WORK_TREE
+       environment variable and the core.worktree configuration
+       variable.
+
 --bare::
        Same as --git-dir=`pwd`.
 
@@ -345,6 +357,13 @@ git so take care if using Cogito etc.
        specifies a path to use instead of the default `.git`
        for the base of the repository.
 
+'GIT_WORK_TREE'::
+       Set the path to the working tree.  The value will not be
+       used in combination with repositories found automatically in
+       a .git directory (i.e. $GIT_DIR is not set).
+       This can also be controlled by the '--work-tree' command line
+       option and the core.worktree configuration variable.
+
 git Commits
 ~~~~~~~~~~~
 'GIT_AUTHOR_NAME'::
@@ -394,6 +413,16 @@ other
 'GIT_PAGER'::
        This environment variable overrides `$PAGER`.
 
+'GIT_FLUSH'::
+       If this environment variable is set to "1", then commands such
+       as git-blame (in incremental mode), git-rev-list, git-log,
+       git-whatchanged, etc., will force a flush of the output stream
+       after each commit-oriented record have been flushed.   If this
+       variable is set to "0", the output of these commands will be done
+       using completely buffered I/O.   If this environment variable is
+       not set, git will choose buffered or record-oriented flushing
+       based on whether stdout appears to be redirected to a file or not.
+
 'GIT_TRACE'::
        If this variable is set to "1", "2" or "true" (comparison
        is case insensitive), git will print `trace:` messages on
@@ -428,4 +457,3 @@ contributors on the git-list <git@vger.kernel.org>.
 GIT
 ---
 Part of the gitlink:git[7] suite
-
index 48c5894736ac3065e80a36e1a5230d86004bee2e..e9f82b97b91b92785b76a224e176b695593cdbe7 100644 (file)
@@ -99,4 +99,3 @@ Documentation by Junio C Hamano, Jonas Fonseca, and the git-list
 GIT
 ---
 Part of the gitlink:git[7] suite
-
diff --git a/Documentation/gitmodules.txt b/Documentation/gitmodules.txt
new file mode 100644 (file)
index 0000000..035294e
--- /dev/null
@@ -0,0 +1,62 @@
+gitmodules(5)
+=============
+
+NAME
+----
+gitmodules - defining submodule properties
+
+SYNOPSIS
+--------
+gitmodules
+
+
+DESCRIPTION
+-----------
+
+The `.gitmodules` file, located in the top-level directory of a git
+working tree, is a text file with a syntax matching the requirements
+of gitlink:git-config[1].
+
+The file contains one subsection per submodule, and the subsection value
+is the name of the submodule. Each submodule section also contains the
+following required keys:
+
+submodule.<name>.path::
+       Defines the path, relative to the top-level directory of the git
+       working tree, where the submodule is expected to be checked out.
+       The path name must not end with a `/`. All submodule paths must
+       be unique within the .gitmodules file.
+
+submodule.<name>.url::
+       Defines an url from where the submodule repository can be cloned.
+
+
+EXAMPLES
+--------
+
+Consider the following .gitmodules file:
+
+       [submodule "libfoo"]
+               path = include/foo
+               url = git://foo.com/git/lib.git
+
+       [submodule "libbar"]
+               path = include/bar
+               url = git://bar.com/git/lib.git
+
+
+This defines two submodules, `libfoo` and `libbar`. These are expected to
+be checked out in the paths 'include/foo' and 'include/bar', and for both
+submodules an url is specified which can be used for cloning the submodules.
+
+SEE ALSO
+--------
+gitlink:git-submodule[1] gitlink:git-config[1]
+
+DOCUMENTATION
+-------------
+Documentation by Lars Hjemli <hjemli@gmail.com>
+
+GIT
+---
+Part of the gitlink:git[7] suite
index aabb9750fddbc28091c46780ccf7b835b62b04c7..6836477ca816a6caa860960c3456cfbbf5cd32f1 100644 (file)
@@ -12,11 +12,10 @@ This document describes the currently defined hooks.
 applypatch-msg
 --------------
 
-This hook is invoked by `git-applypatch` script, which is
-typically invoked by `git-applymbox`.  It takes a single
+This hook is invoked by `git-am` script.  It takes a single
 parameter, the name of the file that holds the proposed commit
 log message.  Exiting with non-zero status causes
-`git-applypatch` to abort before applying the patch.
+`git-am` to abort before applying the patch.
 
 The hook is allowed to edit the message file in place, and can
 be used to normalize the message into some project standard
@@ -29,8 +28,7 @@ The default 'applypatch-msg' hook, when enabled, runs the
 pre-applypatch
 --------------
 
-This hook is invoked by `git-applypatch` script, which is
-typically invoked by `git-applymbox`.  It takes no parameter,
+This hook is invoked by `git-am`.  It takes no parameter,
 and is invoked after the patch is applied, but before a commit
 is made.  Exiting with non-zero status causes the working tree
 after application of the patch not committed.
@@ -44,12 +42,11 @@ The default 'pre-applypatch' hook, when enabled, runs the
 post-applypatch
 ---------------
 
-This hook is invoked by `git-applypatch` script, which is
-typically invoked by `git-applymbox`.  It takes no parameter,
+This hook is invoked by `git-am`.  It takes no parameter,
 and is invoked after the patch is applied and a commit is made.
 
 This hook is meant primarily for notification, and cannot affect
-the outcome of `git-applypatch`.
+the outcome of `git-am`.
 
 pre-commit
 ----------
index 646c55cc6954fbf36a11fbe22cb2c1acb64dfd43..554909fe08de380aa02f2bf37f0f3b43b0233f4b 100644 (file)
@@ -9,16 +9,16 @@ Abstract: In this article, Linus demonstrates how a broken commit
 
 On Sat, 13 Aug 2005, Linus Torvalds wrote:
 
-> That's correct. Same things apply: you can move a patch over, and create a 
-> new one with a modified comment, but basically the _old_ commit will be 
+> That's correct. Same things apply: you can move a patch over, and create a
+> new one with a modified comment, but basically the _old_ commit will be
 > immutable.
 
 Let me clarify.
 
 You can entirely _drop_ old branches, so commits may be immutable, but
-nothing forces you to keep them. Of course, when you drop a commit, you'll 
-always end up dropping all the commits that depended on it, and if you 
-actually got somebody else to pull that commit you can't drop it from 
+nothing forces you to keep them. Of course, when you drop a commit, you'll
+always end up dropping all the commits that depended on it, and if you
+actually got somebody else to pull that commit you can't drop it from
 _their_ repository, but undoing things is not impossible.
 
 For example, let's say that you've made a mess of things: you've committed
@@ -29,7 +29,7 @@ want to save "b" and "c". What you can do is
        # for reference
        git branch broken
 
-       # Reset the main branch to three parents back: this 
+       # Reset the main branch to three parents back: this
        # effectively undoes the three top commits
        git reset HEAD^^^
        git checkout -f
@@ -59,7 +59,7 @@ Finally, check out the end result again:
 
 to see that everything looks sensible.
 
-And then, you can just remove the broken branch if you decide you really 
+And then, you can just remove the broken branch if you decide you really
 don't want it:
 
        # remove 'broken' branch
@@ -68,8 +68,8 @@ don't want it:
        # Prune old objects if you're really really sure
        git prune
 
-And yeah, I'm sure there are other ways of doing this. And as usual, the 
-above is totally untested, and I just wrote it down in this email, so if 
+And yeah, I'm sure there are other ways of doing this. And as usual, the
+above is totally untested, and I just wrote it down in this email, so if
 I've done something wrong, you'll have to figure it out on your own ;)
 
                        Linus
@@ -77,5 +77,3 @@ I've done something wrong, you'll have to figure it out on your own ;)
 To unsubscribe from this list: send the line "unsubscribe git" in
 the body of a message to majordomo@vger.kernel.org
 More majordomo info at  http://vger.kernel.org/majordomo-info.html
-
-
index 3b3a5c2e69e59d4708171ba745d7d4009788102b..7a76045eb742b38e726e15491db2bf4315cb8f6a 100644 (file)
@@ -14,10 +14,10 @@ Petr Baudis <pasky@suse.cz> writes:
 > Dear diary, on Sun, Aug 14, 2005 at 09:57:13AM CEST, I got a letter
 > where Junio C Hamano <junkio@cox.net> told me that...
 >> Linus Torvalds <torvalds@osdl.org> writes:
->> 
->> > Junio, maybe you want to talk about how you move patches from your "pu" 
+>>
+>> > Junio, maybe you want to talk about how you move patches from your "pu"
 >> > branch to the real branches.
->> 
+>>
 > Actually, wouldn't this be also precisely for what StGIT is intended to?
 
 Exactly my feeling.  I was sort of waiting for Catalin to speak
@@ -118,7 +118,7 @@ up your changes, along with other changes.
 
    where                      *your "master" head
   upstream --> #1 --> #2 --> #3
-    used   \ 
+    used   \
    to be     \--> #A --> #2' --> #3' --> #B --> #C
                                                 *upstream head
 
@@ -133,7 +133,7 @@ You fetch from upstream, but not merge.
     $ git fetch upstream
 
 This leaves the updated upstream head in .git/FETCH_HEAD but
-does not touch your .git/HEAD nor .git/refs/heads/master.  
+does not touch your .git/HEAD nor .git/refs/heads/master.
 You run "git rebase" now.
 
     $ git rebase FETCH_HEAD master
@@ -161,5 +161,3 @@ the #1' commit.
 To unsubscribe from this list: send the line "unsubscribe git" in
 the body of a message to majordomo@vger.kernel.org
 More majordomo info at  http://vger.kernel.org/majordomo-info.html
-
-
index 02621b54a03ce5771eab1c49d121a07ba31cbf16..8d55dfbfaef7ef6bb30b65ea52c7825b099b50d8 100644 (file)
@@ -84,4 +84,3 @@ There are four things worth mentioning:
  - This is still crude and does not protect against simultaneous
    make invocations stomping on each other.  I would need to add
    some locking mechanism for this.
-
index d88ec23a97bc59f29a5f9734fc5ba0ef5a9ae6cf..865a6663240f744d448b0a125ebc123afb72ede2 100644 (file)
@@ -146,7 +146,7 @@ Everything is in the good order.  I do not need the temporary branch
 nor tag anymore, so remove them:
 
 ------------------------------------------------
-$ rm -f .git/refs/tags/pu-anchor 
+$ rm -f .git/refs/tags/pu-anchor
 $ git branch -d revert-c99
 ------------------------------------------------
 
index 090e2c9b018c7ea16b98094746d4e005abd27eec..0d73b31224c881eb83f30ec3c5421a81288f6502 100644 (file)
@@ -12,7 +12,7 @@ up with a history like this:
 
             "master"
         o---o
-             \                    "topic" 
+             \                    "topic"
               o---o---o---o---o---o
 
 At this point, "topic" contains something I know I want, but it
@@ -29,11 +29,11 @@ start building on top of "master":
         $ git checkout -b topicA master
         ... pick and apply pieces from P.diff to build
         ... commits on topicA branch.
-                      
+
               o---o---o
              /        "topicA"
         o---o"master"
-             \                    "topic" 
+             \                    "topic"
               o---o---o---o---o---o
 
 Before doing each commit on "topicA" HEAD, I run "diff HEAD"
@@ -59,7 +59,7 @@ other topic:
              /o---o---o
             |/        "topicA"
         o---o"master"
-             \                    "topic" 
+             \                    "topic"
               o---o---o---o---o---o
 
 After I am done, I'd try a pretend-merge between "topicA" and
@@ -73,7 +73,7 @@ After I am done, I'd try a pretend-merge between "topicA" and
              /o---o---o----------'
             |/        "topicA"
         o---o"master"
-             \                    "topic" 
+             \                    "topic"
               o---o---o---o---o---o
 
 The last diff better not to show anything other than cleanups
@@ -84,8 +84,7 @@ for crufts.  Then I can finally clean things up:
 
                                 "topicB"
                o---o---o---o---o
-              / 
+              /
              /o---o---o
             |/        "topicA"
         o---o"master"
-
index 1a1eb246bf5b5ff5f67edea306371604159762ae..4e2f75cb6167633c97ec1981d2b6659368cc0170 100644 (file)
@@ -49,4 +49,3 @@ Now, test your daemon with
        $ git ls-remote git://127.0.0.1/rule-the-world.git
 
 If this does not work, find out why, and submit a patch to this document.
-
index a64054948aec41e820b8864a71229bbd568aa99a..e6601bdd8237bbda80727780434d5b9d337e8bf4 100755 (executable)
@@ -10,7 +10,7 @@ USAGE='<refname> <target directory>'
 export GIT_DIR
 
 test -z "$mandir" && usage
-if ! git-rev-parse --verify "$head^0" >/dev/null; then
+if ! git rev-parse --verify "$head^0" >/dev/null; then
        echo >&2 "head: $head does not exist in the current repository"
        usage
 fi
@@ -18,12 +18,12 @@ fi
 GIT_INDEX_FILE=`pwd`/.quick-doc.index
 export GIT_INDEX_FILE
 rm -f "$GIT_INDEX_FILE"
-git-read-tree $head
-git-checkout-index -a -f --prefix="$mandir"/
+git read-tree $head
+git checkout-index -a -f --prefix="$mandir"/
 
 if test -n "$GZ"; then
        cd "$mandir"
-       for i in `git-ls-tree -r --name-only $head`
+       for i in `git ls-tree -r --name-only $head`
        do
                gzip < $i > $i.gz && rm $i
        done
index 182cef54be5963ff0f32a24329ca195607413e29..d64c259bb35d3140b371e8717a2553146d3f92f5 100644 (file)
@@ -1,3 +1,7 @@
+--summary::
+       Show a diffstat at the end of the merge. The diffstat is also
+       controlled by the configuration option merge.diffstat.
+
 -n, \--no-summary::
        Do not show diffstat at the end of the merge.
 
@@ -21,4 +25,3 @@
        If there is no `-s` option, a built-in list of strategies
        is used instead (`git-merge-recursive` when merging a single
        head, `git-merge-octopus` otherwise).
-
index d922e8e86c173491fc492d3060bf92f4ee7b6c2d..c551ea61d2870e6e4d5471ec4fcbca4fbd802b09 100644 (file)
@@ -121,4 +121,3 @@ The placeholders are:
 - '%Creset': reset color
 - '%m': left, right or boundary mark
 - '%n': newline
-
index 7d515be0fd3b89d602ac2919fd2ea3dd4bc84131..746bc5b7f9a3f96ea321586e095a4fc8ccb6e73f 100644 (file)
@@ -5,10 +5,18 @@
        'full', 'fuller', 'email', 'raw' and 'format:<string>'.
        When left out the format default to 'medium'.
 
+--abbrev-commit::
+       Instead of showing the full 40-byte hexadecimal commit object
+       name, show only handful hexdigits prefix.  Non default number of
+       digits can be specified with "--abbrev=<n>" (which also modifies
+       diff output, if it is displayed).
++
+This should make "--pretty=oneline" a whole lot more readable for
+people using 80-column terminals.
+
 --encoding[=<encoding>]::
        The commit objects record the encoding used for the log message
        in their encoding header; this option can be used to tell the
        command to re-code the commit log message in the encoding
        preferred by the user.  For non plumbing commands this
        defaults to UTF-8.
-
index 8d4e950abc65c233268d785dcbfee67ab0522f4c..b6eb7fc6189daece1a200293dc767b6bc064620a 100644 (file)
@@ -58,7 +58,7 @@ is often useful.
 +
 Some short-cut notations are also supported.
 +
-* `tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`; 
+* `tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`;
   it requests fetching everything up to the given tag.
 * A parameter <ref> without a colon is equivalent to
   <ref>: when pulling/fetching, so it merges <ref> into the current
index 15221b53206eb65072f147ac72f556d0a1ee55e4..4c92e375fed4592f7190086dd40ef6dd1241d238 100644 (file)
@@ -177,4 +177,3 @@ shallow::
        This is similar to `info/grafts` but is internally used
        and maintained by shallow clone mechanism.  See `--depth`
        option to gitlink:git-clone[1] and gitlink:git-fetch[1].
-
index 9ce3c473ae1a9b5fd0b3a909fb264d8e0fff27a5..e5b31c81fa3b5268c6d1bc0afcaec967f401ac28 100644 (file)
@@ -80,7 +80,7 @@ Pack Idx file:
            +--------------------------------+ |
 main       | offset                         | |
 index      | object name 00XXXXXXXXXXXXXXXX | |
-table      +--------------------------------+ | 
+table      +--------------------------------+ |
            | offset                         | |
            | object name 00XXXXXXXXXXXXXXXX | |
            +--------------------------------+ |
@@ -97,14 +97,14 @@ trailer       | | packfile checksum              |
          | +--------------------------------+
          | | idxfile checksum               |
          | +--------------------------------+
-          .-------.      
+          .-------.
                   |
 Pack file entry: <+
 
      packed object header:
        1-byte size extension bit (MSB)
               type (next 3 bit)
-              size0 (lower 4-bit) 
+              size0 (lower 4-bit)
         n-byte sizeN (as long as MSB is set, each 7-bit)
                size0..sizeN form 4+7+7+..+7 bit integer, size0
                is the least significant part, and sizeN is the
@@ -114,5 +114,5 @@ Pack file entry: <+
                is the size before compression).
        If it is DELTA, then
          20-byte base object name SHA1 (the size above is the
-               size of the delta data that follows).
+               size of the delta data that follows).
           delta data, deflated.
index 965ec00a6b403d1a4d23c7db2d08198480dc4f5b..bd9fbee99aeb67c5362523d6b4cb43d4889cf8a5 100644 (file)
@@ -354,7 +354,7 @@ used for pulls:
 
 -------------------------------------
 $ git config --get remote.origin.url
-/home/bob/myrepo
+/home/alice/project
 -------------------------------------
 
 (The complete configuration created by git-clone is visible using
diff --git a/Documentation/urls-remotes.txt b/Documentation/urls-remotes.txt
new file mode 100644 (file)
index 0000000..5dd1f83
--- /dev/null
@@ -0,0 +1,55 @@
+include::urls.txt[]
+
+REMOTES
+-------
+
+In addition to the above, as a short-hand, the name of a
+file in `$GIT_DIR/remotes` directory can be given; the
+named file should be in the following format:
+
+------------
+       URL: one of the above URL format
+       Push: <refspec>
+       Pull: <refspec>
+
+------------
+
+Then such a short-hand is specified in place of
+<repository> without <refspec> parameters on the command
+line, <refspec> specified on `Push:` lines or `Pull:`
+lines are used for `git-push` and `git-fetch`/`git-pull`,
+respectively.  Multiple `Push:` and `Pull:` lines may
+be specified for additional branch mappings.
+
+Or, equivalently, in the `$GIT_DIR/config` (note the use
+of `fetch` instead of `Pull:`):
+
+------------
+       [remote "<remote>"]
+               url = <url>
+               push = <refspec>
+               fetch = <refspec>
+
+------------
+
+The name of a file in `$GIT_DIR/branches` directory can be
+specified as an older notation short-hand; the named
+file should contain a single line, a URL in one of the
+above formats, optionally followed by a hash `#` and the
+name of remote head (URL fragment notation).
+`$GIT_DIR/branches/<remote>` file that stores a <url>
+without the fragment is equivalent to have this in the
+corresponding file in the `$GIT_DIR/remotes/` directory.
+
+------------
+       URL: <url>
+       Pull: refs/heads/master:<remote>
+
+------------
+
+while having `<url>#<head>` is equivalent to
+
+------------
+       URL: <url>
+       Pull: refs/heads/<head>:<remote>
+------------
index 745f9677d005b522f52496339abd5afc4267a815..781df4174b7493eb905d0c87c73751bd4bc77b75 100644 (file)
@@ -32,57 +32,3 @@ To sync with a local directory, use:
 ===============================================================
 - /path/to/repo.git/
 ===============================================================
-
-REMOTES
--------
-
-In addition to the above, as a short-hand, the name of a
-file in `$GIT_DIR/remotes` directory can be given; the
-named file should be in the following format:
-
-------------
-       URL: one of the above URL format
-       Push: <refspec>
-       Pull: <refspec>
-
-------------
-
-Then such a short-hand is specified in place of
-<repository> without <refspec> parameters on the command
-line, <refspec> specified on `Push:` lines or `Pull:`
-lines are used for `git-push` and `git-fetch`/`git-pull`,
-respectively.  Multiple `Push:` and `Pull:` lines may
-be specified for additional branch mappings.
-
-Or, equivalently, in the `$GIT_DIR/config` (note the use
-of `fetch` instead of `Pull:`):
-
-------------
-       [remote "<remote>"]
-               url = <url>
-               push = <refspec>
-               fetch = <refspec>
-
-------------
-
-The name of a file in `$GIT_DIR/branches` directory can be
-specified as an older notation short-hand; the named
-file should contain a single line, a URL in one of the
-above formats, optionally followed by a hash `#` and the
-name of remote head (URL fragment notation).
-`$GIT_DIR/branches/<remote>` file that stores a <url>
-without the fragment is equivalent to have this in the
-corresponding file in the `$GIT_DIR/remotes/` directory.
-
-------------
-       URL: <url>
-       Pull: refs/heads/master:<remote>
-
-------------
-
-while having `<url>#<head>` is equivalent to
-
-------------
-       URL: <url>
-       Pull: refs/heads/<head>:<remote>
-------------
index d6caff42486bff0a78f66ce0ab1dbca0c1c944e2..14825c64119fd75a138060d4bd6e2ae6fe03a88a 100644 (file)
@@ -154,11 +154,11 @@ Author: Jamal Hadi Salim <hadi@cyberus.ca>
 Date:   Sat Dec 2 22:22:25 2006 -0800
 
     [XFRM]: Fix aevent structuring to be more complete.
-    
+
     aevents can not uniquely identify an SA. We break the ABI with this
     patch, but consensus is that since it is not yet utilized by any
     (known) application then it is fine (better do it now than later).
-    
+
     Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
     Signed-off-by: David S. Miller <davem@davemloft.net>
 
@@ -167,7 +167,7 @@ index 8be626f..d7aac9d 100644
 --- a/Documentation/networking/xfrm_sync.txt
 +++ b/Documentation/networking/xfrm_sync.txt
 @@ -47,10 +47,13 @@ aevent_id structure looks like:
+
     struct xfrm_aevent_id {
               struct xfrm_usersa_id           sa_id;
 +             xfrm_address_t                  saddr;
@@ -1057,7 +1057,7 @@ $ git show
 -------------------------------------------------
 
 As a special shortcut,
-               
+
 -------------------------------------------------
 $ git commit -a
 -------------------------------------------------
@@ -1555,7 +1555,7 @@ history.
 
 Fortunately, git also keeps a log, called a "reflog", of all the
 previous values of each branch.  So in this case you can still find the
-old history using, for example, 
+old history using, for example,
 
 -------------------------------------------------
 $ git log master@{1}
@@ -1631,7 +1631,7 @@ If you decide you want the history back, you can always create a new
 reference pointing to it, for example, a new branch:
 
 ------------------------------------------------
-$ git branch recovered-branch 7281251ddd 
+$ git branch recovered-branch 7281251ddd
 ------------------------------------------------
 
 Other types of dangling objects (blobs and trees) are also possible, and
@@ -1803,7 +1803,7 @@ like this:
 
                         you push
   your personal repo ------------------> your public repo
-       ^                                     |
+       ^                                     |
        |                                     |
        | you pull                            | they pull
        |                                     |
@@ -2377,7 +2377,7 @@ the result would create a new merge commit, like this:
         \        \
          a--b--c--m <-- mywork
 ................................................
+
 However, if you prefer to keep the history in mywork a simple series of
 commits without any merges, you may instead choose to use
 gitlink:git-rebase[1]:
@@ -2753,7 +2753,7 @@ must have at least one root, and while you can tie several different
 root objects together into one project by creating a commit object which
 has two or more separate roots as its ultimate parents, that's probably
 just going to confuse people.  So aim for the notion of "one root object
-per project", even if git itself does not enforce that. 
+per project", even if git itself does not enforce that.
 
 A <<def_tag_object,"tag" object>> symbolically identifies and can be
 used to sign other objects. It contains the identifier and type of
@@ -2972,15 +2972,15 @@ cache, and the normal operation is to re-generate it completely from a
 known tree object, or update/compare it with a live tree that is being
 developed.  If you blow the directory cache away entirely, you generally
 haven't lost any information as long as you have the name of the tree
-that it described. 
+that it described.
 
-At the same time, the index is at the same time also the
-staging area for creating new trees, and creating a new tree always
-involves a controlled modification of the index file.  In particular,
-the index file can have the representation of an intermediate tree that
-has not yet been instantiated.  So the index can be thought of as a
-write-back cache, which can contain dirty information that has not yet
-been written back to the backing store.
+At the same time, the index is also the staging area for creating
+new trees, and creating a new tree always involves a controlled
+modification of the index file.  In particular, the index file can
+have the representation of an intermediate tree that has not yet been
+instantiated.  So the index can be thought of as a write-back cache,
+which can contain dirty information that has not yet been written back
+to the backing store.
 
 
 
@@ -2992,7 +2992,7 @@ Generally, all "git" operations work on the index file. Some operations
 work *purely* on the index file (showing the current state of the
 index), but most operations move data to and from the index file. Either
 from the database or from the working directory. Thus there are four
-main combinations: 
+main combinations:
 
 [[working-directory-to-index]]
 working directory -> index
@@ -3455,7 +3455,7 @@ because you interrupted a "git fetch" with ^C or something like that,
 leaving _some_ of the new objects in the object database, but just
 dangling and useless.
 
-Anyway, once you are sure that you're not interested in any dangling 
+Anyway, once you are sure that you're not interested in any dangling
 state, you can just prune all unreachable objects:
 
 ------------------------------------------------
@@ -3466,12 +3466,12 @@ and they'll be gone. But you should only run "git prune" on a quiescent
 repository - it's kind of like doing a filesystem fsck recovery: you
 don't want to do that while the filesystem is mounted.
 
-(The same is true of "git-fsck" itself, btw - but since 
-git-fsck never actually *changes* the repository, it just reports 
-on what it found, git-fsck itself is never "dangerous" to run. 
-Running it while somebody is actually changing the repository can cause 
-confusing and scary messages, but it won't actually do anything bad. In 
-contrast, running "git prune" while somebody is actively changing the 
+(The same is true of "git-fsck" itself, btw - but since
+git-fsck never actually *changes* the repository, it just reports
+on what it found, git-fsck itself is never "dangerous" to run.
+Running it while somebody is actually changing the repository can cause
+confusing and scary messages, but it won't actually do anything bad. In
+contrast, running "git prune" while somebody is actively changing the
 repository is a *BAD* idea).
 
 [[birdview-on-the-source-code]]
index 5c6d2b28982257f0487e00628693829421bc220b..06c360b267f0d9e459e44ccaa81dd16b4384c627 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.5.2.3.GIT
+DEF_VER=v1.5.2.GIT
 
 LF='
 '
diff --git a/INSTALL b/INSTALL
index 361c65bacc50b4038cb9a32bab07c275a1ecdc76..63ba1480a697ddeb98c5665106352fd2bb0ceb5a 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -31,7 +31,7 @@ Issues of note:
    interactive tools.  None of the core git stuff needs the wrapper,
    it's just a convenient shorthand and while it is documented in some
    places, you can always replace "git commit" with "git-commit"
-   instead. 
+   instead.
 
    But let's face it, most of us don't have GNU interactive tools, and
    even if we had it, we wouldn't know what it does.  I don't think it
@@ -89,10 +89,16 @@ Issues of note:
    will include them.  Note that config.mak is not distributed;
    the name is reserved for local settings.
 
- - To build and install documentation suite, you need to have the
-   asciidoc/xmlto toolchain.  Alternatively, pre-formatted
-   documentation are available in "html" and "man" branches of the git
-   repository itself.  For example, you could:
+ - To build and install documentation suite, you need to have
+   the asciidoc/xmlto toolchain.  Because not many people are
+   inclined to install the tools, the default build target
+   ("make all") does _not_ build them.  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
+   "html" and "man" branches of the git repository itself.  For
+   example, you could:
 
        $ mkdir manual && cd manual
        $ git init
@@ -111,4 +117,3 @@ Issues of note:
    would instead give you a copy of what you see at:
 
        http://www.kernel.org/pub/software/scm/git/docs/
-
index eb443bddb9a164c6b6b8c23ec8be71f50cb615a8..5b30e5c864d64e6ae688464b9eb36437e0e04c7f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -146,8 +146,8 @@ STRIP ?= strip
 prefix = $(HOME)
 bindir = $(prefix)/bin
 gitexecdir = $(bindir)
-sharedir = $(prefix)/share/
-template_dir = $(sharedir)/git-core/templates/
+sharedir = $(prefix)/share
+template_dir = $(sharedir)/git-core/templates
 ifeq ($(prefix),/usr)
 sysconfdir = /etc
 else
@@ -204,14 +204,16 @@ SCRIPT_SH = \
        git-fetch.sh \
        git-ls-remote.sh \
        git-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \
-       git-pull.sh git-rebase.sh \
+       git-pull.sh git-rebase.sh git-rebase--interactive.sh \
        git-repack.sh git-request-pull.sh git-reset.sh \
        git-sh-setup.sh \
        git-tag.sh git-verify-tag.sh \
-       git-applymbox.sh git-applypatch.sh git-am.sh \
+       git-am.sh \
        git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
        git-merge-resolve.sh git-merge-ours.sh \
-       git-lost-found.sh git-quiltimport.sh
+       git-lost-found.sh git-quiltimport.sh git-submodule.sh \
+       git-filter-branch.sh \
+       git-stash.sh
 
 SCRIPT_PERL = \
        git-add--interactive.perl \
@@ -240,7 +242,6 @@ PROGRAMS = \
        git-convert-objects$X git-fetch-pack$X \
        git-hash-object$X git-index-pack$X git-local-fetch$X \
        git-fast-import$X \
-       git-merge-base$X \
        git-daemon$X \
        git-merge-index$X git-mktag$X git-mktree$X git-patch-id$X \
        git-peek-remote$X git-receive-pack$X \
@@ -298,7 +299,8 @@ LIB_H = \
        diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \
        run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
        tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \
-       utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h mailmap.h
+       utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h \
+       mailmap.h remote.h
 
 DIFF_OBJS = \
        diff.o diff-lib.o diffcore-break.o diffcore-order.o \
@@ -320,7 +322,7 @@ LIB_OBJS = \
        write_or_die.o trace.o list-objects.o grep.o match-trees.o \
        alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
        color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \
-       convert.o attr.o decorate.o progress.o mailmap.o symlinks.o
+       convert.o attr.o decorate.o progress.o mailmap.o symlinks.o remote.o
 
 BUILTIN_OBJS = \
        builtin-add.o \
@@ -746,9 +748,13 @@ gitk-wish: gitk GIT-GUI-VARS
        chmod +x $@+ && \
        mv -f $@+ $@
 
-git$X: git.c common-cmds.h $(BUILTIN_OBJS) $(GITLIBS) GIT-CFLAGS
+git.o: git.c common-cmds.h GIT-CFLAGS
+       $(QUIET_CC)$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
+               $(ALL_CFLAGS) -c $(filter %.c,$^)
+
+git$X: git.o $(BUILTIN_OBJS) $(GITLIBS)
        $(QUIET_LINK)$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
-               $(ALL_CFLAGS) -o $@ $(filter %.c,$^) \
+               $(ALL_CFLAGS) -o $@ $(filter %.c,$^) git.o \
                $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
 
 help.o: common-cmds.h
@@ -759,6 +765,8 @@ git-merge-subtree$X: git-merge-recursive$X
 $(BUILT_INS): git$X
        $(QUIET_BUILT_IN)rm -f $@ && ln git$X $@
 
+common-cmds.h: ./generate-cmdlist.sh
+
 common-cmds.h: $(wildcard Documentation/git-*.txt)
        $(QUIET_GEN)./generate-cmdlist.sh > $@+ && mv $@+ $@
 
@@ -856,6 +864,8 @@ git$X git.spec \
 
 %.o: %.c GIT-CFLAGS
        $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
+%.s: %.c GIT-CFLAGS
+       $(QUIET_CC)$(CC) -S $(ALL_CFLAGS) $<
 %.o: %.S
        $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
 
@@ -952,7 +962,7 @@ endif
 
 ### Testing rules
 
-TEST_PROGRAMS = test-chmtime$X test-genrandom$X
+TEST_PROGRAMS = test-chmtime$X test-genrandom$X test-date$X test-delta$X test-sha1$X test-match-trees$X
 
 all:: $(TEST_PROGRAMS)
 
@@ -965,26 +975,12 @@ export NO_SVN_TESTS
 test: all
        $(MAKE) -C t/ all
 
-test-date$X: test-date.c date.o ctype.o
-       $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) test-date.c date.o ctype.o
-
-test-delta$X: test-delta.o diff-delta.o patch-delta.o $(GITLIBS)
-       $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
-
-test-dump-cache-tree$X: dump-cache-tree.o $(GITLIBS)
-       $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
+test-date$X: date.o ctype.o
 
-test-sha1$X: test-sha1.o $(GITLIBS)
-       $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
+test-delta$X: diff-delta.o patch-delta.o
 
-test-match-trees$X: test-match-trees.o $(GITLIBS)
-       $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
-
-test-chmtime$X: test-chmtime.c
-       $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $<
-
-test-genrandom$X: test-genrandom.c
-       $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $<
+test-%$X: test-%.o $(GITLIBS)
+       $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 
 check-sha1:: test-sha1$X
        ./test-sha1.sh
@@ -992,7 +988,8 @@ check-sha1:: test-sha1$X
 check: common-cmds.h
        for i in *.c; do sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; done
 
-
+remove-dashes:
+       ./fixup-builtins $(BUILT_INS)
 
 ### Installation rules
 
@@ -1034,15 +1031,16 @@ git.spec: git.spec.in
        mv $@+ $@
 
 GIT_TARNAME=git-$(GIT_VERSION)
-dist: git.spec git-archive
+dist: git.spec git-archive configure
        ./git-archive --format=tar \
                --prefix=$(GIT_TARNAME)/ HEAD^{tree} > $(GIT_TARNAME).tar
        @mkdir -p $(GIT_TARNAME)
-       @cp git.spec $(GIT_TARNAME)
+       @cp git.spec configure $(GIT_TARNAME)
        @echo $(GIT_VERSION) > $(GIT_TARNAME)/version
        @$(MAKE) -C git-gui TARDIR=../$(GIT_TARNAME)/git-gui dist-version
        $(TAR) rf $(GIT_TARNAME).tar \
                $(GIT_TARNAME)/git.spec \
+               $(GIT_TARNAME)/configure \
                $(GIT_TARNAME)/version \
                $(GIT_TARNAME)/git-gui/version
        @rm -rf $(GIT_TARNAME)
@@ -1075,8 +1073,9 @@ dist-doc:
 
 clean:
        rm -f *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o xdiff/*.o \
-               test-chmtime$X test-genrandom$X $(LIB_FILE) $(XDIFF_LIB)
+               $(LIB_FILE) $(XDIFF_LIB)
        rm -f $(ALL_PROGRAMS) $(BUILT_INS) git$X
+       rm -f $(TEST_PROGRAMS)
        rm -f *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags
        rm -rf autom4te.cache
        rm -f configure config.log config.mak.autogen config.mak.append config.status config.cache
index a1c82a863b148bf964a9639eb2864bd177a8977c..0de5e663a2ba03a15eb6711079c6bff0cba023cb 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes-1.5.2.3.txt
\ No newline at end of file
+Documentation/RelNotes-1.5.3.txt
\ No newline at end of file
index 33e76576f149d89922deda1de5548be7bc42d0eb..66fe3e375b545613faba4e051dc41c1acb5d8cee 100644 (file)
@@ -167,7 +167,7 @@ static void write_entry(const unsigned char *sha1, struct strbuf *path,
        } else {
                if (verbose)
                        fprintf(stderr, "%.*s\n", path->len, path->buf);
-               if (S_ISDIR(mode) || S_ISDIRLNK(mode)) {
+               if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
                        *header.typeflag = TYPEFLAG_DIR;
                        mode = (mode | 0777) & ~tar_umask;
                } else if (S_ISLNK(mode)) {
@@ -280,7 +280,7 @@ static int write_tar_entry(const unsigned char *sha1,
        memcpy(path.buf + baselen, filename, filenamelen);
        path.len = baselen + filenamelen;
        path.buf[path.len] = '\0';
-       if (S_ISDIR(mode) || S_ISDIRLNK(mode)) {
+       if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
                strbuf_append_string(&path, "/");
                buffer = NULL;
                size = 0;
index 3cbf6bb8ac4045803140ca5019126015e817155e..444e1623db66fe4f5d8983e1e9e2cf4083b005b4 100644 (file)
@@ -182,7 +182,7 @@ static int write_zip_entry(const unsigned char *sha1,
                goto out;
        }
 
-       if (S_ISDIR(mode) || S_ISDIRLNK(mode)) {
+       if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
                method = 0;
                attr2 = 16;
                result = (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
index 11b1a048b489fa2bb15e4b723e5fe36920f48eee..9e3ae038e818f4e21bc50f864fc5204f6fa44daa 100644 (file)
@@ -49,7 +49,7 @@ void SHA1_Update(SHA_CTX *c, const void *p, unsigned long n)
 void SHA1_Final(unsigned char *hash, SHA_CTX *c)
 {
        uint64_t bitlen;
-       uint32_t bitlen_hi, bitlen_lo; 
+       uint32_t bitlen_hi, bitlen_lo;
        unsigned int i, offset, padlen;
        unsigned char bits[8];
        static const unsigned char padding[64] = { 0x80, };
@@ -69,7 +69,7 @@ void SHA1_Final(unsigned char *hash, SHA_CTX *c)
        bits[5] = bitlen_lo >> 16;
        bits[6] = bitlen_lo >> 8;
        bits[7] = bitlen_lo;
-       SHA1_Update(c, bits, 8); 
+       SHA1_Update(c, bits, 8);
 
        for (i = 0; i < 5; i++) {
                uint32_t v = c->hash[i];
index a328b73375a318228e309419c524c8de0860ed89..8c1cb99fb403875af85e4d1524d21f7eb818f59b 100644 (file)
@@ -181,4 +181,3 @@ sha_transform:
 
 .L_sha_K:
        .word   0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6
-
index 159117106a3db52b430cb1bf82d094e54693f690..734547994f3a35e04fc7fdea10396c0c87bc6f0d 100644 (file)
@@ -40,42 +40,29 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p
        dir->nr = dst - dir->entries;
 
        for (i = 0; i < specs; i++) {
-               struct stat st;
-               const char *match;
-               if (seen[i])
-                       continue;
-
-               match = pathspec[i];
-               if (!match[0])
-                       continue;
-
-               /* Existing file? We must have ignored it */
-               if (!lstat(match, &st)) {
-                       struct dir_entry *ent;
-
-                       ent = dir_add_name(dir, match, strlen(match));
-                       ent->ignored = 1;
-                       if (S_ISDIR(st.st_mode))
-                               ent->ignored_dir = 1;
-                       continue;
-               }
-               die("pathspec '%s' did not match any files", match);
+               if (!seen[i] && !file_exists(pathspec[i]))
+                       die("pathspec '%s' did not match any files",
+                                       pathspec[i]);
        }
 }
 
-static void fill_directory(struct dir_struct *dir, const char **pathspec)
+static void fill_directory(struct dir_struct *dir, const char **pathspec,
+               int ignored_too)
 {
        const char *path, *base;
        int baselen;
 
        /* Set up the default git porcelain excludes */
        memset(dir, 0, sizeof(*dir));
-       dir->exclude_per_dir = ".gitignore";
-       path = git_path("info/exclude");
-       if (!access(path, R_OK))
-               add_excludes_from_file(dir, path);
-       if (!access(excludes_file, R_OK))
-               add_excludes_from_file(dir, excludes_file);
+       if (!ignored_too) {
+               dir->collect_ignored = 1;
+               dir->exclude_per_dir = ".gitignore";
+               path = git_path("info/exclude");
+               if (!access(path, R_OK))
+                       add_excludes_from_file(dir, path);
+               if (!access(excludes_file, R_OK))
+                       add_excludes_from_file(dir, excludes_file);
+       }
 
        /*
         * Calculate common prefix for the pathspec, and
@@ -219,13 +206,11 @@ int cmd_add(int argc, const char **argv, const char *prefix)
        }
        pathspec = get_pathspec(prefix, argv + i);
 
-       fill_directory(&dir, pathspec);
+       fill_directory(&dir, pathspec, ignored_too);
 
        if (show_only) {
                const char *sep = "", *eof = "";
                for (i = 0; i < dir.nr; i++) {
-                       if (!ignored_too && dir.entries[i]->ignored)
-                               continue;
                        printf("%s%s", sep, dir.entries[i]->name);
                        sep = " ";
                        eof = "\n";
@@ -237,25 +222,13 @@ int cmd_add(int argc, const char **argv, const char *prefix)
        if (read_cache() < 0)
                die("index file corrupt");
 
-       if (!ignored_too) {
-               int has_ignored = 0;
-               for (i = 0; i < dir.nr; i++)
-                       if (dir.entries[i]->ignored)
-                               has_ignored = 1;
-               if (has_ignored) {
-                       fprintf(stderr, ignore_warning);
-                       for (i = 0; i < dir.nr; i++) {
-                               if (!dir.entries[i]->ignored)
-                                       continue;
-                               fprintf(stderr, "%s", dir.entries[i]->name);
-                               if (dir.entries[i]->ignored_dir)
-                                       fprintf(stderr, " (directory)");
-                               fputc('\n', stderr);
-                       }
-                       fprintf(stderr,
-                               "Use -f if you really want to add them.\n");
-                       exit(1);
+       if (dir.ignored_nr) {
+               fprintf(stderr, ignore_warning);
+               for (i = 0; i < dir.ignored_nr; i++) {
+                       fprintf(stderr, "%s\n", dir.ignored[i]->name);
                }
+               fprintf(stderr, "Use -f if you really want to add them.\n");
+               exit(1);
        }
 
        for (i = 0; i < dir.nr; i++)
index 9db7cfe74c7a8583995e6c20c4eedebf58391fbc..fc43eed36b55e4966796490b8c0a02fae790229c 100644 (file)
@@ -22,4 +22,3 @@ int cmd_annotate(int argc, const char **argv, const char *prefix)
 
        return cmd_blame(argc + 1, nargv, prefix);
 }
-
index 490e23ef40c2b2d16272c67a67a14a1eb03b3877..0a0b4a9e3f6550b6a4729e94242811dcb6e8d09a 100644 (file)
@@ -55,7 +55,7 @@ static enum whitespace_eol {
 } new_whitespace = warn_on_whitespace;
 static int whitespace_error;
 static int squelch_whitespace_errors = 5;
-static int applied_after_stripping;
+static int applied_after_fixing_ws;
 static const char *patch_input_file;
 
 static void parse_whitespace_option(const char *option)
@@ -1661,7 +1661,7 @@ static int apply_line(char *output, const char *patch, int plen)
        if (add_nl_to_tail)
                output[plen++] = '\n';
        if (fixed)
-               applied_after_stripping++;
+               applied_after_fixing_ws++;
        return output + plen - buf;
 }
 
@@ -1675,6 +1675,7 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
        char *new = xmalloc(size);
        const char *oldlines, *newlines;
        int oldsize = 0, newsize = 0;
+       int new_blank_lines_at_end = 0;
        unsigned long leading, trailing;
        int pos, lines;
 
@@ -1682,6 +1683,7 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
                char first;
                int len = linelen(patch, size);
                int plen;
+               int added_blank_line = 0;
 
                if (!len)
                        break;
@@ -1703,6 +1705,7 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
                        else if (first == '+')
                                first = '-';
                }
+
                switch (first) {
                case '\n':
                        /* Newer GNU diff, empty context line */
@@ -1720,9 +1723,14 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
                                break;
                /* Fall-through for ' ' */
                case '+':
-                       if (first != '+' || !no_add)
-                               newsize += apply_line(new + newsize, patch,
-                                                     plen);
+                       if (first != '+' || !no_add) {
+                               int added = apply_line(new + newsize, patch,
+                                                      plen);
+                               newsize += added;
+                               if (first == '+' &&
+                                   added == 1 && new[newsize-1] == '\n')
+                                       added_blank_line = 1;
+                       }
                        break;
                case '@': case '\\':
                        /* Ignore it, we already handled it */
@@ -1732,6 +1740,10 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
                                error("invalid start of line: '%c'", first);
                        return -1;
                }
+               if (added_blank_line)
+                       new_blank_lines_at_end++;
+               else
+                       new_blank_lines_at_end = 0;
                patch += len;
                size -= len;
        }
@@ -1774,9 +1786,16 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i
                if (match_beginning && offset)
                        offset = -1;
                if (offset >= 0) {
-                       int diff = newsize - oldsize;
-                       unsigned long size = desc->size + diff;
-                       unsigned long alloc = desc->alloc;
+                       int diff;
+                       unsigned long size, alloc;
+
+                       if (new_whitespace == strip_whitespace &&
+                           (desc->size - oldsize - offset == 0)) /* end of file? */
+                               newsize -= new_blank_lines_at_end;
+
+                       diff = newsize - oldsize;
+                       size = desc->size + diff;
+                       alloc = desc->alloc;
 
                        /* Warn if it was necessary to reduce the number
                         * of context lines.
@@ -2869,18 +2888,17 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
                                squelched == 1 ? "" : "s");
                }
                if (new_whitespace == error_on_whitespace)
-                       die("%d line%s add%s trailing whitespaces.",
+                       die("%d line%s add%s whitespace errors.",
                            whitespace_error,
                            whitespace_error == 1 ? "" : "s",
                            whitespace_error == 1 ? "s" : "");
-               if (applied_after_stripping)
+               if (applied_after_fixing_ws)
                        fprintf(stderr, "warning: %d line%s applied after"
-                               " stripping trailing whitespaces.\n",
-                               applied_after_stripping,
-                               applied_after_stripping == 1 ? "" : "s");
+                               " fixing whitespace errors.\n",
+                               applied_after_fixing_ws,
+                               applied_after_fixing_ws == 1 ? "" : "s");
                else if (whitespace_error)
-                       fprintf(stderr, "warning: %d line%s add%s trailing"
-                               " whitespaces.\n",
+                       fprintf(stderr, "warning: %d line%s add%s whitespace errors.\n",
                                whitespace_error,
                                whitespace_error == 1 ? "" : "s",
                                whitespace_error == 1 ? "s" : "");
index 7f4e409c998ba4a864bd39032556d71693ff6793..187491bc172571b783a0be4f4dfa3d94d58bb0fe 100644 (file)
@@ -45,7 +45,7 @@ static int run_remote_archiver(const char *remote, int argc,
        }
 
        url = xstrdup(remote);
-       pid = git_connect(fd, url, exec);
+       pid = git_connect(fd, url, exec, 0);
        if (pid < 0)
                return pid;
 
index 35471fc2615992451c8c5b51a346fe171029b572..0519339098f3258ae6cc2b50d30679a8cfc7f2c7 100644 (file)
@@ -20,7 +20,7 @@
 #include "mailmap.h"
 
 static char blame_usage[] =
-"git-blame [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-p] [-L n,m] [-S <revs-file>] [-M] [-C] [-C] [--contents <filename>] [--incremental] [commit] [--] file\n"
+"git-blame [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-p] [-w] [-L n,m] [-S <revs-file>] [-M] [-C] [-C] [--contents <filename>] [--incremental] [commit] [--] file\n"
 "  -c                  Use the same output mode as git-annotate (Default: off)\n"
 "  -b                  Show blank SHA-1 for boundary commits (Default: off)\n"
 "  -l                  Show long commit SHA1 (Default: off)\n"
@@ -30,6 +30,7 @@ static char blame_usage[] =
 "  -n, --show-number   Show original linenumber (Default: off)\n"
 "  -s                  Suppress author name and timestamp (Default: off)\n"
 "  -p, --porcelain     Show in a format designed for machine consumption\n"
+"  -w                  Ignore whitespace differences\n"
 "  -L n,m              Process only line range n,m, counting from 1\n"
 "  -M, -C              Find line movements within and across files\n"
 "  --incremental       Show blame entries as we find them, incrementally\n"
@@ -45,6 +46,7 @@ static int show_root;
 static int blank_boundary;
 static int incremental;
 static int cmd_is_annotate;
+static int xdl_opts = XDF_NEED_MINIMAL;
 static struct path_list mailmap;
 
 #ifndef DEBUG
@@ -515,9 +517,9 @@ static struct patch *compare_buffer(mmfile_t *file_p, mmfile_t *file_o,
        xdemitconf_t xecfg;
        xdemitcb_t ecb;
 
-       xpp.flags = XDF_NEED_MINIMAL;
+       xpp.flags = xdl_opts;
+       memset(&xecfg, 0, sizeof(xecfg));
        xecfg.ctxlen = context;
-       xecfg.flags = 0;
        ecb.outf = xdiff_outf;
        ecb.priv = &state;
        memset(&state, 0, sizeof(state));
@@ -1457,6 +1459,7 @@ static void found_guilty_entry(struct blame_entry *ent)
                                printf("boundary\n");
                }
                write_filename_info(suspect->path);
+               maybe_flush_or_die(stdout, "stdout");
        }
 }
 
@@ -1744,11 +1747,11 @@ static int read_ancestry(const char *graft_file)
  */
 static int lineno_width(int lines)
 {
-        int i, width;
+       int i, width;
 
-        for (width = 1, i = 10; i <= lines + 1; width++)
-                i *= 10;
-        return width;
+       for (width = 1, i = 10; i <= lines + 1; width++)
+               i *= 10;
+       return width;
 }
 
 /*
@@ -2159,6 +2162,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                        output_option |= OUTPUT_LONG_OBJECT_NAME;
                else if (!strcmp("-s", arg))
                        output_option |= OUTPUT_NO_AUTHOR;
+               else if (!strcmp("-w", arg))
+                       xdl_opts |= XDF_IGNORE_WHITESPACE;
                else if (!strcmp("-S", arg) && ++i < argc)
                        revs_file = argv[i];
                else if (!prefixcmp(arg, "-M")) {
index 94dba6e232343e9b8f1d6d24bb800880607495ed..423c30194c2fecae6c565e2bf36de26fdcfee27e 100644 (file)
@@ -22,7 +22,7 @@ static const char builtin_branch_usage[] =
 static const char *head;
 static unsigned char head_sha1[20];
 
-static int branch_track_remotes;
+static int branch_track = 1; /* 0 = none, 1 = remotes, 2 = all */
 
 static int branch_use_color;
 static char branch_colors[][COLOR_MAXLEN] = {
@@ -55,7 +55,7 @@ static int parse_branch_color_slot(const char *var, int ofs)
        die("bad config variable '%s'", var);
 }
 
-int git_branch_config(const char *var, const char *value)
+static int git_branch_config(const char *var, const char *value)
 {
        if (!strcmp(var, "color.branch")) {
                branch_use_color = git_config_colorbool(var, value);
@@ -66,13 +66,17 @@ int git_branch_config(const char *var, const char *value)
                color_parse(value, var, branch_colors[slot]);
                return 0;
        }
-       if (!strcmp(var, "branch.autosetupmerge"))
-               branch_track_remotes = git_config_bool(var, value);
+       if (!strcmp(var, "branch.autosetupmerge")) {
+               if (!strcmp(value, "all"))
+                       branch_track = 2;
+               else
+                       branch_track = git_config_bool(var, value);
+       }
 
        return git_default_config(var, value);
 }
 
-const char *branch_get_color(enum color_branch ix)
+static const char *branch_get_color(enum color_branch ix)
 {
        if (branch_use_color)
                return branch_colors[ix];
@@ -85,6 +89,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
        unsigned char sha1[20];
        char *name = NULL;
        const char *fmt, *remote;
+       char section[PATH_MAX];
        int i;
        int ret = 0;
 
@@ -152,9 +157,13 @@ static int delete_branches(int argc, const char **argv, int force, int kinds)
                        error("Error deleting %sbranch '%s'", remote,
                               argv[i]);
                        ret = 1;
-               } else
+               } else {
                        printf("Deleted %sbranch %s.\n", remote, argv[i]);
-
+                       snprintf(section, sizeof(section), "branch.%s",
+                                argv[i]);
+                       if (git_config_rename_section(section, NULL) < 0)
+                               warning("Update of config-file failed");
+               }
        }
 
        if (name)
@@ -242,7 +251,6 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
        char c;
        int color;
        struct commit *commit;
-       char subject[256];
 
        switch (item->kind) {
        case REF_LOCAL_BRANCH:
@@ -263,17 +271,23 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
        }
 
        if (verbose) {
+               char *subject = NULL;
+               unsigned long subject_len = 0;
+               const char *sub = " **** invalid ref ****";
+
                commit = lookup_commit(item->sha1);
-               if (commit && !parse_commit(commit))
+               if (commit && !parse_commit(commit)) {
                        pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
-                                           subject, sizeof(subject), 0,
+                                           &subject, &subject_len, 0,
                                            NULL, NULL, 0);
-               else
-                       strcpy(subject, " **** invalid ref ****");
+                       sub = subject;
+               }
                printf("%c %s%-*s%s %s %s\n", c, branch_get_color(color),
                       maxwidth, item->name,
                       branch_get_color(COLOR_BRANCH_RESET),
-                      find_unique_abbrev(item->sha1, abbrev), subject);
+                      find_unique_abbrev(item->sha1, abbrev), sub);
+               if (subject)
+                       free(subject);
        } else {
                printf("%c %s%s%s\n", c, branch_get_color(color), item->name,
                       branch_get_color(COLOR_BRANCH_RESET));
@@ -477,7 +491,7 @@ static void create_branch(const char *name, const char *start_name,
                die("Not a valid branch point: '%s'.", start_name);
        hashcpy(sha1, commit->object.sha1);
 
-       lock = lock_any_ref_for_update(ref, NULL);
+       lock = lock_any_ref_for_update(ref, NULL, 0);
        if (!lock)
                die("Failed to lock ref for update: %s.", strerror(errno));
 
@@ -494,7 +508,9 @@ static void create_branch(const char *name, const char *start_name,
        /* When branching off a remote branch, set up so that git-pull
           automatically merges from there.  So far, this is only done for
           remotes registered via .git/config.  */
-       if (real_ref && track)
+       if (real_ref && (track == 2 ||
+                               (track == 1 &&
+                                !prefixcmp(real_ref, "refs/remotes/"))))
                set_branch_defaults(name, real_ref);
 
        if (write_ref_sha1(lock, sha1, msg) < 0)
@@ -554,7 +570,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
        int i;
 
        git_config(git_branch_config);
-       track = branch_track_remotes;
+       track = branch_track;
 
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
@@ -566,7 +582,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                        break;
                }
                if (!strcmp(arg, "--track")) {
-                       track = 1;
+                       track = 2;
                        continue;
                }
                if (!strcmp(arg, "--no-track")) {
index dbc2339d0f98d561e0263354321a5f2566f9918a..7d2063c1d2e9564306bb2807548f28a067ccdb88 100644 (file)
@@ -2,7 +2,7 @@
 #include "cache.h"
 
 static const char git_config_set_usage[] =
-"git-config [ --global | --system ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list";
+"git-config [ --global | --system ] [ --bool | --int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list";
 
 static char *key;
 static regex_t *key_regexp;
@@ -12,14 +12,17 @@ static int use_key_regexp;
 static int do_all;
 static int do_not_match;
 static int seen;
+static char delim = '=';
+static char key_delim = ' ';
+static char term = '\n';
 static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;
 
 static int show_all_config(const char *key_, const char *value_)
 {
        if (value_)
-               printf("%s=%s\n", key_, value_);
+               printf("%s%c%s%c", key_, delim, value_, term);
        else
-               printf("%s\n", key_);
+               printf("%s%c", key_, term);
        return 0;
 }
 
@@ -40,7 +43,7 @@ static int show_config(const char* key_, const char* value_)
 
        if (show_keys) {
                if (value_)
-                       printf("%s ", key_);
+                       printf("%s%c", key_, key_delim);
                else
                        printf("%s", key_);
        }
@@ -58,7 +61,7 @@ static int show_config(const char* key_, const char* value_)
                                key_, vptr);
        }
        else
-               printf("%s\n", vptr);
+               printf("%s%c", vptr, term);
 
        return 0;
 }
@@ -135,9 +138,33 @@ free_strings:
        return ret;
 }
 
+char *normalize_value(const char *key, const char *value)
+{
+       char *normalized;
+
+       if (!value)
+               return NULL;
+
+       if (type == T_RAW)
+               normalized = xstrdup(value);
+       else {
+               normalized = xmalloc(64);
+               if (type == T_INT) {
+                       int v = git_config_int(key, value);
+                       sprintf(normalized, "%d", v);
+               }
+               else if (type == T_BOOL)
+                       sprintf(normalized, "%s",
+                               git_config_bool(key, value) ? "true" : "false");
+       }
+
+       return normalized;
+}
+
 int cmd_config(int argc, const char **argv, const char *prefix)
 {
        int nongit = 0;
+       char* value;
        setup_git_directory_gently(&nongit);
 
        while (1 < argc) {
@@ -151,14 +178,19 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                        char *home = getenv("HOME");
                        if (home) {
                                char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
-                               setenv("GIT_CONFIG", user_config, 1);
+                               setenv(CONFIG_ENVIRONMENT, user_config, 1);
                                free(user_config);
                        } else {
                                die("$HOME not set");
                        }
                }
                else if (!strcmp(argv[1], "--system"))
-                       setenv("GIT_CONFIG", ETC_GITCONFIG, 1);
+                       setenv(CONFIG_ENVIRONMENT, ETC_GITCONFIG, 1);
+               else if (!strcmp(argv[1], "--null") || !strcmp(argv[1], "-z")) {
+                       term = '\0';
+                       delim = '\n';
+                       key_delim = '\n';
+               }
                else if (!strcmp(argv[1], "--rename-section")) {
                        int ret;
                        if (argc != 4)
@@ -209,9 +241,10 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                        use_key_regexp = 1;
                        do_all = 1;
                        return get_value(argv[2], NULL);
-               } else
-
-                       return git_config_set(argv[1], argv[2]);
+               } else {
+                       value = normalize_value(argv[1], argv[2]);
+                       return git_config_set(argv[1], value);
+               }
        case 4:
                if (!strcmp(argv[1], "--unset"))
                        return git_config_set_multivar(argv[2], NULL, argv[3], 0);
@@ -227,17 +260,21 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                        use_key_regexp = 1;
                        do_all = 1;
                        return get_value(argv[2], argv[3]);
-               } else if (!strcmp(argv[1], "--add"))
-                       return git_config_set_multivar(argv[2], argv[3], "^$", 0);
-               else if (!strcmp(argv[1], "--replace-all"))
-
-                       return git_config_set_multivar(argv[2], argv[3], NULL, 1);
-               else
-
-                       return git_config_set_multivar(argv[1], argv[2], argv[3], 0);
+               } else if (!strcmp(argv[1], "--add")) {
+                       value = normalize_value(argv[2], argv[3]);
+                       return git_config_set_multivar(argv[2], value, "^$", 0);
+               } else if (!strcmp(argv[1], "--replace-all")) {
+                       value = normalize_value(argv[2], argv[3]);
+                       return git_config_set_multivar(argv[2], value, NULL, 1);
+               } else {
+                       value = normalize_value(argv[1], argv[2]);
+                       return git_config_set_multivar(argv[1], value, argv[3], 0);
+               }
        case 5:
-               if (!strcmp(argv[1], "--replace-all"))
-                       return git_config_set_multivar(argv[2], argv[3], argv[4], 1);
+               if (!strcmp(argv[1], "--replace-all")) {
+                       value = normalize_value(argv[2], argv[3]);
+                       return git_config_set_multivar(argv[2], value, argv[4], 1);
+               }
        case 1:
        default:
                usage(git_config_set_usage);
index ff90ebd465002882781507ecfcfc33cab2f759fc..4274ec19500953bd7b6775e6d66271e9e116fa86 100644 (file)
@@ -111,6 +111,8 @@ int cmd_count_objects(int ac, const char **av, const char *prefix)
                for (p = packed_git; p; p = p->next) {
                        if (!p->pack_local)
                                continue;
+                       if (open_pack_index(p))
+                               continue;
                        packed += p->num_objects;
                        num_pack++;
                }
index 165917e40db78e7105a16d6e7a1653862a29fdc5..669110cb0645629ca5b152d8328aa91d63be1550 100644 (file)
@@ -3,6 +3,7 @@
 #include "tag.h"
 #include "refs.h"
 #include "builtin.h"
+#include "exec_cmd.h"
 
 #define SEEN           (1u<<0)
 #define MAX_TAGS       (FLAG_BITS - 1)
@@ -242,12 +243,15 @@ static void describe(const char *arg, int last_one)
 int cmd_describe(int argc, const char **argv, const char *prefix)
 {
        int i;
+       int contains = 0;
 
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
 
                if (*arg != '-')
                        break;
+               else if (!strcmp(arg, "--contains"))
+                       contains = 1;
                else if (!strcmp(arg, "--debug"))
                        debug = 1;
                else if (!strcmp(arg, "--all"))
@@ -272,6 +276,16 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
 
        save_commit_buffer = 0;
 
+       if (contains) {
+               const char **args = xmalloc((4 + argc - i) * sizeof(char*));
+               args[0] = "name-rev";
+               args[1] = "--name-only";
+               args[2] = "--tags";
+               memcpy(args + 3, argv + i, (argc - i) * sizeof(char*));
+               args[3 + argc - i] = NULL;
+               return cmd_name_rev(3 + argc - i, args, prefix);
+       }
+
        if (argc <= i)
                describe("HEAD", 1);
        else
index d90eba95a6be17bd0486e0311c2657b1f69ab7d9..81e7167438ecfc25a6f9a317af663034d653588e 100644 (file)
@@ -23,7 +23,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
        argc = setup_revisions(argc, argv, &rev, NULL);
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
-                       
+
                if (!strcmp(arg, "--cached"))
                        cached = 1;
                else
index 12adb3833cd60771f8e63b2ebaecff3769fa74e2..ed4d5de5d5e6d0bef5b29f3d21a3e58ff7778c8b 100644 (file)
@@ -42,7 +42,7 @@ static int update_ref(const char *action,
        if (!rla)
                rla = "(reflog update)";
        snprintf(msg, sizeof(msg), "%s: %s", rla, action);
-       lock = lock_any_ref_for_update(refname, oldval);
+       lock = lock_any_ref_for_update(refname, oldval, 0);
        if (!lock)
                return 1;
        if (write_ref_sha1(lock, sha1, msg) < 0)
index 5c145d2165027adc5e5d44c6dda969e1ed86be57..ae60fccea74077b4d2456919d2f911f8a257c5b4 100644 (file)
@@ -357,4 +357,3 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
 
        return 0;
 }
-
index 44ce629a498f986f239e008a61d32e10968907e0..a6ef65ea321c614c7616862a44ce0af7998e5749 100644 (file)
@@ -20,6 +20,8 @@ static int check_strict;
 static int keep_cache_objects;
 static unsigned char head_sha1[20];
 static int errors_found;
+static int write_lost_and_found;
+static int verbose;
 #define ERROR_OBJECT 01
 #define ERROR_REACHABLE 02
 
@@ -137,6 +139,21 @@ static void check_unreachable_object(struct object *obj)
        if (!obj->used) {
                printf("dangling %s %s\n", typename(obj->type),
                       sha1_to_hex(obj->sha1));
+               if (write_lost_and_found) {
+                       char *filename = git_path("lost-found/%s/%s",
+                               obj->type == OBJ_COMMIT ? "commit" : "other",
+                               sha1_to_hex(obj->sha1));
+                       FILE *f;
+
+                       if (safe_create_leading_directories(filename)) {
+                               error("Could not create lost-found");
+                               return;
+                       }
+                       if (!(f = fopen(filename, "w")))
+                               die("Could not open %s", filename);
+                       fprintf(f, "%s\n", sha1_to_hex(obj->sha1));
+                       fclose(f);
+               }
                return;
        }
 
@@ -149,6 +166,9 @@ static void check_unreachable_object(struct object *obj)
 
 static void check_object(struct object *obj)
 {
+       if (verbose)
+               fprintf(stderr, "Checking %s\n", sha1_to_hex(obj->sha1));
+
        if (obj->flags & REACHABLE)
                check_reachable_object(obj);
        else
@@ -161,6 +181,9 @@ static void check_connectivity(void)
 
        /* Look up all the requirements, warn about missing objects.. */
        max = get_max_object_index();
+       if (verbose)
+               fprintf(stderr, "Checking connectivity (%d objects)\n", max);
+
        for (i = 0; i < max; i++) {
                struct object *obj = get_indexed_object(i);
 
@@ -229,6 +252,10 @@ static int fsck_tree(struct tree *item)
        const char *o_name;
        const unsigned char *o_sha1;
 
+       if (verbose)
+               fprintf(stderr, "Checking tree %s\n",
+                               sha1_to_hex(item->object.sha1));
+
        init_tree_desc(&desc, item->buffer, item->size);
 
        o_mode = 0;
@@ -256,7 +283,7 @@ static int fsck_tree(struct tree *item)
                case S_IFREG | 0644:
                case S_IFLNK:
                case S_IFDIR:
-               case S_IFDIRLNK:
+               case S_IFGITLINK:
                        break;
                /*
                 * This is nonstandard, but we had a few of these
@@ -317,6 +344,10 @@ static int fsck_commit(struct commit *commit)
        char *buffer = commit->buffer;
        unsigned char tree_sha1[20], sha1[20];
 
+       if (verbose)
+               fprintf(stderr, "Checking commit %s\n",
+                       sha1_to_hex(commit->object.sha1));
+
        if (memcmp(buffer, "tree ", 5))
                return objerror(&commit->object, "invalid format - expected 'tree' line");
        if (get_sha1_hex(buffer+5, tree_sha1) || buffer[45] != '\n')
@@ -336,7 +367,7 @@ static int fsck_commit(struct commit *commit)
        if (!commit->parents && show_root)
                printf("root %s\n", sha1_to_hex(commit->object.sha1));
        if (!commit->date)
-               printf("bad commit date in %s\n", 
+               printf("bad commit date in %s\n",
                       sha1_to_hex(commit->object.sha1));
        return 0;
 }
@@ -345,6 +376,10 @@ static int fsck_tag(struct tag *tag)
 {
        struct object *tagged = tag->tagged;
 
+       if (verbose)
+               fprintf(stderr, "Checking tag %s\n",
+                       sha1_to_hex(tag->object.sha1));
+
        if (!tagged) {
                return objerror(&tag->object, "could not load tagged object");
        }
@@ -446,6 +481,9 @@ static void fsck_dir(int i, char *path)
        if (!dir)
                return;
 
+       if (verbose)
+               fprintf(stderr, "Checking directory %s\n", path);
+
        while ((de = readdir(dir)) != NULL) {
                char name[100];
                unsigned char sha1[20];
@@ -480,6 +518,10 @@ static int fsck_handle_reflog_ent(unsigned char *osha1, unsigned char *nsha1,
 {
        struct object *obj;
 
+       if (verbose)
+               fprintf(stderr, "Checking reflog %s->%s\n",
+                       sha1_to_hex(osha1), sha1_to_hex(nsha1));
+
        if (!is_null_sha1(osha1)) {
                obj = lookup_object(osha1);
                if (obj) {
@@ -549,6 +591,10 @@ static void get_default_heads(void)
 static void fsck_object_dir(const char *path)
 {
        int i;
+
+       if (verbose)
+               fprintf(stderr, "Checking object directory\n");
+
        for (i = 0; i < 256; i++) {
                static char dir[4096];
                sprintf(dir, "%s/%02x", path, i);
@@ -564,6 +610,9 @@ static int fsck_head_link(void)
        int null_is_error = 0;
        const char *head_points_at = resolve_ref("HEAD", sha1, 0, &flag);
 
+       if (verbose)
+               fprintf(stderr, "Checking HEAD link\n");
+
        if (!head_points_at)
                return error("Invalid HEAD");
        if (!strcmp(head_points_at, "HEAD"))
@@ -586,6 +635,9 @@ static int fsck_cache_tree(struct cache_tree *it)
        int i;
        int err = 0;
 
+       if (verbose)
+               fprintf(stderr, "Checking cache tree\n");
+
        if (0 <= it->entry_count) {
                struct object *obj = parse_object(it->sha1);
                if (!obj) {
@@ -605,7 +657,7 @@ static int fsck_cache_tree(struct cache_tree *it)
 
 static const char fsck_usage[] =
 "git-fsck [--tags] [--root] [[--unreachable] [--cache] [--full] "
-"[--strict] <head-sha1>*]";
+"[--strict] [--verbose] <head-sha1>*]";
 
 int cmd_fsck(int argc, char **argv, const char *prefix)
 {
@@ -645,6 +697,16 @@ int cmd_fsck(int argc, char **argv, const char *prefix)
                        check_strict = 1;
                        continue;
                }
+               if (!strcmp(arg, "--verbose")) {
+                       verbose = 1;
+                       continue;
+               }
+               if (!strcmp(arg, "--lost-found")) {
+                       check_full = 1;
+                       include_reflogs = 0;
+                       write_lost_and_found = 1;
+                       continue;
+               }
                if (*arg == '-')
                        usage(fsck_usage);
        }
@@ -668,7 +730,10 @@ int cmd_fsck(int argc, char **argv, const char *prefix)
                        verify_pack(p, 0);
 
                for (p = packed_git; p; p = p->next) {
-                       uint32_t i, num = p->num_objects;
+                       uint32_t i, num;
+                       if (open_pack_index(p))
+                               continue;
+                       num = p->num_objects;
                        for (i = 0; i < num; i++)
                                fsck_sha1(nth_packed_object_sha1(p, i));
                }
@@ -676,7 +741,7 @@ int cmd_fsck(int argc, char **argv, const char *prefix)
 
        heads = 0;
        for (i = 1; i < argc; i++) {
-               const char *arg = argv[i]; 
+               const char *arg = argv[i];
 
                if (*arg == '-')
                        continue;
@@ -715,7 +780,7 @@ int cmd_fsck(int argc, char **argv, const char *prefix)
                        struct object *obj;
 
                        mode = ntohl(active_cache[i]->ce_mode);
-                       if (S_ISDIRLNK(mode))
+                       if (S_ISGITLINK(mode))
                                continue;
                        blob = lookup_blob(active_cache[i]->sha1);
                        if (!blob)
index 3b1f8c2f3e6d352b43c671a409898c43cf1119ec..45025fba30c1fb594a696c26a7eac11862cfd8f9 100644 (file)
 
 #define FAILED_RUN "failed to run %s"
 
-static const char builtin_gc_usage[] = "git-gc [--prune]";
+static const char builtin_gc_usage[] = "git-gc [--prune] [--aggressive]";
 
-static int pack_refs = -1;
+static int pack_refs = 1;
+static int aggressive_window = -1;
 
-static const char *argv_pack_refs[] = {"pack-refs", "--prune", NULL};
+#define MAX_ADD 10
+static const char *argv_pack_refs[] = {"pack-refs", "--all", "--prune", NULL};
 static const char *argv_reflog[] = {"reflog", "expire", "--all", NULL};
-static const char *argv_repack[] = {"repack", "-a", "-d", "-l", NULL};
+static const char *argv_repack[MAX_ADD] = {"repack", "-a", "-d", "-l", NULL};
 static const char *argv_prune[] = {"prune", NULL};
 static const char *argv_rerere[] = {"rerere", "gc", NULL};
 
@@ -34,13 +36,31 @@ static int gc_config(const char *var, const char *value)
                        pack_refs = git_config_bool(var, value);
                return 0;
        }
+       if (!strcmp(var, "gc.aggressivewindow")) {
+               aggressive_window = git_config_int(var, value);
+               return 0;
+       }
        return git_default_config(var, value);
 }
 
+static void append_option(const char **cmd, const char *opt, int max_length)
+{
+       int i;
+
+       for (i = 0; cmd[i]; i++)
+               ;
+
+       if (i + 2 >= max_length)
+               die("Too many options specified");
+       cmd[i++] = opt;
+       cmd[i] = NULL;
+}
+
 int cmd_gc(int argc, const char **argv, const char *prefix)
 {
        int i;
        int prune = 0;
+       char buf[80];
 
        git_config(gc_config);
 
@@ -53,6 +73,14 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
                        prune = 1;
                        continue;
                }
+               if (!strcmp(arg, "--aggressive")) {
+                       append_option(argv_repack, "-f", MAX_ADD);
+                       if (aggressive_window > 0) {
+                               sprintf(buf, "--window=%d", aggressive_window);
+                               append_option(argv_repack, buf, MAX_ADD);
+                       }
+                       continue;
+               }
                /* perhaps other parameters later... */
                break;
        }
index 4df9fd0fad7bbc3fd0cde1e6e57b902fbd277608..66ddaebcc581e4c4bf4dfc66d4171cf988f0d815 100644 (file)
@@ -7,7 +7,7 @@
 #include "builtin.h"
 
 #ifndef DEFAULT_GIT_TEMPLATE_DIR
-#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates/"
+#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates"
 #endif
 
 #ifdef NO_TRUSTABLE_FILEMODE
@@ -40,7 +40,8 @@ static int copy_file(const char *dst, const char *src, int mode)
                return fdo;
        }
        status = copy_fd(fdi, fdo);
-       close(fdo);
+       if (close(fdo) != 0)
+               return error("%s: write error: %s", dst, strerror(errno));
 
        if (!status && adjust_shared_perm(dst))
                return -1;
@@ -173,7 +174,36 @@ static void copy_templates(const char *git_dir, int len, const char *template_di
        closedir(dir);
 }
 
-static int create_default_files(const char *git_dir, const char *template_path)
+/*
+ * Get the full path to the working tree specified in $GIT_WORK_TREE
+ * or NULL if no working tree is specified.
+ */
+static const char *get_work_tree(void)
+{
+       const char *git_work_tree;
+       char cwd[PATH_MAX];
+       static char worktree[PATH_MAX];
+
+       git_work_tree = getenv(GIT_WORK_TREE_ENVIRONMENT);
+       if (!git_work_tree)
+               return NULL;
+       if (!getcwd(cwd, sizeof(cwd)))
+               die("Unable to read current working directory");
+       if (chdir(git_work_tree))
+               die("Cannot change directory to specified working tree '%s'",
+                       git_work_tree);
+       if (git_work_tree[0] != '/') {
+               if (!getcwd(worktree, sizeof(worktree)))
+                       die("Unable to read current working directory");
+               git_work_tree = worktree;
+       }
+       if (chdir(cwd))
+               die("Cannot come back to cwd");
+       return git_work_tree;
+}
+
+static int create_default_files(const char *git_dir, const char *git_work_tree,
+       const char *template_path)
 {
        unsigned len = strlen(git_dir);
        static char path[PATH_MAX];
@@ -252,7 +282,7 @@ static int create_default_files(const char *git_dir, const char *template_path)
        }
        git_config_set("core.filemode", filemode ? "true" : "false");
 
-       if (is_bare_repository()) {
+       if (is_bare_repository() && !git_work_tree) {
                git_config_set("core.bare", "true");
        }
        else {
@@ -260,12 +290,14 @@ static int create_default_files(const char *git_dir, const char *template_path)
                /* allow template config file to override the default */
                if (log_all_ref_updates == -1)
                    git_config_set("core.logallrefupdates", "true");
+               if (git_work_tree)
+                       git_config_set("core.worktree", git_work_tree);
        }
        return reinit;
 }
 
 static const char init_db_usage[] =
-"git-init [--template=<template-directory>] [--shared]";
+"git-init [-q | --quiet] [--template=<template-directory>] [--shared]";
 
 /*
  * If you want to, you can share the DB area with any number of branches.
@@ -276,10 +308,12 @@ static const char init_db_usage[] =
 int cmd_init_db(int argc, const char **argv, const char *prefix)
 {
        const char *git_dir;
+       const char *git_work_tree;
        const char *sha1_dir;
        const char *template_dir = NULL;
        char *path;
        int len, i, reinit;
+       int quiet = 0;
 
        for (i = 1; i < argc; i++, argv++) {
                const char *arg = argv[1];
@@ -289,10 +323,14 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
                        shared_repository = PERM_GROUP;
                else if (!prefixcmp(arg, "--shared="))
                        shared_repository = git_config_perm("arg", arg+9);
+               else if (!strcmp(arg, "-q") || !strcmp(arg, "--quiet"))
+                       quiet = 1;
                else
                        usage(init_db_usage);
        }
 
+       git_work_tree = get_work_tree();
+
        /*
         * Set up the default .git directory contents
         */
@@ -308,7 +346,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
         */
        check_repository_format();
 
-       reinit = create_default_files(git_dir, template_dir);
+       reinit = create_default_files(git_dir, git_work_tree, template_dir);
 
        /*
         * And set up the object store.
@@ -335,10 +373,11 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
                git_config_set("receive.denyNonFastforwards", "true");
        }
 
-       printf("%s%s Git repository in %s/\n",
-               reinit ? "Reinitialized existing" : "Initialized empty",
-               shared_repository ? " shared" : "",
-               git_dir);
+       if (!quiet)
+               printf("%s%s Git repository in %s/\n",
+                      reinit ? "Reinitialized existing" : "Initialized empty",
+                      shared_repository ? " shared" : "",
+                      git_dir);
 
        return 0;
 }
index 37447123f924149f012a298eaf31dacb0c87b724..13bae3110e05b804db22149e9eb366669a8147c7 100644 (file)
@@ -16,6 +16,7 @@
 #include "refs.h"
 
 static int default_show_root = 1;
+static const char *fmt_patch_subject_prefix = "PATCH";
 
 /* this is in builtin-diff.c */
 void add_head(struct rev_info *revs);
@@ -55,18 +56,18 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
        rev->commit_format = CMIT_FMT_DEFAULT;
        rev->verbose_header = 1;
        rev->show_root_diff = default_show_root;
+       rev->subject_prefix = fmt_patch_subject_prefix;
        argc = setup_revisions(argc, argv, rev, "HEAD");
        if (rev->diffopt.pickaxe || rev->diffopt.filter)
                rev->always_show_header = 0;
+       if (rev->diffopt.follow_renames) {
+               rev->always_show_header = 0;
+               if (rev->diffopt.nr_paths != 1)
+                       usage("git logs can only follow renames on one pathname at a time");
+       }
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
-               if (!prefixcmp(arg, "--encoding=")) {
-                       arg += 11;
-                       if (strcmp(arg, "none"))
-                               git_log_output_encoding = xstrdup(arg);
-                       else
-                               git_log_output_encoding = "";
-               } else if (!strcmp(arg, "--decorate")) {
+               if (!strcmp(arg, "--decorate")) {
                        if (!decorate)
                                for_each_ref(add_ref_decoration, NULL);
                        decorate = 1;
@@ -95,6 +96,12 @@ static int cmd_log_walk(struct rev_info *rev)
 
 static int git_log_config(const char *var, const char *value)
 {
+       if (!strcmp(var, "format.subjectprefix")) {
+               if (!value)
+                       die("format.subjectprefix without value");
+               fmt_patch_subject_prefix = xstrdup(value);
+               return 0;
+       }
        if (!strcmp(var, "log.showroot")) {
                default_show_root = git_config_bool(var, value);
                return 0;
@@ -291,6 +298,7 @@ static int git_format_config(const char *var, const char *value)
        if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) {
                return 0;
        }
+
        return git_log_config(var, value);
 }
 
@@ -298,7 +306,8 @@ static int git_format_config(const char *var, const char *value)
 static FILE *realstdout = NULL;
 static const char *output_directory = NULL;
 
-static int reopen_stdout(struct commit *commit, int nr, int keep_subject)
+static int reopen_stdout(struct commit *commit, int nr, int keep_subject,
+                        int numbered_files)
 {
        char filename[PATH_MAX];
        char *sol;
@@ -315,53 +324,61 @@ static int reopen_stdout(struct commit *commit, int nr, int keep_subject)
                        filename[len++] = '/';
        }
 
-       sprintf(filename + len, "%04d", nr);
-       len = strlen(filename);
-
-       sol = strstr(commit->buffer, "\n\n");
-       if (sol) {
-               int j, space = 1;
-
-               sol += 2;
-               /* strip [PATCH] or [PATCH blabla] */
-               if (!keep_subject && !prefixcmp(sol, "[PATCH")) {
-                       char *eos = strchr(sol + 6, ']');
-                       if (eos) {
-                               while (isspace(*eos))
-                                       eos++;
-                               sol = eos;
-                       }
-               }
+       if (numbered_files) {
+               sprintf(filename + len, "%d", nr);
+               len = strlen(filename);
+
+       } else {
+               sprintf(filename + len, "%04d", nr);
+               len = strlen(filename);
 
-               for (j = 0;
-                    j < FORMAT_PATCH_NAME_MAX - suffix_len - 5 &&
-                            len < sizeof(filename) - suffix_len &&
-                            sol[j] && sol[j] != '\n';
-                    j++) {
-                       if (istitlechar(sol[j])) {
-                               if (space) {
-                                       filename[len++] = '-';
-                                       space = 0;
+               sol = strstr(commit->buffer, "\n\n");
+               if (sol) {
+                       int j, space = 1;
+
+                       sol += 2;
+                       /* strip [PATCH] or [PATCH blabla] */
+                       if (!keep_subject && !prefixcmp(sol, "[PATCH")) {
+                               char *eos = strchr(sol + 6, ']');
+                               if (eos) {
+                                       while (isspace(*eos))
+                                               eos++;
+                                       sol = eos;
                                }
-                               filename[len++] = sol[j];
-                               if (sol[j] == '.')
-                                       while (sol[j + 1] == '.')
-                                               j++;
-                       } else
-                               space = 1;
+                       }
+
+                       for (j = 0;
+                            j < FORMAT_PATCH_NAME_MAX - suffix_len - 5 &&
+                                    len < sizeof(filename) - suffix_len &&
+                                    sol[j] && sol[j] != '\n';
+                            j++) {
+                               if (istitlechar(sol[j])) {
+                                       if (space) {
+                                               filename[len++] = '-';
+                                               space = 0;
+                                       }
+                                       filename[len++] = sol[j];
+                                       if (sol[j] == '.')
+                                               while (sol[j + 1] == '.')
+                                                       j++;
+                               } else
+                                       space = 1;
+                       }
+                       while (filename[len - 1] == '.'
+                              || filename[len - 1] == '-')
+                               len--;
+                       filename[len] = 0;
                }
-               while (filename[len - 1] == '.' || filename[len - 1] == '-')
-                       len--;
-               filename[len] = 0;
+               if (len + suffix_len >= sizeof(filename))
+                       return error("Patch pathname too long");
+               strcpy(filename + len, fmt_patch_suffix);
        }
-       if (len + suffix_len >= sizeof(filename))
-               return error("Patch pathname too long");
-       strcpy(filename + len, fmt_patch_suffix);
+
        fprintf(realstdout, "%s\n", filename);
        if (freopen(filename, "w", stdout) == NULL)
                return error("Cannot open patch file %s",filename);
-       return 0;
 
+       return 0;
 }
 
 static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids, const char *prefix)
@@ -431,6 +448,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        int numbered = 0;
        int start_number = -1;
        int keep_subject = 0;
+       int numbered_files = 0;         /* _just_ numbers */
        int subject_prefix = 0;
        int ignore_if_in_upstream = 0;
        int thread = 0;
@@ -450,6 +468,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        rev.diffopt.msg_sep = "";
        rev.diffopt.recursive = 1;
 
+       rev.subject_prefix = fmt_patch_subject_prefix;
        rev.extra_headers = extra_headers;
 
        /*
@@ -465,6 +484,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                        numbered = 1;
                else if (!prefixcmp(argv[i], "--start-number="))
                        start_number = strtol(argv[i] + 15, NULL, 10);
+               else if (!strcmp(argv[i], "--numbered-files"))
+                       numbered_files = 1;
                else if (!strcmp(argv[i], "--start-number")) {
                        i++;
                        if (i == argc)
@@ -540,6 +561,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                die ("-n and -k are mutually exclusive.");
        if (keep_subject && subject_prefix)
                die ("--subject-prefix and -k are mutually exclusive.");
+       if (numbered_files && use_stdout)
+               die ("--numbered-files and --stdout are mutually exclusive.");
 
        argc = setup_revisions(argc, argv, &rev, "HEAD");
        if (argc > 1)
@@ -576,7 +599,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                get_patch_ids(&rev, &ids, prefix);
 
        if (!use_stdout)
-               realstdout = fdopen(dup(1), "w");
+               realstdout = xfdopen(xdup(1), "w");
 
        prepare_revision_walk(&rev);
        while ((commit = get_revision(&rev)) != NULL) {
@@ -614,7 +637,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                        rev.message_id = message_id;
                }
                if (!use_stdout)
-                       if (reopen_stdout(commit, rev.nr, keep_subject))
+                       if (reopen_stdout(commit, rev.nr, keep_subject,
+                                         numbered_files))
                                die("Failed to create output files");
                shown = log_tree_commit(&rev, commit);
                free(commit->buffer);
@@ -733,11 +757,13 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
                        sign = '-';
 
                if (verbose) {
-                       static char buf[16384];
+                       char *buf = NULL;
+                       unsigned long buflen = 0;
                        pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
-                                           buf, sizeof(buf), 0, NULL, NULL, 0);
+                                           &buf, &buflen, 0, NULL, NULL, 0);
                        printf("%c %s %s\n", sign,
                               sha1_to_hex(commit->object.sha1), buf);
+                       free(buf);
                }
                else {
                        printf("%c %s\n", sign,
index f7c066b24b7a6a728fd2f0bf4a92a31fb4a695dd..61577ea13ffdf0143dcb8a13c37ae49c1f8f2018 100644 (file)
@@ -117,7 +117,7 @@ static void show_other_files(struct dir_struct *dir)
                if (0 <= pos)
                        continue;       /* exact match */
                pos = -pos - 1;
-               if (pos < active_nr) { 
+               if (pos < active_nr) {
                        ce = active_cache[pos];
                        if (ce_namelen(ce) == len &&
                            !memcmp(ce->name, ent->name, len))
@@ -470,7 +470,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
        }
 
        if (require_work_tree &&
-                       (is_bare_repository() || is_inside_git_dir()))
+                       (!is_inside_work_tree() || is_inside_git_dir()))
                die("This operation must be run in a work tree");
 
        pathspec = get_pathspec(prefix, argv + i);
index 1cb4dca277b511315d3b914239c57621fc60bcf3..cb4be4fabb84bafd5518e81d2fd0ed6ee191641c 100644 (file)
@@ -15,6 +15,7 @@ static int line_termination = '\n';
 #define LS_TREE_ONLY 2
 #define LS_SHOW_TREES 4
 #define LS_NAME_ONLY 8
+#define LS_SHOW_SIZE 16
 static int abbrev;
 static int ls_options;
 static const char **pathspec;
@@ -22,7 +23,7 @@ static int chomp_prefix;
 static const char *ls_tree_prefix;
 
 static const char ls_tree_usage[] =
-       "git-ls-tree [-d] [-r] [-t] [-z] [--name-only] [--name-status] [--full-name] [--abbrev[=<n>]] <tree-ish> [path...]";
+       "git-ls-tree [-d] [-r] [-t] [-l] [-z] [--name-only] [--name-status] [--full-name] [--abbrev[=<n>]] <tree-ish> [path...]";
 
 static int show_recursive(const char *base, int baselen, const char *pathname)
 {
@@ -59,8 +60,9 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
 {
        int retval = 0;
        const char *type = blob_type;
+       unsigned long size;
 
-       if (S_ISDIRLNK(mode)) {
+       if (S_ISGITLINK(mode)) {
                /*
                 * Maybe we want to have some recursive version here?
                 *
@@ -92,10 +94,24 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
            (baselen < chomp_prefix || memcmp(ls_tree_prefix, base, chomp_prefix)))
                return 0;
 
-       if (!(ls_options & LS_NAME_ONLY))
-               printf("%06o %s %s\t", mode, type,
-                               abbrev ? find_unique_abbrev(sha1,abbrev)
-                                       : sha1_to_hex(sha1));
+       if (!(ls_options & LS_NAME_ONLY)) {
+               if (ls_options & LS_SHOW_SIZE) {
+                       if (!strcmp(type, blob_type)) {
+                               sha1_object_info(sha1, &size);
+                               printf("%06o %s %s %7lu\t", mode, type,
+                                      abbrev ? find_unique_abbrev(sha1, abbrev)
+                                             : sha1_to_hex(sha1),
+                                      size);
+                       } else
+                               printf("%06o %s %s %7c\t", mode, type,
+                                      abbrev ? find_unique_abbrev(sha1, abbrev)
+                                             : sha1_to_hex(sha1),
+                                      '-');
+               } else
+                       printf("%06o %s %s\t", mode, type,
+                              abbrev ? find_unique_abbrev(sha1, abbrev)
+                                     : sha1_to_hex(sha1));
+       }
        write_name_quoted(base + chomp_prefix, baselen - chomp_prefix,
                          pathname,
                          line_termination, stdout);
@@ -126,12 +142,19 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
                case 't':
                        ls_options |= LS_SHOW_TREES;
                        break;
+               case 'l':
+                       ls_options |= LS_SHOW_SIZE;
+                       break;
                case '-':
                        if (!strcmp(argv[1]+2, "name-only") ||
                            !strcmp(argv[1]+2, "name-status")) {
                                ls_options |= LS_NAME_ONLY;
                                break;
                        }
+                       if (!strcmp(argv[1]+2, "long")) {
+                               ls_options |= LS_SHOW_SIZE;
+                               break;
+                       }
                        if (!strcmp(argv[1]+2, "full-name")) {
                                chomp_prefix = 0;
                                break;
index c95e477e831dd436f074bbca9b2b9ca5ad5a5eb1..489c2c58c01514ac3d967d1c3f46f1243f853580 100644 (file)
@@ -851,8 +851,8 @@ static void handle_info(void)
        fprintf(fout, "\n");
 }
 
-int mailinfo(FILE *in, FILE *out, int ks, const char *encoding,
-            const char *msg, const char *patch)
+static int mailinfo(FILE *in, FILE *out, int ks, const char *encoding,
+                   const char *msg, const char *patch)
 {
        keep_subject = ks;
        metainfo_charset = encoding;
index 3bca855aae857cde15f2a249f8e0a5c30b3e7d82..43fc373a15cbe935054b47f9bd67c04ecf216e4e 100644 (file)
@@ -6,9 +6,10 @@
  */
 #include "cache.h"
 #include "builtin.h"
+#include "path-list.h"
 
 static const char git_mailsplit_usage[] =
-"git-mailsplit [-d<prec>] [-f<n>] [-b] -o<directory> <mbox>...";
+"git-mailsplit [-d<prec>] [-f<n>] [-b] -o<directory> <mbox>|<Maildir>...";
 
 static int is_from_line(const char *line, int len)
 {
@@ -96,44 +97,107 @@ static int split_one(FILE *mbox, const char *name, int allow_bare)
        exit(1);
 }
 
-int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip)
+static int populate_maildir_list(struct path_list *list, const char *path)
 {
-       char *name = xmalloc(strlen(dir) + 2 + 3 * sizeof(skip));
+       DIR *dir;
+       struct dirent *dent;
+
+       if ((dir = opendir(path)) == NULL) {
+               error("cannot opendir %s (%s)", path, strerror(errno));
+               return -1;
+       }
+
+       while ((dent = readdir(dir)) != NULL) {
+               if (dent->d_name[0] == '.')
+                       continue;
+               path_list_insert(dent->d_name, list);
+       }
+
+       closedir(dir);
+
+       return 0;
+}
+
+static int split_maildir(const char *maildir, const char *dir,
+       int nr_prec, int skip)
+{
+       char file[PATH_MAX];
+       char curdir[PATH_MAX];
+       char name[PATH_MAX];
        int ret = -1;
+       int i;
+       struct path_list list = {NULL, 0, 0, 1};
 
-       while (*mbox) {
-               const char *file = *mbox++;
-               FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r");
-               int file_done = 0;
+       snprintf(curdir, sizeof(curdir), "%s/cur", maildir);
+       if (populate_maildir_list(&list, curdir) < 0)
+               goto out;
 
-               if ( !f ) {
-                       error("cannot open mbox %s", file);
+       for (i = 0; i < list.nr; i++) {
+               FILE *f;
+               snprintf(file, sizeof(file), "%s/%s", curdir, list.items[i].path);
+               f = fopen(file, "r");
+               if (!f) {
+                       error("cannot open mail %s (%s)", file, strerror(errno));
                        goto out;
                }
 
                if (fgets(buf, sizeof(buf), f) == NULL) {
-                       if (f == stdin)
-                               break; /* empty stdin is OK */
-                       error("cannot read mbox %s", file);
+                       error("cannot read mail %s (%s)", file, strerror(errno));
                        goto out;
                }
 
-               while (!file_done) {
-                       sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
-                       file_done = split_one(f, name, allow_bare);
+               sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
+               split_one(f, name, 1);
+
+               fclose(f);
+       }
+
+       path_list_clear(&list, 1);
+
+       ret = skip;
+out:
+       return ret;
+}
+
+static int split_mbox(const char *file, const char *dir, int allow_bare,
+                     int nr_prec, int skip)
+{
+       char name[PATH_MAX];
+       int ret = -1;
+
+       FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r");
+       int file_done = 0;
+
+       if (!f) {
+               error("cannot open mbox %s", file);
+               goto out;
+       }
+
+       if (fgets(buf, sizeof(buf), f) == NULL) {
+               /* empty stdin is OK */
+               if (f != stdin) {
+                       error("cannot read mbox %s", file);
+                       goto out;
                }
+               file_done = 1;
+       }
 
-               if (f != stdin)
-                       fclose(f);
+       while (!file_done) {
+               sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
+               file_done = split_one(f, name, allow_bare);
        }
+
+       if (f != stdin)
+               fclose(f);
+
        ret = skip;
 out:
-       free(name);
        return ret;
 }
+
 int cmd_mailsplit(int argc, const char **argv, const char *prefix)
 {
-       int nr = 0, nr_prec = 4, ret;
+       int nr = 0, nr_prec = 4, num = 0;
        int allow_bare = 0;
        const char *dir = NULL;
        const char **argp;
@@ -186,9 +250,41 @@ int cmd_mailsplit(int argc, const char **argv, const char *prefix)
                        argp = stdin_only;
        }
 
-       ret = split_mbox(argp, dir, allow_bare, nr_prec, nr);
-       if (ret != -1)
-               printf("%d\n", ret);
+       while (*argp) {
+               const char *arg = *argp++;
+               struct stat argstat;
+               int ret = 0;
+
+               if (arg[0] == '-' && arg[1] == 0) {
+                       ret = split_mbox(arg, dir, allow_bare, nr_prec, nr);
+                       if (ret < 0) {
+                               error("cannot split patches from stdin");
+                               return 1;
+                       }
+                       num += (ret - nr);
+                       nr = ret;
+                       continue;
+               }
+
+               if (stat(arg, &argstat) == -1) {
+                       error("cannot stat %s (%s)", arg, strerror(errno));
+                       return 1;
+               }
+
+               if (S_ISDIR(argstat.st_mode))
+                       ret = split_maildir(arg, dir, nr_prec, nr);
+               else
+                       ret = split_mbox(arg, dir, allow_bare, nr_prec, nr);
+
+               if (ret < 0) {
+                       error("cannot split patches from %s", arg);
+                       return 1;
+               }
+               num += (ret - nr);
+               nr = ret;
+       }
+
+       printf("%d\n", num);
 
-       return ret == -1;
+       return 0;
 }
index 913577390862a847857a650516740059072b60ad..10ec63b17e6b16382f2b39e5c01cc6cf1dce448e 100644 (file)
@@ -36,9 +36,13 @@ int cmd_merge_file(int argc, char **argv, char **envp)
        for (; i < 3; i++)
                names[i] = argv[i + 1];
 
-       for (i = 0; i < 3; i++)
+       for (i = 0; i < 3; i++) {
                if (read_mmfile(mmfs + i, argv[i + 1]))
                        return -1;
+               if (buffer_is_binary(mmfs[i].ptr, mmfs[i].size))
+                       return error("Cannot merge binary files: %s\n",
+                                       argv[i + 1]);
+       }
 
        ret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],
                        &xpp, XDL_MERGE_ZEALOUS, &result);
index 2d94eaaa6a90f2efe4401873930533b12b85522f..61eba343ab781341a0baf127b323508a0c2af332 100644 (file)
@@ -85,6 +85,7 @@ copy_data:
 
 struct name_ref_data {
        int tags_only;
+       int name_only;
        const char *ref_filter;
 };
 
@@ -112,6 +113,10 @@ static int name_ref(const char *path, const unsigned char *sha1, int flags, void
 
                if (!prefixcmp(path, "refs/heads/"))
                        path = path + 11;
+               else if (data->tags_only
+                   && data->name_only
+                   && !prefixcmp(path, "refs/tags/"))
+                       path = path + 10;
                else if (!prefixcmp(path, "refs/"))
                        path = path + 5;
 
@@ -151,7 +156,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
 {
        struct object_array revs = { 0, 0, NULL };
        int as_is = 0, all = 0, transform_stdin = 0;
-       struct name_ref_data data = { 0, NULL };
+       struct name_ref_data data = { 0, 0, NULL };
 
        git_config(git_default_config);
 
@@ -167,6 +172,9 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
                        if (!strcmp(*argv, "--")) {
                                as_is = 1;
                                continue;
+                       } else if (!strcmp(*argv, "--name-only")) {
+                               data.name_only = 1;
+                               continue;
                        } else if (!strcmp(*argv, "--tags")) {
                                data.tags_only = 1;
                                continue;
@@ -267,16 +275,18 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
                        struct object * obj = get_indexed_object(i);
                        if (!obj)
                                continue;
-                       printf("%s %s\n", sha1_to_hex(obj->sha1), get_rev_name(obj));
+                       if (!data.name_only)
+                               printf("%s ", sha1_to_hex(obj->sha1));
+                       printf("%s\n", get_rev_name(obj));
                }
        } else {
                int i;
-               for (i = 0; i < revs.nr; i++)
-                       printf("%s %s\n",
-                               revs.objects[i].name,
-                               get_rev_name(revs.objects[i].item));
+               for (i = 0; i < revs.nr; i++) {
+                       if (!data.name_only)
+                               printf("%s ", revs.objects[i].name);
+                       printf("%s\n", get_rev_name(revs.objects[i].item));
+               }
        }
 
        return 0;
 }
-
index 966f843e4357d45b8c9acf96617bdacd8dc1b133..3d396ca37ac1356c7974aaaf34af39bcd0cf6bae 100644 (file)
@@ -1,5 +1,6 @@
 #include "builtin.h"
 #include "cache.h"
+#include "attr.h"
 #include "object.h"
 #include "blob.h"
 #include "commit.h"
 #include "progress.h"
 
 static const char pack_usage[] = "\
-git-pack-objects [{ -q | --progress | --all-progress }] \n\
+git-pack-objects [{ -q | --progress | --all-progress }] [--max-pack-size=N] \n\
        [--local] [--incremental] [--window=N] [--depth=N] \n\
-       [--no-reuse-delta] [--delta-base-offset] [--non-empty] \n\
-       [--revs [--unpacked | --all]*] [--reflog] [--stdout | base-name] \n\
-       [<ref-list | <object-list]";
+       [--no-reuse-delta] [--no-reuse-object] [--delta-base-offset] \n\
+       [--non-empty] [--revs [--unpacked | --all]*] [--reflog] \n\
+       [--stdout | base-name] [<ref-list | <object-list]";
 
 struct object_entry {
-       unsigned char sha1[20];
-       uint32_t crc32;         /* crc of raw pack data for this object */
-       off_t offset;           /* offset into the final pack file */
+       struct pack_idx_entry idx;
        unsigned long size;     /* uncompressed size */
+
        unsigned int hash;      /* name hint hash */
        unsigned int depth;     /* delta depth */
        struct packed_git *in_pack;     /* already in pack */
@@ -35,14 +35,16 @@ struct object_entry {
        struct object_entry *delta_sibling; /* other deltified objects who
                                             * uses the same base as me
                                             */
+       void *delta_data;       /* cached delta (uncompressed) */
        unsigned long delta_size;       /* delta data size (uncompressed) */
        enum object_type type;
        enum object_type in_pack_type;  /* could be delta */
        unsigned char in_pack_header_size;
        unsigned char preferred_base; /* we do not pack this, but is available
-                                      * to be used as the base objectto delta
+                                      * to be used as the base object to delta
                                       * objects against.
                                       */
+       unsigned char no_try_delta;
 };
 
 /*
@@ -52,22 +54,30 @@ struct object_entry {
  * nice "minimum seek" order.
  */
 static struct object_entry *objects;
-static uint32_t nr_objects, nr_alloc, nr_result;
+static struct object_entry **written_list;
+static uint32_t nr_objects, nr_alloc, nr_result, nr_written;
 
 static int non_empty;
-static int no_reuse_delta;
+static int no_reuse_delta, no_reuse_object;
 static int local;
 static int incremental;
 static int allow_ofs_delta;
 static const char *pack_tmp_name, *idx_tmp_name;
 static char tmpname[PATH_MAX];
-static unsigned char pack_file_sha1[20];
+static const char *base_name;
 static int progress = 1;
 static int window = 10;
+static uint32_t pack_size_limit;
 static int depth = 50;
 static int pack_to_stdout;
 static int num_preferred_base;
 static struct progress progress_state;
+static int pack_compression_level = Z_DEFAULT_COMPRESSION;
+static int pack_compression_seen;
+
+static unsigned long delta_cache_size = 0;
+static unsigned long max_delta_cache_size = 0;
+static unsigned long cache_max_small_delta_size = 1000;
 
 /*
  * The object names in objects array are hashed with this hashtable,
@@ -234,15 +244,15 @@ static void *delta_against(void *buf, unsigned long size, struct object_entry *e
 {
        unsigned long othersize, delta_size;
        enum object_type type;
-       void *otherbuf = read_sha1_file(entry->delta->sha1, &type, &othersize);
+       void *otherbuf = read_sha1_file(entry->delta->idx.sha1, &type, &othersize);
        void *delta_buf;
 
        if (!otherbuf)
-               die("unable to read %s", sha1_to_hex(entry->delta->sha1));
+               die("unable to read %s", sha1_to_hex(entry->delta->idx.sha1));
         delta_buf = diff_delta(otherbuf, othersize,
                               buf, size, &delta_size, 0);
         if (!delta_buf || delta_size != entry->delta_size)
-               die("delta size changed");
+               die("delta size changed");
         free(buf);
         free(otherbuf);
        return delta_buf;
@@ -346,76 +356,45 @@ static void copy_pack_data(struct sha1file *f,
        }
 }
 
-static int check_loose_inflate(unsigned char *data, unsigned long len, unsigned long expect)
-{
-       z_stream stream;
-       unsigned char fakebuf[4096];
-       int st;
-
-       memset(&stream, 0, sizeof(stream));
-       stream.next_in = data;
-       stream.avail_in = len;
-       stream.next_out = fakebuf;
-       stream.avail_out = sizeof(fakebuf);
-       inflateInit(&stream);
-
-       while (1) {
-               st = inflate(&stream, Z_FINISH);
-               if (st == Z_STREAM_END || st == Z_OK) {
-                       st = (stream.total_out == expect &&
-                             stream.total_in == len) ? 0 : -1;
-                       break;
-               }
-               if (st != Z_BUF_ERROR) {
-                       st = -1;
-                       break;
-               }
-               stream.next_out = fakebuf;
-               stream.avail_out = sizeof(fakebuf);
-       }
-       inflateEnd(&stream);
-       return st;
-}
-
-static int revalidate_loose_object(struct object_entry *entry,
-                                  unsigned char *map,
-                                  unsigned long mapsize)
-{
-       /* we already know this is a loose object with new type header. */
-       enum object_type type;
-       unsigned long size, used;
-
-       if (pack_to_stdout)
-               return 0;
-
-       used = unpack_object_header_gently(map, mapsize, &type, &size);
-       if (!used)
-               return -1;
-       map += used;
-       mapsize -= used;
-       return check_loose_inflate(map, mapsize, size);
-}
-
 static unsigned long write_object(struct sha1file *f,
-                                 struct object_entry *entry)
+                                 struct object_entry *entry,
+                                 off_t write_offset)
 {
        unsigned long size;
        enum object_type type;
        void *buf;
        unsigned char header[10];
+       unsigned char dheader[10];
        unsigned hdrlen;
        off_t datalen;
        enum object_type obj_type;
        int to_reuse = 0;
+       /* write limit if limited packsize and not first object */
+       unsigned long limit = pack_size_limit && nr_written ?
+                               pack_size_limit - write_offset : 0;
+                               /* no if no delta */
+       int usable_delta =      !entry->delta ? 0 :
+                               /* yes if unlimited packfile */
+                               !pack_size_limit ? 1 :
+                               /* no if base written to previous pack */
+                               entry->delta->idx.offset == (off_t)-1 ? 0 :
+                               /* otherwise double-check written to this
+                                * pack,  like we do below
+                                */
+                               entry->delta->idx.offset ? 1 : 0;
 
        if (!pack_to_stdout)
                crc32_begin(f);
 
        obj_type = entry->type;
-       if (! entry->in_pack)
+       if (no_reuse_object)
+               to_reuse = 0;   /* explicit */
+       else if (!entry->in_pack)
                to_reuse = 0;   /* can't reuse what we don't have */
        else if (obj_type == OBJ_REF_DELTA || obj_type == OBJ_OFS_DELTA)
-               to_reuse = 1;   /* check_object() decided it for us */
+                               /* check_object() decided it for us ... */
+               to_reuse = usable_delta;
+                               /* ... but pack split may override that */
        else if (obj_type != entry->in_pack_type)
                to_reuse = 0;   /* pack has delta which is unusable */
        else if (entry->delta)
@@ -425,44 +404,49 @@ static unsigned long write_object(struct sha1file *f,
                                 * and we do not need to deltify it.
                                 */
 
-       if (!entry->in_pack && !entry->delta) {
-               unsigned char *map;
-               unsigned long mapsize;
-               map = map_sha1_file(entry->sha1, &mapsize);
-               if (map && !legacy_loose_object(map)) {
-                       /* We can copy straight into the pack file */
-                       if (revalidate_loose_object(entry, map, mapsize))
-                               die("corrupt loose object %s",
-                                   sha1_to_hex(entry->sha1));
-                       sha1write(f, map, mapsize);
-                       munmap(map, mapsize);
-                       written++;
-                       reused++;
-                       return mapsize;
-               }
-               if (map)
-                       munmap(map, mapsize);
-       }
-
        if (!to_reuse) {
-               buf = read_sha1_file(entry->sha1, &type, &size);
-               if (!buf)
-                       die("unable to read %s", sha1_to_hex(entry->sha1));
-               if (size != entry->size)
-                       die("object %s size inconsistency (%lu vs %lu)",
-                           sha1_to_hex(entry->sha1), size, entry->size);
-               if (entry->delta) {
+               z_stream stream;
+               unsigned long maxsize;
+               void *out;
+               if (!usable_delta) {
+                       buf = read_sha1_file(entry->idx.sha1, &obj_type, &size);
+                       if (!buf)
+                               die("unable to read %s", sha1_to_hex(entry->idx.sha1));
+               } else if (entry->delta_data) {
+                       size = entry->delta_size;
+                       buf = entry->delta_data;
+                       entry->delta_data = NULL;
+                       obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
+                               OBJ_OFS_DELTA : OBJ_REF_DELTA;
+               } else {
+                       buf = read_sha1_file(entry->idx.sha1, &type, &size);
+                       if (!buf)
+                               die("unable to read %s", sha1_to_hex(entry->idx.sha1));
                        buf = delta_against(buf, size, entry);
                        size = entry->delta_size;
-                       obj_type = (allow_ofs_delta && entry->delta->offset) ?
+                       obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
                                OBJ_OFS_DELTA : OBJ_REF_DELTA;
                }
+               /* compress the data to store and put compressed length in datalen */
+               memset(&stream, 0, sizeof(stream));
+               deflateInit(&stream, pack_compression_level);
+               maxsize = deflateBound(&stream, size);
+               out = xmalloc(maxsize);
+               /* Compress it */
+               stream.next_in = buf;
+               stream.avail_in = size;
+               stream.next_out = out;
+               stream.avail_out = maxsize;
+               while (deflate(&stream, Z_FINISH) == Z_OK)
+                       /* nothing */;
+               deflateEnd(&stream);
+               datalen = stream.total_out;
+               deflateEnd(&stream);
                /*
                 * The object header is a byte of 'type' followed by zero or
                 * more bytes of length.
                 */
                hdrlen = encode_header(obj_type, size, header);
-               sha1write(f, header, hdrlen);
 
                if (obj_type == OBJ_OFS_DELTA) {
                        /*
@@ -470,22 +454,42 @@ static unsigned long write_object(struct sha1file *f,
                         * encoding of the relative offset for the delta
                         * base from this object's position in the pack.
                         */
-                       off_t ofs = entry->offset - entry->delta->offset;
-                       unsigned pos = sizeof(header) - 1;
-                       header[pos] = ofs & 127;
+                       off_t ofs = entry->idx.offset - entry->delta->idx.offset;
+                       unsigned pos = sizeof(dheader) - 1;
+                       dheader[pos] = ofs & 127;
                        while (ofs >>= 7)
-                               header[--pos] = 128 | (--ofs & 127);
-                       sha1write(f, header + pos, sizeof(header) - pos);
-                       hdrlen += sizeof(header) - pos;
+                               dheader[--pos] = 128 | (--ofs & 127);
+                       if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit) {
+                               free(out);
+                               free(buf);
+                               return 0;
+                       }
+                       sha1write(f, header, hdrlen);
+                       sha1write(f, dheader + pos, sizeof(dheader) - pos);
+                       hdrlen += sizeof(dheader) - pos;
                } else if (obj_type == OBJ_REF_DELTA) {
                        /*
                         * Deltas with a base reference contain
                         * an additional 20 bytes for the base sha1.
                         */
-                       sha1write(f, entry->delta->sha1, 20);
+                       if (limit && hdrlen + 20 + datalen + 20 >= limit) {
+                               free(out);
+                               free(buf);
+                               return 0;
+                       }
+                       sha1write(f, header, hdrlen);
+                       sha1write(f, entry->delta->idx.sha1, 20);
                        hdrlen += 20;
+               } else {
+                       if (limit && hdrlen + datalen + 20 >= limit) {
+                               free(out);
+                               free(buf);
+                               return 0;
+                       }
+                       sha1write(f, header, hdrlen);
                }
-               datalen = sha1write_compressed(f, buf, size);
+               sha1write(f, out, datalen);
+               free(out);
                free(buf);
        }
        else {
@@ -495,45 +499,54 @@ static unsigned long write_object(struct sha1file *f,
                off_t offset;
 
                if (entry->delta) {
-                       obj_type = (allow_ofs_delta && entry->delta->offset) ?
+                       obj_type = (allow_ofs_delta && entry->delta->idx.offset) ?
                                OBJ_OFS_DELTA : OBJ_REF_DELTA;
                        reused_delta++;
                }
                hdrlen = encode_header(obj_type, entry->size, header);
-               sha1write(f, header, hdrlen);
-               if (obj_type == OBJ_OFS_DELTA) {
-                       off_t ofs = entry->offset - entry->delta->offset;
-                       unsigned pos = sizeof(header) - 1;
-                       header[pos] = ofs & 127;
-                       while (ofs >>= 7)
-                               header[--pos] = 128 | (--ofs & 127);
-                       sha1write(f, header + pos, sizeof(header) - pos);
-                       hdrlen += sizeof(header) - pos;
-               } else if (obj_type == OBJ_REF_DELTA) {
-                       sha1write(f, entry->delta->sha1, 20);
-                       hdrlen += 20;
-               }
-
                offset = entry->in_pack_offset;
                revidx = find_packed_object(p, offset);
                datalen = revidx[1].offset - offset;
                if (!pack_to_stdout && p->index_version > 1 &&
                    check_pack_crc(p, &w_curs, offset, datalen, revidx->nr))
-                       die("bad packed object CRC for %s", sha1_to_hex(entry->sha1));
+                       die("bad packed object CRC for %s", sha1_to_hex(entry->idx.sha1));
                offset += entry->in_pack_header_size;
                datalen -= entry->in_pack_header_size;
+               if (obj_type == OBJ_OFS_DELTA) {
+                       off_t ofs = entry->idx.offset - entry->delta->idx.offset;
+                       unsigned pos = sizeof(dheader) - 1;
+                       dheader[pos] = ofs & 127;
+                       while (ofs >>= 7)
+                               dheader[--pos] = 128 | (--ofs & 127);
+                       if (limit && hdrlen + sizeof(dheader) - pos + datalen + 20 >= limit)
+                               return 0;
+                       sha1write(f, header, hdrlen);
+                       sha1write(f, dheader + pos, sizeof(dheader) - pos);
+                       hdrlen += sizeof(dheader) - pos;
+               } else if (obj_type == OBJ_REF_DELTA) {
+                       if (limit && hdrlen + 20 + datalen + 20 >= limit)
+                               return 0;
+                       sha1write(f, header, hdrlen);
+                       sha1write(f, entry->delta->idx.sha1, 20);
+                       hdrlen += 20;
+               } else {
+                       if (limit && hdrlen + datalen + 20 >= limit)
+                               return 0;
+                       sha1write(f, header, hdrlen);
+               }
+
                if (!pack_to_stdout && p->index_version == 1 &&
                    check_pack_inflate(p, &w_curs, offset, datalen, entry->size))
-                       die("corrupt packed object for %s", sha1_to_hex(entry->sha1));
+                       die("corrupt packed object for %s", sha1_to_hex(entry->idx.sha1));
                copy_pack_data(f, p, &w_curs, offset, datalen);
                unuse_pack(&w_curs);
                reused++;
        }
-       if (entry->delta)
+       if (usable_delta)
                written_delta++;
        written++;
        if (!pack_to_stdout)
-               entry->crc32 = crc32_end(f);
+               entry->idx.crc32 = crc32_end(f);
        return hdrlen + datalen;
 }
 
@@ -544,15 +557,23 @@ static off_t write_one(struct sha1file *f,
        unsigned long size;
 
        /* offset is non zero if object is written already. */
-       if (e->offset || e->preferred_base)
+       if (e->idx.offset || e->preferred_base)
                return offset;
 
        /* if we are deltified, write out base object first. */
-       if (e->delta)
+       if (e->delta) {
                offset = write_one(f, e->delta, offset);
+               if (!offset)
+                       return 0;
+       }
 
-       e->offset = offset;
-       size = write_object(f, e);
+       e->idx.offset = offset;
+       size = write_object(f, e, offset);
+       if (!size) {
+               e->idx.offset = 0;
+               return 0;
+       }
+       written_list[nr_written++] = e;
 
        /* make sure off_t is sufficiently large not to wrap */
        if (offset > offset + size)
@@ -566,174 +587,114 @@ static int open_object_dir_tmp(const char *path)
     return mkstemp(tmpname);
 }
 
-static off_t write_pack_file(void)
+/* forward declaration for write_pack_file */
+static int adjust_perm(const char *path, mode_t mode);
+
+static void write_pack_file(void)
 {
-       uint32_t i;
+       uint32_t i = 0, j;
        struct sha1file *f;
-       off_t offset, last_obj_offset = 0;
+       off_t offset, offset_one, last_obj_offset = 0;
        struct pack_header hdr;
-       int do_progress = progress;
-
-       if (pack_to_stdout) {
-               f = sha1fd(1, "<stdout>");
-               do_progress >>= 1;
-       } else {
-               int fd = open_object_dir_tmp("tmp_pack_XXXXXX");
-               if (fd < 0)
-                       die("unable to create %s: %s\n", tmpname, strerror(errno));
-               pack_tmp_name = xstrdup(tmpname);
-               f = sha1fd(fd, pack_tmp_name);
-       }
+       int do_progress = progress >> pack_to_stdout;
+       uint32_t nr_remaining = nr_result;
 
        if (do_progress)
                start_progress(&progress_state, "Writing %u objects...", "", nr_result);
+       written_list = xmalloc(nr_objects * sizeof(struct object_entry *));
 
-       hdr.hdr_signature = htonl(PACK_SIGNATURE);
-       hdr.hdr_version = htonl(PACK_VERSION);
-       hdr.hdr_entries = htonl(nr_result);
-       sha1write(f, &hdr, sizeof(hdr));
-       offset = sizeof(hdr);
-       if (!nr_result)
-               goto done;
-       for (i = 0; i < nr_objects; i++) {
-               last_obj_offset = offset;
-               offset = write_one(f, objects + i, offset);
-               if (do_progress)
-                       display_progress(&progress_state, written);
-       }
-       if (do_progress)
-               stop_progress(&progress_state);
- done:
-       if (written != nr_result)
-               die("wrote %u objects while expecting %u", written, nr_result);
-       sha1close(f, pack_file_sha1, 1);
-
-       return last_obj_offset;
-}
-
-static int sha1_sort(const void *_a, const void *_b)
-{
-       const struct object_entry *a = *(struct object_entry **)_a;
-       const struct object_entry *b = *(struct object_entry **)_b;
-       return hashcmp(a->sha1, b->sha1);
-}
-
-static uint32_t index_default_version = 1;
-static uint32_t index_off32_limit = 0x7fffffff;
-
-static void write_index_file(off_t last_obj_offset, unsigned char *sha1)
-{
-       struct sha1file *f;
-       struct object_entry **sorted_by_sha, **list, **last;
-       uint32_t array[256];
-       uint32_t i, index_version;
-       SHA_CTX ctx;
-
-       int fd = open_object_dir_tmp("tmp_idx_XXXXXX");
-       if (fd < 0)
-               die("unable to create %s: %s\n", tmpname, strerror(errno));
-       idx_tmp_name = xstrdup(tmpname);
-       f = sha1fd(fd, idx_tmp_name);
-
-       if (nr_result) {
-               uint32_t j = 0;
-               sorted_by_sha =
-                       xcalloc(nr_result, sizeof(struct object_entry *));
-               for (i = 0; i < nr_objects; i++)
-                       if (!objects[i].preferred_base)
-                               sorted_by_sha[j++] = objects + i;
-               if (j != nr_result)
-                       die("listed %u objects while expecting %u", j, nr_result);
-               qsort(sorted_by_sha, nr_result, sizeof(*sorted_by_sha), sha1_sort);
-               list = sorted_by_sha;
-               last = sorted_by_sha + nr_result;
-       } else
-               sorted_by_sha = list = last = NULL;
-
-       /* if last object's offset is >= 2^31 we should use index V2 */
-       index_version = (last_obj_offset >> 31) ? 2 : index_default_version;
+       do {
+               unsigned char sha1[20];
+
+               if (pack_to_stdout) {
+                       f = sha1fd(1, "<stdout>");
+               } else {
+                       int fd = open_object_dir_tmp("tmp_pack_XXXXXX");
+                       if (fd < 0)
+                               die("unable to create %s: %s\n", tmpname, strerror(errno));
+                       pack_tmp_name = xstrdup(tmpname);
+                       f = sha1fd(fd, pack_tmp_name);
+               }
 
-       /* index versions 2 and above need a header */
-       if (index_version >= 2) {
-               struct pack_idx_header hdr;
-               hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
-               hdr.idx_version = htonl(index_version);
+               hdr.hdr_signature = htonl(PACK_SIGNATURE);
+               hdr.hdr_version = htonl(PACK_VERSION);
+               hdr.hdr_entries = htonl(nr_remaining);
                sha1write(f, &hdr, sizeof(hdr));
-       }
-
-       /*
-        * Write the first-level table (the list is sorted,
-        * but we use a 256-entry lookup to be able to avoid
-        * having to do eight extra binary search iterations).
-        */
-       for (i = 0; i < 256; i++) {
-               struct object_entry **next = list;
-               while (next < last) {
-                       struct object_entry *entry = *next;
-                       if (entry->sha1[0] != i)
+               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)
                                break;
-                       next++;
+                       offset = offset_one;
+                       if (do_progress)
+                               display_progress(&progress_state, written);
                }
-               array[i] = htonl(next - sorted_by_sha);
-               list = next;
-       }
-       sha1write(f, array, 256 * 4);
-
-       /* Compute the SHA1 hash of sorted object names. */
-       SHA1_Init(&ctx);
-
-       /* Write the actual SHA1 entries. */
-       list = sorted_by_sha;
-       for (i = 0; i < nr_result; i++) {
-               struct object_entry *entry = *list++;
-               if (index_version < 2) {
-                       uint32_t offset = htonl(entry->offset);
-                       sha1write(f, &offset, 4);
-               }
-               sha1write(f, entry->sha1, 20);
-               SHA1_Update(&ctx, entry->sha1, 20);
-       }
 
-       if (index_version >= 2) {
-               unsigned int nr_large_offset = 0;
-
-               /* write the crc32 table */
-               list = sorted_by_sha;
-               for (i = 0; i < nr_objects; i++) {
-                       struct object_entry *entry = *list++;
-                       uint32_t crc32_val = htonl(entry->crc32);
-                       sha1write(f, &crc32_val, 4);
+               /*
+                * Did we write the wrong # entries in the header?
+                * If so, rewrite it like in fast-import
+                */
+               if (pack_to_stdout || nr_written == nr_remaining) {
+                       sha1close(f, sha1, 1);
+               } else {
+                       sha1close(f, sha1, 0);
+                       fixup_pack_header_footer(f->fd, sha1, pack_tmp_name, nr_written);
+                       close(f->fd);
                }
 
-               /* write the 32-bit offset table */
-               list = sorted_by_sha;
-               for (i = 0; i < nr_objects; i++) {
-                       struct object_entry *entry = *list++;
-                       uint32_t offset = (entry->offset <= index_off32_limit) ?
-                               entry->offset : (0x80000000 | nr_large_offset++);
-                       offset = htonl(offset);
-                       sha1write(f, &offset, 4);
+               if (!pack_to_stdout) {
+                       mode_t mode = umask(0);
+
+                       umask(mode);
+                       mode = 0444 & ~mode;
+
+                       idx_tmp_name = write_idx_file(NULL,
+                               (struct pack_idx_entry **) written_list, nr_written, sha1);
+                       snprintf(tmpname, sizeof(tmpname), "%s-%s.pack",
+                                base_name, sha1_to_hex(sha1));
+                       if (adjust_perm(pack_tmp_name, mode))
+                               die("unable to make temporary pack file readable: %s",
+                                   strerror(errno));
+                       if (rename(pack_tmp_name, tmpname))
+                               die("unable to rename temporary pack file: %s",
+                                   strerror(errno));
+                       snprintf(tmpname, sizeof(tmpname), "%s-%s.idx",
+                                base_name, sha1_to_hex(sha1));
+                       if (adjust_perm(idx_tmp_name, mode))
+                               die("unable to make temporary index file readable: %s",
+                                   strerror(errno));
+                       if (rename(idx_tmp_name, tmpname))
+                               die("unable to rename temporary index file: %s",
+                                   strerror(errno));
+                       puts(sha1_to_hex(sha1));
                }
 
-               /* write the large offset table */
-               list = sorted_by_sha;
-               while (nr_large_offset) {
-                       struct object_entry *entry = *list++;
-                       uint64_t offset = entry->offset;
-                       if (offset > index_off32_limit) {
-                               uint32_t split[2];
-                               split[0]        = htonl(offset >> 32);
-                               split[1] = htonl(offset & 0xffffffff);
-                               sha1write(f, split, 8);
-                               nr_large_offset--;
-                       }
+               /* mark written objects as written to previous pack */
+               for (j = 0; j < nr_written; j++) {
+                       written_list[j]->idx.offset = (off_t)-1;
                }
-       }
+               nr_remaining -= nr_written;
+       } while (nr_remaining && i < nr_objects);
 
-       sha1write(f, pack_file_sha1, 20);
-       sha1close(f, NULL, 1);
-       free(sorted_by_sha);
-       SHA1_Final(sha1, &ctx);
+       free(written_list);
+       if (do_progress)
+               stop_progress(&progress_state);
+       if (written != nr_result)
+               die("wrote %u objects while expecting %u", written, nr_result);
+       /*
+        * We have scanned through [0 ... i).  Since we have written
+        * the correct number of objects,  the remaining [i ... nr_objects)
+        * items must be either already written (due to out-of-order delta base)
+        * or a preferred base.  Count those which are neither and complain if any.
+        */
+       for (j = 0; i < nr_objects; i++) {
+               struct object_entry *e = objects + i;
+               j += !e->idx.offset && !e->preferred_base;
+       }
+       if (j)
+               die("wrote %u objects as expected but %u unwritten", written, j);
 }
 
 static int locate_object_entry_hash(const unsigned char *sha1)
@@ -743,7 +704,7 @@ static int locate_object_entry_hash(const unsigned char *sha1)
        memcpy(&ui, sha1, sizeof(unsigned int));
        i = ui % object_ix_hashsz;
        while (0 < object_ix[i]) {
-               if (!hashcmp(sha1, objects[object_ix[i] - 1].sha1))
+               if (!hashcmp(sha1, objects[object_ix[i] - 1].idx.sha1))
                        return i;
                if (++i == object_ix_hashsz)
                        i = 0;
@@ -775,7 +736,7 @@ static void rehash_objects(void)
        object_ix = xrealloc(object_ix, sizeof(int) * object_ix_hashsz);
        memset(object_ix, 0, sizeof(int) * object_ix_hashsz);
        for (i = 0, oe = objects; i < nr_objects; i++, oe++) {
-               int ix = locate_object_entry_hash(oe->sha1);
+               int ix = locate_object_entry_hash(oe->idx.sha1);
                if (0 <= ix)
                        continue;
                ix = -1 - ix;
@@ -788,6 +749,9 @@ static unsigned name_hash(const char *name)
        unsigned char c;
        unsigned hash = 0;
 
+       if (!name)
+               return 0;
+
        /*
         * This effectively just creates a sortable number from the
         * last sixteen non-whitespace characters. Last characters
@@ -801,13 +765,36 @@ static unsigned name_hash(const char *name)
        return hash;
 }
 
+static void setup_delta_attr_check(struct git_attr_check *check)
+{
+       static struct git_attr *attr_delta;
+
+       if (!attr_delta)
+               attr_delta = git_attr("delta", 5);
+
+       check[0].attr = attr_delta;
+}
+
+static int no_try_delta(const char *path)
+{
+       struct git_attr_check check[1];
+
+       setup_delta_attr_check(check);
+       if (git_checkattr(path, ARRAY_SIZE(check), check))
+               return 0;
+       if (ATTR_FALSE(check->value))
+               return 1;
+       return 0;
+}
+
 static int add_object_entry(const unsigned char *sha1, enum object_type type,
-                           unsigned hash, int exclude)
+                           const char *name, int exclude)
 {
        struct object_entry *entry;
        struct packed_git *p, *found_pack = NULL;
        off_t found_offset = 0;
        int ix;
+       unsigned hash = name_hash(name);
 
        ix = nr_objects ? locate_object_entry_hash(sha1) : -1;
        if (ix >= 0) {
@@ -843,7 +830,7 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
 
        entry = objects + nr_objects++;
        memset(entry, 0, sizeof(*entry));
-       hashcpy(entry->sha1, sha1);
+       hashcpy(entry->idx.sha1, sha1);
        entry->hash = hash;
        if (type)
                entry->type = type;
@@ -864,6 +851,9 @@ static int add_object_entry(const unsigned char *sha1, enum object_type type,
        if (progress)
                display_progress(&progress_state, nr_objects);
 
+       if (name && no_try_delta(name))
+               entry->no_try_delta = 1;
+
        return 1;
 }
 
@@ -996,10 +986,9 @@ static void add_pbase_object(struct tree_desc *tree,
                if (cmp < 0)
                        return;
                if (name[cmplen] != '/') {
-                       unsigned hash = name_hash(fullname);
                        add_object_entry(entry.sha1,
                                         S_ISDIR(entry.mode) ? OBJ_TREE : OBJ_BLOB,
-                                        hash, 1);
+                                        fullname, 1);
                        return;
                }
                if (S_ISDIR(entry.mode)) {
@@ -1059,10 +1048,11 @@ static int check_pbase_path(unsigned hash)
        return 0;
 }
 
-static void add_preferred_base_object(const char *name, unsigned hash)
+static void add_preferred_base_object(const char *name)
 {
        struct pbase_tree *it;
        int cmplen;
+       unsigned hash = name_hash(name);
 
        if (!num_preferred_base || check_pbase_path(hash))
                return;
@@ -1070,7 +1060,7 @@ static void add_preferred_base_object(const char *name, unsigned hash)
        cmplen = name_cmp_len(name);
        for (it = pbase_tree; it; it = it->next) {
                if (cmplen == 0) {
-                       add_object_entry(it->pcache.sha1, OBJ_TREE, 0, 1);
+                       add_object_entry(it->pcache.sha1, OBJ_TREE, NULL, 1);
                }
                else {
                        struct tree_desc tree;
@@ -1125,8 +1115,8 @@ static void check_object(struct object_entry *entry)
                buf = use_pack(p, &w_curs, entry->in_pack_offset, &avail);
 
                /*
-                * We want in_pack_type even if we do not reuse delta.
-                * There is no point not reusing non-delta representations.
+                * We want in_pack_type even if we do not reuse delta
+                * since non-delta representations could still be reused.
                 */
                used = unpack_object_header_gently(buf, avail,
                                                   &entry->in_pack_type,
@@ -1160,13 +1150,13 @@ static void check_object(struct object_entry *entry)
                                ofs += 1;
                                if (!ofs || MSB(ofs, 7))
                                        die("delta base offset overflow in pack for %s",
-                                           sha1_to_hex(entry->sha1));
+                                           sha1_to_hex(entry->idx.sha1));
                                c = buf[used_0++];
                                ofs = (ofs << 7) + (c & 127);
                        }
                        if (ofs >= entry->in_pack_offset)
                                die("delta base offset out of bound for %s",
-                                   sha1_to_hex(entry->sha1));
+                                   sha1_to_hex(entry->idx.sha1));
                        ofs = entry->in_pack_offset - ofs;
                        if (!no_reuse_delta && !entry->preferred_base)
                                base_ref = find_packed_object_name(p, ofs);
@@ -1213,10 +1203,10 @@ static void check_object(struct object_entry *entry)
                unuse_pack(&w_curs);
        }
 
-       entry->type = sha1_object_info(entry->sha1, &entry->size);
+       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->sha1));
+                   sha1_to_hex(entry->idx.sha1));
 }
 
 static int pack_offset_sort(const void *_a, const void *_b)
@@ -1226,7 +1216,7 @@ static int pack_offset_sort(const void *_a, const void *_b)
 
        /* avoid filesystem trashing with loose objects */
        if (!a->in_pack && !b->in_pack)
-               return hashcmp(a->sha1, b->sha1);
+               return hashcmp(a->idx.sha1, b->idx.sha1);
 
        if (a->in_pack < b->in_pack)
                return -1;
@@ -1282,6 +1272,23 @@ struct unpacked {
        struct delta_index *index;
 };
 
+static int delta_cacheable(struct unpacked *trg, struct unpacked *src,
+                           unsigned long src_size, unsigned long trg_size,
+                           unsigned long delta_size)
+{
+       if (max_delta_cache_size && delta_cache_size + delta_size > max_delta_cache_size)
+               return 0;
+
+       if (delta_size < cache_max_small_delta_size)
+               return 1;
+
+       /* cache delta, if objects are large enough compared to delta size */
+       if ((src_size >> 20) + (trg_size >> 21) > (delta_size >> 10))
+               return 1;
+
+       return 0;
+}
+
 /*
  * We search for deltas _backwards_ in a list sorted by type and
  * by size, so that we see progressively smaller and smaller files.
@@ -1338,31 +1345,45 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
 
        /* Load data if not already done */
        if (!trg->data) {
-               trg->data = read_sha1_file(trg_entry->sha1, &type, &sz);
+               trg->data = read_sha1_file(trg_entry->idx.sha1, &type, &sz);
                if (sz != trg_size)
                        die("object %s inconsistent object length (%lu vs %lu)",
-                           sha1_to_hex(trg_entry->sha1), sz, trg_size);
+                           sha1_to_hex(trg_entry->idx.sha1), sz, trg_size);
        }
        if (!src->data) {
-               src->data = read_sha1_file(src_entry->sha1, &type, &sz);
+               src->data = read_sha1_file(src_entry->idx.sha1, &type, &sz);
                if (sz != src_size)
                        die("object %s inconsistent object length (%lu vs %lu)",
-                           sha1_to_hex(src_entry->sha1), sz, src_size);
+                           sha1_to_hex(src_entry->idx.sha1), sz, src_size);
        }
        if (!src->index) {
                src->index = create_delta_index(src->data, src_size);
-               if (!src->index)
-                       die("out of memory");
+               if (!src->index) {
+                       static int warned = 0;
+                       if (!warned++)
+                               warning("suboptimal pack - out of memory");
+                       return 0;
+               }
        }
 
        delta_buf = create_delta(src->index, trg->data, trg_size, &delta_size, max_size);
        if (!delta_buf)
                return 0;
 
+       if (trg_entry->delta_data) {
+               delta_cache_size -= trg_entry->delta_size;
+               free(trg_entry->delta_data);
+       }
+       trg_entry->delta_data = 0;
        trg_entry->delta = src_entry;
        trg_entry->delta_size = delta_size;
        trg_entry->depth = src_entry->depth + 1;
-       free(delta_buf);
+
+       if (delta_cacheable(src, trg, src_size, trg_size, delta_size)) {
+               trg_entry->delta_data = xrealloc(delta_buf, delta_size);
+               delta_cache_size += trg_entry->delta_size;
+       } else
+               free(delta_buf);
        return 1;
 }
 
@@ -1412,6 +1433,10 @@ static void find_deltas(struct object_entry **list, int window, int depth)
 
                if (entry->size < 50)
                        continue;
+
+               if (entry->no_try_delta)
+                       continue;
+
                free_delta_index(n->index);
                n->index = NULL;
                free(n->data);
@@ -1494,6 +1519,24 @@ static int git_pack_config(const char *k, const char *v)
                depth = git_config_int(k, v);
                return 0;
        }
+       if (!strcmp(k, "pack.compression")) {
+               int level = git_config_int(k, v);
+               if (level == -1)
+                       level = Z_DEFAULT_COMPRESSION;
+               else if (level < 0 || level > Z_BEST_COMPRESSION)
+                       die("bad pack compression level %d", level);
+               pack_compression_level = level;
+               pack_compression_seen = 1;
+               return 0;
+       }
+       if (!strcmp(k, "pack.deltacachesize")) {
+               max_delta_cache_size = git_config_int(k, v);
+               return 0;
+       }
+       if (!strcmp(k, "pack.deltacachelimit")) {
+               cache_max_small_delta_size = git_config_int(k, v);
+               return 0;
+       }
        return git_default_config(k, v);
 }
 
@@ -1501,7 +1544,6 @@ static void read_object_list_from_stdin(void)
 {
        char line[40 + 1 + PATH_MAX + 2];
        unsigned char sha1[20];
-       unsigned hash;
 
        for (;;) {
                if (!fgets(line, sizeof(line), stdin)) {
@@ -1524,22 +1566,20 @@ static void read_object_list_from_stdin(void)
                if (get_sha1_hex(line, sha1))
                        die("expected sha1, got garbage:\n %s", line);
 
-               hash = name_hash(line+41);
-               add_preferred_base_object(line+41, hash);
-               add_object_entry(sha1, 0, hash, 0);
+               add_preferred_base_object(line+41);
+               add_object_entry(sha1, 0, line+41, 0);
        }
 }
 
 static void show_commit(struct commit *commit)
 {
-       add_object_entry(commit->object.sha1, OBJ_COMMIT, 0, 0);
+       add_object_entry(commit->object.sha1, OBJ_COMMIT, NULL, 0);
 }
 
 static void show_object(struct object_array_entry *p)
 {
-       unsigned hash = name_hash(p->name);
-       add_preferred_base_object(p->name, hash);
-       add_object_entry(p->item->sha1, p->item->type, hash, 0);
+       add_preferred_base_object(p->name);
+       add_object_entry(p->item->sha1, p->item->type, p->name, 0);
 }
 
 static void show_edge(struct commit *commit)
@@ -1592,8 +1632,6 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
        int use_internal_rev_list = 0;
        int thin = 0;
        uint32_t i;
-       off_t last_obj_offset;
-       const char *base_name = NULL;
        const char **rp_av;
        int rp_ac_alloc = 64;
        int rp_ac;
@@ -1605,6 +1643,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
        rp_ac = 2;
 
        git_config(git_pack_config);
+       if (!pack_compression_seen && core_compression_seen)
+               pack_compression_level = core_compression_level;
 
        progress = isatty(2);
        for (i = 1; i < argc; i++) {
@@ -1625,6 +1665,25 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                        incremental = 1;
                        continue;
                }
+               if (!prefixcmp(arg, "--compression=")) {
+                       char *end;
+                       int level = strtoul(arg+14, &end, 0);
+                       if (!arg[14] || *end)
+                               usage(pack_usage);
+                       if (level == -1)
+                               level = Z_DEFAULT_COMPRESSION;
+                       else if (level < 0 || level > Z_BEST_COMPRESSION)
+                               die("bad pack compression level %d", level);
+                       pack_compression_level = level;
+                       continue;
+               }
+               if (!prefixcmp(arg, "--max-pack-size=")) {
+                       char *end;
+                       pack_size_limit = strtoul(arg+16, &end, 0) * 1024 * 1024;
+                       if (!arg[16] || *end)
+                               usage(pack_usage);
+                       continue;
+               }
                if (!prefixcmp(arg, "--window=")) {
                        char *end;
                        window = strtoul(arg+9, &end, 0);
@@ -1655,6 +1714,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                        no_reuse_delta = 1;
                        continue;
                }
+               if (!strcmp("--no-reuse-object", arg)) {
+                       no_reuse_object = no_reuse_delta = 1;
+                       continue;
+               }
                if (!strcmp("--delta-base-offset", arg)) {
                        allow_ofs_delta = 1;
                        continue;
@@ -1688,12 +1751,12 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                }
                if (!prefixcmp(arg, "--index-version=")) {
                        char *c;
-                       index_default_version = strtoul(arg + 16, &c, 10);
-                       if (index_default_version > 2)
+                       pack_idx_default_version = strtoul(arg + 16, &c, 10);
+                       if (pack_idx_default_version > 2)
                                die("bad %s", arg);
                        if (*c == ',')
-                               index_off32_limit = strtoul(c+1, &c, 0);
-                       if (*c || index_off32_limit & 0x80000000)
+                               pack_idx_off32_limit = strtoul(c+1, &c, 0);
+                       if (*c || pack_idx_off32_limit & 0x80000000)
                                die("bad %s", arg);
                        continue;
                }
@@ -1719,6 +1782,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
        if (pack_to_stdout != !base_name)
                usage(pack_usage);
 
+       if (pack_to_stdout && pack_size_limit)
+               die("--max-pack-size cannot be used to build a pack for transfer.");
+
        if (!pack_to_stdout && thin)
                die("--thin cannot be used to build an indexable pack.");
 
@@ -1744,33 +1810,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                fprintf(stderr, "Result has %u objects.\n", nr_result);
        if (nr_result)
                prepare_pack(window, depth);
-       last_obj_offset = write_pack_file();
-       if (!pack_to_stdout) {
-               unsigned char object_list_sha1[20];
-               mode_t mode = umask(0);
-
-               umask(mode);
-               mode = 0444 & ~mode;
-
-               write_index_file(last_obj_offset, object_list_sha1);
-               snprintf(tmpname, sizeof(tmpname), "%s-%s.pack",
-                        base_name, sha1_to_hex(object_list_sha1));
-               if (adjust_perm(pack_tmp_name, mode))
-                       die("unable to make temporary pack file readable: %s",
-                           strerror(errno));
-               if (rename(pack_tmp_name, tmpname))
-                       die("unable to rename temporary pack file: %s",
-                           strerror(errno));
-               snprintf(tmpname, sizeof(tmpname), "%s-%s.idx",
-                        base_name, sha1_to_hex(object_list_sha1));
-               if (adjust_perm(idx_tmp_name, mode))
-                       die("unable to make temporary index file readable: %s",
-                           strerror(errno));
-               if (rename(idx_tmp_name, tmpname))
-                       die("unable to rename temporary index file: %s",
-                           strerror(errno));
-               puts(sha1_to_hex(object_list_sha1));
-       }
+       write_pack_file();
        if (progress)
                fprintf(stderr, "Total %u (delta %u), reused %u (delta %u)\n",
                        written, written_delta, reused, reused_delta);
index d080e30d67a913529d46e0da169faa4b0be75580..758499238f6d4110eb3740b77c92753edc8e5760 100644 (file)
@@ -12,9 +12,11 @@ struct ref_to_prune {
        char name[FLEX_ARRAY];
 };
 
+#define PACK_REFS_PRUNE        0x0001
+#define PACK_REFS_ALL  0x0002
+
 struct pack_refs_cb_data {
-       int prune;
-       int all;
+       unsigned int flags;
        struct ref_to_prune *ref_to_prune;
        FILE *refs_file;
 };
@@ -39,7 +41,7 @@ static int handle_one_ref(const char *path, const unsigned char *sha1,
        is_tag_ref = !prefixcmp(path, "refs/tags/");
 
        /* ALWAYS pack refs that were already packed or are tags */
-       if (!cb->all && !is_tag_ref && !(flags & REF_ISPACKED))
+       if (!(cb->flags & PACK_REFS_ALL) && !is_tag_ref && !(flags & REF_ISPACKED))
                return 0;
 
        fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path);
@@ -53,7 +55,7 @@ static int handle_one_ref(const char *path, const unsigned char *sha1,
                }
        }
 
-       if (cb->prune && !do_not_prune(flags)) {
+       if ((cb->flags & PACK_REFS_PRUNE) && !do_not_prune(flags)) {
                int namelen = strlen(path) + 1;
                struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen);
                hashcpy(n->sha1, sha1);
@@ -85,26 +87,53 @@ static void prune_refs(struct ref_to_prune *r)
 
 static struct lock_file packed;
 
-int cmd_pack_refs(int argc, const char **argv, const char *prefix)
+static int pack_refs(unsigned int flags)
 {
-       int fd, i;
+       int fd;
        struct pack_refs_cb_data cbdata;
 
        memset(&cbdata, 0, sizeof(cbdata));
+       cbdata.flags = flags;
+
+       fd = hold_lock_file_for_update(&packed, git_path("packed-refs"), 1);
+       cbdata.refs_file = fdopen(fd, "w");
+       if (!cbdata.refs_file)
+               die("unable to create ref-pack file structure (%s)",
+                   strerror(errno));
+
+       /* perhaps other traits later as well */
+       fprintf(cbdata.refs_file, "# pack-refs with: peeled \n");
+
+       for_each_ref(handle_one_ref, &cbdata);
+       if (ferror(cbdata.refs_file))
+               die("failed to write ref-pack file");
+       if (fflush(cbdata.refs_file) || fsync(fd) || fclose(cbdata.refs_file))
+               die("failed to write ref-pack file (%s)", strerror(errno));
+       if (commit_lock_file(&packed) < 0)
+               die("unable to overwrite old ref-pack file (%s)", strerror(errno));
+       if (cbdata.flags & PACK_REFS_PRUNE)
+               prune_refs(cbdata.ref_to_prune);
+       return 0;
+}
 
-       cbdata.prune = 1;
+int cmd_pack_refs(int argc, const char **argv, const char *prefix)
+{
+       int i;
+       unsigned int flags;
+
+       flags = PACK_REFS_PRUNE;
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
                if (!strcmp(arg, "--prune")) {
-                       cbdata.prune = 1; /* now the default */
+                       flags |= PACK_REFS_PRUNE; /* now the default */
                        continue;
                }
                if (!strcmp(arg, "--no-prune")) {
-                       cbdata.prune = 0;
+                       flags &= ~PACK_REFS_PRUNE;
                        continue;
                }
                if (!strcmp(arg, "--all")) {
-                       cbdata.all = 1;
+                       flags |= PACK_REFS_ALL;
                        continue;
                }
                /* perhaps other parameters later... */
@@ -113,22 +142,5 @@ int cmd_pack_refs(int argc, const char **argv, const char *prefix)
        if (i != argc)
                usage(builtin_pack_refs_usage);
 
-       fd = hold_lock_file_for_update(&packed, git_path("packed-refs"), 1);
-       cbdata.refs_file = fdopen(fd, "w");
-       if (!cbdata.refs_file)
-               die("unable to create ref-pack file structure (%s)",
-                   strerror(errno));
-
-       /* perhaps other traits later as well */
-       fprintf(cbdata.refs_file, "# pack-refs with: peeled \n");
-
-       for_each_ref(handle_one_ref, &cbdata);
-       fflush(cbdata.refs_file);
-       fsync(fd);
-       fclose(cbdata.refs_file);
-       if (commit_lock_file(&packed) < 0)
-               die("unable to overwrite old ref-pack file (%s)", strerror(errno));
-       if (cbdata.prune)
-               prune_refs(cbdata.ref_to_prune);
-       return 0;
+       return pack_refs(flags);
 }
index cb78401c946eac9019c2e4e953c3b87ef9e214f3..2612f07f74855ad6dec8ccd605279ab3a502e5e2 100644 (file)
@@ -5,17 +5,13 @@
 #include "refs.h"
 #include "run-command.h"
 #include "builtin.h"
-
-#define MAX_URI (16)
+#include "remote.h"
 
 static const char push_usage[] = "git-push [--all] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";
 
-static int all, tags, force, thin = 1, verbose;
+static int all, force, thin = 1, verbose;
 static const char *receivepack;
 
-#define BUF_SIZE (2084)
-static char buffer[BUF_SIZE];
-
 static const char **refspec;
 static int refspec_nr;
 
@@ -27,285 +23,47 @@ static void add_refspec(const char *ref)
        refspec_nr = nr;
 }
 
-static int expand_one_ref(const char *ref, const unsigned char *sha1, int flag, void *cb_data)
-{
-       /* Ignore the "refs/" at the beginning of the refname */
-       ref += 5;
-
-       if (!prefixcmp(ref, "tags/"))
-               add_refspec(xstrdup(ref));
-       return 0;
-}
-
-static void expand_refspecs(void)
-{
-       if (all) {
-               if (refspec_nr)
-                       die("cannot mix '--all' and a refspec");
-
-               /*
-                * No need to expand "--all" - we'll just use
-                * the "--all" flag to send-pack
-                */
-               return;
-       }
-       if (!tags)
-               return;
-       for_each_ref(expand_one_ref, NULL);
-}
-
-struct wildcard_cb {
-       const char *from_prefix;
-       int from_prefix_len;
-       const char *to_prefix;
-       int to_prefix_len;
-       int force;
-};
-
-static int expand_wildcard_ref(const char *ref, const unsigned char *sha1, int flag, void *cb_data)
-{
-       struct wildcard_cb *cb = cb_data;
-       int len = strlen(ref);
-       char *expanded, *newref;
-
-       if (len < cb->from_prefix_len ||
-           memcmp(cb->from_prefix, ref, cb->from_prefix_len))
-               return 0;
-       expanded = xmalloc(len * 2 + cb->force +
-                          (cb->to_prefix_len - cb->from_prefix_len) + 2);
-       newref = expanded + cb->force;
-       if (cb->force)
-               expanded[0] = '+';
-       memcpy(newref, ref, len);
-       newref[len] = ':';
-       memcpy(newref + len + 1, cb->to_prefix, cb->to_prefix_len);
-       strcpy(newref + len + 1 + cb->to_prefix_len,
-              ref + cb->from_prefix_len);
-       add_refspec(expanded);
-       return 0;
-}
-
-static int wildcard_ref(const char *ref)
-{
-       int len;
-       const char *colon;
-       struct wildcard_cb cb;
-
-       memset(&cb, 0, sizeof(cb));
-       if (ref[0] == '+') {
-               cb.force = 1;
-               ref++;
-       }
-       len = strlen(ref);
-       colon = strchr(ref, ':');
-       if (! (colon && ref < colon &&
-              colon[-2] == '/' && colon[-1] == '*' &&
-              /* "<mine>/<asterisk>:<yours>/<asterisk>" is at least 7 bytes */
-              7 <= len &&
-              ref[len-2] == '/' && ref[len-1] == '*') )
-               return 0 ;
-       cb.from_prefix = ref;
-       cb.from_prefix_len = colon - ref - 1;
-       cb.to_prefix = colon + 1;
-       cb.to_prefix_len = len - (colon - ref) - 2;
-       for_each_ref(expand_wildcard_ref, &cb);
-       return 1;
-}
-
 static void set_refspecs(const char **refs, int nr)
 {
-       if (nr) {
-               int i;
-               for (i = 0; i < nr; i++) {
-                       const char *ref = refs[i];
-                       if (!strcmp("tag", ref)) {
-                               char *tag;
-                               int len;
-                               if (nr <= ++i)
-                                       die("tag shorthand without <tag>");
-                               len = strlen(refs[i]) + 11;
-                               tag = xmalloc(len);
-                               strcpy(tag, "refs/tags/");
-                               strcat(tag, refs[i]);
-                               ref = tag;
-                       }
-                       else if (wildcard_ref(ref))
-                               continue;
-                       add_refspec(ref);
-               }
-       }
-       expand_refspecs();
-}
-
-static int get_remotes_uri(const char *repo, const char *uri[MAX_URI])
-{
-       int n = 0;
-       FILE *f = fopen(git_path("remotes/%s", repo), "r");
-       int has_explicit_refspec = refspec_nr || all || tags;
-
-       if (!f)
-               return -1;
-       while (fgets(buffer, BUF_SIZE, f)) {
-               int is_refspec;
-               char *s, *p;
-
-               if (!prefixcmp(buffer, "URL:")) {
-                       is_refspec = 0;
-                       s = buffer + 4;
-               } else if (!prefixcmp(buffer, "Push:")) {
-                       is_refspec = 1;
-                       s = buffer + 5;
-               } else
-                       continue;
-
-               /* Remove whitespace at the head.. */
-               while (isspace(*s))
-                       s++;
-               if (!*s)
-                       continue;
-
-               /* ..and at the end */
-               p = s + strlen(s);
-               while (isspace(p[-1]))
-                       *--p = 0;
-
-               if (!is_refspec) {
-                       if (n < MAX_URI)
-                               uri[n++] = xstrdup(s);
-                       else
-                               error("more than %d URL's specified, ignoring the rest", MAX_URI);
-               }
-               else if (is_refspec && !has_explicit_refspec) {
-                       if (!wildcard_ref(s))
-                               add_refspec(xstrdup(s));
-               }
-       }
-       fclose(f);
-       if (!n)
-               die("remote '%s' has no URL", repo);
-       return n;
-}
-
-static const char **config_uri;
-static const char *config_repo;
-static int config_repo_len;
-static int config_current_uri;
-static int config_get_refspecs;
-static int config_get_receivepack;
-
-static int get_remote_config(const char* key, const char* value)
-{
-       if (!prefixcmp(key, "remote.") &&
-           !strncmp(key + 7, config_repo, config_repo_len)) {
-               if (!strcmp(key + 7 + config_repo_len, ".url")) {
-                       if (config_current_uri < MAX_URI)
-                               config_uri[config_current_uri++] = xstrdup(value);
-                       else
-                               error("more than %d URL's specified, ignoring the rest", MAX_URI);
-               }
-               else if (config_get_refspecs &&
-                        !strcmp(key + 7 + config_repo_len, ".push")) {
-                       if (!wildcard_ref(value))
-                               add_refspec(xstrdup(value));
-               }
-               else if (config_get_receivepack &&
-                        !strcmp(key + 7 + config_repo_len, ".receivepack")) {
-                       if (!receivepack) {
-                               char *rp = xmalloc(strlen(value) + 16);
-                               sprintf(rp, "--receive-pack=%s", value);
-                               receivepack = rp;
-                       } else
-                               error("more than one receivepack given, using the first");
-               }
-       }
-       return 0;
-}
-
-static int get_config_remotes_uri(const char *repo, const char *uri[MAX_URI])
-{
-       config_repo_len = strlen(repo);
-       config_repo = repo;
-       config_current_uri = 0;
-       config_uri = uri;
-       config_get_refspecs = !(refspec_nr || all || tags);
-       config_get_receivepack = (receivepack == NULL);
-
-       git_config(get_remote_config);
-       return config_current_uri;
-}
-
-static int get_branches_uri(const char *repo, const char *uri[MAX_URI])
-{
-       const char *slash = strchr(repo, '/');
-       int n = slash ? slash - repo : 1000;
-       FILE *f = fopen(git_path("branches/%.*s", n, repo), "r");
-       char *s, *p;
-       int len;
-
-       if (!f)
-               return 0;
-       s = fgets(buffer, BUF_SIZE, f);
-       fclose(f);
-       if (!s)
-               return 0;
-       while (isspace(*s))
-               s++;
-       if (!*s)
-               return 0;
-       p = s + strlen(s);
-       while (isspace(p[-1]))
-               *--p = 0;
-       len = p - s;
-       if (slash)
-               len += strlen(slash);
-       p = xmalloc(len + 1);
-       strcpy(p, s);
-       if (slash)
-               strcat(p, slash);
-       uri[0] = p;
-       return 1;
-}
-
-/*
- * Read remotes and branches file, fill the push target URI
- * list.  If there is no command line refspecs, read Push: lines
- * to set up the *refspec list as well.
- * return the number of push target URIs
- */
-static int read_config(const char *repo, const char *uri[MAX_URI])
-{
-       int n;
-
-       if (*repo != '/') {
-               n = get_remotes_uri(repo, uri);
-               if (n > 0)
-                       return n;
-
-               n = get_config_remotes_uri(repo, uri);
-               if (n > 0)
-                       return n;
-
-               n = get_branches_uri(repo, uri);
-               if (n > 0)
-                       return n;
+       int i;
+       for (i = 0; i < nr; i++) {
+               const char *ref = refs[i];
+               if (!strcmp("tag", ref)) {
+                       char *tag;
+                       int len;
+                       if (nr <= ++i)
+                               die("tag shorthand without <tag>");
+                       len = strlen(refs[i]) + 11;
+                       tag = xmalloc(len);
+                       strcpy(tag, "refs/tags/");
+                       strcat(tag, refs[i]);
+                       ref = tag;
+               }
+               add_refspec(ref);
        }
-
-       uri[0] = repo;
-       return 1;
 }
 
 static int do_push(const char *repo)
 {
-       const char *uri[MAX_URI];
-       int i, n, errs;
+       int i, errs;
        int common_argc;
        const char **argv;
        int argc;
+       struct remote *remote = remote_get(repo);
 
-       n = read_config(repo, uri);
-       if (n <= 0)
+       if (!remote)
                die("bad repository '%s'", repo);
 
+       if (remote->receivepack) {
+               char *rp = xmalloc(strlen(remote->receivepack) + 16);
+               sprintf(rp, "--receive-pack=%s", remote->receivepack);
+               receivepack = rp;
+       }
+       if (!refspec && !all && remote->push_refspec_nr) {
+               refspec = remote->push_refspec;
+               refspec_nr = remote->push_refspec_nr;
+       }
+
        argv = xmalloc((refspec_nr + 10) * sizeof(char *));
        argv[0] = "dummy-send-pack";
        argc = 1;
@@ -318,18 +76,23 @@ static int do_push(const char *repo)
        common_argc = argc;
 
        errs = 0;
-       for (i = 0; i < n; i++) {
+       for (i = 0; i < remote->uri_nr; i++) {
                int err;
                int dest_argc = common_argc;
                int dest_refspec_nr = refspec_nr;
                const char **dest_refspec = refspec;
-               const char *dest = uri[i];
+               const char *dest = remote->uri[i];
                const char *sender = "send-pack";
                if (!prefixcmp(dest, "http://") ||
                    !prefixcmp(dest, "https://"))
                        sender = "http-push";
-               else if (thin)
-                       argv[dest_argc++] = "--thin";
+               else {
+                       char *rem = xmalloc(strlen(remote->name) + 10);
+                       sprintf(rem, "--remote=%s", remote->name);
+                       argv[dest_argc++] = rem;
+                       if (thin)
+                               argv[dest_argc++] = "--thin";
+               }
                argv[0] = sender;
                argv[dest_argc++] = dest;
                while (dest_refspec_nr--)
@@ -341,7 +104,7 @@ static int do_push(const char *repo)
                if (!err)
                        continue;
 
-               error("failed to push to '%s'", uri[i]);
+               error("failed to push to '%s'", remote->uri[i]);
                switch (err) {
                case -ERR_RUN_COMMAND_FORK:
                        error("unable to fork for %s", sender);
@@ -362,7 +125,7 @@ static int do_push(const char *repo)
 int cmd_push(int argc, const char **argv, const char *prefix)
 {
        int i;
-       const char *repo = "origin";    /* default repository */
+       const char *repo = NULL;        /* default repository */
 
        for (i = 1; i < argc; i++) {
                const char *arg = argv[i];
@@ -385,7 +148,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
                        continue;
                }
                if (!strcmp(arg, "--tags")) {
-                       tags = 1;
+                       add_refspec("refs/tags/*");
                        continue;
                }
                if (!strcmp(arg, "--force") || !strcmp(arg, "-f")) {
@@ -411,5 +174,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)
                usage(push_usage);
        }
        set_refspecs(argv + i, argc - i);
+       if (all && refspec)
+               usage(push_usage);
+
        return do_push(repo);
 }
index 316fb0f8dae022b35a89b71c94a22331a77a500a..41f81102380bf0ec86e223d393d0ab61b3f854ed 100644 (file)
@@ -84,7 +84,7 @@ static void prime_cache_tree(void)
 
 }
 
-static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--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;
 
index 4c39f1da98e5e690f28f5145a1ab5dba790da68d..ce093cad78ce8008cd8a60d3ab6be5663a712a9d 100644 (file)
@@ -249,7 +249,7 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
        /* we take the lock for the ref itself to prevent it from
         * getting updated.
         */
-       lock = lock_any_ref_for_update(ref, sha1);
+       lock = lock_any_ref_for_update(ref, sha1, 0);
        if (!lock)
                return error("cannot lock ref '%s'", ref);
        log_file = xstrdup(git_path("logs/%s", ref));
index 8c2c8bdc18a69e4dff7386548e5f7ea78a133f7b..c25b3d5586ff08061295350b5ceae01246931037 100644 (file)
@@ -12,6 +12,9 @@ static const char git_rerere_usage[] =
 static int cutoff_noresolve = 15;
 static int cutoff_resolve = 60;
 
+/* if rerere_enabled == -1, fall back to detection of .git/rr-cache */
+static int rerere_enabled = -1;
+
 static char *merge_rr_path;
 
 static const char *rr_path(const char *name, const char *file)
@@ -57,7 +60,8 @@ static int write_rr(struct path_list *rr, int out_fd)
                    write_in_full(out_fd, path, length) != length)
                        die("unable to write rerere record");
        }
-       close(out_fd);
+       if (close(out_fd) != 0)
+               die("unable to write rerere record");
        return commit_lock_file(&write_lock);
 }
 
@@ -281,8 +285,8 @@ static int diff_two(const char *file1, const char *label1,
        printf("--- a/%s\n+++ b/%s\n", label1, label2);
        fflush(stdout);
        xpp.flags = XDF_NEED_MINIMAL;
+       memset(&xecfg, 0, sizeof(xecfg));
        xecfg.ctxlen = 3;
-       xecfg.flags = 0;
        ecb.outf = outf;
        xdl_diff(&minus, &plus, &xpp, &xecfg, &ecb);
 
@@ -386,21 +390,41 @@ static int git_rerere_config(const char *var, const char *value)
                cutoff_resolve = git_config_int(var, value);
        else if (!strcmp(var, "gc.rerereunresolved"))
                cutoff_noresolve = git_config_int(var, value);
+       else if (!strcmp(var, "rerere.enabled"))
+               rerere_enabled = git_config_bool(var, value);
        else
                return git_default_config(var, value);
        return 0;
 }
 
-int cmd_rerere(int argc, const char **argv, const char *prefix)
+static int is_rerere_enabled(void)
 {
-       struct path_list merge_rr = { NULL, 0, 0, 1 };
-       int i, fd = -1;
        struct stat st;
+       const char *rr_cache;
+       int rr_cache_exists;
 
-       if (stat(git_path("rr-cache"), &st) || !S_ISDIR(st.st_mode))
+       if (!rerere_enabled)
                return 0;
 
+       rr_cache = git_path("rr-cache");
+       rr_cache_exists = !stat(rr_cache, &st) && S_ISDIR(st.st_mode);
+       if (rerere_enabled < 0)
+               return rr_cache_exists;
+
+       if (!rr_cache_exists &&
+           (mkdir(rr_cache, 0777) || adjust_shared_perm(rr_cache)))
+               die("Could not create directory %s", rr_cache);
+       return 1;
+}
+
+int cmd_rerere(int argc, const char **argv, const char *prefix)
+{
+       struct path_list merge_rr = { NULL, 0, 0, 1 };
+       int i, fd = -1;
+
        git_config(git_rerere_config);
+       if (!is_rerere_enabled())
+               return 0;
 
        merge_rr_path = xstrdup(git_path("rr-cache/MERGE_RR"));
        fd = hold_lock_file_for_update(&write_lock, merge_rr_path, 1);
@@ -410,6 +434,7 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
                return do_plain_rerere(&merge_rr, fd);
        else if (!strcmp(argv[1], "clear")) {
                for (i = 0; i < merge_rr.nr; i++) {
+                       struct stat st;
                        const char *name = (const char *)merge_rr.items[i].util;
                        if (!stat(git_path("rr-cache/%s", name), &st) &&
                                        S_ISDIR(st.st_mode) &&
@@ -434,4 +459,3 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
        path_list_clear(&merge_rr, 1);
        return 0;
 }
-
index ebf53f5944f1a53c5336f69e2ef3105ce50d0823..86db8b03fe4295497cf011a75617d6dc8f172c64 100644 (file)
@@ -92,13 +92,15 @@ static void show_commit(struct commit *commit)
                putchar('\n');
 
        if (revs.verbose_header) {
-               static char pretty_header[16384];
+               char *buf = NULL;
+               unsigned long buflen = 0;
                pretty_print_commit(revs.commit_format, commit, ~0,
-                                   pretty_header, sizeof(pretty_header),
+                                   &buf, &buflen,
                                    revs.abbrev, NULL, NULL, revs.date_mode);
-               printf("%s%c", pretty_header, hdr_termination);
+               printf("%s%c", buf, hdr_termination);
+               free(buf);
        }
-       fflush(stdout);
+       maybe_flush_or_die(stdout, "stdout");
        if (commit->parents) {
                free_commit_list(commit->parents);
                commit->parents = NULL;
index 37addb25fafbedba9bad6e99746ee65bacdee7d3..497903a85a69288afc291ff49e32f7c80140beae 100644 (file)
@@ -352,6 +352,16 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
                                                : "false");
                                continue;
                        }
+                       if (!strcmp(arg, "--is-inside-work-tree")) {
+                               printf("%s\n", is_inside_work_tree() ? "true"
+                                               : "false");
+                               continue;
+                       }
+                       if (!strcmp(arg, "--is-bare-repository")) {
+                               printf("%s\n", is_bare_repository() ? "true"
+                                               : "false");
+                               continue;
+                       }
                        if (!prefixcmp(arg, "--since=")) {
                                show_datestring("--max-age=", arg+8);
                                continue;
index ea2f15b977a8b62189755ae89e3ee704b45afae8..499bbe7343a635f1c7fc024ed6a1436042dcb8ac 100644 (file)
@@ -25,7 +25,7 @@ static const char *cherry_pick_usage = "git-cherry-pick [--edit] [-n] [-r] [-x]
 
 static int edit;
 static int replay;
-enum { REVERT, CHERRY_PICK } action;
+static enum { REVERT, CHERRY_PICK } action;
 static int no_commit;
 static struct commit *commit;
 static int needed_deref;
@@ -45,8 +45,10 @@ static void parse_options(int argc, const char **argv)
        if (argc < 2)
                usage(usage_str);
 
-       for (i = 1; i < argc - 1; i++) {
+       for (i = 1; i < argc; i++) {
                arg = argv[i];
+               if (arg[0] != '-')
+                       break;
                if (!strcmp(arg, "-n") || !strcmp(arg, "--no-commit"))
                        no_commit = 1;
                else if (!strcmp(arg, "-e") || !strcmp(arg, "--edit"))
@@ -59,7 +61,8 @@ static void parse_options(int argc, const char **argv)
                else if (strcmp(arg, "-r"))
                        usage(usage_str);
        }
-
+       if (i != argc - 1)
+               usage(usage_str);
        arg = argv[argc - 1];
        if (get_sha1(arg, sha1))
                die ("Cannot find '%s'", arg);
@@ -104,7 +107,7 @@ static char *get_oneline(const char *message)
        return result;
 }
 
-char *get_encoding(const char *message)
+static char *get_encoding(const char *message)
 {
        const char *p = message, *eol;
 
@@ -126,7 +129,7 @@ char *get_encoding(const char *message)
        return NULL;
 }
 
-struct lock_file msg_file;
+static struct lock_file msg_file;
 static int msg_fd;
 
 static void add_to_msg(const char *string)
index 8d3f742d432c966e5afe03e8d0628eb92a73920c..16af6199ab2bc8a663d16f78a5d461a5bee05bc7 100644 (file)
@@ -331,4 +331,3 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
 
        return 0;
 }
-
index c892f1f7a643b3d7e5c298837424a72cbc2c4f78..4fa87f6081f74fa667a415038ca64c5f4a7cf775 100644 (file)
@@ -259,17 +259,19 @@ static void join_revs(struct commit_list **list_p,
 
 static void show_one_commit(struct commit *commit, int no_name)
 {
-       char pretty[256], *cp;
+       char *pretty = NULL;
+       const char *pretty_str = "(unavailable)";
+       unsigned long pretty_len = 0;
        struct commit_name *name = commit->util;
-       if (commit->object.parsed)
+
+       if (commit->object.parsed) {
                pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
-                                   pretty, sizeof(pretty), 0, NULL, NULL, 0);
-       else
-               strcpy(pretty, "(unavailable)");
-       if (!prefixcmp(pretty, "[PATCH] "))
-               cp = pretty + 8;
-       else
-               cp = pretty;
+                                   &pretty, &pretty_len,
+                                   0, NULL, NULL, 0);
+               pretty_str = pretty;
+       }
+       if (!prefixcmp(pretty_str, "[PATCH] "))
+               pretty_str += 8;
 
        if (!no_name) {
                if (name && name->head_name) {
@@ -286,7 +288,8 @@ static void show_one_commit(struct commit *commit, int no_name)
                        printf("[%s] ",
                               find_unique_abbrev(commit->object.sha1, 7));
        }
-       puts(cp);
+       puts(pretty_str);
+       free(pretty);
 }
 
 static char *ref_name[MAX_REVS + 1];
index f0d4d9e2d10446a229094c991363f5a17ce4c666..d8358e28f01e2ed74a847767f52d90d84feb25ee 100644 (file)
@@ -1,58 +1,79 @@
 #include "builtin.h"
+#include "cache.h"
 
 /*
- * Remove empty lines from the beginning and end.
+ * Remove trailing spaces from a line.
  *
- * Turn multiple consecutive empty lines into just one
- * empty line.  Return true if it is an incomplete line.
+ * If the line ends with newline, it will be removed too.
+ * Returns the new length of the string.
  */
-static int cleanup(char *line)
+static int cleanup(char *line, int len)
 {
-       int len = strlen(line);
+       if (len) {
+               if (line[len - 1] == '\n')
+                       len--;
 
-       if (len && line[len-1] == '\n') {
-               if (len == 1)
-                       return 0;
-               do {
-                       unsigned char c = line[len-2];
+               while (len) {
+                       unsigned char c = line[len - 1];
                        if (!isspace(c))
                                break;
-                       line[len-2] = '\n';
                        len--;
-                       line[len] = 0;
-               } while (len > 1);
-               return 0;
+               }
+               line[len] = 0;
        }
-       return 1;
+       return len;
 }
 
-void stripspace(FILE *in, FILE *out)
+/*
+ * Remove empty lines from the beginning and end
+ * and also trailing spaces from every line.
+ *
+ * Turn multiple consecutive empty lines between paragraphs
+ * into just one empty line.
+ *
+ * If the input has only empty lines and spaces,
+ * no output will be produced.
+ *
+ * Enable skip_comments to skip every line starting with "#".
+ */
+void stripspace(FILE *in, FILE *out, int skip_comments)
 {
        int empties = -1;
-       int incomplete = 0;
-       char line[1024];
+       int alloc = 1024;
+       char *line = xmalloc(alloc);
+
+       while (fgets(line, alloc, in)) {
+               int len = strlen(line);
 
-       while (fgets(line, sizeof(line), in)) {
-               incomplete = cleanup(line);
+               while (len == alloc - 1 && line[len - 1] != '\n') {
+                       alloc = alloc_nr(alloc);
+                       line = xrealloc(line, alloc);
+                       fgets(line + len, alloc - len, in);
+                       len += strlen(line + len);
+               }
+
+               if (skip_comments && line[0] == '#')
+                       continue;
+               len = cleanup(line, len);
 
                /* Not just an empty line? */
-               if (line[0] != '\n') {
+               if (len) {
                        if (empties > 0)
                                fputc('\n', out);
                        empties = 0;
                        fputs(line, out);
+                       fputc('\n', out);
                        continue;
                }
                if (empties < 0)
                        continue;
                empties++;
        }
-       if (incomplete)
-               fputc('\n', out);
+       free(line);
 }
 
 int cmd_stripspace(int argc, const char **argv, const char *prefix)
 {
-       stripspace(stdin, stdout);
+       stripspace(stdin, stdout, 0);
        return 0;
 }
index 8f9899178b1755ee0acd4a34ee185a4f54fb4219..509369e9e7b1719e53ba2dd2d976066fb9513353 100644 (file)
@@ -134,7 +134,7 @@ static int process_directory(const char *path, int len, struct stat *st)
        /* Exact match: file or existing gitlink */
        if (pos >= 0) {
                struct cache_entry *ce = active_cache[pos];
-               if (S_ISDIRLNK(ntohl(ce->ce_mode))) {
+               if (S_ISGITLINK(ntohl(ce->ce_mode))) {
 
                        /* Do nothing to the index if there is no HEAD! */
                        if (resolve_gitlink_ref(path, "HEAD", sha1) < 0)
@@ -178,7 +178,7 @@ static int process_file(const char *path, int len, struct stat *st)
        int pos = cache_name_pos(path, len);
        struct cache_entry *ce = pos < 0 ? NULL : active_cache[pos];
 
-       if (ce && S_ISDIRLNK(ntohl(ce->ce_mode)))
+       if (ce && S_ISGITLINK(ntohl(ce->ce_mode)))
                return error("%s is already a gitlink, not replacing", path);
 
        return add_one_path(ce, path, len, st);
index 5ee960bf41c4518b6c5530acb123a7ed668538fc..feac2ed12d22dcd23db5823cd32a0f9f1c1c974a 100644 (file)
@@ -3,16 +3,17 @@
 #include "builtin.h"
 
 static const char git_update_ref_usage[] =
-"git-update-ref [-m <reason>] (-d <refname> <value> | <refname> <value> [<oldval>])";
+"git-update-ref [-m <reason>] (-d <refname> <value> | [--no-deref] <refname> <value> [<oldval>])";
 
 int cmd_update_ref(int argc, const char **argv, const char *prefix)
 {
        const char *refname=NULL, *value=NULL, *oldval=NULL, *msg=NULL;
        struct ref_lock *lock;
        unsigned char sha1[20], oldsha1[20];
-       int i, delete;
+       int i, delete, ref_flags;
 
        delete = 0;
+       ref_flags = 0;
        git_config(git_default_config);
 
        for (i = 1; i < argc; i++) {
@@ -30,6 +31,10 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
                        delete = 1;
                        continue;
                }
+               if (!strcmp("--no-deref", argv[i])) {
+                       ref_flags |= REF_NODEREF;
+                       continue;
+               }
                if (!refname) {
                        refname = argv[i];
                        continue;
@@ -59,7 +64,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
        if (oldval && *oldval && get_sha1(oldval, oldsha1))
                die("%s: not a valid old SHA1", oldval);
 
-       lock = lock_any_ref_for_update(refname, oldval ? oldsha1 : NULL);
+       lock = lock_any_ref_for_update(refname, oldval ? oldsha1 : NULL, ref_flags);
        if (!lock)
                die("%s: cannot lock the ref", refname);
        if (write_ref_sha1(lock, sha1, msg) < 0)
index d3f3a7496e1c1adbe3f8bae36603fafee374c8c5..661a92f787d590375ebbed6f71b9574388815349 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -7,9 +7,7 @@ extern const char git_version_string[];
 extern const char git_usage_string[];
 
 extern void help_unknown_cmd(const char *cmd);
-extern int mailinfo(FILE *in, FILE *out, int ks, const char *encoding, const char *msg, const char *patch);
-extern int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip);
-extern void stripspace(FILE *in, FILE *out);
+extern void stripspace(FILE *in, FILE *out, int skip_comments);
 extern int write_tree(unsigned char *sha1, int missing_ok, const char *prefix);
 extern void prune_packed_objects(int);
 
index 6369cc7c536ba7b82a6afcb191628beefe889b72..077f03436941e9c0bf31d3bb2002c1e36b8817b9 100644 (file)
@@ -326,7 +326,7 @@ static int update_one(struct cache_tree *it,
                        mode = ntohl(ce->ce_mode);
                        entlen = pathlen - baselen;
                }
-               if (mode != S_IFDIRLNK && !missing_ok && !has_sha1_file(sha1))
+               if (mode != S_IFGITLINK && !missing_ok && !has_sha1_file(sha1))
                        return error("invalid object %s", sha1_to_hex(sha1));
 
                if (!ce->ce_mode)
@@ -478,7 +478,7 @@ static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)
        if (0 <= it->entry_count) {
                if (size < 20)
                        goto free_return;
-               hashcpy(it->sha1, (unsigned char*)buf);
+               hashcpy(it->sha1, (const unsigned char*)buf);
                buf += 20;
                size -= 20;
        }
diff --git a/cache.h b/cache.h
index 5dff2f1d73eb1a41f664d959d18e6f2c0e102e64..e64071e2e352fee7d42d1896728e5d64626f3c49 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -40,8 +40,8 @@
  * happens that everybody shares the same bit representation
  * in the UNIX world (and apparently wider too..)
  */
-#define S_IFDIRLNK     0160000
-#define S_ISDIRLNK(m)  (((m) & S_IFMT) == S_IFDIRLNK)
+#define S_IFGITLINK    0160000
+#define S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK)
 
 /*
  * Intensive research over the course of many years has shown that
@@ -123,8 +123,8 @@ static inline unsigned int create_ce_mode(unsigned int mode)
 {
        if (S_ISLNK(mode))
                return htonl(S_IFLNK);
-       if (S_ISDIR(mode) || S_ISDIRLNK(mode))
-               return htonl(S_IFDIRLNK);
+       if (S_ISDIR(mode) || S_ISGITLINK(mode))
+               return htonl(S_IFGITLINK);
        return htonl(S_IFREG | ce_permissions(mode));
 }
 static inline unsigned int ce_mode_from_stat(struct cache_entry *ce, unsigned int mode)
@@ -142,7 +142,7 @@ static inline unsigned int ce_mode_from_stat(struct cache_entry *ce, unsigned in
 }
 #define canon_mode(mode) \
        (S_ISREG(mode) ? (S_IFREG | ce_permissions(mode)) : \
-       S_ISLNK(mode) ? S_IFLNK : S_ISDIR(mode) ? S_IFDIR : S_IFDIRLNK)
+       S_ISLNK(mode) ? S_IFLNK : S_ISDIR(mode) ? S_IFDIR : S_IFGITLINK)
 
 #define cache_entry_size(len) ((offsetof(struct cache_entry,name) + (len) + 8) & ~7)
 
@@ -192,6 +192,7 @@ enum object_type {
 };
 
 #define GIT_DIR_ENVIRONMENT "GIT_DIR"
+#define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
 #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
 #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
 #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
@@ -207,6 +208,7 @@ enum object_type {
 extern int is_bare_repository_cfg;
 extern int is_bare_repository(void);
 extern int is_inside_git_dir(void);
+extern int is_inside_work_tree(void);
 extern const char *get_git_dir(void);
 extern char *get_object_directory(void);
 extern char *get_refs_directory(void);
@@ -225,6 +227,24 @@ extern void verify_non_filename(const char *prefix, const char *name);
 
 #define alloc_nr(x) (((x)+16)*3/2)
 
+/*
+ * Realloc the buffer pointed at by variable 'x' so that it can hold
+ * at least 'nr' entries; the number of entries currently allocated
+ * is 'alloc', using the standard growing factor alloc_nr() macro.
+ *
+ * DO NOT USE any expression with side-effect for 'x' or 'alloc'.
+ */
+#define ALLOC_GROW(x, nr, alloc) \
+       do { \
+               if ((nr) > alloc) { \
+                       if (alloc_nr(alloc) < (nr)) \
+                               alloc = (nr); \
+                       else \
+                               alloc = alloc_nr(alloc); \
+                       x = xrealloc((x), alloc * sizeof(*(x))); \
+               } \
+       } while(0)
+
 /* Initialize and use the cache information */
 extern int read_index(struct index_state *);
 extern int read_index_from(struct index_state *, const char *path);
@@ -273,8 +293,8 @@ extern void rollback_lock_file(struct lock_file *);
 extern int delete_ref(const char *, const unsigned char *sha1);
 
 /* Environment bits from configuration mechanism */
-extern int use_legacy_headers;
 extern int trust_executable_bit;
+extern int quote_path_fully;
 extern int has_symlinks;
 extern int assume_unchanged;
 extern int prefer_symlink_refs;
@@ -283,6 +303,8 @@ extern int warn_ambiguous_refs;
 extern int shared_repository;
 extern const char *apply_default_whitespace;
 extern int zlib_compression_level;
+extern int core_compression_level;
+extern int core_compression_seen;
 extern size_t packed_git_window_size;
 extern size_t packed_git_limit;
 extern size_t delta_base_cache_limit;
@@ -353,8 +375,6 @@ extern int move_temp_to_file(const char *tmpfile, const char *filename);
 
 extern int has_sha1_pack(const unsigned char *sha1, const char **ignore);
 extern int has_sha1_file(const unsigned char *sha1);
-extern void *map_sha1_file(const unsigned char *sha1, unsigned long *);
-extern int legacy_loose_object(unsigned char *);
 
 extern int has_pack_file(const unsigned char *sha1);
 extern int has_pack_index(const unsigned char *sha1);
@@ -463,11 +483,10 @@ struct ref {
 #define REF_HEADS      (1u << 1)
 #define REF_TAGS       (1u << 2)
 
-extern pid_t git_connect(int fd[2], char *url, const char *prog);
+#define CONNECT_VERBOSE       (1u << 0)
+extern pid_t git_connect(int fd[2], char *url, const char *prog, int flags);
 extern int finish_connect(pid_t pid);
 extern int path_match(const char *path, int nr, char **match);
-extern int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
-                     int nr_refspec, char **refspec, int all);
 extern int get_ack(int fd, unsigned char *result_sha1);
 extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags);
 extern int server_supports(const char *feature);
@@ -480,14 +499,15 @@ extern void prepare_packed_git(void);
 extern void reprepare_packed_git(void);
 extern void install_packed_git(struct packed_git *pack);
 
-extern struct packed_git *find_sha1_pack(const unsigned char *sha1, 
+extern struct packed_git *find_sha1_pack(const unsigned char *sha1,
                                         struct packed_git *packs);
 
 extern void pack_report(void);
+extern int open_pack_index(struct packed_git *);
 extern unsigned char* use_pack(struct packed_git *, struct pack_window **, off_t, unsigned int *);
 extern void unuse_pack(struct pack_window **);
 extern struct packed_git *add_packed_git(const char *, int, int);
-extern const unsigned char *nth_packed_object_sha1(const struct packed_git *, uint32_t);
+extern const unsigned char *nth_packed_object_sha1(struct packed_git *, uint32_t);
 extern off_t find_pack_entry_one(const unsigned char *, struct packed_git *);
 extern void *unpack_entry(struct packed_git *, off_t, enum object_type *, unsigned long *);
 extern unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
@@ -515,6 +535,8 @@ extern char git_default_name[MAX_GITNAME];
 extern const char *git_commit_encoding;
 extern const char *git_log_output_encoding;
 
+/* IO helper functions */
+extern void maybe_flush_or_die(FILE *, const char *);
 extern int copy_fd(int ifd, int ofd);
 extern int read_in_full(int fd, void *buf, size_t count);
 extern int write_in_full(int fd, const void *buf, size_t count);
@@ -524,6 +546,7 @@ extern int write_or_whine_pipe(int fd, const void *buf, size_t count, const char
 
 /* pager.c */
 extern void setup_pager(void);
+extern char *pager_program;
 extern int pager_in_use;
 extern int pager_use_color;
 
index ea3ca5f950561a92fdd3be1a4ee4bbd726656118..ef622340a52afb3b31b1cdf678ae0a83fb85c923 100644 (file)
@@ -215,8 +215,7 @@ static void combine_diff(const unsigned char *parent, mmfile_t *result_file,
        parent_file.ptr = grab_blob(parent, &sz);
        parent_file.size = sz;
        xpp.flags = XDF_NEED_MINIMAL;
-       xecfg.ctxlen = 0;
-       xecfg.flags = 0;
+       memset(&xecfg, 0, sizeof(xecfg));
        ecb.outf = xdiff_outf;
        ecb.priv = &state;
        memset(&state, 0, sizeof(state));
index 5632e32685478dcce34e479e8e916b0ccd3a3b13..03436b1b077f3f83cebceb697f97c3ba5b26265c 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -27,7 +27,7 @@ struct sort_node
 
 const char *commit_type = "commit";
 
-struct cmt_fmt_map {
+static struct cmt_fmt_map {
        const char *n;
        size_t cmp_len;
        enum cmit_fmt v;
@@ -148,7 +148,7 @@ static int commit_graft_pos(const unsigned char *sha1)
 int register_commit_graft(struct commit_graft *graft, int ignore_dups)
 {
        int pos = commit_graft_pos(graft->sha1);
-       
+
        if (0 <= pos) {
                if (ignore_dups)
                        free(graft);
@@ -406,7 +406,7 @@ struct commit_list * insert_by_date(struct commit *item, struct commit_list **li
        return commit_list_insert(item, pp);
 }
 
-       
+
 void sort_by_date(struct commit_list **list)
 {
        struct commit_list *ret = NULL;
@@ -529,6 +529,14 @@ static int add_rfc2047(char *buf, const char *line, int len,
        return bp - buf;
 }
 
+static unsigned long bound_rfc2047(unsigned long len, const char *encoding)
+{
+       /* upper bound of q encoded string of length 'len' */
+       unsigned long elen = strlen(encoding);
+
+       return len * 3 + elen + 100;
+}
+
 static int add_user_info(const char *what, enum cmit_fmt fmt, char *buf,
                         const char *line, enum date_mode dmode,
                         const char *encoding)
@@ -776,7 +784,7 @@ static void fill_person(struct interp *table, const char *msg, int len)
 }
 
 static long format_commit_message(const struct commit *commit,
-               const char *msg, char *buf, unsigned long space)
+               const char *msg, char **buf_p, unsigned long *space_p)
 {
        struct interp table[] = {
                { "%H" },       /* commit hash */
@@ -905,31 +913,252 @@ static long format_commit_message(const struct commit *commit,
                if (!table[i].value)
                        interp_set_entry(table, i, "<unknown>");
 
-       interpolate(buf, space, user_format, table, ARRAY_SIZE(table));
+       do {
+               char *buf = *buf_p;
+               unsigned long space = *space_p;
+
+               space = interpolate(buf, space, user_format,
+                                   table, ARRAY_SIZE(table));
+               if (!space)
+                       break;
+               buf = xrealloc(buf, space);
+               *buf_p = buf;
+               *space_p = space;
+       } while (1);
        interp_clear_table(table, ARRAY_SIZE(table));
 
-       return strlen(buf);
+       return strlen(*buf_p);
+}
+
+static void pp_header(enum cmit_fmt fmt,
+                     int abbrev,
+                     enum date_mode dmode,
+                     const char *encoding,
+                     const struct commit *commit,
+                     const char **msg_p,
+                     unsigned long *len_p,
+                     unsigned long *ofs_p,
+                     char **buf_p,
+                     unsigned long *space_p)
+{
+       int parents_shown = 0;
+
+       for (;;) {
+               const char *line = *msg_p;
+               char *dst;
+               int linelen = get_one_line(*msg_p, *len_p);
+               unsigned long len;
+
+               if (!linelen)
+                       return;
+               *msg_p += linelen;
+               *len_p -= linelen;
+
+               if (linelen == 1)
+                       /* End of header */
+                       return;
+
+               ALLOC_GROW(*buf_p, linelen + *ofs_p + 20, *space_p);
+               dst = *buf_p + *ofs_p;
+
+               if (fmt == CMIT_FMT_RAW) {
+                       memcpy(dst, line, linelen);
+                       *ofs_p += linelen;
+                       continue;
+               }
+
+               if (!memcmp(line, "parent ", 7)) {
+                       if (linelen != 48)
+                               die("bad parent line in commit");
+                       continue;
+               }
+
+               if (!parents_shown) {
+                       struct commit_list *parent;
+                       int num;
+                       for (parent = commit->parents, num = 0;
+                            parent;
+                            parent = parent->next, num++)
+                               ;
+                       /* with enough slop */
+                       num = *ofs_p + num * 50 + 20;
+                       ALLOC_GROW(*buf_p, num, *space_p);
+                       dst = *buf_p + *ofs_p;
+                       *ofs_p += add_merge_info(fmt, dst, commit, abbrev);
+                       parents_shown = 1;
+               }
+
+               /*
+                * MEDIUM == DEFAULT shows only author with dates.
+                * FULL shows both authors but not dates.
+                * FULLER shows both authors and dates.
+                */
+               if (!memcmp(line, "author ", 7)) {
+                       len = linelen;
+                       if (fmt == CMIT_FMT_EMAIL)
+                               len = bound_rfc2047(linelen, encoding);
+                       ALLOC_GROW(*buf_p, *ofs_p + len + 80, *space_p);
+                       dst = *buf_p + *ofs_p;
+                       *ofs_p += add_user_info("Author", fmt, dst,
+                                               line + 7, dmode, encoding);
+               }
+
+               if (!memcmp(line, "committer ", 10) &&
+                   (fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER)) {
+                       len = linelen;
+                       if (fmt == CMIT_FMT_EMAIL)
+                               len = bound_rfc2047(linelen, encoding);
+                       ALLOC_GROW(*buf_p, *ofs_p + len + 80, *space_p);
+                       dst = *buf_p + *ofs_p;
+                       *ofs_p += add_user_info("Commit", fmt, dst,
+                                               line + 10, dmode, encoding);
+               }
+       }
+}
+
+static void pp_title_line(enum cmit_fmt fmt,
+                         const char **msg_p,
+                         unsigned long *len_p,
+                         unsigned long *ofs_p,
+                         char **buf_p,
+                         unsigned long *space_p,
+                         int indent,
+                         const char *subject,
+                         const char *after_subject,
+                         const char *encoding,
+                         int plain_non_ascii)
+{
+       char *title;
+       unsigned long title_alloc, title_len;
+       unsigned long len;
+
+       title_len = 0;
+       title_alloc = 80;
+       title = xmalloc(title_alloc);
+       for (;;) {
+               const char *line = *msg_p;
+               int linelen = get_one_line(line, *len_p);
+               *msg_p += linelen;
+               *len_p -= linelen;
+
+               if (!linelen || is_empty_line(line, &linelen))
+                       break;
+
+               if (title_alloc <= title_len + linelen + 2) {
+                       title_alloc = title_len + linelen + 80;
+                       title = xrealloc(title, title_alloc);
+               }
+               len = 0;
+               if (title_len) {
+                       if (fmt == CMIT_FMT_EMAIL) {
+                               len++;
+                               title[title_len++] = '\n';
+                       }
+                       len++;
+                       title[title_len++] = ' ';
+               }
+               memcpy(title + title_len, line, linelen);
+               title_len += linelen;
+       }
+
+       /* Enough slop for the MIME header and rfc2047 */
+       len = bound_rfc2047(title_len, encoding)+ 1000;
+       if (subject)
+               len += strlen(subject);
+       if (after_subject)
+               len += strlen(after_subject);
+       if (encoding)
+               len += strlen(encoding);
+       ALLOC_GROW(*buf_p, title_len + *ofs_p + len, *space_p);
+
+       if (subject) {
+               len = strlen(subject);
+               memcpy(*buf_p + *ofs_p, subject, len);
+               *ofs_p += len;
+               *ofs_p += add_rfc2047(*buf_p + *ofs_p,
+                                     title, title_len, encoding);
+       } else {
+               memcpy(*buf_p + *ofs_p, title, title_len);
+               *ofs_p += title_len;
+       }
+       (*buf_p)[(*ofs_p)++] = '\n';
+       if (plain_non_ascii) {
+               const char *header_fmt =
+                       "MIME-Version: 1.0\n"
+                       "Content-Type: text/plain; charset=%s\n"
+                       "Content-Transfer-Encoding: 8bit\n";
+               *ofs_p += snprintf(*buf_p + *ofs_p,
+                                  *space_p - *ofs_p,
+                                  header_fmt, encoding);
+       }
+       if (after_subject) {
+               len = strlen(after_subject);
+               memcpy(*buf_p + *ofs_p, after_subject, len);
+               *ofs_p += len;
+       }
+       free(title);
+       if (fmt == CMIT_FMT_EMAIL) {
+               ALLOC_GROW(*buf_p, *ofs_p + 20, *space_p);
+               (*buf_p)[(*ofs_p)++] = '\n';
+       }
+}
+
+static void pp_remainder(enum cmit_fmt fmt,
+                        const char **msg_p,
+                        unsigned long *len_p,
+                        unsigned long *ofs_p,
+                        char **buf_p,
+                        unsigned long *space_p,
+                        int indent)
+{
+       int first = 1;
+       for (;;) {
+               const char *line = *msg_p;
+               int linelen = get_one_line(line, *len_p);
+               *msg_p += linelen;
+               *len_p -= linelen;
+
+               if (!linelen)
+                       break;
+
+               if (is_empty_line(line, &linelen)) {
+                       if (first)
+                               continue;
+                       if (fmt == CMIT_FMT_SHORT)
+                               break;
+               }
+               first = 0;
+
+               ALLOC_GROW(*buf_p, *ofs_p + linelen + indent + 20, *space_p);
+               if (indent) {
+                       memset(*buf_p + *ofs_p, ' ', indent);
+                       *ofs_p += indent;
+               }
+               memcpy(*buf_p + *ofs_p, line, linelen);
+               *ofs_p += linelen;
+               (*buf_p)[(*ofs_p)++] = '\n';
+       }
 }
 
 unsigned long pretty_print_commit(enum cmit_fmt fmt,
                                  const struct commit *commit,
                                  unsigned long len,
-                                 char *buf, unsigned long space,
+                                 char **buf_p, unsigned long *space_p,
                                  int abbrev, const char *subject,
                                  const char *after_subject,
                                  enum date_mode dmode)
 {
-       int hdr = 1, body = 0, seen_title = 0;
        unsigned long offset = 0;
+       unsigned long beginning_of_body;
        int indent = 4;
-       int parents_shown = 0;
        const char *msg = commit->buffer;
        int plain_non_ascii = 0;
        char *reencoded;
        const char *encoding;
+       char *buf;
 
        if (fmt == CMIT_FMT_USERFORMAT)
-               return format_commit_message(commit, msg, buf, space);
+               return format_commit_message(commit, msg, buf_p, space_p);
 
        encoding = (git_log_output_encoding
                    ? git_log_output_encoding
@@ -937,8 +1166,10 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
        if (!encoding)
                encoding = "utf-8";
        reencoded = logmsg_reencode(commit, encoding);
-       if (reencoded)
+       if (reencoded) {
                msg = reencoded;
+               len = strlen(reencoded);
+       }
 
        if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
                indent = 0;
@@ -969,137 +1200,57 @@ unsigned long pretty_print_commit(enum cmit_fmt fmt,
                }
        }
 
+       pp_header(fmt, abbrev, dmode, encoding,
+                 commit, &msg, &len,
+                 &offset, buf_p, space_p);
+       if (fmt != CMIT_FMT_ONELINE && !subject) {
+               ALLOC_GROW(*buf_p, offset + 20, *space_p);
+               (*buf_p)[offset++] = '\n';
+       }
+
+       /* Skip excess blank lines at the beginning of body, if any... */
        for (;;) {
-               const char *line = msg;
                int linelen = get_one_line(msg, len);
-
+               int ll = linelen;
                if (!linelen)
                        break;
-
-               /*
-                * We want some slop for indentation and a possible
-                * final "...". Thus the "+ 20".
-                */
-               if (offset + linelen + 20 > space) {
-                       memcpy(buf + offset, "    ...\n", 8);
-                       offset += 8;
+               if (!is_empty_line(msg, &ll))
                        break;
-               }
-
                msg += linelen;
                len -= linelen;
-               if (hdr) {
-                       if (linelen == 1) {
-                               hdr = 0;
-                               if ((fmt != CMIT_FMT_ONELINE) && !subject)
-                                       buf[offset++] = '\n';
-                               continue;
-                       }
-                       if (fmt == CMIT_FMT_RAW) {
-                               memcpy(buf + offset, line, linelen);
-                               offset += linelen;
-                               continue;
-                       }
-                       if (!memcmp(line, "parent ", 7)) {
-                               if (linelen != 48)
-                                       die("bad parent line in commit");
-                               continue;
-                       }
-
-                       if (!parents_shown) {
-                               offset += add_merge_info(fmt, buf + offset,
-                                                        commit, abbrev);
-                               parents_shown = 1;
-                               continue;
-                       }
-                       /*
-                        * MEDIUM == DEFAULT shows only author with dates.
-                        * FULL shows both authors but not dates.
-                        * FULLER shows both authors and dates.
-                        */
-                       if (!memcmp(line, "author ", 7))
-                               offset += add_user_info("Author", fmt,
-                                                       buf + offset,
-                                                       line + 7,
-                                                       dmode,
-                                                       encoding);
-                       if (!memcmp(line, "committer ", 10) &&
-                           (fmt == CMIT_FMT_FULL || fmt == CMIT_FMT_FULLER))
-                               offset += add_user_info("Commit", fmt,
-                                                       buf + offset,
-                                                       line + 10,
-                                                       dmode,
-                                                       encoding);
-                       continue;
-               }
+       }
 
-               if (!subject)
-                       body = 1;
+       /* These formats treat the title line specially. */
+       if (fmt == CMIT_FMT_ONELINE
+           || fmt == CMIT_FMT_EMAIL)
+               pp_title_line(fmt, &msg, &len, &offset,
+                             buf_p, space_p, indent,
+                             subject, after_subject, encoding,
+                             plain_non_ascii);
 
-               if (is_empty_line(line, &linelen)) {
-                       if (!seen_title)
-                               continue;
-                       if (!body)
-                               continue;
-                       if (subject)
-                               continue;
-                       if (fmt == CMIT_FMT_SHORT)
-                               break;
-               }
+       beginning_of_body = offset;
+       if (fmt != CMIT_FMT_ONELINE)
+               pp_remainder(fmt, &msg, &len, &offset,
+                            buf_p, space_p, indent);
 
-               seen_title = 1;
-               if (subject) {
-                       int slen = strlen(subject);
-                       memcpy(buf + offset, subject, slen);
-                       offset += slen;
-                       offset += add_rfc2047(buf + offset, line, linelen,
-                                             encoding);
-               }
-               else {
-                       memset(buf + offset, ' ', indent);
-                       memcpy(buf + offset + indent, line, linelen);
-                       offset += linelen + indent;
-               }
-               buf[offset++] = '\n';
-               if (fmt == CMIT_FMT_ONELINE)
-                       break;
-               if (subject && plain_non_ascii) {
-                       int sz;
-                       char header[512];
-                       const char *header_fmt =
-                               "MIME-Version: 1.0\n"
-                               "Content-Type: text/plain; charset=%s\n"
-                               "Content-Transfer-Encoding: 8bit\n";
-                       sz = snprintf(header, sizeof(header), header_fmt,
-                                     encoding);
-                       if (sizeof(header) < sz)
-                               die("Encoding name %s too long", encoding);
-                       memcpy(buf + offset, header, sz);
-                       offset += sz;
-               }
-               if (after_subject) {
-                       int slen = strlen(after_subject);
-                       if (slen > space - offset - 1)
-                               slen = space - offset - 1;
-                       memcpy(buf + offset, after_subject, slen);
-                       offset += slen;
-                       after_subject = NULL;
-               }
-               subject = NULL;
-       }
-       while (offset && isspace(buf[offset-1]))
+       while (offset && isspace((*buf_p)[offset-1]))
                offset--;
+
+       ALLOC_GROW(*buf_p, offset + 20, *space_p);
+       buf = *buf_p;
+
        /* Make sure there is an EOLN for the non-oneline case */
        if (fmt != CMIT_FMT_ONELINE)
                buf[offset++] = '\n';
+
        /*
-        * make sure there is another EOLN to separate the headers from whatever
-        * body the caller appends if we haven't already written a body
+        * The caller may append additional body text in e-mail
+        * format.  Make sure we did not strip the blank line
+        * between the header and the body.
         */
-       if (fmt == CMIT_FMT_EMAIL && !body)
+       if (fmt == CMIT_FMT_EMAIL && offset <= beginning_of_body)
                buf[offset++] = '\n';
        buf[offset] = '\0';
-
        free(reencoded);
        return offset;
 }
@@ -1116,15 +1267,6 @@ struct commit *pop_commit(struct commit_list **stack)
        return item;
 }
 
-int count_parents(struct commit * commit)
-{
-        int count;
-        struct commit_list * parents = commit->parents;
-        for (count = 0; parents; parents = parents->next,count++)
-               ;
-        return count;
-}
-
 void topo_sort_default_setter(struct commit *c, void *data)
 {
        c->util = data;
@@ -1160,7 +1302,7 @@ void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
                next = next->next;
                count++;
        }
-       
+
        if (!count)
                return;
        /* allocate an array to help sort the list */
@@ -1188,11 +1330,11 @@ void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
                }
                next=next->next;
        }
-       /* 
+       /*
          * find the tips
          *
-         * tips are nodes not reachable from any other node in the list 
-         * 
+         * tips are nodes not reachable from any other node in the list
+         *
          * the tips serve as a starting set for the work queue.
          */
        next=*list;
@@ -1220,7 +1362,7 @@ void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
 
                        if (pn) {
                                /*
-                                * parents are only enqueued for emission 
+                                * parents are only enqueued for emission
                                  * when all their children have been emitted thereby
                                  * guaranteeing topological order.
                                  */
index 86e8dca0c9dbac4d990d959296145805319b477a..467872eecabf05ccedbb9bf8247b6de244416b8f 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -61,20 +61,18 @@ enum cmit_fmt {
 };
 
 extern enum cmit_fmt get_commit_format(const char *arg);
-extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *, unsigned long len, char *buf, unsigned long space, int abbrev, const char *subject, const char *after_subject, enum date_mode dmode);
+extern unsigned long pretty_print_commit(enum cmit_fmt fmt, const struct commit *, unsigned long len, char **buf_p, unsigned long *space_p, int abbrev, const char *subject, const char *after_subject, enum date_mode dmode);
 
 /** Removes the first commit from a list sorted by date, and adds all
  * of its parents.
  **/
-struct commit *pop_most_recent_commit(struct commit_list **list, 
+struct commit *pop_most_recent_commit(struct commit_list **list,
                                      unsigned int mark);
 
 struct commit *pop_commit(struct commit_list **stack);
 
 void clear_commit_marks(struct commit *commit, unsigned int mark);
 
-int count_parents(struct commit * commit);
-
 /*
  * Performs an in-place topological sort of list supplied.
  *
index 4cfaee31361d98d2c8f68d250609b09130335baa..c9d46d174259f42a3e2a2eb073475aba517044be 100644 (file)
@@ -40,4 +40,3 @@ int git_munmap(void *start, size_t length)
        free(start);
        return 0;
 }
-
index 7b655fdb78350bf9a8320075bef6cf4f1e87c50c..561ee3b576ae32f10959d3f1b76f6cc62e31d45a 100644 (file)
--- a/config.c
+++ b/config.c
@@ -12,6 +12,8 @@
 static FILE *config_file;
 static const char *config_file_name;
 static int config_linenr;
+static int zlib_compression_seen;
+
 static int get_next_char(void)
 {
        int c;
@@ -269,6 +271,11 @@ int git_default_config(const char *var, const char *value)
                return 0;
        }
 
+       if (!strcmp(var, "core.quotepath")) {
+               quote_path_fully = git_config_bool(var, value);
+               return 0;
+       }
+
        if (!strcmp(var, "core.symlinks")) {
                has_symlinks = git_config_bool(var, value);
                return 0;
@@ -299,8 +306,14 @@ int git_default_config(const char *var, const char *value)
                return 0;
        }
 
-       if (!strcmp(var, "core.legacyheaders")) {
-               use_legacy_headers = git_config_bool(var, value);
+       if (!strcmp(var, "core.loosecompression")) {
+               int level = git_config_int(var, value);
+               if (level == -1)
+                       level = Z_DEFAULT_COMPRESSION;
+               else if (level < 0 || level > Z_BEST_COMPRESSION)
+                       die("bad zlib compression level %d", level);
+               zlib_compression_level = level;
+               zlib_compression_seen = 1;
                return 0;
        }
 
@@ -310,7 +323,10 @@ int git_default_config(const char *var, const char *value)
                        level = Z_DEFAULT_COMPRESSION;
                else if (level < 0 || level > Z_BEST_COMPRESSION)
                        die("bad zlib compression level %d", level);
-               zlib_compression_level = level;
+               core_compression_level = level;
+               core_compression_seen = 1;
+               if (!zlib_compression_seen)
+                       zlib_compression_level = level;
                return 0;
        }
 
@@ -371,6 +387,11 @@ int git_default_config(const char *var, const char *value)
                return 0;
        }
 
+       if (!strcmp(var, "core.pager")) {
+               pager_program = xstrdup(value);
+               return 0;
+       }
+
        /* Add other config variables here and to Documentation/config.txt. */
        return 0;
 }
@@ -512,7 +533,7 @@ static int store_aux(const char* key, const char* value)
        return 0;
 }
 
-static int write_error()
+static int write_error(void)
 {
        fprintf(stderr, "Failed to write new configuration file\n");
 
@@ -610,7 +631,7 @@ static ssize_t find_beginning_of_line(const char* contents, size_t size,
        size_t equal_offset = size, bracket_offset = size;
        ssize_t offset;
 
-       for (offset = offset_-2; offset > 0 
+       for (offset = offset_-2; offset > 0
                        && contents[offset] != '\n'; offset--)
                switch (contents[offset]) {
                        case '=': equal_offset = offset; break;
@@ -978,4 +999,3 @@ int git_config_rename_section(const char *old_name, const char *new_name)
        free(config_filename);
        return ret;
 }
-
index eb9d7a55496492fa021e8262f052c7f46b60ea20..a3032e389f6bf63cd46a3aa23e59b6a6cd537132 100644 (file)
@@ -38,4 +38,3 @@ NO_STRCASESTR=@NO_STRCASESTR@
 NO_STRLCPY=@NO_STRLCPY@
 NO_SETENV=@NO_SETENV@
 NO_ICONV=@NO_ICONV@
-
index da89c9cfcf3469dfab789f2644f953ea46666e90..65e79edc77101ba4f195d5ce267c712da52b3b0b 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -4,6 +4,7 @@
 #include "quote.h"
 #include "refs.h"
 #include "run-command.h"
+#include "remote.h"
 
 static char *server_capabilities;
 
@@ -128,245 +129,6 @@ int path_match(const char *path, int nr, char **match)
        return 0;
 }
 
-struct refspec {
-       char *src;
-       char *dst;
-       char force;
-};
-
-/*
- * A:B means fast forward remote B with local A.
- * +A:B means overwrite remote B with local A.
- * +A is a shorthand for +A:A.
- * A is a shorthand for A:A.
- * :B means delete remote B.
- */
-static struct refspec *parse_ref_spec(int nr_refspec, char **refspec)
-{
-       int i;
-       struct refspec *rs = xcalloc(sizeof(*rs), (nr_refspec + 1));
-       for (i = 0; i < nr_refspec; i++) {
-               char *sp, *dp, *ep;
-               sp = refspec[i];
-               if (*sp == '+') {
-                       rs[i].force = 1;
-                       sp++;
-               }
-               ep = strchr(sp, ':');
-               if (ep) {
-                       dp = ep + 1;
-                       *ep = 0;
-               }
-               else
-                       dp = sp;
-               rs[i].src = sp;
-               rs[i].dst = dp;
-       }
-       rs[nr_refspec].src = rs[nr_refspec].dst = NULL;
-       return rs;
-}
-
-static int count_refspec_match(const char *pattern,
-                              struct ref *refs,
-                              struct ref **matched_ref)
-{
-       int patlen = strlen(pattern);
-       struct ref *matched_weak = NULL;
-       struct ref *matched = NULL;
-       int weak_match = 0;
-       int match = 0;
-
-       for (weak_match = match = 0; refs; refs = refs->next) {
-               char *name = refs->name;
-               int namelen = strlen(name);
-               int weak_match;
-
-               if (namelen < patlen ||
-                   memcmp(name + namelen - patlen, pattern, patlen))
-                       continue;
-               if (namelen != patlen && name[namelen - patlen - 1] != '/')
-                       continue;
-
-               /* A match is "weak" if it is with refs outside
-                * heads or tags, and did not specify the pattern
-                * in full (e.g. "refs/remotes/origin/master") or at
-                * least from the toplevel (e.g. "remotes/origin/master");
-                * otherwise "git push $URL master" would result in
-                * ambiguity between remotes/origin/master and heads/master
-                * at the remote site.
-                */
-               if (namelen != patlen &&
-                   patlen != namelen - 5 &&
-                   prefixcmp(name, "refs/heads/") &&
-                   prefixcmp(name, "refs/tags/")) {
-                       /* We want to catch the case where only weak
-                        * matches are found and there are multiple
-                        * matches, and where more than one strong
-                        * matches are found, as ambiguous.  One
-                        * strong match with zero or more weak matches
-                        * are acceptable as a unique match.
-                        */
-                       matched_weak = refs;
-                       weak_match++;
-               }
-               else {
-                       matched = refs;
-                       match++;
-               }
-       }
-       if (!matched) {
-               *matched_ref = matched_weak;
-               return weak_match;
-       }
-       else {
-               *matched_ref = matched;
-               return match;
-       }
-}
-
-static void link_dst_tail(struct ref *ref, struct ref ***tail)
-{
-       **tail = ref;
-       *tail = &ref->next;
-       **tail = NULL;
-}
-
-static struct ref *try_explicit_object_name(const char *name)
-{
-       unsigned char sha1[20];
-       struct ref *ref;
-       int len;
-
-       if (!*name) {
-               ref = xcalloc(1, sizeof(*ref) + 20);
-               strcpy(ref->name, "(delete)");
-               hashclr(ref->new_sha1);
-               return ref;
-       }
-       if (get_sha1(name, sha1))
-               return NULL;
-       len = strlen(name) + 1;
-       ref = xcalloc(1, sizeof(*ref) + len);
-       memcpy(ref->name, name, len);
-       hashcpy(ref->new_sha1, sha1);
-       return ref;
-}
-
-static int match_explicit_refs(struct ref *src, struct ref *dst,
-                              struct ref ***dst_tail, struct refspec *rs)
-{
-       int i, errs;
-       for (i = errs = 0; rs[i].src; i++) {
-               struct ref *matched_src, *matched_dst;
-
-               matched_src = matched_dst = NULL;
-               switch (count_refspec_match(rs[i].src, src, &matched_src)) {
-               case 1:
-                       break;
-               case 0:
-                       /* The source could be in the get_sha1() format
-                        * not a reference name.  :refs/other is a
-                        * way to delete 'other' ref at the remote end.
-                        */
-                       matched_src = try_explicit_object_name(rs[i].src);
-                       if (matched_src)
-                               break;
-                       errs = 1;
-                       error("src refspec %s does not match any.",
-                             rs[i].src);
-                       break;
-               default:
-                       errs = 1;
-                       error("src refspec %s matches more than one.",
-                             rs[i].src);
-                       break;
-               }
-               switch (count_refspec_match(rs[i].dst, dst, &matched_dst)) {
-               case 1:
-                       break;
-               case 0:
-                       if (!memcmp(rs[i].dst, "refs/", 5)) {
-                               int len = strlen(rs[i].dst) + 1;
-                               matched_dst = xcalloc(1, sizeof(*dst) + len);
-                               memcpy(matched_dst->name, rs[i].dst, len);
-                               link_dst_tail(matched_dst, dst_tail);
-                       }
-                       else if (!strcmp(rs[i].src, rs[i].dst) &&
-                                matched_src) {
-                               /* pushing "master:master" when
-                                * remote does not have master yet.
-                                */
-                               int len = strlen(matched_src->name) + 1;
-                               matched_dst = xcalloc(1, sizeof(*dst) + len);
-                               memcpy(matched_dst->name, matched_src->name,
-                                      len);
-                               link_dst_tail(matched_dst, dst_tail);
-                       }
-                       else {
-                               errs = 1;
-                               error("dst refspec %s does not match any "
-                                     "existing ref on the remote and does "
-                                     "not start with refs/.", rs[i].dst);
-                       }
-                       break;
-               default:
-                       errs = 1;
-                       error("dst refspec %s matches more than one.",
-                             rs[i].dst);
-                       break;
-               }
-               if (errs)
-                       continue;
-               if (matched_dst->peer_ref) {
-                       errs = 1;
-                       error("dst ref %s receives from more than one src.",
-                             matched_dst->name);
-               }
-               else {
-                       matched_dst->peer_ref = matched_src;
-                       matched_dst->force = rs[i].force;
-               }
-       }
-       return -errs;
-}
-
-static struct ref *find_ref_by_name(struct ref *list, const char *name)
-{
-       for ( ; list; list = list->next)
-               if (!strcmp(list->name, name))
-                       return list;
-       return NULL;
-}
-
-int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
-              int nr_refspec, char **refspec, int all)
-{
-       struct refspec *rs = parse_ref_spec(nr_refspec, refspec);
-
-       if (nr_refspec)
-               return match_explicit_refs(src, dst, dst_tail, rs);
-
-       /* pick the remainder */
-       for ( ; src; src = src->next) {
-               struct ref *dst_peer;
-               if (src->peer_ref)
-                       continue;
-               dst_peer = find_ref_by_name(dst, src->name);
-               if ((dst_peer && dst_peer->peer_ref) || (!dst_peer && !all))
-                       continue;
-               if (!dst_peer) {
-                       /* Create a new one and link it */
-                       int len = strlen(src->name) + 1;
-                       dst_peer = xcalloc(1, sizeof(*dst_peer) + len);
-                       memcpy(dst_peer->name, src->name, len);
-                       hashcpy(dst_peer->new_sha1, src->new_sha1);
-                       link_dst_tail(dst_peer, dst_tail);
-               }
-               dst_peer->peer_ref = src;
-       }
-       return 0;
-}
-
 enum protocol {
        PROTO_LOCAL = 1,
        PROTO_SSH,
@@ -391,16 +153,34 @@ static enum protocol get_protocol(const char *name)
 
 #ifndef NO_IPV6
 
+static const char *ai_name(const struct addrinfo *ai)
+{
+       static char addr[INET_ADDRSTRLEN];
+       if ( AF_INET == ai->ai_family ) {
+               struct sockaddr_in *in;
+               in = (struct sockaddr_in *)ai->ai_addr;
+               inet_ntop(ai->ai_family, &in->sin_addr, addr, sizeof(addr));
+       } else if ( AF_INET6 == ai->ai_family ) {
+               struct sockaddr_in6 *in;
+               in = (struct sockaddr_in6 *)ai->ai_addr;
+               inet_ntop(ai->ai_family, &in->sin6_addr, addr, sizeof(addr));
+       } else {
+               strcpy(addr, "(unknown)");
+       }
+       return addr;
+}
+
 /*
  * Returns a connected socket() fd, or else die()s.
  */
-static int git_tcp_connect_sock(char *host)
+static int git_tcp_connect_sock(char *host, int flags)
 {
        int sockfd = -1, saved_errno = 0;
        char *colon, *end;
        const char *port = STR(DEFAULT_GIT_PORT);
        struct addrinfo hints, *ai0, *ai;
        int gai;
+       int cnt = 0;
 
        if (host[0] == '[') {
                end = strchr(host + 1, ']');
@@ -425,10 +205,16 @@ static int git_tcp_connect_sock(char *host)
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = IPPROTO_TCP;
 
+       if (flags & CONNECT_VERBOSE)
+               fprintf(stderr, "Looking up %s ... ", host);
+
        gai = getaddrinfo(host, port, &hints, &ai);
        if (gai)
                die("Unable to look up %s (port %s) (%s)", host, port, gai_strerror(gai));
 
+       if (flags & CONNECT_VERBOSE)
+               fprintf(stderr, "done.\nConnecting to %s (port %s) ... ", host, port);
+
        for (ai0 = ai; ai; ai = ai->ai_next) {
                sockfd = socket(ai->ai_family,
                                ai->ai_socktype, ai->ai_protocol);
@@ -438,10 +224,17 @@ static int git_tcp_connect_sock(char *host)
                }
                if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
                        saved_errno = errno;
+                       fprintf(stderr, "%s[%d: %s]: errno=%s\n",
+                               host,
+                               cnt,
+                               ai_name(ai),
+                               strerror(saved_errno));
                        close(sockfd);
                        sockfd = -1;
                        continue;
                }
+               if (flags & CONNECT_VERBOSE)
+                       fprintf(stderr, "%s ", ai_name(ai));
                break;
        }
 
@@ -450,6 +243,9 @@ static int git_tcp_connect_sock(char *host)
        if (sockfd < 0)
                die("unable to connect a socket (%s)", strerror(saved_errno));
 
+       if (flags & CONNECT_VERBOSE)
+               fprintf(stderr, "done.\n");
+
        return sockfd;
 }
 
@@ -458,7 +254,7 @@ static int git_tcp_connect_sock(char *host)
 /*
  * Returns a connected socket() fd, or else die()s.
  */
-static int git_tcp_connect_sock(char *host)
+static int git_tcp_connect_sock(char *host, int flags)
 {
        int sockfd = -1, saved_errno = 0;
        char *colon, *end;
@@ -467,6 +263,7 @@ static int git_tcp_connect_sock(char *host)
        struct sockaddr_in sa;
        char **ap;
        unsigned int nport;
+       int cnt;
 
        if (host[0] == '[') {
                end = strchr(host + 1, ']');
@@ -485,6 +282,9 @@ static int git_tcp_connect_sock(char *host)
                port = colon + 1;
        }
 
+       if (flags & CONNECT_VERBOSE)
+               fprintf(stderr, "Looking up %s ... ", host);
+
        he = gethostbyname(host);
        if (!he)
                die("Unable to look up %s (%s)", host, hstrerror(h_errno));
@@ -497,7 +297,10 @@ static int git_tcp_connect_sock(char *host)
                nport = se->s_port;
        }
 
-       for (ap = he->h_addr_list; *ap; ap++) {
+       if (flags & CONNECT_VERBOSE)
+               fprintf(stderr, "done.\nConnecting to %s (port %s) ... ", host, port);
+
+       for (cnt = 0, ap = he->h_addr_list; *ap; ap++, cnt++) {
                sockfd = socket(he->h_addrtype, SOCK_STREAM, 0);
                if (sockfd < 0) {
                        saved_errno = errno;
@@ -511,25 +314,36 @@ static int git_tcp_connect_sock(char *host)
 
                if (connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) {
                        saved_errno = errno;
+                       fprintf(stderr, "%s[%d: %s]: errno=%s\n",
+                               host,
+                               cnt,
+                               inet_ntoa(*(struct in_addr *)&sa.sin_addr),
+                               strerror(saved_errno));
                        close(sockfd);
                        sockfd = -1;
                        continue;
                }
+               if (flags & CONNECT_VERBOSE)
+                       fprintf(stderr, "%s ",
+                               inet_ntoa(*(struct in_addr *)&sa.sin_addr));
                break;
        }
 
        if (sockfd < 0)
                die("unable to connect a socket (%s)", strerror(saved_errno));
 
+       if (flags & CONNECT_VERBOSE)
+               fprintf(stderr, "done.\n");
+
        return sockfd;
 }
 
 #endif /* NO_IPV6 */
 
 
-static void git_tcp_connect(int fd[2], char *host)
+static void git_tcp_connect(int fd[2], char *host, int flags)
 {
-       int sockfd = git_tcp_connect_sock(host);
+       int sockfd = git_tcp_connect_sock(host, flags);
 
        fd[0] = sockfd;
        fd[1] = dup(sockfd);
@@ -574,7 +388,7 @@ static int git_proxy_command_options(const char *var, const char *value)
                }
                if (0 <= matchlen) {
                        /* core.gitproxy = none for kernel.org */
-                       if (matchlen == 4 && 
+                       if (matchlen == 4 &&
                            !memcmp(value, "none", 4))
                                matchlen = 0;
                        git_proxy_command = xmalloc(matchlen + 1);
@@ -646,7 +460,7 @@ static void git_proxy_connect(int fd[2], char *host)
  *
  * Does not return a negative value on error; it just dies.
  */
-pid_t git_connect(int fd[2], char *url, const char *prog)
+pid_t git_connect(int fd[2], char *url, const char *prog, int flags)
 {
        char *host, *path = url;
        char *end;
@@ -719,7 +533,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog)
                if (git_use_proxy(host))
                        git_proxy_connect(fd, host);
                else
-                       git_tcp_connect(fd, host);
+                       git_tcp_connect(fd, host, flags);
                /*
                 * Separate original protocol components prog and path
                 * from extended components with a NUL byte.
@@ -773,6 +587,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog)
                        unsetenv(ALTERNATE_DB_ENVIRONMENT);
                        unsetenv(DB_ENVIRONMENT);
                        unsetenv(GIT_DIR_ENVIRONMENT);
+                       unsetenv(GIT_WORK_TREE_ENVIRONMENT);
                        unsetenv(GRAFT_ENVIRONMENT);
                        unsetenv(INDEX_ENVIRONMENT);
                        execlp("sh", "sh", "-c", command, NULL);
index e1c0a01ff30d3756d547781f783a37c96e9b7eb9..05f291c1f1d3d1018f390618816f94d0cd58951b 100644 (file)
@@ -41,4 +41,3 @@ submit a patch to create a subdirectory of contrib/ and put your
 stuff there.
 
 -jc
-
index 50a6f67fd6df5c37a0e244ff5c5997131f3f0f52..fada5ce909876168f68a85c8ca9a8bc269048acb 100644 (file)
@@ -7,4 +7,3 @@ To: Linus Torvalds <torvalds@linux-foundation.org>
 Cc: git@vger.kernel.org
 Date: Sat, 27 Jan 2007 18:52:38 -0500
 Message-ID: <20070127235238.GA28706@coredump.intra.peff.net>
-
index 9e72f0f7b1668ba144397b6a6a2094d4294f5724..f2b10fa5f67942dc1c8d9d4f16048a6e7e976084 100755 (executable)
@@ -682,8 +682,11 @@ _git_push ()
                        esac
                        __gitcomp "$(__git_refs "$remote")" "" "${cur#*:}"
                        ;;
+               +*)
+                       __gitcomp "$(__git_refs)" + "${cur#+}"
+                       ;;
                *)
-                       __gitcomp "$(__git_refs2)"
+                       __gitcomp "$(__git_refs)"
                        ;;
                esac
                ;;
index f60017948f4eb45f6aa7fe0fc60ca1507cec98f2..457f95fc0599b32fb6da20c59094cd77d7f6f252 100644 (file)
@@ -681,8 +681,7 @@ and returns the process output as a string."
                             (condition-case nil (delete-file ".git/MERGE_MSG") (error nil))
                             (with-current-buffer buffer (erase-buffer))
                             (git-set-files-state files 'uptodate)
-                            (when (file-directory-p ".git/rr-cache")
-                              (git-run-command nil nil "rerere"))
+                            (git-run-command nil nil "rerere")
                             (git-refresh-files)
                             (git-refresh-ewoc-hf git-status)
                             (message "Committed %s." commit)
index 436d7caff5c26f7c0ff8c0a410bdabccdec0a900..2ae235b081ea9829a51758bba5a0d0d64111d32c 100755 (executable)
@@ -30,8 +30,8 @@ notbare|"")
 esac
 
 test "true" != "$pack_refs" ||
-git-pack-refs --prune &&
-git-reflog expire --all &&
+git pack-refs --prune &&
+git reflog expire --all &&
 git-repack -a -d -l &&
-$no_prune git-prune &&
-git-rerere gc || exit
+$no_prune git prune &&
+git rerere gc || exit
index 36b90e38494eb79b4859cf59301b5a4e6ccccea1..0ee1bd898ecbb725d13385408b4ed4bcb413f503 100755 (executable)
@@ -17,8 +17,8 @@ dropheads() {
                "$GIT_DIR/LAST_MERGE" || exit 1
 }
 
-head=$(git-rev-parse --verify "$1"^0) &&
-merge=$(git-rev-parse --verify "$2"^0) &&
+head=$(git rev-parse --verify "$1"^0) &&
+merge=$(git rev-parse --verify "$2"^0) &&
 merge_name="$2" &&
 merge_msg="$3" || usage
 
@@ -34,7 +34,7 @@ dropheads
 echo $head > "$GIT_DIR"/ORIG_HEAD
 echo $merge > "$GIT_DIR"/LAST_MERGE
 
-common=$(git-merge-base $head $merge)
+common=$(git merge-base $head $merge)
 if [ -z "$common" ]; then
        die "Unable to find common commit between" $merge $head
 fi
@@ -46,11 +46,11 @@ case "$common" in
        exit 0
        ;;
 "$head")
-       echo "Updating $(git-rev-parse --short $head)..$(git-rev-parse --short $merge)"
-       git-read-tree -u -m $head $merge || exit 1
-       git-update-ref -m "resolve $merge_name: Fast forward" \
+       echo "Updating $(git rev-parse --short $head)..$(git rev-parse --short $merge)"
+       git read-tree -u -m $head $merge || exit 1
+       git update-ref -m "resolve $merge_name: Fast forward" \
                HEAD "$merge" "$head"
-       git-diff-tree -p $head $merge | git-apply --stat
+       git diff-tree -p $head $merge | git apply --stat
        dropheads
        exit 0
        ;;
@@ -62,7 +62,7 @@ git var GIT_COMMITTER_IDENT >/dev/null || exit
 # Find an optimum merge base if there are more than one candidates.
 LF='
 '
-common=$(git-merge-base -a $head $merge)
+common=$(git merge-base -a $head $merge)
 case "$common" in
 ?*"$LF"?*)
        echo "Trying to find the optimum merge base."
@@ -72,10 +72,10 @@ case "$common" in
        for c in $common
        do
                rm -f $G
-               GIT_INDEX_FILE=$G git-read-tree -m $c $head $merge \
+               GIT_INDEX_FILE=$G git read-tree -m $c $head $merge \
                        2>/dev/null || continue
                # Count the paths that are unmerged.
-               cnt=`GIT_INDEX_FILE=$G git-ls-files --unmerged | wc -l`
+               cnt=`GIT_INDEX_FILE=$G git ls-files --unmerged | wc -l`
                if test $best_cnt -le 0 -o $cnt -le $best_cnt
                then
                        best=$c
@@ -92,9 +92,9 @@ case "$common" in
 esac
 
 echo "Trying to merge $merge into $head using $common."
-git-update-index --refresh 2>/dev/null
-git-read-tree -u -m $common $head $merge || exit 1
-result_tree=$(git-write-tree  2> /dev/null)
+git update-index --refresh 2>/dev/null
+git read-tree -u -m $common $head $merge || exit 1
+result_tree=$(git write-tree  2> /dev/null)
 if [ $? -ne 0 ]; then
        echo "Simple merge failed, trying Automatic merge"
        git-merge-index -o git-merge-one-file -a
@@ -102,11 +102,11 @@ if [ $? -ne 0 ]; then
                echo $merge > "$GIT_DIR"/MERGE_HEAD
                die "Automatic merge failed, fix up by hand"
        fi
-       result_tree=$(git-write-tree) || exit 1
+       result_tree=$(git write-tree) || exit 1
 fi
-result_commit=$(echo "$merge_msg" | git-commit-tree $result_tree -p $head -p $merge)
+result_commit=$(echo "$merge_msg" | git commit-tree $result_tree -p $head -p $merge)
 echo "Committed merge $result_commit"
-git-update-ref -m "resolve $merge_name: In-index merge" \
+git update-ref -m "resolve $merge_name: In-index merge" \
        HEAD "$result_commit" "$head"
-git-diff-tree -p $head $result_commit | git-apply --stat
+git diff-tree -p $head $result_commit | git apply --stat
 dropheads
diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
new file mode 100755 (executable)
index 0000000..54a05eb
--- /dev/null
@@ -0,0 +1,1577 @@
+#!/usr/bin/env python
+#
+# git-p4.py -- A tool for bidirectional operation between a Perforce depot and git.
+#
+# Author: Simon Hausmann <simon@lst.de>
+# Copyright: 2007 Simon Hausmann <simon@lst.de>
+#            2007 Trolltech ASA
+# License: MIT <http://www.opensource.org/licenses/mit-license.php>
+#
+
+import optparse, sys, os, marshal, popen2, subprocess, shelve
+import tempfile, getopt, sha, os.path, time, platform
+import re
+
+from sets import Set;
+
+verbose = False
+
+def die(msg):
+    if verbose:
+        raise Exception(msg)
+    else:
+        sys.stderr.write(msg + "\n")
+        sys.exit(1)
+
+def write_pipe(c, str):
+    if verbose:
+        sys.stderr.write('Writing pipe: %s\n' % c)
+
+    pipe = os.popen(c, 'w')
+    val = pipe.write(str)
+    if pipe.close():
+        die('Command failed: %s' % c)
+
+    return val
+
+def read_pipe(c, ignore_error=False):
+    if verbose:
+        sys.stderr.write('Reading pipe: %s\n' % c)
+
+    pipe = os.popen(c, 'rb')
+    val = pipe.read()
+    if pipe.close() and not ignore_error:
+        die('Command failed: %s' % c)
+
+    return val
+
+
+def read_pipe_lines(c):
+    if verbose:
+        sys.stderr.write('Reading pipe: %s\n' % c)
+    ## todo: check return status
+    pipe = os.popen(c, 'rb')
+    val = pipe.readlines()
+    if pipe.close():
+        die('Command failed: %s' % c)
+
+    return val
+
+def system(cmd):
+    if verbose:
+        sys.stderr.write("executing %s\n" % cmd)
+    if os.system(cmd) != 0:
+        die("command failed: %s" % cmd)
+
+def p4CmdList(cmd):
+    cmd = "p4 -G %s" % cmd
+    if verbose:
+        sys.stderr.write("Opening pipe: %s\n" % cmd)
+    pipe = os.popen(cmd, "rb")
+
+    result = []
+    try:
+        while True:
+            entry = marshal.load(pipe)
+            result.append(entry)
+    except EOFError:
+        pass
+    exitCode = pipe.close()
+    if exitCode != None:
+        entry = {}
+        entry["p4ExitCode"] = exitCode
+        result.append(entry)
+
+    return result
+
+def p4Cmd(cmd):
+    list = p4CmdList(cmd)
+    result = {}
+    for entry in list:
+        result.update(entry)
+    return result;
+
+def p4Where(depotPath):
+    if not depotPath.endswith("/"):
+        depotPath += "/"
+    output = p4Cmd("where %s..." % depotPath)
+    if output["code"] == "error":
+        return ""
+    clientPath = ""
+    if "path" in output:
+        clientPath = output.get("path")
+    elif "data" in output:
+        data = output.get("data")
+        lastSpace = data.rfind(" ")
+        clientPath = data[lastSpace + 1:]
+
+    if clientPath.endswith("..."):
+        clientPath = clientPath[:-3]
+    return clientPath
+
+def currentGitBranch():
+    return read_pipe("git name-rev HEAD").split(" ")[1].strip()
+
+def isValidGitDir(path):
+    if (os.path.exists(path + "/HEAD")
+        and os.path.exists(path + "/refs") and os.path.exists(path + "/objects")):
+        return True;
+    return False
+
+def parseRevision(ref):
+    return read_pipe("git rev-parse %s" % ref).strip()
+
+def extractLogMessageFromGitCommit(commit):
+    logMessage = ""
+
+    ## fixme: title is first line of commit, not 1st paragraph.
+    foundTitle = False
+    for log in read_pipe_lines("git cat-file commit %s" % commit):
+       if not foundTitle:
+           if len(log) == 1:
+               foundTitle = True
+           continue
+
+       logMessage += log
+    return logMessage
+
+def extractSettingsGitLog(log):
+    values = {}
+    for line in log.split("\n"):
+        line = line.strip()
+        m = re.search (r"^ *\[git-p4: (.*)\]$", line)
+        if not m:
+            continue
+
+        assignments = m.group(1).split (':')
+        for a in assignments:
+            vals = a.split ('=')
+            key = vals[0].strip()
+            val = ('='.join (vals[1:])).strip()
+            if val.endswith ('\"') and val.startswith('"'):
+                val = val[1:-1]
+
+            values[key] = val
+
+    paths = values.get("depot-paths")
+    if not paths:
+        paths = values.get("depot-path")
+    if paths:
+        values['depot-paths'] = paths.split(',')
+    return values
+
+def gitBranchExists(branch):
+    proc = subprocess.Popen(["git", "rev-parse", branch],
+                            stderr=subprocess.PIPE, stdout=subprocess.PIPE);
+    return proc.wait() == 0;
+
+def gitConfig(key):
+    return read_pipe("git config %s" % key, ignore_error=True).strip()
+
+def findUpstreamBranchPoint(head = "HEAD"):
+    settings = None
+    branchPoint = ""
+    parent = 0
+    while parent < 65535:
+        commit = head + "~%s" % parent
+        log = extractLogMessageFromGitCommit(commit)
+        settings = extractSettingsGitLog(log)
+        if not settings.has_key("depot-paths"):
+            parent = parent + 1
+            continue
+
+        names = read_pipe_lines("git name-rev \"--refs=refs/remotes/p4/*\" \"%s\"" % commit)
+        if len(names) <= 0:
+            continue
+
+        # strip away the beginning of 'HEAD~42 refs/remotes/p4/foo'
+        branchPoint = names[0].strip()[len(commit) + 1:]
+        break
+
+    return [branchPoint, settings]
+
+class Command:
+    def __init__(self):
+        self.usage = "usage: %prog [options]"
+        self.needsGit = True
+
+class P4Debug(Command):
+    def __init__(self):
+        Command.__init__(self)
+        self.options = [
+            optparse.make_option("--verbose", dest="verbose", action="store_true",
+                                 default=False),
+            ]
+        self.description = "A tool to debug the output of p4 -G."
+        self.needsGit = False
+        self.verbose = False
+
+    def run(self, args):
+        j = 0
+        for output in p4CmdList(" ".join(args)):
+            print 'Element: %d' % j
+            j += 1
+            print output
+        return True
+
+class P4RollBack(Command):
+    def __init__(self):
+        Command.__init__(self)
+        self.options = [
+            optparse.make_option("--verbose", dest="verbose", action="store_true"),
+            optparse.make_option("--local", dest="rollbackLocalBranches", action="store_true")
+        ]
+        self.description = "A tool to debug the multi-branch import. Don't use :)"
+        self.verbose = False
+        self.rollbackLocalBranches = False
+
+    def run(self, args):
+        if len(args) != 1:
+            return False
+        maxChange = int(args[0])
+
+        if "p4ExitCode" in p4Cmd("changes -m 1"):
+            die("Problems executing p4");
+
+        if self.rollbackLocalBranches:
+            refPrefix = "refs/heads/"
+            lines = read_pipe_lines("git rev-parse --symbolic --branches")
+        else:
+            refPrefix = "refs/remotes/"
+            lines = read_pipe_lines("git rev-parse --symbolic --remotes")
+
+        for line in lines:
+            if self.rollbackLocalBranches or (line.startswith("p4/") and line != "p4/HEAD\n"):
+                line = line.strip()
+                ref = refPrefix + line
+                log = extractLogMessageFromGitCommit(ref)
+                settings = extractSettingsGitLog(log)
+
+                depotPaths = settings['depot-paths']
+                change = settings['change']
+
+                changed = False
+
+                if len(p4Cmd("changes -m 1 "  + ' '.join (['%s...@%s' % (p, maxChange)
+                                                           for p in depotPaths]))) == 0:
+                    print "Branch %s did not exist at change %s, deleting." % (ref, maxChange)
+                    system("git update-ref -d %s `git rev-parse %s`" % (ref, ref))
+                    continue
+
+                while change and int(change) > maxChange:
+                    changed = True
+                    if self.verbose:
+                        print "%s is at %s ; rewinding towards %s" % (ref, change, maxChange)
+                    system("git update-ref %s \"%s^\"" % (ref, ref))
+                    log = extractLogMessageFromGitCommit(ref)
+                    settings =  extractSettingsGitLog(log)
+
+
+                    depotPaths = settings['depot-paths']
+                    change = settings['change']
+
+                if changed:
+                    print "%s rewound to %s" % (ref, change)
+
+        return True
+
+class P4Submit(Command):
+    def __init__(self):
+        Command.__init__(self)
+        self.options = [
+                optparse.make_option("--continue", action="store_false", dest="firstTime"),
+                optparse.make_option("--verbose", dest="verbose", action="store_true"),
+                optparse.make_option("--origin", dest="origin"),
+                optparse.make_option("--reset", action="store_true", dest="reset"),
+                optparse.make_option("--log-substitutions", dest="substFile"),
+                optparse.make_option("--dry-run", action="store_true"),
+                optparse.make_option("--direct", dest="directSubmit", action="store_true"),
+                optparse.make_option("--trust-me-like-a-fool", dest="trustMeLikeAFool", action="store_true"),
+        ]
+        self.description = "Submit changes from git to the perforce depot."
+        self.usage += " [name of git branch to submit into perforce depot]"
+        self.firstTime = True
+        self.reset = False
+        self.interactive = True
+        self.dryRun = False
+        self.substFile = ""
+        self.firstTime = True
+        self.origin = ""
+        self.directSubmit = False
+        self.trustMeLikeAFool = False
+        self.verbose = False
+        self.isWindows = (platform.system() == "Windows")
+
+        self.logSubstitutions = {}
+        self.logSubstitutions["<enter description here>"] = "%log%"
+        self.logSubstitutions["\tDetails:"] = "\tDetails:  %log%"
+
+    def check(self):
+        if len(p4CmdList("opened ...")) > 0:
+            die("You have files opened with perforce! Close them before starting the sync.")
+
+    def start(self):
+        if len(self.config) > 0 and not self.reset:
+            die("Cannot start sync. Previous sync config found at %s\n"
+                "If you want to start submitting again from scratch "
+                "maybe you want to call git-p4 submit --reset" % self.configFile)
+
+        commits = []
+        if self.directSubmit:
+            commits.append("0")
+        else:
+            for line in read_pipe_lines("git rev-list --no-merges %s..%s" % (self.origin, self.master)):
+                commits.append(line.strip())
+            commits.reverse()
+
+        self.config["commits"] = commits
+
+    def prepareLogMessage(self, template, message):
+        result = ""
+
+        for line in template.split("\n"):
+            if line.startswith("#"):
+                result += line + "\n"
+                continue
+
+            substituted = False
+            for key in self.logSubstitutions.keys():
+                if line.find(key) != -1:
+                    value = self.logSubstitutions[key]
+                    value = value.replace("%log%", message)
+                    if value != "@remove@":
+                        result += line.replace(key, value) + "\n"
+                    substituted = True
+                    break
+
+            if not substituted:
+                result += line + "\n"
+
+        return result
+
+    def applyCommit(self, id):
+        if self.directSubmit:
+            print "Applying local change in working directory/index"
+            diff = self.diffStatus
+        else:
+            print "Applying %s" % (read_pipe("git log --max-count=1 --pretty=oneline %s" % id))
+            diff = read_pipe_lines("git diff-tree -r --name-status \"%s^\" \"%s\"" % (id, id))
+        filesToAdd = set()
+        filesToDelete = set()
+        editedFiles = set()
+        for line in diff:
+            modifier = line[0]
+            path = line[1:].strip()
+            if modifier == "M":
+                system("p4 edit \"%s\"" % path)
+                editedFiles.add(path)
+            elif modifier == "A":
+                filesToAdd.add(path)
+                if path in filesToDelete:
+                    filesToDelete.remove(path)
+            elif modifier == "D":
+                filesToDelete.add(path)
+                if path in filesToAdd:
+                    filesToAdd.remove(path)
+            else:
+                die("unknown modifier %s for %s" % (modifier, path))
+
+        if self.directSubmit:
+            diffcmd = "cat \"%s\"" % self.diffFile
+        else:
+            diffcmd = "git format-patch -k --stdout \"%s^\"..\"%s\"" % (id, id)
+        patchcmd = diffcmd + " | git apply "
+        tryPatchCmd = patchcmd + "--check -"
+        applyPatchCmd = patchcmd + "--check --apply -"
+
+        if os.system(tryPatchCmd) != 0:
+            print "Unfortunately applying the change failed!"
+            print "What do you want to do?"
+            response = "x"
+            while response != "s" and response != "a" and response != "w":
+                response = raw_input("[s]kip this patch / [a]pply the patch forcibly "
+                                     "and with .rej files / [w]rite the patch to a file (patch.txt) ")
+            if response == "s":
+                print "Skipping! Good luck with the next patches..."
+                return
+            elif response == "a":
+                os.system(applyPatchCmd)
+                if len(filesToAdd) > 0:
+                    print "You may also want to call p4 add on the following files:"
+                    print " ".join(filesToAdd)
+                if len(filesToDelete):
+                    print "The following files should be scheduled for deletion with p4 delete:"
+                    print " ".join(filesToDelete)
+                die("Please resolve and submit the conflict manually and "
+                    + "continue afterwards with git-p4 submit --continue")
+            elif response == "w":
+                system(diffcmd + " > patch.txt")
+                print "Patch saved to patch.txt in %s !" % self.clientPath
+                die("Please resolve and submit the conflict manually and "
+                    "continue afterwards with git-p4 submit --continue")
+
+        system(applyPatchCmd)
+
+        for f in filesToAdd:
+            system("p4 add \"%s\"" % f)
+        for f in filesToDelete:
+            system("p4 revert \"%s\"" % f)
+            system("p4 delete \"%s\"" % f)
+
+        logMessage = ""
+        if not self.directSubmit:
+            logMessage = extractLogMessageFromGitCommit(id)
+            logMessage = logMessage.replace("\n", "\n\t")
+            if self.isWindows:
+                logMessage = logMessage.replace("\n", "\r\n")
+            logMessage = logMessage.strip()
+
+        template = read_pipe("p4 change -o")
+
+        if self.interactive:
+            submitTemplate = self.prepareLogMessage(template, logMessage)
+            diff = read_pipe("p4 diff -du ...")
+
+            for newFile in filesToAdd:
+                diff += "==== new file ====\n"
+                diff += "--- /dev/null\n"
+                diff += "+++ %s\n" % newFile
+                f = open(newFile, "r")
+                for line in f.readlines():
+                    diff += "+" + line
+                f.close()
+
+            separatorLine = "######## everything below this line is just the diff #######"
+            if platform.system() == "Windows":
+                separatorLine += "\r"
+            separatorLine += "\n"
+
+            response = "e"
+            if self.trustMeLikeAFool:
+                response = "y"
+
+            firstIteration = True
+            while response == "e":
+                if not firstIteration:
+                    response = raw_input("Do you want to submit this change? [y]es/[e]dit/[n]o/[s]kip ")
+                firstIteration = False
+                if response == "e":
+                    [handle, fileName] = tempfile.mkstemp()
+                    tmpFile = os.fdopen(handle, "w+")
+                    tmpFile.write(submitTemplate + separatorLine + diff)
+                    tmpFile.close()
+                    defaultEditor = "vi"
+                    if platform.system() == "Windows":
+                        defaultEditor = "notepad"
+                    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")
+
+            if response == "y" or response == "yes":
+               if self.dryRun:
+                   print submitTemplate
+                   raw_input("Press return to continue...")
+               else:
+                   if self.directSubmit:
+                       print "Submitting to git first"
+                       os.chdir(self.oldWorkingDirectory)
+                       write_pipe("git commit -a -F -", submitTemplate)
+                       os.chdir(self.clientPath)
+
+                   write_pipe("p4 submit -i", submitTemplate)
+            elif response == "s":
+                for f in editedFiles:
+                    system("p4 revert \"%s\"" % f);
+                for f in filesToAdd:
+                    system("p4 revert \"%s\"" % f);
+                    system("rm %s" %f)
+                for f in filesToDelete:
+                    system("p4 delete \"%s\"" % f);
+                return
+            else:
+                print "Not submitting!"
+                self.interactive = False
+        else:
+            fileName = "submit.txt"
+            file = open(fileName, "w+")
+            file.write(self.prepareLogMessage(template, logMessage))
+            file.close()
+            print ("Perforce submit template written as %s. "
+                   + "Please review/edit and then use p4 submit -i < %s to submit directly!"
+                   % (fileName, fileName))
+
+    def run(self, args):
+        if len(args) == 0:
+            self.master = currentGitBranch()
+            if len(self.master) == 0 or not gitBranchExists("refs/heads/%s" % self.master):
+                die("Detecting current git branch failed!")
+        elif len(args) == 1:
+            self.master = args[0]
+        else:
+            return False
+
+        [upstream, settings] = findUpstreamBranchPoint()
+        depotPath = settings['depot-paths'][0]
+        if len(self.origin) == 0:
+            self.origin = upstream
+
+        if self.verbose:
+            print "Origin branch is " + self.origin
+
+        if len(depotPath) == 0:
+            print "Internal error: cannot locate perforce depot path from existing branches"
+            sys.exit(128)
+
+        self.clientPath = p4Where(depotPath)
+
+        if len(self.clientPath) == 0:
+            print "Error: Cannot locate perforce checkout of %s in client view" % depotPath
+            sys.exit(128)
+
+        print "Perforce checkout for depot path %s located at %s" % (depotPath, self.clientPath)
+        self.oldWorkingDirectory = os.getcwd()
+
+        if self.directSubmit:
+            self.diffStatus = read_pipe_lines("git diff -r --name-status HEAD")
+            if len(self.diffStatus) == 0:
+                print "No changes in working directory to submit."
+                return True
+            patch = read_pipe("git diff -p --binary --diff-filter=ACMRTUXB HEAD")
+            self.diffFile = self.gitdir + "/p4-git-diff"
+            f = open(self.diffFile, "wb")
+            f.write(patch)
+            f.close();
+
+        os.chdir(self.clientPath)
+        response = raw_input("Do you want to sync %s with p4 sync? [y]es/[n]o " % self.clientPath)
+        if response == "y" or response == "yes":
+            system("p4 sync ...")
+
+        if self.reset:
+            self.firstTime = True
+
+        if len(self.substFile) > 0:
+            for line in open(self.substFile, "r").readlines():
+                tokens = line.strip().split("=")
+                self.logSubstitutions[tokens[0]] = tokens[1]
+
+        self.check()
+        self.configFile = self.gitdir + "/p4-git-sync.cfg"
+        self.config = shelve.open(self.configFile, writeback=True)
+
+        if self.firstTime:
+            self.start()
+
+        commits = self.config.get("commits", [])
+
+        while len(commits) > 0:
+            self.firstTime = False
+            commit = commits[0]
+            commits = commits[1:]
+            self.config["commits"] = commits
+            self.applyCommit(commit)
+            if not self.interactive:
+                break
+
+        self.config.close()
+
+        if self.directSubmit:
+            os.remove(self.diffFile)
+
+        if len(commits) == 0:
+            if self.firstTime:
+                print "No changes found to apply between %s and current HEAD" % self.origin
+            else:
+                print "All changes applied!"
+                os.chdir(self.oldWorkingDirectory)
+                response = raw_input("Do you want to sync from Perforce now using git-p4 rebase? [y]es/[n]o ")
+                if response == "y" or response == "yes":
+                    rebase = P4Rebase()
+                    rebase.run([])
+            os.remove(self.configFile)
+
+        return True
+
+class P4Sync(Command):
+    def __init__(self):
+        Command.__init__(self)
+        self.options = [
+                optparse.make_option("--branch", dest="branch"),
+                optparse.make_option("--detect-branches", dest="detectBranches", action="store_true"),
+                optparse.make_option("--changesfile", dest="changesFile"),
+                optparse.make_option("--silent", dest="silent", action="store_true"),
+                optparse.make_option("--detect-labels", dest="detectLabels", action="store_true"),
+                optparse.make_option("--verbose", dest="verbose", action="store_true"),
+                optparse.make_option("--import-local", dest="importIntoRemotes", action="store_false",
+                                     help="Import into refs/heads/ , not refs/remotes"),
+                optparse.make_option("--max-changes", dest="maxChanges"),
+                optparse.make_option("--keep-path", dest="keepRepoPath", action='store_true',
+                                     help="Keep entire BRANCH/DIR/SUBDIR prefix during import")
+        ]
+        self.description = """Imports from Perforce into a git repository.\n
+    example:
+    //depot/my/project/ -- to import the current head
+    //depot/my/project/@all -- to import everything
+    //depot/my/project/@1,6 -- to import only from revision 1 to 6
+
+    (a ... is not needed in the path p4 specification, it's added implicitly)"""
+
+        self.usage += " //depot/path[@revRange]"
+        self.silent = False
+        self.createdBranches = Set()
+        self.committedChanges = Set()
+        self.branch = ""
+        self.detectBranches = False
+        self.detectLabels = False
+        self.changesFile = ""
+        self.syncWithOrigin = True
+        self.verbose = False
+        self.importIntoRemotes = True
+        self.maxChanges = ""
+        self.isWindows = (platform.system() == "Windows")
+        self.keepRepoPath = False
+        self.depotPaths = None
+        self.p4BranchesInGit = []
+
+        if gitConfig("git-p4.syncFromOrigin") == "false":
+            self.syncWithOrigin = False
+
+    def extractFilesFromCommit(self, commit):
+        files = []
+        fnum = 0
+        while commit.has_key("depotFile%s" % fnum):
+            path =  commit["depotFile%s" % fnum]
+
+            found = [p for p in self.depotPaths
+                     if path.startswith (p)]
+            if not found:
+                fnum = fnum + 1
+                continue
+
+            file = {}
+            file["path"] = path
+            file["rev"] = commit["rev%s" % fnum]
+            file["action"] = commit["action%s" % fnum]
+            file["type"] = commit["type%s" % fnum]
+            files.append(file)
+            fnum = fnum + 1
+        return files
+
+    def stripRepoPath(self, path, prefixes):
+        if self.keepRepoPath:
+            prefixes = [re.sub("^(//[^/]+/).*", r'\1', prefixes[0])]
+
+        for p in prefixes:
+            if path.startswith(p):
+                path = path[len(p):]
+
+        return path
+
+    def splitFilesIntoBranches(self, commit):
+        branches = {}
+        fnum = 0
+        while commit.has_key("depotFile%s" % fnum):
+            path =  commit["depotFile%s" % fnum]
+            found = [p for p in self.depotPaths
+                     if path.startswith (p)]
+            if not found:
+                fnum = fnum + 1
+                continue
+
+            file = {}
+            file["path"] = path
+            file["rev"] = commit["rev%s" % fnum]
+            file["action"] = commit["action%s" % fnum]
+            file["type"] = commit["type%s" % fnum]
+            fnum = fnum + 1
+
+            relPath = self.stripRepoPath(path, self.depotPaths)
+
+            for branch in self.knownBranches.keys():
+
+                # add a trailing slash so that a commit into qt/4.2foo doesn't end up in qt/4.2
+                if relPath.startswith(branch + "/"):
+                    if branch not in branches:
+                        branches[branch] = []
+                    branches[branch].append(file)
+                    break
+
+        return branches
+
+    ## Should move this out, doesn't use SELF.
+    def readP4Files(self, files):
+        files = [f for f in files
+                 if f['action'] != 'delete']
+
+        if not files:
+            return
+
+        # We cannot put all the files on the command line
+        # OS have limitations on the max lenght of arguments
+        # POSIX says it's 4096 bytes, default for Linux seems to be 130 K.
+        # and all OS from the table below seems to be higher than POSIX.
+        # See http://www.in-ulm.de/~mascheck/various/argmax/
+        argmax = min(4000, os.sysconf('SC_ARG_MAX'))
+        chunk = ''
+        filedata = []
+        for i in xrange(len(files)):
+            f = files[i]
+            chunk += '"%s#%s" ' % (f['path'], f['rev'])
+            if len(chunk) > argmax or i == len(files)-1:
+                data = p4CmdList('print %s' % chunk)
+                if "p4ExitCode" in data[0]:
+                    die("Problems executing p4. Error: [%d]." % (data[0]['p4ExitCode']));
+                filedata.extend(data)
+                chunk = ''
+
+        j = 0;
+        contents = {}
+        while j < len(filedata):
+            stat = filedata[j]
+            j += 1
+            text = ''
+            while j < len(filedata) and filedata[j]['code'] in ('text',
+                                                                'binary'):
+                text += filedata[j]['data']
+                j += 1
+
+
+            if not stat.has_key('depotFile'):
+                sys.stderr.write("p4 print fails with: %s\n" % repr(stat))
+                continue
+
+            contents[stat['depotFile']] = text
+
+        for f in files:
+            assert not f.has_key('data')
+            f['data'] = contents[f['path']]
+
+    def commit(self, details, files, branch, branchPrefixes, parent = ""):
+        epoch = details["time"]
+        author = details["user"]
+
+        if self.verbose:
+            print "commit into %s" % branch
+
+        # start with reading files; if that fails, we should not
+        # create a commit.
+        new_files = []
+        for f in files:
+            if [p for p in branchPrefixes if f['path'].startswith(p)]:
+                new_files.append (f)
+            else:
+                sys.stderr.write("Ignoring file outside of prefix: %s\n" % path)
+        files = new_files
+        self.readP4Files(files)
+
+
+
+
+        self.gitStream.write("commit %s\n" % branch)
+#        gitStream.write("mark :%s\n" % details["change"])
+        self.committedChanges.add(int(details["change"]))
+        committer = ""
+        if author not in self.users:
+            self.getUserMapFromPerforceServer()
+        if author in self.users:
+            committer = "%s %s %s" % (self.users[author], epoch, self.tz)
+        else:
+            committer = "%s <a@b> %s %s" % (author, epoch, self.tz)
+
+        self.gitStream.write("committer %s\n" % committer)
+
+        self.gitStream.write("data <<EOT\n")
+        self.gitStream.write(details["desc"])
+        self.gitStream.write("\n[git-p4: depot-paths = \"%s\": change = %s"
+                             % (','.join (branchPrefixes), details["change"]))
+        if len(details['options']) > 0:
+            self.gitStream.write(": options = %s" % details['options'])
+        self.gitStream.write("]\nEOT\n\n")
+
+        if len(parent) > 0:
+            if self.verbose:
+                print "parent %s" % parent
+            self.gitStream.write("from %s\n" % parent)
+
+        for file in files:
+            if file["type"] == "apple":
+                print "\nfile %s is a strange apple file that forks. Ignoring!" % file['path']
+                continue
+
+            relPath = self.stripRepoPath(file['path'], branchPrefixes)
+            if file["action"] == "delete":
+                self.gitStream.write("D %s\n" % relPath)
+            else:
+                mode = 644
+                if file["type"].startswith("x"):
+                    mode = 755
+
+                data = file['data']
+
+                if self.isWindows and file["type"].endswith("text"):
+                    data = data.replace("\r\n", "\n")
+
+                self.gitStream.write("M %d inline %s\n" % (mode, relPath))
+                self.gitStream.write("data %s\n" % len(data))
+                self.gitStream.write(data)
+                self.gitStream.write("\n")
+
+        self.gitStream.write("\n")
+
+        change = int(details["change"])
+
+        if self.labels.has_key(change):
+            label = self.labels[change]
+            labelDetails = label[0]
+            labelRevisions = label[1]
+            if self.verbose:
+                print "Change %s is labelled %s" % (change, labelDetails)
+
+            files = p4CmdList("files " + ' '.join (["%s...@%s" % (p, change)
+                                                    for p in branchPrefixes]))
+
+            if len(files) == len(labelRevisions):
+
+                cleanedFiles = {}
+                for info in files:
+                    if info["action"] == "delete":
+                        continue
+                    cleanedFiles[info["depotFile"]] = info["rev"]
+
+                if cleanedFiles == labelRevisions:
+                    self.gitStream.write("tag tag_%s\n" % labelDetails["label"])
+                    self.gitStream.write("from %s\n" % branch)
+
+                    owner = labelDetails["Owner"]
+                    tagger = ""
+                    if author in self.users:
+                        tagger = "%s %s %s" % (self.users[owner], epoch, self.tz)
+                    else:
+                        tagger = "%s <a@b> %s %s" % (owner, epoch, self.tz)
+                    self.gitStream.write("tagger %s\n" % tagger)
+                    self.gitStream.write("data <<EOT\n")
+                    self.gitStream.write(labelDetails["Description"])
+                    self.gitStream.write("EOT\n\n")
+
+                else:
+                    if not self.silent:
+                        print ("Tag %s does not match with change %s: files do not match."
+                               % (labelDetails["label"], change))
+
+            else:
+                if not self.silent:
+                    print ("Tag %s does not match with change %s: file count is different."
+                           % (labelDetails["label"], change))
+
+    def getUserCacheFilename(self):
+        return os.environ["HOME"] + "/.gitp4-usercache.txt"
+
+    def getUserMapFromPerforceServer(self):
+        if self.userMapFromPerforceServer:
+            return
+        self.users = {}
+
+        for output in p4CmdList("users"):
+            if not output.has_key("User"):
+                continue
+            self.users[output["User"]] = output["FullName"] + " <" + output["Email"] + ">"
+
+
+        s = ''
+        for (key, val) in self.users.items():
+            s += "%s\t%s\n" % (key, val)
+
+        open(self.getUserCacheFilename(), "wb").write(s)
+        self.userMapFromPerforceServer = True
+
+    def loadUserMapFromCache(self):
+        self.users = {}
+        self.userMapFromPerforceServer = False
+        try:
+            cache = open(self.getUserCacheFilename(), "rb")
+            lines = cache.readlines()
+            cache.close()
+            for line in lines:
+                entry = line.strip().split("\t")
+                self.users[entry[0]] = entry[1]
+        except IOError:
+            self.getUserMapFromPerforceServer()
+
+    def getLabels(self):
+        self.labels = {}
+
+        l = p4CmdList("labels %s..." % ' '.join (self.depotPaths))
+        if len(l) > 0 and not self.silent:
+            print "Finding files belonging to labels in %s" % `self.depotPath`
+
+        for output in l:
+            label = output["label"]
+            revisions = {}
+            newestChange = 0
+            if self.verbose:
+                print "Querying files for label %s" % label
+            for file in p4CmdList("files "
+                                  +  ' '.join (["%s...@%s" % (p, label)
+                                                for p in self.depotPaths])):
+                revisions[file["depotFile"]] = file["rev"]
+                change = int(file["change"])
+                if change > newestChange:
+                    newestChange = change
+
+            self.labels[newestChange] = [output, revisions]
+
+        if self.verbose:
+            print "Label changes: %s" % self.labels.keys()
+
+    def guessProjectName(self):
+        for p in self.depotPaths:
+            if p.endswith("/"):
+                p = p[:-1]
+            p = p[p.strip().rfind("/") + 1:]
+            if not p.endswith("/"):
+               p += "/"
+            return p
+
+    def getBranchMapping(self):
+        lostAndFoundBranches = set()
+
+        for info in p4CmdList("branches"):
+            details = p4Cmd("branch -o %s" % info["branch"])
+            viewIdx = 0
+            while details.has_key("View%s" % viewIdx):
+                paths = details["View%s" % viewIdx].split(" ")
+                viewIdx = viewIdx + 1
+                # require standard //depot/foo/... //depot/bar/... mapping
+                if len(paths) != 2 or not paths[0].endswith("/...") or not paths[1].endswith("/..."):
+                    continue
+                source = paths[0]
+                destination = paths[1]
+                ## HACK
+                if source.startswith(self.depotPaths[0]) and destination.startswith(self.depotPaths[0]):
+                    source = source[len(self.depotPaths[0]):-4]
+                    destination = destination[len(self.depotPaths[0]):-4]
+
+                    if destination in self.knownBranches:
+                        if not self.silent:
+                            print "p4 branch %s defines a mapping from %s to %s" % (info["branch"], source, destination)
+                            print "but there exists another mapping from %s to %s already!" % (self.knownBranches[destination], destination)
+                        continue
+
+                    self.knownBranches[destination] = source
+
+                    lostAndFoundBranches.discard(destination)
+
+                    if source not in self.knownBranches:
+                        lostAndFoundBranches.add(source)
+
+
+        for branch in lostAndFoundBranches:
+            self.knownBranches[branch] = branch
+
+    def listExistingP4GitBranches(self):
+        self.p4BranchesInGit = []
+
+        cmdline = "git rev-parse --symbolic "
+        if self.importIntoRemotes:
+            cmdline += " --remotes"
+        else:
+            cmdline += " --branches"
+
+        for line in read_pipe_lines(cmdline):
+            line = line.strip()
+
+            ## only import to p4/
+            if not line.startswith('p4/') or line == "p4/HEAD":
+                continue
+            branch = line
+
+            # strip off p4
+            branch = re.sub ("^p4/", "", line)
+
+            self.p4BranchesInGit.append(branch)
+            self.initialParents[self.refPrefix + branch] = parseRevision(line)
+
+    def createOrUpdateBranchesFromOrigin(self):
+        if not self.silent:
+            print ("Creating/updating branch(es) in %s based on origin branch(es)"
+                   % self.refPrefix)
+
+        originPrefix = "origin/p4/"
+
+        for line in read_pipe_lines("git rev-parse --symbolic --remotes"):
+            line = line.strip()
+            if (not line.startswith(originPrefix)) or line.endswith("HEAD"):
+                continue
+
+            headName = line[len(originPrefix):]
+            remoteHead = self.refPrefix + headName
+            originHead = line
+
+            original = extractSettingsGitLog(extractLogMessageFromGitCommit(originHead))
+            if (not original.has_key('depot-paths')
+                or not original.has_key('change')):
+                continue
+
+            update = False
+            if not gitBranchExists(remoteHead):
+                if self.verbose:
+                    print "creating %s" % remoteHead
+                update = True
+            else:
+                settings = extractSettingsGitLog(extractLogMessageFromGitCommit(remoteHead))
+                if settings.has_key('change') > 0:
+                    if settings['depot-paths'] == original['depot-paths']:
+                        originP4Change = int(original['change'])
+                        p4Change = int(settings['change'])
+                        if originP4Change > p4Change:
+                            print ("%s (%s) is newer than %s (%s). "
+                                   "Updating p4 branch from origin."
+                                   % (originHead, originP4Change,
+                                      remoteHead, p4Change))
+                            update = True
+                    else:
+                        print ("Ignoring: %s was imported from %s while "
+                               "%s was imported from %s"
+                               % (originHead, ','.join(original['depot-paths']),
+                                  remoteHead, ','.join(settings['depot-paths'])))
+
+            if update:
+                system("git update-ref %s %s" % (remoteHead, originHead))
+
+    def updateOptionDict(self, d):
+        option_keys = {}
+        if self.keepRepoPath:
+            option_keys['keepRepoPath'] = 1
+
+        d["options"] = ' '.join(sorted(option_keys.keys()))
+
+    def readOptions(self, d):
+        self.keepRepoPath = (d.has_key('options')
+                             and ('keepRepoPath' in d['options']))
+
+    def run(self, args):
+        self.depotPaths = []
+        self.changeRange = ""
+        self.initialParent = ""
+        self.previousDepotPaths = []
+
+        # map from branch depot path to parent branch
+        self.knownBranches = {}
+        self.initialParents = {}
+        self.hasOrigin = gitBranchExists("origin") or gitBranchExists("origin/p4") or gitBranchExists("origin/p4/master")
+        if not self.syncWithOrigin:
+            self.hasOrigin = False
+
+        if self.importIntoRemotes:
+            self.refPrefix = "refs/remotes/p4/"
+        else:
+            self.refPrefix = "refs/heads/p4/"
+
+        if self.syncWithOrigin and self.hasOrigin:
+            if not self.silent:
+                print "Syncing with origin first by calling git fetch origin"
+            system("git fetch origin")
+
+        if len(self.branch) == 0:
+            self.branch = self.refPrefix + "master"
+            if gitBranchExists("refs/heads/p4") and self.importIntoRemotes:
+                system("git update-ref %s refs/heads/p4" % self.branch)
+                system("git branch -D p4");
+            # create it /after/ importing, when master exists
+            if not gitBranchExists(self.refPrefix + "HEAD") and self.importIntoRemotes:
+                system("git symbolic-ref %sHEAD %s" % (self.refPrefix, self.branch))
+
+        # TODO: should always look at previous commits,
+        # merge with previous imports, if possible.
+        if args == []:
+            if self.hasOrigin:
+                self.createOrUpdateBranchesFromOrigin()
+            self.listExistingP4GitBranches()
+
+            if len(self.p4BranchesInGit) > 1:
+                if not self.silent:
+                    print "Importing from/into multiple branches"
+                self.detectBranches = True
+
+            if self.verbose:
+                print "branches: %s" % self.p4BranchesInGit
+
+            p4Change = 0
+            for branch in self.p4BranchesInGit:
+                logMsg =  extractLogMessageFromGitCommit(self.refPrefix + branch)
+
+                settings = extractSettingsGitLog(logMsg)
+
+                self.readOptions(settings)
+                if (settings.has_key('depot-paths')
+                    and settings.has_key ('change')):
+                    change = int(settings['change']) + 1
+                    p4Change = max(p4Change, change)
+
+                    depotPaths = sorted(settings['depot-paths'])
+                    if self.previousDepotPaths == []:
+                        self.previousDepotPaths = depotPaths
+                    else:
+                        paths = []
+                        for (prev, cur) in zip(self.previousDepotPaths, depotPaths):
+                            for i in range(0, min(len(cur), len(prev))):
+                                if cur[i] <> prev[i]:
+                                    i = i - 1
+                                    break
+
+                            paths.append (cur[:i + 1])
+
+                        self.previousDepotPaths = paths
+
+            if p4Change > 0:
+                self.depotPaths = sorted(self.previousDepotPaths)
+                self.changeRange = "@%s,#head" % p4Change
+                if not self.detectBranches:
+                    self.initialParent = parseRevision(self.branch)
+                if not self.silent and not self.detectBranches:
+                    print "Performing incremental import into %s git branch" % self.branch
+
+        if not self.branch.startswith("refs/"):
+            self.branch = "refs/heads/" + self.branch
+
+        if len(args) == 0 and self.depotPaths:
+            if not self.silent:
+                print "Depot paths: %s" % ' '.join(self.depotPaths)
+        else:
+            if self.depotPaths and self.depotPaths != args:
+                print ("previous import used depot path %s and now %s was specified. "
+                       "This doesn't work!" % (' '.join (self.depotPaths),
+                                               ' '.join (args)))
+                sys.exit(1)
+
+            self.depotPaths = sorted(args)
+
+        self.revision = ""
+        self.users = {}
+
+        newPaths = []
+        for p in self.depotPaths:
+            if p.find("@") != -1:
+                atIdx = p.index("@")
+                self.changeRange = p[atIdx:]
+                if self.changeRange == "@all":
+                    self.changeRange = ""
+                elif ',' not in self.changeRange:
+                    self.revision = self.changeRange
+                    self.changeRange = ""
+                p = p[0:atIdx]
+            elif p.find("#") != -1:
+                hashIdx = p.index("#")
+                self.revision = p[hashIdx:]
+                p = p[0:hashIdx]
+            elif self.previousDepotPaths == []:
+                self.revision = "#head"
+
+            p = re.sub ("\.\.\.$", "", p)
+            if not p.endswith("/"):
+                p += "/"
+
+            newPaths.append(p)
+
+        self.depotPaths = newPaths
+
+
+        self.loadUserMapFromCache()
+        self.labels = {}
+        if self.detectLabels:
+            self.getLabels();
+
+        if self.detectBranches:
+            ## FIXME - what's a P4 projectName ?
+            self.projectName = self.guessProjectName()
+
+            if not self.hasOrigin:
+                self.getBranchMapping();
+            if self.verbose:
+                print "p4-git branches: %s" % self.p4BranchesInGit
+                print "initial parents: %s" % self.initialParents
+            for b in self.p4BranchesInGit:
+                if b != "master":
+
+                    ## FIXME
+                    b = b[len(self.projectName):]
+                self.createdBranches.add(b)
+
+        self.tz = "%+03d%02d" % (- time.timezone / 3600, ((- time.timezone % 3600) / 60))
+
+        importProcess = subprocess.Popen(["git", "fast-import"],
+                                         stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+                                         stderr=subprocess.PIPE);
+        self.gitOutput = importProcess.stdout
+        self.gitStream = importProcess.stdin
+        self.gitError = importProcess.stderr
+
+        if self.revision:
+            print "Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), self.revision, self.branch)
+
+            details = { "user" : "git perforce import user", "time" : int(time.time()) }
+            details["desc"] = ("Initial import of %s from the state at revision %s"
+                               % (' '.join(self.depotPaths), self.revision))
+            details["change"] = self.revision
+            newestRevision = 0
+
+            fileCnt = 0
+            for info in p4CmdList("files "
+                                  +  ' '.join(["%s...%s"
+                                               % (p, self.revision)
+                                               for p in self.depotPaths])):
+
+                if info['code'] == 'error':
+                    sys.stderr.write("p4 returned an error: %s\n"
+                                     % info['data'])
+                    sys.exit(1)
+
+
+                change = int(info["change"])
+                if change > newestRevision:
+                    newestRevision = change
+
+                if info["action"] == "delete":
+                    # don't increase the file cnt, otherwise details["depotFile123"] will have gaps!
+                    #fileCnt = fileCnt + 1
+                    continue
+
+                for prop in ["depotFile", "rev", "action", "type" ]:
+                    details["%s%s" % (prop, fileCnt)] = info[prop]
+
+                fileCnt = fileCnt + 1
+
+            details["change"] = newestRevision
+            self.updateOptionDict(details)
+            try:
+                self.commit(details, self.extractFilesFromCommit(details), self.branch, self.depotPaths)
+            except IOError:
+                print "IO error with git fast-import. Is your git version recent enough?"
+                print self.gitError.read()
+
+        else:
+            changes = []
+
+            if len(self.changesFile) > 0:
+                output = open(self.changesFile).readlines()
+                changeSet = Set()
+                for line in output:
+                    changeSet.add(int(line))
+
+                for change in changeSet:
+                    changes.append(change)
+
+                changes.sort()
+            else:
+                if self.verbose:
+                    print "Getting p4 changes for %s...%s" % (', '.join(self.depotPaths),
+                                                              self.changeRange)
+                assert self.depotPaths
+                output = read_pipe_lines("p4 changes " + ' '.join (["%s...%s" % (p, self.changeRange)
+                                                                    for p in self.depotPaths]))
+
+                for line in output:
+                    changeNum = line.split(" ")[1]
+                    changes.append(changeNum)
+
+                changes.reverse()
+
+                if len(self.maxChanges) > 0:
+                    changes = changes[0:min(int(self.maxChanges), len(changes))]
+
+            if len(changes) == 0:
+                if not self.silent:
+                    print "No changes to import!"
+                return True
+
+            if not self.silent and not self.detectBranches:
+                print "Import destination: %s" % self.branch
+
+            self.updatedBranches = set()
+
+            cnt = 1
+            for change in changes:
+                description = p4Cmd("describe %s" % change)
+                self.updateOptionDict(description)
+
+                if not self.silent:
+                    sys.stdout.write("\rImporting revision %s (%s%%)" % (change, cnt * 100 / len(changes)))
+                    sys.stdout.flush()
+                cnt = cnt + 1
+
+                try:
+                    if self.detectBranches:
+                        branches = self.splitFilesIntoBranches(description)
+                        for branch in branches.keys():
+                            ## HACK  --hwn
+                            branchPrefix = self.depotPaths[0] + branch + "/"
+
+                            parent = ""
+
+                            filesForCommit = branches[branch]
+
+                            if self.verbose:
+                                print "branch is %s" % branch
+
+                            self.updatedBranches.add(branch)
+
+                            if branch not in self.createdBranches:
+                                self.createdBranches.add(branch)
+                                parent = self.knownBranches[branch]
+                                if parent == branch:
+                                    parent = ""
+                                elif self.verbose:
+                                    print "parent determined through known branches: %s" % parent
+
+                            # main branch? use master
+                            if branch == "main":
+                                branch = "master"
+                            else:
+
+                                ## FIXME
+                                branch = self.projectName + branch
+
+                            if parent == "main":
+                                parent = "master"
+                            elif len(parent) > 0:
+                                ## FIXME
+                                parent = self.projectName + parent
+
+                            branch = self.refPrefix + branch
+                            if len(parent) > 0:
+                                parent = self.refPrefix + parent
+
+                            if self.verbose:
+                                print "looking for initial parent for %s; current parent is %s" % (branch, parent)
+
+                            if len(parent) == 0 and branch in self.initialParents:
+                                parent = self.initialParents[branch]
+                                del self.initialParents[branch]
+
+                            self.commit(description, filesForCommit, branch, [branchPrefix], parent)
+                    else:
+                        files = self.extractFilesFromCommit(description)
+                        self.commit(description, files, self.branch, self.depotPaths,
+                                    self.initialParent)
+                        self.initialParent = ""
+                except IOError:
+                    print self.gitError.read()
+                    sys.exit(1)
+
+            if not self.silent:
+                print ""
+                if len(self.updatedBranches) > 0:
+                    sys.stdout.write("Updated branches: ")
+                    for b in self.updatedBranches:
+                        sys.stdout.write("%s " % b)
+                    sys.stdout.write("\n")
+
+
+        self.gitStream.close()
+        if importProcess.wait() != 0:
+            die("fast-import failed: %s" % self.gitError.read())
+        self.gitOutput.close()
+        self.gitError.close()
+
+        return True
+
+class P4Rebase(Command):
+    def __init__(self):
+        Command.__init__(self)
+        self.options = [ ]
+        self.description = ("Fetches the latest revision from perforce and "
+                            + "rebases the current work (branch) against it")
+        self.verbose = False
+
+    def run(self, args):
+        sync = P4Sync()
+        sync.run([])
+
+        [upstream, settings] = findUpstreamBranchPoint()
+        if len(upstream) == 0:
+            die("Cannot find upstream branchpoint for rebase")
+
+        # the branchpoint may be p4/foo~3, so strip off the parent
+        upstream = re.sub("~[0-9]+$", "", upstream)
+
+        print "Rebasing the current branch onto %s" % upstream
+        oldHead = read_pipe("git rev-parse HEAD").strip()
+        system("git rebase %s" % upstream)
+        system("git diff-tree --stat --summary -M %s HEAD" % oldHead)
+        return True
+
+class P4Clone(P4Sync):
+    def __init__(self):
+        P4Sync.__init__(self)
+        self.description = "Creates a new git repository and imports from Perforce into it"
+        self.usage = "usage: %prog [options] //depot/path[@revRange]"
+        self.options.append(
+            optparse.make_option("--destination", dest="cloneDestination",
+                                 action='store', default=None,
+                                 help="where to leave result of the clone"))
+        self.cloneDestination = None
+        self.needsGit = False
+
+    def defaultDestination(self, args):
+        ## TODO: use common prefix of args?
+        depotPath = args[0]
+        depotDir = re.sub("(@[^@]*)$", "", depotPath)
+        depotDir = re.sub("(#[^#]*)$", "", depotDir)
+        depotDir = re.sub(r"\.\.\.$,", "", depotDir)
+        depotDir = re.sub(r"/$", "", depotDir)
+        return os.path.split(depotDir)[1]
+
+    def run(self, args):
+        if len(args) < 1:
+            return False
+
+        if self.keepRepoPath and not self.cloneDestination:
+            sys.stderr.write("Must specify destination for --keep-path\n")
+            sys.exit(1)
+
+        depotPaths = args
+
+        if not self.cloneDestination and len(depotPaths) > 1:
+            self.cloneDestination = depotPaths[-1]
+            depotPaths = depotPaths[:-1]
+
+        for p in depotPaths:
+            if not p.startswith("//"):
+                return False
+
+        if not self.cloneDestination:
+            self.cloneDestination = self.defaultDestination(args)
+
+        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)
+        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")
+                system("git checkout -f")
+            else:
+                print "Could not detect main branch. No checkout/master branch created."
+
+        return True
+
+class P4Branches(Command):
+    def __init__(self):
+        Command.__init__(self)
+        self.options = [ ]
+        self.description = ("Shows the git branches that hold imports and their "
+                            + "corresponding perforce depot paths")
+        self.verbose = False
+
+    def run(self, args):
+        cmdline = "git rev-parse --symbolic "
+        cmdline += " --remotes"
+
+        for line in read_pipe_lines(cmdline):
+            line = line.strip()
+
+            if not line.startswith('p4/') or line == "p4/HEAD":
+                continue
+            branch = line
+
+            log = extractLogMessageFromGitCommit("refs/remotes/%s" % branch)
+            settings = extractSettingsGitLog(log)
+
+            print "%s <= %s (%s)" % (branch, ",".join(settings["depot-paths"]), settings["change"])
+        return True
+
+class HelpFormatter(optparse.IndentedHelpFormatter):
+    def __init__(self):
+        optparse.IndentedHelpFormatter.__init__(self)
+
+    def format_description(self, description):
+        if description:
+            return description + "\n"
+        else:
+            return ""
+
+def printUsage(commands):
+    print "usage: %s <command> [options]" % sys.argv[0]
+    print ""
+    print "valid commands: %s" % ", ".join(commands)
+    print ""
+    print "Try %s <command> --help for command specific help." % sys.argv[0]
+    print ""
+
+commands = {
+    "debug" : P4Debug,
+    "submit" : P4Submit,
+    "sync" : P4Sync,
+    "rebase" : P4Rebase,
+    "clone" : P4Clone,
+    "rollback" : P4RollBack,
+    "branches" : P4Branches
+}
+
+
+def main():
+    if len(sys.argv[1:]) == 0:
+        printUsage(commands.keys())
+        sys.exit(2)
+
+    cmd = ""
+    cmdName = sys.argv[1]
+    try:
+        klass = commands[cmdName]
+        cmd = klass()
+    except KeyError:
+        print "unknown command %s" % cmdName
+        print ""
+        printUsage(commands.keys())
+        sys.exit(2)
+
+    options = cmd.options
+    cmd.gitdir = os.environ.get("GIT_DIR", None)
+
+    args = sys.argv[2:]
+
+    if len(options) > 0:
+        options.append(optparse.make_option("--git-dir", dest="gitdir"))
+
+        parser = optparse.OptionParser(cmd.usage.replace("%prog", "%prog " + cmdName),
+                                       options,
+                                       description = cmd.description,
+                                       formatter = HelpFormatter())
+
+        (cmd, args) = parser.parse_args(sys.argv[2:], cmd);
+    global verbose
+    verbose = cmd.verbose
+    if cmd.needsGit:
+        if cmd.gitdir == None:
+            cmd.gitdir = os.path.abspath(".git")
+            if not isValidGitDir(cmd.gitdir):
+                cmd.gitdir = read_pipe("git rev-parse --git-dir").strip()
+                if os.path.exists(cmd.gitdir):
+                    cdup = read_pipe("git rev-parse --show-cdup").strip()
+                    if len(cdup) > 0:
+                        os.chdir(cdup);
+
+        if not isValidGitDir(cmd.gitdir):
+            if isValidGitDir(cmd.gitdir + "/.git"):
+                cmd.gitdir += "/.git"
+            else:
+                die("fatal: cannot locate git repository at %s" % cmd.gitdir)
+
+        os.environ["GIT_DIR"] = cmd.gitdir
+
+    if not cmd.run(args):
+        parser.print_help()
+
+
+if __name__ == '__main__':
+    main()
diff --git a/contrib/fast-import/git-p4.bat b/contrib/fast-import/git-p4.bat
new file mode 100644 (file)
index 0000000..9f97e88
--- /dev/null
@@ -0,0 +1 @@
+@python "%~d0%~p0git-p4" %*
diff --git a/contrib/fast-import/git-p4.txt b/contrib/fast-import/git-p4.txt
new file mode 100644 (file)
index 0000000..b16a838
--- /dev/null
@@ -0,0 +1,159 @@
+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".
+
+Importing
+=========
+
+You can simply start with
+
+  git-p4 clone //depot/path/project
+
+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:
+
+  git-p4 clone //depot/project/main@all myproject
+
+
+
+If you want more control you can also use the git-p4 sync command directly:
+
+  mkdir repo-git
+  cd repo-git
+  git init
+  git-p4 sync //path/in/your/perforce/depot
+
+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.
+
+If you want to import the entire history of a given depot path just use
+
+  git-p4 sync //path/in/depot@all
+
+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
+
+  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.
+
+
+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 git-p4.syncFromOrigin false
+
+Updating
+========
+
+A common working pattern is to fetch the latest changes from the Perforce depot
+and merge them with local uncommitted changes. The recommended way is to use
+git's rebase mechanism to preserve linear history. git-p4 provides a convenient
+
+  git-p4 rebase
+
+command that calls git-p4 sync followed by git rebase to rebase the current
+working branch.
+
+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
+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
+
+    git-p4 submit
+
+in your git repository. If you want to submit changes in a specific branch that
+is not your current git branch you can also pass that as an argument:
+
+    git-p4 submit mytopicbranch
+
+You can override the reference branch with the --origin=mysourcebranch option.
+
+If a submit fails you may have to "p4 resolve" and submit manually. You can
+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
+=======
+
+# Clone a repository
+  git-p4 clone //depot/path/project
+# Enter the newly cloned directory
+  cd project
+# Do some work...
+  vi foo.h
+# ... and commit locally to gi
+  git commit foo.h
+# In the meantime somebody submitted changes to the Perforce depot. Rebase your latest
+# changes against the latest changes in Perforce:
+  git-p4 rebase
+# Submit your locally committed changes back to Perforce
+  git-p4 submit
+# ... and synchronize with Perforce
+  git-p4 rebase
+
+
+Implementation Details...
+=========================
+
+* Changesets from Perforce are imported using git fast-import.
+* The import does not require anything from the Perforce client view as it just uses
+  "p4 print //depot/path/file#revision" to get the actual file contents.
+* Every imported changeset has a special [git-p4...] line at the
+  end of the log message that gives information about the corresponding
+  Perforce change number and is also used by git-p4 itself to find out
+  where to continue importing when doing incremental imports.
+  Basically when syncing it extracts the perforce change number of the
+  latest commit in the "p4" branch and uses "p4 changes //depot/path/...@changenum,#head"
+  to find out which changes need to be imported.
+* git-p4 submit uses "git rev-list" to pick the commits between the "p4" branch
+  and the current branch.
+  The commits themselves are applied using git diff/format-patch ... | git apply
+
index 2d80e2bad2e6f322d7ff7e9f03a6897a11f74231..593176662050f0c84897759ab7d80f31aabfae53 100755 (executable)
@@ -259,10 +259,13 @@ class CellRendererGraph(gtk.GenericCellRenderer):
                                self.set_colour(ctx, colour, 0.0, 0.5)
                        ctx.show_text(name)
 
-class Commit:
+class Commit(object):
        """ This represent a commit object obtained after parsing the git-rev-list
        output """
 
+       __slots__ = ['children_sha1', 'message', 'author', 'date', 'committer',
+                                'commit_date', 'commit_sha1', 'parent_sha1']
+
        children_sha1 = {}
 
        def __init__(self, commit_lines):
@@ -339,7 +342,7 @@ class Commit:
                fp.close()
                return diff
 
-class AnnotateWindow:
+class AnnotateWindow(object):
        """Annotate window.
        This object represents and manages a single window containing the
        annotate information of the file
@@ -349,6 +352,7 @@ class AnnotateWindow:
                self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
                self.window.set_border_width(0)
                self.window.set_title("Git repository browser annotation window")
+               self.prev_read = ""
 
                # Use two thirds of the screen by default
                screen = self.window.get_screen()
@@ -398,7 +402,10 @@ class AnnotateWindow:
        def data_ready(self, source, condition):
                while (1):
                        try :
-                               buffer = source.read(8192)
+                               # A simple readline doesn't work
+                               # a readline bug ??
+                               buffer = source.read(100)
+
                        except:
                                # resource temporary not available
                                return True
@@ -408,6 +415,19 @@ class AnnotateWindow:
                                source.close()
                                return False
 
+                       if (self.prev_read != ""):
+                               buffer = self.prev_read + buffer
+                               self.prev_read = ""
+
+                       if (buffer[len(buffer) -1] != '\n'):
+                               try:
+                                       newline_index = buffer.rindex("\n")
+                               except ValueError:
+                                       newline_index = 0
+
+                               self.prev_read = buffer[newline_index:(len(buffer))]
+                               buffer = buffer[0:newline_index]
+
                        for buff in buffer.split("\n"):
                                annotate_line = re.compile('^([0-9a-f]{40}) (.+) (.+) (.+)$')
                                m = annotate_line.match(buff)
@@ -513,13 +533,13 @@ class AnnotateWindow:
 
                self.add_file_data(filename, commit_sha1, line_num)
 
-               fp = os.popen("git blame --incremental -- " + filename + " " + commit_sha1)
+               fp = os.popen("git blame --incremental -C -C -- " + filename + " " + commit_sha1)
                flags = fcntl.fcntl(fp.fileno(), fcntl.F_GETFL)
                fcntl.fcntl(fp.fileno(), fcntl.F_SETFL, flags | os.O_NONBLOCK)
                self.io_watch_tag = gobject.io_add_watch(fp, gobject.IO_IN, self.data_ready)
 
 
-class DiffWindow:
+class DiffWindow(object):
        """Diff window.
        This object represents and manages a single window containing the
        differences between two revisions on a branch.
@@ -674,7 +694,7 @@ class DiffWindow:
                        fp.close()
                dialog.destroy()
 
-class GitView:
+class GitView(object):
        """ This is the main class
        """
        version = "0.9"
@@ -1277,5 +1297,3 @@ if __name__ == "__main__":
 
        view = GitView( without_diff != 1)
        view.run(sys.argv[without_diff:])
-
-
index d1bef9125bca0997e0e714b3f89e9c2df307d598..c589a39a0c81818150575c74866a57619e1adf2a 100644 (file)
@@ -199,7 +199,7 @@ generate_email_footer()
 
 
        hooks/post-receive
-       -- 
+       --
        $projectdesc
        EOF
 }
index dc09eae972711496aa390cb99b3017a936ce1afc..5838b3ab05fb1d9a1cf6a565513b3c7409adc73a 100644 (file)
@@ -26,10 +26,8 @@ if [ -d "$GIT_DIR"/remotes ]; then
                                mv "$GIT_DIR"/remotes "$GIT_DIR"/remotes.old
                        fi ;;
                *)
-                       echo "git-config $key "$value" $regex"
-                       git-config $key "$value" $regex || error=1 ;;
+                       echo "git config $key "$value" $regex"
+                       git config $key "$value" $regex || error=1 ;;
                esac
        done
 fi
-
-
index 9877b98508497c9377876bd08e8f130660b9ba05..3ff6bd166ab7db5612a419ffcdc93b9b3d7eb2f8 100755 (executable)
@@ -20,17 +20,24 @@ new_workdir=$2
 branch=$3
 
 # want to make sure that what is pointed to has a .git directory ...
-test -d "$orig_git/.git" || die "\"$orig_git\" is not a git repository!"
+git_dir=$(cd "$orig_git" 2>/dev/null &&
+  git rev-parse --git-dir 2>/dev/null) ||
+  die "\"$orig_git\" is not a git repository!"
+
+if test "$git_dir" = ".git"
+then
+       git_dir="$orig_git/.git"
+fi
 
 # don't link to a workdir
-if test -L "$orig_git/.git/config"
+if test -L "$git_dir/config"
 then
        die "\"$orig_git\" is a working directory only, please specify" \
                "a complete repository."
 fi
 
 # make sure the the links use full paths
-orig_git=$(cd "$orig_git"; pwd)
+git_dir=$(cd "$git_dir"; pwd)
 
 # create the workdir
 mkdir -p "$new_workdir/.git" || die "unable to create \"$new_workdir\"!"
@@ -45,13 +52,13 @@ do
                mkdir -p "$(dirname "$new_workdir/.git/$x")"
                ;;
        esac
-       ln -s "$orig_git/.git/$x" "$new_workdir/.git/$x"
+       ln -s "$git_dir/$x" "$new_workdir/.git/$x"
 done
 
 # now setup the workdir
 cd "$new_workdir"
 # copy the HEAD from the original repository as a default branch
-cp "$orig_git/.git/HEAD" .git/HEAD
+cp "$git_dir/HEAD" .git/HEAD
 # checkout the branch (either the same as HEAD from the original repository, or
 # the one that was asked for)
 git checkout -f $branch
index cefbcebdcaa0a085745c81b2ed1103e9575cb635..90e7900e6d7aff2fadf9ba04f8d982733493411c 100644 (file)
@@ -194,7 +194,7 @@ static unsigned long parse_oldstyle_date(const char *buf)
                fmt++;
        } while (*buf && *fmt);
        printf("left: %s\n", buf);
-       return mktime(&tm);                             
+       return mktime(&tm);
 }
 
 static int convert_date_line(char *dst, void **buf, unsigned long *sp)
diff --git a/copy.c b/copy.c
index d340bb253ec35af379c29e71f384e15d6822fb9a..c225d1b0ff0a67e637f7200ab5c2a917b550af4f 100644 (file)
--- a/copy.c
+++ b/copy.c
@@ -34,4 +34,3 @@ int copy_fd(int ifd, int ofd)
        close(ifd);
        return 0;
 }
-
index 7c806ada48d0fd58c091f9415fc8bb2f61bdd2e6..9ab997120d04c5be0aa9d3ff3ba090ba12b7bec8 100644 (file)
@@ -29,18 +29,20 @@ static void sha1flush(struct sha1file *f, unsigned int count)
        }
 }
 
-int sha1close(struct sha1file *f, unsigned char *result, int update)
+int sha1close(struct sha1file *f, unsigned char *result, int final)
 {
        unsigned offset = f->offset;
        if (offset) {
                SHA1_Update(&f->ctx, f->buffer, offset);
                sha1flush(f, offset);
+               f->offset = 0;
        }
+       if (!final)
+               return 0;       /* only want to flush (no checksum write, no close) */
        SHA1_Final(f->buffer, &f->ctx);
        if (result)
                hashcpy(result, f->buffer);
-       if (update)
-               sha1flush(f, 20);
+       sha1flush(f, 20);
        if (close(f->fd))
                die("%s: sha1 file error on close (%s)", f->name, strerror(errno));
        free(f);
@@ -71,33 +73,6 @@ int sha1write(struct sha1file *f, void *buf, unsigned int count)
        return 0;
 }
 
-struct sha1file *sha1create(const char *fmt, ...)
-{
-       struct sha1file *f;
-       unsigned len;
-       va_list arg;
-       int fd;
-
-       f = xmalloc(sizeof(*f));
-
-       va_start(arg, fmt);
-       len = vsnprintf(f->name, sizeof(f->name), fmt, arg);
-       va_end(arg);
-       if (len >= PATH_MAX)
-               die("you wascally wabbit, you");
-       f->namelen = len;
-
-       fd = open(f->name, O_CREAT | O_EXCL | O_WRONLY, 0666);
-       if (fd < 0)
-               die("unable to open %s (%s)", f->name, strerror(errno));
-       f->fd = fd;
-       f->error = 0;
-       f->offset = 0;
-       f->do_crc = 0;
-       SHA1_Init(&f->ctx);
-       return f;
-}
-
 struct sha1file *sha1fd(int fd, const char *name)
 {
        struct sha1file *f;
@@ -119,34 +94,6 @@ struct sha1file *sha1fd(int fd, const char *name)
        return f;
 }
 
-int sha1write_compressed(struct sha1file *f, void *in, unsigned int size)
-{
-       z_stream stream;
-       unsigned long maxsize;
-       void *out;
-
-       memset(&stream, 0, sizeof(stream));
-       deflateInit(&stream, zlib_compression_level);
-       maxsize = deflateBound(&stream, size);
-       out = xmalloc(maxsize);
-
-       /* Compress it */
-       stream.next_in = in;
-       stream.avail_in = size;
-
-       stream.next_out = out;
-       stream.avail_out = maxsize;
-
-       while (deflate(&stream, Z_FINISH) == Z_OK)
-               /* nothing */;
-       deflateEnd(&stream);
-
-       size = stream.total_out;
-       sha1write(f, out, size);
-       free(out);
-       return size;
-}
-
 void crc32_begin(struct sha1file *f)
 {
        f->crc32 = crc32(0, Z_NULL, 0);
index 7e1339189dcdc6e271fad5df7ad427954642ae9e..c3c792f1b56026b6a4d9d10b6ba63947c7f383cf 100644 (file)
@@ -13,10 +13,8 @@ struct sha1file {
 };
 
 extern struct sha1file *sha1fd(int fd, const char *name);
-extern struct sha1file *sha1create(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 extern int sha1close(struct sha1file *, unsigned char *, int);
 extern int sha1write(struct sha1file *, void *, unsigned int);
-extern int sha1write_compressed(struct sha1file *, void *, unsigned int);
 extern void crc32_begin(struct sha1file *);
 extern uint32_t crc32_end(struct sha1file *);
 
diff --git a/ctype.c b/ctype.c
index 56bdffa636e6b4465ab8451de0351ff394182885..ee06eb7f48f1d3e818b3037369b4e056fe7e5be7 100644 (file)
--- a/ctype.c
+++ b/ctype.c
@@ -20,4 +20,3 @@ unsigned char sane_ctype[256] = {
        AA, AA, AA, AA, AA, AA, AA, AA, AA, AA, AA,  0,  0,  0,  0,  0,         /* 112-15 */
        /* Nothing in the 128.. range */
 };
-
index 674e30dca3d05cabc5a72e7bb0a40e64eaa4b2eb..a3f2ac1d81a21883c5ec7e9f1270c9109c675f12 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -133,7 +133,7 @@ static int avoid_alias(char *p)
 {
        int sl, ndot;
 
-       /* 
+       /*
         * This resurrects the belts and suspenders paranoia check by HPA
         * done in <435560F7.4080006@zytor.com> thread, now enter_repo()
         * does not do getcwd() based path canonicalizations.
@@ -247,7 +247,7 @@ static char *path_ok(struct interp *itable)
                int pathlen = strlen(path);
 
                /* The validation is done on the paths after enter_repo
-                * appends optional {.git,.git/.git} and friends, but 
+                * appends optional {.git,.git/.git} and friends, but
                 * it does not use getcwd().  So if your /pub is
                 * a symlink to /mnt/pub, you can whitelist /pub and
                 * do not have to say /mnt/pub.
@@ -439,7 +439,7 @@ static void parse_extra_args(struct interp *table, char *extra_args, int buflen)
        }
 }
 
-void fill_in_extra_table_entries(struct interp *itable)
+static void fill_in_extra_table_entries(struct interp *itable)
 {
        char *hp;
 
diff --git a/date.c b/date.c
index 4690371e5559f72b7755b3cc92ae85843098d285..316841e8ad3705559fddb0ca4aff969fdf91b011 100644 (file)
--- a/date.c
+++ b/date.c
@@ -403,7 +403,7 @@ static int match_multi_number(unsigned long num, char c, const char *date, char
 }
 
 /*
- * We've seen a digit. Time? Year? Date? 
+ * We've seen a digit. Time? Year? Date?
  */
 static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt)
 {
@@ -495,7 +495,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
        } else if (num > 0 && num < 13) {
                tm->tm_mon = num-1;
        }
-               
+
        return n;
 }
 
@@ -569,13 +569,13 @@ int parse_date(const char *date, char *result, int maxlen)
                if (!match) {
                        /* BAD CRAP */
                        match = 1;
-               }       
+               }
 
                date += match;
        }
 
        /* mktime uses local timezone */
-       then = my_mktime(&tm); 
+       then = my_mktime(&tm);
        if (offset == -1)
                offset = (then - mktime(&tm)) / 60;
 
@@ -691,7 +691,7 @@ static const struct typelen {
        { "days", 24*60*60 },
        { "weeks", 7*24*60*60 },
        { NULL }
-};     
+};
 
 static const char *approxidate_alpha(const char *date, struct tm *tm, int *num)
 {
index 9f998d0a73e0127d3a68a7caecb3727569149871..faf96e47130e3a2af26f55fc1173874f078617fc 100644 (file)
@@ -1,21 +1,14 @@
 /*
  * diff-delta.c: generate a delta between two buffers
  *
- *  Many parts of this file have been lifted from LibXDiff version 0.10.
- *  http://www.xmailserver.org/xdiff-lib.html
+ * This code was greatly inspired by parts of LibXDiff from Davide Libenzi
+ * http://www.xmailserver.org/xdiff-lib.html
  *
- *  LibXDiff was written by Davide Libenzi <davidel@xmailserver.org>
- *  Copyright (C) 2003 Davide Libenzi
+ * Rewritten for GIT by Nicolas Pitre <nico@cam.org>, (C) 2005-2007
  *
- *  Many mods for GIT usage by Nicolas Pitre <nico@cam.org>, (C) 2005.
- *
- *  This file is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  Use of this within git automatically means that the LGPL
- *  licensing gets turned into GPLv2 within this project.
+ * This code is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
  */
 
 #include "git-compat-util.h"
@@ -246,7 +239,7 @@ create_delta(const struct delta_index *index,
             const void *trg_buf, unsigned long trg_size,
             unsigned long *delta_size, unsigned long max_size)
 {
-       unsigned int i, outpos, outsize, val;
+       unsigned int i, outpos, outsize, moff, msize, val;
        int inscnt;
        const unsigned char *ref_data, *ref_top, *data, *top;
        unsigned char *out;
@@ -291,30 +284,33 @@ create_delta(const struct delta_index *index,
        }
        inscnt = i;
 
+       moff = 0;
+       msize = 0;
        while (data < top) {
-               unsigned int moff = 0, msize = 0;
-               struct index_entry *entry;
-               val ^= U[data[-RABIN_WINDOW]];
-               val = ((val << 8) | *data) ^ T[val >> RABIN_SHIFT];
-               i = val & index->hash_mask;
-               for (entry = index->hash[i]; entry; entry = entry->next) {
-                       const unsigned char *ref = entry->ptr;
-                       const unsigned char *src = data;
-                       unsigned int ref_size = ref_top - ref;
-                       if (entry->val != val)
-                               continue;
-                       if (ref_size > top - src)
-                               ref_size = top - src;
-                       if (ref_size > 0x10000)
-                               ref_size = 0x10000;
-                       if (ref_size <= msize)
-                               break;
-                       while (ref_size-- && *src++ == *ref)
-                               ref++;
-                       if (msize < ref - entry->ptr) {
-                               /* this is our best match so far */
-                               msize = ref - entry->ptr;
-                               moff = entry->ptr - ref_data;
+               if (msize < 4096) {
+                       struct index_entry *entry;
+                       val ^= U[data[-RABIN_WINDOW]];
+                       val = ((val << 8) | *data) ^ T[val >> RABIN_SHIFT];
+                       i = val & index->hash_mask;
+                       for (entry = index->hash[i]; entry; entry = entry->next) {
+                               const unsigned char *ref = entry->ptr;
+                               const unsigned char *src = data;
+                               unsigned int ref_size = ref_top - ref;
+                               if (entry->val != val)
+                                       continue;
+                               if (ref_size > top - src)
+                                       ref_size = top - src;
+                               if (ref_size <= msize)
+                                       break;
+                               while (ref_size-- && *src++ == *ref)
+                                       ref++;
+                               if (msize < ref - entry->ptr) {
+                                       /* this is our best match so far */
+                                       msize = ref - entry->ptr;
+                                       moff = entry->ptr - ref_data;
+                                       if (msize >= 4096) /* good enough */
+                                               break;
+                               }
                        }
                }
 
@@ -327,27 +323,13 @@ create_delta(const struct delta_index *index,
                                out[outpos - inscnt - 1] = inscnt;
                                inscnt = 0;
                        }
+                       msize = 0;
                } else {
+                       unsigned int left;
                        unsigned char *op;
 
-                       if (msize >= RABIN_WINDOW) {
-                               const unsigned char *sk;
-                               sk = data + msize - RABIN_WINDOW;
-                               val = 0;
-                               for (i = 0; i < RABIN_WINDOW; i++)
-                                       val = ((val << 8) | *sk++) ^ T[val >> RABIN_SHIFT];
-                       } else {
-                               const unsigned char *sk = data + 1;
-                               for (i = 1; i < msize; i++) {
-                                       val ^= U[sk[-RABIN_WINDOW]];
-                                       val = ((val << 8) | *sk++) ^ T[val >> RABIN_SHIFT];
-                               }
-                       }
-
                        if (inscnt) {
                                while (moff && ref_data[moff-1] == data[-1]) {
-                                       if (msize == 0x10000)
-                                               break;
                                        /* we can match one byte back */
                                        msize++;
                                        moff--;
@@ -363,23 +345,40 @@ create_delta(const struct delta_index *index,
                                inscnt = 0;
                        }
 
-                       data += msize;
+                       /* A copy op is currently limited to 64KB (pack v2) */
+                       left = (msize < 0x10000) ? 0 : (msize - 0x10000);
+                       msize -= left;
+
                        op = out + outpos++;
                        i = 0x80;
 
-                       if (moff & 0xff) { out[outpos++] = moff; i |= 0x01; }
-                       moff >>= 8;
-                       if (moff & 0xff) { out[outpos++] = moff; i |= 0x02; }
-                       moff >>= 8;
-                       if (moff & 0xff) { out[outpos++] = moff; i |= 0x04; }
-                       moff >>= 8;
-                       if (moff & 0xff) { out[outpos++] = moff; i |= 0x08; }
+                       if (moff & 0x000000ff)
+                               out[outpos++] = moff >> 0,  i |= 0x01;
+                       if (moff & 0x0000ff00)
+                               out[outpos++] = moff >> 8,  i |= 0x02;
+                       if (moff & 0x00ff0000)
+                               out[outpos++] = moff >> 16, i |= 0x04;
+                       if (moff & 0xff000000)
+                               out[outpos++] = moff >> 24, i |= 0x08;
 
-                       if (msize & 0xff) { out[outpos++] = msize; i |= 0x10; }
-                       msize >>= 8;
-                       if (msize & 0xff) { out[outpos++] = msize; i |= 0x20; }
+                       if (msize & 0x00ff)
+                               out[outpos++] = msize >> 0, i |= 0x10;
+                       if (msize & 0xff00)
+                               out[outpos++] = msize >> 8, i |= 0x20;
 
                        *op = i;
+
+                       data += msize;
+                       moff += msize;
+                       msize = left;
+
+                       if (msize < 4096) {
+                               int j;
+                               val = 0;
+                               for (j = -RABIN_WINDOW; j < 0; j++)
+                                       val = ((val << 8) | data[j])
+                                             ^ T[val >> RABIN_SHIFT];
+                       }
                }
 
                if (outpos >= outsize - MAX_OP_SIZE) {
@@ -389,7 +388,7 @@ create_delta(const struct delta_index *index,
                                outsize = max_size + MAX_OP_SIZE + 1;
                        if (max_size && outpos > max_size)
                                break;
-                       out = xrealloc(out, outsize);
+                       out = realloc(out, outsize);
                        if (!out) {
                                free(tmp);
                                return NULL;
index 07f4e8106a51384d2236b182438472884c300da6..92c0e39ad6f21e0511ee84052e2b762d6e447f61 100644 (file)
@@ -24,7 +24,7 @@ static int read_directory(const char *path, struct path_list *list)
 
        while ((e = readdir(dir)))
                if (strcmp(".", e->d_name) && strcmp("..", e->d_name))
-                       path_list_insert(xstrdup(e->d_name), list);
+                       path_list_insert(e->d_name, list);
 
        closedir(dir);
        return 0;
@@ -664,7 +664,7 @@ int run_diff_index(struct rev_info *revs, int cached)
        const char *tree_name;
        int match_missing = 0;
 
-       /* 
+       /*
         * Backward compatibility wart - "diff-index -m" does
         * not mean "do not ignore merges", but totally different.
         */
diff --git a/diff.c b/diff.c
index da992dd4851dd67ab9a307c1b08ebed442e406cb..cd6b0c4e0bb5efad828fa29e92e8729418401080 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -56,6 +56,14 @@ static struct ll_diff_driver {
        char *cmd;
 } *user_diff, **user_diff_tail;
 
+static void read_config_if_needed(void)
+{
+       if (!user_diff_tail) {
+               user_diff_tail = &user_diff;
+               git_config(git_diff_ui_config);
+       }
+}
+
 /*
  * Currently there is only "diff.<drivername>.command" variable;
  * because there are "diff.color.<slot>" variables, we are parsing
@@ -93,6 +101,45 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val
        return 0;
 }
 
+/*
+ * 'diff.<what>.funcname' attribute can be specified in the configuration
+ * to define a customized regexp to find the beginning of a function to
+ * be used for hunk header lines of "diff -p" style output.
+ */
+static struct funcname_pattern {
+       char *name;
+       char *pattern;
+       struct funcname_pattern *next;
+} *funcname_pattern_list;
+
+static int parse_funcname_pattern(const char *var, const char *ep, const char *value)
+{
+       const char *name;
+       int namelen;
+       struct funcname_pattern *pp;
+
+       name = var + 5; /* "diff." */
+       namelen = ep - name;
+
+       for (pp = funcname_pattern_list; pp; pp = pp->next)
+               if (!strncmp(pp->name, name, namelen) && !pp->name[namelen])
+                       break;
+       if (!pp) {
+               char *namebuf;
+               pp = xcalloc(1, sizeof(*pp));
+               namebuf = xmalloc(namelen + 1);
+               memcpy(namebuf, name, namelen);
+               namebuf[namelen] = 0;
+               pp->name = namebuf;
+               pp->next = funcname_pattern_list;
+               funcname_pattern_list = pp;
+       }
+       if (pp->pattern)
+               free(pp->pattern);
+       pp->pattern = xstrdup(value);
+       return 0;
+}
+
 /*
  * These are to give UI layer defaults.
  * The core-level commands such as git-diff-files should
@@ -122,8 +169,12 @@ int git_diff_ui_config(const char *var, const char *value)
        if (!prefixcmp(var, "diff.")) {
                const char *ep = strrchr(var, '.');
 
-               if (ep != var + 4 && !strcmp(ep, ".command"))
-                       return parse_lldiff_command(var, ep, value);
+               if (ep != var + 4) {
+                       if (!strcmp(ep, ".command"))
+                               return parse_lldiff_command(var, ep, value);
+                       if (!strcmp(ep, ".funcname"))
+                               return parse_funcname_pattern(var, ep, value);
+               }
        }
        if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
                int slot = parse_diff_color_slot(var, 11);
@@ -390,6 +441,7 @@ static void diff_words_show(struct diff_words_data *diff_words)
        mmfile_t minus, plus;
        int i;
 
+       memset(&xecfg, 0, sizeof(xecfg));
        minus.size = diff_words->minus.text.size;
        minus.ptr = xmalloc(minus.size);
        memcpy(minus.ptr, diff_words->minus.text.ptr, minus.size);
@@ -408,7 +460,6 @@ 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;
-       xecfg.flags = 0;
        ecb.outf = xdiff_outf;
        ecb.priv = diff_words;
        diff_words->xm.consume = fn_out_diff_words_aux;
@@ -1102,30 +1153,111 @@ static void setup_diff_attr_check(struct git_attr_check *check)
 {
        static struct git_attr *attr_diff;
 
-       if (!attr_diff)
+       if (!attr_diff) {
                attr_diff = git_attr("diff", 4);
-       check->attr = attr_diff;
+       }
+       check[0].attr = attr_diff;
 }
 
-static int file_is_binary(struct diff_filespec *one)
+static void diff_filespec_check_attr(struct diff_filespec *one)
 {
        struct git_attr_check attr_diff_check;
+       int check_from_data = 0;
+
+       if (one->checked_attr)
+               return;
 
        setup_diff_attr_check(&attr_diff_check);
+       one->is_binary = 0;
+       one->funcname_pattern_ident = NULL;
+
        if (!git_checkattr(one->path, 1, &attr_diff_check)) {
-               const char *value = attr_diff_check.value;
+               const char *value;
+
+               /* binaryness */
+               value = attr_diff_check.value;
                if (ATTR_TRUE(value))
-                       return 0;
+                       ;
                else if (ATTR_FALSE(value))
-                       return 1;
+                       one->is_binary = 1;
+               else
+                       check_from_data = 1;
+
+               /* funcname pattern ident */
+               if (ATTR_TRUE(value) || ATTR_FALSE(value) || ATTR_UNSET(value))
+                       ;
+               else
+                       one->funcname_pattern_ident = value;
        }
 
-       if (!one->data) {
-               if (!DIFF_FILE_VALID(one))
-                       return 0;
-               diff_populate_filespec(one, 0);
+       if (check_from_data) {
+               if (!one->data && DIFF_FILE_VALID(one))
+                       diff_populate_filespec(one, 0);
+
+               if (one->data)
+                       one->is_binary = buffer_is_binary(one->data, one->size);
        }
-       return buffer_is_binary(one->data, one->size);
+}
+
+int diff_filespec_is_binary(struct diff_filespec *one)
+{
+       diff_filespec_check_attr(one);
+       return one->is_binary;
+}
+
+static const char *funcname_pattern(const char *ident)
+{
+       struct funcname_pattern *pp;
+
+       read_config_if_needed();
+       for (pp = funcname_pattern_list; pp; pp = pp->next)
+               if (!strcmp(ident, pp->name))
+                       return pp->pattern;
+       return NULL;
+}
+
+static struct builtin_funcname_pattern {
+       const char *name;
+       const char *pattern;
+} builtin_funcname_pattern[] = {
+       { "java", "!^[  ]*\\(catch\\|do\\|for\\|if\\|instanceof\\|"
+                       "new\\|return\\|switch\\|throw\\|while\\)\n"
+                       "^[     ]*\\(\\([       ]*"
+                       "[A-Za-z_][A-Za-z_0-9]*\\)\\{2,\\}"
+                       "[      ]*([^;]*$\\)" },
+       { "tex", "^\\(\\\\\\(sub\\)*section{.*\\)$" },
+};
+
+static const char *diff_funcname_pattern(struct diff_filespec *one)
+{
+       const char *ident, *pattern;
+       int i;
+
+       diff_filespec_check_attr(one);
+       ident = one->funcname_pattern_ident;
+
+       if (!ident)
+               /*
+                * If the config file has "funcname.default" defined, that
+                * regexp is used; otherwise NULL is returned and xemit uses
+                * the built-in default.
+                */
+               return funcname_pattern("default");
+
+       /* Look up custom "funcname.$ident" regexp from config. */
+       pattern = funcname_pattern(ident);
+       if (pattern)
+               return pattern;
+
+       /*
+        * And define built-in fallback patterns here.  Note that
+        * these can be overriden by the user's config settings.
+        */
+       for (i = 0; i < ARRAY_SIZE(builtin_funcname_pattern); i++)
+               if (!strcmp(ident, builtin_funcname_pattern[i].name))
+                       return builtin_funcname_pattern[i].pattern;
+
+       return NULL;
 }
 
 static void builtin_diff(const char *name_a,
@@ -1182,7 +1314,8 @@ static void builtin_diff(const char *name_a,
        if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
                die("unable to read files to diff");
 
-       if (!o->text && (file_is_binary(one) || file_is_binary(two))) {
+       if (!o->text &&
+           (diff_filespec_is_binary(one) || diff_filespec_is_binary(two))) {
                /* Quite common confusing case */
                if (mf1.size == mf2.size &&
                    !memcmp(mf1.ptr, mf2.ptr, mf1.size))
@@ -1201,7 +1334,13 @@ static void builtin_diff(const char *name_a,
                xdemitconf_t xecfg;
                xdemitcb_t ecb;
                struct emit_callback ecbdata;
+               const char *funcname_pattern;
+
+               funcname_pattern = diff_funcname_pattern(one);
+               if (!funcname_pattern)
+                       funcname_pattern = diff_funcname_pattern(two);
 
+               memset(&xecfg, 0, sizeof(xecfg));
                memset(&ecbdata, 0, sizeof(ecbdata));
                ecbdata.label_path = lbl;
                ecbdata.color_diff = o->color_diff;
@@ -1209,6 +1348,8 @@ static void builtin_diff(const char *name_a,
                xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
                xecfg.ctxlen = o->context;
                xecfg.flags = XDL_EMIT_FUNCNAMES;
+               if (funcname_pattern)
+                       xdiff_set_find_func(&xecfg, funcname_pattern);
                if (!diffopts)
                        ;
                else if (!prefixcmp(diffopts, "--unified="))
@@ -1260,7 +1401,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
        if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
                die("unable to read files to diff");
 
-       if (file_is_binary(one) || file_is_binary(two)) {
+       if (diff_filespec_is_binary(one) || diff_filespec_is_binary(two)) {
                data->is_binary = 1;
                data->added = mf2.size;
                data->deleted = mf1.size;
@@ -1270,9 +1411,8 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
                xdemitconf_t xecfg;
                xdemitcb_t ecb;
 
+               memset(&xecfg, 0, sizeof(xecfg));
                xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
-               xecfg.ctxlen = 0;
-               xecfg.flags = 0;
                ecb.outf = xdiff_outf;
                ecb.priv = diffstat;
                xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
@@ -1302,7 +1442,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
        if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
                die("unable to read files to diff");
 
-       if (file_is_binary(two))
+       if (diff_filespec_is_binary(two))
                goto free_and_return;
        else {
                /* Crazy xdl interfaces.. */
@@ -1310,9 +1450,8 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
                xdemitconf_t xecfg;
                xdemitcb_t ecb;
 
+               memset(&xecfg, 0, sizeof(xecfg));
                xpp.flags = XDF_NEED_MINIMAL;
-               xecfg.ctxlen = 0;
-               xecfg.flags = 0;
                ecb.outf = xdiff_outf;
                ecb.priv = &data;
                xdl_diff(&mf1, &mf2, &xpp, &xecfg, &ecb);
@@ -1460,7 +1599,7 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
        if (size_only && 0 < s->size)
                return 0;
 
-       if (S_ISDIRLNK(s->mode))
+       if (S_ISGITLINK(s->mode))
                return diff_populate_gitlink(s, size_only);
 
        if (!s->sha1_valid ||
@@ -1753,10 +1892,7 @@ static const char *external_diff_attr(const char *name)
                    !ATTR_UNSET(value)) {
                        struct ll_diff_driver *drv;
 
-                       if (!user_diff_tail) {
-                               user_diff_tail = &user_diff;
-                               git_config(git_diff_ui_config);
-                       }
+                       read_config_if_needed();
                        for (drv = user_diff; drv; drv = drv->next)
                                if (!strcmp(drv->name, value))
                                        return drv->cmd;
@@ -1813,6 +1949,11 @@ static void diff_fill_sha1_info(struct diff_filespec *one)
                hashclr(one->sha1);
 }
 
+static int similarity_index(struct diff_filepair *p)
+{
+       return p->score * 100 / MAX_SCORE;
+}
+
 static void run_diff(struct diff_filepair *p, struct diff_options *o)
 {
        const char *pgm = external_diff();
@@ -1847,23 +1988,20 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o)
                                "similarity index %d%%\n"
                                "copy from %s\n"
                                "copy to %s\n",
-                               (int)(0.5 + p->score * 100.0/MAX_SCORE),
-                               name_munged, other_munged);
+                               similarity_index(p), name_munged, other_munged);
                break;
        case DIFF_STATUS_RENAMED:
                len += snprintf(msg + len, sizeof(msg) - len,
                                "similarity index %d%%\n"
                                "rename from %s\n"
                                "rename to %s\n",
-                               (int)(0.5 + p->score * 100.0/MAX_SCORE),
-                               name_munged, other_munged);
+                               similarity_index(p), name_munged, other_munged);
                break;
        case DIFF_STATUS_MODIFIED:
                if (p->score) {
                        len += snprintf(msg + len, sizeof(msg) - len,
                                        "dissimilarity index %d%%\n",
-                                       (int)(0.5 + p->score *
-                                             100.0/MAX_SCORE));
+                                       similarity_index(p));
                        complete_rewrite = 1;
                        break;
                }
@@ -1878,8 +2016,8 @@ static void run_diff(struct diff_filepair *p, struct diff_options *o)
 
                if (o->binary) {
                        mmfile_t mf;
-                       if ((!fill_mmfile(&mf, one) && file_is_binary(one)) ||
-                           (!fill_mmfile(&mf, two) && file_is_binary(two)))
+                       if ((!fill_mmfile(&mf, one) && diff_filespec_is_binary(one)) ||
+                           (!fill_mmfile(&mf, two) && diff_filespec_is_binary(two)))
                                abbrev = 40;
                }
                len += snprintf(msg + len, sizeof(msg) - len,
@@ -2103,6 +2241,8 @@ static int opt_arg(const char *arg, int arg_short, const char *arg_long, int *va
        return 1;
 }
 
+static int diff_scoreopt_parse(const char *opt);
+
 int diff_opt_parse(struct diff_options *options, const char **av, int ac)
 {
        const char *arg = av[0];
@@ -2199,6 +2339,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                options->detect_rename = DIFF_DETECT_RENAME;
        }
        else if (!prefixcmp(arg, "-C")) {
+               if (options->detect_rename == DIFF_DETECT_COPY)
+                       options->find_copies_harder = 1;
                if ((options->rename_score =
                     diff_scoreopt_parse(arg)) == -1)
                        return -1;
@@ -2206,6 +2348,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
        }
        else if (!strcmp(arg, "--find-copies-harder"))
                options->find_copies_harder = 1;
+       else if (!strcmp(arg, "--follow"))
+               options->follow_renames = 1;
        else if (!strcmp(arg, "--abbrev"))
                options->abbrev = DEFAULT_ABBREV;
        else if (!prefixcmp(arg, "--abbrev=")) {
@@ -2233,6 +2377,10 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                options->exit_with_status = 1;
        else if (!strcmp(arg, "--quiet"))
                options->quiet = 1;
+       else if (!strcmp(arg, "--ext-diff"))
+               options->allow_external = 1;
+       else if (!strcmp(arg, "--no-ext-diff"))
+               options->allow_external = 0;
        else
                return 0;
        return 1;
@@ -2274,7 +2422,7 @@ static int parse_num(const char **cp_p)
        return (int)((num >= scale) ? MAX_SCORE : (MAX_SCORE * num / scale));
 }
 
-int diff_scoreopt_parse(const char *opt)
+static int diff_scoreopt_parse(const char *opt)
 {
        int opt1, opt2, cmd;
 
@@ -2381,8 +2529,7 @@ static void diff_flush_raw(struct diff_filepair *p,
        }
 
        if (p->score)
-               sprintf(status, "%c%03d", p->status,
-                       (int)(0.5 + p->score * 100.0/MAX_SCORE));
+               sprintf(status, "%c%03d", p->status, similarity_index(p));
        else {
                status[0] = p->status;
                status[1] = 0;
@@ -2665,8 +2812,7 @@ static void show_rename_copy(const char *renamecopy, struct diff_filepair *p)
 {
        char *names = pprint_rename(p->one->path, p->two->path);
 
-       printf(" %s %s (%d%%)\n", renamecopy, names,
-              (int)(0.5 + p->score * 100.0/MAX_SCORE));
+       printf(" %s %s (%d%%)\n", renamecopy, names, similarity_index(p));
        free(names);
        show_mode_change(p, 0);
 }
@@ -2690,7 +2836,7 @@ static void diff_summary(struct diff_filepair *p)
                if (p->score) {
                        char *name = quote_one(p->two->path);
                        printf(" rewrite %s (%d%%)\n", name,
-                               (int)(0.5 + p->score * 100.0/MAX_SCORE));
+                              similarity_index(p));
                        free(name);
                        show_mode_change(p, 0);
                } else  show_mode_change(p, 1);
@@ -2754,6 +2900,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
                struct diff_filepair *p = q->queue[i];
                int len1, len2;
 
+               memset(&xecfg, 0, sizeof(xecfg));
                if (p->status == 0)
                        return error("internal diff status error");
                if (p->status == DIFF_STATUS_UNKNOWN)
@@ -2773,7 +2920,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
                        return error("unable to read files to diff");
 
                /* Maybe hash p->two? into the patch id? */
-               if (file_is_binary(p->two))
+               if (diff_filespec_is_binary(p->two))
                        continue;
 
                len1 = remove_space(p->one->path, strlen(p->one->path));
@@ -3000,6 +3147,7 @@ void diffcore_std(struct diff_options *options)
 {
        if (options->quiet)
                return;
+
        if (options->break_opt != -1)
                diffcore_break(options->break_opt);
        if (options->detect_rename)
@@ -3032,7 +3180,7 @@ void diff_addremove(struct diff_options *options,
         * entries to the diff-core.  They will be prefixed
         * with something like '=' or '*' (I haven't decided
         * which but should not make any difference).
-        * Feeding the same new and old to diff_change() 
+        * Feeding the same new and old to diff_change()
         * also has the same effect.
         * Before the final output happens, they are pruned after
         * merged into rename/copy pairs as appropriate.
@@ -3059,7 +3207,7 @@ void diff_change(struct diff_options *options,
                 unsigned old_mode, unsigned new_mode,
                 const unsigned char *old_sha1,
                 const unsigned char *new_sha1,
-                const char *base, const char *path) 
+                const char *base, const char *path)
 {
        char concatpath[PATH_MAX];
        struct diff_filespec *one, *two;
diff --git a/diff.h b/diff.h
index 63738c1dd4c71cb1beacaffea40bf51377a137ea..9fd6d447d4c62e158c941a736e547c7e516cdd93 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -55,6 +55,7 @@ struct diff_options {
                 full_index:1,
                 silent_on_remove:1,
                 find_copies_harder:1,
+                follow_renames:1,
                 color_diff:1,
                 color_diff_words:1,
                 has_changes:1,
@@ -155,8 +156,6 @@ extern void diff_unmerge(struct diff_options *,
                         unsigned mode,
                         const unsigned char *sha1);
 
-extern int diff_scoreopt_parse(const char *opt);
-
 #define DIFF_SETUP_REVERSE             1
 #define DIFF_SETUP_USE_CACHE           2
 #define DIFF_SETUP_USE_SIZE_CACHE      4
index 9c19b8cab778362b9d369135e743fb232a7cd295..ae8a7d03e2d103739897ac37fe1f9966956b9ec8 100644 (file)
@@ -66,8 +66,7 @@ static int should_break(struct diff_filespec *src,
        if (base_size < MINIMUM_BREAK_SIZE)
                return 0; /* we do not break too small filepair */
 
-       if (diffcore_count_changes(src->data, src->size,
-                                  dst->data, dst->size,
+       if (diffcore_count_changes(src, dst,
                                   NULL, NULL,
                                   0,
                                   &src_copied, &literal_added))
index 7338a40c5964ae6ddfb855465249fc1a2fa5a2a3..d9729e5ec27d2ff2bacf4ed930195f9293f8ca5a 100644 (file)
@@ -5,23 +5,20 @@
 /*
  * Idea here is very simple.
  *
- * We have total of (sz-N+1) N-byte overlapping sequences in buf whose
- * size is sz.  If the same N-byte sequence appears in both source and
- * destination, we say the byte that starts that sequence is shared
- * between them (i.e. copied from source to destination).
+ * Almost all data we are interested in are text, but sometimes we have
+ * to deal with binary data.  So we cut them into chunks delimited by
+ * LF byte, or 64-byte sequence, whichever comes first, and hash them.
  *
- * For each possible N-byte sequence, if the source buffer has more
- * instances of it than the destination buffer, that means the
- * difference are the number of bytes not copied from source to
- * destination.  If the counts are the same, everything was copied
- * from source to destination.  If the destination has more,
- * everything was copied, and destination added more.
+ * For those chunks, if the source buffer has more instances of it
+ * than the destination buffer, that means the difference are the
+ * number of bytes not copied from source to destination.  If the
+ * counts are the same, everything was copied from source to
+ * destination.  If the destination has more, everything was copied,
+ * and destination added more.
  *
  * We are doing an approximation so we do not really have to waste
  * memory by actually storing the sequence.  We just hash them into
  * somewhere around 2^16 hashbuckets and count the occurrences.
- *
- * The length of the sequence is arbitrarily set to 8 for now.
  */
 
 /* Wild guess at the initial hash size */
@@ -125,11 +122,14 @@ static struct spanhash_top *add_spanhash(struct spanhash_top *top,
        }
 }
 
-static struct spanhash_top *hash_chars(unsigned char *buf, unsigned int sz)
+static struct spanhash_top *hash_chars(struct diff_filespec *one)
 {
        int i, n;
        unsigned int accum1, accum2, hashval;
        struct spanhash_top *hash;
+       unsigned char *buf = one->data;
+       unsigned int sz = one->size;
+       int is_text = !diff_filespec_is_binary(one);
 
        i = INITIAL_HASH_SIZE;
        hash = xmalloc(sizeof(*hash) + sizeof(struct spanhash) * (1<<i));
@@ -143,6 +143,11 @@ static struct spanhash_top *hash_chars(unsigned char *buf, unsigned int sz)
                unsigned int c = *buf++;
                unsigned int old_1 = accum1;
                sz--;
+
+               /* Ignore CR in CRLF sequence if text */
+               if (is_text && c == '\r' && sz && *buf == '\n')
+                       continue;
+
                accum1 = (accum1 << 7) ^ (accum2 >> 25);
                accum2 = (accum2 << 7) ^ (old_1 >> 25);
                accum1 += c;
@@ -156,8 +161,8 @@ static struct spanhash_top *hash_chars(unsigned char *buf, unsigned int sz)
        return hash;
 }
 
-int diffcore_count_changes(void *src, unsigned long src_size,
-                          void *dst, unsigned long dst_size,
+int diffcore_count_changes(struct diff_filespec *src,
+                          struct diff_filespec *dst,
                           void **src_count_p,
                           void **dst_count_p,
                           unsigned long delta_limit,
@@ -172,14 +177,14 @@ int diffcore_count_changes(void *src, unsigned long src_size,
        if (src_count_p)
                src_count = *src_count_p;
        if (!src_count) {
-               src_count = hash_chars(src, src_size);
+               src_count = hash_chars(src);
                if (src_count_p)
                        *src_count_p = src_count;
        }
        if (dst_count_p)
                dst_count = *dst_count_p;
        if (!dst_count) {
-               dst_count = hash_chars(dst, dst_size);
+               dst_count = hash_chars(dst);
                if (dst_count_p)
                        *dst_count_p = dst_count;
        }
index c4a77d71da5602b68c541c2487fcbecfdfff2944..af9fffe6e8e145b066157da8791c749257e7c8e9 100644 (file)
@@ -102,7 +102,7 @@ void diffcore_pickaxe(const char *needle, int opts)
                for (i = 0; i < q->nr; i++)
                        diff_free_filepair(q->queue[i]);
        }
-       else 
+       else
                /* Showing only the filepairs that has the needle */
                for (i = 0; i < q->nr; i++) {
                        struct diff_filepair *p = q->queue[i];
index 93c40d9e04f35897b1ac2ad578db0c0972aacbc1..6bde4396f212833cc1d411e723d5215c086e7c2d 100644 (file)
@@ -119,10 +119,26 @@ static int is_exact_match(struct diff_filespec *src,
        return 0;
 }
 
+static int basename_same(struct diff_filespec *src, struct diff_filespec *dst)
+{
+       int src_len = strlen(src->path), dst_len = strlen(dst->path);
+       while (src_len && dst_len) {
+               char c1 = src->path[--src_len];
+               char c2 = dst->path[--dst_len];
+               if (c1 != c2)
+                       return 0;
+               if (c1 == '/')
+                       return 1;
+       }
+       return (!src_len || src->path[src_len - 1] == '/') &&
+               (!dst_len || dst->path[dst_len - 1] == '/');
+}
+
 struct diff_score {
        int src; /* index in rename_src */
        int dst; /* index in rename_dst */
        int score;
+       int name_score;
 };
 
 static int estimate_similarity(struct diff_filespec *src,
@@ -174,8 +190,7 @@ static int estimate_similarity(struct diff_filespec *src,
 
        delta_limit = (unsigned long)
                (base_size * (MAX_SCORE-minimum_score) / MAX_SCORE);
-       if (diffcore_count_changes(src->data, src->size,
-                                  dst->data, dst->size,
+       if (diffcore_count_changes(src, dst,
                                   &src->cnt_data, &dst->cnt_data,
                                   delta_limit,
                                   &src_copied, &literal_added))
@@ -224,6 +239,10 @@ static void record_rename_pair(int dst_index, int src_index, int score)
 static int score_compare(const void *a_, const void *b_)
 {
        const struct diff_score *a = a_, *b = b_;
+
+       if (a->score == b->score)
+               return b->name_score - a->name_score;
+
        return b->score - a->score;
 }
 
@@ -295,9 +314,22 @@ void diffcore_rename(struct diff_options *options)
                        if (rename_dst[i].pair)
                                continue; /* dealt with an earlier round */
                        for (j = 0; j < rename_src_nr; j++) {
+                               int k;
                                struct diff_filespec *one = rename_src[j].one;
                                if (!is_exact_match(one, two, contents_too))
                                        continue;
+
+                               /* see if there is a basename match, too */
+                               for (k = j; k < rename_src_nr; k++) {
+                                       one = rename_src[k].one;
+                                       if (basename_same(one, two) &&
+                                               is_exact_match(one, two,
+                                                       contents_too)) {
+                                               j = k;
+                                               break;
+                                       }
+                               }
+
                                record_rename_pair(i, j, (int)MAX_SCORE);
                                rename_count++;
                                break; /* we are done with this entry */
@@ -329,6 +361,7 @@ void diffcore_rename(struct diff_options *options)
                        m->dst = i;
                        m->score = estimate_similarity(one, two,
                                                       minimum_score);
+                       m->name_score = basename_same(one, two);
                        diff_free_filespec_data(one);
                }
                /* We do not need the text anymore */
index 7b9294eab2c1cb9f7cb03307c90203344d97e3f6..eef17c4ca2e81c572fb110e9eb11e8ed9d51f9a0 100644 (file)
@@ -27,6 +27,7 @@ struct diff_filespec {
        char *path;
        void *data;
        void *cnt_data;
+       const char *funcname_pattern_ident;
        unsigned long size;
        int xfrm_flags;          /* for use by the xfrm */
        unsigned short mode;     /* file mode */
@@ -37,6 +38,8 @@ struct diff_filespec {
 #define DIFF_FILE_VALID(spec) (((spec)->mode) != 0)
        unsigned should_free : 1; /* data should be free()'ed */
        unsigned should_munmap : 1; /* data should be munmap()'ed */
+       unsigned checked_attr : 1;
+       unsigned is_binary : 1; /* data should be considered "binary" */
 };
 
 extern struct diff_filespec *alloc_filespec(const char *);
@@ -45,6 +48,7 @@ extern void fill_filespec(struct diff_filespec *, const unsigned char *,
 
 extern int diff_populate_filespec(struct diff_filespec *, int);
 extern void diff_free_filespec_data(struct diff_filespec *);
+extern int diff_filespec_is_binary(struct diff_filespec *);
 
 struct diff_filepair {
        struct diff_filespec *one;
@@ -103,8 +107,8 @@ void diff_debug_queue(const char *, struct diff_queue_struct *);
 #define diff_debug_queue(a,b) do {} while(0)
 #endif
 
-extern int diffcore_count_changes(void *src, unsigned long src_size,
-                                 void *dst, unsigned long dst_size,
+extern int diffcore_count_changes(struct diff_filespec *src,
+                                 struct diff_filespec *dst,
                                  void **src_count_p,
                                  void **dst_count_p,
                                  unsigned long delta_limit,
diff --git a/dir.c b/dir.c
index 11fab7f4bf9b93be33795dfd5c1a3c55c8a8079d..8d8faf5d788b402d5fd4f5d724954fd2ee178fdb 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -271,27 +271,34 @@ int excluded(struct dir_struct *dir, const char *pathname)
        return 0;
 }
 
-struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)
-{
+static struct dir_entry *dir_entry_new(const char *pathname, int len) {
        struct dir_entry *ent;
 
-       if (cache_name_pos(pathname, len) >= 0)
-               return NULL;
-
-       if (dir->nr == dir->alloc) {
-               int alloc = alloc_nr(dir->alloc);
-               dir->alloc = alloc;
-               dir->entries = xrealloc(dir->entries, alloc*sizeof(ent));
-       }
        ent = xmalloc(sizeof(*ent) + len + 1);
-       ent->ignored = ent->ignored_dir = 0;
        ent->len = len;
        memcpy(ent->name, pathname, len);
        ent->name[len] = 0;
-       dir->entries[dir->nr++] = ent;
        return ent;
 }
 
+struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)
+{
+       if (cache_name_pos(pathname, len) >= 0)
+               return NULL;
+
+       ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc);
+       return dir->entries[dir->nr++] = dir_entry_new(pathname, len);
+}
+
+struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len)
+{
+       if (cache_name_pos(pathname, len) >= 0)
+               return NULL;
+
+       ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->ignored_alloc);
+       return dir->ignored[dir->ignored_nr++] = dir_entry_new(pathname, len);
+}
+
 enum exist_status {
        index_nonexistent = 0,
        index_directory,
@@ -321,7 +328,7 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len)
                        break;
                if (endchar == '/')
                        return index_directory;
-               if (!endchar && S_ISDIRLNK(ntohl(ce->ce_mode)))
+               if (!endchar && S_ISGITLINK(ntohl(ce->ce_mode)))
                        return index_gitdir;
        }
        return index_nonexistent;
@@ -356,7 +363,7 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len)
  *      also true and the directory is empty, in which case
  *      we just ignore it entirely.
  *  (b) if it looks like a git directory, and we don't have
- *      'no_dirlinks' set we treat it as a gitlink, and show it
+ *      'no_gitlinks' set we treat it as a gitlink, and show it
  *      as a directory.
  *  (c) otherwise, we recurse into it.
  */
@@ -383,7 +390,7 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
        case index_nonexistent:
                if (dir->show_other_directories)
                        break;
-               if (!dir->no_dirlinks) {
+               if (!dir->no_gitlinks) {
                        unsigned char sha1[20];
                        if (resolve_gitlink_ref(dirname, "HEAD", sha1) == 0)
                                return show_directory;
@@ -424,6 +431,18 @@ static int simplify_away(const char *path, int pathlen, const struct path_simpli
        return 0;
 }
 
+static int in_pathspec(const char *path, int len, const struct path_simplify *simplify)
+{
+       if (simplify) {
+               for (; simplify->path; simplify++) {
+                       if (len == simplify->len
+                           && !memcmp(path, simplify->path, len))
+                               return 1;
+               }
+       }
+       return 0;
+}
+
 /*
  * Read a directory tree. We currently ignore anything but
  * directories, regular files and symlinks. That's because git
@@ -464,6 +483,9 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
                                continue;
 
                        exclude = excluded(dir, fullname);
+                       if (exclude && dir->collect_ignored
+                           && in_pathspec(fullname, baselen + len, simplify))
+                               dir_add_ignored(dir, fullname, baselen + len);
                        if (exclude != dir->show_ignored) {
                                if (!dir->show_ignored || DTYPE(de) != DT_DIR) {
                                        continue;
@@ -610,6 +632,7 @@ int read_directory(struct dir_struct *dir, const char *path, const char *base, i
        read_directory_recursive(dir, path, base, baselen, 0, simplify);
        free_simplify(simplify);
        qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);
+       qsort(dir->ignored, dir->ignored_nr, sizeof(struct dir_entry *), cmp_name);
        return dir->nr;
 }
 
diff --git a/dir.h b/dir.h
index 817c674da1e017cffea9dddae672f9125aca8475..ec0e8ababc7fa00d9bf039e0ad97d8639b70450f 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -13,9 +13,7 @@
 
 
 struct dir_entry {
-       unsigned int ignored : 1;
-       unsigned int ignored_dir : 1;
-       unsigned int len : 30;
+       unsigned int len;
        char name[FLEX_ARRAY]; /* more */
 };
 
@@ -31,11 +29,14 @@ struct exclude_list {
 
 struct dir_struct {
        int nr, alloc;
+       int ignored_nr, ignored_alloc;
        unsigned int show_ignored:1,
                     show_other_directories:1,
                     hide_empty_directories:1,
-                    no_dirlinks:1;
+                    no_gitlinks:1,
+                    collect_ignored:1;
        struct dir_entry **entries;
+       struct dir_entry **ignored;
 
        /* Exclude info */
        const char *exclude_per_dir;
diff --git a/entry.c b/entry.c
index 82bf7259a7d1d34a92a9bf214bccd9771748c582..c540ae13e858685faa8dbbada5b064074235ae6d 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -31,7 +31,7 @@ static void remove_subtree(const char *path)
        struct dirent *de;
        char pathbuf[PATH_MAX];
        char *name;
-       
+
        if (!dir)
                die("cannot opendir %s (%s)", path, strerror(errno));
        strcpy(pathbuf, path);
@@ -145,7 +145,7 @@ static int write_entry(struct cache_entry *ce, char *path, const struct checkout
                                                 "symlink %s (%s)", path, strerror(errno));
                }
                break;
-       case S_IFDIRLNK:
+       case S_IFGITLINK:
                if (to_tempfile)
                        return error("git-checkout-index: cannot create temporary subproject %s", path);
                if (mkdir(path, 0777) < 0)
@@ -194,7 +194,7 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
                unlink(path);
                if (S_ISDIR(st.st_mode)) {
                        /* If it is a gitlink, leave it alone! */
-                       if (S_ISDIRLNK(ntohl(ce->ce_mode)))
+                       if (S_ISGITLINK(ntohl(ce->ce_mode)))
                                return 0;
                        if (!state->force)
                                return error("%s is a directory", path);
index 22316597df60648c850001e068938eaf39d57f6d..f83fb9e44806c03cde06eede7888a4dcb901c5c3 100644 (file)
@@ -11,8 +11,8 @@
 
 char git_default_email[MAX_GITNAME];
 char git_default_name[MAX_GITNAME];
-int use_legacy_headers = 1;
 int trust_executable_bit = 1;
+int quote_path_fully = 1;
 int has_symlinks = 1;
 int assume_unchanged;
 int prefer_symlink_refs;
@@ -24,10 +24,13 @@ const char *git_commit_encoding;
 const char *git_log_output_encoding;
 int shared_repository = PERM_UMASK;
 const char *apply_default_whitespace;
-int zlib_compression_level = Z_DEFAULT_COMPRESSION;
+int zlib_compression_level = Z_BEST_SPEED;
+int core_compression_level;
+int core_compression_seen;
 size_t packed_git_window_size = DEFAULT_PACKED_GIT_WINDOW_SIZE;
 size_t packed_git_limit = DEFAULT_PACKED_GIT_LIMIT;
 size_t delta_base_cache_limit = 16 * 1024 * 1024;
+char *pager_program;
 int pager_in_use;
 int pager_use_color = 1;
 int auto_crlf = 0;     /* 1: both ways, -1: only when adding git objects */
@@ -104,5 +107,3 @@ char *get_graft_file(void)
                setup_git_env();
        return git_graft_file;
 }
-
-
index 17554f68493a8409c64b47334a94e622d47d8133..f9bfcc72c87bf79fcb7a5faef01bc0d12aa15420 100644 (file)
@@ -1272,7 +1272,7 @@ static int update_branch(struct branch *b)
 
        if (read_ref(b->name, old_sha1))
                hashclr(old_sha1);
-       lock = lock_any_ref_for_update(b->name, old_sha1);
+       lock = lock_any_ref_for_update(b->name, old_sha1, 0);
        if (!lock)
                return error("Unable to lock %s", b->name);
        if (!force_update && !is_null_sha1(old_sha1)) {
index 06f4aeced439312c43f2736a1684f9e22218899b..9c81305be5f4c1a78794c9d5397bd828ba705fcc 100644 (file)
@@ -114,7 +114,7 @@ static const unsigned char* get_rev(void)
                commit->object.flags |= POPPED;
                if (!(commit->object.flags & COMMON))
                        non_common_revs--;
-       
+
                parents = commit->parents;
 
                if (commit->object.flags & COMMON) {
@@ -733,7 +733,7 @@ int main(int argc, char **argv)
        }
        if (!dest)
                usage(fetch_pack_usage);
-       pid = git_connect(fd, dest, uploadpack);
+       pid = git_connect(fd, dest, uploadpack, verbose ? CONNECT_VERBOSE : 0);
        if (pid < 0)
                return 1;
        if (heads && nr_heads)
diff --git a/fetch.c b/fetch.c
index 6f1f420be26ac6dafec366b3dc0671fb7f4940dc..811be87a3c1e0d14d9f2b37650d56575b49caa22 100644 (file)
--- a/fetch.c
+++ b/fetch.c
@@ -15,7 +15,7 @@ int get_verbosely = 0;
 int get_recover = 0;
 static unsigned char current_commit_sha1[20];
 
-void pull_say(const char *fmt, const char *hex) 
+void pull_say(const char *fmt, const char *hex)
 {
        if (get_verbosely)
                fprintf(stderr, fmt, hex);
@@ -47,7 +47,7 @@ static int process_tree(struct tree *tree)
                struct object *obj = NULL;
 
                /* submodule commits are not stored in the superproject */
-               if (S_ISDIRLNK(entry.mode))
+               if (S_ISGITLINK(entry.mode))
                        continue;
                if (S_ISDIR(entry.mode)) {
                        struct tree *tree = lookup_tree(entry.sha1);
@@ -156,7 +156,7 @@ static int process(struct object *obj)
                        return 0;
                prefetch(obj->sha1);
        }
-               
+
        object_list_insert(obj, process_queue_end);
        process_queue_end = &(*process_queue_end)->next;
        return 0;
diff --git a/fixup-builtins b/fixup-builtins
new file mode 100755 (executable)
index 0000000..49e861d
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+while [ "$1" ]
+do
+       old="$1"
+       new=$(echo "$1" | sed 's/git-/git /')
+       echo "Converting '$old' to '$new'"
+       git ls-files '*.sh' | while read file
+       do
+               sed "s/\\<$old\\>/$new/g" < $file > $file.new
+               chmod --reference=$file $file.new
+               mv $file.new $file
+       done
+       shift
+done
+git update-index --refresh >& /dev/null
+exit 0
index 975777f05ed69ef78f1fd91ac512f5b92a384141..17df47b95067449f03039b8ecd7715701302fa68 100755 (executable)
@@ -7,7 +7,7 @@ struct cmdname_help
     char help[80];
 };
 
-struct cmdname_help common_cmds[] = {"
+static struct cmdname_help common_cmds[] = {"
 
 sort <<\EOF |
 add
index 8b5712968ebcfe3f8fb5426e5104de2e7d2d3334..e5e6f2c91c1faf58239ab73672fbb05cda91762f 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -60,17 +60,17 @@ fall_back_3way () {
     mkdir "$dotest/patch-merge-tmp-dir"
 
     # First see if the patch records the index info that we can use.
-    git-apply -z --index-info "$dotest/patch" \
+    git apply -z --index-info "$dotest/patch" \
        >"$dotest/patch-merge-index-info" &&
     GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
-    git-update-index -z --index-info <"$dotest/patch-merge-index-info" &&
+    git update-index -z --index-info <"$dotest/patch-merge-index-info" &&
     GIT_INDEX_FILE="$dotest/patch-merge-tmp-index" \
-    git-write-tree >"$dotest/patch-merge-base+" ||
+    git write-tree >"$dotest/patch-merge-base+" ||
     cannot_fallback "Repository lacks necessary blobs to fall back on 3-way merge."
 
     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 $binary --cached <"$dotest/patch"
     then
        mv "$dotest/patch-merge-base+" "$dotest/patch-merge-base"
        mv "$dotest/patch-merge-tmp-index" "$dotest/patch-merge-index"
@@ -80,7 +80,7 @@ It does not apply to blobs recorded in its index."
     fi
 
     test -f "$dotest/patch-merge-index" &&
-    his_tree=$(GIT_INDEX_FILE="$dotest/patch-merge-index" git-write-tree) &&
+    his_tree=$(GIT_INDEX_FILE="$dotest/patch-merge-index" git write-tree) &&
     orig_tree=$(cat "$dotest/patch-merge-base") &&
     rm -fr "$dotest"/patch-merge-* || exit 1
 
@@ -95,10 +95,7 @@ It does not apply to blobs recorded in its index."
     eval GITHEAD_$his_tree='"$SUBJECT"'
     export GITHEAD_$his_tree
     git-merge-recursive $orig_tree -- HEAD $his_tree || {
-           if test -d "$GIT_DIR/rr-cache"
-           then
-               git-rerere
-           fi
+           git rerere
            echo Failed to merge in the changes.
            exit 1
     }
@@ -198,7 +195,7 @@ else
        # Start afresh.
        mkdir -p "$dotest" || exit
 
-       git-mailsplit -d"$prec" -o"$dotest" -b -- "$@" > "$dotest/last" ||  {
+       git mailsplit -d"$prec" -o"$dotest" -b -- "$@" > "$dotest/last" ||  {
                rm -fr "$dotest"
                exit 1
        }
@@ -216,7 +213,7 @@ fi
 
 case "$resolved" in
 '')
-       files=$(git-diff-index --cached --name-only HEAD) || exit
+       files=$(git diff-index --cached --name-only HEAD) || exit
        if [ "$files" ]; then
           echo "Dirty index: cannot apply patches (dirty: $files)" >&2
           exit 1
@@ -252,10 +249,7 @@ last=`cat "$dotest/last"`
 this=`cat "$dotest/next"`
 if test "$skip" = t
 then
-       if test -d "$GIT_DIR/rr-cache"
-       then
-               git-rerere clear
-       fi
+       git rerere clear
        this=`expr "$this" + 1`
        resume=
 fi
@@ -287,14 +281,14 @@ do
        # by the user, or the user can tell us to do so by --resolved flag.
        case "$resume" in
        '')
-               git-mailinfo $keep $utf8 "$dotest/msg" "$dotest/patch" \
+               git mailinfo $keep $utf8 "$dotest/msg" "$dotest/patch" \
                        <"$dotest/$msgnum" >"$dotest/info" ||
                        stop_here $this
                test -s $dotest/patch || {
                        echo "Patch is empty.  Was it split wrong?"
                        stop_here $this
                }
-               git-stripspace < "$dotest/msg" > "$dotest/msg-clean"
+               git stripspace < "$dotest/msg" > "$dotest/msg-clean"
                ;;
        esac
 
@@ -347,7 +341,7 @@ do
                case "$resolved$interactive" in
                tt)
                        # This is used only for interactive view option.
-                       git-diff-index -p --cached HEAD >"$dotest/patch"
+                       git diff-index -p --cached HEAD >"$dotest/patch"
                        ;;
                esac
        esac
@@ -399,7 +393,7 @@ do
 
        case "$resolved" in
        '')
-               git-apply $git_apply_opt $binary --index "$dotest/patch"
+               git apply $git_apply_opt $binary --index "$dotest/patch"
                apply_status=$?
                ;;
        t)
@@ -408,11 +402,11 @@ do
                # trust what the user has in the index file and the
                # working tree.
                resolved=
-               git-diff-index --quiet --cached HEAD && {
+               git diff-index --quiet --cached HEAD && {
                        echo "No changes - did you forget to use 'git add'?"
                        stop_here_user_resolve $this
                }
-               unmerged=$(git-ls-files -u)
+               unmerged=$(git ls-files -u)
                if test -n "$unmerged"
                then
                        echo "You still have unmerged paths in your index"
@@ -420,10 +414,7 @@ do
                        stop_here_user_resolve $this
                fi
                apply_status=0
-               if test -d "$GIT_DIR/rr-cache"
-               then
-                       git rerere
-               fi
+               git rerere
                ;;
        esac
 
@@ -433,7 +424,7 @@ do
                then
                    # Applying the patch to an earlier tree and merging the
                    # result may have produced the same tree as ours.
-                   git-diff-index --quiet --cached HEAD && {
+                   git diff-index --quiet --cached HEAD && {
                        echo No changes -- Patch already applied.
                        go_next
                        continue
@@ -453,12 +444,12 @@ do
                "$GIT_DIR"/hooks/pre-applypatch || stop_here $this
        fi
 
-       tree=$(git-write-tree) &&
+       tree=$(git write-tree) &&
        echo Wrote tree $tree &&
-       parent=$(git-rev-parse --verify HEAD) &&
-       commit=$(git-commit-tree $tree -p $parent <"$dotest/final-commit") &&
+       parent=$(git rev-parse --verify HEAD) &&
+       commit=$(git commit-tree $tree -p $parent <"$dotest/final-commit") &&
        echo Committed: $commit &&
-       git-update-ref -m "$GIT_REFLOG_ACTION: $SUBJECT" HEAD $commit $parent ||
+       git update-ref -m "$GIT_REFLOG_ACTION: $SUBJECT" HEAD $commit $parent ||
        stop_here $this
 
        if test -x "$GIT_DIR"/hooks/post-applypatch
diff --git a/git-applymbox.sh b/git-applymbox.sh
deleted file mode 100755 (executable)
index c18e80f..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-#!/bin/sh
-##
-## "dotest" is my stupid name for my patch-application script, which
-## I never got around to renaming after I tested it. We're now on the
-## second generation of scripts, still called "dotest".
-##
-## Update: Ryan Anderson finally shamed me into naming this "applymbox".
-##
-## You give it a mbox-format collection of emails, and it will try to
-## apply them to the kernel using "applypatch"
-##
-## The patch application may fail in the middle.  In which case:
-## (1) look at .dotest/patch and fix it up to apply
-## (2) re-run applymbox with -c .dotest/msg-number for the current one.
-## Pay a special attention to the commit log message if you do this and
-## use a Signoff_file, because applypatch wants to append the sign-off
-## message to msg-clean every time it is run.
-##
-## git-am is supposed to be the newer and better tool for this job.
-
-USAGE='[-u] [-k] [-q] [-m] (-c .dotest/<num> | mbox) [signoff]'
-. git-sh-setup
-
-git var GIT_COMMITTER_IDENT >/dev/null || exit
-
-keep_subject= query_apply= continue= utf8=-u resume=t
-while case "$#" in 0) break ;; esac
-do
-       case "$1" in
-       -u)     utf8=-u ;;
-       -n)     utf8=-n ;;
-       -k)     keep_subject=-k ;;
-       -q)     query_apply=t ;;
-       -c)     continue="$2"; resume=f; shift ;;
-       -m)     fall_back_3way=t ;;
-       -*)     usage ;;
-       *)      break ;;
-       esac
-       shift
-done
-
-case "$continue" in
-'')
-       rm -rf .dotest
-       mkdir .dotest
-       num_msgs=$(git-mailsplit "$1" .dotest) || exit 1
-       echo "$num_msgs patch(es) to process."
-       shift
-esac
-
-files=$(git-diff-index --cached --name-only HEAD) || exit
-if [ "$files" ]; then
-   echo "Dirty index: cannot apply patches (dirty: $files)" >&2
-   exit 1
-fi
-
-case "$query_apply" in
-t)     touch .dotest/.query_apply
-esac
-case "$fall_back_3way" in
-t)     : >.dotest/.3way
-esac
-case "$keep_subject" in
--k)    : >.dotest/.keep_subject
-esac
-
-signoff="$1"
-set x .dotest/0*
-shift
-while case "$#" in 0) break;; esac
-do
-    i="$1" 
-    case "$resume,$continue" in
-    f,$i)      resume=t;;
-    f,*)       shift
-               continue;;
-    *)
-           git-mailinfo $keep_subject $utf8 \
-               .dotest/msg .dotest/patch <$i >.dotest/info || exit 1
-           test -s .dotest/patch || {
-               echo "Patch is empty.  Was it split wrong?"
-               exit 1
-           }
-           git-stripspace < .dotest/msg > .dotest/msg-clean
-           ;;
-    esac
-    while :; # for fixing up and retry
-    do
-       git-applypatch .dotest/msg-clean .dotest/patch .dotest/info "$signoff"
-       case "$?" in
-       0)
-               # Remove the cleanly applied one to reduce clutter.
-               rm -f .dotest/$i
-               ;;
-       2)
-               # 2 is a special exit code from applypatch to indicate that
-               # the patch wasn't applied, but continue anyway 
-               ;;
-       *)
-               ret=$?
-               if test -f .dotest/.query_apply
-               then
-                       echo >&2 "* Patch failed."
-                       echo >&2 "* You could fix it up in your editor and"
-                       echo >&2 "  retry.  If you want to do so, say yes here"
-                       echo >&2 "  AFTER fixing .dotest/patch up."
-                       echo >&2 -n "Retry [y/N]? "
-                       read yesno
-                       case "$yesno" in
-                       [Yy]*)
-                               continue ;;
-                       esac
-               fi
-               exit $ret
-       esac
-       break
-    done
-    shift
-done
-# return to pristine
-rm -fr .dotest
diff --git a/git-applypatch.sh b/git-applypatch.sh
deleted file mode 100755 (executable)
index 8df2aee..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-#!/bin/sh
-##
-## applypatch takes four file arguments, and uses those to
-## apply the unpacked patch (surprise surprise) that they
-## represent to the current tree.
-##
-## The arguments are:
-##     $1 - file with commit message
-##     $2 - file with the actual patch
-##     $3 - "info" file with Author, email and subject
-##     $4 - optional file containing signoff to add
-##
-
-USAGE='<msg> <patch> <info> [<signoff>]'
-. git-sh-setup
-
-case "$#" in 3|4) ;; *) usage ;; esac
-
-final=.dotest/final-commit
-##
-## If this file exists, we ask before applying
-##
-query_apply=.dotest/.query_apply
-
-## We do not munge the first line of the commit message too much
-## if this file exists.
-keep_subject=.dotest/.keep_subject
-
-## We do not attempt the 3-way merge fallback unless this file exists.
-fall_back_3way=.dotest/.3way
-
-MSGFILE=$1
-PATCHFILE=$2
-INFO=$3
-SIGNOFF=$4
-EDIT=${VISUAL:-${EDITOR:-vi}}
-
-export GIT_AUTHOR_NAME="$(sed -n '/^Author/ s/Author: //p' "$INFO")"
-export GIT_AUTHOR_EMAIL="$(sed -n '/^Email/ s/Email: //p' "$INFO")"
-export GIT_AUTHOR_DATE="$(sed -n '/^Date/ s/Date: //p' "$INFO")"
-export SUBJECT="$(sed -n '/^Subject/ s/Subject: //p' "$INFO")"
-
-if test '' != "$SIGNOFF"
-then
-       if test -f "$SIGNOFF"
-       then
-               SIGNOFF=`cat "$SIGNOFF"` || exit
-       elif case "$SIGNOFF" in yes | true | me | please) : ;; *) false ;; esac
-       then
-               SIGNOFF=`git-var GIT_COMMITTER_IDENT | sed -e '
-                               s/>.*/>/
-                               s/^/Signed-off-by: /'
-               `
-       else
-               SIGNOFF=
-       fi
-       if test '' != "$SIGNOFF"
-       then
-               LAST_SIGNED_OFF_BY=`
-                       sed -ne '/^Signed-off-by: /p' "$MSGFILE" |
-                       tail -n 1
-               `
-               test "$LAST_SIGNED_OFF_BY" = "$SIGNOFF" || {
-                   test '' = "$LAST_SIGNED_OFF_BY" && echo
-                   echo "$SIGNOFF"
-               } >>"$MSGFILE"
-       fi
-fi
-
-patch_header=
-test -f "$keep_subject" || patch_header='[PATCH] '
-
-{
-       echo "$patch_header$SUBJECT"
-       if test -s "$MSGFILE"
-       then
-               echo
-               cat "$MSGFILE"
-       fi
-} >"$final"
-
-interactive=yes
-test -f "$query_apply" || interactive=no
-
-while [ "$interactive" = yes ]; do
-       echo "Commit Body is:"
-       echo "--------------------------"
-       cat "$final"
-       echo "--------------------------"
-       printf "Apply? [y]es/[n]o/[e]dit/[a]ccept all "
-       read reply
-       case "$reply" in
-               y|Y) interactive=no;;
-               n|N) exit 2;;   # special value to tell dotest to keep going
-               e|E) "$EDIT" "$final";;
-               a|A) rm -f "$query_apply"
-                    interactive=no ;;
-       esac
-done
-
-if test -x "$GIT_DIR"/hooks/applypatch-msg
-then
-       "$GIT_DIR"/hooks/applypatch-msg "$final" || exit
-fi
-
-echo
-echo Applying "'$SUBJECT'"
-echo
-
-git-apply --index "$PATCHFILE" || {
-
-       # git-apply exits with status 1 when the patch does not apply,
-       # but it die()s with other failures, most notably upon corrupt
-       # patch.  In the latter case, there is no point to try applying
-       # it to another tree and do 3-way merge.
-       test $? = 1 || exit 1
-
-       test -f "$fall_back_3way" || exit 1
-
-       # Here if we know which revision the patch applies to,
-       # we create a temporary working tree and index, apply the
-       # patch, and attempt 3-way merge with the resulting tree.
-
-       O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd`
-       rm -fr .patch-merge-*
-
-       if git-apply -z --index-info "$PATCHFILE" \
-               >.patch-merge-index-info 2>/dev/null &&
-               GIT_INDEX_FILE=.patch-merge-tmp-index \
-               git-update-index -z --index-info <.patch-merge-index-info &&
-               GIT_INDEX_FILE=.patch-merge-tmp-index \
-               git-write-tree >.patch-merge-tmp-base &&
-               (
-                       mkdir .patch-merge-tmp-dir &&
-                       cd .patch-merge-tmp-dir &&
-                       GIT_INDEX_FILE="../.patch-merge-tmp-index" \
-                       GIT_OBJECT_DIRECTORY="$O_OBJECT" \
-                       git-apply $binary --index
-               ) <"$PATCHFILE"
-       then
-               echo Using index info to reconstruct a base tree...
-               mv .patch-merge-tmp-base .patch-merge-base
-               mv .patch-merge-tmp-index .patch-merge-index
-       else
-       (
-               N=10
-
-               # Otherwise, try nearby trees that can be used to apply the
-               # patch.
-               git-rev-list --max-count=$N HEAD
-
-               # or hoping the patch is against known tags...
-               git-ls-remote --tags .
-       ) |
-           while read base junk
-           do
-               # Try it if we have it as a tree.
-               git-cat-file tree "$base" >/dev/null 2>&1 || continue
-
-               rm -fr .patch-merge-tmp-* &&
-               mkdir .patch-merge-tmp-dir || break
-               (
-                       cd .patch-merge-tmp-dir &&
-                       GIT_INDEX_FILE=../.patch-merge-tmp-index &&
-                       GIT_OBJECT_DIRECTORY="$O_OBJECT" &&
-                       export GIT_INDEX_FILE GIT_OBJECT_DIRECTORY &&
-                       git-read-tree "$base" &&
-                       git-apply --index &&
-                       mv ../.patch-merge-tmp-index ../.patch-merge-index &&
-                       echo "$base" >../.patch-merge-base
-               ) <"$PATCHFILE"  2>/dev/null && break
-           done
-       fi
-
-       test -f .patch-merge-index &&
-       his_tree=$(GIT_INDEX_FILE=.patch-merge-index git-write-tree) &&
-       orig_tree=$(cat .patch-merge-base) &&
-       rm -fr .patch-merge-* || exit 1
-
-       echo Falling back to patching base and 3-way merge using $orig_tree...
-
-       # This is not so wrong.  Depending on which base we picked,
-       # orig_tree may be wildly different from ours, but his_tree
-       # has the same set of wildly different changes in parts the
-       # patch did not touch, so resolve ends up canceling them,
-       # saying that we reverted all those changes.
-
-       if git-merge-resolve $orig_tree -- HEAD $his_tree
-       then
-               echo Done.
-       else
-               echo Failed to merge in the changes.
-               exit 1
-       fi
-}
-
-if test -x "$GIT_DIR"/hooks/pre-applypatch
-then
-       "$GIT_DIR"/hooks/pre-applypatch || exit
-fi
-
-tree=$(git-write-tree) || exit 1
-echo Wrote tree $tree
-parent=$(git-rev-parse --verify HEAD) &&
-commit=$(git-commit-tree $tree -p $parent <"$final") || exit 1
-echo Committed: $commit
-git-update-ref -m "applypatch: $SUBJECT" HEAD $commit $parent || exit
-
-if test -x "$GIT_DIR"/hooks/post-applypatch
-then
-       "$GIT_DIR"/hooks/post-applypatch
-fi
index c1e7c1ddcbbf45995b53785a0f39314f6d499d2c..b21077206a93139fd8652d5174817e18c89ba22e 100755 (executable)
@@ -3,19 +3,19 @@
 # This tool is copyright (c) 2005, Martin Langhoff.
 # It is released under the Gnu Public License, version 2.
 #
-# The basic idea is to walk the output of tla abrowse, 
-# fetch the changesets and apply them. 
+# The basic idea is to walk the output of tla abrowse,
+# fetch the changesets and apply them.
 #
 
 =head1 Invocation
 
-    git-archimport [ -h ] [ -v ] [ -o ] [ -a ] [ -f ] [ -T ] 
-       [ -D depth] [ -t tempdir ] <archive>/<branch> [ <archive>/<branch> ]
+    git-archimport [ -h ] [ -v ] [ -o ] [ -a ] [ -f ] [ -T ]
+       [ -D depth] [ -t tempdir ] <archive>/<branch> [ <archive>/<branch> ]
 
 Imports a project from one or more Arch repositories. It will follow branches
 and repositories within the namespaces defined by the <archive/branch>
 parameters supplied. If it cannot find the remote branch a merge comes from
-it will just import it as a regular commit. If it can find it, it will mark it 
+it will just import it as a regular commit. If it can find it, it will mark it
 as a merge whenever possible.
 
 See man (1) git-archimport for more details.
@@ -25,14 +25,14 @@ See man (1) git-archimport for more details.
  - create tag objects instead of ref tags
  - audit shell-escaping of filenames
  - hide our private tags somewhere smarter
- - find a way to make "cat *patches | patch" safe even when patchfiles are missing newlines  
+ - find a way to make "cat *patches | patch" safe even when patchfiles are missing newlines
  - sort and apply patches by graphing ancestry relations instead of just
    relying in dates supplied in the changeset itself.
    tla ancestry-graph -m could be helpful here...
 
 =head1 Devel tricks
 
-Add print in front of the shell commands invoked via backticks. 
+Add print in front of the shell commands invoked via backticks.
 
 =head1 Devel Notes
 
@@ -126,16 +126,16 @@ sub do_abrowse {
     my $stage = shift;
     while (my ($limit, $level) = each %arch_branches) {
         next unless $level == $stage;
-        
-       open ABROWSE, "$TLA abrowse -fkD --merges $limit |" 
+
+       open ABROWSE, "$TLA abrowse -fkD --merges $limit |"
                                 or die "Problems with tla abrowse: $!";
-    
+
         my %ps        = ();         # the current one
         my $lastseen  = '';
-    
+
         while (<ABROWSE>) {
             chomp;
-            
+
             # first record padded w 8 spaces
             if (s/^\s{8}\b//) {
                 my ($id, $type) = split(m/\s+/, $_, 2);
@@ -147,13 +147,13 @@ sub do_abrowse {
                     push (@psets, \%last_ps);
                     $psets{ $last_ps{id} } = \%last_ps;
                 }
-                
+
                 my $branch = extract_versionname($id);
                 %ps = ( id => $id, branch => $branch );
                 if (%last_ps && ($last_ps{branch} eq $branch)) {
                     $ps{parent_id} = $last_ps{id};
                 }
-                
+
                 $arch_branches{$branch} = 1;
                 $lastseen = 'id';
 
@@ -166,16 +166,16 @@ sub do_abrowse {
                     $ps{type} = 't';
                     # read which revision we've tagged when we parse the log
                     $ps{tag}  = $1;
-                } else { 
+                } else {
                     warn "Unknown type $type";
                 }
 
                 $arch_branches{$branch} = 1;
                 $lastseen = 'id';
-            } elsif (s/^\s{10}//) { 
-                # 10 leading spaces or more 
+            } elsif (s/^\s{10}//) {
+                # 10 leading spaces or more
                 # indicate commit metadata
-                
+
                 # date
                 if ($lastseen eq 'id' && m/^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d)/){
                     $ps{date}   = $1;
@@ -186,12 +186,12 @@ sub do_abrowse {
                 } elsif ($lastseen eq 'merges' && s/^\s{2}//) {
                     my $id = $_;
                     push (@{$ps{merges}}, $id);
-                   
+
                     # aggressive branch finding:
                     if ($opt_D) {
                         my $branch = extract_versionname($id);
                         my $repo = extract_reponame($branch);
-                        
+
                         if (archive_reachable($repo) &&
                                 !defined $arch_branches{$branch}) {
                             $arch_branches{$branch} = $stage + 1;
@@ -208,10 +208,10 @@ sub do_abrowse {
             if (@psets && $psets[$#psets]{branch} eq $ps{branch}) {
                 $temp{parent_id} = $psets[$#psets]{id};
             }
-            push (@psets, \%temp);  
+            push (@psets, \%temp);
             $psets{ $temp{id} } = \%temp;
-        }    
-        
+        }
+
         close ABROWSE or die "$TLA abrowse failed on $limit\n";
     }
 }                               # end foreach $root
@@ -253,7 +253,7 @@ unless (-d $git_dir) { # initial import
     while (my $file = readdir(DIR)) {
         # skip non-interesting-files
         next unless -f "$ptag_dir/$file";
-   
+
         # convert first '--' to '/' from old git-archimport to use
         # as an archivename/c--b--v private tag
         if ($file !~ m!,!) {
@@ -275,7 +275,7 @@ sub extract_reponame {
     my $fq_cvbr = shift; # archivename/[[[[category]branch]version]revision]
     return (split(/\//, $fq_cvbr))[0];
 }
+
 sub extract_versionname {
     my $name = shift;
     $name =~ s/--(?:patch|version(?:fix)?|base)-\d+$//;
@@ -283,7 +283,7 @@ sub extract_versionname {
 }
 
 # convert a fully-qualified revision or version to a unique dirname:
-#   normalperson@yhbt.net-05/mpd--uclinux--1--patch-2 
+#   normalperson@yhbt.net-05/mpd--uclinux--1--patch-2
 # becomes: normalperson@yhbt.net-05,mpd--uclinux--1
 #
 # the git notion of a branch is closer to
@@ -339,7 +339,7 @@ sub git_branchname {
 
 sub process_patchset_accurate {
     my $ps = shift;
-    
+
     # switch to that branch if we're not already in that branch:
     if (-e "$git_dir/refs/heads/$ps->{branch}") {
        system('git-checkout','-f',$ps->{branch}) == 0 or die "$! $?\n";
@@ -348,7 +348,7 @@ sub process_patchset_accurate {
        my $rm = safe_pipe_capture('git-ls-files','--others','-z');
        rmtree(split(/\0/,$rm)) if $rm;
     }
-    
+
     # Apply the import/changeset/merge into the working tree
     my $dir = sync_to_ps($ps);
     # read the new log entry:
@@ -361,9 +361,9 @@ sub process_patchset_accurate {
     parselog($ps, \@commitlog);
 
     if ($ps->{id} =~ /--base-0$/ && $ps->{id} ne $psets[0]{id}) {
-        # this should work when importing continuations 
+        # this should work when importing continuations
         if ($ps->{tag} && (my $branchpoint = eval { ptag($ps->{tag}) })) {
-            
+
             # find where we are supposed to branch from
            if (! -e "$git_dir/refs/heads/$ps->{branch}") {
                system('git-branch',$ps->{branch},$branchpoint) == 0 or die "$! $?\n";
@@ -388,8 +388,8 @@ sub process_patchset_accurate {
         }
         # allow multiple bases/imports here since Arch supports cherry-picks
         # from unrelated trees
-    } 
-    
+    }
+
     # update the index with all the changes we got
     system('git-diff-files --name-only -z | '.
             'git-update-index --remove -z --stdin') == 0 or die "$! $?\n";
@@ -402,7 +402,7 @@ sub process_patchset_accurate {
 # does not handle permissions or any renames involving directories
 sub process_patchset_fast {
     my $ps = shift;
-    # 
+    #
     # create the branch if needed
     #
     if ($ps->{type} eq 'i' && !$import) {
@@ -417,9 +417,9 @@ sub process_patchset_fast {
             # new branch! we need to verify a few things
             die "Branch on a non-tag!" unless $ps->{type} eq 't';
             my $branchpoint = ptag($ps->{tag});
-            die "Tagging from unknown id unsupported: $ps->{tag}" 
+            die "Tagging from unknown id unsupported: $ps->{tag}"
                 unless $branchpoint;
-            
+
             # find where we are supposed to branch from
            if (! -e "$git_dir/refs/heads/$ps->{branch}") {
                system('git-branch',$ps->{branch},$branchpoint) == 0 or die "$! $?\n";
@@ -435,13 +435,13 @@ sub process_patchset_fast {
             }
             system('git-checkout',$ps->{branch}) == 0 or die "$! $?\n";
             return 0;
-        } 
+        }
         die $! if $?;
-    } 
+    }
 
     #
     # Apply the import/changeset/merge into the working tree
-    # 
+    #
     if ($ps->{type} eq 'i' || $ps->{type} eq 't') {
         apply_import($ps) or die $!;
         $stats{import_or_tag}++;
@@ -455,10 +455,10 @@ sub process_patchset_fast {
     # prepare update git's index, based on what arch knows
     # about the pset, resolve parents, etc
     #
-    
-    my @commitlog = safe_pipe_capture($TLA,'cat-archive-log',$ps->{id}); 
+
+    my @commitlog = safe_pipe_capture($TLA,'cat-archive-log',$ps->{id});
     die "Error in cat-archive-log: $!" if $?;
-        
+
     parselog($ps,\@commitlog);
 
     # imports don't give us good info
@@ -485,10 +485,10 @@ sub process_patchset_fast {
         if (@$ren % 2) {
             die "Odd number of entries in rename!?";
         }
-        
+
         while (@$ren) {
             my $from = shift @$ren;
-            my $to   = shift @$ren;           
+            my $to   = shift @$ren;
 
             unless (-d dirname($to)) {
                 mkpath(dirname($to)); # will die on err
@@ -529,20 +529,20 @@ if ($opt_f) {
             "Things may be a bit slow\n";
     *process_patchset = *process_patchset_accurate;
 }
-    
+
 foreach my $ps (@psets) {
     # process patchsets
     $ps->{branch} = git_branchname($ps->{id});
 
     #
-    # ensure we have a clean state 
-    # 
+    # ensure we have a clean state
+    #
     if (my $dirty = `git-diff-files`) {
         die "Unclean tree when about to process $ps->{id} " .
             " - did we fail to commit cleanly before?\n$dirty";
     }
     die $! if $?;
-    
+
     #
     # skip commits already in repo
     #
@@ -559,7 +559,7 @@ foreach my $ps (@psets) {
     my $tree = `git-write-tree`;
     die "cannot write tree $!" if $?;
     chomp $tree;
-    
+
     #
     # Who's your daddy?
     #
@@ -570,18 +570,18 @@ foreach my $ps (@psets) {
             close HEAD;
             chomp $p;
             push @par, '-p', $p;
-        } else { 
+        } else {
             if ($ps->{type} eq 's') {
                 warn "Could not find the right head for the branch $ps->{branch}";
             }
         }
     }
-    
+
     if ($ps->{merges}) {
         push @par, find_parents($ps);
     }
 
-    #    
+    #
     # Commit, tag and clean state
     #
     $ENV{TZ}                  = 'GMT';
@@ -592,14 +592,14 @@ foreach my $ps (@psets) {
     $ENV{GIT_COMMITTER_EMAIL} = $ps->{email};
     $ENV{GIT_COMMITTER_DATE}  = $ps->{date};
 
-    my $pid = open2(*READER, *WRITER,'git-commit-tree',$tree,@par) 
+    my $pid = open2(*READER, *WRITER,'git-commit-tree',$tree,@par)
         or die $!;
     print WRITER $ps->{summary},"\n\n";
     print WRITER $ps->{message},"\n";
-    
+
     # make it easy to backtrack and figure out which Arch revision this was:
     print WRITER 'git-archimport-id: ',$ps->{id},"\n";
-    
+
     close WRITER;
     my $commitid = <READER>;    # read
     chomp $commitid;
@@ -611,7 +611,7 @@ foreach my $ps (@psets) {
     }
     #
     # Update the branch
-    # 
+    #
     open  HEAD, ">","$git_dir/refs/heads/$ps->{branch}";
     print HEAD $commitid;
     close HEAD;
@@ -640,7 +640,7 @@ exit 0;
 sub sync_to_ps {
     my $ps = shift;
     my $tree_dir = $tmp.'/'.tree_dirname($ps->{id});
-    
+
     $opt_v && print "sync_to_ps($ps->{id}) method: ";
 
     if (-d $tree_dir) {
@@ -674,7 +674,7 @@ sub sync_to_ps {
         safe_pipe_capture($TLA,'get','--no-pristine',$ps->{id},$tree_dir);
         $stats{get_new}++;
     }
-   
+
     # added -I flag to rsync since we're going to fast! AIEEEEE!!!!
     system('rsync','-aI','--delete','--exclude',$git_dir,
 #               '--exclude','.arch-inventory',
@@ -691,15 +691,15 @@ sub apply_import {
     mkpath($tmp);
 
     safe_pipe_capture($TLA,'get','-s','--no-pristine',$ps->{id},"$tmp/import");
-    die "Cannot get import: $!" if $?;    
+    die "Cannot get import: $!" if $?;
     system('rsync','-aI','--delete', '--exclude',$git_dir,
                '--exclude','.arch-ids','--exclude','{arch}',
                "$tmp/import/", './');
     die "Cannot rsync import:$!" if $?;
-    
+
     rmtree("$tmp/import");
     die "Cannot remove tempdir: $!" if $?;
-    
+
 
     return 1;
 }
@@ -712,13 +712,13 @@ sub apply_cset {
     # get the changeset
     safe_pipe_capture($TLA,'get-changeset',$ps->{id},"$tmp/changeset");
     die "Cannot get changeset: $!" if $?;
-    
+
     # apply patches
     if (`find $tmp/changeset/patches -type f -name '*.patch'`) {
         # this can be sped up considerably by doing
         #    (find | xargs cat) | patch
         # but that can get mucked up by patches
-        # with missing trailing newlines or the standard 
+        # with missing trailing newlines or the standard
         # 'missing newline' flag in the patch - possibly
         # produced with an old/buggy diff.
         # slow and safe, we invoke patch once per patchfile
@@ -741,7 +741,7 @@ sub apply_cset {
 
     # bring in new files
     system('rsync','-aI','--exclude',$git_dir,
-               '--exclude','.arch-ids',
+               '--exclude','.arch-ids',
                '--exclude', '{arch}',
                "$tmp/changeset/new-files-archive/",'./');
 
@@ -789,7 +789,7 @@ sub parselog {
         removed_files => 1,
         removed_directories => 1,
     );
-    
+
     chomp (@$log);
     while ($_ = shift @$log) {
         if (/^Continuation-of:\s*(.*)/) {
@@ -828,7 +828,7 @@ sub parselog {
             }
         }
     }
-   
+
     # drop leading empty lines from the log message
     while (@$log && $log->[0] eq '') {
        shift @$log;
@@ -842,7 +842,7 @@ sub parselog {
        $ps->{summary} = $log->[0] . '...';
     }
     $ps->{message} = join("\n",@$log);
-    
+
     # skip Arch control files, unescape pika-escaped files
     foreach my $k (keys %want_headers) {
         next unless (defined $ps->{$k});
@@ -867,7 +867,7 @@ sub parselog {
 # write/read a tag
 sub tag {
     my ($tag, $commit) = @_;
+
     if ($opt_o) {
         $tag =~ s|/|--|g;
     } else {
@@ -875,7 +875,7 @@ sub tag {
        $patchname =~ s/.*--//;
         $tag = git_branchname ($tag) . '--' . $patchname;
     }
-    
+
     if ($commit) {
         open(C,">","$git_dir/refs/tags/$tag")
             or die "Cannot create tag $tag: $!\n";
@@ -902,8 +902,8 @@ sub ptag {
     my ($tag, $commit) = @_;
 
     # don't use subdirs for tags yet, it could screw up other porcelains
-    $tag =~ s|/|,|g; 
-    
+    $tag =~ s|/|,|g;
+
     my $tag_file = "$ptag_dir/$tag";
     my $tag_branch_dir = dirname($tag_file);
     mkpath($tag_branch_dir) unless (-d $tag_branch_dir);
@@ -915,7 +915,7 @@ sub ptag {
             or die "Cannot write tag $tag: $!\n";
         close(C)
             or die "Cannot write tag $tag: $!\n";
-       $rptags{$commit} = $tag 
+       $rptags{$commit} = $tag
            unless $tag =~ m/--base-0$/;
     } else {                    # read
         # if the tag isn't there, return 0
@@ -941,7 +941,7 @@ sub find_parents {
     # Identify what branches are merging into me
     # and whether we are fully merged
     # git-merge-base <headsha> <headsha> should tell
-    # me what the base of the merge should be 
+    # me what the base of the merge should be
     #
     my $ps = shift;
 
@@ -963,14 +963,14 @@ sub find_parents {
     }
 
     #
-    # foreach branch find a merge base and walk it to the 
+    # foreach branch find a merge base and walk it to the
     # head where we are, collecting the merged patchsets that
     # Arch has recorded. Keep that in @have
     # Compare that with the commits on the other branch
     # between merge-base and the tip of the branch (@need)
     # and see if we have a series of consecutive patches
     # starting from the merge base. The tip of the series
-    # of consecutive patches merged is our new parent for 
+    # of consecutive patches merged is our new parent for
     # that branch.
     #
     foreach my $branch (keys %branches) {
@@ -979,13 +979,13 @@ sub find_parents {
        next unless -e "$git_dir/refs/heads/$branch";
 
        my $mergebase = `git-merge-base $branch $ps->{branch}`;
-       if ($?) { 
-           # Don't die here, Arch supports one-way cherry-picking
-           # between branches with no common base (or any relationship
-           # at all beforehand)
-           warn "Cannot find merge base for $branch and $ps->{branch}";
-           next;
-       }
+       if ($?) {
+           # Don't die here, Arch supports one-way cherry-picking
+           # between branches with no common base (or any relationship
+           # at all beforehand)
+           warn "Cannot find merge base for $branch and $ps->{branch}";
+           next;
+       }
        chomp $mergebase;
 
        # now walk up to the mergepoint collecting what patches we have
@@ -1010,7 +1010,7 @@ sub find_parents {
        # merge what we have with what ancestors have
        %have = (%have, %ancestorshave);
 
-       # see what the remote branch has - these are the merges we 
+       # see what the remote branch has - these are the merges we
        # will want to have in a consecutive series from the mergebase
        my $otherbranchtip = git_rev_parse($branch);
        my @needraw = `git-rev-list --topo-order $otherbranchtip ^$mergebase`;
@@ -1018,7 +1018,7 @@ sub find_parents {
        foreach my $needps (@needraw) {         # get the psets
            $needps = commitid2pset($needps);
            # git-rev-list will also
-           # list commits merged in via earlier 
+           # list commits merged in via earlier
            # merges. we are only interested in commits
            # from the branch we're looking at
            if ($branch eq $needps->{branch}) {
@@ -1054,7 +1054,7 @@ sub find_parents {
        next unless ref    $psets{$p}{merges};
        my @merges = @{$psets{$p}{merges}};
        foreach my $merge (@merges) {
-           if ($parents{$merge}) { 
+           if ($parents{$merge}) {
                delete $parents{$merge};
            }
        }
@@ -1079,10 +1079,10 @@ sub git_rev_parse {
 sub commitid2pset {
     my $commitid = shift;
     chomp $commitid;
-    my $name = $rptags{$commitid} 
+    my $name = $rptags{$commitid}
        || die "Cannot find reverse tag mapping for $commitid";
     $name =~ s|,|/|;
-    my $ps   = $psets{$name} 
+    my $ps   = $psets{$name}
        || (print Dumper(sort keys %psets)) && die "Cannot find patchset for $name";
     return $ps;
 }
@@ -1112,7 +1112,7 @@ sub archive_reachable {
     my $archive = shift;
     return 1 if $reachable{$archive};
     return 0 if $unreachable{$archive};
-    
+
     if (system "$TLA whereis-archive $archive >/dev/null") {
         if ($opt_a && (system($TLA,'register-archive',
                       "http://mirrors.sourcecontrol.net/$archive") == 0)) {
@@ -1127,4 +1127,3 @@ sub archive_reachable {
         return 1;
     }
 }
-
index 1cd456173dc386528cbbbca35e327badf97a25e2..388887a556e47fa803c1965777d52532ac233b05 100755 (executable)
@@ -56,7 +56,7 @@ bisect_start() {
        # Verify HEAD. If we were bisecting before this, reset to the
        # top-of-line master first!
        #
-       head=$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD) ||
+       head=$(GIT_DIR="$GIT_DIR" git symbolic-ref HEAD) ||
        die "Bad HEAD - I need a symbolic ref"
        case "$head" in
        refs/heads/bisect)
@@ -99,7 +99,7 @@ bisect_start() {
                break
                ;;
            *)
-               rev=$(git-rev-parse --verify "$arg^{commit}" 2>/dev/null) || {
+               rev=$(git rev-parse --verify "$arg^{commit}" 2>/dev/null) || {
                    test $has_double_dash -eq 1 &&
                        die "'$arg' does not appear to be a valid revision"
                    break
@@ -124,9 +124,9 @@ bisect_bad() {
        bisect_autostart
        case "$#" in
        0)
-               rev=$(git-rev-parse --verify HEAD) ;;
+               rev=$(git rev-parse --verify HEAD) ;;
        1)
-               rev=$(git-rev-parse --verify "$1^{commit}") ;;
+               rev=$(git rev-parse --verify "$1^{commit}") ;;
        *)
                usage ;;
        esac || exit
@@ -138,19 +138,19 @@ bisect_bad() {
 bisect_write_bad() {
        rev="$1"
        echo "$rev" >"$GIT_DIR/refs/bisect/bad"
-       echo "# bad: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
+       echo "# bad: "$(git show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
 }
 
 bisect_good() {
        bisect_autostart
         case "$#" in
-       0)    revs=$(git-rev-parse --verify HEAD) || exit ;;
-       *)    revs=$(git-rev-parse --revs-only --no-flags "$@") &&
+       0)    revs=$(git rev-parse --verify HEAD) || exit ;;
+       *)    revs=$(git rev-parse --revs-only --no-flags "$@") &&
                test '' != "$revs" || die "Bad rev input: $@" ;;
        esac
        for rev in $revs
        do
-               rev=$(git-rev-parse --verify "$rev^{commit}") || exit
+               rev=$(git rev-parse --verify "$rev^{commit}") || exit
                bisect_write_good "$rev"
                echo "git-bisect good $rev" >>"$GIT_DIR/BISECT_LOG"
 
@@ -161,7 +161,7 @@ bisect_good() {
 bisect_write_good() {
        rev="$1"
        echo "$rev" >"$GIT_DIR/refs/bisect/good-$rev"
-       echo "# good: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
+       echo "# good: "$(git show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
 }
 
 bisect_next_check() {
@@ -211,10 +211,10 @@ bisect_next() {
        bisect_autostart
        bisect_next_check good
 
-       bad=$(git-rev-parse --verify refs/bisect/bad) &&
+       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 $good $bad --" &&
+       eval="git rev-list --bisect-vars $good $bad --" &&
        eval="$eval $(cat "$GIT_DIR/BISECT_NAMES")" &&
        eval=$(eval "$eval") &&
        eval "$eval" || exit
@@ -225,7 +225,7 @@ bisect_next() {
        fi
        if [ "$bisect_rev" = "$bad" ]; then
                echo "$bisect_rev is first bad commit"
-               git-diff-tree --pretty $bisect_rev
+               git diff-tree --pretty $bisect_rev
                exit 0
        fi
 
@@ -233,8 +233,8 @@ bisect_next() {
        echo "$bisect_rev" >"$GIT_DIR/refs/heads/new-bisect"
        git checkout -q new-bisect || exit
        mv "$GIT_DIR/refs/heads/new-bisect" "$GIT_DIR/refs/heads/bisect" &&
-       GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD refs/heads/bisect
-       git-show-branch "$bisect_rev"
+       GIT_DIR="$GIT_DIR" git symbolic-ref HEAD refs/heads/bisect
+       git show-branch "$bisect_rev"
 }
 
 bisect_visualize() {
@@ -250,7 +250,7 @@ bisect_reset() {
           else
               branch=master
           fi ;;
-       1) git-show-ref --verify --quiet -- "refs/heads/$1" || {
+       1) git show-ref --verify --quiet -- "refs/heads/$1" || {
               echo >&2 "$1 does not seem to be a valid branch"
               exit 1
           }
@@ -288,12 +288,12 @@ bisect_replay () {
                        ;;
                good)
                        echo "$rev" >"$GIT_DIR/refs/bisect/good-$rev"
-                       echo "# good: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
+                       echo "# good: "$(git show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
                        echo "git-bisect good $rev" >>"$GIT_DIR/BISECT_LOG"
                        ;;
                bad)
                        echo "$rev" >"$GIT_DIR/refs/bisect/bad"
-                       echo "# bad: "$(git-show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
+                       echo "# bad: "$(git show-branch $rev) >>"$GIT_DIR/BISECT_LOG"
                        echo "git-bisect bad $rev" >>"$GIT_DIR/BISECT_LOG"
                        ;;
                *)
index 7c5ca3d62f85b78ec82f02c2045435d889c32cdd..17f43927aa7b766c1ba28150c4945fac7ff3e132 100755 (executable)
@@ -6,8 +6,8 @@ SUBDIRECTORY_OK=Sometimes
 require_work_tree
 
 old_name=HEAD
-old=$(git-rev-parse --verify $old_name 2>/dev/null)
-oldbranch=$(git-symbolic-ref $old_name 2>/dev/null)
+old=$(git rev-parse --verify $old_name 2>/dev/null)
+oldbranch=$(git symbolic-ref $old_name 2>/dev/null)
 new=
 new_name=
 force=
@@ -29,9 +29,9 @@ while [ "$#" != "0" ]; do
                shift
                [ -z "$newbranch" ] &&
                        die "git checkout: -b needs a branch name"
-               git-show-ref --verify --quiet -- "refs/heads/$newbranch" &&
+               git show-ref --verify --quiet -- "refs/heads/$newbranch" &&
                        die "git checkout: branch $newbranch already exists"
-               git-check-ref-format "heads/$newbranch" ||
+               git check-ref-format "heads/$newbranch" ||
                        die "git checkout: we do not like '$newbranch' as a branch name."
                ;;
        "-l")
@@ -57,20 +57,20 @@ while [ "$#" != "0" ]; do
                usage
                ;;
        *)
-               if rev=$(git-rev-parse --verify "$arg^0" 2>/dev/null)
+               if rev=$(git rev-parse --verify "$arg^0" 2>/dev/null)
                then
                        if [ -z "$rev" ]; then
                                echo "unknown flag $arg"
                                exit 1
                        fi
                        new_name="$arg"
-                       if git-show-ref --verify --quiet -- "refs/heads/$arg"
+                       if git show-ref --verify --quiet -- "refs/heads/$arg"
                        then
-                               rev=$(git-rev-parse --verify "refs/heads/$arg^0")
+                               rev=$(git rev-parse --verify "refs/heads/$arg^0")
                                branch="$arg"
                        fi
                        new="$rev"
-               elif rev=$(git-rev-parse --verify "$arg^{tree}" 2>/dev/null)
+               elif rev=$(git rev-parse --verify "$arg^{tree}" 2>/dev/null)
                then
                        # checking out selected paths from a tree-ish.
                        new="$rev"
@@ -129,14 +129,14 @@ Did you intend to checkout '$@' which can not be resolved as commit?"
                # from a specific tree-ish; note that this is for
                # rescuing paths and is never meant to remove what
                # is not in the named tree-ish.
-               git-ls-tree --full-name -r "$new" "$@" |
-               git-update-index --index-info || exit $?
+               git ls-tree --full-name -r "$new" "$@" |
+               git update-index --index-info || exit $?
        fi
 
        # Make sure the request is about existing paths.
-       git-ls-files --error-unmatch -- "$@" >/dev/null || exit
-       git-ls-files -- "$@" |
-       git-checkout-index -f -u --stdin
+       git ls-files --error-unmatch -- "$@" >/dev/null || exit
+       git ls-files -- "$@" |
+       git checkout-index -f -u --stdin
        exit $?
 else
        # Make sure we did not fall back on $arg^{tree} codepath
@@ -144,7 +144,7 @@ else
        # but switching branches.
        if test '' != "$new"
        then
-               git-rev-parse --verify "$new^{commit}" >/dev/null 2>&1 ||
+               git rev-parse --verify "$new^{commit}" >/dev/null 2>&1 ||
                die "Cannot switch branch to a non-commit."
        fi
 fi
@@ -200,10 +200,10 @@ fi
 
 if [ "$force" ]
 then
-    git-read-tree $v --reset -u $new
+    git read-tree $v --reset -u $new
 else
-    git-update-index --refresh >/dev/null
-    merge_error=$(git-read-tree -m -u --exclude-per-directory=.gitignore $old $new 2>&1) || (
+    git update-index --refresh >/dev/null
+    merge_error=$(git read-tree -m -u --exclude-per-directory=.gitignore $old $new 2>&1) || (
        case "$merge" in
        '')
                echo >&2 "$merge_error"
@@ -211,7 +211,7 @@ else
        esac
 
        # Match the index to the working tree, and do a three-way.
-       git diff-files --name-only | git update-index --remove --stdin &&
+       git diff-files --name-only | git update-index --remove --stdin &&
        work=`git write-tree` &&
        git read-tree $v --reset -u $new || exit
 
@@ -246,7 +246,7 @@ else
     (exit $saved_err)
 fi
 
-# 
+#
 # Switch the HEAD pointer to the new branch if we
 # checked out a branch head, and remove any potential
 # old MERGE_HEAD's (subsequent commits will clearly not
@@ -254,12 +254,13 @@ fi
 #
 if [ "$?" -eq 0 ]; then
        if [ "$newbranch" ]; then
-               git-branch $track $newbranch_log "$newbranch" "$new_name" || exit
+               git branch $track $newbranch_log "$newbranch" "$new_name" || exit
                branch="$newbranch"
        fi
        if test -n "$branch"
        then
-               GIT_DIR="$GIT_DIR" git-symbolic-ref -m "checkout: moving to $branch" HEAD "refs/heads/$branch"
+               old_branch_name=`expr "z$oldbranch" : 'zrefs/heads/\(.*\)'`
+               GIT_DIR="$GIT_DIR" git symbolic-ref -m "checkout: moving from $old_branch_name to $branch" HEAD "refs/heads/$branch"
                if test -n "$quiet"
                then
                        true    # nothing
@@ -271,15 +272,7 @@ if [ "$?" -eq 0 ]; then
                fi
        elif test -n "$detached"
        then
-               # NEEDSWORK: we would want a command to detach the HEAD
-               # atomically, instead of this handcrafted command sequence.
-               # Perhaps:
-               #       git update-ref --detach HEAD $new
-               # or something like that...
-               #
-               git-rev-parse HEAD >"$GIT_DIR/HEAD.new" &&
-               mv "$GIT_DIR/HEAD.new" "$GIT_DIR/HEAD" &&
-               git-update-ref -m "checkout: moving to $arg" HEAD "$detached" ||
+               git update-ref --no-deref -m "checkout: moving to $arg" HEAD "$detached" ||
                        die "Cannot detach HEAD"
                if test -n "$detach_warn"
                then
index 299309d97169e6d9a52a8175dd0b8f6d54c5b369..a5cfd9f07a48b97ceebfe54e88fdcc519c3e0015 100755 (executable)
@@ -20,7 +20,7 @@ require_work_tree
 ignored=
 ignoredonly=
 cleandir=
-disabled="`git-config --bool clean.requireForce`"
+disabled="`git config --bool clean.requireForce`"
 rmf="rm -f --"
 rmrf="rm -rf --"
 rm_refuse="echo Not removing"
@@ -83,7 +83,7 @@ if [ -z "$ignored" ]; then
        fi
 fi
 
-git-ls-files --others --directory $excl ${excl_info:+"$excl_info"} -- "$@" |
+git ls-files --others --directory $excl ${excl_info:+"$excl_info"} -- "$@" |
 while read -r file; do
        if [ -d "$file" -a ! -L "$file" ]; then
                if [ -z "$cleandir" ]; then
index d45618d9afe203d103cb6cdcbd66e23b0dc42932..09225540e607c5337f6a4807a570d7e296a555b9 100755 (executable)
@@ -2,7 +2,7 @@
 #
 # Copyright (c) 2005, Linus Torvalds
 # Copyright (c) 2005, Junio C Hamano
-# 
+#
 # Clone a repository into a different directory that does not yet exist.
 
 # See git-sh-setup why.
@@ -43,7 +43,7 @@ clone_dumb_http () {
        clone_tmp="$GIT_DIR/clone-tmp" &&
        mkdir -p "$clone_tmp" || exit 1
        if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \
-               "`git-config --bool http.noEPSV`" = true ]; then
+               "`git config --bool http.noEPSV`" = true ]; then
                curl_extra_args="${curl_extra_args} --disable-epsv"
        fi
        http_fetch "$1/info/refs" "$clone_tmp/refs" ||
@@ -72,6 +72,17 @@ Perhaps git-update-server-info needs to be run there?"
        rm -fr "$clone_tmp"
        http_fetch "$1/HEAD" "$GIT_DIR/REMOTE_HEAD" ||
        rm -f "$GIT_DIR/REMOTE_HEAD"
+       if test -f "$GIT_DIR/REMOTE_HEAD"; then
+               head_sha1=`cat "$GIT_DIR/REMOTE_HEAD"`
+               case "$head_sha1" in
+               'ref: refs/'*)
+                       ;;
+               *)
+                       git-http-fetch $v -a "$head_sha1" "$1" ||
+                       rm -f "$GIT_DIR/REMOTE_HEAD"
+                       ;;
+               esac
+       fi
 }
 
 quiet=
@@ -98,7 +109,7 @@ while
        *,--na|*,--nak|*,--nake|*,--naked|\
        *,-b|*,--b|*,--ba|*,--bar|*,--bare) bare=yes ;;
        *,-l|*,--l|*,--lo|*,--loc|*,--loca|*,--local) use_local=yes ;;
-        *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared) 
+        *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared)
           local_shared=yes; use_local=yes ;;
        1,--template) usage ;;
        *,--template)
@@ -121,7 +132,7 @@ while
                */*)
                    die "'$2' is not suitable for an origin name"
                esac
-               git-check-ref-format "heads/$2" ||
+               git check-ref-format "heads/$2" ||
                    die "'$2' is not suitable for a branch name"
                test -z "$origin_override" ||
                    die "Do not give more than one --origin options."
@@ -176,15 +187,31 @@ dir="$2"
 # Try using "humanish" part of source repo if user didn't specify one
 [ -z "$dir" ] && dir=$(echo "$repo" | sed -e 's|/$||' -e 's|:*/*\.git$||' -e 's|.*[/:]||g')
 [ -e "$dir" ] && die "destination directory '$dir' already exists."
-mkdir -p "$dir" &&
-D=$(cd "$dir" && pwd) &&
-trap 'err=$?; cd ..; rm -rf "$D"; exit $err' 0
-case "$bare" in
-yes)
-       GIT_DIR="$D" ;;
-*)
-       GIT_DIR="$D/.git" ;;
-esac && export GIT_DIR && git-init ${template+"$template"} || usage
+[ yes = "$bare" ] && unset GIT_WORK_TREE
+[ -n "$GIT_WORK_TREE" ] && [ -e "$GIT_WORK_TREE" ] &&
+die "working tree '$GIT_WORK_TREE' already exists."
+D=
+W=
+cleanup() {
+       err=$?
+       test -z "$D" && rm -rf "$dir"
+       test -z "$W" && test -n "$GIT_WORK_TREE" && rm -rf "$GIT_WORK_TREE"
+       cd ..
+       test -n "$D" && rm -rf "$D"
+       test -n "$W" && rm -rf "$W"
+       exit $err
+}
+trap cleanup 0
+mkdir -p "$dir" && D=$(cd "$dir" && pwd) || usage
+test -n "$GIT_WORK_TREE" && mkdir -p "$GIT_WORK_TREE" &&
+W=$(cd "$GIT_WORK_TREE" && pwd) && export GIT_WORK_TREE="$W"
+if test yes = "$bare" || test -n "$GIT_WORK_TREE"; then
+       GIT_DIR="$D"
+else
+       GIT_DIR="$D/.git"
+fi &&
+export GIT_DIR &&
+git-init $quiet ${template+"$template"} || usage
 
 if test -n "$reference"
 then
@@ -334,11 +361,15 @@ then
                *)
                        continue ;;
                esac
-               git-update-ref -m "clone: from $repo" "$destname" "$sha1" ""
+               git update-ref -m "clone: from $repo" "$destname" "$sha1" ""
        done < "$GIT_DIR/CLONE_HEAD"
 fi
 
-cd "$D" || exit
+if test -n "$W"; then
+       cd "$W" || exit
+else
+       cd "$D" || exit
+fi
 
 if test -z "$bare" && test -f "$GIT_DIR/REMOTE_HEAD"
 then
@@ -377,37 +408,42 @@ then
                )
        )
 
+       # Upstream URL
+       git config remote."$origin".url "$repo" &&
+
+       # Set up the mappings to track the remote branches.
+       git config remote."$origin".fetch \
+               "+refs/heads/*:$remote_top/*" '^$' &&
+
        # Write out remote.$origin config, and update our "$head_points_at".
        case "$head_points_at" in
        ?*)
                # Local default branch
-               git-symbolic-ref HEAD "refs/heads/$head_points_at" &&
+               git symbolic-ref HEAD "refs/heads/$head_points_at" &&
 
                # Tracking branch for the primary branch at the remote.
-               origin_track="$remote_top/$head_points_at" &&
-               git-update-ref HEAD "$head_sha1" &&
-
-               # Upstream URL
-               git-config remote."$origin".url "$repo" &&
+               git update-ref HEAD "$head_sha1" &&
 
-               # Set up the mappings to track the remote branches.
-               git-config remote."$origin".fetch \
-                       "+refs/heads/*:$remote_top/*" '^$' &&
                rm -f "refs/remotes/$origin/HEAD"
-               git-symbolic-ref "refs/remotes/$origin/HEAD" \
+               git symbolic-ref "refs/remotes/$origin/HEAD" \
                        "refs/remotes/$origin/$head_points_at" &&
 
-               git-config branch."$head_points_at".remote "$origin" &&
-               git-config branch."$head_points_at".merge "refs/heads/$head_points_at"
+               git config branch."$head_points_at".remote "$origin" &&
+               git config branch."$head_points_at".merge "refs/heads/$head_points_at"
+               ;;
+       '')
+               # Source had detached HEAD pointing nowhere
+               git update-ref --no-deref HEAD "$head_sha1" &&
+               rm -f "refs/remotes/$origin/HEAD"
+               ;;
        esac
 
        case "$no_checkout" in
        '')
                test "z$quiet" = z -a "z$no_progress" = z && v=-v || v=
-               git-read-tree -m -u $v HEAD HEAD
+               git read-tree -m -u $v HEAD HEAD
        esac
 fi
 rm -f "$GIT_DIR/CLONE_HEAD" "$GIT_DIR/REMOTE_HEAD"
 
 trap - 0
-
index e8b60f70497c71bd66b96115b9bba78cee523a8c..f3cd8ee97839578bbfc719fd37d5b25b826623a8 100755 (executable)
@@ -8,7 +8,7 @@ SUBDIRECTORY_OK=Yes
 . git-sh-setup
 require_work_tree
 
-git-rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
+git rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
 
 case "$0" in
 *status)
@@ -53,7 +53,7 @@ run_status () {
        t) color= ;;
        *) color=--nocolor ;;
        esac
-       git-runstatus ${color} \
+       git runstatus ${color} \
                ${verbose:+--verbose} \
                ${amend:+--amend} \
                ${untracked_files:+--untracked}
@@ -335,20 +335,20 @@ t,)
                cd_to_toplevel &&
                GIT_INDEX_FILE="$NEXT_INDEX" &&
                export GIT_INDEX_FILE &&
-               git-diff-files --name-only -z |
-               git-update-index --remove -z --stdin
+               git diff-files --name-only -z |
+               git update-index --remove -z --stdin
        ) || exit
        ;;
 ,t)
        save_index &&
-       git-ls-files --error-unmatch -- "$@" >/dev/null || exit
+       git ls-files --error-unmatch -- "$@" >/dev/null || exit
 
-       git-diff-files --name-only -z -- "$@"  |
+       git diff-files --name-only -z -- "$@"  |
        (
                cd_to_toplevel &&
                GIT_INDEX_FILE="$NEXT_INDEX" &&
                export GIT_INDEX_FILE &&
-               git-update-index --remove -z --stdin
+               git update-index --remove -z --stdin
        ) || exit
        ;;
 ,)
@@ -364,28 +364,28 @@ t,)
                        refuse_partial "Cannot do a partial commit during a merge."
                fi
                TMP_INDEX="$GIT_DIR/tmp-index$$"
-               commit_only=`git-ls-files --error-unmatch -- "$@"` || exit
+               commit_only=`git ls-files --error-unmatch -- "$@"` || exit
 
                # Build a temporary index and update the real index
                # the same way.
                if test -z "$initial_commit"
                then
                        GIT_INDEX_FILE="$THIS_INDEX" \
-                       git-read-tree --index-output="$TMP_INDEX" -i -m HEAD
+                       git read-tree --index-output="$TMP_INDEX" -i -m HEAD
                else
                        rm -f "$TMP_INDEX"
                fi || exit
 
                printf '%s\n' "$commit_only" |
                GIT_INDEX_FILE="$TMP_INDEX" \
-               git-update-index --add --remove --stdin &&
+               git update-index --add --remove --stdin &&
 
                save_index &&
                printf '%s\n' "$commit_only" |
                (
                        GIT_INDEX_FILE="$NEXT_INDEX"
                        export GIT_INDEX_FILE
-                       git-update-index --remove --stdin
+                       git update-index --remove --stdin
                ) || exit
                ;;
        esac
@@ -408,12 +408,12 @@ case "$status_only" in
 t)
        # This will silently fail in a read-only repository, which is
        # what we want.
-       GIT_INDEX_FILE="$USE_INDEX" git-update-index -q --unmerged --refresh
+       GIT_INDEX_FILE="$USE_INDEX" git update-index -q --unmerged --refresh
        run_status
        exit $?
        ;;
 '')
-       GIT_INDEX_FILE="$USE_INDEX" git-update-index -q --refresh || exit
+       GIT_INDEX_FILE="$USE_INDEX" git update-index -q --refresh || exit
        ;;
 esac
 
@@ -454,20 +454,22 @@ then
 elif test -f "$GIT_DIR/SQUASH_MSG"
 then
        cat "$GIT_DIR/SQUASH_MSG"
-fi | git-stripspace >"$GIT_DIR"/COMMIT_EDITMSG
+fi | git stripspace >"$GIT_DIR"/COMMIT_EDITMSG
 
 case "$signoff" in
 t)
-       need_blank_before_signoff=
+       sign=$(git-var GIT_COMMITTER_IDENT | sed -e '
+               s/>.*/>/
+               s/^/Signed-off-by: /
+               ')
+       blank_before_signoff=
        tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
-       grep 'Signed-off-by:' >/dev/null || need_blank_before_signoff=yes
-       {
-               test -z "$need_blank_before_signoff" || echo
-               git-var GIT_COMMITTER_IDENT | sed -e '
-                       s/>.*/>/
-                       s/^/Signed-off-by: /
-               '
-       } >>"$GIT_DIR"/COMMIT_EDITMSG
+       grep 'Signed-off-by:' >/dev/null || blank_before_signoff='
+'
+       tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
+       grep "$sign"$ >/dev/null ||
+       printf '%s%s\n' "$blank_before_signoff" "$sign" \
+               >>"$GIT_DIR"/COMMIT_EDITMSG
        ;;
 esac
 
@@ -483,34 +485,8 @@ fi >>"$GIT_DIR"/COMMIT_EDITMSG
 # Author
 if test '' != "$use_commit"
 then
-       pick_author_script='
-       /^author /{
-               s/'\''/'\''\\'\'\''/g
-               h
-               s/^author \([^<]*\) <[^>]*> .*$/\1/
-               s/'\''/'\''\'\'\''/g
-               s/.*/GIT_AUTHOR_NAME='\''&'\''/p
-
-               g
-               s/^author [^<]* <\([^>]*\)> .*$/\1/
-               s/'\''/'\''\'\'\''/g
-               s/.*/GIT_AUTHOR_EMAIL='\''&'\''/p
-
-               g
-               s/^author [^<]* <[^>]*> \(.*\)$/\1/
-               s/'\''/'\''\'\'\''/g
-               s/.*/GIT_AUTHOR_DATE='\''&'\''/p
-
-               q
-       }
-       '
-       encoding=$(git config i18n.commitencoding || echo UTF-8)
-       set_author_env=`git show -s --pretty=raw --encoding="$encoding" "$use_commit" |
-       LANG=C LC_ALL=C sed -ne "$pick_author_script"`
-       eval "$set_author_env"
-       export GIT_AUTHOR_NAME
-       export GIT_AUTHOR_EMAIL
-       export GIT_AUTHOR_DATE
+       eval "$(get_author_ident_from_commit "$use_commit")"
+       export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
 fi
 if test '' != "$force_author"
 then
@@ -531,12 +507,12 @@ then
                PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"`
        elif test -n "$amend"; then
                rloga='commit (amend)'
-               PARENTS=$(git-cat-file commit HEAD |
+               PARENTS=$(git cat-file commit HEAD |
                        sed -n -e '/^$/q' -e 's/^parent /-p /p')
        fi
-       current="$(git-rev-parse --verify HEAD)"
+       current="$(git rev-parse --verify HEAD)"
 else
-       if [ -z "$(git-ls-files)" ]; then
+       if [ -z "$(git ls-files)" ]; then
                echo >&2 'nothing to commit (use "git add file1 file2" to include for commit)'
                exit 1
        fi
@@ -557,7 +533,7 @@ then
        } >>"$GIT_DIR"/COMMIT_EDITMSG
 else
        # we need to check if there is anything to commit
-       run_status >/dev/null 
+       run_status >/dev/null
 fi
 if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" -a -z "$amend" ]
 then
@@ -603,23 +579,23 @@ then
 else
     cat "$GIT_DIR"/COMMIT_EDITMSG
 fi |
-git-stripspace >"$GIT_DIR"/COMMIT_MSG
+git stripspace >"$GIT_DIR"/COMMIT_MSG
 
 if cnt=`grep -v -i '^Signed-off-by' "$GIT_DIR"/COMMIT_MSG |
-       git-stripspace |
+       git stripspace |
        wc -l` &&
    test 0 -lt $cnt
 then
        if test -z "$TMP_INDEX"
        then
-               tree=$(GIT_INDEX_FILE="$USE_INDEX" git-write-tree)
+               tree=$(GIT_INDEX_FILE="$USE_INDEX" git write-tree)
        else
-               tree=$(GIT_INDEX_FILE="$TMP_INDEX" git-write-tree) &&
+               tree=$(GIT_INDEX_FILE="$TMP_INDEX" git write-tree) &&
                rm -f "$TMP_INDEX"
        fi &&
-       commit=$(cat "$GIT_DIR"/COMMIT_MSG | git-commit-tree $tree $PARENTS) &&
+       commit=$(cat "$GIT_DIR"/COMMIT_MSG | git commit-tree $tree $PARENTS) &&
        rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
-       git-update-ref -m "$GIT_REFLOG_ACTION: $rlogm" HEAD $commit "$current" &&
+       git update-ref -m "$GIT_REFLOG_ACTION: $rlogm" HEAD $commit "$current" &&
        rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" &&
        if test -f "$NEXT_INDEX"
        then
@@ -636,10 +612,7 @@ rm -f "$GIT_DIR/COMMIT_MSG" "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
 
 cd_to_toplevel
 
-if test -d "$GIT_DIR/rr-cache"
-then
-       git-rerere
-fi
+git rerere
 
 if test "$ret" = 0
 then
@@ -649,7 +622,7 @@ then
        fi
        if test -z "$quiet"
        then
-               commit=`git-diff-tree --always --shortstat --pretty="format:%h: %s"\
+               commit=`git diff-tree --always --shortstat --pretty="format:%h: %s"\
                       --summary --root HEAD --`
                echo "Created${initial_commit:+ initial} commit $commit"
        fi
index b2ab3f82567d54607a07f4061153adae86854fa9..362e040f52cf8df17811ae95e46f0b60d2b6f071 100644 (file)
@@ -287,6 +287,22 @@ static inline ssize_t xwrite(int fd, const void *buf, size_t len)
        }
 }
 
+static inline int xdup(int fd)
+{
+       int ret = dup(fd);
+       if (ret < 0)
+               die("dup failed: %s", strerror(errno));
+       return ret;
+}
+
+static inline FILE *xfdopen(int fd, const char *mode)
+{
+       FILE *stream = fdopen(fd, mode);
+       if (stream == NULL)
+               die("Out of memory? fdopen failed: %s", strerror(errno));
+       return stream;
+}
+
 static inline size_t xsize_t(off_t len)
 {
        return (size_t)len;
index d6ae99b8c00c278f6e4b0190dfb892b857f27103..e9832d2bb913d61ce8a92ddf32e009ad59659d53 100755 (executable)
@@ -15,9 +15,9 @@ unless ($ENV{GIT_DIR} && -r $ENV{GIT_DIR}){
     die "GIT_DIR is not defined or is unreadable";
 }
 
-our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d);
+our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d, $opt_u);
 
-getopts('hPpvcfam:d:');
+getopts('uhPpvcfam:d:');
 
 $opt_h && usage();
 
@@ -178,6 +178,10 @@ foreach my $f (@files) {
 
 my %cvsstat;
 if (@canstatusfiles) {
+    if ($opt_u) {
+      my @updated = safe_pipe_capture(@cvs, 'update', @canstatusfiles);
+      print @updated;
+    }
     my @cvsoutput;
     @cvsoutput= safe_pipe_capture(@cvs, 'status', @canstatusfiles);
     my $matchcount = 0;
@@ -193,7 +197,7 @@ if (@canstatusfiles) {
 # ... validate new files,
 foreach my $f (@afiles) {
     if (defined ($cvsstat{$f}) and $cvsstat{$f} ne "Unknown") {
-       $dirty = 1;
+       $dirty = 1;
        warn "File $f is already known in your CVS checkout -- perhaps it has been added by another user. Or this may indicate that it exists on a different branch. If this is the case, use -f to force the merge.\n";
        warn "Status was: $cvsstat{$f}\n";
     }
index 4e6c9c6cc7c1fbbf69c455d6095cc8d18c81de16..ba23eb8eebdb841139062d4221c87515b96d8729 100755 (executable)
@@ -29,7 +29,7 @@ use IPC::Open2;
 $SIG{'PIPE'}="IGNORE";
 $ENV{'TZ'}="UTC";
 
-our ($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,$opt_M,$opt_A,$opt_S,$opt_L, $opt_a);
+our ($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,$opt_M,$opt_A,$opt_S,$opt_L, $opt_a, $opt_r);
 my (%conv_author_name, %conv_author_email);
 
 sub usage(;$) {
@@ -40,7 +40,7 @@ Usage: ${\basename $0}     # fetch/update GIT from CVS
        [-o branch-for-HEAD] [-h] [-v] [-d CVSROOT] [-A author-conv-file]
        [-p opts-for-cvsps] [-P file] [-C GIT_repository] [-z fuzz] [-i] [-k]
        [-u] [-s subst] [-a] [-m] [-M regex] [-S regex] [-L commitlimit]
-       [CVS_module]
+       [-r remote] [CVS_module]
 END
        exit(1);
 }
@@ -114,7 +114,7 @@ sub read_repo_config {
     }
 }
 
-my $opts = "haivmkuo:d:p:C:z:s:M:P:A:S:L:";
+my $opts = "haivmkuo:d:p:r:C:z:s:M:P:A:S:L:";
 read_repo_config($opts);
 getopts($opts) or usage();
 usage if $opt_h;
@@ -134,18 +134,26 @@ if ($opt_d) {
 } else {
        usage("CVSROOT needs to be set");
 }
-$opt_o ||= "origin";
 $opt_s ||= "-";
 $opt_a ||= 0;
 
 my $git_tree = $opt_C;
 $git_tree ||= ".";
 
+my $remote;
+if (defined $opt_r) {
+       $remote = 'refs/remotes/' . $opt_r;
+       $opt_o ||= "master";
+} else {
+       $opt_o ||= "origin";
+       $remote = 'refs/heads';
+}
+
 my $cvs_tree;
 if ($#ARGV == 0) {
        $cvs_tree = $ARGV[0];
 } elsif (-f 'CVS/Repository') {
-       open my $f, '<', 'CVS/Repository' or 
+       open my $f, '<', 'CVS/Repository' or
            die 'Failed to open CVS/Repository';
        $cvs_tree = <$f>;
        chomp $cvs_tree;
@@ -434,7 +442,7 @@ sub file {
        my ($self,$fn,$rev) = @_;
        my $res;
 
-       my ($fh, $name) = tempfile('gitcvs.XXXXXX', 
+       my ($fh, $name) = tempfile('gitcvs.XXXXXX',
                    DIR => File::Spec->tmpdir(), UNLINK => 1);
 
        $self->_file($fn,$rev) and $res = $self->_line($fh);
@@ -520,9 +528,9 @@ sub is_sha1 {
 
 sub get_headref ($$) {
     my $name    = shift;
-    my $git_dir = shift; 
-    
-    my $f = "$git_dir/refs/heads/$name";
+    my $git_dir = shift;
+
+    my $f = "$git_dir/$remote/$name";
     if (open(my $fh, $f)) {
            chomp(my $r = <$fh>);
            is_sha1($r) or die "Cannot get head id for $name ($r): $!";
@@ -573,12 +581,12 @@ unless (-d $git_dir) {
 
        # Get the last import timestamps
        my $fmt = '($ref, $author) = (%(refname), %(author));';
-       open(H, "git-for-each-ref --perl --format='$fmt' refs/heads |") or
+       open(H, "git-for-each-ref --perl --format='$fmt' $remote |") or
                die "Cannot run git-for-each-ref: $!\n";
        while (defined(my $entry = <H>)) {
                my ($ref, $author);
                eval($entry) || die "cannot eval refs list: $@";
-               my ($head) = ($ref =~ m|^refs/heads/(.*)|);
+               my ($head) = ($ref =~ m|^$remote/(.*)|);
                $author =~ /^.*\s(\d+)\s[-+]\d{4}$/;
                $branch_date{$head} = $1;
        }
@@ -701,9 +709,9 @@ sub commit {
                $index{$branch} = tmpnam();
                $ENV{GIT_INDEX_FILE} = $index{$branch};
                if ($ancestor) {
-                   system("git-read-tree", $ancestor);
+                   system("git-read-tree", "$remote/$ancestor");
                } else {
-                   system("git-read-tree", $branch);
+                   system("git-read-tree", "$remote/$branch");
                }
                die "read-tree failed: $?\n" if $?;
            }
@@ -762,40 +770,17 @@ sub commit {
        waitpid($pid,0);
        die "Error running git-commit-tree: $?\n" if $?;
 
-       system("git-update-ref refs/heads/$branch $cid") == 0
+       system("git-update-ref $remote/$branch $cid") == 0
                or die "Cannot write branch $branch for update: $!\n";
 
        if ($tag) {
-               my ($in, $out) = ('','');
                my ($xtag) = $tag;
                $xtag =~ s/\s+\*\*.*$//; # Remove stuff like ** INVALID ** and ** FUNKY **
                $xtag =~ tr/_/\./ if ( $opt_u );
                $xtag =~ s/[\/]/$opt_s/g;
-               
-               my $pid = open2($in, $out, 'git-mktag');
-               print $out "object $cid\n".
-                   "type commit\n".
-                   "tag $xtag\n".
-                   "tagger $author_name <$author_email>\n"
-                   or die "Cannot create tag object $xtag: $!\n";
-               close($out)
-                   or die "Cannot create tag object $xtag: $!\n";
-
-               my $tagobj = <$in>;
-               chomp $tagobj;
-
-               if ( !close($in) or waitpid($pid, 0) != $pid or
-                    $? != 0 or $tagobj !~ /^[0123456789abcdef]{40}$/ ) {
-                   die "Cannot create tag object $xtag: $!\n";
-               }
-               
-
-               open(C,">$git_dir/refs/tags/$xtag")
+
+               system('git-tag', $xtag, $cid) == 0
                        or die "Cannot create tag $xtag: $!\n";
-               print C "$tagobj\n"
-                       or die "Cannot write tag $xtag: $!\n";
-               close(C)
-                       or die "Cannot write tag $xtag: $!\n";
 
                print "Created tag '$xtag' on '$branch'\n" if $opt_v;
        }
@@ -883,12 +868,12 @@ while (<CVS>) {
                                print STDERR "Branch $branch erroneously stems from itself -- changed ancestor to $opt_o\n";
                                $ancestor = $opt_o;
                        }
-                       if (-f "$git_dir/refs/heads/$branch") {
+                       if (-f "$git_dir/$remote/$branch") {
                                print STDERR "Branch $branch already exists!\n";
                                $state=11;
                                next;
                        }
-                       unless (open(H,"$git_dir/refs/heads/$ancestor")) {
+                       unless (open(H,"$git_dir/$remote/$ancestor")) {
                                print STDERR "Branch $ancestor does not exist!\n";
                                $ignorebranch{$branch} = 1;
                                $state=11;
@@ -896,7 +881,7 @@ while (<CVS>) {
                        }
                        chomp(my $id = <H>);
                        close(H);
-                       unless (open(H,"> $git_dir/refs/heads/$branch")) {
+                       unless (open(H,"> $git_dir/$remote/$branch")) {
                                print STDERR "Could not create branch $branch: $!\n";
                                $ignorebranch{$branch} = 1;
                                $state=11;
@@ -1010,17 +995,19 @@ if ($orig_branch) {
                die "Fast-forward update failed: $?\n" if $?;
        }
        else {
-               system(qw(git-merge cvsimport HEAD), "refs/heads/$opt_o");
+               system(qw(git-merge cvsimport HEAD), "$remote/$opt_o");
                die "Could not merge $opt_o into the current branch.\n" if $?;
        }
 } else {
        $orig_branch = "master";
        print "DONE; creating $orig_branch branch\n" if $opt_v;
-       system("git-update-ref", "refs/heads/master", "refs/heads/$opt_o")
+       system("git-update-ref", "refs/heads/master", "$remote/$opt_o")
                unless -f "$git_dir/refs/heads/master";
+       system("git-symbolic-ref", "$remote/HEAD", "$remote/$opt_o")
+               if ($opt_r && $opt_o ne 'HEAD');
        system('git-update-ref', 'HEAD', "$orig_branch");
        unless ($opt_i) {
-               system('git checkout');
+               system('git checkout -f');
                die "checkout failed: $?\n" if $?;
        }
 }
index 1de517791f8a293a9c770f6260ff48f9719845ad..10aba507d731b977d354fcbf67ecf9112ec1579c 100755 (executable)
@@ -22,6 +22,9 @@ use bytes;
 use Fcntl;
 use File::Temp qw/tempdir tempfile/;
 use File::Basename;
+use Getopt::Long qw(:config require_order no_ignore_case);
+
+my $VERSION = '@@GIT_VERSION@@';
 
 my $log = GITCVS::log->new();
 my $cfg;
@@ -85,19 +88,62 @@ my $methods = {
 my $state = { prependdir => '' };
 $log->info("--------------- STARTING -----------------");
 
+my $usage =
+    "Usage: git-cvsserver [options] [pserver|server] [<directory> ...]\n".
+    "    --base-path <path>  : Prepend to requested CVSROOT\n".
+    "    --strict-paths      : Don't allow recursing into subdirectories\n".
+    "    --export-all        : Don't check for gitcvs.enabled in config\n".
+    "    --version, -V       : Print version information and exit\n".
+    "    --help, -h, -H      : Print usage information and exit\n".
+    "\n".
+    "<directory> ... is a list of allowed directories. If no directories\n".
+    "are given, all are allowed. This is an additional restriction, gitcvs\n".
+    "access still needs to be enabled by the gitcvs.enabled config option.\n";
+
+my @opts = ( 'help|h|H', 'version|V',
+            'base-path=s', 'strict-paths', 'export-all' );
+GetOptions( $state, @opts )
+    or die $usage;
+
+if ($state->{version}) {
+    print "git-cvsserver version $VERSION\n";
+    exit;
+}
+if ($state->{help}) {
+    print $usage;
+    exit;
+}
+
 my $TEMP_DIR = tempdir( CLEANUP => 1 );
 $log->debug("Temporary directory is '$TEMP_DIR'");
 
+$state->{method} = 'ext';
+if (@ARGV) {
+    if ($ARGV[0] eq 'pserver') {
+       $state->{method} = 'pserver';
+       shift @ARGV;
+    } elsif ($ARGV[0] eq 'server') {
+       shift @ARGV;
+    }
+}
+
+# everything else is a directory
+$state->{allowed_roots} = [ @ARGV ];
+
+# don't export the whole system unless the users requests it
+if ($state->{'export-all'} && !@{$state->{allowed_roots}}) {
+    die "--export-all can only be used together with an explicit whitelist\n";
+}
+
 # if we are called with a pserver argument,
 # deal with the authentication cat before entering the
 # main loop
-$state->{method} = 'ext';
-if (@ARGV && $ARGV[0] eq 'pserver') {
-    $state->{method} = 'pserver';
+if ($state->{method} eq 'pserver') {
     my $line = <STDIN>; chomp $line;
-    unless( $line eq 'BEGIN AUTH REQUEST') {
+    unless( $line =~ /^BEGIN (AUTH|VERIFICATION) REQUEST$/) {
        die "E Do not understand $line - expecting BEGIN AUTH REQUEST\n";
     }
+    my $request = $1;
     $line = <STDIN>; chomp $line;
     req_Root('root', $line) # reuse Root
        or die "E Invalid root $line \n";
@@ -109,10 +155,11 @@ if (@ARGV && $ARGV[0] eq 'pserver') {
     }
     $line = <STDIN>; chomp $line;    # validate the password?
     $line = <STDIN>; chomp $line;
-    unless ($line eq 'END AUTH REQUEST') {
-       die "E Do not understand $line -- expecting END AUTH REQUEST\n";
+    unless ($line eq "END $request REQUEST") {
+       die "E Do not understand $line -- expecting END $request REQUEST\n";
     }
     print "I LOVE YOU\n";
+    exit if $request eq 'VERIFICATION'; # cvs login
     # and now back to our regular programme...
 }
 
@@ -165,13 +212,53 @@ sub req_Root
     my ( $cmd, $data ) = @_;
     $log->debug("req_Root : $data");
 
-    $state->{CVSROOT} = $data;
+    unless ($data =~ m#^/#) {
+       print "error 1 Root must be an absolute pathname\n";
+       return 0;
+    }
+
+    my $cvsroot = $state->{'base-path'} || '';
+    $cvsroot =~ s#/+$##;
+    $cvsroot .= $data;
+
+    if ($state->{CVSROOT}
+       && ($state->{CVSROOT} ne $cvsroot)) {
+       print "error 1 Conflicting roots specified\n";
+       return 0;
+    }
+
+    $state->{CVSROOT} = $cvsroot;
 
     $ENV{GIT_DIR} = $state->{CVSROOT} . "/";
+
+    if (@{$state->{allowed_roots}}) {
+       my $allowed = 0;
+       foreach my $dir (@{$state->{allowed_roots}}) {
+           next unless $dir =~ m#^/#;
+           $dir =~ s#/+$##;
+           if ($state->{'strict-paths'}) {
+               if ($ENV{GIT_DIR} =~ m#^\Q$dir\E/?$#) {
+                   $allowed = 1;
+                   last;
+               }
+           } elsif ($ENV{GIT_DIR} =~ m#^\Q$dir\E(/?$|/)#) {
+               $allowed = 1;
+               last;
+           }
+       }
+
+       unless ($allowed) {
+           print "E $ENV{GIT_DIR} does not seem to be a valid GIT repository\n";
+           print "E \n";
+           print "error 1 $ENV{GIT_DIR} is not a valid repository\n";
+           return 0;
+       }
+    }
+
     unless (-d $ENV{GIT_DIR} && -e $ENV{GIT_DIR}.'HEAD') {
        print "E $ENV{GIT_DIR} does not seem to be a valid GIT repository\n";
-        print "E \n";
-        print "error 1 $ENV{GIT_DIR} is not a valid repository\n";
+       print "E \n";
+       print "error 1 $ENV{GIT_DIR} is not a valid repository\n";
        return 0;
     }
 
@@ -194,7 +281,8 @@ sub req_Root
 
     my $enabled = ($cfg->{gitcvs}{$state->{method}}{enabled}
                   || $cfg->{gitcvs}{enabled});
-    unless ($enabled && $enabled =~ /^\s*(1|true|yes)\s*$/i) {
+    unless ($state->{'export-all'} ||
+           ($enabled && $enabled =~ /^\s*(1|true|yes)\s*$/i)) {
         print "E GITCVS emulation needs to be enabled on this repo\n";
         print "E the repo config file needs a [gitcvs] section added, and the parameter 'enabled' set to 1\n";
         print "E \n";
@@ -1725,14 +1813,14 @@ sub req_annotate
 # the second is $state->{files} which is everything after it.
 sub argsplit
 {
-    return unless( defined($state->{arguments}) and ref $state->{arguments} eq "ARRAY" );
-
-    my $type = shift;
-
     $state->{args} = [];
     $state->{files} = [];
     $state->{opt} = {};
 
+    return unless( defined($state->{arguments}) and ref $state->{arguments} eq "ARRAY" );
+
+    my $type = shift;
+
     if ( defined($type) )
     {
         my $opt = {};
index 0e05cf1195737d2c7afc4b9447d7b4105908bf77..c3a200120df636fe8db0f02902d92c351c6c5e2e 100755 (executable)
@@ -61,7 +61,7 @@ do
                quiet=--quiet
                ;;
        -v|--verbose)
-               verbose=Yes
+               verbose="$verbose"Yes
                ;;
        -k|--k|--ke|--kee|--keep)
                keep='-k -k'
@@ -117,20 +117,20 @@ append_fetch_head () {
        test -n "$verbose" && flags="$flags$LF-v"
        test -n "$force$single_force" && flags="$flags$LF-f"
        GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION" \
-               git-fetch--tool $flags append-fetch-head "$@"
+               git fetch--tool $flags append-fetch-head "$@"
 }
 
 # updating the current HEAD with git-fetch in a bare
 # repository is always fine.
 if test -z "$update_head_ok" && test $(is_bare_repository) = false
 then
-       orig_head=$(git-rev-parse --verify HEAD 2>/dev/null)
+       orig_head=$(git rev-parse --verify HEAD 2>/dev/null)
 fi
 
 # Allow --notags from remote.$1.tagopt
 case "$tags$no_tags" in
 '')
-       case "$(git-config --get "remote.$1.tagopt")" in
+       case "$(git config --get "remote.$1.tagopt")" in
        --no-tags)
                no_tags=t ;;
        esac
@@ -146,7 +146,7 @@ if test "$tags"
 then
        taglist=`IFS='  ' &&
                  echo "$ls_remote_result" |
-                 git-show-ref --exclude-existing=refs/tags/ |
+                 git show-ref --exclude-existing=refs/tags/ |
                  while read sha1 name
                  do
                        echo ".${name}:${name}"
@@ -163,18 +163,18 @@ fi
 
 fetch_all_at_once () {
 
-  eval=$(echo "$1" | git-fetch--tool parse-reflist "-")
+  eval=$(echo "$1" | git fetch--tool parse-reflist "-")
   eval "$eval"
 
     ( : subshell because we muck with IFS
       IFS="    $LF"
       (
        if test "$remote" = . ; then
-           git-show-ref $rref || echo failed "$remote"
+           git show-ref $rref || echo failed "$remote"
        elif test -f "$remote" ; then
            test -n "$shallow_depth" &&
                die "shallow clone with bundle is not supported"
-           git-bundle unbundle "$remote" $rref ||
+           git bundle unbundle "$remote" $rref ||
            echo failed "$remote"
        else
                if      test -d "$remote" &&
@@ -190,19 +190,25 @@ fetch_all_at_once () {
                        # connected to our repository's tips, in which
                        # case we do not have to do any fetch.
                        theirs=$(echo "$ls_remote_result" | \
-                               git-fetch--tool -s pick-rref "$rref" "-") &&
+                               git fetch--tool -s pick-rref "$rref" "-") &&
 
                        # This will barf when $theirs reach an object that
                        # we do not have in our repository.  Otherwise,
                        # we already have everything the fetch would bring in.
-                       git-rev-list --objects $theirs --not --all \
+                       git rev-list --objects $theirs --not --all \
                                >/dev/null 2>/dev/null
                then
                        echo "$ls_remote_result" | \
-                               git-fetch--tool pick-rref "$rref" "-"
+                               git fetch--tool pick-rref "$rref" "-"
                else
+                       flags=
+                       case $verbose in
+                       YesYes*)
+                           flags="-v"
+                           ;;
+                       esac
                        git-fetch-pack --thin $exec $keep $shallow_depth \
-                               $quiet $no_progress "$remote" $rref ||
+                               $quiet $no_progress $flags "$remote" $rref ||
                        echo failed "$remote"
                fi
        fi
@@ -212,7 +218,7 @@ fetch_all_at_once () {
        test -n "$verbose" && flags="$flags -v"
        test -n "$force" && flags="$flags -f"
        GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION" \
-               git-fetch--tool $flags native-store \
+               git fetch--tool $flags native-store \
                        "$remote" "$remote_nick" "$refs"
       )
     ) || exit
@@ -259,13 +265,13 @@ fetch_per_ref () {
              curl_extra_args="-k"
          fi
          if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \
-               "`git-config --bool http.noEPSV`" = true ]; then
+               "`git config --bool http.noEPSV`" = true ]; then
              noepsv_opt="--disable-epsv"
          fi
 
          # Find $remote_name from ls-remote output.
          head=$(echo "$ls_remote_result" | \
-               git-fetch--tool -s pick-rref "$remote_name" "-")
+               git fetch--tool -s pick-rref "$remote_name" "-")
          expr "z$head" : "z$_x40\$" >/dev/null ||
                die "No such ref $remote_name at $remote"
          echo >&2 "Fetching $remote_name from $remote using $proto"
@@ -277,7 +283,7 @@ fetch_per_ref () {
                die "shallow clone with rsync not supported"
          TMP_HEAD="$GIT_DIR/TMP_HEAD"
          rsync -L -q "$remote/$remote_name" "$TMP_HEAD" || exit 1
-         head=$(git-rev-parse --verify TMP_HEAD)
+         head=$(git rev-parse --verify TMP_HEAD)
          rm -f "$TMP_HEAD"
          case "$quiet" in '') v=-v ;; *) v= ;; esac
          test "$rsync_slurped_objects" || {
@@ -336,10 +342,10 @@ case "$no_tags$tags" in
                # using local tracking branch.
                taglist=$(IFS=' ' &&
                echo "$ls_remote_result" |
-               git-show-ref --exclude-existing=refs/tags/ |
+               git show-ref --exclude-existing=refs/tags/ |
                while read sha1 name
                do
-                       git-cat-file -t "$sha1" >/dev/null 2>&1 || continue
+                       git cat-file -t "$sha1" >/dev/null 2>&1 || continue
                        echo >&2 "Auto-following $name"
                        echo ".${name}:${name}"
                done)
@@ -359,10 +365,10 @@ case "$orig_head" in
 '')
        ;;
 ?*)
-       curr_head=$(git-rev-parse --verify HEAD 2>/dev/null)
+       curr_head=$(git rev-parse --verify HEAD 2>/dev/null)
        if test "$curr_head" != "$orig_head"
        then
-           git-update-ref \
+           git update-ref \
                        -m "$GIT_REFLOG_ACTION: Undoing incorrectly fetched HEAD." \
                        HEAD "$orig_head"
                die "Cannot fetch into the current branch."
diff --git a/git-filter-branch.sh b/git-filter-branch.sh
new file mode 100755 (executable)
index 0000000..d77902d
--- /dev/null
@@ -0,0 +1,288 @@
+#!/bin/sh
+#
+# Rewrite revision history
+# Copyright (c) Petr Baudis, 2006
+# Minimal changes to "port" it to core-git (c) Johannes Schindelin, 2007
+#
+# Lets you rewrite the revision history of the current branch, creating
+# a new branch. You can specify a number of filters to modify the commits,
+# files and trees.
+
+set -e
+
+USAGE="git-filter-branch [-d TEMPDIR] [FILTERS] DESTBRANCH [REV-RANGE]"
+. git-sh-setup
+
+warn () {
+        echo "$*" >&2
+}
+
+map()
+{
+       # if it was not rewritten, take the original
+       if test -r "$workdir/../map/$1"
+       then
+               cat "$workdir/../map/$1"
+       else
+               echo "$1"
+       fi
+}
+
+# override die(): this version puts in an extra line break, so that
+# the progress is still visible
+
+die()
+{
+       echo >&2
+       echo "$*" >&2
+       exit 1
+}
+
+# When piped a commit, output a script to set the ident of either
+# "author" or "committer
+
+set_ident () {
+       lid="$(echo "$1" | tr "A-Z" "a-z")"
+       uid="$(echo "$1" | tr "a-z" "A-Z")"
+       pick_id_script='
+               /^'$lid' /{
+                       s/'\''/'\''\\'\'\''/g
+                       h
+                       s/^'$lid' \([^<]*\) <[^>]*> .*$/\1/
+                       s/'\''/'\''\'\'\''/g
+                       s/.*/export GIT_'$uid'_NAME='\''&'\''/p
+
+                       g
+                       s/^'$lid' [^<]* <\([^>]*\)> .*$/\1/
+                       s/'\''/'\''\'\'\''/g
+                       s/.*/export GIT_'$uid'_EMAIL='\''&'\''/p
+
+                       g
+                       s/^'$lid' [^<]* <[^>]*> \(.*\)$/\1/
+                       s/'\''/'\''\'\'\''/g
+                       s/.*/export GIT_'$uid'_DATE='\''&'\''/p
+
+                       q
+               }
+       '
+
+       LANG=C LC_ALL=C sed -ne "$pick_id_script"
+       # Ensure non-empty id name.
+       echo "[ -n \"\$GIT_${uid}_NAME\" ] || export GIT_${uid}_NAME=\"\${GIT_${uid}_EMAIL%%@*}\""
+}
+
+tempdir=.git-rewrite
+filter_env=
+filter_tree=
+filter_index=
+filter_parent=
+filter_msg=cat
+filter_commit='git commit-tree "$@"'
+filter_tag_name=
+filter_subdir=
+while case "$#" in 0) usage;; esac
+do
+       case "$1" in
+       --)
+               shift
+               break
+               ;;
+       -*)
+               ;;
+       *)
+               break;
+       esac
+
+       # all switches take one argument
+       ARG="$1"
+       case "$#" in 1) usage ;; esac
+       shift
+       OPTARG="$1"
+       shift
+
+       case "$ARG" in
+       -d)
+               tempdir="$OPTARG"
+               ;;
+       --env-filter)
+               filter_env="$OPTARG"
+               ;;
+       --tree-filter)
+               filter_tree="$OPTARG"
+               ;;
+       --index-filter)
+               filter_index="$OPTARG"
+               ;;
+       --parent-filter)
+               filter_parent="$OPTARG"
+               ;;
+       --msg-filter)
+               filter_msg="$OPTARG"
+               ;;
+       --commit-filter)
+               filter_commit="$OPTARG"
+               ;;
+       --tag-name-filter)
+               filter_tag_name="$OPTARG"
+               ;;
+       --subdirectory-filter)
+               filter_subdir="$OPTARG"
+               ;;
+       *)
+               usage
+               ;;
+       esac
+done
+
+dstbranch="$1"
+shift
+test -n "$dstbranch" || die "missing branch name"
+git show-ref "refs/heads/$dstbranch" 2> /dev/null &&
+       die "branch $dstbranch already exists"
+
+test ! -e "$tempdir" || die "$tempdir already exists, please remove it"
+mkdir -p "$tempdir/t"
+cd "$tempdir/t"
+workdir="$(pwd)"
+
+case "$GIT_DIR" in
+/*)
+       ;;
+*)
+       GIT_DIR="$(pwd)/../../$GIT_DIR"
+       ;;
+esac
+export GIT_DIR GIT_WORK_TREE=.
+
+export GIT_INDEX_FILE="$(pwd)/../index"
+git read-tree # seed the index file
+
+ret=0
+
+
+mkdir ../map # map old->new commit ids for rewriting parents
+
+case "$filter_subdir" in
+"")
+       git rev-list --reverse --topo-order --default HEAD \
+               --parents "$@"
+       ;;
+*)
+       git rev-list --reverse --topo-order --default HEAD \
+               --parents --full-history "$@" -- "$filter_subdir"
+esac > ../revs
+commits=$(cat ../revs | wc -l | tr -d " ")
+
+test $commits -eq 0 && die "Found nothing to rewrite"
+
+i=0
+while read commit parents; do
+       i=$(($i+1))
+       printf "\rRewrite $commit ($i/$commits)"
+
+       case "$filter_subdir" in
+       "")
+               git read-tree -i -m $commit
+               ;;
+       *)
+               git read-tree -i -m $commit:"$filter_subdir"
+       esac
+
+       export GIT_COMMIT=$commit
+       git cat-file commit "$commit" >../commit
+
+       eval "$(set_ident AUTHOR <../commit)" ||
+               die "setting author failed for commit $commit"
+       eval "$(set_ident COMMITTER <../commit)" ||
+               die "setting committer failed for commit $commit"
+       eval "$filter_env" < /dev/null ||
+               die "env filter failed: $filter_env"
+
+       if [ "$filter_tree" ]; then
+               git checkout-index -f -u -a
+               # files that $commit removed are now still in the working tree;
+               # remove them, else they would be added again
+               git ls-files -z --others | xargs -0 rm -f
+               eval "$filter_tree" < /dev/null ||
+                       die "tree filter failed: $filter_tree"
+
+               git diff-index -r $commit | cut -f 2- | tr '\n' '\0' | \
+                       xargs -0 git update-index --add --replace --remove
+               git ls-files -z --others | \
+                       xargs -0 git update-index --add --replace --remove
+       fi
+
+       eval "$filter_index" < /dev/null ||
+               die "index filter failed: $filter_index"
+
+       parentstr=
+       for parent in $parents; do
+               for reparent in $(map "$parent"); do
+                       parentstr="$parentstr -p $reparent"
+               done
+       done
+       if [ "$filter_parent" ]; then
+               parentstr="$(echo "$parentstr" | eval "$filter_parent")" ||
+                               die "parent filter failed: $filter_parent"
+       fi
+
+       sed -e '1,/^$/d' <../commit | \
+               eval "$filter_msg" > ../message ||
+                       die "msg filter failed: $filter_msg"
+       sh -c "$filter_commit" "git commit-tree" \
+               $(git write-tree) $parentstr < ../message > ../map/$commit
+done <../revs
+
+src_head=$(tail -n 1 ../revs | sed -e 's/ .*//')
+target_head=$(head -n 1 ../map/$src_head)
+case "$target_head" in
+'')
+       echo Nothing rewritten
+       ;;
+*)
+       git update-ref refs/heads/"$dstbranch" $target_head
+       if [ $(cat ../map/$src_head | wc -l) -gt 1 ]; then
+               echo "WARNING: Your commit filter caused the head commit to expand to several rewritten commits. Only the first such commit was recorded as the current $dstbranch head but you will need to resolve the situation now (probably by manually merging the other commits). These are all the commits:" >&2
+               sed 's/^/       /' ../map/$src_head >&2
+               ret=1
+       fi
+       ;;
+esac
+
+if [ "$filter_tag_name" ]; then
+       git for-each-ref --format='%(objectname) %(objecttype) %(refname)' refs/tags |
+       while read sha1 type ref; do
+               ref="${ref#refs/tags/}"
+               # XXX: Rewrite tagged trees as well?
+               if [ "$type" != "commit" -a "$type" != "tag" ]; then
+                       continue;
+               fi
+
+               if [ "$type" = "tag" ]; then
+                       # Dereference to a commit
+                       sha1t="$sha1"
+                       sha1="$(git rev-parse "$sha1"^{commit} 2>/dev/null)" || continue
+               fi
+
+               [ -f "../map/$sha1" ] || continue
+               new_sha1="$(cat "../map/$sha1")"
+               export GIT_COMMIT="$sha1"
+               new_ref="$(echo "$ref" | eval "$filter_tag_name")" ||
+                       die "tag name filter failed: $filter_tag_name"
+
+               echo "$ref -> $new_ref ($sha1 -> $new_sha1)"
+
+               if [ "$type" = "tag" ]; then
+                       # Warn that we are not rewriting the tag object itself.
+                       warn "unreferencing tag object $sha1t"
+               fi
+
+               git update-ref "refs/tags/$new_ref" "$new_sha1"
+       done
+fi
+
+cd ../..
+rm -rf "$tempdir"
+printf "\nRewritten history saved to the $dstbranch branch\n"
+
+exit $ret
index eee495a98666094415233a7023c03db9852dfe53..9770b0bc27ae4dfd44f4bfcfc74946fabefdc127 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=0.7.GITGUI
+DEF_VER=0.8.GITGUI
 
 LF='
 '
index ab550fc6a70f861f7e6eac5295342ccc95aee9a3..1bac6fed46635e2387d16e801294a4750476ddaa 100644 (file)
@@ -31,11 +31,35 @@ ifndef INSTALL
        INSTALL = install
 endif
 
+INSTALL_D0 = $(INSTALL) -d -m755 # space is required here
+INSTALL_D1 =
+INSTALL_R0 = $(INSTALL) -m644 # space is required here
+INSTALL_R1 =
+INSTALL_X0 = $(INSTALL) -m755 # space is required here
+INSTALL_X1 =
+INSTALL_L0 = rm -f # space is required here
+INSTALL_L1 = && ln # space is required here
+INSTALL_L2 =
+INSTALL_L3 =
+
 ifndef V
-       QUIET_GEN      = @echo '   ' GEN $@;
-       QUIET_BUILT_IN = @echo '   ' BUILTIN $@;
-       QUIET_INDEX    = @echo '   ' INDEX $(dir $@);
+       QUIET          = @
+       QUIET_GEN      = $(QUIET)echo '   ' GEN $@ &&
+       QUIET_BUILT_IN = $(QUIET)echo '   ' BUILTIN $@ &&
+       QUIET_INDEX    = $(QUIET)echo '   ' INDEX $(dir $@) &&
        QUIET_2DEVNULL = 2>/dev/null
+
+       INSTALL_D0 = dir=
+       INSTALL_D1 = && echo ' ' DEST $$dir && $(INSTALL) -d -m755 "$$dir"
+       INSTALL_R0 = src=
+       INSTALL_R1 = && echo '   ' INSTALL 644 `basename $$src` && $(INSTALL) -m644 $$src
+       INSTALL_X0 = src=
+       INSTALL_X1 = && echo '   ' INSTALL 755 `basename $$src` && $(INSTALL) -m755 $$src
+
+       INSTALL_L0 = dst=
+       INSTALL_L1 = && src=
+       INSTALL_L2 = && dst=
+       INSTALL_L3 = && echo '   ' 'LINK       ' `basename "$$dst"` '->' `basename "$$src"` && rm -f "$$dst" && ln "$$src" "$$dst"
 endif
 
 TCL_PATH   ?= tclsh
@@ -115,12 +139,12 @@ GIT-GUI-VARS: .FORCE-GIT-GUI-VARS
 all:: $(ALL_PROGRAMS) lib/tclIndex
 
 install: all
-       $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)'
-       $(INSTALL) git-gui '$(DESTDIR_SQ)$(gitexecdir_SQ)'
-       $(foreach p,$(GITGUI_BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;)
-       $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(libdir_SQ)'
-       $(INSTALL) -m644 lib/tclIndex '$(DESTDIR_SQ)$(libdir_SQ)'
-       $(foreach p,$(ALL_LIBFILES), $(INSTALL) -m644 $p '$(DESTDIR_SQ)$(libdir_SQ)' ;)
+       $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL_D1)
+       $(QUIET)$(INSTALL_X0)git-gui $(INSTALL_X1) '$(DESTDIR_SQ)$(gitexecdir_SQ)'
+       $(QUIET)$(foreach p,$(GITGUI_BUILT_INS), $(INSTALL_L0)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L1)'$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' $(INSTALL_L2)'$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' $(INSTALL_L3) &&) true
+       $(QUIET)$(INSTALL_D0)'$(DESTDIR_SQ)$(libdir_SQ)' $(INSTALL_D1)
+       $(QUIET)$(INSTALL_R0)lib/tclIndex $(INSTALL_R1) '$(DESTDIR_SQ)$(libdir_SQ)'
+       $(QUIET)$(foreach p,$(ALL_LIBFILES), $(INSTALL_R0)$p $(INSTALL_R1) '$(DESTDIR_SQ)$(libdir_SQ)' &&) true
 
 dist-version:
        @mkdir -p $(TARDIR)
index 4fbc408c4d0a1f950c7d32768ed55cbd91005023..9df2e47029cd6b7dedf0417d6028226b868e953d 100755 (executable)
@@ -42,6 +42,24 @@ if {[catch {package require Tcl 8.4} err]
        exit 1
 }
 
+######################################################################
+##
+## enable verbose loading?
+
+if {![catch {set _verbose $env(GITGUI_VERBOSE)}]} {
+       unset _verbose
+       rename auto_load real__auto_load
+       proc auto_load {name args} {
+               puts stderr "auto_load $name"
+               return [uplevel 1 real__auto_load $name $args]
+       }
+       rename source real__source
+       proc source {name} {
+               puts stderr "source    $name"
+               uplevel 1 real__source $name
+       }
+}
+
 ######################################################################
 ##
 ## configure our library
@@ -54,26 +72,33 @@ if {$oguirel eq {1}} {
 } elseif {[string match @@* $oguirel]} {
        set oguilib [file join [file dirname [file normalize $argv0]] lib]
 }
+
 set idx [file join $oguilib tclIndex]
-catch {
-       set fd [open $idx r]
-       if {[gets $fd] eq {# Autogenerated by git-gui Makefile}} {
-               set idx [list]
-               while {[gets $fd n] >= 0} {
-                       if {$n ne {} && ![string match #* $n]} {
-                               lappend idx $n
-                       }
+if {[catch {set fd [open $idx r]} err]} {
+       catch {wm withdraw .}
+       tk_messageBox \
+               -icon error \
+               -type ok \
+               -title "git-gui: fatal error" \
+               -message $err
+       exit 1
+}
+if {[gets $fd] eq {# Autogenerated by git-gui Makefile}} {
+       set idx [list]
+       while {[gets $fd n] >= 0} {
+               if {$n ne {} && ![string match #* $n]} {
+                       lappend idx $n
                }
-       } else {
-               set idx {}
        }
-       close $fd
+} else {
+       set idx {}
 }
+close $fd
+
 if {$idx ne {}} {
        set loaded [list]
        foreach p $idx {
                if {[lsearch -exact $loaded $p] >= 0} continue
-               puts $p
                source [file join $oguilib $p]
                lappend loaded $p
        }
@@ -81,21 +106,7 @@ if {$idx ne {}} {
 } else {
        set auto_path [concat [list $oguilib] $auto_path]
 }
-unset -nocomplain oguilib oguirel idx fd
-
-if {![catch {set _verbose $env(GITGUI_VERBOSE)}]} {
-       unset _verbose
-       rename auto_load real__auto_load
-       proc auto_load {name args} {
-               puts stderr "auto_load $name"
-               return [uplevel 1 real__auto_load $name $args]
-       }
-       rename source real__source
-       proc source {name} {
-               puts stderr "source    $name"
-               uplevel 1 real__source $name
-       }
-}
+unset -nocomplain oguirel idx fd
 
 ######################################################################
 ##
@@ -211,6 +222,15 @@ proc is_config_true {name} {
        }
 }
 
+proc get_config {name} {
+       global repo_config
+       if {[catch {set v $repo_config($name)}]} {
+               return {}
+       } else {
+               return $v
+       }
+}
+
 proc load_config {include_global} {
        global repo_config global_config default_config
 
@@ -264,6 +284,17 @@ proc git {args} {
        return [eval exec git $args]
 }
 
+proc current-branch {} {
+       set ref {}
+       set fd [open [gitdir HEAD] r]
+       if {[gets $fd ref] <16
+        || ![regsub {^ref: refs/heads/} $ref {} ref]} {
+               set ref {}
+       }
+       close $fd
+       return $ref
+}
+
 auto_load tk_optionMenu
 rename tk_optionMenu real__tkOptionMenu
 proc tk_optionMenu {w varName args} {
@@ -407,15 +438,7 @@ proc repository_state {ctvar hdvar mhvar} {
 
        set mh [list]
 
-       if {[catch {set current_branch [git symbolic-ref HEAD]}]} {
-               set current_branch {}
-       } else {
-               regsub ^refs/((heads|tags|remotes)/)? \
-                       $current_branch \
-                       {} \
-                       current_branch
-       }
-
+       set current_branch [current-branch]
        if {[catch {set hd [git rev-parse --verify HEAD]}]} {
                set hd {}
                set ct initial
@@ -1231,6 +1254,10 @@ foreach class {Button Checkbutton Entry Label
 }
 unset class
 
+if {[is_Windows] || [is_MacOSX]} {
+       option add *Menu.tearOff 0
+}
+
 if {[is_MacOSX]} {
        set M1B M1
        set M1T Cmd
@@ -1261,11 +1288,13 @@ proc apply_config {} {
        }
 }
 
+set default_config(merge.diffstat) true
 set default_config(merge.summary) false
 set default_config(merge.verbosity) 2
 set default_config(user.name) {}
 set default_config(user.email) {}
 
+set default_config(gui.pruneduringfetch) false
 set default_config(gui.trustmtime) false
 set default_config(gui.diffcontext) 5
 set default_config(gui.newbranchtemplate) {}
@@ -1427,6 +1456,11 @@ if {[is_enabled branch]} {
        lappend disable_on_lock [list .mbar.branch entryconf \
                [.mbar.branch index last] -state]
 
+       .mbar.branch add command -label {Rename...} \
+               -command branch_rename::dialog
+       lappend disable_on_lock [list .mbar.branch entryconf \
+               [.mbar.branch index last] -state]
+
        .mbar.branch add command -label {Delete...} \
                -command do_delete_branch
        lappend disable_on_lock [list .mbar.branch entryconf \
@@ -1524,6 +1558,8 @@ if {[is_enabled transport]} {
        menu .mbar.push
        .mbar.push add command -label {Push...} \
                -command do_push_anywhere
+       .mbar.push add command -label {Delete...} \
+               -command remote_branch_delete::dialog
 }
 
 if {[is_MacOSX]} {
@@ -1640,14 +1676,8 @@ switch -- $subcommand {
 browser {
        set subcommand_args {rev?}
        switch [llength $argv] {
-       0 {
-               set current_branch [git symbolic-ref HEAD]
-               regsub ^refs/((heads|tags|remotes)/)? \
-                       $current_branch {} current_branch
-       }
-       1 {
-               set current_branch [lindex $argv 0]
-       }
+       0 { set current_branch [current-branch] }
+       1 { set current_branch [lindex $argv 0] }
        default usage
        }
        browser::new $current_branch
@@ -1680,9 +1710,7 @@ blame {
        unset is_path
 
        if {$head eq {}} {
-               set current_branch [git symbolic-ref HEAD]
-               regsub ^refs/((heads|tags|remotes)/)? \
-                       $current_branch {} current_branch
+               set current_branch [current-branch]
        } else {
                set current_branch $head
        }
diff --git a/git-gui/lib/branch_rename.tcl b/git-gui/lib/branch_rename.tcl
new file mode 100644 (file)
index 0000000..4051016
--- /dev/null
@@ -0,0 +1,136 @@
+# git-gui branch rename support
+# Copyright (C) 2007 Shawn Pearce
+
+class branch_rename {
+
+field w
+field oldname
+field newname
+
+constructor dialog {} {
+       global all_heads current_branch
+
+       make_toplevel top w
+       wm title $top "[appname] ([reponame]): Rename Branch"
+       if {$top ne {.}} {
+               wm geometry $top "+[winfo rootx .]+[winfo rooty .]"
+       }
+
+       set oldname $current_branch
+       set newname [get_config gui.newbranchtemplate]
+
+       label $w.header -text {Rename Branch} -font font_uibold
+       pack $w.header -side top -fill x
+
+       frame $w.buttons
+       button $w.buttons.rename -text Rename \
+               -default active \
+               -command [cb _rename]
+       pack $w.buttons.rename -side right
+       button $w.buttons.cancel -text {Cancel} \
+               -command [list destroy $w]
+       pack $w.buttons.cancel -side right -padx 5
+       pack $w.buttons -side bottom -fill x -pady 10 -padx 10
+
+       frame $w.rename
+       label $w.rename.oldname_l -text {Branch:}
+       eval tk_optionMenu $w.rename.oldname_m @oldname $all_heads
+
+       label $w.rename.newname_l -text {New Name:}
+       entry $w.rename.newname_t \
+               -borderwidth 1 \
+               -relief sunken \
+               -width 40 \
+               -textvariable @newname \
+               -validate key \
+               -validatecommand {
+                       if {%d == 1 && [regexp {[~^:?*\[\0- ]} %S]} {return 0}
+                       return 1
+               }
+
+       grid $w.rename.oldname_l $w.rename.oldname_m -sticky w  -padx {0 5}
+       grid $w.rename.newname_l $w.rename.newname_t -sticky we -padx {0 5}
+       grid columnconfigure $w.rename 1 -weight 1
+       pack $w.rename -anchor nw -fill x -pady 5 -padx 5
+
+       bind $w <Key-Return> [cb _rename]
+       bind $w <Key-Escape> [list destroy $w]
+       bind $w <Visibility> "
+               grab $w
+               $w.rename.newname_t icursor end
+               focus $w.rename.newname_t
+       "
+       tkwait window $w
+}
+
+method _rename {} {
+       global all_heads current_branch
+
+       if {$oldname eq {}} {
+               tk_messageBox \
+                       -icon error \
+                       -type ok \
+                       -title [wm title $w] \
+                       -parent $w \
+                       -message "Please select a branch to rename."
+               focus $w.rename.oldname_m
+               return
+       }
+       if {$newname eq {}
+               || $newname eq [get_config gui.newbranchtemplate]} {
+               tk_messageBox \
+                       -icon error \
+                       -type ok \
+                       -title [wm title $w] \
+                       -parent $w \
+                       -message "Please supply a branch name."
+               focus $w.rename.newname_t
+               return
+       }
+       if {![catch {git show-ref --verify -- "refs/heads/$newname"}]} {
+               tk_messageBox \
+                       -icon error \
+                       -type ok \
+                       -title [wm title $w] \
+                       -parent $w \
+                       -message "Branch '$newname' already exists."
+               focus $w.rename.newname_t
+               return
+       }
+       if {[catch {git check-ref-format "heads/$newname"}]} {
+               tk_messageBox \
+                       -icon error \
+                       -type ok \
+                       -title [wm title $w] \
+                       -parent $w \
+                       -message "We do not like '$newname' as a branch name."
+               focus $w.rename.newname_t
+               return
+       }
+
+       if {[catch {git branch -m $oldname $newname} err]} {
+               tk_messageBox \
+                       -icon error \
+                       -type ok \
+                       -title [wm title $w] \
+                       -parent $w \
+                       -message "Failed to rename '$oldname'.\n\n$err"
+               return
+       }
+
+       set oldidx [lsearch -exact -sorted $all_heads $oldname]
+       if {$oldidx >= 0} {
+               set all_heads [lreplace $all_heads $oldidx $oldidx]
+       }
+       lappend all_heads $newname
+       set all_heads [lsort $all_heads]
+       populate_branch_menu
+
+       if {$current_branch eq $oldname} {
+               set current_branch $newname
+       }
+
+       destroy $w
+}
+
+}
index b29e14e64dd305922f82556e8e445be42a9fbb38..ae19a8f9cf3901a808c85f0c028fbf44813d30b5 100644 (file)
@@ -55,7 +55,7 @@ proc save_config {} {
 }
 
 proc do_about {} {
-       global appvers copyright
+       global appvers copyright oguilib
        global tcl_patchLevel tk_patchLevel
 
        set w .about_dialog
@@ -94,6 +94,10 @@ $copyright" \
                append v ", Tk version $tk_patchLevel"
        }
 
+       set d {}
+       append d "git exec dir: [gitexec]\n"
+       append d "git-gui lib: $oguilib"
+
        label $w.vers \
                -text $v \
                -padx 5 -pady 5 \
@@ -103,6 +107,15 @@ $copyright" \
                -relief solid
        pack $w.vers -side top -fill x -padx 5 -pady 5
 
+       label $w.dirs \
+               -text $d \
+               -padx 5 -pady 5 \
+               -justify left \
+               -anchor w \
+               -borderwidth 1 \
+               -relief solid
+       pack $w.dirs -side top -fill x -padx 5 -pady 5
+
        menu $w.ctxm -tearoff 0
        $w.ctxm add command \
                -label {Copy} \
@@ -174,8 +187,10 @@ proc do_options {} {
 
                {b merge.summary {Summarize Merge Commits}}
                {i-1..5 merge.verbosity {Merge Verbosity}}
+               {b merge.diffstat {Show Diffstat After Merge}}
 
                {b gui.trustmtime  {Trust File Modification Timestamps}}
+               {b gui.pruneduringfetch {Prune Tracking Branches During Fetch}}
                {i-0..99 gui.diffcontext {Number of Diff Context Lines}}
                {t gui.newbranchtemplate {New Branch Name Template}}
                } {
index 99f353ed7d793ca9accf2c5d246938c8a51fea02..b54824ab725d9f11c6c5a38a8e0c53f37e41adc5 100644 (file)
@@ -95,6 +95,7 @@ proc populate_fetch_menu {} {
        global all_remotes repo_config
 
        set m .mbar.fetch
+       set prune_list [list]
        foreach r $all_remotes {
                set enable 0
                if {![catch {set a $repo_config(remote.$r.url)}]} {
@@ -115,11 +116,21 @@ proc populate_fetch_menu {} {
                }
 
                if {$enable} {
+                       lappend prune_list $r
                        $m add command \
                                -label "Fetch from $r..." \
                                -command [list fetch_from $r]
                }
        }
+
+       if {$prune_list ne {}} {
+               $m add separator
+       }
+       foreach r $prune_list {
+               $m add command \
+                       -label "Prune from $r..." \
+                       -command [list prune_from $r]
+       }
 }
 
 proc populate_push_menu {} {
diff --git a/git-gui/lib/remote_branch_delete.tcl b/git-gui/lib/remote_branch_delete.tcl
new file mode 100644 (file)
index 0000000..b83e1b6
--- /dev/null
@@ -0,0 +1,347 @@
+# git-gui remote branch deleting support
+# Copyright (C) 2007 Shawn Pearce
+
+class remote_branch_delete {
+
+field w
+field head_m
+
+field urltype   {url}
+field remote    {}
+field url       {}
+
+field checktype  {head}
+field check_head {}
+
+field status    {}
+field idle_id   {}
+field full_list {}
+field head_list {}
+field active_ls {}
+field head_cache
+field full_cache
+field cached
+
+constructor dialog {} {
+       global all_remotes M1B
+
+       make_toplevel top w
+       wm title $top "[appname] ([reponame]): Delete Remote Branch"
+       if {$top ne {.}} {
+               wm geometry $top "+[winfo rootx .]+[winfo rooty .]"
+       }
+
+       label $w.header -text {Delete Remote Branch} -font font_uibold
+       pack $w.header -side top -fill x
+
+       frame $w.buttons
+       button $w.buttons.delete -text Delete \
+               -default active \
+               -command [cb _delete]
+       pack $w.buttons.delete -side right
+       button $w.buttons.cancel -text {Cancel} \
+               -command [list destroy $w]
+       pack $w.buttons.cancel -side right -padx 5
+       pack $w.buttons -side bottom -fill x -pady 10 -padx 10
+
+       labelframe $w.dest -text {From Repository}
+       if {$all_remotes ne {}} {
+               radiobutton $w.dest.remote_r \
+                       -text {Remote:} \
+                       -value remote \
+                       -variable @urltype
+               eval tk_optionMenu $w.dest.remote_m @remote $all_remotes
+               grid $w.dest.remote_r $w.dest.remote_m -sticky w
+               if {[lsearch -sorted -exact $all_remotes origin] != -1} {
+                       set remote origin
+               } else {
+                       set remote [lindex $all_remotes 0]
+               }
+               set urltype remote
+               trace add variable @remote write [cb _write_remote]
+       } else {
+               set urltype url
+       }
+       radiobutton $w.dest.url_r \
+               -text {Arbitrary URL:} \
+               -value url \
+               -variable @urltype
+       entry $w.dest.url_t \
+               -borderwidth 1 \
+               -relief sunken \
+               -width 50 \
+               -textvariable @url \
+               -validate key \
+               -validatecommand {
+                       if {%d == 1 && [regexp {\s} %S]} {return 0}
+                       return 1
+               }
+       trace add variable @url write [cb _write_url]
+       grid $w.dest.url_r $w.dest.url_t -sticky we -padx {0 5}
+       grid columnconfigure $w.dest 1 -weight 1
+       pack $w.dest -anchor nw -fill x -pady 5 -padx 5
+
+       labelframe $w.heads -text {Branches}
+       listbox $w.heads.l \
+               -height 10 \
+               -width 70 \
+               -listvariable @head_list \
+               -selectmode extended \
+               -yscrollcommand [list $w.heads.sby set]
+       scrollbar $w.heads.sby -command [list $w.heads.l yview]
+
+       frame $w.heads.footer
+       label $w.heads.footer.status \
+               -textvariable @status \
+               -anchor w \
+               -justify left
+       button $w.heads.footer.rescan \
+               -text {Rescan} \
+               -command [cb _rescan]
+       pack $w.heads.footer.status -side left -fill x -expand 1
+       pack $w.heads.footer.rescan -side right
+
+       pack $w.heads.footer -side bottom -fill x -expand 1
+       pack $w.heads.sby -side right -fill y
+       pack $w.heads.l -side left -fill both -expand 1
+       pack $w.heads -fill both -expand 1 -pady 5 -padx 5
+
+       labelframe $w.validate -text {Delete Only If}
+       radiobutton $w.validate.head_r \
+               -text {Merged Into:} \
+               -value head \
+               -variable @checktype
+       set head_m [tk_optionMenu $w.validate.head_m @check_head {}]
+       trace add variable @head_list write [cb _write_head_list]
+       trace add variable @check_head write [cb _write_check_head]
+       grid $w.validate.head_r $w.validate.head_m -sticky w
+       radiobutton $w.validate.always_r \
+               -text {Always (Do not perform merge checks)} \
+               -value always \
+               -variable @checktype
+       grid $w.validate.always_r -columnspan 2 -sticky w
+       grid columnconfigure $w.validate 1 -weight 1
+       pack $w.validate -anchor nw -fill x -pady 5 -padx 5
+
+       trace add variable @urltype write [cb _write_urltype]
+       _rescan $this
+
+       bind $w <Key-F5>     [cb _rescan]
+       bind $w <$M1B-Key-r> [cb _rescan]
+       bind $w <$M1B-Key-R> [cb _rescan]
+       bind $w <Key-Return> [cb _delete]
+       bind $w <Key-Escape> [list destroy $w]
+       return $w
+}
+
+method _delete {} {
+       switch $urltype {
+       remote {set uri $remote}
+       url    {set uri $url}
+       }
+
+       set cache $urltype:$uri
+       set crev {}
+       if {$checktype eq {head}} {
+               if {$check_head eq {}} {
+                       tk_messageBox \
+                               -icon error \
+                               -type ok \
+                               -title [wm title $w] \
+                               -parent $w \
+                               -message "A branch is required for 'Merged Into'."
+                       return
+               }
+               set crev $full_cache("$cache\nrefs/heads/$check_head")
+       }
+
+       set not_merged [list]
+       set need_fetch 0
+       set have_selection 0
+       set push_cmd [list git push]
+       lappend push_cmd -v
+       lappend push_cmd $uri
+
+       foreach i [$w.heads.l curselection] {
+               set ref [lindex $full_list $i]
+               if {$crev ne {}} {
+                       set obj $full_cache("$cache\n$ref")
+                       if {[catch {set m [git merge-base $obj $crev]}]} {
+                               set need_fetch 1
+                               set m {}
+                       }
+                       if {$obj ne $m} {
+                               lappend not_merged [lindex $head_list $i]
+                               continue
+                       }
+               }
+
+               lappend push_cmd :$ref
+               set have_selection 1
+       }
+
+       if {$not_merged ne {}} {
+               set msg "The following branches are not completely merged into $check_head:
+
+ - [join $not_merged "\n - "]"
+
+               if {$need_fetch} {
+                       append msg "
+
+One or more of the merge tests failed because you have not fetched the necessary commits.  Try fetching from $uri first."
+               }
+
+               tk_messageBox \
+                       -icon info \
+                       -type ok \
+                       -title [wm title $w] \
+                       -parent $w \
+                       -message $msg
+               if {!$have_selection} return
+       }
+
+       if {!$have_selection} {
+               tk_messageBox \
+                       -icon error \
+                       -type ok \
+                       -title [wm title $w] \
+                       -parent $w \
+                       -message "Please select one or more branches to delete."
+               return
+       }
+
+       if {[tk_messageBox \
+               -icon warning \
+               -type yesno \
+               -title [wm title $w] \
+               -parent $w \
+               -message {Recovering deleted branches is difficult.
+
+Delete the selected branches?}] ne yes} {
+               return
+       }
+
+       destroy $w
+
+       set cons [console::new \
+               "push $uri" \
+               "Deleting branches from $uri"]
+       console::exec $cons $push_cmd
+}
+
+method _rescan {{force 1}} {
+       switch $urltype {
+       remote {set uri $remote}
+       url    {set uri $url}
+       }
+
+       if {$force} {
+               unset -nocomplain cached($urltype:$uri)
+       }
+
+       if {$idle_id ne {}} {
+               after cancel $idle_id
+               set idle_id {}
+       }
+
+       _load $this $urltype:$uri $uri
+}
+
+method _write_remote     {args} { set urltype remote }
+method _write_url        {args} { set urltype url    }
+method _write_check_head {args} { set checktype head }
+
+method _write_head_list {args} {
+       $head_m delete 0 end
+       foreach abr $head_list {
+               $head_m insert end radiobutton \
+                       -label $abr \
+                       -value $abr \
+                       -variable @check_head
+       }
+       if {[lsearch -exact -sorted $head_list $check_head] < 0} {
+               set check_head {}
+       }
+}
+
+method _write_urltype {args} {
+       if {$urltype eq {url}} {
+               if {$idle_id ne {}} {
+                       after cancel $idle_id
+               }
+               _load $this none: {}
+               set idle_id [after 1000 [cb _rescan 0]]
+       } else {
+               _rescan $this 0
+       }
+}
+
+method _load {cache uri} {
+       if {$active_ls ne {}} {
+               catch {close $active_ls}
+       }
+
+       if {$uri eq {}} {
+               $w.heads.l conf -state disabled
+               set head_list [list]
+               set full_list [list]
+               set status {No repository selected.}
+               return
+       }
+
+       if {[catch {set x $cached($cache)}]} {
+               set status "Scanning $uri..."
+               $w.heads.l conf -state disabled
+               set head_list [list]
+               set full_list [list]
+               set head_cache($cache) [list]
+               set full_cache($cache) [list]
+               set active_ls [open "| [list git ls-remote $uri]" r]
+               fconfigure $active_ls \
+                       -blocking 0 \
+                       -translation lf \
+                       -encoding utf-8
+               fileevent $active_ls readable [cb _read $cache $active_ls]
+       } else {
+               set status {}
+               set full_list $full_cache($cache)
+               set head_list $head_cache($cache)
+               $w.heads.l conf -state normal
+       }
+}
+
+method _read {cache fd} {
+       if {$fd ne $active_ls} {
+               catch {close $fd}
+               return
+       }
+
+       while {[gets $fd line] >= 0} {
+               if {[string match {*^{}} $line]} continue
+               if {[regexp {^([0-9a-f]{40})    (.*)$} $line _junk obj ref]} {
+                       if {[regsub ^refs/heads/ $ref {} abr]} {
+                               lappend head_list $abr
+                               lappend head_cache($cache) $abr
+                               lappend full_list $ref
+                               lappend full_cache($cache) $ref
+                               set full_cache("$cache\n$ref") $obj
+                       }
+               }
+       }
+
+       if {[eof $fd]} {
+               if {[catch {close $fd} err]} {
+                       set status $err
+                       set head_list [list]
+                       set full_list [list]
+               } else {
+                       set status {}
+                       set cached($cache) 1
+                       $w.heads.l conf -state normal
+               }
+       }
+} ifdeleted {
+       catch {close $fd}
+}
+
+}
index c0e7d20fce67349938373c0cfdf879aa3137d18f..e8ebc6eda090faed16c80ba748d21c0c53f9f2a4 100644 (file)
@@ -5,9 +5,19 @@ proc fetch_from {remote} {
        set w [console::new \
                "fetch $remote" \
                "Fetching new changes from $remote"]
-       set cmd [list git fetch]
-       lappend cmd $remote
-       console::exec $w $cmd
+       set cmds [list]
+       lappend cmds [list exec git fetch $remote]
+       if {[is_config_true gui.pruneduringfetch]} {
+               lappend cmds [list exec git remote prune $remote]
+       }
+       console::chain $w $cmds
+}
+
+proc prune_from {remote} {
+       set w [console::new \
+               "remote prune $remote" \
+               "Pruning tracking branches deleted from $remote"]
+       console::exec $w [list git remote prune $remote]
 }
 
 proc push_to {remote} {
index 58570dff137adfdeb72ebf3f088af7379eded522..c0b00e0fd143ab9d96933f2d39baa94e7e50e0ef 100755 (executable)
@@ -17,10 +17,10 @@ while read dangling type sha1
 do
        case "$dangling" in
        dangling)
-               if git-rev-parse --verify "$sha1^0" >/dev/null 2>/dev/null
+               if git rev-parse --verify "$sha1^0" >/dev/null 2>/dev/null
                then
                        dir="$laf/commit"
-                       git-show-branch "$sha1"
+                       git show-branch "$sha1"
                else
                        dir="$laf/other"
                fi
index a6ed99a7c52ac557b01e4dbf271abdf5b9a18b4b..3671f3433e82f7c54e09e90b411a63f1f068210d 100755 (executable)
@@ -58,7 +58,7 @@ http://* | https://* | ftp://* )
             curl_extra_args="-k"
         fi
        if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \
-               "`git-config --bool http.noEPSV`" = true ]; then
+               "`git config --bool http.noEPSV`" = true ]; then
                curl_extra_args="${curl_extra_args} --disable-epsv"
        fi
        curl -nsf $curl_extra_args --header "Pragma: no-cache" "$peek_repo/info/refs" ||
index eb3f473d5a3ac2a894503c1a7601b763548f8722..645e1147dc886f2b1ca6d2020b44db746b082bf0 100755 (executable)
@@ -45,7 +45,7 @@ esac
 # MRT is the current "merge result tree"
 
 MRC=$head MSG= PARENT="-p $head"
-MRT=$(git-write-tree)
+MRT=$(git write-tree)
 CNT=1 ;# counting our head
 NON_FF_MERGE=0
 OCTOPUS_FAILURE=0
@@ -61,7 +61,7 @@ do
                exit 2
        esac
 
-       common=$(git-merge-base --all $MRC $SHA1) ||
+       common=$(git merge-base --all $MRC $SHA1) ||
                die "Unable to find common commit with $SHA1"
 
        case "$LF$common$LF" in
@@ -82,22 +82,22 @@ do
                # We still need to count this as part of the parent set.
 
                echo "Fast forwarding to: $SHA1"
-               git-read-tree -u -m $head $SHA1 || exit
-               MRC=$SHA1 MRT=$(git-write-tree)
+               git read-tree -u -m $head $SHA1 || exit
+               MRC=$SHA1 MRT=$(git write-tree)
                continue
        fi
 
        NON_FF_MERGE=1
 
        echo "Trying simple merge with $SHA1"
-       git-read-tree -u -m --aggressive  $common $MRT $SHA1 || exit 2
-       next=$(git-write-tree 2>/dev/null)
+       git read-tree -u -m --aggressive  $common $MRT $SHA1 || exit 2
+       next=$(git write-tree 2>/dev/null)
        if test $? -ne 0
        then
                echo "Simple merge did not work, trying automatic merge."
                git-merge-index -o git-merge-one-file -a ||
                OCTOPUS_FAILURE=1
-               next=$(git-write-tree 2>/dev/null)
+               next=$(git write-tree 2>/dev/null)
        fi
 
        # We have merged the other branch successfully.  Ideally
index 7d62d7902cb1d7cd2749091b86d532306bea89b3..1e7727d2763e744b94f55c2056eccaab12367c9e 100755 (executable)
@@ -13,7 +13,7 @@
 #   $7 - file in branch2 mode (or empty)
 #
 # Handle some trivial cases.. The _really_ trivial cases have
-# been handled already by git-read-tree, but that one doesn't
+# been handled already by git read-tree, but that one doesn't
 # do any merges that might change the tree layout.
 
 case "${1:-.}${2:-.}${3:-.}" in
@@ -27,14 +27,15 @@ case "${1:-.}${2:-.}${3:-.}" in
                # read-tree checked that index matches HEAD already,
                # so we know we do not have this path tracked.
                # there may be an unrelated working tree file here,
-               # which we should just leave unmolested.
-               exit 0
+               # which we should just leave unmolested.  Make sure
+               # we do not have it in the index, though.
+               exec git update-index --remove -- "$4"
        fi
        if test -f "$4"; then
                rm -f -- "$4" &&
                rmdir -p "$(expr "z$4" : 'z\(.*\)/')" 2>/dev/null || :
        fi &&
-               exec git-update-index --remove -- "$4"
+               exec git update-index --remove -- "$4"
        ;;
 
 #
@@ -42,7 +43,8 @@ case "${1:-.}${2:-.}${3:-.}" in
 #
 ".$2.")
        # the other side did not add and we added so there is nothing
-       # to be done.
+       # to be done, except making the path merged.
+       exec git update-index --add --cacheinfo "$6" "$2" "$4"
        ;;
 "..$3")
        echo "Adding $4"
@@ -50,8 +52,8 @@ case "${1:-.}${2:-.}${3:-.}" in
                echo "ERROR: untracked $4 is overwritten by the merge."
                exit 1
        }
-       git-update-index --add --cacheinfo "$6$7" "$2$3" "$4" &&
-               exec git-checkout-index -u -f -- "$4"
+       git update-index --add --cacheinfo "$7" "$3" "$4" &&
+               exec git checkout-index -u -f -- "$4"
        ;;
 
 #
@@ -64,8 +66,8 @@ case "${1:-.}${2:-.}${3:-.}" in
                exit 1
        fi
        echo "Adding $4"
-       git-update-index --add --cacheinfo "$6" "$2" "$4" &&
-               exec git-checkout-index -u -f -- "$4"
+       git update-index --add --cacheinfo "$6" "$2" "$4" &&
+               exec git checkout-index -u -f -- "$4"
        ;;
 
 #
@@ -84,11 +86,11 @@ case "${1:-.}${2:-.}${3:-.}" in
        case "$1" in
        '')
                echo "Added $4 in both, but differently."
-               # This extracts OUR file in $orig, and uses git-apply to
+               # This extracts OUR file in $orig, and uses git apply to
                # remove lines that are unique to ours.
                orig=`git-unpack-file $2`
                sz0=`wc -c <"$orig"`
-               diff -u -La/$orig -Lb/$orig $orig $src2 | git-apply --no-add 
+               diff -u -La/$orig -Lb/$orig $orig $src2 | git apply --no-add
                sz1=`wc -c <"$orig"`
 
                # If we do not have enough common material, it is not
@@ -104,12 +106,12 @@ case "${1:-.}${2:-.}${3:-.}" in
        # Be careful for funny filename such as "-L" in "$4", which
        # would confuse "merge" greatly.
        src1=`git-unpack-file $2`
-       git-merge-file "$src1" "$orig" "$src2"
+       git merge-file "$src1" "$orig" "$src2"
        ret=$?
 
        # Create the working tree file, using "our tree" version from the
        # index, and then store the result of the merge.
-       git-checkout-index -f --stage=2 -- "$4" && cat "$src1" >"$4"
+       git checkout-index -f --stage=2 -- "$4" && cat "$src1" >"$4"
        rm -f -- "$orig" "$src1" "$src2"
 
        if [ "$6" != "$7" ]; then
@@ -124,7 +126,7 @@ case "${1:-.}${2:-.}${3:-.}" in
                echo "ERROR: Merge conflict in $4"
                exit 1
        fi
-       exec git-update-index -- "$4"
+       exec git update-index -- "$4"
        ;;
 
 *)
index 2b6a5c0d104b09b2eb471be9ec86e215ac003b0a..c81a790aa60ea08144dd0899d1aee2ec334a1825 100755 (executable)
@@ -9,6 +9,6 @@
 # because the current index is what we will be committing as the
 # merge result.
 
-git-diff-index --quiet --cached HEAD || exit 2
+git diff-index --quiet --cached HEAD || exit 2
 
 exit 0
index 75e1de49ac9adb443e6065c93ac691c27f0f5518..bb19da2cc15715df9c96ddea18c6d449ce49b6e4 100755 (executable)
@@ -37,10 +37,10 @@ then
        exit 2
 fi
 
-git-update-index --refresh 2>/dev/null
-git-read-tree -u -m --aggressive $bases $head $remotes || exit 2
+git update-index --refresh 2>/dev/null
+git read-tree -u -m --aggressive $bases $head $remotes || exit 2
 echo "Trying simple merge."
-if result_tree=$(git-write-tree  2>/dev/null)
+if result_tree=$(git write-tree  2>/dev/null)
 then
        exit 0
 else
index 4faecb933df33fd4b72e0968d7ee04e1ccc49aec..4b1e595363cdcfae9d9c567d98127ee83bcc2b23 100755 (executable)
@@ -40,10 +40,10 @@ case "$bases" in
        for c in $bases
        do
                rm -f $G
-               GIT_INDEX_FILE=$G git-read-tree -m $c $head $remotes \
+               GIT_INDEX_FILE=$G git read-tree -m $c $head $remotes \
                         2>/dev/null || continue
                # Count the paths that are unmerged.
-               cnt=`GIT_INDEX_FILE=$G git-ls-files --unmerged | wc -l`
+               cnt=`GIT_INDEX_FILE=$G git ls-files --unmerged | wc -l`
                if test $best_cnt -le 0 -o $cnt -le $best_cnt
                then
                        best=$c
@@ -63,10 +63,10 @@ case "$bases" in
        ;;
 esac
 
-git-update-index --refresh 2>/dev/null
-git-read-tree -u -m $common $head $remotes || exit 2
+git update-index --refresh 2>/dev/null
+git read-tree -u -m $common $head $remotes || exit 2
 echo "Trying simple merge."
-if result_tree=$(git-write-tree  2>/dev/null)
+if result_tree=$(git write-tree  2>/dev/null)
 then
        exit 0
 else
index b2f8a2acd398b7c61b68a59c6d3631ca84be0727..5ccf28251d51d3ee10675d48cf04829f5d6d8c06 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-USAGE='[-n] [--no-commit] [--squash] [-s <strategy>] [-m=<merge-message>] <commit>+'
+USAGE='[-n] [--summary] [--no-commit] [--squash] [-s <strategy>] [-m=<merge-message>] <commit>+'
 
 SUBDIRECTORY_OK=Yes
 . git-sh-setup
@@ -31,7 +31,7 @@ dropsave() {
 
 savestate() {
        # Stash away any local modifications.
-       git-diff-index -z --name-only $head |
+       git diff-index -z --name-only $head |
        cpio -0 -o >"$GIT_DIR/MERGE_SAVE"
 }
 
@@ -40,7 +40,7 @@ restorestate() {
        then
                git reset --hard $head >/dev/null
                cpio -iuv <"$GIT_DIR/MERGE_SAVE"
-               git-update-index --refresh >/dev/null
+               git update-index --refresh >/dev/null
        fi
 }
 
@@ -57,7 +57,7 @@ finish_up_to_date () {
 squash_message () {
        echo Squashed commit of the following:
        echo
-       git-log --no-merges ^"$head" $remote
+       git log --no-merges ^"$head" $remote
 }
 
 finish () {
@@ -79,7 +79,7 @@ finish () {
                        echo "No merge message -- not updating HEAD"
                        ;;
                *)
-                       git-update-ref -m "$rlogm" HEAD "$1" "$head" || exit 1
+                       git update-ref -m "$rlogm" HEAD "$1" "$head" || exit 1
                        ;;
                esac
                ;;
@@ -88,24 +88,24 @@ finish () {
        '')
                ;;
        ?*)
-               case "$no_summary" in
-               '')
-                       git-diff-tree --stat --summary -M "$head" "$1"
-                       ;;
-               esac
+               if test "$show_diffstat" = t
+               then
+                       # We want color (if set), but no pager
+                       GIT_PAGER='' git diff --stat --summary -M "$head" "$1"
+               fi
                ;;
        esac
 }
 
 merge_name () {
        remote="$1"
-       rh=$(git-rev-parse --verify "$remote^0" 2>/dev/null) || return
-       bh=$(git-show-ref -s --verify "refs/heads/$remote" 2>/dev/null)
+       rh=$(git rev-parse --verify "$remote^0" 2>/dev/null) || return
+       bh=$(git show-ref -s --verify "refs/heads/$remote" 2>/dev/null)
        if test "$rh" = "$bh"
        then
                echo "$rh               branch '$remote' of ."
        elif truname=$(expr "$remote" : '\(.*\)~[1-9][0-9]*$') &&
-               git-show-ref -q --verify "refs/heads/$truname" 2>/dev/null
+               git show-ref -q --verify "refs/heads/$truname" 2>/dev/null
        then
                echo "$rh               branch '$truname' (early part) of ."
        elif test "$remote" = "FETCH_HEAD" -a -r "$GIT_DIR/FETCH_HEAD"
@@ -125,7 +125,9 @@ do
        case "$1" in
        -n|--n|--no|--no-|--no-s|--no-su|--no-sum|--no-summ|\
                --no-summa|--no-summar|--no-summary)
-               no_summary=t ;;
+               show_diffstat=false ;;
+       --summary)
+               show_diffstat=t ;;
        --sq|--squ|--squa|--squas|--squash)
                squash=t no_commit=t ;;
        --no-c|--no-co|--no-com|--no-comm|--no-commi|--no-commit)
@@ -167,6 +169,11 @@ do
        shift
 done
 
+if test -z "$show_diffstat"; then
+    test "$(git config --bool merge.diffstat)" = false && show_diffstat=false
+    test -z "$show_diffstat" && show_diffstat=t
+fi
+
 # This could be traditional "merge <msg> HEAD <commit>..."  and the
 # way we can tell it is to see if the second token is HEAD, but some
 # people might have misused the interface and used a committish that
@@ -174,15 +181,15 @@ done
 # have "-m" so it is an additional safety measure to check for it.
 
 if test -z "$have_message" &&
-       second_token=$(git-rev-parse --verify "$2^0" 2>/dev/null) &&
-       head_commit=$(git-rev-parse --verify "HEAD" 2>/dev/null) &&
+       second_token=$(git rev-parse --verify "$2^0" 2>/dev/null) &&
+       head_commit=$(git rev-parse --verify "HEAD" 2>/dev/null) &&
        test "$second_token" = "$head_commit"
 then
        merge_msg="$1"
        shift
        head_arg="$1"
        shift
-elif ! git-rev-parse --verify HEAD >/dev/null 2>&1
+elif ! git rev-parse --verify HEAD >/dev/null 2>&1
 then
        # If the merged head is a valid one there is no reason to
        # forbid "git merge" into a branch yet to be born.  We do
@@ -196,8 +203,8 @@ then
        rh=$(git rev-parse --verify "$1^0") ||
                die "$1 - not something we can merge"
 
-       git-update-ref -m "initial pull" HEAD "$rh" "" &&
-       git-read-tree --reset -u HEAD
+       git update-ref -m "initial pull" HEAD "$rh" "" &&
+       git read-tree --reset -u HEAD
        exit
 
 else
@@ -212,11 +219,11 @@ else
        merge_name=$(for remote
                do
                        merge_name "$remote"
-               done | git-fmt-merge-msg
+               done | git fmt-merge-msg
        )
        merge_msg="${merge_msg:+$merge_msg$LF$LF}$merge_name"
 fi
-head=$(git-rev-parse --verify "$head_arg"^0) || usage
+head=$(git rev-parse --verify "$head_arg"^0) || usage
 
 # All the rest are remote heads
 test "$#" = 0 && usage ;# we need at least one remote head.
@@ -225,7 +232,7 @@ set_reflog_action "merge $*"
 remoteheads=
 for remote
 do
-       remotehead=$(git-rev-parse --verify "$remote"^0 2>/dev/null) ||
+       remotehead=$(git rev-parse --verify "$remote"^0 2>/dev/null) ||
            die "$remote - not something we can merge"
        remoteheads="${remoteheads}$remotehead "
        eval GITHEAD_$remotehead='"$remote"'
@@ -237,7 +244,7 @@ case "$use_strategies" in
 '')
        case "$#" in
        1)
-               var="`git-config --get pull.twohead`"
+               var="`git config --get pull.twohead`"
                if test -n "$var"
                then
                        use_strategies="$var"
@@ -245,7 +252,7 @@ case "$use_strategies" in
                        use_strategies="$default_twohead_strategies"
                fi ;;
        *)
-               var="`git-config --get pull.octopus`"
+               var="`git config --get pull.octopus`"
                if test -n "$var"
                then
                        use_strategies="$var"
@@ -271,10 +278,10 @@ done
 
 case "$#" in
 1)
-       common=$(git-merge-base --all $head "$@")
+       common=$(git merge-base --all $head "$@")
        ;;
 *)
-       common=$(git-show-branch --merge-base $head "$@")
+       common=$(git show-branch --merge-base $head "$@")
        ;;
 esac
 echo "$head" >"$GIT_DIR/ORIG_HEAD"
@@ -294,15 +301,15 @@ f,*)
        ;;
 ?,1,"$head",*)
        # Again the most common case of merging one remote.
-       echo "Updating $(git-rev-parse --short $head)..$(git-rev-parse --short $1)"
-       git-update-index --refresh 2>/dev/null
+       echo "Updating $(git rev-parse --short $head)..$(git rev-parse --short $1)"
+       git update-index --refresh 2>/dev/null
        msg="Fast forward"
        if test -n "$have_message"
        then
                msg="$msg (no commit created; -m option ignored)"
        fi
-       new_head=$(git-rev-parse --verify "$1^0") &&
-       git-read-tree -v -m -u --exclude-per-directory=.gitignore $head "$new_head" &&
+       new_head=$(git rev-parse --verify "$1^0") &&
+       git read-tree -v -m -u --exclude-per-directory=.gitignore $head "$new_head" &&
        finish "$new_head" "$msg" || exit
        dropsave
        exit 0
@@ -314,7 +321,7 @@ f,*)
 ?,1,*,)
        # We are not doing octopus, not fast forward, and have only
        # one common.
-       git-update-index --refresh 2>/dev/null
+       git update-index --refresh 2>/dev/null
        case " $use_strategies " in
        *' recursive '*|*' recur '*)
                : run merge later
@@ -323,13 +330,13 @@ f,*)
                # See if it is really trivial.
                git var GIT_COMMITTER_IDENT >/dev/null || exit
                echo "Trying really trivial in-index merge..."
-               if git-read-tree --trivial -m -u -v $common $head "$1" &&
-                  result_tree=$(git-write-tree)
+               if git read-tree --trivial -m -u -v $common $head "$1" &&
+                  result_tree=$(git write-tree)
                then
                        echo "Wonderful."
                        result_commit=$(
                                printf '%s\n' "$merge_msg" |
-                               git-commit-tree $result_tree -p HEAD -p "$1"
+                               git commit-tree $result_tree -p HEAD -p "$1"
                        ) || exit
                        finish "$result_commit" "In-index merge"
                        dropsave
@@ -343,7 +350,7 @@ f,*)
        up_to_date=t
        for remote
        do
-               common_one=$(git-merge-base --all $head $remote)
+               common_one=$(git merge-base --all $head $remote)
                if test "$common_one" != "$remote"
                then
                        up_to_date=f
@@ -412,8 +419,8 @@ do
        if test "$exit" -eq 1
        then
            cnt=`{
-               git-diff-files --name-only
-               git-ls-files --unmerged
+               git diff-files --name-only
+               git ls-files --unmerged
            } | wc -l`
            if test $best_cnt -le 0 -o $cnt -le $best_cnt
            then
@@ -425,15 +432,15 @@ do
     }
 
     # Automerge succeeded.
-    result_tree=$(git-write-tree) && break
+    result_tree=$(git write-tree) && break
 done
 
 # If we have a resulting tree, that means the strategy module
 # auto resolved the merge cleanly.
 if test '' != "$result_tree"
 then
-    parents=$(git-show-branch --independent "$head" "$@" | sed -e 's/^/-p /')
-    result_commit=$(printf '%s\n' "$merge_msg" | git-commit-tree $result_tree $parents) || exit
+    parents=$(git show-branch --independent "$head" "$@" | sed -e 's/^/-p /')
+    result_commit=$(printf '%s\n' "$merge_msg" | git commit-tree $result_tree $parents) || exit
     finish "$result_commit" "Merge made by $wt_strategy."
     dropsave
     exit 0
@@ -489,9 +496,6 @@ Conflicts:
                sed -e 's/^[^   ]*      /       /' |
                uniq
        } >>"$GIT_DIR/MERGE_MSG"
-       if test -d "$GIT_DIR/rr-cache"
-       then
-               git-rerere
-       fi
+       git rerere
        die "Automatic merge failed; fix conflicts and then commit the result."
 fi
index e62351bcbabc00a3d89ddf1c8dd936cea400501f..47a80553ad3283c49cae0fbffcf444b93c8e34b7 100755 (executable)
@@ -5,7 +5,7 @@
 # Copyright (c) 2006 Theodore Y. Ts'o
 #
 # This file is licensed under the GPL v2, or a later version
-# at the discretion of Junio C Hammano.
+# at the discretion of Junio C Hamano.
 #
 
 USAGE='[--tool=tool] [file to merge] ...'
@@ -65,14 +65,14 @@ resolve_symlink_merge () {
        read ans
        case "$ans" in
            [lL]*)
-               git-checkout-index -f --stage=2 -- "$path"
-               git-add -- "$path"
+               git checkout-index -f --stage=2 -- "$path"
+               git add -- "$path"
                cleanup_temp_files --save-backup
                return
                ;;
            [rR]*)
-               git-checkout-index -f --stage=3 -- "$path"
-               git-add -- "$path"
+               git checkout-index -f --stage=3 -- "$path"
+               git add -- "$path"
                cleanup_temp_files --save-backup
                return
                ;;
@@ -93,12 +93,12 @@ resolve_deleted_merge () {
        read ans
        case "$ans" in
            [mMcC]*)
-               git-add -- "$path"
+               git add -- "$path"
                cleanup_temp_files --save-backup
                return
                ;;
            [dD]*)
-               git-rm -- "$path" > /dev/null
+               git rm -- "$path" > /dev/null
                cleanup_temp_files
                return
                ;;
@@ -140,7 +140,7 @@ remove_backup () {
 merge_file () {
     path="$1"
 
-    f=`git-ls-files -u -- "$path"`
+    f=`git ls-files -u -- "$path"`
     if test -z "$f" ; then
        if test ! -f "$path" ; then
            echo "$path: file not found"
@@ -215,6 +215,12 @@ merge_file () {
            check_unchanged
            save_backup
            ;;
+       gvimdiff)
+               touch "$BACKUP"
+               gvimdiff -f -- "$LOCAL" "$path" "$REMOTE"
+               check_unchanged
+               save_backup
+               ;;
        xxdiff)
            touch "$BACKUP"
            if base_present ; then
@@ -291,9 +297,9 @@ do
 done
 
 if test -z "$merge_tool"; then
-    merge_tool=`git-config merge.tool`
+    merge_tool=`git config merge.tool`
     case "$merge_tool" in
-       kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | "")
+       kdiff3 | tkdiff | xxdiff | meld | opendiff | emerge | vimdiff | gvimdiff | "")
            ;; # happy
        *)
            echo >&2 "git config option merge.tool set to unknown tool: $merge_tool"
@@ -304,28 +310,42 @@ if test -z "$merge_tool"; then
 fi
 
 if test -z "$merge_tool" ; then
-    if type kdiff3 >/dev/null 2>&1 && test -n "$DISPLAY"; then
-       merge_tool="kdiff3";
-    elif type tkdiff >/dev/null 2>&1 && test -n "$DISPLAY"; then
-       merge_tool=tkdiff
-    elif type xxdiff >/dev/null 2>&1 && test -n "$DISPLAY"; then
-       merge_tool=xxdiff
-    elif type meld >/dev/null 2>&1 && test -n "$DISPLAY"; then
-       merge_tool=meld
-    elif type opendiff >/dev/null 2>&1; then
-       merge_tool=opendiff
-    elif type emacs >/dev/null 2>&1; then
-       merge_tool=emerge
-    elif type vimdiff >/dev/null 2>&1; then
-       merge_tool=vimdiff
-    else
+    if test -n "$DISPLAY"; then
+        merge_tool_candidates="kdiff3 tkdiff xxdiff meld gvimdiff"
+        if test -n "$GNOME_DESKTOP_SESSION_ID" ; then
+            merge_tool_candidates="meld $merge_tool_candidates"
+        fi
+        if test "$KDE_FULL_SESSION" = "true"; then
+            merge_tool_candidates="kdiff3 $merge_tool_candidates"
+        fi
+    fi
+    if echo "${VISUAL:-$EDITOR}" | grep 'emacs' > /dev/null 2>&1; then
+        merge_tool_candidates="$merge_tool_candidates emerge"
+    fi
+    if echo "${VISUAL:-$EDITOR}" | grep 'vim' > /dev/null 2>&1; then
+        merge_tool_candidates="$merge_tool_candidates vimdiff"
+    fi
+    merge_tool_candidates="$merge_tool_candidates opendiff emerge vimdiff"
+    echo "merge tool candidates: $merge_tool_candidates"
+    for i in $merge_tool_candidates; do
+        if test $i = emerge ; then
+            cmd=emacs
+        else
+            cmd=$i
+        fi
+        if type $cmd > /dev/null 2>&1; then
+            merge_tool=$i
+            break
+        fi
+    done
+    if test -z "$merge_tool" ; then
        echo "No available merge resolution programs available."
        exit 1
     fi
 fi
 
 case "$merge_tool" in
-    kdiff3|tkdiff|meld|xxdiff|vimdiff|opendiff)
+    kdiff3|tkdiff|meld|xxdiff|vimdiff|gvimdiff|opendiff)
        if ! type "$merge_tool" > /dev/null 2>&1; then
            echo "The merge tool $merge_tool is not available"
            exit 1
index 60a758bfe3bf535733612d4a0843fb42055f4c80..0f3d97b67eef3108728265e26f5d79c4526d11ac 100644 (file)
@@ -358,4 +358,3 @@ for id in changes:
     if stitch == 1:
         git.clean_directories()
         stitch = 0
-
index 0506b12cb26966cfaa9eb73f3e1d1a9c5d66cc02..695a4094bb4230341618bd6f16d0bea9bff2e826 100755 (executable)
@@ -2,7 +2,7 @@
 
 # git-ls-remote could be called from outside a git managed repository;
 # this would fail in that case and would issue an error message.
-GIT_DIR=$(git-rev-parse --git-dir 2>/dev/null) || :;
+GIT_DIR=$(git rev-parse --git-dir 2>/dev/null) || :;
 
 get_data_source () {
        case "$1" in
@@ -13,7 +13,7 @@ get_data_source () {
                echo self
                ;;
        *)
-               if test "$(git-config --get "remote.$1.url")"
+               if test "$(git config --get "remote.$1.url")"
                then
                        echo config
                elif test -f "$GIT_DIR/remotes/$1"
@@ -38,7 +38,7 @@ get_remote_url () {
                echo "$1"
                ;;
        config)
-               git-config --get "remote.$1.url"
+               git config --get "remote.$1.url"
                ;;
        remotes)
                sed -ne '/^URL: */{
@@ -55,8 +55,8 @@ get_remote_url () {
 }
 
 get_default_remote () {
-       curr_branch=$(git-symbolic-ref -q HEAD | sed -e 's|^refs/heads/||')
-       origin=$(git-config --get "branch.$curr_branch.remote")
+       curr_branch=$(git symbolic-ref -q HEAD | sed -e 's|^refs/heads/||')
+       origin=$(git config --get "branch.$curr_branch.remote")
        echo ${origin:-origin}
 }
 
@@ -66,7 +66,7 @@ get_remote_default_refs_for_push () {
        '' | branches | self)
                ;; # no default push mapping, just send matching refs.
        config)
-               git-config --get-all "remote.$1.push" ;;
+               git config --get-all "remote.$1.push" ;;
        remotes)
                sed -ne '/^Push: */{
                        s///p
@@ -107,9 +107,9 @@ canon_refs_list_for_fetch () {
                shift
                if test "$remote" = "$(get_default_remote)"
                then
-                       curr_branch=$(git-symbolic-ref -q HEAD | \
+                       curr_branch=$(git symbolic-ref -q HEAD | \
                            sed -e 's|^refs/heads/||')
-                       merge_branches=$(git-config \
+                       merge_branches=$(git config \
                            --get-all "branch.${curr_branch}.merge")
                fi
                if test -z "$merge_branches" && test $is_explicit != explicit
@@ -156,7 +156,7 @@ canon_refs_list_for_fetch () {
 
                if local_ref_name=$(expr "z$local" : 'zrefs/\(.*\)')
                then
-                  git-check-ref-format "$local_ref_name" ||
+                  git check-ref-format "$local_ref_name" ||
                   die "* refusing to create funny ref '$local_ref_name' locally"
                fi
                echo "${dot_prefix}${force}${remote}:${local}"
@@ -171,11 +171,11 @@ get_remote_default_refs_for_fetch () {
                echo "HEAD:" ;;
        self)
                canon_refs_list_for_fetch -d "$1" \
-                       $(git-for-each-ref --format='%(refname):')
+                       $(git for-each-ref --format='%(refname):')
                ;;
        config)
                canon_refs_list_for_fetch -d "$1" \
-                       $(git-config --get-all "remote.$1.fetch") ;;
+                       $(git config --get-all "remote.$1.fetch") ;;
        branches)
                remote_branch=$(sed -ne '/#/s/.*#//p' "$GIT_DIR/branches/$1")
                case "$remote_branch" in '') remote_branch=master ;; esac
@@ -254,7 +254,7 @@ get_uploadpack () {
        data_source=$(get_data_source "$1")
        case "$data_source" in
        config)
-               uplp=$(git-config --get "remote.$1.uploadpack")
+               uplp=$(git config --get "remote.$1.uploadpack")
                echo ${uplp:-git-upload-pack}
                ;;
        *)
index a3665d7751cc836dc669390df7b972c29575037b..5e96d1f228da506b11452abec70e7c50d8907733 100755 (executable)
@@ -22,6 +22,9 @@ do
        -n|--n|--no|--no-|--no-s|--no-su|--no-sum|--no-summ|\
                --no-summa|--no-summar|--no-summary)
                no_summary=-n ;;
+       --summary)
+               no_summary=$1
+               ;;
        --no-c|--no-co|--no-com|--no-comm|--no-commi|--no-commit)
                no_commit=--no-commit ;;
        --sq|--squ|--squa|--squas|--squash)
@@ -51,10 +54,10 @@ do
        shift
 done
 
-orig_head=$(git-rev-parse --verify HEAD 2>/dev/null)
+orig_head=$(git rev-parse --verify HEAD 2>/dev/null)
 git-fetch --update-head-ok "$@" || exit 1
 
-curr_head=$(git-rev-parse --verify HEAD 2>/dev/null)
+curr_head=$(git rev-parse --verify HEAD 2>/dev/null)
 if test "$curr_head" != "$orig_head"
 then
        # The fetch involved updating the current branch.
@@ -66,8 +69,8 @@ then
        echo >&2 "Warning: fetch updated the current branch head."
        echo >&2 "Warning: fast forwarding your working tree from"
        echo >&2 "Warning: commit $orig_head."
-       git-update-index --refresh 2>/dev/null
-       git-read-tree -u -m "$orig_head" "$curr_head" ||
+       git update-index --refresh 2>/dev/null
+       git read-tree -u -m "$orig_head" "$curr_head" ||
                die 'Cannot fast-forward your working tree.
 After making sure that you saved anything precious from
 $ git diff '$orig_head'
@@ -83,7 +86,7 @@ merge_head=$(sed -e '/        not-for-merge   /d' \
 
 case "$merge_head" in
 '')
-       curr_branch=$(git-symbolic-ref -q HEAD)
+       curr_branch=$(git symbolic-ref -q HEAD)
        case $? in
          0) ;;
          1) echo >&2 "You are not currently on a branch; you must explicitly"
@@ -110,11 +113,11 @@ esac
 
 if test -z "$orig_head"
 then
-       git-update-ref -m "initial pull" HEAD $merge_head "" &&
-       git-read-tree --reset -u HEAD || exit 1
+       git update-ref -m "initial pull" HEAD $merge_head "" &&
+       git read-tree --reset -u HEAD || exit 1
        exit
 fi
 
-merge_name=$(git-fmt-merge-msg <"$GIT_DIR/FETCH_HEAD") || exit
+merge_name=$(git fmt-merge-msg <"$GIT_DIR/FETCH_HEAD") || exit
 exec git-merge $no_summary $no_commit $squash $strategy_args \
        "$merge_name" HEAD $merge_head
index a7a6757dd8a3e0ff2635537a83591169c259986f..2124df9e4a86ec446f19745043051a1b989d66d9 100755 (executable)
@@ -67,12 +67,12 @@ tmp_info="$tmp_dir/info"
 
 
 # Find the intial commit
-commit=$(git-rev-parse HEAD)
+commit=$(git rev-parse HEAD)
 
 mkdir $tmp_dir || exit 2
 for patch_name in $(cat "$QUILT_PATCHES/series" | grep -v '^#'); do
        echo $patch_name
-       (cat $QUILT_PATCHES/$patch_name | git-mailinfo "$tmp_msg" "$tmp_patch" > "$tmp_info") || exit 3
+       (cat $QUILT_PATCHES/$patch_name | git mailinfo "$tmp_msg" "$tmp_patch" > "$tmp_info") || exit 3
        test -s .dotest/patch || {
                echo "Patch is empty.  Was it split wrong?"
                exit 1
@@ -113,10 +113,10 @@ for patch_name in $(cat "$QUILT_PATCHES/series" | grep -v '^#'); do
        fi
 
        if [ -z "$dry_run" ] ; then
-               git-apply --index -C1 "$tmp_patch" &&
-               tree=$(git-write-tree) &&
-               commit=$( (echo "$SUBJECT"; echo; cat "$tmp_msg") | git-commit-tree $tree -p $commit) &&
-               git-update-ref -m "quiltimport: $patch_name" HEAD $commit || exit 4
+               git apply --index -C1 "$tmp_patch" &&
+               tree=$(git write-tree) &&
+               commit=$( (echo "$SUBJECT"; echo; cat "$tmp_msg") | git commit-tree $tree -p $commit) &&
+               git update-ref -m "quiltimport: $patch_name" HEAD $commit || exit 4
        fi
 done
 rm -rf $tmp_dir || exit 5
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
new file mode 100755 (executable)
index 0000000..d9563ec
--- /dev/null
@@ -0,0 +1,425 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Johannes E. Schindelin
+
+# SHORT DESCRIPTION
+#
+# This script makes it easy to fix up commits in the middle of a series,
+# and rearrange commits.
+#
+# The original idea comes from Eric W. Biederman, in
+# http://article.gmane.org/gmane.comp.version-control.git/22407
+
+USAGE='(--continue | --abort | --skip | [--preserve-merges] [--verbose]
+       [--onto <branch>] <upstream> [<branch>])'
+
+. git-sh-setup
+require_work_tree
+
+DOTEST="$GIT_DIR/.dotest-merge"
+TODO="$DOTEST"/todo
+DONE="$DOTEST"/done
+REWRITTEN="$DOTEST"/rewritten
+PRESERVE_MERGES=
+STRATEGY=
+VERBOSE=
+test -d "$REWRITTEN" && PRESERVE_MERGES=t
+test -f "$DOTEST"/strategy && STRATEGY="$(cat "$DOTEST"/strategy)"
+test -f "$DOTEST"/verbose && VERBOSE=t
+
+warn () {
+       echo "$*" >&2
+}
+
+require_clean_work_tree () {
+       # test if working tree is dirty
+       git rev-parse --verify HEAD > /dev/null &&
+       git update-index --refresh &&
+       git diff-files --quiet &&
+       git diff-index --cached --quiet HEAD ||
+       die "Working tree is dirty"
+}
+
+ORIG_REFLOG_ACTION="$GIT_REFLOG_ACTION"
+
+comment_for_reflog () {
+       case "$ORIG_REFLOG_ACTION" in
+       ''|rebase*)
+               GIT_REFLOG_ACTION="rebase -i ($1)"
+               export GIT_REFLOG_ACTION
+       esac
+}
+
+mark_action_done () {
+       sed -e 1q < "$TODO" >> "$DONE"
+       sed -e 1d < "$TODO" >> "$TODO".new
+       mv -f "$TODO".new "$TODO"
+}
+
+make_patch () {
+       parent_sha1=$(git rev-parse --verify "$1"^ 2> /dev/null)
+       git diff "$parent_sha1".."$1" > "$DOTEST"/patch
+}
+
+die_with_patch () {
+       test -f "$DOTEST"/message ||
+               git cat-file commit $sha1 | sed "1,/^$/d" > "$DOTEST"/message
+       test -f "$DOTEST"/author-script ||
+               get_author_ident_from_commit $sha1 > "$DOTEST"/author-script
+       make_patch "$1"
+       die "$2"
+}
+
+die_abort () {
+       rm -rf "$DOTEST"
+       die "$1"
+}
+
+pick_one () {
+       case "$1" in -n) sha1=$2 ;; *) sha1=$1 ;; esac
+       git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
+       test -d "$REWRITTEN" &&
+               pick_one_preserving_merges "$@" && return
+       parent_sha1=$(git rev-parse --verify $sha1^ 2>/dev/null)
+       current_sha1=$(git rev-parse --verify HEAD)
+       if [ $current_sha1 = $parent_sha1 ]; then
+               git reset --hard $sha1
+               sha1=$(git rev-parse --short $sha1)
+               warn Fast forward to $sha1
+       else
+               git cherry-pick $STRATEGY "$@"
+       fi
+}
+
+pick_one_preserving_merges () {
+       case "$1" in -n) sha1=$2 ;; *) sha1=$1 ;; esac
+       sha1=$(git rev-parse $sha1)
+
+       if [ -f "$DOTEST"/current-commit ]
+       then
+               current_commit=$(cat "$DOTEST"/current-commit) &&
+               git rev-parse HEAD > "$REWRITTEN"/$current_commit &&
+               rm "$DOTEST"/current-commit ||
+               die "Cannot write current commit's replacement sha1"
+       fi
+
+       # 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 [ -f "$REWRITTEN"/$p ]
+               then
+                       preserve=f
+                       new_p=$(cat "$REWRITTEN"/$p)
+                       test $p != $new_p && fast_forward=f
+                       case "$new_parents" in
+                       *$new_p*)
+                               ;; # do nothing; that parent is already there
+                       *)
+                               new_parents="$new_parents $new_p"
+                       esac
+               fi
+       done
+       case $fast_forward in
+       t)
+               echo "Fast forward to $sha1"
+               test $preserve=f && echo $sha1 > "$REWRITTEN"/$sha1
+               ;;
+       f)
+               test "a$1" = a-n && die "Refusing to squash a merge: $sha1"
+
+               first_parent=$(expr "$new_parents" : " \([^ ]*\)")
+               # detach HEAD to current parent
+               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
+                       author_script=$(get_author_ident_from_commit $sha1)
+                       eval "$author_script"
+                       msg="$(git cat-file commit $sha1 | \
+                               sed -e '1,/^$/d' -e "s/[\"\\]/\\\\&/g")"
+                       # NEEDSWORK: give rerere a chance
+                       if ! git merge $STRATEGY -m "$msg" $new_parents
+                       then
+                               echo "$msg" > "$GIT_DIR"/MERGE_MSG
+                               die Error redoing merge $sha1
+                       fi
+                       ;;
+               *)
+                       git cherry-pick $STRATEGY "$@" ||
+                               die_with_patch $sha1 "Could not pick $sha1"
+               esac
+       esac
+}
+
+do_next () {
+       test -f "$DOTEST"/message && rm "$DOTEST"/message
+       test -f "$DOTEST"/author-script && rm "$DOTEST"/author-script
+       read command sha1 rest < "$TODO"
+       case "$command" in
+       \#|'')
+               mark_action_done
+               ;;
+       pick)
+               comment_for_reflog pick
+
+               mark_action_done
+               pick_one $sha1 ||
+                       die_with_patch $sha1 "Could not apply $sha1... $rest"
+               ;;
+       edit)
+               comment_for_reflog edit
+
+               mark_action_done
+               pick_one $sha1 ||
+                       die_with_patch $sha1 "Could not apply $sha1... $rest"
+               make_patch $sha1
+               warn
+               warn "You can amend the commit now, with"
+               warn
+               warn "  git commit --amend"
+               warn
+               exit 0
+               ;;
+       squash)
+               comment_for_reflog squash
+
+               test -z "$(grep -ve '^$' -e '^#' < $DONE)" &&
+                       die "Cannot 'squash' without a previous commit"
+
+               mark_action_done
+               failed=f
+               pick_one -n $sha1 || failed=t
+               MSG="$DOTEST"/message
+               echo "# This is a combination of two commits." > "$MSG"
+               echo "# The first commit's message is:" >> "$MSG"
+               echo >> "$MSG"
+               git cat-file commit HEAD | sed -e '1,/^$/d' >> "$MSG"
+               echo >> "$MSG"
+               echo "# And this is the 2nd commit message:" >> "$MSG"
+               echo >> "$MSG"
+               git cat-file commit $sha1 | sed -e '1,/^$/d' >> "$MSG"
+               git reset --soft HEAD^
+               author_script=$(get_author_ident_from_commit $sha1)
+               echo "$author_script" > "$DOTEST"/author-script
+               case $failed in
+               f)
+                       # This is like --amend, but with a different message
+                       eval "$author_script"
+                       export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
+                       git commit -F "$MSG" -e
+                       ;;
+               t)
+                       cp "$MSG" "$GIT_DIR"/MERGE_MSG
+                       warn
+                       warn "Could not apply $sha1... $rest"
+                       die_with_patch $sha1 ""
+               esac
+               ;;
+       *)
+               warn "Unknown command: $command $sha1 $rest"
+               die_with_patch $sha1 "Please fix this in the file $TODO."
+       esac
+       test -s "$TODO" && return
+
+       comment_for_reflog finish &&
+       HEADNAME=$(cat "$DOTEST"/head-name) &&
+       OLDHEAD=$(cat "$DOTEST"/head) &&
+       SHORTONTO=$(git rev-parse --short $(cat "$DOTEST"/onto)) &&
+       if [ -d "$REWRITTEN" ]
+       then
+               test -f "$DOTEST"/current-commit &&
+                       current_commit=$(cat "$DOTEST"/current-commit) &&
+                       git rev-parse HEAD > "$REWRITTEN"/$current_commit
+               NEWHEAD=$(cat "$REWRITTEN"/$OLDHEAD)
+       else
+               NEWHEAD=$(git rev-parse HEAD)
+       fi &&
+       message="$GIT_REFLOG_ACTION: $HEADNAME onto $SHORTONTO)" &&
+       git update-ref -m "$message" $HEADNAME $NEWHEAD $OLDHEAD &&
+       git symbolic-ref HEAD $HEADNAME && {
+               test ! -f "$DOTEST"/verbose ||
+                       git diff --stat $(cat "$DOTEST"/head)..HEAD
+       } &&
+       rm -rf "$DOTEST" &&
+       warn "Successfully rebased and updated $HEADNAME."
+
+       exit
+}
+
+do_rest () {
+       while :
+       do
+               do_next
+       done
+}
+
+while case $# in 0) break ;; esac
+do
+       case "$1" in
+       --continue)
+               comment_for_reflog continue
+
+               test -d "$DOTEST" || die "No interactive rebase running"
+
+               # commit if necessary
+               git rev-parse --verify HEAD > /dev/null &&
+               git update-index --refresh &&
+               git diff-files --quiet &&
+               ! git diff-index --cached --quiet HEAD &&
+               . "$DOTEST"/author-script &&
+               export GIT_AUTHOR_NAME GIT_AUTHOR_NAME GIT_AUTHOR_DATE &&
+               git commit -F "$DOTEST"/message -e
+
+               require_clean_work_tree
+               do_rest
+               ;;
+       --abort)
+               comment_for_reflog abort
+
+               test -d "$DOTEST" || die "No interactive rebase running"
+
+               HEADNAME=$(cat "$DOTEST"/head-name)
+               HEAD=$(cat "$DOTEST"/head)
+               git symbolic-ref HEAD $HEADNAME &&
+               git reset --hard $HEAD &&
+               rm -rf "$DOTEST"
+               exit
+               ;;
+       --skip)
+               comment_for_reflog skip
+
+               test -d "$DOTEST" || die "No interactive rebase running"
+
+               git reset --hard && do_rest
+               ;;
+       -s|--strategy)
+               shift
+               case "$#,$1" in
+               *,*=*)
+                       STRATEGY="-s `expr "z$1" : 'z-[^=]*=\(.*\)'`" ;;
+               1,*)
+                       usage ;;
+               *)
+                       STRATEGY="-s $2"
+                       shift ;;
+               esac
+               ;;
+       --merge)
+               # we use merge anyway
+               ;;
+       -C*)
+               die "Interactive rebase uses merge, so $1 does not make sense"
+               ;;
+       -v|--verbose)
+               VERBOSE=t
+               ;;
+       -p|--preserve-merges)
+               PRESERVE_MERGES=t
+               ;;
+       -i|--interactive)
+               # yeah, we know
+               ;;
+       ''|-h)
+               usage
+               ;;
+       *)
+               test -d "$DOTEST" &&
+                       die "Interactive rebase already started"
+
+               git var GIT_COMMITTER_IDENT >/dev/null ||
+                       die "You need to set your committer info first"
+
+               comment_for_reflog start
+
+               ONTO=
+               case "$1" in
+               --onto)
+                       ONTO=$(git rev-parse --verify "$2") ||
+                               die "Does not point to a valid commit: $2"
+                       shift; shift
+                       ;;
+               esac
+
+               require_clean_work_tree
+
+               if [ ! -z "$2"]
+               then
+                       git show-ref --verify --quiet "refs/heads/$2" ||
+                               die "Invalid branchname: $2"
+                       git checkout "$2" ||
+                               die "Could not checkout $2"
+               fi
+
+               HEAD=$(git rev-parse --verify HEAD) || die "No HEAD?"
+               UPSTREAM=$(git rev-parse --verify "$1") || die "Invalid base"
+
+               test -z "$ONTO" && ONTO=$UPSTREAM
+
+               mkdir "$DOTEST" || die "Could not create temporary $DOTEST"
+               : > "$DOTEST"/interactive || die "Could not mark as interactive"
+               git symbolic-ref HEAD > "$DOTEST"/head-name ||
+                       die "Could not get HEAD"
+
+               echo $HEAD > "$DOTEST"/head
+               echo $UPSTREAM > "$DOTEST"/upstream
+               echo $ONTO > "$DOTEST"/onto
+               test -z "$STRATEGY" || echo "$STRATEGY" > "$DOTEST"/strategy
+               test t = "$VERBOSE" && : > "$DOTEST"/verbose
+               if [ t = "$PRESERVE_MERGES" ]
+               then
+                       # $REWRITTEN contains files for each commit that is
+                       # reachable by at least one merge base of $HEAD and
+                       # $UPSTREAM. They are not necessarily rewritten, but
+                       # their children might be.
+                       # This ensures that commits on merged, but otherwise
+                       # unrelated side branches are left alone. (Think "X"
+                       # in the man page's example.)
+                       mkdir "$REWRITTEN" &&
+                       for c in $(git merge-base --all $HEAD $UPSTREAM)
+                       do
+                               echo $ONTO > "$REWRITTEN"/$c ||
+                                       die "Could not init rewritten commits"
+                       done
+                       MERGES_OPTION=
+               else
+                       MERGES_OPTION=--no-merges
+               fi
+
+               SHORTUPSTREAM=$(git rev-parse --short $UPSTREAM)
+               SHORTHEAD=$(git rev-parse --short $HEAD)
+               SHORTONTO=$(git rev-parse --short $ONTO)
+               cat > "$TODO" << EOF
+# Rebasing $SHORTUPSTREAM..$SHORTHEAD onto $SHORTONTO
+#
+# Commands:
+#  pick = use commit
+#  edit = use commit, but stop for amending
+#  squash = use commit, but meld into previous commit
+#
+# If you remove a line here THAT COMMIT WILL BE LOST.
+#
+EOF
+               git rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \
+                       --abbrev=7 --reverse $UPSTREAM..$HEAD | \
+                       sed "s/^/pick /" >> "$TODO"
+
+               test -z "$(grep -ve '^$' -e '^#' < $TODO)" &&
+                       die_abort "Nothing to do"
+
+               cp "$TODO" "$TODO".backup
+               ${VISUAL:-${EDITOR:-vi}} "$TODO" ||
+                       die "Could not execute editor"
+
+               test -z "$(grep -ve '^$' -e '^#' < $TODO)" &&
+                       die_abort "Nothing to do"
+
+               git checkout $ONTO && do_rest
+       esac
+       shift
+done
index 2dc2c4fe9b4d4a7ff10398938efbed28fa6f43f7..cbafa14ed524212441ba76e1bdb558585795e2f3 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano.
 #
 
-USAGE='[-v] [--onto <newbase>] <upstream> [<branch>]'
+USAGE='[--interactive | -i] [-v] [--onto <newbase>] <upstream> [<branch>]'
 LONG_USAGE='git-rebase replaces <branch> with a new branch of the
 same name.  When the --onto option is provided the new branch starts
 out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
@@ -51,15 +51,15 @@ continue_merge () {
        test -n "$prev_head" || die "prev_head must be defined"
        test -d "$dotest" || die "$dotest directory does not exist"
 
-       unmerged=$(git-ls-files -u)
+       unmerged=$(git ls-files -u)
        if test -n "$unmerged"
        then
                echo "You still have unmerged paths in your index"
-               echo "did you forget update-index?"
+               echo "did you forget to use git add?"
                die "$RESOLVEMSG"
        fi
 
-       if ! git-diff-index --quiet HEAD
+       if ! git diff-index --quiet HEAD
        then
                if ! git-commit -C "`cat $dotest/current`"
                then
@@ -71,10 +71,10 @@ continue_merge () {
        else
                printf "Already applied: %0${prec}d" $msgnum
        fi
-       echo ' '`git-rev-list --pretty=oneline -1 HEAD | \
+       echo ' '`git rev-list --pretty=oneline -1 HEAD | \
                                sed 's/^[a-f0-9]\+ //'`
 
-       prev_head=`git-rev-parse HEAD^0`
+       prev_head=`git rev-parse HEAD^0`
        # save the resulting commit so we can read-tree on it later
        echo "$prev_head" > "$dotest/prev_head"
 
@@ -86,8 +86,8 @@ continue_merge () {
 call_merge () {
        cmt="$(cat $dotest/cmt.$1)"
        echo "$cmt" > "$dotest/current"
-       hd=$(git-rev-parse --verify HEAD)
-       cmt_name=$(git-symbolic-ref HEAD)
+       hd=$(git rev-parse --verify HEAD)
+       cmt_name=$(git symbolic-ref HEAD)
        msgnum=$(cat $dotest/msgnum)
        end=$(cat $dotest/end)
        eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
@@ -101,7 +101,7 @@ call_merge () {
                return
                ;;
        1)
-               test -d "$GIT_DIR/rr-cache" && git-rerere
+               git rerere
                die "$RESOLVEMSG"
                ;;
        2)
@@ -120,13 +120,23 @@ finish_rb_merge () {
        echo "All done."
 }
 
+is_interactive () {
+       test -f "$dotest"/interactive ||
+       while case $#,"$1" in 0,|*,-i|*,--interactive) break ;; esac
+       do
+               shift
+       done && test -n "$1"
+}
+
+is_interactive "$@" && exec git-rebase--interactive "$@"
+
 while case "$#" in 0) break ;; esac
 do
        case "$1" in
        --continue)
-               git-diff-files --quiet || {
+               git diff-files --quiet || {
                        echo "You must edit all merge conflicts and then"
-                       echo "mark them as resolved using git update-index"
+                       echo "mark them as resolved using git add"
                        exit 1
                }
                if test -d "$dotest"
@@ -150,10 +160,7 @@ do
        --skip)
                if test -d "$dotest"
                then
-                       if test -d "$GIT_DIR/rr-cache"
-                       then
-                               git-rerere clear
-                       fi
+                       git rerere clear
                        prev_head="`cat $dotest/prev_head`"
                        end="`cat $dotest/end`"
                        msgnum="`cat $dotest/msgnum`"
@@ -171,10 +178,7 @@ do
                exit
                ;;
        --abort)
-               if test -d "$GIT_DIR/rr-cache"
-               then
-                       git-rerere clear
-               fi
+               git rerere clear
                if test -d "$dotest"
                then
                        rm -r "$dotest"
@@ -249,8 +253,8 @@ else
 fi
 
 # The tree must be really really clean.
-git-update-index --refresh || exit
-diff=$(git-diff-index --cached --name-status -r HEAD)
+git update-index --refresh || exit
+diff=$(git diff-index --cached --name-status -r HEAD)
 case "$diff" in
 ?*)    echo "cannot rebase: your index is not up-to-date"
        echo "$diff"
@@ -265,7 +269,7 @@ upstream=`git rev-parse --verify "${upstream_name}^0"` ||
 
 # Make sure the branch to rebase onto is valid.
 onto_name=${newbase-"$upstream_name"}
-onto=$(git-rev-parse --verify "${onto_name}^0") || exit
+onto=$(git rev-parse --verify "${onto_name}^0") || exit
 
 # If a hook exists, give it a chance to interrupt
 if test -x "$GIT_DIR/hooks/pre-rebase"
@@ -291,14 +295,16 @@ case "$#" in
        fi
        ;;
 esac
-branch=$(git-rev-parse --verify "${branch_name}^0") || exit
+branch=$(git rev-parse --verify "${branch_name}^0") || exit
 
 # Now we are rebasing commits $upstream..$branch on top of $onto
 
-# Check if we are already based on $onto, but this should be
-# done only when upstream and onto are the same.
-mb=$(git-merge-base "$onto" "$branch")
-if test "$upstream" = "$onto" && test "$mb" = "$onto"
+# Check if we are already based on $onto with linear history,
+# but this should be done only when upstream and onto are the same.
+mb=$(git merge-base "$onto" "$branch")
+if test "$upstream" = "$onto" && test "$mb" = "$onto" &&
+       # linear history?
+       ! git rev-list --parents "$onto".."$branch" | grep " .* " > /dev/null
 then
        echo >&2 "Current branch $branch_name is up to date."
        exit 0
@@ -307,7 +313,8 @@ fi
 if test -n "$verbose"
 then
        echo "Changes from $mb to $onto:"
-       git-diff-tree --stat --summary "$mb" "$onto"
+       # We want color (if set), but no pager
+       GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
 fi
 
 # Rewind the head to "$onto"; this saves our current head in ORIG_HEAD.
@@ -324,7 +331,7 @@ fi
 
 if test -z "$do_merge"
 then
-       git-format-patch -k --stdout --full-index --ignore-if-in-upstream "$upstream"..ORIG_HEAD |
+       git format-patch -k --stdout --full-index --ignore-if-in-upstream "$upstream"..ORIG_HEAD |
        git am $git_am_opt --binary -3 -k --resolvemsg="$RESOLVEMSG"
        exit $?
 fi
@@ -335,11 +342,11 @@ fi
 mkdir -p "$dotest"
 echo "$onto" > "$dotest/onto"
 echo "$onto_name" > "$dotest/onto_name"
-prev_head=`git-rev-parse HEAD^0`
+prev_head=`git rev-parse HEAD^0`
 echo "$prev_head" > "$dotest/prev_head"
 
 msgnum=0
-for cmt in `git-rev-list --reverse --no-merges "$upstream"..ORIG_HEAD`
+for cmt in `git rev-list --reverse --no-merges "$upstream"..ORIG_HEAD`
 do
        msgnum=$(($msgnum + 1))
        echo "$cmt" > "$dotest/cmt.$msgnum"
index 576379912793c9740620892cd3ee1cf7d2f18cfe..01cf480221be1e5860bd701d5d17ced25766d38d 100755 (executable)
@@ -258,6 +258,7 @@ sub show_remote {
        if ($info->{'PUSH'}) {
                my @pushed = map {
                        s|^refs/heads/||;
+                       s|^\+refs/heads/|+|;
                        s|:refs/heads/|:|;
                        $_;
                } @{$info->{'PUSH'}};
@@ -318,9 +319,21 @@ sub add_usage {
        exit(1);
 }
 
+local $VERBOSE = 0;
+@ARGV = grep {
+       if ($_ eq '-v' or $_ eq '--verbose') {
+               $VERBOSE=1;
+               0
+       } else {
+               1
+       }
+} @ARGV;
+
 if (!@ARGV) {
        for (sort keys %$remote) {
-               print "$_\n";
+               print "$_";
+               print "\t$remote->{$_}->{URL}" if $VERBOSE;
+               print "\n";
        }
 }
 elsif ($ARGV[0] eq 'show') {
index ddfa8b44a17f1ea7ff039bca1d6132ba07e5cf12..b5c667110d31fe9e083f8b7d4db727ed63333e37 100755 (executable)
@@ -3,12 +3,12 @@
 # Copyright (c) 2005 Linus Torvalds
 #
 
-USAGE='[-a] [-d] [-f] [-l] [-n] [-q] [--window=N] [--depth=N]'
+USAGE='[-a] [-d] [-f] [-l] [-n] [-q] [--max-pack-size=N] [--window=N] [--depth=N]'
 SUBDIRECTORY_OK='Yes'
 . git-sh-setup
 
 no_update_info= all_into_one= remove_redundant=
-local= quiet= no_reuse_delta= extra=
+local= quiet= no_reuse= extra=
 while case "$#" in 0) break ;; esac
 do
        case "$1" in
@@ -16,8 +16,9 @@ do
        -a)     all_into_one=t ;;
        -d)     remove_redundant=t ;;
        -q)     quiet=-q ;;
-       -f)     no_reuse_delta=--no-reuse-delta ;;
+       -f)     no_reuse=--no-reuse-object ;;
        -l)     local=--local ;;
+       --max-pack-size=*) extra="$extra $1" ;;
        --window=*) extra="$extra $1" ;;
        --depth=*) extra="$extra $1" ;;
        *)      usage ;;
@@ -35,7 +36,7 @@ true)
 esac
 
 PACKDIR="$GIT_OBJECT_DIRECTORY/pack"
-PACKTMP="$GIT_DIR/.tmp-$$-pack"
+PACKTMP="$GIT_OBJECT_DIRECTORY/.tmp-$$-pack"
 rm -f "$PACKTMP"-*
 trap 'rm -f "$PACKTMP"-*' 0 1 2 3 15
 
@@ -61,12 +62,16 @@ case ",$all_into_one," in
        ;;
 esac
 
-args="$args $local $quiet $no_reuse_delta$extra"
-name=$(git-pack-objects --non-empty --all --reflog $args </dev/null "$PACKTMP") ||
+args="$args $local $quiet $no_reuse$extra"
+names=$(git pack-objects --non-empty --all --reflog $args </dev/null "$PACKTMP") ||
        exit 1
-if [ -z "$name" ]; then
-       echo Nothing new to pack.
-else
+if [ -z "$names" ]; then
+       if test -z "$quiet"; then
+               echo Nothing new to pack.
+       fi
+fi
+for name in $names ; do
+       fullbases="$fullbases pack-$name"
        chmod a-w "$PACKTMP-$name.pack"
        chmod a-w "$PACKTMP-$name.idx"
        if test "$quiet" != '-q'; then
@@ -92,7 +97,7 @@ else
                exit 1
        }
        rm -f "$PACKDIR/old-pack-$name.pack" "$PACKDIR/old-pack-$name.idx"
-fi
+done
 
 if test "$remove_redundant" = t
 then
@@ -103,14 +108,14 @@ then
                ( cd "$PACKDIR" &&
                  for e in $existing
                  do
-                       case "$e" in
-                       pack-$name) ;;
+                       case " $fullbases " in
+                       *" $e "*) ;;
                        *)      rm -f "$e.pack" "$e.idx" "$e.keep" ;;
                        esac
                  done
                )
        fi
-       git-prune-packed $quiet
+       git prune-packed $quiet
 fi
 
 case "$no_update_info" in
index ba577d4ce1b0aaf5777667410dc9cca6c999df1d..a992430679ab2c4b3c8c5eeb5a26a6fbba0976f4 100755 (executable)
@@ -18,8 +18,8 @@ head=${3-HEAD}
 [ "$base" ] || usage
 [ "$url" ] || usage
 
-baserev=`git-rev-parse --verify "$base"^0` &&
-headrev=`git-rev-parse --verify "$head"^0` || exit
+baserev=`git rev-parse --verify "$base"^0` &&
+headrev=`git rev-parse --verify "$head"^0` || exit
 
 merge_base=`git merge-base $baserev $headrev` ||
 die "fatal: No commits in common between $base and $head"
index a172d7ce25b40f192b0036d29a8a60e62649159c..1dc606fbd3fd29f5f4c9928a2518df46109ef449 100755 (executable)
@@ -24,7 +24,7 @@ do
                usage
                ;;
        *)
-               rev=$(git-rev-parse --verify "$1") || exit
+               rev=$(git rev-parse --verify "$1") || exit
                shift
                break
                ;;
@@ -33,7 +33,7 @@ do
 done
 
 : ${rev=HEAD}
-rev=$(git-rev-parse --verify $rev^0) || exit
+rev=$(git rev-parse --verify $rev^0) || exit
 
 # Skip -- in "git reset HEAD -- foo" and "git reset -- foo".
 case "$1" in --) shift ;; esac
@@ -46,7 +46,7 @@ then
        test "$reset_type" = "--mixed" ||
                die "Cannot do partial $reset_type reset."
 
-       git-diff-index --cached $rev -- "$@" |
+       git diff-index --cached $rev -- "$@" |
        sed -e 's/^:\([0-7][0-7]*\) [0-7][0-7]* \([0-9a-f][0-9a-f]*\) [0-9a-f][0-9a-f]* [A-Z]   \(.*\)$/\1 \2   \3/' |
        git update-index --add --remove --index-info || exit
        git update-index --refresh
@@ -66,22 +66,22 @@ fi
 if test "$reset_type" = "--soft"
 then
        if test -f "$GIT_DIR/MERGE_HEAD" ||
-          test "" != "$(git-ls-files --unmerged)"
+          test "" != "$(git ls-files --unmerged)"
        then
                die "Cannot do a soft reset in the middle of a merge."
        fi
 else
-       git-read-tree -v --reset $update "$rev" || exit
+       git read-tree -v --reset $update "$rev" || exit
 fi
 
 # Any resets update HEAD to the head being switched to.
-if orig=$(git-rev-parse --verify HEAD 2>/dev/null)
+if orig=$(git rev-parse --verify HEAD 2>/dev/null)
 then
        echo "$orig" >"$GIT_DIR/ORIG_HEAD"
 else
        rm -f "$GIT_DIR/ORIG_HEAD"
 fi
-git-update-ref -m "$GIT_REFLOG_ACTION" HEAD "$rev"
+git update-ref -m "$GIT_REFLOG_ACTION" HEAD "$rev"
 update_ref_status=$?
 
 case "$reset_type" in
@@ -96,7 +96,7 @@ case "$reset_type" in
        ;; # Nothing else to do
 --mixed )
        # Report what has not been updated.
-       git-update-index --refresh
+       git update-index --refresh
        ;;
 esac
 
index 7c0c90bd21bbb009de81aa315bed1c947a32c423..89f7c36ee527e84a663eb6c6ea51ae9614e0ead9 100755 (executable)
@@ -64,15 +64,17 @@ Options:
                   email sent, rather than to the first email sent.
                   Defaults to on.
 
-   --no-signed-off-cc Suppress the automatic addition of email addresses
-                 that appear in Signed-off-by: or Cc: lines to the cc:
-                 list.  Note: Using this option is not recommended.
+   --signed-off-cc Automatically add email addresses that appear in
+                 Signed-off-by: or Cc: lines to the cc: list. Defaults to on.
 
    --smtp-server  If set, specifies the outgoing SMTP server to use.
                   Defaults to localhost.
 
    --suppress-from Suppress sending emails to yourself if your address
-                  appears in a From: line.
+                  appears in a From: line. Defaults to off.
+
+   --thread       Specify that the "In-Reply-To:" header should be set on all
+                  emails. Defaults to on.
 
    --quiet       Make git-send-email less verbose.  One line per email
                   should be all that is output.
@@ -137,9 +139,6 @@ my $compose_filename = ".msg.$$";
 my (@to,@cc,@initial_cc,@bcclist,@xh,
        $initial_reply_to,$initial_subject,@files,$from,$compose,$time);
 
-# Behavior modification variables
-my ($chain_reply_to, $quiet, $suppress_from, $no_signed_off_cc,
-       $dry_run) = (1, 0, 0, 0, 0);
 my $smtp_server;
 my $envelope_sender;
 
@@ -154,9 +153,22 @@ if ($@) {
        $term = new FakeTerm "$@: going non-interactive";
 }
 
-my $def_chain = $repo->config_bool('sendemail.chainreplyto');
-if (defined $def_chain and not $def_chain) {
-    $chain_reply_to = 0;
+# Behavior modification variables
+my ($quiet, $dry_run) = (0, 0);
+
+# Variables with corresponding config settings
+my ($thread, $chain_reply_to, $suppress_from, $signed_off_cc);
+
+my %config_settings = (
+    "thread" => [\$thread, 1],
+    "chainreplyto" => [\$chain_reply_to, 1],
+    "suppressfrom" => [\$suppress_from, 0],
+    "signedoffcc" => [\$signed_off_cc, 1],
+);
+
+foreach my $setting (keys %config_settings) {
+    my $config = $repo->config_bool("sendemail.$setting");
+    ${$config_settings{$setting}->[0]} = (defined $config) ? $config : $config_settings{$setting}->[1];
 }
 
 @bcclist = $repo->config('sendemail.bcc');
@@ -177,10 +189,11 @@ my $rc = GetOptions("from=s" => \$from,
                    "smtp-server=s" => \$smtp_server,
                    "compose" => \$compose,
                    "quiet" => \$quiet,
-                   "suppress-from" => \$suppress_from,
-                   "no-signed-off-cc|no-signed-off-by-cc" => \$no_signed_off_cc,
+                   "suppress-from!" => \$suppress_from,
+                   "signed-off-cc|signed-off-by-cc!" => \$signed_off_cc,
                    "dry-run" => \$dry_run,
                    "envelope-sender=s" => \$envelope_sender,
+                   "thread!" => \$thread,
         );
 
 unless ($rc) {
@@ -241,6 +254,8 @@ if (@alias_files and $aliasfiletype and defined $parse_alias{$aliasfiletype}) {
        }
 }
 
+($from) = expand_aliases($from) if defined $from;
+
 my $prompting = 0;
 if (!defined $from) {
        $from = $author || $committer;
@@ -287,7 +302,7 @@ if (!defined $initial_subject && $compose) {
        $prompting++;
 }
 
-if (!defined $initial_reply_to && $prompting) {
+if ($thread && !defined $initial_reply_to && $prompting) {
        do {
                $_= $term->readline("Message-ID to be used as In-Reply-To for the first email? ",
                        $initial_reply_to);
@@ -412,13 +427,21 @@ sub extract_valid_address {
 # 1 second since the last time we were called.
 
 # We'll setup a template for the message id, using the "from" address:
-my $message_id_from = extract_valid_address($from);
-my $message_id_template = "<%s-git-send-email-$message_id_from>";
 
 sub make_message_id
 {
        my $date = time;
        my $pseudo_rand = int (rand(4200));
+       my $du_part;
+       for ($from, $committer, $author) {
+               $du_part = extract_valid_address($_);
+               last if ($du_part ne '');
+       }
+       if ($du_part eq '') {
+               use Sys::Hostname qw();
+               $du_part = 'user@' . Sys::Hostname::hostname();
+       }
+       my $message_id_template = "<%s-git-send-email-$du_part>";
        $message_id = sprintf $message_id_template, "$date$pseudo_rand";
        #print "new message id = $message_id\n"; # Was useful for debugging
 }
@@ -467,6 +490,8 @@ sub send_message
                $ccline = "\nCc: $cc";
        }
        $from = sanitize_address_rfc822($from);
+       make_message_id();
+
        my $header = "From: $from
 To: $to${ccline}
 Subject: $subject
@@ -474,7 +499,7 @@ Date: $date
 Message-Id: $message_id
 X-Mailer: git-send-email $gitversion
 ";
-       if ($reply_to) {
+       if ($thread && $reply_to) {
 
                $header .= "In-Reply-To: $reply_to\n";
                $header .= "References: $references\n";
@@ -533,7 +558,6 @@ X-Mailer: git-send-email $gitversion
 
 $reply_to = $initial_reply_to;
 $references = $initial_reply_to || '';
-make_message_id();
 $subject = $initial_subject;
 
 foreach my $t (@files) {
@@ -600,7 +624,7 @@ foreach my $t (@files) {
                        }
                } else {
                        $message .=  $_;
-                       if (/^(Signed-off-by|Cc): (.*)$/i && !$no_signed_off_cc) {
+                       if (/^(Signed-off-by|Cc): (.*)$/i && $signed_off_cc) {
                                my $c = $2;
                                chomp $c;
                                push @cc, $c;
@@ -627,7 +651,6 @@ foreach my $t (@files) {
                        $references = "$message_id";
                }
        }
-       make_message_id();
 }
 
 if ($compose) {
index f24c7f2d23c13e9874308a019f3c0f93225de3c0..4ed07e9ddca885e8a4f184a68bb6363fdc7c56e9 100755 (executable)
@@ -29,15 +29,11 @@ set_reflog_action() {
 }
 
 is_bare_repository () {
-       git-config --bool --get core.bare ||
-       case "$GIT_DIR" in
-       .git | */.git) echo false ;;
-       *) echo true ;;
-       esac
+       git rev-parse --is-bare-repository
 }
 
 cd_to_toplevel () {
-       cdup=$(git-rev-parse --show-cdup)
+       cdup=$(git rev-parse --show-cdup)
        if test ! -z "$cdup"
        then
                cd "$cdup" || {
@@ -48,11 +44,38 @@ cd_to_toplevel () {
 }
 
 require_work_tree () {
-       test $(is_bare_repository) = false &&
-       test $(git-rev-parse --is-inside-git-dir) = false ||
+       test $(git rev-parse --is-inside-work-tree) = true &&
+       test $(git rev-parse --is-inside-git-dir) = false ||
        die "fatal: $0 cannot be used without a working tree."
 }
 
+get_author_ident_from_commit () {
+       pick_author_script='
+       /^author /{
+               s/'\''/'\''\\'\'\''/g
+               h
+               s/^author \([^<]*\) <[^>]*> .*$/\1/
+               s/'\''/'\''\'\'\''/g
+               s/.*/GIT_AUTHOR_NAME='\''&'\''/p
+
+               g
+               s/^author [^<]* <\([^>]*\)> .*$/\1/
+               s/'\''/'\''\'\'\''/g
+               s/.*/GIT_AUTHOR_EMAIL='\''&'\''/p
+
+               g
+               s/^author [^<]* <[^>]*> \(.*\)$/\1/
+               s/'\''/'\''\'\'\''/g
+               s/.*/GIT_AUTHOR_DATE='\''&'\''/p
+
+               q
+       }
+       '
+       encoding=$(git config i18n.commitencoding || echo UTF-8)
+       git show -s --pretty=raw --encoding="$encoding" "$1" |
+       LANG=C LC_ALL=C sed -ne "$pick_author_script"
+}
+
 if [ -z "$LONG_USAGE" ]
 then
        LONG_USAGE="Usage: $0 $USAGE"
@@ -72,12 +95,12 @@ esac
 if [ -z "$SUBDIRECTORY_OK" ]
 then
        : ${GIT_DIR=.git}
-       GIT_DIR=$(GIT_DIR="$GIT_DIR" git-rev-parse --git-dir) || {
+       GIT_DIR=$(GIT_DIR="$GIT_DIR" git rev-parse --git-dir) || {
                exit=$?
                echo >&2 "You need to run this command from the toplevel of the working tree."
                exit $exit
        }
 else
-       GIT_DIR=$(git-rev-parse --git-dir) || exit
+       GIT_DIR=$(git rev-parse --git-dir) || exit
 fi
 : ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
diff --git a/git-stash.sh b/git-stash.sh
new file mode 100755 (executable)
index 0000000..de13dd1
--- /dev/null
@@ -0,0 +1,198 @@
+#!/bin/sh
+# Copyright (c) 2007, Nanako Shiraishi
+
+USAGE='[ | list | show | apply | clear]'
+
+SUBDIRECTORY_OK=Yes
+. git-sh-setup
+require_work_tree
+
+TMP="$GIT_DIR/.git-stash.$$"
+trap 'rm -f "$TMP-*"' 0
+
+ref_stash=refs/stash
+
+no_changes () {
+       git diff-index --quiet --cached HEAD &&
+       git diff-files --quiet
+}
+
+clear_stash () {
+       logfile="$GIT_DIR/logs/$ref_stash" &&
+       mkdir -p "$(dirname "$logfile")" &&
+       : >"$logfile"
+}
+
+save_stash () {
+       stash_msg="$1"
+
+       if no_changes
+       then
+               echo >&2 'No local changes to save'
+               exit 0
+       fi
+       test -f "$GIT_DIR/logs/$ref_stash" ||
+               clear_stash || die "Cannot initialize stash"
+
+       # state of the base commit
+       if b_commit=$(git rev-parse --verify HEAD)
+       then
+               head=$(git log --abbrev-commit --pretty=oneline -n 1 HEAD)
+       else
+               die "You do not have the initial commit yet"
+       fi
+
+       if branch=$(git symbolic-ref -q HEAD)
+       then
+               branch=${branch#refs/heads/}
+       else
+               branch='(no branch)'
+       fi
+       msg=$(printf '%s: %s' "$branch" "$head")
+
+       # state of the index
+       i_tree=$(git write-tree) &&
+       i_commit=$(printf 'index on %s' "$msg" |
+               git commit-tree $i_tree -p $b_commit) ||
+               die "Cannot save the current index state"
+
+       # state of the working tree
+       w_tree=$( (
+               rm -f "$TMP-index" &&
+               cp -p ${GIT_INDEX_FILE-"$GIT_DIR/index"} "$TMP-index" &&
+               GIT_INDEX_FILE="$TMP-index" &&
+               export GIT_INDEX_FILE &&
+               git read-tree -m $i_tree &&
+               git add -u &&
+               git write-tree &&
+               rm -f "$TMP-index"
+       ) ) ||
+               die "Cannot save the current worktree state"
+
+       # create the stash
+       if test -z "$stash_msg"
+       then
+               stash_msg=$(printf 'WIP on %s' "$msg")
+       else
+               stash_msg=$(printf 'On %s: %s' "$branch" "$stash_msg")
+       fi
+       w_commit=$(printf '%s\n' "$stash_msg" |
+               git commit-tree $w_tree -p $b_commit -p $i_commit) ||
+               die "Cannot record working tree state"
+
+       git update-ref -m "$stash_msg" $ref_stash $w_commit ||
+               die "Cannot save the current status"
+       printf >&2 'Saved "%s"\n' "$stash_msg"
+}
+
+have_stash () {
+       git rev-parse --verify $ref_stash >/dev/null 2>&1
+}
+
+list_stash () {
+       have_stash || return 0
+       git log --pretty=oneline -g "$@" $ref_stash |
+       sed -n -e 's/^[.0-9a-f]* refs\///p'
+}
+
+show_stash () {
+       flags=$(git rev-parse --no-revs --flags "$@")
+       if test -z "$flags"
+       then
+               flags=--stat
+       fi
+       s=$(git rev-parse --revs-only --no-flags --default $ref_stash "$@")
+
+       w_commit=$(git rev-parse --verify "$s") &&
+       b_commit=$(git rev-parse --verify "$s^") &&
+       git diff $flags $b_commit $w_commit
+}
+
+apply_stash () {
+       git diff-files --quiet ||
+               die 'Cannot restore on top of a dirty state'
+
+       unstash_index=
+       case "$1" in
+       --index)
+               unstash_index=t
+               shift
+       esac
+
+       # current index state
+       c_tree=$(git write-tree) ||
+               die 'Cannot apply a stash in the middle of a merge'
+
+       s=$(git rev-parse --revs-only --no-flags --default $ref_stash "$@") &&
+       w_tree=$(git rev-parse --verify "$s:") &&
+       b_tree=$(git rev-parse --verify "$s^:") ||
+               die "$*: no valid stashed state found"
+
+       test -z "$unstash_index" || {
+               git diff --binary $s^2^..$s^2 | git apply --cached
+               test $? -ne 0 &&
+                       die 'Conflicts in index. Try without --index.'
+               unstashed_index_tree=$(git-write-tree) ||
+                       die 'Could not save index tree'
+               git reset
+       }
+
+       eval "
+               GITHEAD_$w_tree='Stashed changes' &&
+               GITHEAD_$c_tree='Updated upstream' &&
+               GITHEAD_$b_tree='Version stash was based on' &&
+               export GITHEAD_$w_tree GITHEAD_$c_tree GITHEAD_$b_tree
+       "
+
+       if git-merge-recursive $b_tree -- $c_tree $w_tree
+       then
+               # No conflict
+               a="$TMP-added" &&
+               git diff --cached --name-only --diff-filter=A $c_tree >"$a" &&
+               git read-tree --reset $c_tree &&
+               git update-index --add --stdin <"$a" ||
+                       die "Cannot unstage modified files"
+               git-status
+               rm -f "$a"
+               test -z "$unstash_index" || git read-tree $unstashed_index_tree
+       else
+               # Merge conflict; keep the exit status from merge-recursive
+               status=$?
+               test -z "$unstash_index" || echo 'Index was not unstashed.' >&2
+               exit $status
+       fi
+}
+
+# Main command set
+case "$1" in
+list)
+       shift
+       if test $# = 0
+       then
+               set x -n 10
+               shift
+       fi
+       list_stash "$@"
+       ;;
+show)
+       shift
+       show_stash "$@"
+       ;;
+apply)
+       shift
+       apply_stash "$@"
+       ;;
+clear)
+       clear_stash
+       ;;
+help | usage)
+       usage
+       ;;
+*)
+       if test $# -gt 0 && test "$1" = save
+       then
+               shift
+       fi
+       save_stash "$*" && git-reset --hard
+       ;;
+esac
diff --git a/git-submodule.sh b/git-submodule.sh
new file mode 100755 (executable)
index 0000000..1f0cb99
--- /dev/null
@@ -0,0 +1,320 @@
+#!/bin/sh
+#
+# git-submodules.sh: add, init, update or list git submodules
+#
+# Copyright (c) 2007 Lars Hjemli
+
+USAGE='[--quiet] [--cached] [add <repo> [-b branch]|status|init|update] [--] [<path>...]'
+. git-sh-setup
+require_work_tree
+
+add=
+branch=
+init=
+update=
+status=
+quiet=
+cached=
+
+#
+# print stuff on stdout unless -q was specified
+#
+say()
+{
+       if test -z "$quiet"
+       then
+               echo "$@"
+       fi
+}
+
+# NEEDSWORK: identical function exists in get_repo_base in clone.sh
+get_repo_base() {
+       (
+               cd "`/bin/pwd`" &&
+               cd "$1" || cd "$1.git" &&
+               {
+                       cd .git
+                       pwd
+               }
+       ) 2>/dev/null
+}
+
+#
+# Map submodule path to submodule name
+#
+# $1 = path
+#
+module_name()
+{
+       name=$(GIT_CONFIG=.gitmodules git config --get-regexp '^submodule\..*\.path$' "$1" |
+       sed -nre 's/^submodule\.(.+)\.path .+$/\1/p')
+       test -z "$name" &&
+       die "No submodule mapping found in .gitmodules for path '$path'"
+       echo "$name"
+}
+
+#
+# Clone a submodule
+#
+# Prior to calling, modules_update checks that a possibly existing
+# path is not a git repository.
+# Likewise, module_add checks that path does not exist at all,
+# since it is the location of a new submodule.
+#
+module_clone()
+{
+       path=$1
+       url=$2
+
+       # If there already is a directory at the submodule path,
+       # expect it to be empty (since that is the default checkout
+       # action) and try to remove it.
+       # Note: if $path is a symlink to a directory the test will
+       # succeed but the rmdir will fail. We might want to fix this.
+       if test -d "$path"
+       then
+               rmdir "$path" 2>/dev/null ||
+               die "Directory '$path' exist, but is neither empty nor a git repository"
+       fi
+
+       test -e "$path" &&
+       die "A file already exist at path '$path'"
+
+       git-clone -n "$url" "$path" ||
+       die "Clone of '$url' into submodule path '$path' failed"
+}
+
+#
+# Add a new submodule to the working tree, .gitmodules and the index
+#
+# $@ = repo [path]
+#
+# optional branch is stored in global branch variable
+#
+module_add()
+{
+       repo=$1
+       path=$2
+
+       if test -z "$repo"; then
+               usage
+       fi
+
+       # Turn the source into an absolute path if
+       # it is local
+       if base=$(get_repo_base "$repo"); then
+               repo="$base"
+       fi
+
+       # Guess path from repo if not specified or strip trailing slashes
+       if test -z "$path"; then
+               path=$(echo "$repo" | sed -e 's|/*$||' -e 's|:*/*\.git$||' -e 's|.*[/:]||g')
+       else
+               path=$(echo "$path" | sed -e 's|/*$||')
+       fi
+
+       test -e "$path" &&
+       die "'$path' already exists"
+
+       git ls-files --error-unmatch "$path" > /dev/null 2>&1 &&
+       die "'$path' already exists in the index"
+
+       module_clone "$path" "$repo" || exit
+       (unset GIT_DIR && cd "$path" && git checkout -q ${branch:+-b "$branch" "origin/$branch"}) ||
+       die "Unable to checkout submodule '$path'"
+       git add "$path" ||
+       die "Failed to add submodule '$path'"
+
+       GIT_CONFIG=.gitmodules git config submodule."$path".path "$path" &&
+       GIT_CONFIG=.gitmodules git config submodule."$path".url "$repo" &&
+       git add .gitmodules ||
+       die "Failed to register submodule '$path'"
+}
+
+#
+# Register submodules in .git/config
+#
+# $@ = requested paths (default to all)
+#
+modules_init()
+{
+       git ls-files --stage -- "$@" | grep -e '^160000 ' |
+       while read mode sha1 stage path
+       do
+               # Skip already registered paths
+               name=$(module_name "$path") || exit
+               url=$(git config submodule."$name".url)
+               test -z "$url" || continue
+
+               url=$(GIT_CONFIG=.gitmodules git config submodule."$name".url)
+               test -z "$url" &&
+               die "No url found for submodule path '$path' in .gitmodules"
+
+               git config submodule."$name".url "$url" ||
+               die "Failed to register url for submodule path '$path'"
+
+               say "Submodule '$name' ($url) registered for path '$path'"
+       done
+}
+
+#
+# Update each submodule path to correct revision, using clone and checkout as needed
+#
+# $@ = requested paths (default to all)
+#
+modules_update()
+{
+       git ls-files --stage -- "$@" | grep -e '^160000 ' |
+       while read mode sha1 stage path
+       do
+               name=$(module_name "$path") || exit
+               url=$(git config submodule."$name".url)
+               if test -z "$url"
+               then
+                       # Only mention uninitialized submodules when its
+                       # path have been specified
+                       test "$#" != "0" &&
+                       say "Submodule path '$path' not initialized"
+                       continue
+               fi
+
+               if ! test -d "$path"/.git
+               then
+                       module_clone "$path" "$url" || exit
+                       subsha1=
+               else
+                       subsha1=$(unset GIT_DIR && cd "$path" &&
+                               git rev-parse --verify HEAD) ||
+                       die "Unable to find current revision in submodule path '$path'"
+               fi
+
+               if test "$subsha1" != "$sha1"
+               then
+                       (unset GIT_DIR && cd "$path" && git-fetch &&
+                               git-checkout -q "$sha1") ||
+                       die "Unable to checkout '$sha1' in submodule path '$path'"
+
+                       say "Submodule path '$path': checked out '$sha1'"
+               fi
+       done
+}
+
+set_name_rev () {
+       revname=$( (
+               unset GIT_DIR &&
+               cd "$1" && {
+                       git describe "$2" 2>/dev/null ||
+                       git describe --tags "$2" 2>/dev/null ||
+                       git describe --contains --tags "$2"
+               }
+       ) )
+       test -z "$revname" || revname=" ($revname)"
+}
+
+#
+# List all submodules, prefixed with:
+#  - submodule not initialized
+#  + different revision checked out
+#
+# If --cached was specified the revision in the index will be printed
+# instead of the currently checked out revision.
+#
+# $@ = requested paths (default to all)
+#
+modules_list()
+{
+       git ls-files --stage -- "$@" | grep -e '^160000 ' |
+       while read mode sha1 stage path
+       do
+               name=$(module_name "$path") || exit
+               url=$(git config submodule."$name".url)
+               if test -z "url" || ! test -d "$path"/.git
+               then
+                       say "-$sha1 $path"
+                       continue;
+               fi
+               revname=$(unset GIT_DIR && cd "$path" && git describe --tags $sha1)
+               set_name_rev "$path" "$sha1"
+               if git diff-files --quiet -- "$path"
+               then
+                       say " $sha1 $path$revname"
+               else
+                       if test -z "$cached"
+                       then
+                               sha1=$(unset GIT_DIR && cd "$path" && git rev-parse --verify HEAD)
+                               set_name_rev "$path" "$sha1"
+                       fi
+                       say "+$sha1 $path$revname"
+               fi
+       done
+}
+
+while case "$#" in 0) break ;; esac
+do
+       case "$1" in
+       add)
+               add=1
+               ;;
+       init)
+               init=1
+               ;;
+       update)
+               update=1
+               ;;
+       status)
+               status=1
+               ;;
+       -q|--quiet)
+               quiet=1
+               ;;
+       -b|--branch)
+               case "$2" in
+               '')
+                       usage
+                       ;;
+               esac
+               branch="$2"; shift
+               ;;
+       --cached)
+               cached=1
+               ;;
+       --)
+               break
+               ;;
+       -*)
+               usage
+               ;;
+       *)
+               break
+               ;;
+       esac
+       shift
+done
+
+case "$add,$branch" in
+1,*)
+       ;;
+,)
+       ;;
+,*)
+       usage
+       ;;
+esac
+
+case "$add,$init,$update,$status,$cached" in
+1,,,,)
+       module_add "$@"
+       ;;
+,1,,,)
+       modules_init "$@"
+       ;;
+,,1,,)
+       modules_update "$@"
+       ;;
+,,,1,*)
+       modules_list "$@"
+       ;;
+*)
+       usage
+       ;;
+esac
index e35006142af766080b3bafe0cdcd39bf2ccf3f04..b3dffccf38a52714f000f1f90b6c32ecdeb43f82 100755 (executable)
@@ -38,14 +38,16 @@ use IPC::Open3;
 use Git;
 
 BEGIN {
-       my $s;
+       # import functions from Git into our packages, en masse
+       no strict 'refs';
        foreach (qw/command command_oneline command_noisy command_output_pipe
                    command_input_pipe command_close_pipe/) {
-               $s .= "*SVN::Git::Editor::$_ = *SVN::Git::Fetcher::$_ = ".
-                     "*Git::SVN::Migration::$_ = ".
-                     "*Git::SVN::Log::$_ = *Git::SVN::$_ = *$_ = *Git::$_; ";
+               for my $package ( qw(SVN::Git::Editor SVN::Git::Fetcher
+                       Git::SVN::Migration Git::SVN::Log Git::SVN),
+                       __PACKAGE__) {
+                       *{"${package}::$_"} = \&{"Git::$_"};
+               }
        }
-       eval $s;
 }
 
 my ($SVN);
@@ -372,16 +374,9 @@ sub cmd_dcommit {
                die "Unable to determine upstream SVN information from ",
                    "$head history\n";
        }
-       my $c = $refs[-1];
        my $last_rev;
-       foreach my $d (@refs) {
-               if (!verify_ref("$d~1")) {
-                       fatal "Commit $d\n",
-                             "has no parent commit, and therefore ",
-                             "nothing to diff against.\n",
-                             "You should be working from a repository ",
-                             "originally created by git-svn\n";
-               }
+       my ($linear_refs, $parents) = linearize_history($gs, \@refs);
+       foreach my $d (@$linear_refs) {
                unless (defined $last_rev) {
                        (undef, $last_rev, undef) = cmt_metadata("$d~1");
                        unless (defined $last_rev) {
@@ -403,6 +398,9 @@ sub cmd_dcommit {
                                        svn_path => '');
                        if (!SVN::Git::Editor->new(\%ed_opts)->apply_diff) {
                                print "No changes\n$d~1 == $d\n";
+                       } elsif ($parents->{$d} && @{$parents->{$d}}) {
+                               $gs->{inject_parents_dcommit}->{$last_rev} =
+                                                              $parents->{$d};
                        }
                }
        }
@@ -594,8 +592,7 @@ sub post_fetch_checkout {
        my $index = $ENV{GIT_INDEX_FILE} || "$ENV{GIT_DIR}/index";
        return if -f $index;
 
-       chomp(my $bare = `git config --bool --get core.bare`);
-       return if $bare eq 'true';
+       return if command_oneline(qw/rev-parse --is-inside-work-tree/) eq 'false';
        return if command_oneline(qw/rev-parse --is-inside-git-dir/) eq 'true';
        command_noisy(qw/read-tree -m -u -v HEAD HEAD/);
        print STDERR "Checked out HEAD:\n  ",
@@ -785,12 +782,12 @@ sub read_repo_config {
 
 sub extract_metadata {
        my $id = shift or return (undef, undef, undef);
-       my ($url, $rev, $uuid) = ($id =~ /^git-svn-id:\s(\S+?)\@(\d+)
+       my ($url, $rev, $uuid) = ($id =~ /^\s*git-svn-id:\s+(.*)\@(\d+)
                                                        \s([a-f\d\-]+)$/x);
        if (!defined $rev || !$uuid || !$url) {
                # some of the original repositories I made had
                # identifiers like this:
-               ($rev, $uuid) = ($id =~/^git-svn-id:\s(\d+)\@([a-f\d\-]+)/);
+               ($rev, $uuid) = ($id =~/^\s*git-svn-id:\s(\d+)\@([a-f\d\-]+)/);
        }
        return ($url, $rev, $uuid);
 }
@@ -802,25 +799,87 @@ sub cmt_metadata {
 
 sub working_head_info {
        my ($head, $refs) = @_;
-       my ($fh, $ctx) = command_output_pipe('rev-list', $head);
-       while (my $hash = <$fh>) {
-               chomp($hash);
-               my ($url, $rev, $uuid) = cmt_metadata($hash);
+       my ($fh, $ctx) = command_output_pipe('log', $head);
+       my $hash;
+       my %max;
+       while (<$fh>) {
+               if ( m{^commit ($::sha1)$} ) {
+                       unshift @$refs, $hash if $hash and $refs;
+                       $hash = $1;
+                       next;
+               }
+               next unless s{^\s*(git-svn-id:)}{$1};
+               my ($url, $rev, $uuid) = extract_metadata($_);
                if (defined $url && defined $rev) {
+                       next if $max{$url} and $max{$url} < $rev;
                        if (my $gs = Git::SVN->find_by_url($url)) {
                                my $c = $gs->rev_db_get($rev);
                                if ($c && $c eq $hash) {
                                        close $fh; # break the pipe
                                        return ($url, $rev, $uuid, $gs);
+                               } else {
+                                       $max{$url} ||= $gs->rev_db_max;
                                }
                        }
                }
-               unshift @$refs, $hash if $refs;
        }
        command_close_pipe($fh, $ctx);
        (undef, undef, undef, undef);
 }
 
+sub read_commit_parents {
+       my ($parents, $c) = @_;
+       my ($fh, $ctx) = command_output_pipe(qw/cat-file commit/, $c);
+       while (<$fh>) {
+               chomp;
+               last if '';
+               /^parent ($sha1)/ or next;
+               push @{$parents->{$c}}, $1;
+       }
+       close $fh; # break the pipe
+}
+
+sub linearize_history {
+       my ($gs, $refs) = @_;
+       my %parents;
+       foreach my $c (@$refs) {
+               read_commit_parents(\%parents, $c);
+       }
+
+       my @linear_refs;
+       my %skip = ();
+       my $last_svn_commit = $gs->last_commit;
+       foreach my $c (reverse @$refs) {
+               next if $c eq $last_svn_commit;
+               last if $skip{$c};
+
+               unshift @linear_refs, $c;
+               $skip{$c} = 1;
+
+               # we only want the first parent to diff against for linear
+               # history, we save the rest to inject when we finalize the
+               # svn commit
+               my $fp_a = verify_ref("$c~1");
+               my $fp_b = shift @{$parents{$c}} if $parents{$c};
+               if (!$fp_a || !$fp_b) {
+                       die "Commit $c\n",
+                           "has no parent commit, and therefore ",
+                           "nothing to diff against.\n",
+                           "You should be working from a repository ",
+                           "originally created by git-svn\n";
+               }
+               if ($fp_a ne $fp_b) {
+                       die "$c~1 = $fp_a, however parsing commit $c ",
+                           "revealed that:\n$c~1 = $fp_b\nBUG!\n";
+               }
+
+               foreach my $p (@{$parents{$c}}) {
+                       $skip{$p} = 1;
+               }
+       }
+       (\@linear_refs, \%parents);
+}
+
 package Git::SVN;
 use strict;
 use warnings;
@@ -846,26 +905,26 @@ BEGIN {
        # some options are read globally, but can be overridden locally
        # per [svn-remote "..."] section.  Command-line options will *NOT*
        # override options set in an [svn-remote "..."] section
-       my $e;
-       foreach (qw/follow_parent no_metadata use_svm_props
-                   use_svnsync_props/) {
-               my $key = $_;
+       no strict 'refs';
+       for my $option (qw/follow_parent no_metadata use_svm_props
+                          use_svnsync_props/) {
+               my $key = $option;
                $key =~ tr/_//d;
-               $e .= "sub $_ {
-                       my (\$self) = \@_;
-                       return \$self->{-$_} if exists \$self->{-$_};
-                       my \$k = \"svn-remote.\$self->{repo_id}\.$key\";
-                       eval { command_oneline(qw/config --get/, \$k) };
-                       if (\$@) {
-                               \$self->{-$_} = \$Git::SVN::_$_;
+               my $prop = "-$option";
+               *$option = sub {
+                       my ($self) = @_;
+                       return $self->{$prop} if exists $self->{$prop};
+                       my $k = "svn-remote.$self->{repo_id}.$key";
+                       eval { command_oneline(qw/config --get/, $k) };
+                       if ($@) {
+                               $self->{$prop} = ${"Git::SVN::_$option"};
                        } else {
-                               my \$v = command_oneline(qw/config --bool/,\$k);
-                               \$self->{-$_} = \$v eq 'false' ? 0 : 1;
+                               my $v = command_oneline(qw/config --bool/,$k);
+                               $self->{$prop} = $v eq 'false' ? 0 : 1;
                        }
-                       return \$self->{-$_} }\n";
+                       return $self->{$prop};
+               }
        }
-       $e .= "1;\n";
-       eval $e or die $@;
 }
 
 my %LOCKFILES;
@@ -1457,7 +1516,7 @@ sub tmp_config {
        my (@args) = @_;
        my $old_def_config = "$ENV{GIT_DIR}/svn/config";
        my $config = "$ENV{GIT_DIR}/svn/.metadata";
-       if (-e $old_def_config && ! -e $config) {
+       if (! -f $config && -f $old_def_config) {
                rename $old_def_config, $config or
                       die "Failed rename $old_def_config => $config: $!\n";
        }
@@ -1541,6 +1600,11 @@ sub get_commit_parents {
        if (my $cur = ::verify_ref($self->refname.'^0')) {
                push @tmp, $cur;
        }
+       if (my $ipd = $self->{inject_parents_dcommit}) {
+               if (my $commit = delete $ipd->{$log_entry->{revision}}) {
+                       push @tmp, @$commit;
+               }
+       }
        push @tmp, $_ foreach (@{$log_entry->{parents}}, @tmp);
        while (my $p = shift @tmp) {
                next if $seen{$p};
@@ -1964,16 +2028,19 @@ sub rebuild {
                return;
        }
        print "Rebuilding $db_path ...\n";
-       my ($rev_list, $ctx) = command_output_pipe("rev-list", $self->refname);
+       my ($log, $ctx) = command_output_pipe("log", $self->refname);
        my $latest;
        my $full_url = $self->full_url;
        remove_username($full_url);
        my $svn_uuid;
-       while (<$rev_list>) {
-               chomp;
-               my $c = $_;
-               die "Non-SHA1: $c\n" unless $c =~ /^$::sha1$/o;
-               my ($url, $rev, $uuid) = ::cmt_metadata($c);
+       my $c;
+       while (<$log>) {
+               if ( m{^commit ($::sha1)$} ) {
+                       $c = $1;
+                       next;
+               }
+               next unless s{^\s*(git-svn-id:)}{$1};
+               my ($url, $rev, $uuid) = ::extract_metadata($_);
                remove_username($url);
 
                # ignore merges (from set-tree)
@@ -1991,7 +2058,7 @@ sub rebuild {
                $self->rev_db_set($rev, $c);
                print "r$rev = $c\n";
        }
-       command_close_pipe($rev_list, $ctx);
+       command_close_pipe($log, $ctx);
        print "Done rebuilding $db_path\n";
 }
 
@@ -2899,17 +2966,17 @@ my ($can_do_switch, %ignored_err, $RA);
 
 BEGIN {
        # enforce temporary pool usage for some simple functions
-       my $e;
-       foreach (qw/rev_proplist get_latest_revnum get_uuid get_repos_root/) {
-               $e .= "sub $_ {
-                       my \$self = shift;
-                       my \$pool = SVN::Pool->new;
-                       my \@ret = \$self->SUPER::$_(\@_,\$pool);
-                       \$pool->clear;
-                       wantarray ? \@ret : \$ret[0]; }\n";
+       no strict 'refs';
+       for my $f (qw/rev_proplist get_latest_revnum get_uuid get_repos_root/) {
+               my $SUPER = "SUPER::$f";
+               *$f = sub {
+                       my $self = shift;
+                       my $pool = SVN::Pool->new;
+                       my @ret = $self->$SUPER(@_,$pool);
+                       $pool->clear;
+                       wantarray ? @ret : $ret[0];
+               };
        }
-
-       eval "$e; 1;" or die $@;
 }
 
 sub new {
@@ -2923,6 +2990,7 @@ sub new {
            SVN::Client::get_ssl_server_trust_file_provider(),
            SVN::Client::get_simple_prompt_provider(
              \&Git::SVN::Prompt::simple, 2),
+           SVN::Client::get_ssl_client_cert_file_provider(),
            SVN::Client::get_ssl_client_cert_prompt_provider(
              \&Git::SVN::Prompt::ssl_client_cert, 2),
            SVN::Client::get_ssl_client_cert_pw_prompt_provider(
@@ -2934,6 +3002,7 @@ sub new {
              \&Git::SVN::Prompt::username, 2),
          ]);
        my $config = SVN::Core::config_get_config($config_dir);
+       $RA = undef;
        my $self = SVN::Ra->new(url => $url, auth => $baton,
                              config => $config,
                              pool => SVN::Pool->new,
@@ -3072,11 +3141,8 @@ sub gs_do_switch {
        $editor->{git_commit_ok};
 }
 
-sub gs_fetch_loop_common {
-       my ($self, $base, $head, $gsv, $globs) = @_;
-       return if ($base > $head);
-       my $inc = $_log_window_size;
-       my ($min, $max) = ($base, $head < $base + $inc ? $head : $base + $inc);
+sub longest_common_path {
+       my ($gsv, $globs) = @_;
        my %common;
        my $common_max = scalar @$gsv;
 
@@ -3108,6 +3174,15 @@ sub gs_fetch_loop_common {
                        last;
                }
        }
+       $longest_path;
+}
+
+sub gs_fetch_loop_common {
+       my ($self, $base, $head, $gsv, $globs) = @_;
+       return if ($base > $head);
+       my $inc = $_log_window_size;
+       my ($min, $max) = ($base, $head < $base + $inc ? $head : $base + $inc);
+       my $longest_path = longest_common_path($gsv, $globs);
        while (1) {
                my %revs;
                my $err;
index 3af8c7e1106d755b1589750ff5673ff6a6cd3b14..b73d6494d80fe5ee19e1d95971e2e4e64e980dea 100755 (executable)
@@ -542,7 +542,7 @@ sub copy_path($$$$$$$$) {
        if ($node_kind eq $SVN::Node::dir) {
                $srcpath =~ s#/*$#/#;
        }
-       
+
        my $pid = open my $f,'-|';
        die $! unless defined $pid;
        if (!$pid) {
@@ -560,7 +560,7 @@ sub copy_path($$$$$$$$) {
                } else {
                        $p = $path;
                }
-               push(@$new,[$mode,$sha1,$p]);   
+               push(@$new,[$mode,$sha1,$p]);
        }
        close($f) or
                print STDERR "$newrev:$newbranch: could not list files in $oldpath \@ $rev\n";
@@ -867,34 +867,14 @@ sub commit {
                        or die "Cannot write branch $dest for update: $!\n";
        }
 
-       if($tag) {
-               my($in, $out) = ('','');
+       if ($tag) {
                $last_rev = "-" if %$changed_paths;
                # the tag was 'complex', i.e. did not refer to a "real" revision
 
                $dest =~ tr/_/\./ if $opt_u;
-               $branch = $dest;
-
-               my $pid = open2($in, $out, 'git-mktag');
-               print $out ("object $cid\n".
-                   "type commit\n".
-                   "tag $dest\n".
-                   "tagger $committer_name <$committer_email> 0 +0000\n") and
-               close($out)
-                   or die "Cannot create tag object $dest: $!\n";
-
-               my $tagobj = <$in>;
-               chomp $tagobj;
-
-               if ( !close($in) or waitpid($pid, 0) != $pid or
-                               $? != 0 or $tagobj !~ /^[0123456789abcdef]{40}$/ ) {
-                       die "Cannot create tag object $dest: $!\n";
-               }
 
-               open(C,">$git_dir/refs/tags/$dest") and
-               print C ("$tagobj\n") and
-               close(C)
-                       or die "Cannot create tag $branch: $!\n";
+               system('git-tag', $dest, $cid) == 0
+                       or die "Cannot create tag $dest: $!\n";
 
                print "Created tag '$dest' on '$branch'\n" if $opt_v;
        }
index 6f0b7a72192bbeb7ca4693f40f80e2bd20d5eb03..1c25d88c72b0645e6e619a05b1fbbbc091752444 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 # Copyright (c) 2005 Linus Torvalds
 
-USAGE='-l [<pattern>] | [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg>] <tagname> [<head>]'
+USAGE='[-n [<num>]] -l [<pattern>] | [-a | -s | -u <key-id>] [-f | -d | -v] [-m <msg>] <tagname> [<head>]'
 SUBDIRECTORY_OK='Yes'
 . git-sh-setup
 
@@ -13,36 +13,82 @@ message=
 username=
 list=
 verify=
+LINES=0
 while case "$#" in 0) break ;; esac
 do
     case "$1" in
     -a)
        annotate=1
+       shift
        ;;
     -s)
        annotate=1
        signed=1
+       shift
        ;;
     -f)
        force=1
+       shift
        ;;
-    -l)
-       case "$#" in
-       1)
-               set x . ;;
+    -n)
+        case "$#,$2" in
+       1,* | *,-*)
+               LINES=1         # no argument
+               ;;
+       *)      shift
+               LINES=$(expr "$1" : '\([0-9]*\)')
+               [ -z "$LINES" ] && LINES=1 # 1 line is default when -n is used
+               ;;
        esac
        shift
-       git rev-parse --symbolic --tags | sort | grep "$@"
-       exit $?
+       ;;
+    -l)
+       list=1
+       shift
+       case $# in
+       0)      PATTERN=
+               ;;
+       *)
+               PATTERN="$1"    # select tags by shell pattern, not re
+               shift
+               ;;
+       esac
+       git rev-parse --symbolic --tags | sort |
+           while read TAG
+           do
+               case "$TAG" in
+               *$PATTERN*) ;;
+               *)          continue ;;
+               esac
+               [ "$LINES" -le 0 ] && { echo "$TAG"; continue ;}
+               OBJTYPE=$(git cat-file -t "$TAG")
+               case $OBJTYPE in
+               tag)
+                       ANNOTATION=$(git cat-file tag "$TAG" |
+                               sed -e '1,/^$/d' |
+                               sed -n -e "
+                                       /^-----BEGIN PGP SIGNATURE-----\$/q
+                                       2,\$s/^/    /
+                                       p
+                                       ${LINES}q
+                               ")
+                       printf "%-15s %s\n" "$TAG" "$ANNOTATION"
+                       ;;
+               *)      echo "$TAG"
+                       ;;
+               esac
+           done
        ;;
     -m)
-       annotate=1
+       annotate=1
        shift
        message="$1"
        if test "$#" = "0"; then
            die "error: option -m needs an argument"
        else
+           message="$1"
            message_given=1
+           shift
        fi
        ;;
     -F)
@@ -53,25 +99,31 @@ do
        else
            message="$(cat "$1")"
            message_given=1
+           shift
        fi
        ;;
     -u)
        annotate=1
        signed=1
        shift
-       username="$1"
+       if test "$#" = "0"; then
+           die "error: option -u needs an argument"
+       else
+           username="$1"
+           shift
+       fi
        ;;
     -d)
-       shift
+       shift
        had_error=0
        for tag
        do
-               cur=$(git-show-ref --verify --hash -- "refs/tags/$tag") || {
+               cur=$(git show-ref --verify --hash -- "refs/tags/$tag") || {
                        echo >&2 "Seriously, what tag are you talking about?"
                        had_error=1
                        continue
                }
-               git-update-ref -m 'tag: delete' -d "refs/tags/$tag" "$cur" || {
+               git update-ref -m 'tag: delete' -d "refs/tags/$tag" "$cur" || {
                        had_error=1
                        continue
                }
@@ -82,7 +134,7 @@ do
     -v)
        shift
        tag_name="$1"
-       tag=$(git-show-ref --verify --hash -- "refs/tags/$tag_name") ||
+       tag=$(git show-ref --verify --hash -- "refs/tags/$tag_name") ||
                die "Seriously, what tag are you talking about?"
        git-verify-tag -v "$tag"
        exit $?
@@ -94,27 +146,28 @@ do
        break
        ;;
     esac
-    shift
 done
 
+[ -n "$list" ] && exit 0
+
 name="$1"
 [ "$name" ] || usage
 prev=0000000000000000000000000000000000000000
-if git-show-ref --verify --quiet -- "refs/tags/$name"
+if git show-ref --verify --quiet -- "refs/tags/$name"
 then
     test -n "$force" || die "tag '$name' already exists"
     prev=`git rev-parse "refs/tags/$name"`
 fi
 shift
-git-check-ref-format "tags/$name" ||
+git check-ref-format "tags/$name" ||
        die "we do not like '$name' as a tag name."
 
-object=$(git-rev-parse --verify --default HEAD "$@") || exit 1
-type=$(git-cat-file -t $object) || exit 1
+object=$(git rev-parse --verify --default HEAD "$@") || exit 1
+type=$(git cat-file -t $object) || exit 1
 tagger=$(git-var GIT_COMMITTER_IDENT) || exit 1
 
 test -n "$username" ||
-       username=$(git-repo-config user.signingkey) ||
+       username=$(git repo-config user.signingkey) ||
        username=$(expr "z$tagger" : 'z\(.*>\)')
 
 trap 'rm -f "$GIT_DIR"/TAG_TMP* "$GIT_DIR"/TAG_FINALMSG "$GIT_DIR"/TAG_EDITMSG' 0
@@ -130,7 +183,7 @@ if [ "$annotate" ]; then
     fi
 
     grep -v '^#' <"$GIT_DIR"/TAG_EDITMSG |
-    git-stripspace >"$GIT_DIR"/TAG_FINALMSG
+    git stripspace >"$GIT_DIR"/TAG_FINALMSG
 
     [ -s "$GIT_DIR"/TAG_FINALMSG -o -n "$message_given" ] || {
        echo >&2 "No tag message?"
@@ -150,4 +203,3 @@ if [ "$annotate" ]; then
 fi
 
 git update-ref "refs/tags/$name" "$object" "$prev"
-
index 8db7dd0b7d371cfeec84e70ff2a51ccf53a994e7..37b0023b270928cd80e0a6456c3d34d8173c975b 100755 (executable)
@@ -21,7 +21,7 @@ then
        usage
 fi
 
-type="$(git-cat-file -t "$1" 2>/dev/null)" ||
+type="$(git cat-file -t "$1" 2>/dev/null)" ||
        die "$1: no such object."
 
 test "$type" = tag ||
@@ -29,17 +29,17 @@ test "$type" = tag ||
 
 case "$verbose" in
 t)
-       git-cat-file -p "$1" |
+       git cat-file -p "$1" |
        sed -n -e '/^-----BEGIN PGP SIGNATURE-----/q' -e p
        ;;
 esac
 
 trap 'rm -f "$GIT_DIR/.tmp-vtag"' 0
 
-git-cat-file tag "$1" >"$GIT_DIR/.tmp-vtag" || exit 1
-
-cat "$GIT_DIR/.tmp-vtag" |
-sed '/-----BEGIN PGP/Q' |
+git cat-file tag "$1" >"$GIT_DIR/.tmp-vtag" || exit 1
+sed -n -e '
+       /^-----BEGIN PGP SIGNATURE-----$/q
+       p
+' <"$GIT_DIR/.tmp-vtag" |
 gpg --verify "$GIT_DIR/.tmp-vtag" - || exit 1
 rm -f "$GIT_DIR/.tmp-vtag"
-
diff --git a/git.c b/git.c
index 29b55a16047837084fd9e2e8238137b8a2fe44ea..a647f9c61e28e74a6294afcd8b01528e12d3c24d 100644 (file)
--- a/git.c
+++ b/git.c
@@ -4,7 +4,7 @@
 #include "quote.h"
 
 const char git_usage_string[] =
-       "git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate] [--bare] [--git-dir=GIT_DIR] [--help] COMMAND [ARGS]";
+       "git [--version] [--exec-path[=GIT_EXEC_PATH]] [-p|--paginate] [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE] [--help] COMMAND [ARGS]";
 
 static void prepend_to_path(const char *dir, int len)
 {
@@ -28,7 +28,7 @@ static void prepend_to_path(const char *dir, int len)
        free(path);
 }
 
-static int handle_options(const char*** argv, int* argc)
+static int handle_options(const char*** argv, int* argc, int* envchanged)
 {
        int handled = 0;
 
@@ -64,14 +64,34 @@ static int handle_options(const char*** argv, int* argc)
                                usage(git_usage_string);
                        }
                        setenv(GIT_DIR_ENVIRONMENT, (*argv)[1], 1);
+                       if (envchanged)
+                               *envchanged = 1;
                        (*argv)++;
                        (*argc)--;
                        handled++;
                } else if (!prefixcmp(cmd, "--git-dir=")) {
                        setenv(GIT_DIR_ENVIRONMENT, cmd + 10, 1);
+                       if (envchanged)
+                               *envchanged = 1;
+               } else if (!strcmp(cmd, "--work-tree")) {
+                       if (*argc < 2) {
+                               fprintf(stderr, "No directory given for --work-tree.\n" );
+                               usage(git_usage_string);
+                       }
+                       setenv(GIT_WORK_TREE_ENVIRONMENT, (*argv)[1], 1);
+                       if (envchanged)
+                               *envchanged = 1;
+                       (*argv)++;
+                       (*argc)--;
+               } else if (!prefixcmp(cmd, "--work-tree=")) {
+                       setenv(GIT_WORK_TREE_ENVIRONMENT, cmd + 12, 1);
+                       if (envchanged)
+                               *envchanged = 1;
                } else if (!strcmp(cmd, "--bare")) {
                        static char git_dir[PATH_MAX+1];
                        setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 1);
+                       if (envchanged)
+                               *envchanged = 1;
                } else {
                        fprintf(stderr, "Unknown option: %s\n", cmd);
                        usage(git_usage_string);
@@ -150,7 +170,7 @@ static int split_cmdline(char *cmdline, const char ***argv)
 
 static int handle_alias(int *argcp, const char ***argv)
 {
-       int nongit = 0, ret = 0, saved_errno = errno;
+       int nongit = 0, envchanged = 0, ret = 0, saved_errno = errno;
        const char *subdir;
        int count, option_count;
        const char** new_argv;
@@ -161,6 +181,21 @@ static int handle_alias(int *argcp, const char ***argv)
        git_config(git_alias_config);
        if (alias_string) {
                if (alias_string[0] == '!') {
+                       if (*argcp > 1) {
+                               int i, sz = PATH_MAX;
+                               char *s = xmalloc(sz), *new_alias = s;
+
+                               add_to_string(&s, &sz, alias_string, 0);
+                               free(alias_string);
+                               alias_string = new_alias;
+                               for (i = 1; i < *argcp &&
+                                       !add_to_string(&s, &sz, " ", 0) &&
+                                       !add_to_string(&s, &sz, (*argv)[i], 1)
+                                       ; i++)
+                                       ; /* do nothing */
+                               if (!sz)
+                                       die("Too many or long arguments");
+                       }
                        trace_printf("trace: alias to shell cmd: %s => %s\n",
                                     alias_command, alias_string + 1);
                        ret = system(alias_string + 1);
@@ -171,7 +206,11 @@ static int handle_alias(int *argcp, const char ***argv)
                            alias_string + 1, alias_command);
                }
                count = split_cmdline(alias_string, &new_argv);
-               option_count = handle_options(&new_argv, &count);
+               option_count = handle_options(&new_argv, &count, &envchanged);
+               if (envchanged)
+                       die("alias '%s' changes environment variables\n"
+                                "You can use '!git' in the alias to do this.",
+                                alias_command);
                memmove(new_argv - option_count, new_argv,
                                count * sizeof(char *));
                new_argv -= option_count;
@@ -214,18 +253,57 @@ const char git_version_string[] = GIT_VERSION;
  * require working tree to be present -- anything uses this needs
  * RUN_SETUP for reading from the configuration file.
  */
-#define NOT_BARE       (1<<2)
+#define NEED_WORK_TREE (1<<2)
+
+struct cmd_struct {
+       const char *cmd;
+       int (*fn)(int, const char **, const char *);
+       int option;
+};
 
-static void handle_internal_command(int argc, const char **argv, char **envp)
+static int run_command(struct cmd_struct *p, int argc, const char **argv)
+{
+       int status;
+       struct stat st;
+       const char *prefix;
+
+       prefix = NULL;
+       if (p->option & RUN_SETUP)
+               prefix = setup_git_directory();
+       if (p->option & USE_PAGER)
+               setup_pager();
+       if ((p->option & NEED_WORK_TREE) &&
+           (!is_inside_work_tree() || is_inside_git_dir()))
+               die("%s must be run in a work tree", p->cmd);
+       trace_argv_printf(argv, argc, "trace: built-in: git");
+
+       status = p->fn(argc, argv, prefix);
+       if (status)
+               return status;
+
+       /* Somebody closed stdout? */
+       if (fstat(fileno(stdout), &st))
+               return 0;
+       /* Ignore write errors for pipes and sockets.. */
+       if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
+               return 0;
+
+       /* Check for ENOSPC and EIO errors.. */
+       if (fflush(stdout))
+               die("write failure on standard output: %s", strerror(errno));
+       if (ferror(stdout))
+               die("unknown write failure on standard output");
+       if (fclose(stdout))
+               die("close failed on standard output: %s", strerror(errno));
+       return 0;
+}
+
+static void handle_internal_command(int argc, const char **argv)
 {
        const char *cmd = argv[0];
-       static struct cmd_struct {
-               const char *cmd;
-               int (*fn)(int, const char **, const char *);
-               int option;
-       } commands[] = {
-               { "add", cmd_add, RUN_SETUP | NOT_BARE },
-               { "annotate", cmd_annotate, RUN_SETUP | USE_PAGER },
+       static struct cmd_struct commands[] = {
+               { "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
+               { "annotate", cmd_annotate, RUN_SETUP },
                { "apply", cmd_apply },
                { "archive", cmd_archive },
                { "blame", cmd_blame, RUN_SETUP },
@@ -234,9 +312,9 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
                { "cat-file", cmd_cat_file, RUN_SETUP },
                { "checkout-index", cmd_checkout_index, RUN_SETUP },
                { "check-ref-format", cmd_check_ref_format },
-               { "check-attr", cmd_check_attr, RUN_SETUP | NOT_BARE },
+               { "check-attr", cmd_check_attr, RUN_SETUP | NEED_WORK_TREE },
                { "cherry", cmd_cherry, RUN_SETUP },
-               { "cherry-pick", cmd_cherry_pick, RUN_SETUP | NOT_BARE },
+               { "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
                { "commit-tree", cmd_commit_tree, RUN_SETUP },
                { "config", cmd_config },
                { "count-objects", cmd_count_objects, RUN_SETUP },
@@ -264,10 +342,10 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
                { "mailsplit", cmd_mailsplit },
                { "merge-base", cmd_merge_base, RUN_SETUP },
                { "merge-file", cmd_merge_file },
-               { "mv", cmd_mv, RUN_SETUP | NOT_BARE },
+               { "mv", cmd_mv, RUN_SETUP | NEED_WORK_TREE },
                { "name-rev", cmd_name_rev, RUN_SETUP },
                { "pack-objects", cmd_pack_objects, RUN_SETUP },
-               { "pickaxe", cmd_blame, RUN_SETUP | USE_PAGER },
+               { "pickaxe", cmd_blame, RUN_SETUP },
                { "prune", cmd_prune, RUN_SETUP },
                { "prune-packed", cmd_prune_packed, RUN_SETUP },
                { "push", cmd_push, RUN_SETUP },
@@ -277,9 +355,9 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
                { "rerere", cmd_rerere, RUN_SETUP },
                { "rev-list", cmd_rev_list, RUN_SETUP },
                { "rev-parse", cmd_rev_parse, RUN_SETUP },
-               { "revert", cmd_revert, RUN_SETUP | NOT_BARE },
-               { "rm", cmd_rm, RUN_SETUP | NOT_BARE },
-               { "runstatus", cmd_runstatus, RUN_SETUP | NOT_BARE },
+               { "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
+               { "rm", cmd_rm, RUN_SETUP | NEED_WORK_TREE },
+               { "runstatus", cmd_runstatus, RUN_SETUP | NEED_WORK_TREE },
                { "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER },
                { "show-branch", cmd_show_branch, RUN_SETUP },
                { "show", cmd_show, RUN_SETUP | USE_PAGER },
@@ -307,25 +385,13 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
 
        for (i = 0; i < ARRAY_SIZE(commands); i++) {
                struct cmd_struct *p = commands+i;
-               const char *prefix;
                if (strcmp(p->cmd, cmd))
                        continue;
-
-               prefix = NULL;
-               if (p->option & RUN_SETUP)
-                       prefix = setup_git_directory();
-               if (p->option & USE_PAGER)
-                       setup_pager();
-               if ((p->option & NOT_BARE) &&
-                               (is_bare_repository() || is_inside_git_dir()))
-                       die("%s must be run in a work tree", cmd);
-               trace_argv_printf(argv, argc, "trace: built-in: git");
-
-               exit(p->fn(argc, argv, prefix));
+               exit(run_command(p, argc, argv));
        }
 }
 
-int main(int argc, const char **argv, char **envp)
+int main(int argc, const char **argv)
 {
        const char *cmd = argv[0] ? argv[0] : "git-help";
        char *slash = strrchr(cmd, '/');
@@ -358,14 +424,14 @@ int main(int argc, const char **argv, char **envp)
        if (!prefixcmp(cmd, "git-")) {
                cmd += 4;
                argv[0] = cmd;
-               handle_internal_command(argc, argv, envp);
+               handle_internal_command(argc, argv);
                die("cannot handle %s internally", cmd);
        }
 
        /* Look for flags.. */
        argv++;
        argc--;
-       handle_options(&argv, &argc);
+       handle_options(&argv, &argc, NULL);
        if (argc > 0) {
                if (!prefixcmp(argv[0], "--"))
                        argv[0] += 2;
@@ -390,7 +456,7 @@ int main(int argc, const char **argv, char **envp)
 
        while (1) {
                /* See if it's an internal command */
-               handle_internal_command(argc, argv, envp);
+               handle_internal_command(argc, argv);
 
                /* .. then try the external ones */
                execv_git_cmd(argv);
index 3a45eb876157d9979f51fe88ecc5d5ae4a93ff1c..27182baa84f0a39427cfb85f8ba7dd40256dbd3d 100644 (file)
@@ -63,7 +63,7 @@ Git tools for importing Perforce repositories.
 %package email
 Summary:        Git tools for sending email
 Group:          Development/Tools
-Requires:      git-core = %{version}-%{release} 
+Requires:      git-core = %{version}-%{release}
 %description email
 Git tools for sending email.
 
@@ -164,11 +164,10 @@ rm -rf $RPM_BUILD_ROOT
 %{_bindir}/git-gui
 %{_bindir}/git-citool
 %{_datadir}/git-gui/
-# Not Yet...
-# %{!?_without_docs: %{_mandir}/man1/git-gui.1}
-# %{!?_without_docs: %doc Documentation/git-gui.html}
-# %{!?_without_docs: %{_mandir}/man1/git-citool.1}
-# %{!?_without_docs: %doc Documentation/git-citool.html}
+%{!?_without_docs: %{_mandir}/man1/git-gui.1*}
+%{!?_without_docs: %doc Documentation/git-gui.html}
+%{!?_without_docs: %{_mandir}/man1/git-citool.1*}
+%{!?_without_docs: %doc Documentation/git-citool.html}
 
 %files -n gitk
 %defattr(-,root,root)
@@ -188,6 +187,12 @@ rm -rf $RPM_BUILD_ROOT
 %{!?_without_docs: %doc Documentation/technical}
 
 %changelog
+* Tue Jun 26 2007 Quy Tonthat <qtonthat@gmail.com>
+- Fixed problems looking for wrong manpages.
+
+* Thu Jun 21 2007 Shawn O. Pearce <spearce@spearce.org>
+- Added documentation files for git-gui
+
 * Tue May 13 2007 Quy Tonthat <qtonthat@gmail.com>
 - Added lib files for git-gui
 - Added Documentation/technical (As needed by Git Users Manual)
diff --git a/gitk b/gitk
index a57e84cef7143839af954e2aa1fcb3d633befe41..2d6a6ef9cef40b0ea5090f49d13c30836f0f1c20 100755 (executable)
--- a/gitk
+++ b/gitk
@@ -16,13 +16,76 @@ proc gitdir {} {
     }
 }
 
+# A simple scheduler for compute-intensive stuff.
+# The aim is to make sure that event handlers for GUI actions can
+# run at least every 50-100 ms.  Unfortunately fileevent handlers are
+# run before X event handlers, so reading from a fast source can
+# make the GUI completely unresponsive.
+proc run args {
+    global isonrunq runq
+
+    set script $args
+    if {[info exists isonrunq($script)]} return
+    if {$runq eq {}} {
+       after idle dorunq
+    }
+    lappend runq [list {} $script]
+    set isonrunq($script) 1
+}
+
+proc filerun {fd script} {
+    fileevent $fd readable [list filereadable $fd $script]
+}
+
+proc filereadable {fd script} {
+    global runq
+
+    fileevent $fd readable {}
+    if {$runq eq {}} {
+       after idle dorunq
+    }
+    lappend runq [list $fd $script]
+}
+
+proc dorunq {} {
+    global isonrunq runq
+
+    set tstart [clock clicks -milliseconds]
+    set t0 $tstart
+    while {$runq ne {}} {
+       set fd [lindex $runq 0 0]
+       set script [lindex $runq 0 1]
+       set repeat [eval $script]
+       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
+               # file readers return 2 if they could do more straight away
+               lappend runq [list $fd $script]
+           } else {
+               fileevent $fd readable [list filereadable $fd $script]
+           }
+       } elseif {$fd eq {}} {
+           unset isonrunq($script)
+       }
+       set t0 $t1
+       if {$t1 - $tstart >= 80} break
+    }
+    if {$runq ne {}} {
+       after idle dorunq
+    }
+}
+
+# Start off a git rev-list process and arrange to read its output
 proc start_rev_list {view} {
-    global startmsecs nextupdate
+    global startmsecs
     global commfd leftover tclencoding datemode
     global viewargs viewfiles commitidx
+    global lookingforhead showlocalchanges
 
     set startmsecs [clock clicks -milliseconds]
-    set nextupdate [expr {$startmsecs + 100}]
     set commitidx($view) 0
     set args $viewargs($view)
     if {$viewfiles($view) ne {}} {
@@ -41,11 +104,12 @@ proc start_rev_list {view} {
     }
     set commfd($view) $fd
     set leftover($view) {}
+    set lookingforhead $showlocalchanges
     fconfigure $fd -blocking 0 -translation lf
     if {$tclencoding != {}} {
        fconfigure $fd -encoding $tclencoding
     }
-    fileevent $fd readable [list getcommitlines $fd $view]
+    filerun $fd [list getcommitlines $fd $view]
     nowbusy $view
 }
 
@@ -72,15 +136,17 @@ proc getcommits {} {
 }
 
 proc getcommitlines {fd view}  {
-    global commitlisted nextupdate
+    global commitlisted
     global leftover commfd
     global displayorder commitidx commitrow commitdata
-    global parentlist childlist children curview hlview
-    global vparentlist vchildlist vdisporder vcmitlisted
+    global parentlist children curview hlview
+    global vparentlist vdisporder vcmitlisted
 
     set stuff [read $fd 500000]
     if {$stuff == {}} {
-       if {![eof $fd]} return
+       if {![eof $fd]} {
+           return 1
+       }
        global viewname
        unset commfd($view)
        notbusy $view
@@ -105,9 +171,9 @@ proc getcommitlines {fd view}  {
            error_popup $err
        }
        if {$view == $curview} {
-           after idle finishcommits
+           run chewcommits $view
        }
-       return
+       return 0
     }
     set start 0
     set gotsome 0
@@ -171,41 +237,52 @@ proc getcommitlines {fd view}  {
        incr commitidx($view)
        if {$view == $curview} {
            lappend parentlist $olds
-           lappend childlist $children($view,$id)
            lappend displayorder $id
            lappend commitlisted $listed
        } else {
            lappend vparentlist($view) $olds
-           lappend vchildlist($view) $children($view,$id)
            lappend vdisporder($view) $id
            lappend vcmitlisted($view) $listed
        }
        set gotsome 1
     }
     if {$gotsome} {
-       if {$view == $curview} {
-           while {[layoutmore $nextupdate]} doupdate
-       } elseif {[info exists hlview] && $view == $hlview} {
-           vhighlightmore
-       }
-    }
-    if {[clock clicks -milliseconds] >= $nextupdate} {
-       doupdate
+       run chewcommits $view
     }
+    return 2
 }
 
-proc doupdate {} {
-    global commfd nextupdate numcommits
+proc chewcommits {view} {
+    global curview hlview commfd
+    global selectedline pending_select
+
+    set more 0
+    if {$view == $curview} {
+       set allread [expr {![info exists commfd($view)]}]
+       set tlimit [expr {[clock clicks -milliseconds] + 50}]
+       set more [layoutmore $tlimit $allread]
+       if {$allread && !$more} {
+           global displayorder nullid commitidx phase
+           global numcommits startmsecs
 
-    foreach v [array names commfd] {
-       fileevent $commfd($v) readable {}
+           if {[info exists pending_select]} {
+               set row [expr {[lindex $displayorder 0] eq $nullid}]
+               selectline $row 1
+           }
+           if {$commitidx($curview) > 0} {
+               #set ms [expr {[clock clicks -milliseconds] - $startmsecs}]
+               #puts "overall $ms ms for $numcommits commits"
+           } else {
+               show_status "No commits selected"
+           }
+           notbusy layout
+           set phase {}
+       }
     }
-    update
-    set nextupdate [expr {[clock clicks -milliseconds] + 100}]
-    foreach v [array names commfd] {
-       set fd $commfd($v)
-       fileevent $fd readable [list getcommitlines $fd $v]
+    if {[info exists hlview] && $view == $hlview} {
+       vhighlightmore
     }
+    return $more
 }
 
 proc readcommit {id} {
@@ -230,8 +307,9 @@ proc updatecommits {} {
     catch {unset selectedline}
     catch {unset thickerline}
     catch {unset viewdata($n)}
-    discardallcommits
     readrefs
+    changedrefs
+    regetallcommits
     showview $n
 }
 
@@ -263,12 +341,16 @@ proc parsecommit {id contents listed} {
        }
     }
     set headline {}
-    # take the first line of the comment as the headline
-    set i [string first "\n" $comment]
+    # take the first non-blank line of the comment as the headline
+    set headline [string trimleft $comment]
+    set i [string first "\n" $headline]
     if {$i >= 0} {
-       set headline [string trim [string range $comment 0 $i]]
-    } else {
-       set headline $comment
+       set headline [string range $headline 0 $i]
+    }
+    set headline [string trimright $headline]
+    set i [string first "\r" $headline]
+    if {$i >= 0} {
+       set headline [string trimright [string range $headline 0 $i]]
     }
     if {!$listed} {
        # git rev-list indents the comment by 4 spaces;
@@ -303,47 +385,39 @@ proc getcommit {id} {
 }
 
 proc readrefs {} {
-    global tagids idtags headids idheads tagcontents
-    global otherrefids idotherrefs mainhead
+    global tagids idtags headids idheads tagobjid
+    global otherrefids idotherrefs mainhead mainheadid
 
     foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
        catch {unset $v}
     }
-    set refd [open [list | git show-ref] r]
-    while {0 <= [set n [gets $refd line]]} {
-       if {![regexp {^([0-9a-f]{40}) refs/([^^]*)$} $line \
-           match id path]} {
-           continue
-       }
-       if {[regexp {^remotes/.*/HEAD$} $path match]} {
-           continue
-       }
-       if {![regexp {^(tags|heads)/(.*)$} $path match type name]} {
-           set type others
-           set name $path
-       }
-       if {[regexp {^remotes/} $path match]} {
-           set type heads
-       }
-       if {$type == "tags"} {
-           set tagids($name) $id
-           lappend idtags($id) $name
-           set obj {}
-           set type {}
-           set tag {}
-           catch {
-               set commit [exec git rev-parse "$id^0"]
-               if {$commit != $id} {
-                   set tagids($name) $commit
-                   lappend idtags($commit) $name
-               }
-           }           
-           catch {
-               set tagcontents($name) [exec git cat-file tag $id]
+    set refd [open [list | git show-ref -d] r]
+    while {[gets $refd line] >= 0} {
+       if {[string index $line 40] ne " "} continue
+       set id [string range $line 0 39]
+       set ref [string range $line 41 end]
+       if {![string match "refs/*" $ref]} continue
+       set name [string range $ref 5 end]
+       if {[string match "remotes/*" $name]} {
+           if {![string match "*/HEAD" $name]} {
+               set headids($name) $id
+               lappend idheads($id) $name
            }
-       } elseif { $type == "heads" } {
+       } elseif {[string match "heads/*" $name]} {
+           set name [string range $name 6 end]
            set headids($name) $id
            lappend idheads($id) $name
+       } elseif {[string match "tags/*" $name]} {
+           # this lets refs/tags/foo^{} overwrite refs/tags/foo,
+           # which is what we want since the former is the commit ID
+           set name [string range $name 5 end]
+           if {[string match "*^{}" $name]} {
+               set name [string range $name 0 end-3]
+           } else {
+               set tagobjid($name) $id
+           }
+           set tagids($name) $id
+           lappend idtags($id) $name
        } else {
            set otherrefids($name) $id
            lappend idotherrefs($id) $name
@@ -351,12 +425,40 @@ proc readrefs {} {
     }
     close $refd
     set mainhead {}
+    set mainheadid {}
     catch {
        set thehead [exec git symbolic-ref HEAD]
        if {[string match "refs/heads/*" $thehead]} {
            set mainhead [string range $thehead 11 end]
+           if {[info exists headids($mainhead)]} {
+               set mainheadid $headids($mainhead)
+           }
+       }
+    }
+}
+
+# update things for a head moved to a child of its previous location
+proc movehead {id name} {
+    global headids idheads
+
+    removehead $headids($name) $name
+    set headids($name) $id
+    lappend idheads($id) $name
+}
+
+# update things when a head has been removed
+proc removehead {id name} {
+    global headids idheads
+
+    if {$idheads($id) eq $name} {
+       unset idheads($id)
+    } else {
+       set i [lsearch -exact $idheads($id) $name]
+       if {$i >= 0} {
+           set idheads($id) [lreplace $idheads($id) $i $i]
        }
     }
+    unset headids($name)
 }
 
 proc show_error {w top msg} {
@@ -395,14 +497,14 @@ proc confirm_popup msg {
 
 proc makewindow {} {
     global canv canv2 canv3 linespc charspc ctext cflist
-    global textfont mainfont uifont
+    global textfont mainfont uifont tabstop
     global findtype findtypemenu findloc findstring fstring geometry
     global entries sha1entry sha1string sha1but
     global maincursor textcursor curtextcursor
-    global rowctxmenu mergemax wrapcomment
+    global rowctxmenu fakerowmenu mergemax wrapcomment
     global highlight_files gdttype
     global searchstring sstring
-    global bgcolor fgcolor bglist fglist diffcolors
+    global bgcolor fgcolor bglist fglist diffcolors selectbgcolor
     global headctxmenu
 
     menu .bar
@@ -457,15 +559,18 @@ proc makewindow {} {
     set cscroll .tf.histframe.csb
     set canv .tf.histframe.pwclist.canv
     canvas $canv \
+       -selectbackground $selectbgcolor \
        -background $bgcolor -bd 0 \
        -yscrollincr $linespc -yscrollcommand "scrollcanv $cscroll"
     .tf.histframe.pwclist add $canv
     set canv2 .tf.histframe.pwclist.canv2
     canvas $canv2 \
+       -selectbackground $selectbgcolor \
        -background $bgcolor -bd 0 -yscrollincr $linespc
     .tf.histframe.pwclist add $canv2
     set canv3 .tf.histframe.pwclist.canv3
     canvas $canv3 \
+       -selectbackground $selectbgcolor \
        -background $bgcolor -bd 0 -yscrollincr $linespc
     .tf.histframe.pwclist add $canv3
     eval .tf.histframe.pwclist sash place 0 $geometry(pwsash0)
@@ -612,6 +717,7 @@ proc makewindow {} {
     pack .bleft.mid.diff .bleft.mid.old .bleft.mid.new -side left
     set ctext .bleft.ctext
     text $ctext -background $bgcolor -foreground $fgcolor \
+       -tabs "[expr {$tabstop * $charspc}]" \
        -state disabled -font $textfont \
        -yscrollcommand scrolltext -wrap none
     scrollbar .bleft.sb -command "$ctext yview"
@@ -666,6 +772,7 @@ proc makewindow {} {
     set cflist .bright.cfiles
     set indent [font measure $mainfont "nn"]
     text $cflist \
+       -selectbackground $selectbgcolor \
        -background $bgcolor -foreground $fgcolor \
        -font $mainfont \
        -tabs [list $indent [expr {2 * $indent}]] \
@@ -766,6 +873,19 @@ proc makewindow {} {
     $rowctxmenu add command -label "Create new branch" -command mkbranch
     $rowctxmenu add command -label "Cherry-pick this commit" \
        -command cherrypick
+    $rowctxmenu add command -label "Reset HEAD branch to here" \
+       -command resethead
+
+    set fakerowmenu .fakerowmenu
+    menu $fakerowmenu -tearoff 0
+    $fakerowmenu add command -label "Diff this -> selected" \
+       -command {diffvssel 0}
+    $fakerowmenu add command -label "Diff selected -> this" \
+       -command {diffvssel 1}
+    $fakerowmenu add command -label "Make patch" -command mkpatch
+#    $fakerowmenu add command -label "Commit" -command {mkcommit 0}
+#    $fakerowmenu add command -label "Commit all" -command {mkcommit 1}
+#    $fakerowmenu add command -label "Revert local changes" -command revertlocal
 
     set headctxmenu .headctxmenu
     menu $headctxmenu -tearoff 0
@@ -820,12 +940,12 @@ proc click {w} {
 }
 
 proc savestuff {w} {
-    global canv canv2 canv3 ctext cflist mainfont textfont uifont
+    global canv canv2 canv3 ctext cflist mainfont textfont uifont tabstop
     global stuffsaved findmergefiles maxgraphpct
-    global maxwidth showneartags
+    global maxwidth showneartags showlocalchanges
     global viewname viewfiles viewargs viewperm nextviewnum
     global cmitmode wrapcomment
-    global colors bgcolor fgcolor diffcolors
+    global colors bgcolor fgcolor diffcolors selectbgcolor
 
     if {$stuffsaved} return
     if {![winfo viewable .]} return
@@ -834,16 +954,19 @@ proc savestuff {w} {
        puts $f [list set mainfont $mainfont]
        puts $f [list set textfont $textfont]
        puts $f [list set uifont $uifont]
+       puts $f [list set tabstop $tabstop]
        puts $f [list set findmergefiles $findmergefiles]
        puts $f [list set maxgraphpct $maxgraphpct]
        puts $f [list set maxwidth $maxwidth]
        puts $f [list set cmitmode $cmitmode]
        puts $f [list set wrapcomment $wrapcomment]
        puts $f [list set showneartags $showneartags]
+       puts $f [list set showlocalchanges $showlocalchanges]
        puts $f [list set bgcolor $bgcolor]
        puts $f [list set fgcolor $fgcolor]
        puts $f [list set colors $colors]
        puts $f [list set diffcolors $diffcolors]
+       puts $f [list set selectbgcolor $selectbgcolor]
 
        puts $f "set geometry(main) [wm geometry .]"
        puts $f "set geometry(topwidth) [winfo width .tf]"
@@ -1562,9 +1685,9 @@ proc newviewok {top n} {
        set viewargs($n) $newargs
        addviewmenu $n
        if {!$newishighlight} {
-           after idle showview $n
+           run showview $n
        } else {
-           after idle addvhighlight $n
+           run addvhighlight $n
        }
     } else {
        # editing an existing view
@@ -1580,7 +1703,7 @@ proc newviewok {top n} {
            set viewfiles($n) $files
            set viewargs($n) $newargs
            if {$curview == $n} {
-               after idle updatecommits
+               run updatecommits
            }
        }
     }
@@ -1631,16 +1754,16 @@ proc unflatten {var l} {
 
 proc showview {n} {
     global curview viewdata viewfiles
-    global displayorder parentlist childlist rowidlist rowoffsets
+    global displayorder parentlist rowidlist rowoffsets
     global colormap rowtextx commitrow nextcolor canvxmax
-    global numcommits rowrangelist commitlisted idrowranges
+    global numcommits rowrangelist commitlisted idrowranges rowchk
     global selectedline currentid canv canvy0
     global matchinglines treediffs
     global pending_select phase
-    global commitidx rowlaidout rowoptim linesegends
-    global commfd nextupdate
-    global selectedview
-    global vparentlist vchildlist vdisporder vcmitlisted
+    global commitidx rowlaidout rowoptim
+    global commfd
+    global selectedview selectfirst
+    global vparentlist vdisporder vcmitlisted
     global hlview selectedhlview
 
     if {$n == $curview} return
@@ -1657,20 +1780,22 @@ proc showview {n} {
        } else {
            set yscreen [expr {($ybot - $ytop) / 2}]
        }
+    } elseif {[info exists pending_select]} {
+       set selid $pending_select
+       unset pending_select
     }
     unselectline
     normalline
     stopfindproc
     if {$curview >= 0} {
        set vparentlist($curview) $parentlist
-       set vchildlist($curview) $childlist
        set vdisporder($curview) $displayorder
        set vcmitlisted($curview) $commitlisted
        if {$phase ne {}} {
            set viewdata($curview) \
                [list $phase $rowidlist $rowoffsets $rowrangelist \
                     [flatten idrowranges] [flatten idinlist] \
-                    $rowlaidout $rowoptim $numcommits $linesegends]
+                    $rowlaidout $rowoptim $numcommits]
        } elseif {![info exists viewdata($curview)]
                  || [lindex $viewdata($curview) 0] ne {}} {
            set viewdata($curview) \
@@ -1691,7 +1816,9 @@ proc showview {n} {
     .bar.view entryconf Delete* -state [expr {$n == 0? "disabled": "normal"}]
 
     if {![info exists viewdata($n)]} {
-       set pending_select $selid
+       if {$selid ne {}} {
+           set pending_select $selid
+       }
        getcommits
        return
     }
@@ -1700,7 +1827,6 @@ proc showview {n} {
     set phase [lindex $v 0]
     set displayorder $vdisporder($n)
     set parentlist $vparentlist($n)
-    set childlist $vchildlist($n)
     set commitlisted $vcmitlisted($n)
     set rowidlist [lindex $v 1]
     set rowoffsets [lindex $v 2]
@@ -1714,7 +1840,7 @@ proc showview {n} {
        set rowlaidout [lindex $v 6]
        set rowoptim [lindex $v 7]
        set numcommits [lindex $v 8]
-       set linesegends [lindex $v 9]
+       catch {unset rowchk}
     }
 
     catch {unset colormap}
@@ -1725,7 +1851,8 @@ proc showview {n} {
     set row 0
     setcanvscroll
     set yf 0
-    set row 0
+    set row {}
+    set selectfirst 0
     if {$selid ne {} && [info exists commitrow($n,$selid)]} {
        set row $commitrow($n,$selid)
        # try to get the selected row in the same position on the screen
@@ -1738,16 +1865,23 @@ proc showview {n} {
     }
     allcanvs yview moveto $yf
     drawvisible
-    selectline $row 0
+    if {$row ne {}} {
+       selectline $row 0
+    } elseif {$selid ne {}} {
+       set pending_select $selid
+    } else {
+       set row [expr {[lindex $displayorder 0] eq $nullid}]
+       if {$row < $numcommits} {
+           selectline $row 0
+       } else {
+           set selectfirst 1
+       }
+    }
     if {$phase ne {}} {
        if {$phase eq "getcommits"} {
            show_status "Reading commits..."
        }
-       if {[info exists commfd($n)]} {
-           layoutmore {}
-       } else {
-           finishcommits
-       }
+       run chewcommits $n
     } elseif {$numcommits == 0} {
        show_status "No commits selected"
     }
@@ -1825,7 +1959,6 @@ proc addvhighlight {n} {
     if {$n != $curview && ![info exists viewdata($n)]} {
        set viewdata($n) [list getcommits {{}} {{}} {} {} {} 0 0 0 {}]
        set vparentlist($n) {}
-       set vchildlist($n) {}
        set vdisporder($n) {}
        set vcmitlisted($n) {}
        start_rev_list $n
@@ -1935,7 +2068,7 @@ proc do_file_hl {serial} {
     set cmd [concat | git diff-tree -r -s --stdin $gdtargs]
     set filehighlight [open $cmd r+]
     fconfigure $filehighlight -blocking 0
-    fileevent $filehighlight readable readfhighlight
+    filerun $filehighlight readfhighlight
     set fhl_list {}
     drawvisible
     flushhighlights
@@ -1963,7 +2096,11 @@ proc readfhighlight {} {
     global filehighlight fhighlights commitrow curview mainfont iddrawn
     global fhl_list
 
-    while {[gets $filehighlight line] >= 0} {
+    if {![info exists filehighlight]} {
+       return 0
+    }
+    set nr 0
+    while {[incr nr] <= 100 && [gets $filehighlight line] >= 0} {
        set line [string trim $line]
        set i [lsearch -exact $fhl_list $line]
        if {$i < 0} continue
@@ -1987,8 +2124,10 @@ proc readfhighlight {} {
        puts "oops, git diff-tree died"
        catch {close $filehighlight}
        unset filehighlight
+       return 0
     }
     next_hlcont
+    return 1
 }
 
 proc find_change {name ix op} {
@@ -2055,7 +2194,7 @@ proc vrel_change {name ix op} {
 
     rhighlight_none
     if {$highlight_related ne "None"} {
-       after idle drawvisible
+       run drawvisible
     }
 }
 
@@ -2070,7 +2209,7 @@ proc rhighlight_sel {a} {
     set anc_todo [list $a]
     if {$highlight_related ne "None"} {
        rhighlight_none
-       after idle drawvisible
+       run drawvisible
     }
 }
 
@@ -2288,17 +2427,15 @@ proc ntimes {n o} {
 }
 
 proc usedinrange {id l1 l2} {
-    global children commitrow childlist curview
+    global children commitrow curview
 
     if {[info exists commitrow($curview,$id)]} {
        set r $commitrow($curview,$id)
        if {$l1 <= $r && $r <= $l2} {
            return [expr {$r - $l1 + 1}]
        }
-       set kids [lindex $childlist $r]
-    } else {
-       set kids $children($curview,$id)
     }
+    set kids $children($curview,$id)
     foreach c $kids {
        set r $commitrow($curview,$c)
        if {$l1 <= $r && $r <= $l2} {
@@ -2341,7 +2478,7 @@ proc sanity {row {full 0}} {
 }
 
 proc makeuparrow {oid x y z} {
-    global rowidlist rowoffsets uparrowlen idrowranges
+    global rowidlist rowoffsets uparrowlen idrowranges displayorder
 
     for {set i 1} {$i < $uparrowlen && $y > 1} {incr i} {
        incr y -1
@@ -2364,7 +2501,7 @@ proc makeuparrow {oid x y z} {
     }
     set tmp [lreplace [lindex $rowoffsets $y] $x $x {}]
     lset rowoffsets $y [incrange $tmp [expr {$x+1}] -1]
-    lappend idrowranges($oid) $y
+    lappend idrowranges($oid) [lindex $displayorder $y]
 }
 
 proc initlayout {} {
@@ -2373,15 +2510,14 @@ proc initlayout {} {
     global idinlist rowchk rowrangelist idrowranges
     global numcommits canvxmax canv
     global nextcolor
-    global parentlist childlist children
+    global parentlist
     global colormap rowtextx
-    global linesegends
+    global selectfirst
 
     set numcommits 0
     set displayorder {}
     set commitlisted {}
     set parentlist {}
-    set childlist {}
     set rowrangelist {}
     set nextcolor 0
     set rowidlist {{}}
@@ -2394,7 +2530,7 @@ proc initlayout {} {
     catch {unset colormap}
     catch {unset rowtextx}
     catch {unset idrowranges}
-    set linesegends {}
+    set selectfirst 1
 }
 
 proc setcanvscroll {} {
@@ -2425,15 +2561,18 @@ proc visiblerows {} {
     return [list $r0 $r1]
 }
 
-proc layoutmore {tmax} {
+proc layoutmore {tmax allread} {
     global rowlaidout rowoptim commitidx numcommits optim_delay
-    global uparrowlen curview
+    global uparrowlen curview rowidlist idinlist
 
+    set showlast 0
+    set showdelay $optim_delay
+    set optdelay [expr {$uparrowlen + 1}]
     while {1} {
-       if {$rowoptim - $optim_delay > $numcommits} {
-           showstuff [expr {$rowoptim - $optim_delay}]
-       } elseif {$rowlaidout - $uparrowlen - 1 > $rowoptim} {
-           set nr [expr {$rowlaidout - $uparrowlen - 1 - $rowoptim}]
+       if {$rowoptim - $showdelay > $numcommits} {
+           showstuff [expr {$rowoptim - $showdelay}] $showlast
+       } elseif {$rowlaidout - $optdelay > $rowoptim} {
+           set nr [expr {$rowlaidout - $optdelay - $rowoptim}]
            if {$nr > 100} {
                set nr 100
            }
@@ -2447,10 +2586,24 @@ proc layoutmore {tmax} {
                set nr 150
            }
            set row $rowlaidout
-           set rowlaidout [layoutrows $row [expr {$row + $nr}] 0]
+           set rowlaidout [layoutrows $row [expr {$row + $nr}] $allread]
            if {$rowlaidout == $row} {
                return 0
            }
+       } elseif {$allread} {
+           set optdelay 0
+           set nrows $commitidx($curview)
+           if {[lindex $rowidlist $nrows] ne {} ||
+               [array names idinlist] ne {}} {
+               layouttail
+               set rowlaidout $commitidx($curview)
+           } elseif {$rowoptim == $nrows} {
+               set showdelay 0
+               set showlast 1
+               if {$numcommits == $nrows} {
+                   return 0
+               }
+           }
        } else {
            return 0
        }
@@ -2460,57 +2613,116 @@ proc layoutmore {tmax} {
     }
 }
 
-proc showstuff {canshow} {
-    global numcommits commitrow pending_select selectedline
-    global linesegends idrowranges idrangedrawn curview
+proc showstuff {canshow last} {
+    global numcommits commitrow pending_select selectedline curview
+    global lookingforhead mainheadid displayorder nullid selectfirst
+    global lastscrollset
 
     if {$numcommits == 0} {
        global phase
        set phase "incrdraw"
        allcanvs delete all
     }
-    set row $numcommits
+    set r0 $numcommits
+    set prev $numcommits
     set numcommits $canshow
-    setcanvscroll
+    set t [clock clicks -milliseconds]
+    if {$prev < 100 || $last || $t - $lastscrollset > 500} {
+       set lastscrollset $t
+       setcanvscroll
+    }
     set rows [visiblerows]
-    set r0 [lindex $rows 0]
     set r1 [lindex $rows 1]
-    set selrow -1
-    for {set r $row} {$r < $canshow} {incr r} {
-       foreach id [lindex $linesegends [expr {$r+1}]] {
-           set i -1
-           foreach {s e} [rowranges $id] {
-               incr i
-               if {$e ne {} && $e < $numcommits && $s <= $r1 && $e >= $r0
-                   && ![info exists idrangedrawn($id,$i)]} {
-                   drawlineseg $id $i
-                   set idrangedrawn($id,$i) 1
-               }
-           }
-       }
+    if {$r1 >= $canshow} {
+       set r1 [expr {$canshow - 1}]
     }
-    if {$canshow > $r1} {
-       set canshow $r1
-    }
-    while {$row < $canshow} {
-       drawcmitrow $row
-       incr row
+    if {$r0 <= $r1} {
+       drawcommits $r0 $r1
     }
     if {[info exists pending_select] &&
        [info exists commitrow($curview,$pending_select)] &&
        $commitrow($curview,$pending_select) < $numcommits} {
        selectline $commitrow($curview,$pending_select) 1
     }
-    if {![info exists selectedline] && ![info exists pending_select]} {
-       selectline 0 1
+    if {$selectfirst} {
+       if {[info exists selectedline] || [info exists pending_select]} {
+           set selectfirst 0
+       } else {
+           set l [expr {[lindex $displayorder 0] eq $nullid}]
+           selectline $l 1
+           set selectfirst 0
+       }
+    }
+    if {$lookingforhead && [info exists commitrow($curview,$mainheadid)]
+       && ($last || $commitrow($curview,$mainheadid) < $numcommits - 1)} {
+       set lookingforhead 0
+       dodiffindex
+    }
+}
+
+proc doshowlocalchanges {} {
+    global lookingforhead curview mainheadid phase commitrow
+
+    if {[info exists commitrow($curview,$mainheadid)] &&
+       ($phase eq {} || $commitrow($curview,$mainheadid) < $numcommits - 1)} {
+       dodiffindex
+    } elseif {$phase ne {}} {
+       set lookingforhead 1
+    }
+}
+
+proc dohidelocalchanges {} {
+    global lookingforhead localrow lserial
+
+    set lookingforhead 0
+    if {$localrow >= 0} {
+       removerow $localrow
+       set localrow -1
+    }
+    incr lserial
+}
+
+# spawn off a process to do git diff-index HEAD
+proc dodiffindex {} {
+    global localrow lserial
+
+    incr lserial
+    set localrow -1
+    set fd [open "|git diff-index HEAD" r]
+    fconfigure $fd -blocking 0
+    filerun $fd [list readdiffindex $fd $lserial]
+}
+
+proc readdiffindex {fd serial} {
+    global localrow commitrow mainheadid nullid curview
+    global commitinfo commitdata lserial
+
+    if {[gets $fd line] < 0} {
+       if {[eof $fd]} {
+           close $fd
+           return 0
+       }
+       return 1
+    }
+    # we only need to see one line and we don't really care what it says...
+    close $fd
+
+    if {$serial == $lserial && $localrow == -1} {
+       # add the line for the local diff to the graph
+       set localrow $commitrow($curview,$mainheadid)
+       set hl "Local uncommitted changes"
+       set commitinfo($nullid) [list  $hl {} {} {} {} "    $hl\n"]
+       set commitdata($nullid) "\n    $hl\n"
+       insertrow $localrow $nullid
     }
+    return 0
 }
 
 proc layoutrows {row endrow last} {
     global rowidlist rowoffsets displayorder
     global uparrowlen downarrowlen maxwidth mingaplen
-    global childlist parentlist
-    global idrowranges linesegends
+    global children parentlist
+    global idrowranges
     global commitidx curview
     global idinlist rowchk rowrangelist
 
@@ -2527,7 +2739,6 @@ proc layoutrows {row endrow last} {
                lappend oldolds $p
            }
        }
-       set lse {}
        set nev [expr {[llength $idlist] + [llength $newolds]
                       + [llength $oldolds] - $maxwidth + 1}]
        if {$nev > 0} {
@@ -2544,8 +2755,7 @@ proc layoutrows {row endrow last} {
                        set offs [incrange $offs $x 1]
                        set idinlist($i) 0
                        set rm1 [expr {$row - 1}]
-                       lappend lse $i
-                       lappend idrowranges($i) $rm1
+                       lappend idrowranges($i) [lindex $displayorder $rm1]
                        if {[incr nev -1] <= 0} break
                        continue
                    }
@@ -2555,14 +2765,13 @@ proc layoutrows {row endrow last} {
            lset rowidlist $row $idlist
            lset rowoffsets $row $offs
        }
-       lappend linesegends $lse
        set col [lsearch -exact $idlist $id]
        if {$col < 0} {
            set col [llength $idlist]
            lappend idlist $id
            lset rowidlist $row $idlist
            set z {}
-           if {[lindex $childlist $row] ne {}} {
+           if {$children($curview,$id) ne {}} {
                set z [expr {[llength [lindex $rowidlist [expr {$row-1}]]] - $col}]
                unset idinlist($id)
            }
@@ -2577,7 +2786,7 @@ proc layoutrows {row endrow last} {
        set ranges {}
        if {[info exists idrowranges($id)]} {
            set ranges $idrowranges($id)
-           lappend ranges $row
+           lappend ranges $id
            unset idrowranges($id)
        }
        lappend rowrangelist $ranges
@@ -2602,7 +2811,7 @@ proc layoutrows {row endrow last} {
        }
        foreach i $newolds {
            set idinlist($i) 1
-           set idrowranges($i) $row
+           set idrowranges($i) $id
        }
        incr col $l
        foreach oid $oldolds {
@@ -2621,7 +2830,7 @@ proc layoutrows {row endrow last} {
 proc addextraid {id row} {
     global displayorder commitrow commitinfo
     global commitidx commitlisted
-    global parentlist childlist children curview
+    global parentlist children curview
 
     incr commitidx($curview)
     lappend displayorder $id
@@ -2635,7 +2844,6 @@ proc addextraid {id row} {
     if {![info exists children($curview,$id)]} {
        set children($curview,$id) {}
     }
-    lappend childlist $children($curview,$id)
 }
 
 proc layouttail {} {
@@ -2660,6 +2868,7 @@ proc layouttail {} {
     }
 
     foreach id [array names idinlist] {
+       unset idinlist($id)
        addextraid $id $row
        lset rowidlist $row [list $id]
        lset rowoffsets $row 0
@@ -2683,7 +2892,7 @@ proc insert_pad {row col npad} {
 }
 
 proc optimize_rows {row col endrow} {
-    global rowidlist rowoffsets idrowranges displayorder
+    global rowidlist rowoffsets displayorder
 
     for {} {$row < $endrow} {incr row} {
        set idlist [lindex $rowidlist $row]
@@ -2707,7 +2916,13 @@ proc optimize_rows {row col endrow} {
                    set isarrow 1
                }
            }
+           # Looking at lines from this row to the previous row,
+           # make them go straight up if they end in an arrow on
+           # the previous row; otherwise make them go straight up
+           # or at 45 degrees.
            if {$z < -1 || ($z < 0 && $isarrow)} {
+               # Line currently goes left too much;
+               # insert pads in the previous row, then optimize it
                set npad [expr {-1 - $z + $isarrow}]
                set offs [incrange $offs $col $npad]
                insert_pad $y0 $x0 $npad
@@ -2718,6 +2933,8 @@ proc optimize_rows {row col endrow} {
                set x0 [expr {$col + $z}]
                set z0 [lindex $rowoffsets $y0 $x0]
            } elseif {$z > 1 || ($z > 0 && $isarrow)} {
+               # Line currently goes right too much;
+               # insert pads in this line and adjust the next's rowoffsets
                set npad [expr {$z - 1 + $isarrow}]
                set y1 [expr {$row + 1}]
                set offs2 [lindex $rowoffsets $y1]
@@ -2748,6 +2965,7 @@ proc optimize_rows {row col endrow} {
                    set z0 [expr {$xc - $x0}]
                }
            }
+           # avoid lines jigging left then immediately right
            if {$z0 ne {} && $z < 0 && $z0 > 0} {
                insert_pad $y0 $x0 1
                set offs [incrange $offs $col 1]
@@ -2756,6 +2974,7 @@ proc optimize_rows {row col endrow} {
        }
        if {!$haspad} {
            set o {}
+           # Find the first column that doesn't have a line going right
            for {set col [llength $idlist]} {[incr col -1] >= 0} {} {
                set o [lindex $offs $col]
                if {$o eq {}} {
@@ -2774,6 +2993,8 @@ proc optimize_rows {row col endrow} {
                }
                if {$o eq {} || $o <= 0} break
            }
+           # Insert a pad at that column as long as it has a line and
+           # isn't the last column, and adjust the next row' offsets
            if {$o ne {} && [incr col] < [llength $idlist]} {
                set y1 [expr {$row + 1}]
                set offs2 [lindex $rowoffsets $y1]
@@ -2827,99 +3048,216 @@ proc rowranges {id} {
     } elseif {[info exists idrowranges($id)]} {
        set ranges $idrowranges($id)
     }
-    return $ranges
+    set linenos {}
+    foreach rid $ranges {
+       lappend linenos $commitrow($curview,$rid)
+    }
+    if {$linenos ne {}} {
+       lset linenos 0 [expr {[lindex $linenos 0] + 1}]
+    }
+    return $linenos
 }
 
-proc drawlineseg {id i} {
-    global rowoffsets rowidlist
-    global displayorder
-    global canv colormap linespc
-    global numcommits commitrow curview
+# work around tk8.4 refusal to draw arrows on diagonal segments
+proc adjarrowhigh {coords} {
+    global linespc
 
-    set ranges [rowranges $id]
-    set downarrow 1
-    if {[info exists commitrow($curview,$id)]
-       && $commitrow($curview,$id) < $numcommits} {
-       set downarrow [expr {$i < [llength $ranges] / 2 - 1}]
-    } else {
-       set downarrow 1
-    }
-    set startrow [lindex $ranges [expr {2 * $i}]]
-    set row [lindex $ranges [expr {2 * $i + 1}]]
-    if {$startrow == $row} return
-    assigncolor $id
-    set coords {}
-    set col [lsearch -exact [lindex $rowidlist $row] $id]
-    if {$col < 0} {
-       puts "oops: drawline: id $id not on row $row"
-       return
+    set x0 [lindex $coords 0]
+    set x1 [lindex $coords 2]
+    if {$x0 != $x1} {
+       set y0 [lindex $coords 1]
+       set y1 [lindex $coords 3]
+       if {$y0 - $y1 <= 2 * $linespc && $x1 == [lindex $coords 4]} {
+           # we have a nearby vertical segment, just trim off the diag bit
+           set coords [lrange $coords 2 end]
+       } else {
+           set slope [expr {($x0 - $x1) / ($y0 - $y1)}]
+           set xi [expr {$x0 - $slope * $linespc / 2}]
+           set yi [expr {$y0 - $linespc / 2}]
+           set coords [lreplace $coords 0 1 $xi $y0 $xi $yi]
+       }
     }
-    set lasto {}
-    set ns 0
+    return $coords
+}
+
+proc drawlineseg {id row endrow arrowlow} {
+    global rowidlist displayorder iddrawn linesegs
+    global canv colormap linespc curview maxlinelen
+
+    set cols [list [lsearch -exact [lindex $rowidlist $row] $id]]
+    set le [expr {$row + 1}]
+    set arrowhigh 1
     while {1} {
-       set o [lindex $rowoffsets $row $col]
-       if {$o eq {}} break
-       if {$o ne $lasto} {
-           # changing direction
-           set x [xc $row $col]
-           set y [yc $row]
-           lappend coords $x $y
-           set lasto $o
+       set c [lsearch -exact [lindex $rowidlist $le] $id]
+       if {$c < 0} {
+           incr le -1
+           break
+       }
+       lappend cols $c
+       set x [lindex $displayorder $le]
+       if {$x eq $id} {
+           set arrowhigh 0
+           break
+       }
+       if {[info exists iddrawn($x)] || $le == $endrow} {
+           set c [lsearch -exact [lindex $rowidlist [expr {$le+1}]] $id]
+           if {$c >= 0} {
+               lappend cols $c
+               set arrowhigh 0
+           }
+           break
        }
-       incr col $o
-       incr row -1
+       incr le
     }
-    set x [xc $row $col]
-    set y [yc $row]
-    lappend coords $x $y
-    if {$i == 0} {
-       # draw the link to the first child as part of this line
-       incr row -1
-       set child [lindex $displayorder $row]
-       set ccol [lsearch -exact [lindex $rowidlist $row] $child]
-       if {$ccol >= 0} {
-           set x [xc $row $ccol]
-           set y [yc $row]
-           if {$ccol < $col - 1} {
-               lappend coords [xc $row [expr {$col - 1}]] [yc $row]
-           } elseif {$ccol > $col + 1} {
-               lappend coords [xc $row [expr {$col + 1}]] [yc $row]
+    if {$le <= $row} {
+       return $row
+    }
+
+    set lines {}
+    set i 0
+    set joinhigh 0
+    if {[info exists linesegs($id)]} {
+       set lines $linesegs($id)
+       foreach li $lines {
+           set r0 [lindex $li 0]
+           if {$r0 > $row} {
+               if {$r0 == $le && [lindex $li 1] - $row <= $maxlinelen} {
+                   set joinhigh 1
+               }
+               break
+           }
+           incr i
+       }
+    }
+    set joinlow 0
+    if {$i > 0} {
+       set li [lindex $lines [expr {$i-1}]]
+       set r1 [lindex $li 1]
+       if {$r1 == $row && $le - [lindex $li 0] <= $maxlinelen} {
+           set joinlow 1
+       }
+    }
+
+    set x [lindex $cols [expr {$le - $row}]]
+    set xp [lindex $cols [expr {$le - 1 - $row}]]
+    set dir [expr {$xp - $x}]
+    if {$joinhigh} {
+       set ith [lindex $lines $i 2]
+       set coords [$canv coords $ith]
+       set ah [$canv itemcget $ith -arrow]
+       set arrowhigh [expr {$ah eq "first" || $ah eq "both"}]
+       set x2 [lindex $cols [expr {$le + 1 - $row}]]
+       if {$x2 ne {} && $x - $x2 == $dir} {
+           set coords [lrange $coords 0 end-2]
+       }
+    } else {
+       set coords [list [xc $le $x] [yc $le]]
+    }
+    if {$joinlow} {
+       set itl [lindex $lines [expr {$i-1}] 2]
+       set al [$canv itemcget $itl -arrow]
+       set arrowlow [expr {$al eq "last" || $al eq "both"}]
+    } elseif {$arrowlow &&
+             [lsearch -exact [lindex $rowidlist [expr {$row-1}]] $id] >= 0} {
+       set arrowlow 0
+    }
+    set arrow [lindex {none first last both} [expr {$arrowhigh + 2*$arrowlow}]]
+    for {set y $le} {[incr y -1] > $row} {} {
+       set x $xp
+       set xp [lindex $cols [expr {$y - 1 - $row}]]
+       set ndir [expr {$xp - $x}]
+       if {$dir != $ndir || $xp < 0} {
+           lappend coords [xc $y $x] [yc $y]
+       }
+       set dir $ndir
+    }
+    if {!$joinlow} {
+       if {$xp < 0} {
+           # join parent line to first child
+           set ch [lindex $displayorder $row]
+           set xc [lsearch -exact [lindex $rowidlist $row] $ch]
+           if {$xc < 0} {
+               puts "oops: drawlineseg: child $ch not on row $row"
+           } else {
+               if {$xc < $x - 1} {
+                   lappend coords [xc $row [expr {$x-1}]] [yc $row]
+               } elseif {$xc > $x + 1} {
+                   lappend coords [xc $row [expr {$x+1}]] [yc $row]
+               }
+               set x $xc
            }
-           lappend coords $x $y
-       }
-    }
-    if {[llength $coords] < 4} return
-    if {$downarrow} {
-       # This line has an arrow at the lower end: check if the arrow is
-       # on a diagonal segment, and if so, work around the Tk 8.4
-       # refusal to draw arrows on diagonal lines.
-       set x0 [lindex $coords 0]
-       set x1 [lindex $coords 2]
-       if {$x0 != $x1} {
-           set y0 [lindex $coords 1]
-           set y1 [lindex $coords 3]
-           if {$y0 - $y1 <= 2 * $linespc && $x1 == [lindex $coords 4]} {
-               # we have a nearby vertical segment, just trim off the diag bit
-               set coords [lrange $coords 2 end]
+           lappend coords [xc $row $x] [yc $row]
+       } else {
+           set xn [xc $row $xp]
+           set yn [yc $row]
+           # work around tk8.4 refusal to draw arrows on diagonal segments
+           if {$arrowlow && $xn != [lindex $coords end-1]} {
+               if {[llength $coords] < 4 ||
+                   [lindex $coords end-3] != [lindex $coords end-1] ||
+                   [lindex $coords end] - $yn > 2 * $linespc} {
+                   set xn [xc $row [expr {$xp - 0.5 * $dir}]]
+                   set yo [yc [expr {$row + 0.5}]]
+                   lappend coords $xn $yo $xn $yn
+               }
            } else {
-               set slope [expr {($x0 - $x1) / ($y0 - $y1)}]
-               set xi [expr {$x0 - $slope * $linespc / 2}]
-               set yi [expr {$y0 - $linespc / 2}]
-               set coords [lreplace $coords 0 1 $xi $y0 $xi $yi]
+               lappend coords $xn $yn
+           }
+       }
+       if {!$joinhigh} {
+           if {$arrowhigh} {
+               set coords [adjarrowhigh $coords]
+           }
+           assigncolor $id
+           set t [$canv create line $coords -width [linewidth $id] \
+                      -fill $colormap($id) -tags lines.$id -arrow $arrow]
+           $canv lower $t
+           bindline $t $id
+           set lines [linsert $lines $i [list $row $le $t]]
+       } else {
+           $canv coords $ith $coords
+           if {$arrow ne $ah} {
+               $canv itemconf $ith -arrow $arrow
+           }
+           lset lines $i 0 $row
+       }
+    } else {
+       set xo [lsearch -exact [lindex $rowidlist [expr {$row - 1}]] $id]
+       set ndir [expr {$xo - $xp}]
+       set clow [$canv coords $itl]
+       if {$dir == $ndir} {
+           set clow [lrange $clow 2 end]
+       }
+       set coords [concat $coords $clow]
+       if {!$joinhigh} {
+           lset lines [expr {$i-1}] 1 $le
+           if {$arrowhigh} {
+               set coords [adjarrowhigh $coords]
            }
+       } else {
+           # coalesce two pieces
+           $canv delete $ith
+           set b [lindex $lines [expr {$i-1}] 0]
+           set e [lindex $lines $i 1]
+           set lines [lreplace $lines [expr {$i-1}] $i [list $b $e $itl]]
+       }
+       $canv coords $itl $coords
+       if {$arrow ne $al} {
+           $canv itemconf $itl -arrow $arrow
        }
     }
-    set arrow [expr {2 * ($i > 0) + $downarrow}]
-    set arrow [lindex {none first last both} $arrow]
-    set t [$canv create line $coords -width [linewidth $id] \
-              -fill $colormap($id) -tags lines.$id -arrow $arrow]
-    $canv lower $t
-    bindline $t $id
+
+    set linesegs($id) $lines
+    return $le
 }
 
-proc drawparentlinks {id row col olds} {
-    global rowidlist canv colormap
+proc drawparentlinks {id row} {
+    global rowidlist canv colormap curview parentlist
+    global idpos
 
+    set rowids [lindex $rowidlist $row]
+    set col [lsearch -exact $rowids $id]
+    if {$col < 0} return
+    set olds [lindex $parentlist $row]
     set row2 [expr {$row + 1}]
     set x [xc $row $col]
     set y [yc $row]
@@ -2937,9 +3275,7 @@ proc drawparentlinks {id row col olds} {
        if {$x2 > $rmx} {
            set rmx $x2
        }
-       set ranges [rowranges $p]
-       if {$ranges ne {} && $row2 == [lindex $ranges 0]
-           && $row2 < [lindex $ranges 1]} {
+       if {[lsearch -exact $rowids $p] < 0} {
            # drawlineseg will do this one for us
            continue
        }
@@ -2957,40 +3293,30 @@ proc drawparentlinks {id row col olds} {
        $canv lower $t
        bindline $t $p
     }
-    return $rmx
+    if {$rmx > [lindex $idpos($id) 1]} {
+       lset idpos($id) 1 $rmx
+       redrawtags $id
+    }
 }
 
 proc drawlines {id} {
-    global colormap canv
-    global idrangedrawn
-    global children iddrawn commitrow rowidlist curview
-
-    $canv delete lines.$id
-    set nr [expr {[llength [rowranges $id]] / 2}]
-    for {set i 0} {$i < $nr} {incr i} {
-       if {[info exists idrangedrawn($id,$i)]} {
-           drawlineseg $id $i
-       }
-    }
-    foreach child $children($curview,$id) {
-       if {[info exists iddrawn($child)]} {
-           set row $commitrow($curview,$child)
-           set col [lsearch -exact [lindex $rowidlist $row] $child]
-           if {$col >= 0} {
-               drawparentlinks $child $row $col [list $id]
-           }
-       }
-    }
+    global canv
+
+    $canv itemconf lines.$id -width [linewidth $id]
 }
 
-proc drawcmittext {id row col rmx} {
+proc drawcmittext {id row col} {
     global linespc canv canv2 canv3 canvy0 fgcolor
-    global commitlisted commitinfo rowidlist
+    global commitlisted commitinfo rowidlist parentlist
     global rowtextx idpos idtags idheads idotherrefs
     global linehtag linentag linedtag
-    global mainfont canvxmax boldrows boldnamerows fgcolor
+    global mainfont canvxmax boldrows boldnamerows fgcolor nullid
 
-    set ofill [expr {[lindex $commitlisted $row]? "blue": "white"}]
+    if {$id eq $nullid} {
+       set ofill red
+    } else {
+       set ofill [expr {[lindex $commitlisted $row]? "blue": "white"}]
+    }
     set x [xc $row $col]
     set y [yc $row]
     set orad [expr {$linespc / 3}]
@@ -2999,10 +3325,18 @@ proc drawcmittext {id row col rmx} {
               -fill $ofill -outline $fgcolor -width 1 -tags circle]
     $canv raise $t
     $canv bind $t <1> {selcanvline {} %x %y}
-    set xt [xc $row [llength [lindex $rowidlist $row]]]
-    if {$xt < $rmx} {
-       set xt $rmx
+    set rmx [llength [lindex $rowidlist $row]]
+    set olds [lindex $parentlist $row]
+    if {$olds ne {}} {
+       set nextids [lindex $rowidlist [expr {$row + 1}]]
+       foreach p $olds {
+           set i [lsearch -exact $nextids $p]
+           if {$i > $rmx} {
+               set rmx $i
+           }
+       }
     }
+    set xt [xc $row $rmx]
     set rowtextx($row) $xt
     set idpos($id) [list $x $xt $y]
     if {[info exists idtags($id)] || [info exists idheads($id)]
@@ -3040,29 +3374,13 @@ proc drawcmittext {id row col rmx} {
 
 proc drawcmitrow {row} {
     global displayorder rowidlist
-    global idrangedrawn iddrawn
+    global iddrawn
     global commitinfo parentlist numcommits
     global filehighlight fhighlights findstring nhighlights
     global hlview vhighlights
     global highlight_related rhighlights
 
     if {$row >= $numcommits} return
-    foreach id [lindex $rowidlist $row] {
-       if {$id eq {}} continue
-       set i -1
-       foreach {s e} [rowranges $id] {
-           incr i
-           if {$row < $s} continue
-           if {$e eq {}} break
-           if {$row <= $e} {
-               if {$e < $numcommits && ![info exists idrangedrawn($id,$i)]} {
-                   drawlineseg $id $i
-                   set idrangedrawn($id,$i) 1
-               }
-               break
-           }
-       }
-    }
 
     set id [lindex $displayorder $row]
     if {[info exists hlview] && ![info exists vhighlights($row)]} {
@@ -3087,49 +3405,99 @@ proc drawcmitrow {row} {
        getcommit $id
     }
     assigncolor $id
-    set olds [lindex $parentlist $row]
-    if {$olds ne {}} {
-       set rmx [drawparentlinks $id $row $col $olds]
-    } else {
-       set rmx 0
-    }
-    drawcmittext $id $row $col $rmx
+    drawcmittext $id $row $col
     set iddrawn($id) 1
 }
 
-proc drawfrac {f0 f1} {
-    global numcommits canv
-    global linespc
+proc drawcommits {row {endrow {}}} {
+    global numcommits iddrawn displayorder curview
+    global parentlist rowidlist
 
-    set ymax [lindex [$canv cget -scrollregion] 3]
-    if {$ymax eq {} || $ymax == 0} return
-    set y0 [expr {int($f0 * $ymax)}]
-    set row [expr {int(($y0 - 3) / $linespc) - 1}]
     if {$row < 0} {
        set row 0
     }
-    set y1 [expr {int($f1 * $ymax)}]
-    set endrow [expr {int(($y1 - 3) / $linespc) + 1}]
+    if {$endrow eq {}} {
+       set endrow $row
+    }
     if {$endrow >= $numcommits} {
        set endrow [expr {$numcommits - 1}]
     }
-    for {} {$row <= $endrow} {incr row} {
-       drawcmitrow $row
+
+    # make the lines join to already-drawn rows either side
+    set r [expr {$row - 1}]
+    if {$r < 0 || ![info exists iddrawn([lindex $displayorder $r])]} {
+       set r $row
+    }
+    set er [expr {$endrow + 1}]
+    if {$er >= $numcommits ||
+       ![info exists iddrawn([lindex $displayorder $er])]} {
+       set er $endrow
+    }
+    for {} {$r <= $er} {incr r} {
+       set id [lindex $displayorder $r]
+       set wasdrawn [info exists iddrawn($id)]
+       if {!$wasdrawn} {
+           drawcmitrow $r
+       }
+       if {$r == $er} break
+       set nextid [lindex $displayorder [expr {$r + 1}]]
+       if {$wasdrawn && [info exists iddrawn($nextid)]} {
+           catch {unset prevlines}
+           continue
+       }
+       drawparentlinks $id $r
+
+       if {[info exists lineends($r)]} {
+           foreach lid $lineends($r) {
+               unset prevlines($lid)
+           }
+       }
+       set rowids [lindex $rowidlist $r]
+       foreach lid $rowids {
+           if {$lid eq {}} continue
+           if {$lid eq $id} {
+               # see if this is the first child of any of its parents
+               foreach p [lindex $parentlist $r] {
+                   if {[lsearch -exact $rowids $p] < 0} {
+                       # make this line extend up to the child
+                       set le [drawlineseg $p $r $er 0]
+                       lappend lineends($le) $p
+                       set prevlines($p) 1
+                   }
+               }
+           } elseif {![info exists prevlines($lid)]} {
+               set le [drawlineseg $lid $r $er 1]
+               lappend lineends($le) $lid
+               set prevlines($lid) 1
+           }
+       }
     }
 }
 
+proc drawfrac {f0 f1} {
+    global canv linespc
+
+    set ymax [lindex [$canv cget -scrollregion] 3]
+    if {$ymax eq {} || $ymax == 0} return
+    set y0 [expr {int($f0 * $ymax)}]
+    set row [expr {int(($y0 - 3) / $linespc) - 1}]
+    set y1 [expr {int($f1 * $ymax)}]
+    set endrow [expr {int(($y1 - 3) / $linespc) + 1}]
+    drawcommits $row $endrow
+}
+
 proc drawvisible {} {
     global canv
     eval drawfrac [$canv yview]
 }
 
 proc clear_display {} {
-    global iddrawn idrangedrawn
+    global iddrawn linesegs
     global vhighlights fhighlights nhighlights rhighlights
 
     allcanvs delete all
     catch {unset iddrawn}
-    catch {unset idrangedrawn}
+    catch {unset linesegs}
     catch {unset vhighlights}
     catch {unset fhighlights}
     catch {unset nhighlights}
@@ -3356,27 +3724,14 @@ proc show_status {msg} {
        -tags text -fill $fgcolor
 }
 
-proc finishcommits {} {
-    global commitidx phase curview
-    global pending_select
-
-    if {$commitidx($curview) > 0} {
-       drawrest
-    } else {
-       show_status "No commits selected"
-    }
-    set phase {}
-    catch {unset pending_select}
-}
-
 # Insert a new commit as the child of the commit on row $row.
 # The new commit will be displayed on row $row and the commits
 # on that row and below will move down one row.
 proc insertrow {row newcmit} {
-    global displayorder parentlist childlist commitlisted
+    global displayorder parentlist commitlisted children
     global commitrow curview rowidlist rowoffsets numcommits
-    global rowrangelist idrowranges rowlaidout rowoptim numcommits
-    global linesegends selectedline
+    global rowrangelist rowlaidout rowoptim numcommits
+    global selectedline rowchk commitidx
 
     if {$row >= $numcommits} {
        puts "oops, inserting new row $row but only have $numcommits rows"
@@ -3385,16 +3740,17 @@ proc insertrow {row newcmit} {
     set p [lindex $displayorder $row]
     set displayorder [linsert $displayorder $row $newcmit]
     set parentlist [linsert $parentlist $row $p]
-    set kids [lindex $childlist $row]
+    set kids $children($curview,$p)
     lappend kids $newcmit
-    lset childlist $row $kids
-    set childlist [linsert $childlist $row {}]
+    set children($curview,$p) $kids
+    set children($curview,$newcmit) {}
     set commitlisted [linsert $commitlisted $row 1]
     set l [llength $displayorder]
     for {set r $row} {$r < $l} {incr r} {
        set id [lindex $displayorder $r]
        set commitrow($curview,$id) $r
     }
+    incr commitidx($curview)
 
     set idlist [lindex $rowidlist $row]
     set offs [lindex $rowoffsets $row]
@@ -3419,47 +3775,18 @@ proc insertrow {row newcmit} {
     set rowoffsets [linsert $rowoffsets [expr {$row+1}] $newoffs]
 
     set rowrangelist [linsert $rowrangelist $row {}]
-    set l [llength $rowrangelist]
-    for {set r 0} {$r < $l} {incr r} {
-       set ranges [lindex $rowrangelist $r]
-       if {$ranges ne {} && [lindex $ranges end] >= $row} {
-           set newranges {}
-           foreach x $ranges {
-               if {$x >= $row} {
-                   lappend newranges [expr {$x + 1}]
-               } else {
-                   lappend newranges $x
-               }
-           }
-           lset rowrangelist $r $newranges
-       }
-    }
     if {[llength $kids] > 1} {
        set rp1 [expr {$row + 1}]
        set ranges [lindex $rowrangelist $rp1]
        if {$ranges eq {}} {
-           set ranges [list $row $rp1]
-       } elseif {[lindex $ranges end-1] == $rp1} {
-           lset ranges end-1 $row
+           set ranges [list $newcmit $p]
+       } elseif {[lindex $ranges end-1] eq $p} {
+           lset ranges end-1 $newcmit
        }
        lset rowrangelist $rp1 $ranges
     }
-    foreach id [array names idrowranges] {
-       set ranges $idrowranges($id)
-       if {$ranges ne {} && [lindex $ranges end] >= $row} {
-           set newranges {}
-           foreach x $ranges {
-               if {$x >= $row} {
-                   lappend newranges [expr {$x + 1}]
-               } else {
-                   lappend newranges $x
-               }
-           }
-           set idrowranges($id) $newranges
-       }
-    }
 
-    set linesegends [linsert $linesegends $row {}]
+    catch {unset rowchk}
 
     incr rowlaidout
     incr rowoptim
@@ -3471,16 +3798,75 @@ proc insertrow {row newcmit} {
     redisplay
 }
 
-# Don't change the text pane cursor if it is currently the hand cursor,
-# showing that we are over a sha1 ID link.
-proc settextcursor {c} {
-    global ctext curtextcursor
+# Remove a commit that was inserted with insertrow on row $row.
+proc removerow {row} {
+    global displayorder parentlist commitlisted children
+    global commitrow curview rowidlist rowoffsets numcommits
+    global rowrangelist idrowranges rowlaidout rowoptim numcommits
+    global linesegends selectedline rowchk commitidx
 
-    if {[$ctext cget -cursor] == $curtextcursor} {
-       $ctext config -cursor $c
+    if {$row >= $numcommits} {
+       puts "oops, removing row $row but only have $numcommits rows"
+       return
     }
-    set curtextcursor $c
-}
+    set rp1 [expr {$row + 1}]
+    set id [lindex $displayorder $row]
+    set p [lindex $parentlist $row]
+    set displayorder [lreplace $displayorder $row $row]
+    set parentlist [lreplace $parentlist $row $row]
+    set commitlisted [lreplace $commitlisted $row $row]
+    set kids $children($curview,$p)
+    set i [lsearch -exact $kids $id]
+    if {$i >= 0} {
+       set kids [lreplace $kids $i $i]
+       set children($curview,$p) $kids
+    }
+    set l [llength $displayorder]
+    for {set r $row} {$r < $l} {incr r} {
+       set id [lindex $displayorder $r]
+       set commitrow($curview,$id) $r
+    }
+    incr commitidx($curview) -1
+
+    set rowidlist [lreplace $rowidlist $row $row]
+    set rowoffsets [lreplace $rowoffsets $rp1 $rp1]
+    if {$kids ne {}} {
+       set offs [lindex $rowoffsets $row]
+       set offs [lreplace $offs end end]
+       lset rowoffsets $row $offs
+    }
+
+    set rowrangelist [lreplace $rowrangelist $row $row]
+    if {[llength $kids] > 0} {
+       set ranges [lindex $rowrangelist $row]
+       if {[lindex $ranges end-1] eq $id} {
+           set ranges [lreplace $ranges end-1 end]
+           lset rowrangelist $row $ranges
+       }
+    }
+
+    catch {unset rowchk}
+
+    incr rowlaidout -1
+    incr rowoptim -1
+    incr numcommits -1
+
+    if {[info exists selectedline] && $selectedline > $row} {
+       incr selectedline -1
+    }
+    redisplay
+}
+
+# Don't change the text pane cursor if it is currently the hand cursor,
+# showing that we are over a sha1 ID link.
+proc settextcursor {c} {
+    global ctext curtextcursor
+
+    if {[$ctext cget -cursor] == $curtextcursor} {
+       $ctext config -cursor $c
+    }
+    set curtextcursor $c
+}
 
 proc nowbusy {what} {
     global isbusy
@@ -3502,25 +3888,6 @@ proc notbusy {what} {
     }
 }
 
-proc drawrest {} {
-    global startmsecs
-    global rowlaidout commitidx curview
-    global pending_select
-
-    set row $rowlaidout
-    layoutrows $rowlaidout $commitidx($curview) 1
-    layouttail
-    optimize_rows $row 0 $commitidx($curview)
-    showstuff $commitidx($curview)
-    if {[info exists pending_select]} {
-       selectline 0 1
-    }
-
-    set drawmsecs [expr {[clock clicks -milliseconds] - $startmsecs}]
-    #global numcommits
-    #puts "overall $drawmsecs ms for $numcommits commits"
-}
-
 proc findmatches {f} {
     global findtype foundstring foundstrlen
     if {$findtype == "Regexp"} {
@@ -3594,13 +3961,13 @@ proc dofind {} {
            if {$matches == {}} continue
            set doesmatch 1
            if {$ty == "Headline"} {
-               drawcmitrow $l
+               drawcommits $l
                markmatches $canv $l $f $linehtag($l) $matches $mainfont
            } elseif {$ty == "Author"} {
-               drawcmitrow $l
+               drawcommits $l
                markmatches $canv2 $l $f $linentag($l) $matches $mainfont
            } elseif {$ty == "Date"} {
-               drawcmitrow $l
+               drawcommits $l
                markmatches $canv3 $l $f $linedtag($l) $matches $mainfont
            }
        }
@@ -3693,7 +4060,7 @@ proc stopfindproc {{done 0}} {
 proc markheadline {l id} {
     global canv mainfont linehtag
 
-    drawcmitrow $l
+    drawcommits $l
     set bbox [$canv bbox $linehtag($l)]
     set t [$canv create rect $bbox -outline {} -tags matches -fill yellow]
     $canv lower $t
@@ -3798,75 +4165,106 @@ proc viewnextline {dir} {
 
 # add a list of tag or branch names at position pos
 # returns the number of names inserted
-proc appendrefs {pos tags var} {
-    global ctext commitrow linknum curview $var
+proc appendrefs {pos ids var} {
+    global ctext commitrow linknum curview $var maxrefs
 
     if {[catch {$ctext index $pos}]} {
        return 0
     }
-    set tags [lsort $tags]
-    set sep {}
-    foreach tag $tags {
-       set id [set $var\($tag\)]
-       set lk link$linknum
-       incr linknum
-       $ctext insert $pos $sep
-       $ctext insert $pos $tag $lk
-       $ctext tag conf $lk -foreground blue
-       if {[info exists commitrow($curview,$id)]} {
-           $ctext tag bind $lk <1> \
-               [list selectline $commitrow($curview,$id) 1]
-           $ctext tag conf $lk -underline 1
-           $ctext tag bind $lk <Enter> { %W configure -cursor hand2 }
-           $ctext tag bind $lk <Leave> { %W configure -cursor $curtextcursor }
+    $ctext conf -state normal
+    $ctext delete $pos "$pos lineend"
+    set tags {}
+    foreach id $ids {
+       foreach tag [set $var\($id\)] {
+           lappend tags [list $tag $id]
        }
-       set sep ", "
     }
+    if {[llength $tags] > $maxrefs} {
+       $ctext insert $pos "many ([llength $tags])"
+    } else {
+       set tags [lsort -index 0 -decreasing $tags]
+       set sep {}
+       foreach ti $tags {
+           set id [lindex $ti 1]
+           set lk link$linknum
+           incr linknum
+           $ctext tag delete $lk
+           $ctext insert $pos $sep
+           $ctext insert $pos [lindex $ti 0] $lk
+           if {[info exists commitrow($curview,$id)]} {
+               $ctext tag conf $lk -foreground blue
+               $ctext tag bind $lk <1> \
+                   [list selectline $commitrow($curview,$id) 1]
+               $ctext tag conf $lk -underline 1
+               $ctext tag bind $lk <Enter> { %W configure -cursor hand2 }
+               $ctext tag bind $lk <Leave> \
+                   { %W configure -cursor $curtextcursor }
+           }
+           set sep ", "
+       }
+    }
+    $ctext conf -state disabled
     return [llength $tags]
 }
 
-proc taglist {ids} {
-    global idtags
+# called when we have finished computing the nearby tags
+proc dispneartags {delay} {
+    global selectedline currentid showneartags tagphase
 
-    set tags {}
-    foreach id $ids {
-       foreach tag $idtags($id) {
-           lappend tags $tag
-       }
+    if {![info exists selectedline] || !$showneartags} return
+    after cancel dispnexttag
+    if {$delay} {
+       after 200 dispnexttag
+       set tagphase -1
+    } else {
+       after idle dispnexttag
+       set tagphase 0
     }
-    return $tags
 }
 
-# called when we have finished computing the nearby tags
-proc dispneartags {} {
-    global selectedline currentid ctext anc_tags desc_tags showneartags
-    global desc_heads
+proc dispnexttag {} {
+    global selectedline currentid showneartags tagphase ctext
 
     if {![info exists selectedline] || !$showneartags} return
-    set id $currentid
-    $ctext conf -state normal
-    if {[info exists desc_heads($id)]} {
-       if {[appendrefs branch $desc_heads($id) headids] > 1} {
-           $ctext insert "branch -2c" "es"
+    switch -- $tagphase {
+       0 {
+           set dtags [desctags $currentid]
+           if {$dtags ne {}} {
+               appendrefs precedes $dtags idtags
+           }
+       }
+       1 {
+           set atags [anctags $currentid]
+           if {$atags ne {}} {
+               appendrefs follows $atags idtags
+           }
+       }
+       2 {
+           set dheads [descheads $currentid]
+           if {$dheads ne {}} {
+               if {[appendrefs branch $dheads idheads] > 1
+                   && [$ctext get "branch -3c"] eq "h"} {
+                   # turn "Branch" into "Branches"
+                   $ctext conf -state normal
+                   $ctext insert "branch -2c" "es"
+                   $ctext conf -state disabled
+               }
+           }
        }
     }
-    if {[info exists anc_tags($id)]} {
-       appendrefs follows [taglist $anc_tags($id)] tagids
-    }
-    if {[info exists desc_tags($id)]} {
-       appendrefs precedes [taglist $desc_tags($id)] tagids
+    if {[incr tagphase] <= 2} {
+       after idle dispnexttag
     }
-    $ctext conf -state disabled
 }
 
 proc selectline {l isnew} {
     global canv canv2 canv3 ctext commitinfo selectedline
     global displayorder linehtag linentag linedtag
-    global canvy0 linespc parentlist childlist
+    global canvy0 linespc parentlist children curview
     global currentid sha1entry
     global commentend idtags linknum
     global mergemax numcommits pending_select
-    global cmitmode desc_tags anc_tags showneartags allcommits desc_heads
+    global cmitmode showneartags allcommits
 
     catch {unset pending_select}
     $canv delete hover
@@ -3973,7 +4371,7 @@ proc selectline {l isnew} {
        }
     }
 
-    foreach c [lindex $childlist $l] {
+    foreach c $children($curview,$id) {
        append headers "Child:  [commit_descriptor $c]"
     }
 
@@ -3986,30 +4384,22 @@ proc selectline {l isnew} {
        $ctext insert end "Branch: "
        $ctext mark set branch "end -1c"
        $ctext mark gravity branch left
-       if {[info exists desc_heads($id)]} {
-           if {[appendrefs branch $desc_heads($id) headids] > 1} {
-               # turn "Branch" into "Branches"
-               $ctext insert "branch -2c" "es"
-           }
-       }
        $ctext insert end "\nFollows: "
        $ctext mark set follows "end -1c"
        $ctext mark gravity follows left
-       if {[info exists anc_tags($id)]} {
-           appendrefs follows [taglist $anc_tags($id)] tagids
-       }
        $ctext insert end "\nPrecedes: "
        $ctext mark set precedes "end -1c"
        $ctext mark gravity precedes left
-       if {[info exists desc_tags($id)]} {
-           appendrefs precedes [taglist $desc_tags($id)] tagids
-       }
        $ctext insert end "\n"
+       dispneartags 1
     }
     $ctext insert end "\n"
-    appendwithlinks [lindex $info 5] {comment}
+    set comment [lindex $info 5]
+    if {[string first "\r" $comment] >= 0} {
+       set comment [string map {"\r" "\n    "} $comment]
+    }
+    appendwithlinks $comment {comment}
 
-    $ctext tag delete Comments
     $ctext tag remove found 1.0 end
     $ctext conf -state disabled
     set commentend [$ctext index "end - 1c"]
@@ -4144,20 +4534,25 @@ proc goforw {} {
 }
 
 proc gettree {id} {
-    global treefilelist treeidlist diffids diffmergeid treepending
+    global treefilelist treeidlist diffids diffmergeid treepending nullid
 
     set diffids $id
     catch {unset diffmergeid}
     if {![info exists treefilelist($id)]} {
        if {![info exists treepending]} {
-           if {[catch {set gtf [open [concat | git ls-tree -r $id] r]}]} {
+           if {$id ne $nullid} {
+               set cmd [concat | git ls-tree -r $id]
+           } else {
+               set cmd [concat | git ls-files]
+           }
+           if {[catch {set gtf [open $cmd r]}]} {
                return
            }
            set treepending $id
            set treefilelist($id) {}
            set treeidlist($id) {}
            fconfigure $gtf -blocking 0
-           fileevent $gtf readable [list gettreeline $gtf $id]
+           filerun $gtf [list gettreeline $gtf $id]
        }
     } else {
        setfilelist $id
@@ -4165,16 +4560,28 @@ proc gettree {id} {
 }
 
 proc gettreeline {gtf id} {
-    global treefilelist treeidlist treepending cmitmode diffids
-
-    while {[gets $gtf line] >= 0} {
-       if {[lindex $line 1] ne "blob"} continue
-       set sha1 [lindex $line 2]
-       set fname [lindex $line 3]
+    global treefilelist treeidlist treepending cmitmode diffids nullid
+
+    set nl 0
+    while {[incr nl] <= 1000 && [gets $gtf line] >= 0} {
+       if {$diffids ne $nullid} {
+           if {[lindex $line 1] ne "blob"} continue
+           set i [string first "\t" $line]
+           if {$i < 0} continue
+           set sha1 [lindex $line 2]
+           set fname [string range $line [expr {$i+1}] end]
+           if {[string index $fname 0] eq "\""} {
+               set fname [lindex $fname 0]
+           }
+           lappend treeidlist($id) $sha1
+       } else {
+           set fname $line
+       }
        lappend treefilelist($id) $fname
-       lappend treeidlist($id) $sha1
     }
-    if {![eof $gtf]} return
+    if {![eof $gtf]} {
+       return [expr {$nl >= 1000? 2: 1}]
+    }
     close $gtf
     unset treepending
     if {$cmitmode ne "tree"} {
@@ -4186,10 +4593,11 @@ proc gettreeline {gtf id} {
     } else {
        setfilelist $id
     }
+    return 0
 }
 
 proc showfile {f} {
-    global treefilelist treeidlist diffids
+    global treefilelist treeidlist diffids nullid
     global ctext commentend
 
     set i [lsearch -exact $treefilelist($diffids) $f]
@@ -4197,13 +4605,20 @@ proc showfile {f} {
        puts "oops, $f not in list for id $diffids"
        return
     }
-    set blob [lindex $treeidlist($diffids) $i]
-    if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} {
-       puts "oops, error reading blob $blob: $err"
-       return
+    if {$diffids ne $nullid} {
+       set blob [lindex $treeidlist($diffids) $i]
+       if {[catch {set bf [open [concat | git cat-file blob $blob] r]} err]} {
+           puts "oops, error reading blob $blob: $err"
+           return
+       }
+    } else {
+       if {[catch {set bf [open $f r]} err]} {
+           puts "oops, can't read $f: $err"
+           return
+       }
     }
     fconfigure $bf -blocking 0
-    fileevent $bf readable [list getblobline $bf $diffids]
+    filerun $bf [list getblobline $bf $diffids]
     $ctext config -state normal
     clear_ctext $commentend
     $ctext insert end "\n"
@@ -4217,18 +4632,21 @@ proc getblobline {bf id} {
 
     if {$id ne $diffids || $cmitmode ne "tree"} {
        catch {close $bf}
-       return
+       return 0
     }
     $ctext config -state normal
-    while {[gets $bf line] >= 0} {
+    set nl 0
+    while {[incr nl] <= 1000 && [gets $bf line] >= 0} {
        $ctext insert end "$line\n"
     }
     if {[eof $bf]} {
        # delete last newline
        $ctext delete "end - 2c" "end - 1c"
        close $bf
+       return 0
     }
     $ctext config -state disabled
+    return [expr {$nl >= 1000? 2: 1}]
 }
 
 proc mergediff {id l} {
@@ -4248,91 +4666,86 @@ proc mergediff {id l} {
     fconfigure $mdf -blocking 0
     set mdifffd($id) $mdf
     set np [llength [lindex $parentlist $l]]
-    fileevent $mdf readable [list getmergediffline $mdf $id $np]
-    set nextupdate [expr {[clock clicks -milliseconds] + 100}]
+    filerun $mdf [list getmergediffline $mdf $id $np]
 }
 
 proc getmergediffline {mdf id np} {
-    global diffmergeid ctext cflist nextupdate mergemax
+    global diffmergeid ctext cflist mergemax
     global difffilestart mdifffd
 
-    set n [gets $mdf line]
-    if {$n < 0} {
-       if {[eof $mdf]} {
+    $ctext conf -state normal
+    set nr 0
+    while {[incr nr] <= 1000 && [gets $mdf line] >= 0} {
+       if {![info exists diffmergeid] || $id != $diffmergeid
+           || $mdf != $mdifffd($id)} {
            close $mdf
+           return 0
        }
-       return
-    }
-    if {![info exists diffmergeid] || $id != $diffmergeid
-       || $mdf != $mdifffd($id)} {
-       return
-    }
-    $ctext conf -state normal
-    if {[regexp {^diff --cc (.*)} $line match fname]} {
-       # start of a new file
-       $ctext insert end "\n"
-       set here [$ctext index "end - 1c"]
-       lappend difffilestart $here
-       add_flist [list $fname]
-       set l [expr {(78 - [string length $fname]) / 2}]
-       set pad [string range "----------------------------------------" 1 $l]
-       $ctext insert end "$pad $fname $pad\n" filesep
-    } elseif {[regexp {^@@} $line]} {
-       $ctext insert end "$line\n" hunksep
-    } elseif {[regexp {^[0-9a-f]{40}$} $line] || [regexp {^index} $line]} {
-       # do nothing
-    } else {
-       # parse the prefix - one ' ', '-' or '+' for each parent
-       set spaces {}
-       set minuses {}
-       set pluses {}
-       set isbad 0
-       for {set j 0} {$j < $np} {incr j} {
-           set c [string range $line $j $j]
-           if {$c == " "} {
-               lappend spaces $j
-           } elseif {$c == "-"} {
-               lappend minuses $j
-           } elseif {$c == "+"} {
-               lappend pluses $j
-           } else {
-               set isbad 1
-               break
+       if {[regexp {^diff --cc (.*)} $line match fname]} {
+           # start of a new file
+           $ctext insert end "\n"
+           set here [$ctext index "end - 1c"]
+           lappend difffilestart $here
+           add_flist [list $fname]
+           set l [expr {(78 - [string length $fname]) / 2}]
+           set pad [string range "----------------------------------------" 1 $l]
+           $ctext insert end "$pad $fname $pad\n" filesep
+       } elseif {[regexp {^@@} $line]} {
+           $ctext insert end "$line\n" hunksep
+       } elseif {[regexp {^[0-9a-f]{40}$} $line] || [regexp {^index} $line]} {
+           # do nothing
+       } else {
+           # parse the prefix - one ' ', '-' or '+' for each parent
+           set spaces {}
+           set minuses {}
+           set pluses {}
+           set isbad 0
+           for {set j 0} {$j < $np} {incr j} {
+               set c [string range $line $j $j]
+               if {$c == " "} {
+                   lappend spaces $j
+               } elseif {$c == "-"} {
+                   lappend minuses $j
+               } elseif {$c == "+"} {
+                   lappend pluses $j
+               } else {
+                   set isbad 1
+                   break
+               }
            }
-       }
-       set tags {}
-       set num {}
-       if {!$isbad && $minuses ne {} && $pluses eq {}} {
-           # line doesn't appear in result, parents in $minuses have the line
-           set num [lindex $minuses 0]
-       } elseif {!$isbad && $pluses ne {} && $minuses eq {}} {
-           # line appears in result, parents in $pluses don't have the line
-           lappend tags mresult
-           set num [lindex $spaces 0]
-       }
-       if {$num ne {}} {
-           if {$num >= $mergemax} {
-               set num "max"
+           set tags {}
+           set num {}
+           if {!$isbad && $minuses ne {} && $pluses eq {}} {
+               # line doesn't appear in result, parents in $minuses have the line
+               set num [lindex $minuses 0]
+           } elseif {!$isbad && $pluses ne {} && $minuses eq {}} {
+               # line appears in result, parents in $pluses don't have the line
+               lappend tags mresult
+               set num [lindex $spaces 0]
            }
-           lappend tags m$num
+           if {$num ne {}} {
+               if {$num >= $mergemax} {
+                   set num "max"
+               }
+               lappend tags m$num
+           }
+           $ctext insert end "$line\n" $tags
        }
-       $ctext insert end "$line\n" $tags
     }
     $ctext conf -state disabled
-    if {[clock clicks -milliseconds] >= $nextupdate} {
-       incr nextupdate 100
-       fileevent $mdf readable {}
-       update
-       fileevent $mdf readable [list getmergediffline $mdf $id $np]
+    if {[eof $mdf]} {
+       close $mdf
+       return 0
     }
+    return [expr {$nr >= 1000? 2: 1}]
 }
 
 proc startdiff {ids} {
-    global treediffs diffids treepending diffmergeid
+    global treediffs diffids treepending diffmergeid nullid
 
     set diffids $ids
     catch {unset diffmergeid}
-    if {![info exists treediffs($ids)]} {
+    if {![info exists treediffs($ids)] || [lsearch -exact $ids $nullid] >= 0} {
        if {![info exists treepending]} {
            gettreediffs $ids
        }
@@ -4347,59 +4760,83 @@ proc addtocflist {ids} {
     getblobdiffs $ids
 }
 
+proc diffcmd {ids flags} {
+    global nullid
+
+    set i [lsearch -exact $ids $nullid]
+    if {$i >= 0} {
+       set cmd [concat | git diff-index $flags]
+       if {[llength $ids] > 1} {
+           if {$i == 0} {
+               lappend cmd -R [lindex $ids 1]
+           } else {
+               lappend cmd [lindex $ids 0]
+           }
+       } else {
+           lappend cmd HEAD
+       }
+    } else {
+       set cmd [concat | git diff-tree --no-commit-id -r $flags $ids]
+    }
+    return $cmd
+}
+
 proc gettreediffs {ids} {
     global treediff treepending
+
     set treepending $ids
     set treediff {}
-    if {[catch \
-        {set gdtf [open [concat | git diff-tree --no-commit-id -r $ids] r]} \
-       ]} return
+    if {[catch {set gdtf [open [diffcmd $ids {}] r]}]} return
     fconfigure $gdtf -blocking 0
-    fileevent $gdtf readable [list gettreediffline $gdtf $ids]
+    filerun $gdtf [list gettreediffline $gdtf $ids]
 }
 
 proc gettreediffline {gdtf ids} {
     global treediff treediffs treepending diffids diffmergeid
     global cmitmode
 
-    set n [gets $gdtf line]
-    if {$n < 0} {
-       if {![eof $gdtf]} return
-       close $gdtf
-       set treediffs($ids) $treediff
-       unset treepending
-       if {$cmitmode eq "tree"} {
-           gettree $diffids
-       } elseif {$ids != $diffids} {
-           if {![info exists diffmergeid]} {
-               gettreediffs $diffids
+    set nr 0
+    while {[incr nr] <= 1000 && [gets $gdtf line] >= 0} {
+       set i [string first "\t" $line]
+       if {$i >= 0} {
+           set file [string range $line [expr {$i+1}] end]
+           if {[string index $file 0] eq "\""} {
+               set file [lindex $file 0]
            }
-       } else {
-           addtocflist $ids
+           lappend treediff $file
        }
-       return
     }
-    set file [lindex $line 5]
-    lappend treediff $file
+    if {![eof $gdtf]} {
+       return [expr {$nr >= 1000? 2: 1}]
+    }
+    close $gdtf
+    set treediffs($ids) $treediff
+    unset treepending
+    if {$cmitmode eq "tree"} {
+       gettree $diffids
+    } elseif {$ids != $diffids} {
+       if {![info exists diffmergeid]} {
+           gettreediffs $diffids
+       }
+    } else {
+       addtocflist $ids
+    }
+    return 0
 }
 
 proc getblobdiffs {ids} {
-    global diffopts blobdifffd diffids env curdifftag curtagstart
-    global nextupdate diffinhdr treediffs
+    global diffopts blobdifffd diffids env
+    global diffinhdr treediffs
 
     set env(GIT_DIFF_OPTS) $diffopts
-    set cmd [concat | git diff-tree --no-commit-id -r -p -C $ids]
-    if {[catch {set bdf [open $cmd r]} err]} {
+    if {[catch {set bdf [open [diffcmd $ids {-p -C}] r]} err]} {
        puts "error getting diffs: $err"
        return
     }
     set diffinhdr 0
     fconfigure $bdf -blocking 0
     set blobdifffd($ids) $bdf
-    set curdifftag Comments
-    set curtagstart 0.0
-    fileevent $bdf readable [list getblobdiffline $bdf $diffids]
-    set nextupdate [expr {[clock clicks -milliseconds] + 100}]
+    filerun $bdf [list getblobdiffline $bdf $diffids]
 }
 
 proc setinlist {var i val} {
@@ -4415,84 +4852,111 @@ proc setinlist {var i val} {
     }
 }
 
+proc makediffhdr {fname ids} {
+    global ctext curdiffstart treediffs
+
+    set i [lsearch -exact $treediffs($ids) $fname]
+    if {$i >= 0} {
+       setinlist difffilestart $i $curdiffstart
+    }
+    set l [expr {(78 - [string length $fname]) / 2}]
+    set pad [string range "----------------------------------------" 1 $l]
+    $ctext insert $curdiffstart "$pad $fname $pad" filesep
+}
+
 proc getblobdiffline {bdf ids} {
-    global diffids blobdifffd ctext curdifftag curtagstart
+    global diffids blobdifffd ctext curdiffstart
     global diffnexthead diffnextnote difffilestart
-    global nextupdate diffinhdr treediffs
+    global diffinhdr treediffs
 
-    set n [gets $bdf line]
-    if {$n < 0} {
-       if {[eof $bdf]} {
-           close $bdf
-           if {$ids == $diffids && $bdf == $blobdifffd($ids)} {
-               $ctext tag add $curdifftag $curtagstart end
-           }
-       }
-       return
-    }
-    if {$ids != $diffids || $bdf != $blobdifffd($ids)} {
-       return
-    }
+    set nr 0
     $ctext conf -state normal
-    if {[regexp {^diff --git a/(.*) b/(.*)} $line match fname newname]} {
-       # start of a new file
-       $ctext insert end "\n"
-       $ctext tag add $curdifftag $curtagstart end
-       set here [$ctext index "end - 1c"]
-       set curtagstart $here
-       set header $newname
-       set i [lsearch -exact $treediffs($ids) $fname]
-       if {$i >= 0} {
-           setinlist difffilestart $i $here
+    while {[incr nr] <= 1000 && [gets $bdf line] >= 0} {
+       if {$ids != $diffids || $bdf != $blobdifffd($ids)} {
+           close $bdf
+           return 0
        }
-       if {$newname ne $fname} {
-           set i [lsearch -exact $treediffs($ids) $newname]
-           if {$i >= 0} {
-               setinlist difffilestart $i $here
+       if {![string compare -length 11 "diff --git " $line]} {
+           # trim off "diff --git "
+           set line [string range $line 11 end]
+           set diffinhdr 1
+           # start of a new file
+           $ctext insert end "\n"
+           set curdiffstart [$ctext index "end - 1c"]
+           $ctext insert end "\n" filesep
+           # If the name hasn't changed the length will be odd,
+           # the middle char will be a space, and the two bits either
+           # side will be a/name and b/name, or "a/name" and "b/name".
+           # If the name has changed we'll get "rename from" and
+           # "rename to" lines following this, and we'll use them
+           # to get the filenames.
+           # This complexity is necessary because spaces in the filename(s)
+           # don't get escaped.
+           set l [string length $line]
+           set i [expr {$l / 2}]
+           if {!(($l & 1) && [string index $line $i] eq " " &&
+                 [string range $line 2 [expr {$i - 1}]] eq \
+                     [string range $line [expr {$i + 3}] end])} {
+               continue
+           }
+           # unescape if quoted and chop off the a/ from the front
+           if {[string index $line 0] eq "\""} {
+               set fname [string range [lindex $line 0] 2 end]
+           } else {
+               set fname [string range $line 2 [expr {$i - 1}]]
+           }
+           makediffhdr $fname $ids
+
+       } elseif {[regexp {^@@ -([0-9]+)(,[0-9]+)? \+([0-9]+)(,[0-9]+)? @@(.*)} \
+                      $line match f1l f1c f2l f2c rest]} {
+           $ctext insert end "$line\n" hunksep
+           set diffinhdr 0
+
+       } elseif {$diffinhdr} {
+           if {![string compare -length 12 "rename from " $line]} {
+               set fname [string range $line 12 end]
+               if {[string index $fname 0] eq "\""} {
+                   set fname [lindex $fname 0]
+               }
+               set i [lsearch -exact $treediffs($ids) $fname]
+               if {$i >= 0} {
+                   setinlist difffilestart $i $curdiffstart
+               }
+           } elseif {![string compare -length 10 $line "rename to "]} {
+               set fname [string range $line 10 end]
+               if {[string index $fname 0] eq "\""} {
+                   set fname [lindex $fname 0]
+               }
+               makediffhdr $fname $ids
+           } elseif {[string compare -length 3 $line "---"] == 0} {
+               # do nothing
+               continue
+           } elseif {[string compare -length 3 $line "+++"] == 0} {
+               set diffinhdr 0
+               continue
            }
-       }
-       set curdifftag "f:$fname"
-       $ctext tag delete $curdifftag
-       set l [expr {(78 - [string length $header]) / 2}]
-       set pad [string range "----------------------------------------" 1 $l]
-       $ctext insert end "$pad $header $pad\n" filesep
-       set diffinhdr 1
-    } elseif {$diffinhdr && [string compare -length 3 $line "---"] == 0} {
-       # do nothing
-    } elseif {$diffinhdr && [string compare -length 3 $line "+++"] == 0} {
-       set diffinhdr 0
-    } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
-                  $line match f1l f1c f2l f2c rest]} {
-       $ctext insert end "$line\n" hunksep
-       set diffinhdr 0
-    } else {
-       set x [string range $line 0 0]
-       if {$x == "-" || $x == "+"} {
-           set tag [expr {$x == "+"}]
-           $ctext insert end "$line\n" d$tag
-       } elseif {$x == " "} {
-           $ctext insert end "$line\n"
-       } elseif {$diffinhdr || $x == "\\"} {
-           # e.g. "\ No newline at end of file"
            $ctext insert end "$line\n" filesep
+
        } else {
-           # Something else we don't recognize
-           if {$curdifftag != "Comments"} {
-               $ctext insert end "\n"
-               $ctext tag add $curdifftag $curtagstart end
-               set curtagstart [$ctext index "end - 1c"]
-               set curdifftag Comments
+           set x [string range $line 0 0]
+           if {$x == "-" || $x == "+"} {
+               set tag [expr {$x == "+"}]
+               $ctext insert end "$line\n" d$tag
+           } elseif {$x == " "} {
+               $ctext insert end "$line\n"
+           } else {
+               # "\ No newline at end of file",
+               # or something else we don't recognize
+               $ctext insert end "$line\n" hunksep
            }
-           $ctext insert end "$line\n" filesep
        }
     }
     $ctext conf -state disabled
-    if {[clock clicks -milliseconds] >= $nextupdate} {
-       incr nextupdate 100
-       fileevent $bdf readable {}
-       update
-       fileevent $bdf readable "getblobdiffline $bdf {$ids}"
+    if {[eof $bdf]} {
+       close $bdf
+       return 0
     }
+    return [expr {$nr >= 1000? 2: 1}]
 }
 
 proc changediffdisp {} {
@@ -4690,13 +5154,15 @@ proc redisplay {} {
 }
 
 proc incrfont {inc} {
-    global mainfont textfont ctext canv phase
+    global mainfont textfont ctext canv phase cflist
+    global charspc tabstop
     global stopped entries
     unmarkmatches
     set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]]
     set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]]
     setcoords
-    $ctext conf -font $textfont
+    $ctext conf -font $textfont -tabs "[expr {$tabstop * $charspc}]"
+    $cflist conf -font $textfont
     $ctext tag conf filesep -font [concat $textfont bold]
     foreach e $entries {
        $e conf -font $mainfont
@@ -4954,18 +5420,25 @@ proc mstime {} {
 
 proc rowmenu {x y id} {
     global rowctxmenu commitrow selectedline rowmenuid curview
+    global nullid fakerowmenu mainhead
 
+    set rowmenuid $id
     if {![info exists selectedline]
        || $commitrow($curview,$id) eq $selectedline} {
        set state disabled
     } else {
        set state normal
     }
-    $rowctxmenu entryconfigure "Diff this*" -state $state
-    $rowctxmenu entryconfigure "Diff selected*" -state $state
-    $rowctxmenu entryconfigure "Make patch" -state $state
-    set rowmenuid $id
-    tk_popup $rowctxmenu $x $y
+    if {$id ne $nullid} {
+       set menu $rowctxmenu
+       $menu entryconfigure 7 -label "Reset $mainhead branch to here"
+    } else {
+       set menu $fakerowmenu
+    }
+    $menu entryconfigure "Diff this*" -state $state
+    $menu entryconfigure "Diff selected*" -state $state
+    $menu entryconfigure "Make patch" -state $state
+    tk_popup $menu $x $y
 }
 
 proc diffvssel {dirn} {
@@ -5005,7 +5478,6 @@ proc doseldiff {oldid newid} {
     $ctext insert end [lindex $commitinfo($newid) 0]
     $ctext insert end "\n"
     $ctext conf -state disabled
-    $ctext tag delete Comments
     $ctext tag remove found 1.0 end
     startdiff [list $oldid $newid]
 }
@@ -5076,12 +5548,20 @@ proc mkpatchrev {} {
 }
 
 proc mkpatchgo {} {
-    global patchtop
+    global patchtop nullid
 
     set oldid [$patchtop.fromsha1 get]
     set newid [$patchtop.tosha1 get]
     set fname [$patchtop.fname get]
-    if {[catch {exec git diff-tree -p $oldid $newid >$fname &} err]} {
+    if {$newid eq $nullid} {
+       set cmd [list git diff-index -p $oldid]
+    } elseif {$oldid eq $nullid} {
+       set cmd [list git diff-index -p -R $newid]
+    } else {
+       set cmd [list git diff-tree -p $oldid $newid]
+    }
+    lappend cmd >$fname &
+    if {[catch {eval exec $cmd} err]} {
        error_popup "Error creating patch: $err"
     }
     catch {destroy $patchtop}
@@ -5158,10 +5638,11 @@ proc domktag {} {
 
 proc redrawtags {id} {
     global canv linehtag commitrow idpos selectedline curview
-    global mainfont canvxmax
+    global mainfont canvxmax iddrawn
 
     if {![info exists commitrow($curview,$id)]} return
-    drawcmitrow $commitrow($curview,$id)
+    if {![info exists iddrawn($id)]} return
+    drawcommits $commitrow($curview,$id)
     $canv delete tag.$id
     set xt [eval drawtags $id $idpos($id)]
     $canv coords $linehtag($commitrow($curview,$id)) $xt [lindex $idpos($id) 2]
@@ -5288,26 +5769,28 @@ proc mkbrgo {top} {
        notbusy newbranch
        error_popup $err
     } else {
+       set headids($name) $id
+       lappend idheads($id) $name
        addedhead $id $name
-       # XXX should update list of heads displayed for selected commit
        notbusy newbranch
        redrawtags $id
+       dispneartags 0
     }
 }
 
 proc cherrypick {} {
     global rowmenuid curview commitrow
-    global mainhead desc_heads anc_tags desc_tags allparents allchildren
+    global mainhead
 
-    if {[info exists desc_heads($rowmenuid)]
-       && [lsearch -exact $desc_heads($rowmenuid) $mainhead] >= 0} {
+    set oldhead [exec git rev-parse HEAD]
+    set dheads [descheads $rowmenuid]
+    if {$dheads ne {} && [lsearch -exact $dheads $oldhead] >= 0} {
        set ok [confirm_popup "Commit [string range $rowmenuid 0 7] is already\
                        included in branch $mainhead -- really re-apply it?"]
        if {!$ok} return
     }
     nowbusy cherrypick
     update
-    set oldhead [exec git rev-parse HEAD]
     # Unfortunately git-cherry-pick writes stuff to stderr even when
     # no error occurs, and exec takes that as an indication of error...
     if {[catch {exec sh -c "git cherry-pick -r $rowmenuid 2>&1"} err]} {
@@ -5321,16 +5804,11 @@ proc cherrypick {} {
        error_popup "No changes committed"
        return
     }
-    set allparents($newhead) $oldhead
-    lappend allchildren($oldhead) $newhead
-    set desc_heads($newhead) $mainhead
-    if {[info exists anc_tags($oldhead)]} {
-       set anc_tags($newhead) $anc_tags($oldhead)
-    }
-    set desc_tags($newhead) {}
+    addnewchild $newhead $oldhead
     if {[info exists commitrow($curview,$oldhead)]} {
        insertrow $commitrow($curview,$oldhead) $newhead
        if {$mainhead ne {}} {
+           movehead $newhead $mainhead
            movedhead $newhead $mainhead
        }
        redrawtags $oldhead
@@ -5339,48 +5817,146 @@ proc cherrypick {} {
     notbusy cherrypick
 }
 
+proc resethead {} {
+    global mainheadid mainhead rowmenuid confirm_ok resettype
+    global showlocalchanges
+
+    set confirm_ok 0
+    set w ".confirmreset"
+    toplevel $w
+    wm transient $w .
+    wm title $w "Confirm reset"
+    message $w.m -text \
+       "Reset branch $mainhead to [string range $rowmenuid 0 7]?" \
+       -justify center -aspect 1000
+    pack $w.m -side top -fill x -padx 20 -pady 20
+    frame $w.f -relief sunken -border 2
+    message $w.f.rt -text "Reset type:" -aspect 1000
+    grid $w.f.rt -sticky w
+    set resettype mixed
+    radiobutton $w.f.soft -value soft -variable resettype -justify left \
+       -text "Soft: Leave working tree and index untouched"
+    grid $w.f.soft -sticky w
+    radiobutton $w.f.mixed -value mixed -variable resettype -justify left \
+       -text "Mixed: Leave working tree untouched, reset index"
+    grid $w.f.mixed -sticky w
+    radiobutton $w.f.hard -value hard -variable resettype -justify left \
+       -text "Hard: Reset working tree and index\n(discard ALL local changes)"
+    grid $w.f.hard -sticky w
+    pack $w.f -side top -fill x
+    button $w.ok -text OK -command "set confirm_ok 1; destroy $w"
+    pack $w.ok -side left -fill x -padx 20 -pady 20
+    button $w.cancel -text Cancel -command "destroy $w"
+    pack $w.cancel -side right -fill x -padx 20 -pady 20
+    bind $w <Visibility> "grab $w; focus $w"
+    tkwait window $w
+    if {!$confirm_ok} return
+    if {[catch {set fd [open \
+           [list | sh -c "git reset --$resettype $rowmenuid 2>&1"] r]} err]} {
+       error_popup $err
+    } else {
+       dohidelocalchanges
+       set w ".resetprogress"
+       filerun $fd [list readresetstat $fd $w]
+       toplevel $w
+       wm transient $w
+       wm title $w "Reset progress"
+       message $w.m -text "Reset in progress, please wait..." \
+           -justify center -aspect 1000
+       pack $w.m -side top -fill x -padx 20 -pady 5
+       canvas $w.c -width 150 -height 20 -bg white
+       $w.c create rect 0 0 0 20 -fill green -tags rect
+       pack $w.c -side top -fill x -padx 20 -pady 5 -expand 1
+       nowbusy reset
+    }
+}
+
+proc readresetstat {fd w} {
+    global mainhead mainheadid showlocalchanges
+
+    if {[gets $fd line] >= 0} {
+       if {[regexp {([0-9]+)% \(([0-9]+)/([0-9]+)\)} $line match p m n]} {
+           set x [expr {($m * 150) / $n}]
+           $w.c coords rect 0 0 $x 20
+       }
+       return 1
+    }
+    destroy $w
+    notbusy reset
+    if {[catch {close $fd} err]} {
+       error_popup $err
+    }
+    set oldhead $mainheadid
+    set newhead [exec git rev-parse HEAD]
+    if {$newhead ne $oldhead} {
+       movehead $newhead $mainhead
+       movedhead $newhead $mainhead
+       set mainheadid $newhead
+       redrawtags $oldhead
+       redrawtags $newhead
+    }
+    if {$showlocalchanges} {
+       doshowlocalchanges
+    }
+    return 0
+}
+
 # context menu for a head
 proc headmenu {x y id head} {
-    global headmenuid headmenuhead headctxmenu
+    global headmenuid headmenuhead headctxmenu mainhead
 
     set headmenuid $id
     set headmenuhead $head
+    set state normal
+    if {$head eq $mainhead} {
+       set state disabled
+    }
+    $headctxmenu entryconfigure 0 -state $state
+    $headctxmenu entryconfigure 1 -state $state
     tk_popup $headctxmenu $x $y
 }
 
 proc cobranch {} {
     global headmenuid headmenuhead mainhead headids
+    global showlocalchanges mainheadid
 
     # check the tree is clean first??
     set oldmainhead $mainhead
     nowbusy checkout
     update
+    dohidelocalchanges
     if {[catch {
-       exec git checkout $headmenuhead
+       exec git checkout -q $headmenuhead
     } err]} {
        notbusy checkout
        error_popup $err
     } else {
        notbusy checkout
        set mainhead $headmenuhead
+       set mainheadid $headmenuid
        if {[info exists headids($oldmainhead)]} {
            redrawtags $headids($oldmainhead)
        }
        redrawtags $headmenuid
     }
+    if {$showlocalchanges} {
+       dodiffindex
+    }
 }
 
 proc rmbranch {} {
-    global desc_heads headmenuid headmenuhead mainhead
+    global headmenuid headmenuhead mainhead
     global headids idheads
 
     set head $headmenuhead
     set id $headmenuid
+    # this check shouldn't be needed any more...
     if {$head eq $mainhead} {
        error_popup "Cannot delete the currently checked-out branch"
        return
     }
-    if {$desc_heads($id) eq $head} {
+    set dheads [descheads $id]
+    if {$dheads eq $headids($head)} {
        # the stuff on this branch isn't on any other branch
        if {![confirm_popup "The commits on branch $head aren't on any other\
                        branch.\nReally delete branch $head?"]} return
@@ -5392,385 +5968,886 @@ proc rmbranch {} {
        error_popup $err
        return
     }
+    removehead $id $head
     removedhead $id $head
     redrawtags $id
     notbusy rmbranch
+    dispneartags 0
 }
 
 # Stuff for finding nearby tags
 proc getallcommits {} {
-    global allcstart allcommits allcfd allids
+    global allcommits allids nbmp nextarc seeds
 
     set allids {}
-    set fd [open [concat | git rev-list --all --topo-order --parents] r]
-    set allcfd $fd
-    fconfigure $fd -blocking 0
-    set allcommits "reading"
-    nowbusy allcommits
-    restartgetall $fd
+    set nbmp 0
+    set nextarc 0
+    set allcommits 0
+    set seeds {}
+    regetallcommits
 }
 
-proc discardallcommits {} {
-    global allparents allchildren allcommits allcfd
-    global desc_tags anc_tags alldtags tagisdesc allids desc_heads
+# Called when the graph might have changed
+proc regetallcommits {} {
+    global allcommits seeds
 
-    if {![info exists allcommits]} return
-    if {$allcommits eq "reading"} {
-       catch {close $allcfd}
-    }
-    foreach v {allcommits allchildren allparents allids desc_tags anc_tags
-               alldtags tagisdesc desc_heads} {
-       catch {unset $v}
+    set cmd [concat | git rev-list --all --parents]
+    foreach id $seeds {
+       lappend cmd "^$id"
     }
-}
-
-proc restartgetall {fd} {
-    global allcstart
+    set fd [open $cmd r]
+    fconfigure $fd -blocking 0
+    incr allcommits
+    nowbusy allcommits
+    filerun $fd [list getallclines $fd]
+}
+
+# Since most commits have 1 parent and 1 child, we group strings of
+# such commits into "arcs" joining branch/merge points (BMPs), which
+# are commits that either don't have 1 parent or don't have 1 child.
+#
+# arcnos(id) - incoming arcs for BMP, arc we're on for other nodes
+# arcout(id) - outgoing arcs for BMP
+# arcids(a) - list of IDs on arc including end but not start
+# arcstart(a) - BMP ID at start of arc
+# arcend(a) - BMP ID at end of arc
+# growing(a) - arc a is still growing
+# arctags(a) - IDs out of arcids (excluding end) that have tags
+# archeads(a) - IDs out of arcids (excluding end) that have heads
+# The start of an arc is at the descendent end, so "incoming" means
+# coming from descendents, and "outgoing" means going towards ancestors.
 
-    fileevent $fd readable [list getallclines $fd]
-    set allcstart [clock clicks -milliseconds]
-}
+proc getallclines {fd} {
+    global allids allparents allchildren idtags idheads nextarc nbmp
+    global arcnos arcids arctags arcout arcend arcstart archeads growing
+    global seeds allcommits
 
-proc combine_dtags {l1 l2} {
-    global tagisdesc notfirstd
+    set nid 0
+    while {[incr nid] <= 1000 && [gets $fd line] >= 0} {
+       set id [lindex $line 0]
+       if {[info exists allparents($id)]} {
+           # seen it already
+           continue
+       }
+       lappend allids $id
+       set olds [lrange $line 1 end]
+       set allparents($id) $olds
+       if {![info exists allchildren($id)]} {
+           set allchildren($id) {}
+           set arcnos($id) {}
+           lappend seeds $id
+       } else {
+           set a $arcnos($id)
+           if {[llength $olds] == 1 && [llength $a] == 1} {
+               lappend arcids($a) $id
+               if {[info exists idtags($id)]} {
+                   lappend arctags($a) $id
+               }
+               if {[info exists idheads($id)]} {
+                   lappend archeads($a) $id
+               }
+               if {[info exists allparents($olds)]} {
+                   # seen parent already
+                   if {![info exists arcout($olds)]} {
+                       splitarc $olds
+                   }
+                   lappend arcids($a) $olds
+                   set arcend($a) $olds
+                   unset growing($a)
+               }
+               lappend allchildren($olds) $id
+               lappend arcnos($olds) $a
+               continue
+           }
+       }
+       incr nbmp
+       foreach a $arcnos($id) {
+           lappend arcids($a) $id
+           set arcend($a) $id
+           unset growing($a)
+       }
 
-    set res [lsort -unique [concat $l1 $l2]]
-    for {set i 0} {$i < [llength $res]} {incr i} {
-       set x [lindex $res $i]
-       for {set j [expr {$i+1}]} {$j < [llength $res]} {} {
-           set y [lindex $res $j]
-           if {[info exists tagisdesc($x,$y)]} {
-               if {$tagisdesc($x,$y) > 0} {
-                   # x is a descendent of y, exclude x
-                   set res [lreplace $res $i $i]
-                   incr i -1
-                   break
-               } else {
-                   # y is a descendent of x, exclude y
-                   set res [lreplace $res $j $j]
+       set ao {}
+       foreach p $olds {
+           lappend allchildren($p) $id
+           set a [incr nextarc]
+           set arcstart($a) $id
+           set archeads($a) {}
+           set arctags($a) {}
+           set archeads($a) {}
+           set arcids($a) {}
+           lappend ao $a
+           set growing($a) 1
+           if {[info exists allparents($p)]} {
+               # seen it already, may need to make a new branch
+               if {![info exists arcout($p)]} {
+                   splitarc $p
                }
-           } else {
-               # no relation, keep going
-               incr j
+               lappend arcids($a) $p
+               set arcend($a) $p
+               unset growing($a)
            }
+           lappend arcnos($p) $a
        }
+       set arcout($id) $ao
     }
-    return $res
+    if {$nid > 0} {
+       global cached_dheads cached_dtags cached_atags
+       catch {unset cached_dheads}
+       catch {unset cached_dtags}
+       catch {unset cached_atags}
+    }
+    if {![eof $fd]} {
+       return [expr {$nid >= 1000? 2: 1}]
+    }
+    close $fd
+    if {[incr allcommits -1] == 0} {
+       notbusy allcommits
+    }
+    dispneartags 0
+    return 0
 }
 
-proc combine_atags {l1 l2} {
-    global tagisdesc
+proc recalcarc {a} {
+    global arctags archeads arcids idtags idheads
 
-    set res [lsort -unique [concat $l1 $l2]]
-    for {set i 0} {$i < [llength $res]} {incr i} {
-       set x [lindex $res $i]
-       for {set j [expr {$i+1}]} {$j < [llength $res]} {} {
-           set y [lindex $res $j]
-           if {[info exists tagisdesc($x,$y)]} {
-               if {$tagisdesc($x,$y) < 0} {
-                   # x is an ancestor of y, exclude x
-                   set res [lreplace $res $i $i]
-                   incr i -1
-                   break
-               } else {
-                   # y is an ancestor of x, exclude y
-                   set res [lreplace $res $j $j]
-               }
-           } else {
-               # no relation, keep going
-               incr j
-           }
+    set at {}
+    set ah {}
+    foreach id [lrange $arcids($a) 0 end-1] {
+       if {[info exists idtags($id)]} {
+           lappend at $id
+       }
+       if {[info exists idheads($id)]} {
+           lappend ah $id
        }
     }
-    return $res
+    set arctags($a) $at
+    set archeads($a) $ah
 }
 
-proc forward_pass {id children} {
-    global idtags desc_tags idheads desc_heads alldtags tagisdesc
+proc splitarc {p} {
+    global arcnos arcids nextarc nbmp arctags archeads idtags idheads
+    global arcstart arcend arcout allparents growing
 
-    set dtags {}
-    set dheads {}
-    foreach child $children {
-       if {[info exists idtags($child)]} {
-           set ctags [list $child]
+    set a $arcnos($p)
+    if {[llength $a] != 1} {
+       puts "oops splitarc called but [llength $a] arcs already"
+       return
+    }
+    set a [lindex $a 0]
+    set i [lsearch -exact $arcids($a) $p]
+    if {$i < 0} {
+       puts "oops splitarc $p not in arc $a"
+       return
+    }
+    set na [incr nextarc]
+    if {[info exists arcend($a)]} {
+       set arcend($na) $arcend($a)
+    } else {
+       set l [lindex $allparents([lindex $arcids($a) end]) 0]
+       set j [lsearch -exact $arcnos($l) $a]
+       set arcnos($l) [lreplace $arcnos($l) $j $j $na]
+    }
+    set tail [lrange $arcids($a) [expr {$i+1}] end]
+    set arcids($a) [lrange $arcids($a) 0 $i]
+    set arcend($a) $p
+    set arcstart($na) $p
+    set arcout($p) $na
+    set arcids($na) $tail
+    if {[info exists growing($a)]} {
+       set growing($na) 1
+       unset growing($a)
+    }
+    incr nbmp
+
+    foreach id $tail {
+       if {[llength $arcnos($id)] == 1} {
+           set arcnos($id) $na
        } else {
-           set ctags $desc_tags($child)
+           set j [lsearch -exact $arcnos($id) $a]
+           set arcnos($id) [lreplace $arcnos($id) $j $j $na]
        }
-       if {$dtags eq {}} {
-           set dtags $ctags
-       } elseif {$ctags ne $dtags} {
-           set dtags [combine_dtags $dtags $ctags]
+    }
+
+    # reconstruct tags and heads lists
+    if {$arctags($a) ne {} || $archeads($a) ne {}} {
+       recalcarc $a
+       recalcarc $na
+    } else {
+       set arctags($na) {}
+       set archeads($na) {}
+    }
+}
+
+# Update things for a new commit added that is a child of one
+# existing commit.  Used when cherry-picking.
+proc addnewchild {id p} {
+    global allids allparents allchildren idtags nextarc nbmp
+    global arcnos arcids arctags arcout arcend arcstart archeads growing
+    global seeds
+
+    lappend allids $id
+    set allparents($id) [list $p]
+    set allchildren($id) {}
+    set arcnos($id) {}
+    lappend seeds $id
+    incr nbmp
+    lappend allchildren($p) $id
+    set a [incr nextarc]
+    set arcstart($a) $id
+    set archeads($a) {}
+    set arctags($a) {}
+    set arcids($a) [list $p]
+    set arcend($a) $p
+    if {![info exists arcout($p)]} {
+       splitarc $p
+    }
+    lappend arcnos($p) $a
+    set arcout($id) [list $a]
+}
+
+# Returns 1 if a is an ancestor of b, -1 if b is an ancestor of a,
+# or 0 if neither is true.
+proc anc_or_desc {a b} {
+    global arcout arcstart arcend arcnos cached_isanc
+
+    if {$arcnos($a) eq $arcnos($b)} {
+       # Both are on the same arc(s); either both are the same BMP,
+       # or if one is not a BMP, the other is also not a BMP or is
+       # the BMP at end of the arc (and it only has 1 incoming arc).
+       if {$a eq $b} {
+           return 0
        }
-       set cheads $desc_heads($child)
-       if {$dheads eq {}} {
-           set dheads $cheads
-       } elseif {$cheads ne $dheads} {
-           set dheads [lsort -unique [concat $dheads $cheads]]
+       # assert {[llength $arcnos($a)] == 1}
+       set arc [lindex $arcnos($a) 0]
+       set i [lsearch -exact $arcids($arc) $a]
+       set j [lsearch -exact $arcids($arc) $b]
+       if {$i < 0 || $i > $j} {
+           return 1
+       } else {
+           return -1
        }
     }
-    set desc_tags($id) $dtags
-    if {[info exists idtags($id)]} {
-       set adt $dtags
-       foreach tag $dtags {
-           set adt [concat $adt $alldtags($tag)]
+
+    if {![info exists arcout($a)]} {
+       set arc [lindex $arcnos($a) 0]
+       if {[info exists arcend($arc)]} {
+           set aend $arcend($arc)
+       } else {
+           set aend {}
        }
-       set adt [lsort -unique $adt]
-       set alldtags($id) $adt
-       foreach tag $adt {
-           set tagisdesc($id,$tag) -1
-           set tagisdesc($tag,$id) 1
+       set a $arcstart($arc)
+    } else {
+       set aend $a
+    }
+    if {![info exists arcout($b)]} {
+       set arc [lindex $arcnos($b) 0]
+       if {[info exists arcend($arc)]} {
+           set bend $arcend($arc)
+       } else {
+           set bend {}
        }
+       set b $arcstart($arc)
+    } else {
+       set bend $b
     }
-    if {[info exists idheads($id)]} {
-       set dheads [concat $dheads $idheads($id)]
+    if {$a eq $bend} {
+       return 1
+    }
+    if {$b eq $aend} {
+       return -1
+    }
+    if {[info exists cached_isanc($a,$bend)]} {
+       if {$cached_isanc($a,$bend)} {
+           return 1
+       }
+    }
+    if {[info exists cached_isanc($b,$aend)]} {
+       if {$cached_isanc($b,$aend)} {
+           return -1
+       }
+       if {[info exists cached_isanc($a,$bend)]} {
+           return 0
+       }
     }
-    set desc_heads($id) $dheads
-}
 
-proc getallclines {fd} {
-    global allparents allchildren allcommits allcstart
-    global desc_tags anc_tags idtags tagisdesc allids
-    global idheads travindex
+    set todo [list $a $b]
+    set anc($a) a
+    set anc($b) b
+    for {set i 0} {$i < [llength $todo]} {incr i} {
+       set x [lindex $todo $i]
+       if {$anc($x) eq {}} {
+           continue
+       }
+       foreach arc $arcnos($x) {
+           set xd $arcstart($arc)
+           if {$xd eq $bend} {
+               set cached_isanc($a,$bend) 1
+               set cached_isanc($b,$aend) 0
+               return 1
+           } elseif {$xd eq $aend} {
+               set cached_isanc($b,$aend) 1
+               set cached_isanc($a,$bend) 0
+               return -1
+           }
+           if {![info exists anc($xd)]} {
+               set anc($xd) $anc($x)
+               lappend todo $xd
+           } elseif {$anc($xd) ne $anc($x)} {
+               set anc($xd) {}
+           }
+       }
+    }
+    set cached_isanc($a,$bend) 0
+    set cached_isanc($b,$aend) 0
+    return 0
+}
 
-    while {[gets $fd line] >= 0} {
-       set id [lindex $line 0]
-       lappend allids $id
-       set olds [lrange $line 1 end]
-       set allparents($id) $olds
-       if {![info exists allchildren($id)]} {
-           set allchildren($id) {}
+# This identifies whether $desc has an ancestor that is
+# a growing tip of the graph and which is not an ancestor of $anc
+# and returns 0 if so and 1 if not.
+# If we subsequently discover a tag on such a growing tip, and that
+# turns out to be a descendent of $anc (which it could, since we
+# don't necessarily see children before parents), then $desc
+# isn't a good choice to display as a descendent tag of
+# $anc (since it is the descendent of another tag which is
+# a descendent of $anc).  Similarly, $anc isn't a good choice to
+# display as a ancestor tag of $desc.
+#
+proc is_certain {desc anc} {
+    global arcnos arcout arcstart arcend growing problems
+
+    set certain {}
+    if {[llength $arcnos($anc)] == 1} {
+       # tags on the same arc are certain
+       if {$arcnos($desc) eq $arcnos($anc)} {
+           return 1
        }
-       foreach p $olds {
-           lappend allchildren($p) $id
+       if {![info exists arcout($anc)]} {
+           # if $anc is partway along an arc, use the start of the arc instead
+           set a [lindex $arcnos($anc) 0]
+           set anc $arcstart($a)
        }
-       # compute nearest tagged descendents as we go
-       # also compute descendent heads
-       forward_pass $id $allchildren($id)
-       if {[clock clicks -milliseconds] - $allcstart >= 50} {
-           fileevent $fd readable {}
-           after idle restartgetall $fd
-           return
+    }
+    if {[llength $arcnos($desc)] > 1 || [info exists arcout($desc)]} {
+       set x $desc
+    } else {
+       set a [lindex $arcnos($desc) 0]
+       set x $arcend($a)
+    }
+    if {$x == $anc} {
+       return 1
+    }
+    set anclist [list $x]
+    set dl($x) 1
+    set nnh 1
+    set ngrowanc 0
+    for {set i 0} {$i < [llength $anclist] && ($nnh > 0 || $ngrowanc > 0)} {incr i} {
+       set x [lindex $anclist $i]
+       if {$dl($x)} {
+           incr nnh -1
+       }
+       set done($x) 1
+       foreach a $arcout($x) {
+           if {[info exists growing($a)]} {
+               if {![info exists growanc($x)] && $dl($x)} {
+                   set growanc($x) 1
+                   incr ngrowanc
+               }
+           } else {
+               set y $arcend($a)
+               if {[info exists dl($y)]} {
+                   if {$dl($y)} {
+                       if {!$dl($x)} {
+                           set dl($y) 0
+                           if {![info exists done($y)]} {
+                               incr nnh -1
+                           }
+                           if {[info exists growanc($x)]} {
+                               incr ngrowanc -1
+                           }
+                           set xl [list $y]
+                           for {set k 0} {$k < [llength $xl]} {incr k} {
+                               set z [lindex $xl $k]
+                               foreach c $arcout($z) {
+                                   if {[info exists arcend($c)]} {
+                                       set v $arcend($c)
+                                       if {[info exists dl($v)] && $dl($v)} {
+                                           set dl($v) 0
+                                           if {![info exists done($v)]} {
+                                               incr nnh -1
+                                           }
+                                           if {[info exists growanc($v)]} {
+                                               incr ngrowanc -1
+                                           }
+                                           lappend xl $v
+                                       }
+                                   }
+                               }
+                           }
+                       }
+                   }
+               } elseif {$y eq $anc || !$dl($x)} {
+                   set dl($y) 0
+                   lappend anclist $y
+               } else {
+                   set dl($y) 1
+                   lappend anclist $y
+                   incr nnh
+               }
+           }
        }
     }
-    if {[eof $fd]} {
-       set travindex [llength $allids]
-       set allcommits "traversing"
-       after idle restartatags
-       if {[catch {close $fd} err]} {
-           error_popup "Error reading full commit graph: $err.\n\
-                        Results may be incomplete."
+    foreach x [array names growanc] {
+       if {$dl($x)} {
+           return 0
        }
+       return 0
     }
+    return 1
 }
 
-# walk backward through the tree and compute nearest tagged ancestors
-proc restartatags {} {
-    global allids allparents idtags anc_tags travindex
+proc validate_arctags {a} {
+    global arctags idtags
 
-    set t0 [clock clicks -milliseconds]
-    set i $travindex
-    while {[incr i -1] >= 0} {
-       set id [lindex $allids $i]
-       set atags {}
-       foreach p $allparents($id) {
-           if {[info exists idtags($p)]} {
-               set ptags [list $p]
-           } else {
-               set ptags $anc_tags($p)
+    set i -1
+    set na $arctags($a)
+    foreach id $arctags($a) {
+       incr i
+       if {![info exists idtags($id)]} {
+           set na [lreplace $na $i $i]
+           incr i -1
+       }
+    }
+    set arctags($a) $na
+}
+
+proc validate_archeads {a} {
+    global archeads idheads
+
+    set i -1
+    set na $archeads($a)
+    foreach id $archeads($a) {
+       incr i
+       if {![info exists idheads($id)]} {
+           set na [lreplace $na $i $i]
+           incr i -1
+       }
+    }
+    set archeads($a) $na
+}
+
+# Return the list of IDs that have tags that are descendents of id,
+# ignoring IDs that are descendents of IDs already reported.
+proc desctags {id} {
+    global arcnos arcstart arcids arctags idtags allparents
+    global growing cached_dtags
+
+    if {![info exists allparents($id)]} {
+       return {}
+    }
+    set t1 [clock clicks -milliseconds]
+    set argid $id
+    if {[llength $arcnos($id)] == 1 && [llength $allparents($id)] == 1} {
+       # part-way along an arc; check that arc first
+       set a [lindex $arcnos($id) 0]
+       if {$arctags($a) ne {}} {
+           validate_arctags $a
+           set i [lsearch -exact $arcids($a) $id]
+           set tid {}
+           foreach t $arctags($a) {
+               set j [lsearch -exact $arcids($a) $t]
+               if {$j >= $i} break
+               set tid $t
            }
-           if {$atags eq {}} {
-               set atags $ptags
-           } elseif {$ptags ne $atags} {
-               set atags [combine_atags $atags $ptags]
+           if {$tid ne {}} {
+               return $tid
            }
        }
-       set anc_tags($id) $atags
-       if {[clock clicks -milliseconds] - $t0 >= 50} {
-           set travindex $i
-           after idle restartatags
-           return
+       set id $arcstart($a)
+       if {[info exists idtags($id)]} {
+           return $id
+       }
+    }
+    if {[info exists cached_dtags($id)]} {
+       return $cached_dtags($id)
+    }
+
+    set origid $id
+    set todo [list $id]
+    set queued($id) 1
+    set nc 1
+    for {set i 0} {$i < [llength $todo] && $nc > 0} {incr i} {
+       set id [lindex $todo $i]
+       set done($id) 1
+       set ta [info exists hastaggedancestor($id)]
+       if {!$ta} {
+           incr nc -1
+       }
+       # ignore tags on starting node
+       if {!$ta && $i > 0} {
+           if {[info exists idtags($id)]} {
+               set tagloc($id) $id
+               set ta 1
+           } elseif {[info exists cached_dtags($id)]} {
+               set tagloc($id) $cached_dtags($id)
+               set ta 1
+           }
+       }
+       foreach a $arcnos($id) {
+           set d $arcstart($a)
+           if {!$ta && $arctags($a) ne {}} {
+               validate_arctags $a
+               if {$arctags($a) ne {}} {
+                   lappend tagloc($id) [lindex $arctags($a) end]
+               }
+           }
+           if {$ta || $arctags($a) ne {}} {
+               set tomark [list $d]
+               for {set j 0} {$j < [llength $tomark]} {incr j} {
+                   set dd [lindex $tomark $j]
+                   if {![info exists hastaggedancestor($dd)]} {
+                       if {[info exists done($dd)]} {
+                           foreach b $arcnos($dd) {
+                               lappend tomark $arcstart($b)
+                           }
+                           if {[info exists tagloc($dd)]} {
+                               unset tagloc($dd)
+                           }
+                       } elseif {[info exists queued($dd)]} {
+                           incr nc -1
+                       }
+                       set hastaggedancestor($dd) 1
+                   }
+               }
+           }
+           if {![info exists queued($d)]} {
+               lappend todo $d
+               set queued($d) 1
+               if {![info exists hastaggedancestor($d)]} {
+                   incr nc
+               }
+           }
        }
     }
-    set allcommits "done"
-    set travindex 0
-    notbusy allcommits
-    dispneartags
-}
-
-# update the desc_tags and anc_tags arrays for a new tag just added
-proc addedtag {id} {
-    global desc_tags anc_tags allparents allchildren allcommits
-    global idtags tagisdesc alldtags
-
-    if {![info exists desc_tags($id)]} return
-    set adt $desc_tags($id)
-    foreach t $desc_tags($id) {
-       set adt [concat $adt $alldtags($t)]
-    }
-    set adt [lsort -unique $adt]
-    set alldtags($id) $adt
-    foreach t $adt {
-       set tagisdesc($id,$t) -1
-       set tagisdesc($t,$id) 1
-    }
-    if {[info exists anc_tags($id)]} {
-       set todo $anc_tags($id)
-       while {$todo ne {}} {
-           set do [lindex $todo 0]
-           set todo [lrange $todo 1 end]
-           if {[info exists tagisdesc($id,$do)]} continue
-           set tagisdesc($do,$id) -1
-           set tagisdesc($id,$do) 1
-           if {[info exists anc_tags($do)]} {
-               set todo [concat $todo $anc_tags($do)]
+    set tags {}
+    foreach id [array names tagloc] {
+       if {![info exists hastaggedancestor($id)]} {
+           foreach t $tagloc($id) {
+               if {[lsearch -exact $tags $t] < 0} {
+                   lappend tags $t
+               }
            }
        }
     }
+    set t2 [clock clicks -milliseconds]
+    set loopix $i
 
-    set lastold $desc_tags($id)
-    set lastnew [list $id]
-    set nup 0
-    set nch 0
-    set todo $allparents($id)
-    while {$todo ne {}} {
-       set do [lindex $todo 0]
-       set todo [lrange $todo 1 end]
-       if {![info exists desc_tags($do)]} continue
-       if {$desc_tags($do) ne $lastold} {
-           set lastold $desc_tags($do)
-           set lastnew [combine_dtags $lastold [list $id]]
-           incr nch
-       }
-       if {$lastold eq $lastnew} continue
-       set desc_tags($do) $lastnew
-       incr nup
-       if {![info exists idtags($do)]} {
-           set todo [concat $todo $allparents($do)]
+    # remove tags that are descendents of other tags
+    for {set i 0} {$i < [llength $tags]} {incr i} {
+       set a [lindex $tags $i]
+       for {set j 0} {$j < $i} {incr j} {
+           set b [lindex $tags $j]
+           set r [anc_or_desc $a $b]
+           if {$r == 1} {
+               set tags [lreplace $tags $j $j]
+               incr j -1
+               incr i -1
+           } elseif {$r == -1} {
+               set tags [lreplace $tags $i $i]
+               incr i -1
+               break
+           }
        }
     }
 
-    if {![info exists anc_tags($id)]} return
-    set lastold $anc_tags($id)
-    set lastnew [list $id]
-    set nup 0
-    set nch 0
-    set todo $allchildren($id)
-    while {$todo ne {}} {
-       set do [lindex $todo 0]
-       set todo [lrange $todo 1 end]
-       if {![info exists anc_tags($do)]} continue
-       if {$anc_tags($do) ne $lastold} {
-           set lastold $anc_tags($do)
-           set lastnew [combine_atags $lastold [list $id]]
-           incr nch
+    if {[array names growing] ne {}} {
+       # graph isn't finished, need to check if any tag could get
+       # eclipsed by another tag coming later.  Simply ignore any
+       # tags that could later get eclipsed.
+       set ctags {}
+       foreach t $tags {
+           if {[is_certain $t $origid]} {
+               lappend ctags $t
+           }
        }
-       if {$lastold eq $lastnew} continue
-       set anc_tags($do) $lastnew
-       incr nup
-       if {![info exists idtags($do)]} {
-           set todo [concat $todo $allchildren($do)]
+       if {$tags eq $ctags} {
+           set cached_dtags($origid) $tags
+       } else {
+           set tags $ctags
        }
+    } else {
+       set cached_dtags($origid) $tags
+    }
+    set t3 [clock clicks -milliseconds]
+    if {0 && $t3 - $t1 >= 100} {
+       puts "iterating descendents ($loopix/[llength $todo] nodes) took\
+           [expr {$t2-$t1}]+[expr {$t3-$t2}]ms, $nc candidates left"
     }
+    return $tags
 }
 
-# update the desc_heads array for a new head just added
-proc addedhead {hid head} {
-    global desc_heads allparents headids idheads
-
-    set headids($head) $hid
-    lappend idheads($hid) $head
-
-    set todo [list $hid]
-    while {$todo ne {}} {
-       set do [lindex $todo 0]
-       set todo [lrange $todo 1 end]
-       if {![info exists desc_heads($do)] ||
-           [lsearch -exact $desc_heads($do) $head] >= 0} continue
-       set oldheads $desc_heads($do)
-       lappend desc_heads($do) $head
-       set heads $desc_heads($do)
-       while {1} {
-           set p $allparents($do)
-           if {[llength $p] != 1 || ![info exists desc_heads($p)] ||
-               $desc_heads($p) ne $oldheads} break
-           set do $p
-           set desc_heads($do) $heads
+proc anctags {id} {
+    global arcnos arcids arcout arcend arctags idtags allparents
+    global growing cached_atags
+
+    if {![info exists allparents($id)]} {
+       return {}
+    }
+    set t1 [clock clicks -milliseconds]
+    set argid $id
+    if {[llength $arcnos($id)] == 1 && [llength $allparents($id)] == 1} {
+       # part-way along an arc; check that arc first
+       set a [lindex $arcnos($id) 0]
+       if {$arctags($a) ne {}} {
+           validate_arctags $a
+           set i [lsearch -exact $arcids($a) $id]
+           foreach t $arctags($a) {
+               set j [lsearch -exact $arcids($a) $t]
+               if {$j > $i} {
+                   return $t
+               }
+           }
+       }
+       if {![info exists arcend($a)]} {
+           return {}
+       }
+       set id $arcend($a)
+       if {[info exists idtags($id)]} {
+           return $id
+       }
+    }
+    if {[info exists cached_atags($id)]} {
+       return $cached_atags($id)
+    }
+
+    set origid $id
+    set todo [list $id]
+    set queued($id) 1
+    set taglist {}
+    set nc 1
+    for {set i 0} {$i < [llength $todo] && $nc > 0} {incr i} {
+       set id [lindex $todo $i]
+       set done($id) 1
+       set td [info exists hastaggeddescendent($id)]
+       if {!$td} {
+           incr nc -1
+       }
+       # ignore tags on starting node
+       if {!$td && $i > 0} {
+           if {[info exists idtags($id)]} {
+               set tagloc($id) $id
+               set td 1
+           } elseif {[info exists cached_atags($id)]} {
+               set tagloc($id) $cached_atags($id)
+               set td 1
+           }
+       }
+       foreach a $arcout($id) {
+           if {!$td && $arctags($a) ne {}} {
+               validate_arctags $a
+               if {$arctags($a) ne {}} {
+                   lappend tagloc($id) [lindex $arctags($a) 0]
+               }
+           }
+           if {![info exists arcend($a)]} continue
+           set d $arcend($a)
+           if {$td || $arctags($a) ne {}} {
+               set tomark [list $d]
+               for {set j 0} {$j < [llength $tomark]} {incr j} {
+                   set dd [lindex $tomark $j]
+                   if {![info exists hastaggeddescendent($dd)]} {
+                       if {[info exists done($dd)]} {
+                           foreach b $arcout($dd) {
+                               if {[info exists arcend($b)]} {
+                                   lappend tomark $arcend($b)
+                               }
+                           }
+                           if {[info exists tagloc($dd)]} {
+                               unset tagloc($dd)
+                           }
+                       } elseif {[info exists queued($dd)]} {
+                           incr nc -1
+                       }
+                       set hastaggeddescendent($dd) 1
+                   }
+               }
+           }
+           if {![info exists queued($d)]} {
+               lappend todo $d
+               set queued($d) 1
+               if {![info exists hastaggeddescendent($d)]} {
+                   incr nc
+               }
+           }
+       }
+    }
+    set t2 [clock clicks -milliseconds]
+    set loopix $i
+    set tags {}
+    foreach id [array names tagloc] {
+       if {![info exists hastaggeddescendent($id)]} {
+           foreach t $tagloc($id) {
+               if {[lsearch -exact $tags $t] < 0} {
+                   lappend tags $t
+               }
+           }
        }
-       set todo [concat $todo $p]
     }
-}
 
-# update the desc_heads array for a head just removed
-proc removedhead {hid head} {
-    global desc_heads allparents headids idheads
+    # remove tags that are ancestors of other tags
+    for {set i 0} {$i < [llength $tags]} {incr i} {
+       set a [lindex $tags $i]
+       for {set j 0} {$j < $i} {incr j} {
+           set b [lindex $tags $j]
+           set r [anc_or_desc $a $b]
+           if {$r == -1} {
+               set tags [lreplace $tags $j $j]
+               incr j -1
+               incr i -1
+           } elseif {$r == 1} {
+               set tags [lreplace $tags $i $i]
+               incr i -1
+               break
+           }
+       }
+    }
 
-    unset headids($head)
-    if {$idheads($hid) eq $head} {
-       unset idheads($hid)
-    } else {
-       set i [lsearch -exact $idheads($hid) $head]
-       if {$i >= 0} {
-           set idheads($hid) [lreplace $idheads($hid) $i $i]
+    if {[array names growing] ne {}} {
+       # graph isn't finished, need to check if any tag could get
+       # eclipsed by another tag coming later.  Simply ignore any
+       # tags that could later get eclipsed.
+       set ctags {}
+       foreach t $tags {
+           if {[is_certain $origid $t]} {
+               lappend ctags $t
+           }
+       }
+       if {$tags eq $ctags} {
+           set cached_atags($origid) $tags
+       } else {
+           set tags $ctags
        }
+    } else {
+       set cached_atags($origid) $tags
+    }
+    set t3 [clock clicks -milliseconds]
+    if {0 && $t3 - $t1 >= 100} {
+       puts "iterating ancestors ($loopix/[llength $todo] nodes) took\
+           [expr {$t2-$t1}]+[expr {$t3-$t2}]ms, $nc candidates left"
     }
+    return $tags
+}
 
-    set todo [list $hid]
-    while {$todo ne {}} {
-       set do [lindex $todo 0]
-       set todo [lrange $todo 1 end]
-       if {![info exists desc_heads($do)]} continue
-       set i [lsearch -exact $desc_heads($do) $head]
-       if {$i < 0} continue
-       set oldheads $desc_heads($do)
-       set heads [lreplace $desc_heads($do) $i $i]
-       while {1} {
-           set desc_heads($do) $heads
-           set p $allparents($do)
-           if {[llength $p] != 1 || ![info exists desc_heads($p)] ||
-               $desc_heads($p) ne $oldheads} break
-           set do $p
+# Return the list of IDs that have heads that are descendents of id,
+# including id itself if it has a head.
+proc descheads {id} {
+    global arcnos arcstart arcids archeads idheads cached_dheads
+    global allparents
+
+    if {![info exists allparents($id)]} {
+       return {}
+    }
+    set aret {}
+    if {[llength $arcnos($id)] == 1 && [llength $allparents($id)] == 1} {
+       # part-way along an arc; check it first
+       set a [lindex $arcnos($id) 0]
+       if {$archeads($a) ne {}} {
+           validate_archeads $a
+           set i [lsearch -exact $arcids($a) $id]
+           foreach t $archeads($a) {
+               set j [lsearch -exact $arcids($a) $t]
+               if {$j > $i} break
+               lappend aret $t
+           }
        }
-       set todo [concat $todo $p]
+       set id $arcstart($a)
     }
+    set origid $id
+    set todo [list $id]
+    set seen($id) 1
+    set ret {}
+    for {set i 0} {$i < [llength $todo]} {incr i} {
+       set id [lindex $todo $i]
+       if {[info exists cached_dheads($id)]} {
+           set ret [concat $ret $cached_dheads($id)]
+       } else {
+           if {[info exists idheads($id)]} {
+               lappend ret $id
+           }
+           foreach a $arcnos($id) {
+               if {$archeads($a) ne {}} {
+                   validate_archeads $a
+                   if {$archeads($a) ne {}} {
+                       set ret [concat $ret $archeads($a)]
+                   }
+               }
+               set d $arcstart($a)
+               if {![info exists seen($d)]} {
+                   lappend todo $d
+                   set seen($d) 1
+               }
+           }
+       }
+    }
+    set ret [lsort -unique $ret]
+    set cached_dheads($origid) $ret
+    return [concat $ret $aret]
 }
 
-# update things for a head moved to a child of its previous location
-proc movedhead {id name} {
-    global headids idheads
+proc addedtag {id} {
+    global arcnos arcout cached_dtags cached_atags
 
-    set oldid $headids($name)
-    set headids($name) $id
-    if {$idheads($oldid) eq $name} {
-       unset idheads($oldid)
-    } else {
-       set i [lsearch -exact $idheads($oldid) $name]
-       if {$i >= 0} {
-           set idheads($oldid) [lreplace $idheads($oldid) $i $i]
-       }
+    if {![info exists arcnos($id)]} return
+    if {![info exists arcout($id)]} {
+       recalcarc [lindex $arcnos($id) 0]
     }
-    lappend idheads($id) $name
+    catch {unset cached_dtags}
+    catch {unset cached_atags}
 }
 
-proc changedrefs {} {
-    global desc_heads desc_tags anc_tags allcommits allids
-    global allchildren allparents idtags travindex
+proc addedhead {hid head} {
+    global arcnos arcout cached_dheads
 
-    if {![info exists allcommits]} return
-    catch {unset desc_heads}
-    catch {unset desc_tags}
-    catch {unset anc_tags}
-    catch {unset alldtags}
-    catch {unset tagisdesc}
-    foreach id $allids {
-       forward_pass $id $allchildren($id)
+    if {![info exists arcnos($hid)]} return
+    if {![info exists arcout($hid)]} {
+       recalcarc [lindex $arcnos($hid) 0]
     }
-    if {$allcommits ne "reading"} {
-       set travindex [llength $allids]
-       if {$allcommits ne "traversing"} {
-           set allcommits "traversing"
-           after idle restartatags
+    catch {unset cached_dheads}
+}
+
+proc removedhead {hid head} {
+    global cached_dheads
+
+    catch {unset cached_dheads}
+}
+
+proc movedhead {hid head} {
+    global arcnos arcout cached_dheads
+
+    if {![info exists arcnos($hid)]} return
+    if {![info exists arcout($hid)]} {
+       recalcarc [lindex $arcnos($hid) 0]
+    }
+    catch {unset cached_dheads}
+}
+
+proc changedrefs {} {
+    global cached_dheads cached_dtags cached_atags
+    global arctags archeads arcnos arcout idheads idtags
+
+    foreach id [concat [array names idheads] [array names idtags]] {
+       if {[info exists arcnos($id)] && ![info exists arcout($id)]} {
+           set a [lindex $arcnos($id) 0]
+           if {![info exists donearc($a)]} {
+               recalcarc $a
+               set donearc($a) 1
+           }
        }
     }
+    catch {unset cached_dtags}
+    catch {unset cached_atags}
+    catch {unset cached_dheads}
 }
 
 proc rereadrefs {} {
@@ -5817,7 +6894,7 @@ proc listrefs {id} {
 }
 
 proc showtag {tag isnew} {
-    global ctext tagcontents tagids linknum
+    global ctext tagcontents tagids linknum tagobjid
 
     if {$isnew} {
        addtohistory [list showtag $tag 0]
@@ -5825,6 +6902,11 @@ proc showtag {tag isnew} {
     $ctext conf -state normal
     clear_ctext
     set linknum 0
+    if {![info exists tagcontents($tag)]} {
+       catch {
+           set tagcontents($tag) [exec git cat-file tag $tagobjid($tag)]
+       }
+    }
     if {[info exists tagcontents($tag)]} {
        set text $tagcontents($tag)
     } else {
@@ -5844,9 +6926,9 @@ proc doquit {} {
 
 proc doprefs {} {
     global maxwidth maxgraphpct diffopts
-    global oldprefs prefstop showneartags
-    global bgcolor fgcolor ctext diffcolors
-    global uifont
+    global oldprefs prefstop showneartags showlocalchanges
+    global bgcolor fgcolor ctext diffcolors selectbgcolor
+    global uifont tabstop
 
     set top .gitkprefs
     set prefstop $top
@@ -5854,7 +6936,7 @@ proc doprefs {} {
        raise $top
        return
     }
-    foreach v {maxwidth maxgraphpct diffopts showneartags} {
+    foreach v {maxwidth maxgraphpct diffopts showneartags showlocalchanges} {
        set oldprefs($v) [set $v]
     }
     toplevel $top
@@ -5871,6 +6953,11 @@ proc doprefs {} {
        -font optionfont
     spinbox $top.maxpct -from 1 -to 100 -width 4 -textvariable maxgraphpct
     grid x $top.maxpctl $top.maxpct -sticky w
+    frame $top.showlocal
+    label $top.showlocal.l -text "Show local changes" -font optionfont
+    checkbutton $top.showlocal.b -variable showlocalchanges
+    pack $top.showlocal.b $top.showlocal.l -side left
+    grid x $top.showlocal -sticky w
 
     label $top.ddisp -text "Diff display options"
     $top.ddisp configure -font $uifont
@@ -5884,6 +6971,9 @@ proc doprefs {} {
     checkbutton $top.ntag.b -variable showneartags
     pack $top.ntag.b $top.ntag.l -side left
     grid x $top.ntag -sticky w
+    label $top.tabstopl -text "tabstop" -font optionfont
+    spinbox $top.tabstop -from 1 -to 20 -width 4 -textvariable tabstop
+    grid x $top.tabstopl $top.tabstop -sticky w
 
     label $top.cdisp -text "Colors: press to choose"
     $top.cdisp configure -font $uifont
@@ -5912,6 +7002,10 @@ proc doprefs {} {
                      "diff hunk header" \
                      [list $ctext tag conf hunksep -foreground]]
     grid x $top.hunksepbut $top.hunksep -sticky w
+    label $top.selbgsep -padx 40 -relief sunk -background $selectbgcolor
+    button $top.selbgbut -text "Select bg" -font optionfont \
+       -command [list choosecolor selectbgcolor 0 $top.selbgsep background setselbg]
+    grid x $top.selbgbut $top.selbgsep -sticky w
 
     frame $top.buts
     button $top.buts.ok -text "OK" -command prefsok -default active
@@ -5936,6 +7030,16 @@ proc choosecolor {v vi w x cmd} {
     eval $cmd $c
 }
 
+proc setselbg {c} {
+    global bglist cflist
+    foreach w $bglist {
+       $w configure -selectbackground $c
+    }
+    $cflist tag configure highlight \
+       -background [$cflist cget -selectbackground]
+    allcanvs itemconf secsel -fill $c
+}
+
 proc setbg {c} {
     global bglist
 
@@ -5956,9 +7060,9 @@ proc setfg {c} {
 
 proc prefscan {} {
     global maxwidth maxgraphpct diffopts
-    global oldprefs prefstop showneartags
+    global oldprefs prefstop showneartags showlocalchanges
 
-    foreach v {maxwidth maxgraphpct diffopts showneartags} {
+    foreach v {maxwidth maxgraphpct diffopts showneartags showlocalchanges} {
        set $v $oldprefs($v)
     }
     catch {destroy $prefstop}
@@ -5967,10 +7071,19 @@ proc prefscan {} {
 
 proc prefsok {} {
     global maxwidth maxgraphpct
-    global oldprefs prefstop showneartags
+    global oldprefs prefstop showneartags showlocalchanges
+    global charspc ctext tabstop
 
     catch {destroy $prefstop}
     unset prefstop
+    $ctext configure -tabs "[expr {$tabstop * $charspc}]"
+    if {$showlocalchanges != $oldprefs(showlocalchanges)} {
+       if {$showlocalchanges} {
+           doshowlocalchanges
+       } else {
+           dohidelocalchanges
+       }
+    }
     if {$maxwidth != $oldprefs(maxwidth)
        || $maxgraphpct != $oldprefs(maxgraphpct)} {
        redisplay
@@ -5980,7 +7093,10 @@ proc prefsok {} {
 }
 
 proc formatdate {d} {
-    return [clock format $d -format "%Y-%m-%d %H:%M:%S"]
+    if {$d ne {}} {
+       set d [clock format $d -format "%Y-%m-%d %H:%M:%S"]
+    }
+    return $d
 }
 
 # This list of encoding names and aliases is distilled from
@@ -6276,6 +7392,7 @@ if {$tclencoding == {}} {
 set mainfont {Helvetica 9}
 set textfont {Courier 9}
 set uifont {Helvetica 9 bold}
+set tabstop 8
 set findmergefiles 0
 set maxgraphpct 50
 set maxwidth 16
@@ -6287,11 +7404,15 @@ set mingaplen 30
 set cmitmode "patch"
 set wrapcomment "none"
 set showneartags 1
+set maxrefs 20
+set maxlinelen 200
+set showlocalchanges 1
 
 set colors {green red blue magenta darkgrey brown orange}
 set bgcolor white
 set fgcolor black
 set diffcolors {red "#00a000" blue}
+set selectbgcolor gray85
 
 catch {source ~/.gitk}
 
@@ -6338,6 +7459,9 @@ if {$i >= 0} {
     }
 }
 
+set nullid "0000000000000000000000000000000000000000"
+
+set runq {}
 set history {}
 set historyindex 0
 set fh_serial 0
@@ -6362,6 +7486,9 @@ set cmdlineok 0
 set stopped 0
 set stuffsaved 0
 set patchnum 0
+set lookingforhead 0
+set localrow -1
+set lserial 0
 setcoords
 makewindow
 wm title . "[file tail $argv0]: [file tail [pwd]]"
index e02e90f0429be0d2a69b76571101f20b8f75530f..7186cede2fad816ef4d497ac2c863869d5db76a0 100644 (file)
@@ -79,4 +79,3 @@ Originally written by:
 
 Any comment/question/concern to:
   Git mailing list <git@vger.kernel.org>
-
index 9f0822fab3d10fd5a83234f761847d7818c6da0a..096313bec0a3f39596fda96d2f968181a7b7cd84 100644 (file)
@@ -181,10 +181,15 @@ table.diff_tree {
        font-family: monospace;
 }
 
+table.combined.diff_tree th {
+       text-align: center;
+}
+
 table.combined.diff_tree td {
        padding-right: 24px;
 }
 
+table.combined.diff_tree th.link,
 table.combined.diff_tree td.link {
        padding: 0px 2px;
 }
@@ -276,6 +281,12 @@ table.diff_tree span.file_status.copied {
   color: #70a070;
 }
 
+/* noage: "No commits" */
+table.project_list td.noage {
+       color: #808080;
+       font-style: italic;
+}
+
 /* age2: 60*60*24*2 <= age */
 table.project_list td.age2, table.blame td.age2 {
        font-style: italic;
index 5c7011a37b2e4dab8c38de54a3e531d2fa16ddbe..dc609f4f8622f8c1a49c1ae75e3a89c3144e0e26 100755 (executable)
@@ -94,6 +94,13 @@ our $default_text_plain_charset  = undef;
 # (relative to the current git repository)
 our $mimetypes_file = undef;
 
+# assume this charset if line contains non-UTF-8 characters;
+# it should be valid encoding (see Encoding::Supported(3pm) for list),
+# for which encoding all byte sequences are valid, for example
+# 'iso-8859-1' aka 'latin1' (it is decoded without checking, so it
+# could be even 'utf-8' for the old behavior)
+our $fallback_encoding = 'latin1';
+
 # You define site-wide feature defaults here; override them with
 # $GITWEB_CONFIG as necessary.
 our %feature = (
@@ -132,7 +139,7 @@ our %feature = (
        # $feature{'snapshot'}{'default'} = [undef];
        # To have project specific config enable override in $GITWEB_CONFIG
        # $feature{'snapshot'}{'override'} = 1;
-       # and in project config gitweb.snapshot = none|gzip|bzip2;
+       # and in project config gitweb.snapshot = none|gzip|bzip2|zip;
        'snapshot' => {
                'sub' => \&feature_snapshot,
                'override' => 0,
@@ -244,6 +251,8 @@ sub feature_snapshot {
                return ('x-gzip', 'gz', 'gzip');
        } elsif ($val eq 'bzip2') {
                return ('x-bzip2', 'bz2', 'bzip2');
+       } elsif ($val eq 'zip') {
+               return ('x-zip', 'zip', '');
        } elsif ($val eq 'none') {
                return ();
        }
@@ -600,6 +609,20 @@ sub validate_refname {
        return $input;
 }
 
+# decode sequences of octets in utf8 into Perl's internal form,
+# which is utf-8 with utf8 flag set if needed.  gitweb writes out
+# in utf-8 thanks to "binmode STDOUT, ':utf8'" at beginning
+sub to_utf8 {
+       my $str = shift;
+       my $res;
+       eval { $res = decode_utf8($str, Encode::FB_CROAK); };
+       if (defined $res) {
+               return $res;
+       } else {
+               return decode($fallback_encoding, $str, Encode::FB_DEFAULT);
+       }
+}
+
 # quote unsafe chars, but keep the slash, even when it's not
 # correct, but quoted slashes look too horrible in bookmarks
 sub esc_param {
@@ -624,7 +647,7 @@ sub esc_html ($;%) {
        my $str = shift;
        my %opts = @_;
 
-       $str = decode_utf8($str);
+       $str = to_utf8($str);
        $str = $cgi->escapeHTML($str);
        if ($opts{'-nbsp'}) {
                $str =~ s/ /&nbsp;/g;
@@ -638,7 +661,7 @@ sub esc_path {
        my $str = shift;
        my %opts = @_;
 
-       $str = decode_utf8($str);
+       $str = to_utf8($str);
        $str = $cgi->escapeHTML($str);
        if ($opts{'-nbsp'}) {
                $str =~ s/ /&nbsp;/g;
@@ -923,7 +946,7 @@ sub format_subject_html {
 
        if (length($short) < length($long)) {
                return $cgi->a({-href => $href, -class => "list subject",
-                               -title => decode_utf8($long)},
+                               -title => to_utf8($long)},
                       esc_html($short) . $extra);
        } else {
                return $cgi->a({-href => $href, -class => "list subject"},
@@ -931,7 +954,200 @@ sub format_subject_html {
        }
 }
 
-# format patch (diff) line (rather not to be used for diff headers)
+# format git diff header line, i.e. "diff --(git|combined|cc) ..."
+sub format_git_diff_header_line {
+       my $line = shift;
+       my $diffinfo = shift;
+       my ($from, $to) = @_;
+
+       if ($diffinfo->{'nparents'}) {
+               # combined diff
+               $line =~ s!^(diff (.*?) )"?.*$!$1!;
+               if ($to->{'href'}) {
+                       $line .= $cgi->a({-href => $to->{'href'}, -class => "path"},
+                                        esc_path($to->{'file'}));
+               } else { # file was deleted (no href)
+                       $line .= esc_path($to->{'file'});
+               }
+       } else {
+               # "ordinary" diff
+               $line =~ s!^(diff (.*?) )"?a/.*$!$1!;
+               if ($from->{'href'}) {
+                       $line .= $cgi->a({-href => $from->{'href'}, -class => "path"},
+                                        'a/' . esc_path($from->{'file'}));
+               } else { # file was added (no href)
+                       $line .= 'a/' . esc_path($from->{'file'});
+               }
+               $line .= ' ';
+               if ($to->{'href'}) {
+                       $line .= $cgi->a({-href => $to->{'href'}, -class => "path"},
+                                        'b/' . esc_path($to->{'file'}));
+               } else { # file was deleted
+                       $line .= 'b/' . esc_path($to->{'file'});
+               }
+       }
+
+       return "<div class=\"diff header\">$line</div>\n";
+}
+
+# format extended diff header line, before patch itself
+sub format_extended_diff_header_line {
+       my $line = shift;
+       my $diffinfo = shift;
+       my ($from, $to) = @_;
+
+       # match <path>
+       if ($line =~ s!^((copy|rename) from ).*$!$1! && $from->{'href'}) {
+               $line .= $cgi->a({-href=>$from->{'href'}, -class=>"path"},
+                                      esc_path($from->{'file'}));
+       }
+       if ($line =~ s!^((copy|rename) to ).*$!$1! && $to->{'href'}) {
+               $line .= $cgi->a({-href=>$to->{'href'}, -class=>"path"},
+                                esc_path($to->{'file'}));
+       }
+       # match single <mode>
+       if ($line =~ m/\s(\d{6})$/) {
+               $line .= '<span class="info"> (' .
+                        file_type_long($1) .
+                        ')</span>';
+       }
+       # match <hash>
+       if ($line =~ m/^index [0-9a-fA-F]{40},[0-9a-fA-F]{40}/) {
+               # can match only for combined diff
+               $line = 'index ';
+               for (my $i = 0; $i < $diffinfo->{'nparents'}; $i++) {
+                       if ($from->{'href'}[$i]) {
+                               $line .= $cgi->a({-href=>$from->{'href'}[$i],
+                                                 -class=>"hash"},
+                                                substr($diffinfo->{'from_id'}[$i],0,7));
+                       } else {
+                               $line .= '0' x 7;
+                       }
+                       # separator
+                       $line .= ',' if ($i < $diffinfo->{'nparents'} - 1);
+               }
+               $line .= '..';
+               if ($to->{'href'}) {
+                       $line .= $cgi->a({-href=>$to->{'href'}, -class=>"hash"},
+                                        substr($diffinfo->{'to_id'},0,7));
+               } else {
+                       $line .= '0' x 7;
+               }
+
+       } elsif ($line =~ m/^index [0-9a-fA-F]{40}..[0-9a-fA-F]{40}/) {
+               # can match only for ordinary diff
+               my ($from_link, $to_link);
+               if ($from->{'href'}) {
+                       $from_link = $cgi->a({-href=>$from->{'href'}, -class=>"hash"},
+                                            substr($diffinfo->{'from_id'},0,7));
+               } else {
+                       $from_link = '0' x 7;
+               }
+               if ($to->{'href'}) {
+                       $to_link = $cgi->a({-href=>$to->{'href'}, -class=>"hash"},
+                                          substr($diffinfo->{'to_id'},0,7));
+               } else {
+                       $to_link = '0' x 7;
+               }
+               my ($from_id, $to_id) = ($diffinfo->{'from_id'}, $diffinfo->{'to_id'});
+               $line =~ s!$from_id\.\.$to_id!$from_link..$to_link!;
+       }
+
+       return $line . "<br/>\n";
+}
+
+# format from-file/to-file diff header
+sub format_diff_from_to_header {
+       my ($from_line, $to_line, $diffinfo, $from, $to, @parents) = @_;
+       my $line;
+       my $result = '';
+
+       $line = $from_line;
+       #assert($line =~ m/^---/) if DEBUG;
+       # no extra formatting for "^--- /dev/null"
+       if (! $diffinfo->{'nparents'}) {
+               # ordinary (single parent) diff
+               if ($line =~ m!^--- "?a/!) {
+                       if ($from->{'href'}) {
+                               $line = '--- a/' .
+                                       $cgi->a({-href=>$from->{'href'}, -class=>"path"},
+                                               esc_path($from->{'file'}));
+                       } else {
+                               $line = '--- a/' .
+                                       esc_path($from->{'file'});
+                       }
+               }
+               $result .= qq!<div class="diff from_file">$line</div>\n!;
+
+       } else {
+               # combined diff (merge commit)
+               for (my $i = 0; $i < $diffinfo->{'nparents'}; $i++) {
+                       if ($from->{'href'}[$i]) {
+                               $line = '--- ' .
+                                       $cgi->a({-href=>href(action=>"blobdiff",
+                                                            hash_parent=>$diffinfo->{'from_id'}[$i],
+                                                            hash_parent_base=>$parents[$i],
+                                                            file_parent=>$from->{'file'}[$i],
+                                                            hash=>$diffinfo->{'to_id'},
+                                                            hash_base=>$hash,
+                                                            file_name=>$to->{'file'}),
+                                                -class=>"path",
+                                                -title=>"diff" . ($i+1)},
+                                               $i+1) .
+                                       '/' .
+                                       $cgi->a({-href=>$from->{'href'}[$i], -class=>"path"},
+                                               esc_path($from->{'file'}[$i]));
+                       } else {
+                               $line = '--- /dev/null';
+                       }
+                       $result .= qq!<div class="diff from_file">$line</div>\n!;
+               }
+       }
+
+       $line = $to_line;
+       #assert($line =~ m/^\+\+\+/) if DEBUG;
+       # no extra formatting for "^+++ /dev/null"
+       if ($line =~ m!^\+\+\+ "?b/!) {
+               if ($to->{'href'}) {
+                       $line = '+++ b/' .
+                               $cgi->a({-href=>$to->{'href'}, -class=>"path"},
+                                       esc_path($to->{'file'}));
+               } else {
+                       $line = '+++ b/' .
+                               esc_path($to->{'file'});
+               }
+       }
+       $result .= qq!<div class="diff to_file">$line</div>\n!;
+
+       return $result;
+}
+
+# create note for patch simplified by combined diff
+sub format_diff_cc_simplified {
+       my ($diffinfo, @parents) = @_;
+       my $result = '';
+
+       $result .= "<div class=\"diff header\">" .
+                  "diff --cc ";
+       if (!is_deleted($diffinfo)) {
+               $result .= $cgi->a({-href => href(action=>"blob",
+                                                 hash_base=>$hash,
+                                                 hash=>$diffinfo->{'to_id'},
+                                                 file_name=>$diffinfo->{'to_file'}),
+                                   -class => "path"},
+                                  esc_path($diffinfo->{'to_file'}));
+       } else {
+               $result .= esc_path($diffinfo->{'to_file'});
+       }
+       $result .= "</div>\n" . # class="diff header"
+                  "<div class=\"diff nodifferences\">" .
+                  "Simple merge" .
+                  "</div>\n"; # class="diff nodifferences"
+
+       return $result;
+}
+
+# format patch (diff) line (not to be used for diff headers)
 sub format_diff_line {
        my $line = shift;
        my ($from, $to) = @_;
@@ -1237,7 +1453,7 @@ sub git_get_projects_list {
                        if (check_export_ok("$projectroot/$path")) {
                                my $pr = {
                                        path => $path,
-                                       owner => decode_utf8($owner),
+                                       owner => to_utf8($owner),
                                };
                                push @list, $pr;
                                (my $forks_path = $path) =~ s/\.git$//;
@@ -1249,12 +1465,12 @@ sub git_get_projects_list {
        return @list;
 }
 
-sub git_get_project_owner {
-       my $project = shift;
-       my $owner;
+our $gitweb_project_owner = undef;
+sub git_get_project_list_from_file {
 
-       return undef unless $project;
+       return if (defined $gitweb_project_owner);
 
+       $gitweb_project_owner = {};
        # read from file (url-encoded):
        # 'git%2Fgit.git Linus+Torvalds'
        # 'libs%2Fklibc%2Fklibc.git H.+Peter+Anvin'
@@ -1266,13 +1482,25 @@ sub git_get_project_owner {
                        my ($pr, $ow) = split ' ', $line;
                        $pr = unescape($pr);
                        $ow = unescape($ow);
-                       if ($pr eq $project) {
-                               $owner = decode_utf8($ow);
-                               last;
-                       }
+                       $gitweb_project_owner->{$pr} = to_utf8($ow);
                }
                close $fd;
        }
+}
+
+sub git_get_project_owner {
+       my $project = shift;
+       my $owner;
+
+       return undef unless $project;
+
+       if (!defined $gitweb_project_owner) {
+               git_get_project_list_from_file();
+       }
+
+       if (exists $gitweb_project_owner->{$project}) {
+               $owner = $gitweb_project_owner->{$project};
+       }
        if (!defined $owner) {
                $owner = get_file_owner("$projectroot/$project");
        }
@@ -1298,6 +1526,7 @@ sub git_get_last_activity {
                my $age = time - $timestamp;
                return ($age, age_string($age));
        }
+       return (undef, undef);
 }
 
 sub git_get_references {
@@ -1657,6 +1886,48 @@ sub parse_ls_tree_line ($;%) {
        return wantarray ? %res : \%res;
 }
 
+# generates _two_ hashes, references to which are passed as 2 and 3 argument
+sub parse_from_to_diffinfo {
+       my ($diffinfo, $from, $to, @parents) = @_;
+
+       if ($diffinfo->{'nparents'}) {
+               # combined diff
+               $from->{'file'} = [];
+               $from->{'href'} = [];
+               fill_from_file_info($diffinfo, @parents)
+                       unless exists $diffinfo->{'from_file'};
+               for (my $i = 0; $i < $diffinfo->{'nparents'}; $i++) {
+                       $from->{'file'}[$i] = $diffinfo->{'from_file'}[$i] || $diffinfo->{'to_file'};
+                       if ($diffinfo->{'status'}[$i] ne "A") { # not new (added) file
+                               $from->{'href'}[$i] = href(action=>"blob",
+                                                          hash_base=>$parents[$i],
+                                                          hash=>$diffinfo->{'from_id'}[$i],
+                                                          file_name=>$from->{'file'}[$i]);
+                       } else {
+                               $from->{'href'}[$i] = undef;
+                       }
+               }
+       } else {
+               $from->{'file'} = $diffinfo->{'from_file'} || $diffinfo->{'file'};
+               if ($diffinfo->{'status'} ne "A") { # not new (added) file
+                       $from->{'href'} = href(action=>"blob", hash_base=>$hash_parent,
+                                              hash=>$diffinfo->{'from_id'},
+                                              file_name=>$from->{'file'});
+               } else {
+                       delete $from->{'href'};
+               }
+       }
+
+       $to->{'file'} = $diffinfo->{'to_file'} || $diffinfo->{'file'};
+       if (!is_deleted($diffinfo)) { # file exists in result
+               $to->{'href'} = href(action=>"blob", hash_base=>$hash,
+                                    hash=>$diffinfo->{'to_id'},
+                                    file_name=>$to->{'file'});
+       } else {
+               delete $to->{'href'};
+       }
+}
+
 ## ......................................................................
 ## parse to array of hashes functions
 
@@ -1757,7 +2028,7 @@ sub get_file_owner {
        }
        my $owner = $gcos;
        $owner =~ s/[,;].*$//;
-       return decode_utf8($owner);
+       return to_utf8($owner);
 }
 
 ## ......................................................................
@@ -1840,7 +2111,7 @@ sub git_header_html {
 
        my $title = "$site_name";
        if (defined $project) {
-               $title .= " - " . decode_utf8($project);
+               $title .= " - " . to_utf8($project);
                if (defined $action) {
                        $title .= "/$action";
                        if (defined $file_name) {
@@ -1943,12 +2214,18 @@ EOF
                } else {
                        $search_hash = "HEAD";
                }
+               my $action = $my_uri;
+               my ($use_pathinfo) = gitweb_check_feature('pathinfo');
+               if ($use_pathinfo) {
+                       $action .= "/$project";
+               } else {
+                       $cgi->param("p", $project);
+               }
                $cgi->param("a", "search");
                $cgi->param("h", $search_hash);
-               $cgi->param("p", $project);
-               print $cgi->startform(-method => "get", -action => $my_uri) .
+               print $cgi->startform(-method => "get", -action => $action) .
                      "<div class=\"search\">\n" .
-                     $cgi->hidden(-name => "p") . "\n" .
+                     (!$use_pathinfo && $cgi->hidden(-name => "p") . "\n") .
                      $cgi->hidden(-name => "a") . "\n" .
                      $cgi->hidden(-name => "h") . "\n" .
                      $cgi->popup_menu(-name => 'st', -default => 'commit',
@@ -2114,7 +2391,7 @@ sub git_print_page_path {
 
        print "<div class=\"page_path\">";
        print $cgi->a({-href => href(action=>"tree", hash_base=>$hb),
-                     -title => 'tree root'}, decode_utf8("[$project]"));
+                     -title => 'tree root'}, to_utf8("[$project]"));
        print " / ";
        if (defined $name) {
                my @dirname = split '/', $name;
@@ -2364,6 +2641,11 @@ sub from_ids_eq {
        }
 }
 
+sub is_deleted {
+       my $diffinfo = shift;
+
+       return $diffinfo->{'to_id'} eq ('0' x 40);
+}
 
 sub git_difftree_body {
        my ($difftree, $hash, @parents) = @_;
@@ -2378,6 +2660,26 @@ sub git_difftree_body {
        print "<table class=\"" .
              (@parents > 1 ? "combined " : "") .
              "diff_tree\">\n";
+
+       # header only for combined diff in 'commitdiff' view
+       my $has_header = @parents > 1 && $action eq 'commitdiff';
+       if ($has_header) {
+               # table header
+               print "<thead><tr>\n" .
+                      "<th></th><th></th>\n"; # filename, patchN link
+               for (my $i = 0; $i < @parents; $i++) {
+                       my $par = $parents[$i];
+                       print "<th>" .
+                             $cgi->a({-href => href(action=>"commitdiff",
+                                                    hash=>$hash, hash_parent=>$par),
+                                      -title => 'commitdiff to parent number ' .
+                                                 ($i+1) . ': ' . substr($par,0,7)},
+                                     $i+1) .
+                             "&nbsp;</th>\n";
+               }
+               print "</tr></thead>\n<tbody>\n";
+       }
+
        my $alternate = 1;
        my $patchno = 0;
        foreach my $line (@{$difftree}) {
@@ -2401,7 +2703,7 @@ sub git_difftree_body {
                        fill_from_file_info($diff, @parents)
                                unless exists $diff->{'from_file'};
 
-                       if ($diff->{'to_id'} ne ('0' x 40)) {
+                       if (!is_deleted($diff)) {
                                # file exists in the result (child) commit
                                print "<td>" .
                                      $cgi->a({-href => href(action=>"blob", hash=>$diff->{'to_id'},
@@ -2650,6 +2952,7 @@ sub git_difftree_body {
                } # we should not encounter Unmerged (U) or Unknown (X) status
                print "</tr>\n";
        }
+       print "</tbody>" if $has_header;
        print "</table>\n";
 }
 
@@ -2714,13 +3017,35 @@ sub git_patchset_body {
                        # advance raw git-diff output if needed
                        $patch_idx++ if defined $diffinfo;
 
-                       # read and prepare patch information
-                       if (ref($difftree->[$patch_idx]) eq "HASH") {
-                               # pre-parsed (or generated by hand)
-                               $diffinfo = $difftree->[$patch_idx];
-                       } else {
-                               $diffinfo = parse_difftree_raw_line($difftree->[$patch_idx]);
+                       # compact combined diff output can have some patches skipped
+                       # find which patch (using pathname of result) we are at now
+                       my $to_name;
+                       if ($diff_header[0] =~ m!^diff --cc "?(.*)"?$!) {
+                               $to_name = $1;
                        }
+
+                       do {
+                               # read and prepare patch information
+                               if (ref($difftree->[$patch_idx]) eq "HASH") {
+                                       # pre-parsed (or generated by hand)
+                                       $diffinfo = $difftree->[$patch_idx];
+                               } else {
+                                       $diffinfo = parse_difftree_raw_line($difftree->[$patch_idx]);
+                               }
+
+                               # check if current raw line has no patch (it got simplified)
+                               if (defined $to_name && $to_name ne $diffinfo->{'to_file'}) {
+                                       print "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n" .
+                                             format_diff_cc_simplified($diffinfo, @hash_parents) .
+                                             "</div>\n";  # class="patch"
+
+                                       $patch_idx++;
+                                       $patch_number++;
+                               }
+                       } until (!defined $to_name || $to_name eq $diffinfo->{'to_file'} ||
+                                $patch_idx > $#$difftree);
+                       # modifies %from, %to hashes
+                       parse_from_to_diffinfo($diffinfo, \%from, \%to, @hash_parents);
                        if ($diffinfo->{'nparents'}) {
                                # combined diff
                                $from{'file'} = [];
@@ -2750,7 +3075,7 @@ sub git_patchset_body {
                        }
 
                        $to{'file'} = $diffinfo->{'to_file'} || $diffinfo->{'file'};
-                       if ($diffinfo->{'to_id'} ne ('0' x 40)) { # file exists in result
+                       if (!is_deleted($diffinfo)) { # file exists in result
                                $to{'href'} = href(action=>"blob", hash_base=>$hash,
                                                   hash=>$diffinfo->{'to_id'},
                                                   file_name=>$to{'file'});
@@ -2764,105 +3089,15 @@ sub git_patchset_body {
 
                # print "git diff" header
                $patch_line = shift @diff_header;
-               if ($diffinfo->{'nparents'}) {
-
-                       # combined diff
-                       $patch_line =~ s!^(diff (.*?) )"?.*$!$1!;
-                       if ($to{'href'}) {
-                               $patch_line .= $cgi->a({-href => $to{'href'}, -class => "path"},
-                                                      esc_path($to{'file'}));
-                       } else { # file was deleted
-                               $patch_line .= esc_path($to{'file'});
-                       }
-
-               } else {
-
-                       $patch_line =~ s!^(diff (.*?) )"?a/.*$!$1!;
-                       if ($from{'href'}) {
-                               $patch_line .= $cgi->a({-href => $from{'href'}, -class => "path"},
-                                                      'a/' . esc_path($from{'file'}));
-                       } else { # file was added
-                               $patch_line .= 'a/' . esc_path($from{'file'});
-                       }
-                       $patch_line .= ' ';
-                       if ($to{'href'}) {
-                               $patch_line .= $cgi->a({-href => $to{'href'}, -class => "path"},
-                                                      'b/' . esc_path($to{'file'}));
-                       } else { # file was deleted
-                               $patch_line .= 'b/' . esc_path($to{'file'});
-                       }
-
-               }
-               print "<div class=\"diff header\">$patch_line</div>\n";
+               print format_git_diff_header_line($patch_line, $diffinfo,
+                                                 \%from, \%to);
 
                # print extended diff header
                print "<div class=\"diff extended_header\">\n" if (@diff_header > 0);
        EXTENDED_HEADER:
                foreach $patch_line (@diff_header) {
-                       # match <path>
-                       if ($patch_line =~ s!^((copy|rename) from ).*$!$1! && $from{'href'}) {
-                               $patch_line .= $cgi->a({-href=>$from{'href'}, -class=>"path"},
-                                                      esc_path($from{'file'}));
-                       }
-                       if ($patch_line =~ s!^((copy|rename) to ).*$!$1! && $to{'href'}) {
-                               $patch_line .= $cgi->a({-href=>$to{'href'}, -class=>"path"},
-                                                      esc_path($to{'file'}));
-                       }
-                       # match single <mode>
-                       if ($patch_line =~ m/\s(\d{6})$/) {
-                               $patch_line .= '<span class="info"> (' .
-                                              file_type_long($1) .
-                                              ')</span>';
-                       }
-                       # match <hash>
-                       if ($patch_line =~ m/^index [0-9a-fA-F]{40},[0-9a-fA-F]{40}/) {
-                               # can match only for combined diff
-                               $patch_line = 'index ';
-                               for (my $i = 0; $i < $diffinfo->{'nparents'}; $i++) {
-                                       if ($from{'href'}[$i]) {
-                                               $patch_line .= $cgi->a({-href=>$from{'href'}[$i],
-                                                                       -class=>"hash"},
-                                                                      substr($diffinfo->{'from_id'}[$i],0,7));
-                                       } else {
-                                               $patch_line .= '0' x 7;
-                                       }
-                                       # separator
-                                       $patch_line .= ',' if ($i < $diffinfo->{'nparents'} - 1);
-                               }
-                               $patch_line .= '..';
-                               if ($to{'href'}) {
-                                       $patch_line .= $cgi->a({-href=>$to{'href'}, -class=>"hash"},
-                                                              substr($diffinfo->{'to_id'},0,7));
-                               } else {
-                                       $patch_line .= '0' x 7;
-                               }
-
-                       } elsif ($patch_line =~ m/^index [0-9a-fA-F]{40}..[0-9a-fA-F]{40}/) {
-                               # can match only for ordinary diff
-                               my ($from_link, $to_link);
-                               if ($from{'href'}) {
-                                       $from_link = $cgi->a({-href=>$from{'href'}, -class=>"hash"},
-                                                            substr($diffinfo->{'from_id'},0,7));
-                               } else {
-                                       $from_link = '0' x 7;
-                               }
-                               if ($to{'href'}) {
-                                       $to_link = $cgi->a({-href=>$to{'href'}, -class=>"hash"},
-                                                          substr($diffinfo->{'to_id'},0,7));
-                               } else {
-                                       $to_link = '0' x 7;
-                               }
-                               #affirm {
-                               #       my ($from_hash, $to_hash) =
-                               #               ($patch_line =~ m/^index ([0-9a-fA-F]{40})..([0-9a-fA-F]{40})/);
-                               #       my ($from_id, $to_id) =
-                               #               ($diffinfo->{'from_id'}, $diffinfo->{'to_id'});
-                               #       ($from_hash eq $from_id) && ($to_hash eq $to_id);
-                               #} if DEBUG;
-                               my ($from_id, $to_id) = ($diffinfo->{'from_id'}, $diffinfo->{'to_id'});
-                               $patch_line =~ s!$from_id\.\.$to_id!$from_link..$to_link!;
-                       }
-                       print $patch_line . "<br/>\n";
+                       print format_extended_diff_header_line($patch_line, $diffinfo,
+                                                              \%from, \%to);
                }
                print "</div>\n"  if (@diff_header > 0); # class="diff extended_header"
 
@@ -2874,24 +3109,15 @@ sub git_patchset_body {
                }
                next PATCH if ($patch_line =~ m/^diff /);
                #assert($patch_line =~ m/^---/) if DEBUG;
-               if (!$diffinfo->{'nparents'} && # not from-file line for combined diff
-                   $from{'href'} && $patch_line =~ m!^--- "?a/!) {
-                       $patch_line = '--- a/' .
-                                     $cgi->a({-href=>$from{'href'}, -class=>"path"},
-                                             esc_path($from{'file'}));
-               }
-               print "<div class=\"diff from_file\">$patch_line</div>\n";
+               #assert($patch_line eq $last_patch_line) if DEBUG;
 
                $patch_line = <$fd>;
                chomp $patch_line;
+               #assert($patch_line =~ m/^\+\+\+/) if DEBUG;
 
-               #assert($patch_line =~ m/^+++/) if DEBUG;
-               if ($to{'href'} && $patch_line =~ m!^\+\+\+ "?b/!) {
-                       $patch_line = '+++ b/' .
-                                     $cgi->a({-href=>$to{'href'}, -class=>"path"},
-                                             esc_path($to{'file'}));
-               }
-               print "<div class=\"diff to_file\">$patch_line</div>\n";
+               print format_diff_from_to_header($last_patch_line, $patch_line,
+                                                $diffinfo, \%from, \%to,
+                                                @hash_parents);
 
                # the patch itself
        LINE:
@@ -2907,6 +3133,27 @@ sub git_patchset_body {
                print "</div>\n"; # class="patch"
        }
 
+       # for compact combined (--cc) format, with chunk and patch simpliciaction
+       # patchset might be empty, but there might be unprocessed raw lines
+       for ($patch_idx++ if $patch_number > 0;
+            $patch_idx < @$difftree;
+            $patch_idx++) {
+               # read and prepare patch information
+               if (ref($difftree->[$patch_idx]) eq "HASH") {
+                       # pre-parsed (or generated by hand)
+                       $diffinfo = $difftree->[$patch_idx];
+               } else {
+                       $diffinfo = parse_difftree_raw_line($difftree->[$patch_idx]);
+               }
+
+               # generate anchor for "patch" links in difftree / whatchanged part
+               print "<div class=\"patch\" id=\"patch". ($patch_idx+1) ."\">\n" .
+                     format_diff_cc_simplified($diffinfo, @hash_parents) .
+                     "</div>\n";  # class="patch"
+
+               $patch_number++;
+       }
+
        if ($patch_number == 0) {
                if (@hash_parents > 1) {
                        print "<div class=\"diff nodifferences\">Trivial merge</div>\n";
@@ -2934,11 +3181,11 @@ sub git_project_list_body {
                ($pr->{'age'}, $pr->{'age_string'}) = @aa;
                if (!defined $pr->{'descr'}) {
                        my $descr = git_get_project_description($pr->{'path'}) || "";
-                       $pr->{'descr_long'} = decode_utf8($descr);
+                       $pr->{'descr_long'} = to_utf8($descr);
                        $pr->{'descr'} = chop_str($descr, 25, 5);
                }
                if (!defined $pr->{'owner'}) {
-                       $pr->{'owner'} = get_file_owner("$projectroot/$pr->{'path'}") || "";
+                       $pr->{'owner'} = git_get_project_owner("$pr->{'path'}") || "";
                }
                if ($check_forks) {
                        my $pname = $pr->{'path'};
@@ -3362,7 +3609,7 @@ sub git_project_index {
 
        foreach my $pr (@projects) {
                if (!exists $pr->{'owner'}) {
-                       $pr->{'owner'} = get_file_owner("$projectroot/$pr->{'path'}");
+                       $pr->{'owner'} = git_get_project_owner("$pr->{'path'}");
                }
 
                my ($path, $owner) = ($pr->{'path'}, $pr->{'owner'});
@@ -3976,19 +4223,28 @@ sub git_snapshot {
                $hash = git_get_head_hash($project);
        }
 
-       my $filename = decode_utf8(basename($project)) . "-$hash.tar.$suffix";
+       my $git = git_cmd_str();
+       my $name = $project;
+       $name =~ s,([^/])/*\.git$,$1,;
+       $name = basename($name);
+       my $filename = to_utf8($name);
+       $name =~ s/\047/\047\\\047\047/g;
+       my $cmd;
+       if ($suffix eq 'zip') {
+               $filename .= "-$hash.$suffix";
+               $cmd = "$git archive --format=zip --prefix=\'$name\'/ $hash";
+       } else {
+               $filename .= "-$hash.tar.$suffix";
+               $cmd = "$git archive --format=tar --prefix=\'$name\'/ $hash | $command";
+       }
 
        print $cgi->header(
                -type => "application/$ctype",
                -content_disposition => 'inline; filename="' . "$filename" . '"',
                -status => '200 OK');
 
-       my $git = git_cmd_str();
-       my $name = $project;
-       $name =~ s/\047/\047\\\047\047/g;
-       open my $fd, "-|",
-               "$git archive --format=tar --prefix=\'$name\'/ $hash | $command"
-               or die_error(undef, "Execute git-tar-tree failed");
+       open my $fd, "-|", $cmd
+               or die_error(undef, "Execute git-archive failed");
        binmode STDOUT, ':raw';
        print <$fd>;
        binmode STDOUT, ':utf8'; # as set at the beginning of gitweb.cgi
@@ -4413,7 +4669,11 @@ sub git_commitdiff {
                die_error(undef, "Unknown commit object");
        }
 
-       # we need to prepare $formats_nav before any parameter munging
+       # choose format for commitdiff for merge
+       if (! defined $hash_parent && @{$co{'parents'}} > 1) {
+               $hash_parent = '--cc';
+       }
+       # we need to prepare $formats_nav before almost any parameter munging
        my $formats_nav;
        if ($format eq 'html') {
                $formats_nav =
@@ -4421,14 +4681,22 @@ sub git_commitdiff {
                                               hash=>$hash, hash_parent=>$hash_parent)},
                                "raw");
 
-               if (defined $hash_parent) {
+               if (defined $hash_parent &&
+                   $hash_parent ne '-c' && $hash_parent ne '--cc') {
                        # commitdiff with two commits given
                        my $hash_parent_short = $hash_parent;
                        if ($hash_parent =~ m/^[0-9a-fA-F]{40}$/) {
                                $hash_parent_short = substr($hash_parent, 0, 7);
                        }
                        $formats_nav .=
-                               ' (from: ' .
+                               ' (from';
+                       for (my $i = 0; $i < @{$co{'parents'}}; $i++) {
+                               if ($co{'parents'}[$i] eq $hash_parent) {
+                                       $formats_nav .= ' parent ' . ($i+1);
+                                       last;
+                               }
+                       }
+                       $formats_nav .= ': ' .
                                $cgi->a({-href => href(action=>"commitdiff",
                                                       hash=>$hash_parent)},
                                        esc_html($hash_parent_short)) .
@@ -4446,6 +4714,17 @@ sub git_commitdiff {
                                ')';
                } else {
                        # merge commit
+                       if ($hash_parent eq '--cc') {
+                               $formats_nav .= ' | ' .
+                                       $cgi->a({-href => href(action=>"commitdiff",
+                                                              hash=>$hash, hash_parent=>'-c')},
+                                               'combined');
+                       } else { # $hash_parent eq '-c'
+                               $formats_nav .= ' | ' .
+                                       $cgi->a({-href => href(action=>"commitdiff",
+                                                              hash=>$hash, hash_parent=>'--cc')},
+                                               'compact');
+                       }
                        $formats_nav .=
                                ' (merge: ' .
                                join(' ', map {
@@ -4458,9 +4737,10 @@ sub git_commitdiff {
        }
 
        my $hash_parent_param = $hash_parent;
-       if (!defined $hash_parent) {
+       if (!defined $hash_parent_param) {
+               # --cc for multiple parents, --root for parentless
                $hash_parent_param =
-                       @{$co{'parents'}} > 1 ? '-c' : $co{'parent'} || '--root';
+                       @{$co{'parents'}} > 1 ? '--cc' : $co{'parent'} || '--root';
        }
 
        # read commitdiff
@@ -4537,10 +4817,14 @@ TEXT
 
        # write patch
        if ($format eq 'html') {
-               git_difftree_body(\@difftree, $hash, $hash_parent || @{$co{'parents'}});
+               my $use_parents = !defined $hash_parent ||
+                       $hash_parent eq '-c' || $hash_parent eq '--cc';
+               git_difftree_body(\@difftree, $hash,
+                                 $use_parents ? @{$co{'parents'}} : $hash_parent);
                print "<br/>\n";
 
-               git_patchset_body($fd, \@difftree, $hash, $hash_parent || @{$co{'parents'}});
+               git_patchset_body($fd, \@difftree, $hash,
+                                 $use_parents ? @{$co{'parents'}} : $hash_parent);
                close $fd;
                print "</div>\n"; # class="page_body"
                git_footer_html();
diff --git a/help.c b/help.c
index 6a9af4d175f2fe9724a2844df63e4011ba91f1b3..1cd33ece6bcec6f71c6749205c18c0f413034d89 100644 (file)
--- a/help.c
+++ b/help.c
@@ -219,5 +219,3 @@ int cmd_help(int argc, const char **argv, const char *prefix)
 
        return 0;
 }
-
-
index 09baedc18ae320a2f09fa61d9065bedb69c02a41..202fae0ba8b348aeca6ec6c61045f39aa0d1fa66 100644 (file)
@@ -828,7 +828,7 @@ static void abort_object_request(struct object_request *obj_req)
        }
        unlink(obj_req->tmpfile);
        if (obj_req->slot) {
-               release_active_slot(obj_req->slot);
+               release_active_slot(obj_req->slot);
                obj_req->slot = NULL;
        }
        release_object_request(obj_req);
index e3f767582bfc71fc3d1b90be8fa76ab3ad7e1664..7c3720f602bb8f50ed54a4f7e7a85c7e08d1c07b 100644 (file)
@@ -9,6 +9,7 @@
 #include "diff.h"
 #include "revision.h"
 #include "exec_cmd.h"
+#include "remote.h"
 
 #include <expat.h>
 
@@ -517,7 +518,7 @@ static void start_put(struct transfer_request *request)
        request->buffer.size = stream.total_out;
        request->buffer.posn = 0;
 
-       request->url = xmalloc(strlen(remote->url) + 
+       request->url = xmalloc(strlen(remote->url) +
                               strlen(request->lock->token) + 51);
        strcpy(request->url, remote->url);
        posn = request->url + strlen(remote->url);
diff --git a/http.c b/http.c
index ae27e0c9409b93558e50318f2dd0a4fe758293b5..c6fb8ace9f9f43935f4128fc223b01e6cb9fa605 100644 (file)
--- a/http.c
+++ b/http.c
@@ -137,7 +137,7 @@ static int http_options(const char *var, const char *value)
                return 0;
        }
 
-#ifdef USE_CURL_MULTI  
+#ifdef USE_CURL_MULTI
        if (!strcmp("http.maxrequests", var)) {
                if (max_requests == -1)
                        max_requests = git_config_int(var, value);
diff --git a/ident.c b/ident.c
index 3d49608e6f9afe22f24a2faf70f2d6cee50b8919..6612d17eba1b2bac59689d4fd5e742df242662fc 100644 (file)
--- a/ident.c
+++ b/ident.c
@@ -83,11 +83,18 @@ static void setup_ident(void)
        }
 
        if (!git_default_email[0]) {
-               if (!pw)
-                       pw = getpwuid(getuid());
-               if (!pw)
-                       die("You don't exist. Go away!");
-               copy_email(pw);
+               const char *email = getenv("EMAIL");
+
+               if (email && email[0])
+                       strlcpy(git_default_email, email,
+                               sizeof(git_default_email));
+               else {
+                       if (!pw)
+                               pw = getpwuid(getuid());
+                       if (!pw)
+                               die("You don't exist. Go away!");
+                       copy_email(pw);
+               }
        }
 
        /* And set the default date */
@@ -197,8 +204,6 @@ const char *fmt_ident(const char *name, const char *email,
                name = git_default_name;
        if (!email)
                email = git_default_email;
-       if (!email)
-               email = getenv("EMAIL");
 
        if (!*name) {
                struct passwd *pw;
index 4283a4acdaf28a8edc2f595e6137cc396f4988dc..a5a069608419a8ecc42be63eb7998efd262f0ddc 100644 (file)
@@ -1239,7 +1239,7 @@ split_msg( msg_data_t *all_msgs, msg_data_t *msg, int *ofs )
        msg->data[ msg->len ] = 0;
 
        *ofs += msg->len;
-       return 1;
+       return 1;
 }
 
 static imap_server_conf_t server =
index 58c4a9c41dd7a05b86d40e6eeee33ba0a3fb6c4f..8403c36b63c041fe0c81276391a0bbea906e833d 100644 (file)
@@ -13,13 +13,11 @@ static const char index_pack_usage[] =
 
 struct object_entry
 {
-       off_t offset;
+       struct pack_idx_entry idx;
        unsigned long size;
        unsigned int hdr_size;
-       uint32_t crc32;
        enum object_type type;
        enum object_type real_type;
-       unsigned char sha1[20];
 };
 
 union delta_base {
@@ -197,7 +195,7 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
        unsigned shift;
        void *data;
 
-       obj->offset = consumed_bytes;
+       obj->idx.offset = consumed_bytes;
        input_crc32 = crc32(0, Z_NULL, 0);
 
        p = fill(1);
@@ -229,15 +227,15 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
                while (c & 128) {
                        base_offset += 1;
                        if (!base_offset || MSB(base_offset, 7))
-                               bad_object(obj->offset, "offset value overflow for delta base object");
+                               bad_object(obj->idx.offset, "offset value overflow for delta base object");
                        p = fill(1);
                        c = *p;
                        use(1);
                        base_offset = (base_offset << 7) + (c & 127);
                }
-               delta_base->offset = obj->offset - base_offset;
-               if (delta_base->offset >= obj->offset)
-                       bad_object(obj->offset, "delta base offset is out of bound");
+               delta_base->offset = obj->idx.offset - base_offset;
+               if (delta_base->offset >= obj->idx.offset)
+                       bad_object(obj->idx.offset, "delta base offset is out of bound");
                break;
        case OBJ_COMMIT:
        case OBJ_TREE:
@@ -245,19 +243,19 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
        case OBJ_TAG:
                break;
        default:
-               bad_object(obj->offset, "unknown object type %d", obj->type);
+               bad_object(obj->idx.offset, "unknown object type %d", obj->type);
        }
-       obj->hdr_size = consumed_bytes - obj->offset;
+       obj->hdr_size = consumed_bytes - obj->idx.offset;
 
-       data = unpack_entry_data(obj->offset, obj->size);
-       obj->crc32 = input_crc32;
+       data = unpack_entry_data(obj->idx.offset, obj->size);
+       obj->idx.crc32 = input_crc32;
        return data;
 }
 
 static void *get_data_from_pack(struct object_entry *obj)
 {
-       unsigned long from = obj[0].offset + obj[0].hdr_size;
-       unsigned long len = obj[1].offset - from;
+       unsigned long from = obj[0].idx.offset + obj[0].hdr_size;
+       unsigned long len = obj[1].idx.offset - from;
        unsigned long rdy = 0;
        unsigned char *src, *data;
        z_stream stream;
@@ -360,11 +358,11 @@ static void resolve_delta(struct object_entry *delta_obj, void *base_data,
                             &result_size);
        free(delta_data);
        if (!result)
-               bad_object(delta_obj->offset, "failed to apply delta");
-       sha1_object(result, result_size, type, delta_obj->sha1);
+               bad_object(delta_obj->idx.offset, "failed to apply delta");
+       sha1_object(result, result_size, type, delta_obj->idx.sha1);
        nr_resolved_deltas++;
 
-       hashcpy(delta_base.sha1, delta_obj->sha1);
+       hashcpy(delta_base.sha1, delta_obj->idx.sha1);
        if (!find_delta_children(&delta_base, &first, &last)) {
                for (j = first; j <= last; j++) {
                        struct object_entry *child = objects + deltas[j].obj_no;
@@ -374,7 +372,7 @@ static void resolve_delta(struct object_entry *delta_obj, void *base_data,
        }
 
        memset(&delta_base, 0, sizeof(delta_base));
-       delta_base.offset = delta_obj->offset;
+       delta_base.offset = delta_obj->idx.offset;
        if (!find_delta_children(&delta_base, &first, &last)) {
                for (j = first; j <= last; j++) {
                        struct object_entry *child = objects + deltas[j].obj_no;
@@ -418,12 +416,12 @@ static void parse_pack_objects(unsigned char *sha1)
                        delta->obj_no = i;
                        delta++;
                } else
-                       sha1_object(data, obj->size, obj->type, obj->sha1);
+                       sha1_object(data, obj->size, obj->type, obj->idx.sha1);
                free(data);
                if (verbose)
                        display_progress(&progress, i+1);
        }
-       objects[i].offset = consumed_bytes;
+       objects[i].idx.offset = consumed_bytes;
        if (verbose)
                stop_progress(&progress);
 
@@ -465,10 +463,10 @@ static void parse_pack_objects(unsigned char *sha1)
 
                if (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA)
                        continue;
-               hashcpy(base.sha1, obj->sha1);
+               hashcpy(base.sha1, obj->idx.sha1);
                ref = !find_delta_children(&base, &ref_first, &ref_last);
                memset(&base, 0, sizeof(base));
-               base.offset = obj->offset;
+               base.offset = obj->idx.offset;
                ofs = !find_delta_children(&base, &ofs_first, &ofs_last);
                if (!ref && !ofs)
                        continue;
@@ -535,11 +533,11 @@ static void append_obj_to_pack(const unsigned char *sha1, void *buf,
        }
        header[n++] = c;
        write_or_die(output_fd, header, n);
-       obj[0].crc32 = crc32(0, Z_NULL, 0);
-       obj[0].crc32 = crc32(obj[0].crc32, header, n);
-       obj[1].offset = obj[0].offset + n;
-       obj[1].offset += write_compressed(output_fd, buf, size, &obj[0].crc32);
-       hashcpy(obj->sha1, sha1);
+       obj[0].idx.crc32 = crc32(0, Z_NULL, 0);
+       obj[0].idx.crc32 = crc32(obj[0].idx.crc32, header, n);
+       obj[1].idx.offset = obj[0].idx.offset + n;
+       obj[1].idx.offset += write_compressed(output_fd, buf, size, &obj[0].idx.crc32);
+       hashcpy(obj->idx.sha1, sha1);
 }
 
 static int delta_pos_compare(const void *_a, const void *_b)
@@ -602,145 +600,6 @@ static void fix_unresolved_deltas(int nr_unresolved)
        free(sorted_by_pos);
 }
 
-static uint32_t index_default_version = 1;
-static uint32_t index_off32_limit = 0x7fffffff;
-
-static int sha1_compare(const void *_a, const void *_b)
-{
-       struct object_entry *a = *(struct object_entry **)_a;
-       struct object_entry *b = *(struct object_entry **)_b;
-       return hashcmp(a->sha1, b->sha1);
-}
-
-/*
- * On entry *sha1 contains the pack content SHA1 hash, on exit it is
- * the SHA1 hash of sorted object names.
- */
-static const char *write_index_file(const char *index_name, unsigned char *sha1)
-{
-       struct sha1file *f;
-       struct object_entry **sorted_by_sha, **list, **last;
-       uint32_t array[256];
-       int i, fd;
-       SHA_CTX ctx;
-       uint32_t index_version;
-
-       if (nr_objects) {
-               sorted_by_sha =
-                       xcalloc(nr_objects, sizeof(struct object_entry *));
-               list = sorted_by_sha;
-               last = sorted_by_sha + nr_objects;
-               for (i = 0; i < nr_objects; ++i)
-                       sorted_by_sha[i] = &objects[i];
-               qsort(sorted_by_sha, nr_objects, sizeof(sorted_by_sha[0]),
-                     sha1_compare);
-       }
-       else
-               sorted_by_sha = list = last = NULL;
-
-       if (!index_name) {
-               static char tmpfile[PATH_MAX];
-               snprintf(tmpfile, sizeof(tmpfile),
-                        "%s/tmp_idx_XXXXXX", get_object_directory());
-               fd = mkstemp(tmpfile);
-               index_name = xstrdup(tmpfile);
-       } else {
-               unlink(index_name);
-               fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
-       }
-       if (fd < 0)
-               die("unable to create %s: %s", index_name, strerror(errno));
-       f = sha1fd(fd, index_name);
-
-       /* if last object's offset is >= 2^31 we should use index V2 */
-       index_version = (objects[nr_objects-1].offset >> 31) ? 2 : index_default_version;
-
-       /* index versions 2 and above need a header */
-       if (index_version >= 2) {
-               struct pack_idx_header hdr;
-               hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
-               hdr.idx_version = htonl(index_version);
-               sha1write(f, &hdr, sizeof(hdr));
-       }
-
-       /*
-        * Write the first-level table (the list is sorted,
-        * but we use a 256-entry lookup to be able to avoid
-        * having to do eight extra binary search iterations).
-        */
-       for (i = 0; i < 256; i++) {
-               struct object_entry **next = list;
-               while (next < last) {
-                       struct object_entry *obj = *next;
-                       if (obj->sha1[0] != i)
-                               break;
-                       next++;
-               }
-               array[i] = htonl(next - sorted_by_sha);
-               list = next;
-       }
-       sha1write(f, array, 256 * 4);
-
-       /* compute the SHA1 hash of sorted object names. */
-       SHA1_Init(&ctx);
-
-       /*
-        * Write the actual SHA1 entries..
-        */
-       list = sorted_by_sha;
-       for (i = 0; i < nr_objects; i++) {
-               struct object_entry *obj = *list++;
-               if (index_version < 2) {
-                       uint32_t offset = htonl(obj->offset);
-                       sha1write(f, &offset, 4);
-               }
-               sha1write(f, obj->sha1, 20);
-               SHA1_Update(&ctx, obj->sha1, 20);
-       }
-
-       if (index_version >= 2) {
-               unsigned int nr_large_offset = 0;
-
-               /* write the crc32 table */
-               list = sorted_by_sha;
-               for (i = 0; i < nr_objects; i++) {
-                       struct object_entry *obj = *list++;
-                       uint32_t crc32_val = htonl(obj->crc32);
-                       sha1write(f, &crc32_val, 4);
-               }
-
-               /* write the 32-bit offset table */
-               list = sorted_by_sha;
-               for (i = 0; i < nr_objects; i++) {
-                       struct object_entry *obj = *list++;
-                       uint32_t offset = (obj->offset <= index_off32_limit) ?
-                               obj->offset : (0x80000000 | nr_large_offset++);
-                       offset = htonl(offset);
-                       sha1write(f, &offset, 4);
-               }
-
-               /* write the large offset table */
-               list = sorted_by_sha;
-               while (nr_large_offset) {
-                       struct object_entry *obj = *list++;
-                       uint64_t offset = obj->offset;
-                       if (offset > index_off32_limit) {
-                               uint32_t split[2];
-                               split[0]        = htonl(offset >> 32);
-                               split[1] = htonl(offset & 0xffffffff);
-                               sha1write(f, split, 8);
-                               nr_large_offset--;
-                       }
-               }
-       }
-
-       sha1write(f, sha1, 20);
-       sha1close(f, NULL, 1);
-       free(sorted_by_sha);
-       SHA1_Final(sha1, &ctx);
-       return index_name;
-}
-
 static void final(const char *final_pack_name, const char *curr_pack_name,
                  const char *final_index_name, const char *curr_index_name,
                  const char *keep_name, const char *keep_msg,
@@ -775,7 +634,8 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
                                write_or_die(keep_fd, keep_msg, keep_msg_len);
                                write_or_die(keep_fd, "\n", 1);
                        }
-                       close(keep_fd);
+                       if (close(keep_fd) != 0)
+                               die("cannot write keep file");
                        report = "keep";
                }
        }
@@ -830,6 +690,7 @@ int main(int argc, char **argv)
        const char *curr_index, *index_name = NULL;
        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];
 
        for (i = 1; i < argc; i++) {
@@ -865,12 +726,12 @@ int main(int argc, char **argv)
                                index_name = argv[++i];
                        } else if (!prefixcmp(arg, "--index-version=")) {
                                char *c;
-                               index_default_version = strtoul(arg + 16, &c, 10);
-                               if (index_default_version > 2)
+                               pack_idx_default_version = strtoul(arg + 16, &c, 10);
+                               if (pack_idx_default_version > 2)
                                        die("bad %s", arg);
                                if (*c == ',')
-                                       index_off32_limit = strtoul(c+1, &c, 0);
-                               if (*c || index_off32_limit & 0x80000000)
+                                       pack_idx_off32_limit = strtoul(c+1, &c, 0);
+                               if (*c || pack_idx_off32_limit & 0x80000000)
                                        die("bad %s", arg);
                        } else
                                usage(index_pack_usage);
@@ -940,7 +801,13 @@ int main(int argc, char **argv)
                            nr_deltas - nr_resolved_deltas);
        }
        free(deltas);
-       curr_index = write_index_file(index_name, sha1);
+
+       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);
+       free(idx_objects);
+
        final(pack_name, curr_pack,
                index_name, curr_index,
                keep_name, keep_msg,
index fb30694f4741147bba62350f704111d3afbf8133..00826778fc3d760a9b001423cd9c26e7972c126f 100644 (file)
@@ -44,33 +44,33 @@ void interp_clear_table(struct interp *table, int ninterps)
  *        { "%%", "%"},
  *    }
  *
- * Returns 1 on a successful substitution pass that fits in result,
- * Returns 0 on a failed or overflowing substitution pass.
+ * Returns 0 on a successful substitution pass that fits in result,
+ * Returns a number of bytes needed to hold the full substituted
+ * string otherwise.
  */
 
-int interpolate(char *result, int reslen,
+unsigned long interpolate(char *result, unsigned long reslen,
                const char *orig,
                const struct interp *interps, int ninterps)
 {
        const char *src = orig;
        char *dest = result;
-       int newlen = 0;
+       unsigned long newlen = 0;
        const char *name, *value;
-       int namelen, valuelen;
+       unsigned long namelen, valuelen;
        int i;
        char c;
 
         memset(result, 0, reslen);
 
-       while ((c = *src) && newlen < reslen - 1) {
+       while ((c = *src)) {
                if (c == '%') {
                        /* Try to match an interpolation string. */
                        for (i = 0; i < ninterps; i++) {
                                name = interps[i].name;
                                namelen = strlen(name);
-                               if (strncmp(src, name, namelen) == 0) {
+                               if (strncmp(src, name, namelen) == 0)
                                        break;
-                               }
                        }
 
                        /* Check for valid interpolation. */
@@ -78,29 +78,25 @@ int interpolate(char *result, int reslen,
                                value = interps[i].value;
                                valuelen = strlen(value);
 
-                               if (newlen + valuelen < reslen - 1) {
+                               if (newlen + valuelen + 1 < reslen) {
                                        /* Substitute. */
                                        strncpy(dest, value, valuelen);
-                                       newlen += valuelen;
                                        dest += valuelen;
-                                       src += namelen;
-                               } else {
-                                       /* Something's not fitting. */
-                                       return 0;
                                }
-
-                       } else {
-                               /* Skip bogus interpolation. */
-                               *dest++ = *src++;
-                               newlen++;
+                               newlen += valuelen;
+                               src += namelen;
+                               continue;
                        }
-
-               } else {
-                       /* Straight copy one non-interpolation character. */
-                       *dest++ = *src++;
-                       newlen++;
                }
+               /* Straight copy one non-interpolation character. */
+               if (newlen + 1 < reslen)
+                       *dest++ = *src;
+               src++;
+               newlen++;
        }
 
-       return newlen < reslen - 1;
+       if (newlen + 1 < reslen)
+               return 0;
+       else
+               return newlen + 2;
 }
index 16a26b998699a8a5a5b3472f4b57a574a292beef..77407e67dca97eb85274c69e2e7469e1d4d40b3b 100644 (file)
@@ -19,8 +19,8 @@ struct interp {
 extern void interp_set_entry(struct interp *table, int slot, const char *value);
 extern void interp_clear_table(struct interp *table, int ninterps);
 
-extern int interpolate(char *result, int reslen,
-                      const char *orig,
-                      const struct interp *interps, int ninterps);
+extern unsigned long interpolate(char *result, unsigned long reslen,
+                                const char *orig,
+                                const struct interp *interps, int ninterps);
 
 #endif /* INTERPOLATE_H */
index 310f8d39082a12d2c3daddd1fca454686e7425c3..e5c88c278fe23eefbf4cb4dd0c66251b208e48bd 100644 (file)
@@ -87,7 +87,7 @@ static void process_tree(struct rev_info *revs,
                        process_tree(revs,
                                     lookup_tree(entry.sha1),
                                     p, &me, entry.path);
-               else if (S_ISDIRLNK(entry.mode))
+               else if (S_ISGITLINK(entry.mode))
                        process_gitlink(revs, entry.sha1,
                                        p, &me, entry.path);
                else
index 4b650efa8b19424a61566b7ec87e7808874a6721..bf7ec6c2a3e25d09d3a43047d0cf3e1e6f883178 100644 (file)
@@ -114,7 +114,7 @@ static int fetch_pack(const unsigned char *sha1)
                return -1;
        target = find_sha1_pack(sha1, packs);
        if (!target)
-               return error("Couldn't find %s: not separate or in any pack", 
+               return error("Couldn't find %s: not separate or in any pack",
                             sha1_to_hex(sha1));
        if (get_verbosely) {
                fprintf(stderr, "Getting pack %s\n",
@@ -122,11 +122,11 @@ static int fetch_pack(const unsigned char *sha1)
                fprintf(stderr, " which contains %s\n",
                        sha1_to_hex(sha1));
        }
-       sprintf(filename, "%s/objects/pack/pack-%s.pack", 
+       sprintf(filename, "%s/objects/pack/pack-%s.pack",
                path, sha1_to_hex(target->sha1));
        copy_file(filename, sha1_pack_name(target->sha1),
                  sha1_to_hex(target->sha1), 1);
-       sprintf(filename, "%s/objects/pack/pack-%s.idx", 
+       sprintf(filename, "%s/objects/pack/pack-%s.idx",
                path, sha1_to_hex(target->sha1));
        copy_file(filename, sha1_pack_index_name(target->sha1),
                  sha1_to_hex(target->sha1), 1);
@@ -141,7 +141,7 @@ static int fetch_file(const unsigned char *sha1)
        char *hex = sha1_to_hex(sha1);
        char *dest_filename = sha1_file_name(sha1);
 
-       if (object_name_start < 0) {
+       if (object_name_start < 0) {
                strcpy(filename, path); /* e.g. git.git */
                strcat(filename, "/objects/");
                object_name_start = strlen(filename);
index 23db35aff21d7c33197726128e2f120291e6e9f0..5ad2858b4885022141d915fa0555c51f80d11c1c 100644 (file)
@@ -97,4 +97,3 @@ void rollback_lock_file(struct lock_file *lk)
                unlink(lk->filename);
        lk->filename[0] = 0;
 }
-
index 4bef909144b2b5b402ee7cf0d959a0995c00ff0e..8624d5a39ca3119fe7c4204a2c3b1f272a4b609d 100644 (file)
@@ -79,16 +79,25 @@ static int detect_any_signoff(char *letter, int size)
        return seen_head && seen_name;
 }
 
-static int append_signoff(char *buf, int buf_sz, int at, const char *signoff)
+static unsigned long append_signoff(char **buf_p, unsigned long *buf_sz_p,
+                                   unsigned long at, const char *signoff)
 {
        static const char signed_off_by[] = "Signed-off-by: ";
-       int signoff_len = strlen(signoff);
+       size_t signoff_len = strlen(signoff);
        int has_signoff = 0;
-       char *cp = buf;
-
-       /* Do we have enough space to add it? */
-       if (buf_sz - at <= strlen(signed_off_by) + signoff_len + 3)
-               return at;
+       char *cp;
+       char *buf;
+       unsigned long buf_sz;
+
+       buf = *buf_p;
+       buf_sz = *buf_sz_p;
+       if (buf_sz <= at + strlen(signed_off_by) + signoff_len + 3) {
+               buf_sz += strlen(signed_off_by) + signoff_len + 3;
+               buf = xrealloc(buf, buf_sz);
+               *buf_p = buf;
+               *buf_sz_p = buf_sz;
+       }
+       cp = buf;
 
        /* First see if we already have the sign-off by the signer */
        while ((cp = strstr(cp, signed_off_by))) {
@@ -133,7 +142,8 @@ static unsigned int digits_in_number(unsigned int number)
 
 void show_log(struct rev_info *opt, const char *sep)
 {
-       static char this_header[16384];
+       char *msgbuf = NULL;
+       unsigned long msgbuf_len = 0;
        struct log_info *log = opt->loginfo;
        struct commit *commit = log->commit, *parent = log->parent;
        int abbrev = opt->diffopt.abbrev;
@@ -190,7 +200,7 @@ void show_log(struct rev_info *opt, const char *sep)
                                        digits_in_number(opt->total),
                                        opt->nr, opt->total);
                        subject = buffer;
-               } else if (opt->total == 0) {
+               } else if (opt->total == 0 && opt->subject_prefix && *opt->subject_prefix) {
                        static char buffer[256];
                        snprintf(buffer, sizeof(buffer),
                                        "Subject: [%s] ",
@@ -278,14 +288,15 @@ void show_log(struct rev_info *opt, const char *sep)
        /*
         * And then the pretty-printed message itself
         */
-       len = pretty_print_commit(opt->commit_format, commit, ~0u, this_header,
-                                 sizeof(this_header), abbrev, subject,
+       len = pretty_print_commit(opt->commit_format, commit, ~0u,
+                                 &msgbuf, &msgbuf_len, abbrev, subject,
                                  extra_headers, opt->date_mode);
 
        if (opt->add_signoff)
-               len = append_signoff(this_header, sizeof(this_header), len,
+               len = append_signoff(&msgbuf, &msgbuf_len, len,
                                     opt->add_signoff);
-       printf("%s%s%s", this_header, extra, sep);
+       printf("%s%s%s", msgbuf, extra, sep);
+       free(msgbuf);
 }
 
 int log_tree_diff_flush(struct rev_info *opt)
@@ -397,5 +408,6 @@ int log_tree_commit(struct rev_info *opt, struct commit *commit)
                shown = 1;
        }
        opt->loginfo = NULL;
+       maybe_flush_or_die(stdout, "stdout");
        return shown;
 }
index cb567a2832d9f8c784aea388af9144c12eddc7d5..87141670595c50a4fa7b87a12b85ff0e2b7da8af 100644 (file)
--- a/mailmap.c
+++ b/mailmap.c
@@ -89,4 +89,3 @@ int map_email(struct path_list *map, const char *email, char *name, int maxlen)
        }
        return 0;
 }
-
index 23cafe47b495ba40fbdd46eb35943be5f722a1d7..d7e29c4d1d3e44c85e0eeb28040e8ea945090594 100644 (file)
@@ -301,4 +301,3 @@ void shift_tree(const unsigned char *hash1,
 
        splice_tree(hash1, add_prefix, hash2, shifted);
 }
-
index 748d15c0e04c0d63fbe586ad59c795ddaf3dec92..1e031eafe0c70eec092a53e8ab291b9887622b0e 100644 (file)
@@ -62,6 +62,7 @@ static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2)
        xdemitcb_t ecb;
 
        xpp.flags = XDF_NEED_MINIMAL;
+       memset(&xecfg, 0, sizeof(xecfg));
        xecfg.ctxlen = 3;
        xecfg.flags = XDL_EMIT_COMMON;
        ecb.outf = common_outf;
index 5599fd321bb4c09c1c0ce4fc62dfb9ecf5531c2b..fa719cb0b1bd227423587c9e41eed77c755465a4 100644 (file)
@@ -25,7 +25,7 @@ static void run_program(void)
 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);
        arguments[0] = pgm;
index 4a82b741ae020376ac67b34d5fce86e8a87a3b5d..c8539ec0bafce5e238d97d6397a9d08c2c92a09c 100644 (file)
@@ -127,7 +127,7 @@ static void output(int v, const char *fmt, ...)
        va_end(args);
 }
 
-static void flush_output()
+static void flush_output(void)
 {
        struct output_buffer *b, *n;
        for (b = output_list; b; b = n) {
index 3b8d9e6887ae051bf61cc0833f97d83bb47a0bae..7d4f628444058d80e798e141285d558fb7104c5b 100644 (file)
@@ -106,8 +106,8 @@ static void show_diff(struct merge_list *entry)
        xdemitcb_t ecb;
 
        xpp.flags = XDF_NEED_MINIMAL;
+       memset(&xecfg, 0, sizeof(xecfg));
        xecfg.ctxlen = 3;
-       xecfg.flags = 0;
        ecb.outf = show_outf;
        ecb.priv = NULL;
 
diff --git a/mktag.c b/mktag.c
index 931011121e7276513b55fc41691c65a0d924119d..b82e377bd826617810488ea8c92a4135bceebda6 100644 (file)
--- a/mktag.c
+++ b/mktag.c
  * The first three lines are guaranteed to be at least 63 bytes:
  * "object <sha1>\n" is 48 bytes, "type tag\n" at 9 bytes is the
  * shortest possible type-line, and "tag .\n" at 6 bytes is the
- * shortest single-character-tag line. 
- *
- * We also artificially limit the size of the full object to 8kB.
- * Just because I'm a lazy bastard, and if you can't fit a signature
- * in that size, you're doing something wrong.
+ * shortest single-character-tag line.
  */
 
-/* Some random size */
-#define MAXSIZE (8192)
-
 /*
  * We refuse to tag something we can't verify. Just because.
  */
index 847531d19f88e420ad68f95f11ab2f1f77876d08..3f06b835675206912777a774d91c3ba611fa5a06 100644 (file)
@@ -1,29 +1,29 @@
-/* 
+/*
  * The contents of this file are subject to the Mozilla Public
  * License Version 1.1 (the "License"); you may not use this file
  * except in compliance with the License. You may obtain a copy of
  * the License at http://www.mozilla.org/MPL/
- * 
+ *
  * Software distributed under the License is distributed on an "AS
  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  * implied. See the License for the specific language governing
  * rights and limitations under the License.
- * 
+ *
  * The Original Code is SHA 180-1 Reference Implementation (Compact version)
- * 
+ *
  * The Initial Developer of the Original Code is Paul Kocher of
- * Cryptography Research.  Portions created by Paul Kocher are 
+ * Cryptography Research.  Portions created by Paul Kocher are
  * Copyright (C) 1995-9 by Cryptography Research, Inc.  All
  * Rights Reserved.
- * 
+ *
  * Contributor(s):
  *
  *     Paul Kocher
- * 
+ *
  * Alternatively, the contents of this file may be used under the
  * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable 
- * instead of those above.  If you wish to allow use of your 
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above.  If you wish to allow use of your
  * version of this file only under the terms of the GPL and not to
  * allow others to use your version of this file under the MPL,
  * indicate your decision by deleting the provisions above and
@@ -149,4 +149,3 @@ static void shaHashBlock(SHA_CTX *ctx) {
   ctx->H[3] += D;
   ctx->H[4] += E;
 }
-
index 5d82afa3bdd21a2855c569a73cf3277b5c6a41bc..16f2d3d43ca8bee1eeb306308277bef8c707a972 100644 (file)
@@ -1,29 +1,29 @@
-/* 
+/*
  * The contents of this file are subject to the Mozilla Public
  * License Version 1.1 (the "License"); you may not use this file
  * except in compliance with the License. You may obtain a copy of
  * the License at http://www.mozilla.org/MPL/
- * 
+ *
  * Software distributed under the License is distributed on an "AS
  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  * implied. See the License for the specific language governing
  * rights and limitations under the License.
- * 
+ *
  * The Original Code is SHA 180-1 Header File
- * 
+ *
  * The Initial Developer of the Original Code is Paul Kocher of
- * Cryptography Research.  Portions created by Paul Kocher are 
+ * Cryptography Research.  Portions created by Paul Kocher are
  * Copyright (C) 1995-9 by Cryptography Research, Inc.  All
  * Rights Reserved.
- * 
+ *
  * Contributor(s):
  *
  *     Paul Kocher
- * 
+ *
  * Alternatively, the contents of this file may be used under the
  * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable 
- * instead of those above.  If you wish to allow use of your 
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above.  If you wish to allow use of your
  * version of this file only under the terms of the GPL and not to
  * allow others to use your version of this file under the MPL,
  * indicate your decision by deleting the provisions above and
index 022e8d841c7f5498b6f008647ed37c430826b443..5345671569e9500ad31124dacf9525739687d9be 100644 (file)
@@ -85,5 +85,3 @@ void mark_reachable(struct object *obj, unsigned int mask)
                        mark_reachable(refs->ref[i], mask);
        }
 }
-
-
index 94f19eed86ceebcc85770a379faf7b1270d1fad4..397bbfa090cd281214013c42a5f0b1de6063a861 100644 (file)
--- a/object.h
+++ b/object.h
@@ -66,7 +66,7 @@ void set_object_refs(struct object *obj, struct object_refs *refs);
 
 void mark_reachable(struct object *obj, unsigned int mask);
 
-struct object_list *object_list_insert(struct object *item, 
+struct object_list *object_list_insert(struct object *item,
                                       struct object_list **list_p);
 
 void object_list_append(struct object *item,
index d04536bbff7cba22ca67521d45e690dfa5aa8675..d7dd62bb8346c4cac8dbd7334e999a450c21c5ab 100644 (file)
@@ -1,6 +1,23 @@
 #include "cache.h"
 #include "pack.h"
 
+struct idx_entry
+{
+       const unsigned char *sha1;
+       off_t                offset;
+};
+
+static int compare_entries(const void *e1, const void *e2)
+{
+       const struct idx_entry *entry1 = e1;
+       const struct idx_entry *entry2 = e2;
+       if (entry1->offset < entry2->offset)
+               return -1;
+       if (entry1->offset > entry2->offset)
+               return 1;
+       return 0;
+}
+
 static int verify_packfile(struct packed_git *p,
                struct pack_window **w_curs)
 {
@@ -11,6 +28,7 @@ static int verify_packfile(struct packed_git *p,
        off_t offset = 0, pack_sig = p->pack_size - 20;
        uint32_t nr_objects, i;
        int err;
+       struct idx_entry *entries;
 
        /* Note that the pack header checks are actually performed by
         * use_pack when it first opens the pack file.  If anything
@@ -41,44 +59,48 @@ static int verify_packfile(struct packed_git *p,
         * we do not do scan-streaming check on the pack file.
         */
        nr_objects = p->num_objects;
+       entries = xmalloc(nr_objects * sizeof(*entries));
+       /* first sort entries by pack offset, since unpacking them is more efficient that way */
+       for (i = 0; i < nr_objects; i++) {
+               entries[i].sha1 = nth_packed_object_sha1(p, i);
+               if (!entries[i].sha1)
+                       die("internal error pack-check nth-packed-object");
+               entries[i].offset = find_pack_entry_one(entries[i].sha1, p);
+               if (!entries[i].offset)
+                       die("internal error pack-check find-pack-entry-one");
+       }
+       qsort(entries, nr_objects, sizeof(*entries), compare_entries);
+
        for (i = 0, err = 0; i < nr_objects; i++) {
-               const unsigned char *sha1;
                void *data;
                enum object_type type;
                unsigned long size;
-               off_t offset;
 
-               sha1 = nth_packed_object_sha1(p, i);
-               if (!sha1)
-                       die("internal error pack-check nth-packed-object");
-               offset = find_pack_entry_one(sha1, p);
-               if (!offset)
-                       die("internal error pack-check find-pack-entry-one");
-               data = unpack_entry(p, offset, &type, &size);
+               data = unpack_entry(p, entries[i].offset, &type, &size);
                if (!data) {
                        err = error("cannot unpack %s from %s",
-                                   sha1_to_hex(sha1), p->pack_name);
+                                   sha1_to_hex(entries[i].sha1), p->pack_name);
                        continue;
                }
-               if (check_sha1_signature(sha1, data, size, typename(type))) {
+               if (check_sha1_signature(entries[i].sha1, data, size, typename(type))) {
                        err = error("packed %s from %s is corrupt",
-                                   sha1_to_hex(sha1), p->pack_name);
+                                   sha1_to_hex(entries[i].sha1), p->pack_name);
                        free(data);
                        continue;
                }
                free(data);
        }
+       free(entries);
 
        return err;
 }
 
 
-#define MAX_CHAIN 40
+#define MAX_CHAIN 50
 
 static void show_pack_info(struct packed_git *p)
 {
-       uint32_t nr_objects, i, chain_histogram[MAX_CHAIN];
-
+       uint32_t nr_objects, i, chain_histogram[MAX_CHAIN+1];
        nr_objects = p->num_objects;
        memset(chain_histogram, 0, sizeof(chain_histogram));
 
@@ -109,32 +131,37 @@ static void show_pack_info(struct packed_git *p)
                        printf("%-6s %lu %"PRIuMAX" %u %s\n",
                               type, size, (uintmax_t)offset,
                               delta_chain_length, sha1_to_hex(base_sha1));
-                       if (delta_chain_length < MAX_CHAIN)
+                       if (delta_chain_length <= MAX_CHAIN)
                                chain_histogram[delta_chain_length]++;
                        else
                                chain_histogram[0]++;
                }
        }
 
-       for (i = 0; i < MAX_CHAIN; i++) {
+       for (i = 0; i <= MAX_CHAIN; i++) {
                if (!chain_histogram[i])
                        continue;
-               printf("chain length %s %d: %d object%s\n",
-                      i ? "=" : ">=",
-                      i ? i : MAX_CHAIN,
-                      chain_histogram[i],
-                      1 < chain_histogram[i] ? "s" : "");
+               printf("chain length = %d: %d object%s\n", i,
+                      chain_histogram[i], chain_histogram[i] > 1 ? "s" : "");
        }
+       if (chain_histogram[0])
+               printf("chain length > %d: %d object%s\n", MAX_CHAIN,
+                      chain_histogram[0], chain_histogram[0] > 1 ? "s" : "");
 }
 
 int verify_pack(struct packed_git *p, int verbose)
 {
-       off_t index_size = p->index_size;
-       const unsigned char *index_base = p->index_data;
+       off_t index_size;
+       const unsigned char *index_base;
        SHA_CTX ctx;
        unsigned char sha1[20];
        int ret;
 
+       if (open_pack_index(p))
+               return error("packfile %s index not opened", p->pack_name);
+       index_size = p->index_size;
+       index_base = p->index_data;
+
        ret = 0;
        /* Verify SHA1 sum of the index file */
        SHA1_Init(&ctx);
index 87077e150c1b53a26464089a2cabafafb32e6636..f5cd0ac59e5794a375172b998399a546eaef4ab1 100644 (file)
@@ -81,7 +81,7 @@ static struct llist * llist_copy(struct llist *list)
 {
        struct llist *ret;
        struct llist_item *new, *old, *prev;
-       
+
        llist_init(&ret);
 
        if ((ret->size = list->size) == 0)
@@ -100,7 +100,7 @@ static struct llist * llist_copy(struct llist *list)
        }
        new->next = NULL;
        ret->back = new;
-       
+
        return ret;
 }
 
@@ -550,6 +550,9 @@ static struct pack_list * add_pack(struct packed_git *p)
        l.pack = p;
        llist_init(&l.all_objects);
 
+       if (open_pack_index(p))
+               return NULL;
+
        base = p->index_data;
        base += 256 * 4 + ((p->index_version < 2) ? 4 : 8);
        step = (p->index_version < 2) ? 24 : 20;
index ae2e481e5554cfa66cf137d38c38f961b9aa8ec7..1cf5f7c9f0956a457de03c64238d298a9d996984 100644 (file)
@@ -1,5 +1,147 @@
 #include "cache.h"
 #include "pack.h"
+#include "csum-file.h"
+
+uint32_t pack_idx_default_version = 1;
+uint32_t pack_idx_off32_limit = 0x7fffffff;
+
+static int sha1_compare(const void *_a, const void *_b)
+{
+       struct pack_idx_entry *a = *(struct pack_idx_entry **)_a;
+       struct pack_idx_entry *b = *(struct pack_idx_entry **)_b;
+       return hashcmp(a->sha1, b->sha1);
+}
+
+/*
+ * On entry *sha1 contains the pack content SHA1 hash, on exit it is
+ * the SHA1 hash of sorted object names. The objects array passed in
+ * will be sorted by SHA1 on exit.
+ */
+const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1)
+{
+       struct sha1file *f;
+       struct pack_idx_entry **sorted_by_sha, **list, **last;
+       off_t last_obj_offset = 0;
+       uint32_t array[256];
+       int i, fd;
+       SHA_CTX ctx;
+       uint32_t index_version;
+
+       if (nr_objects) {
+               sorted_by_sha = objects;
+               list = sorted_by_sha;
+               last = sorted_by_sha + nr_objects;
+               for (i = 0; i < nr_objects; ++i) {
+                       if (objects[i]->offset > last_obj_offset)
+                               last_obj_offset = objects[i]->offset;
+               }
+               qsort(sorted_by_sha, nr_objects, sizeof(sorted_by_sha[0]),
+                     sha1_compare);
+       }
+       else
+               sorted_by_sha = list = last = NULL;
+
+       if (!index_name) {
+               static char tmpfile[PATH_MAX];
+               snprintf(tmpfile, sizeof(tmpfile),
+                        "%s/tmp_idx_XXXXXX", get_object_directory());
+               fd = mkstemp(tmpfile);
+               index_name = xstrdup(tmpfile);
+       } else {
+               unlink(index_name);
+               fd = open(index_name, O_CREAT|O_EXCL|O_WRONLY, 0600);
+       }
+       if (fd < 0)
+               die("unable to create %s: %s", index_name, strerror(errno));
+       f = sha1fd(fd, index_name);
+
+       /* if last object's offset is >= 2^31 we should use index V2 */
+       index_version = (last_obj_offset >> 31) ? 2 : pack_idx_default_version;
+
+       /* index versions 2 and above need a header */
+       if (index_version >= 2) {
+               struct pack_idx_header hdr;
+               hdr.idx_signature = htonl(PACK_IDX_SIGNATURE);
+               hdr.idx_version = htonl(index_version);
+               sha1write(f, &hdr, sizeof(hdr));
+       }
+
+       /*
+        * Write the first-level table (the list is sorted,
+        * but we use a 256-entry lookup to be able to avoid
+        * having to do eight extra binary search iterations).
+        */
+       for (i = 0; i < 256; i++) {
+               struct pack_idx_entry **next = list;
+               while (next < last) {
+                       struct pack_idx_entry *obj = *next;
+                       if (obj->sha1[0] != i)
+                               break;
+                       next++;
+               }
+               array[i] = htonl(next - sorted_by_sha);
+               list = next;
+       }
+       sha1write(f, array, 256 * 4);
+
+       /* compute the SHA1 hash of sorted object names. */
+       SHA1_Init(&ctx);
+
+       /*
+        * Write the actual SHA1 entries..
+        */
+       list = sorted_by_sha;
+       for (i = 0; i < nr_objects; i++) {
+               struct pack_idx_entry *obj = *list++;
+               if (index_version < 2) {
+                       uint32_t offset = htonl(obj->offset);
+                       sha1write(f, &offset, 4);
+               }
+               sha1write(f, obj->sha1, 20);
+               SHA1_Update(&ctx, obj->sha1, 20);
+       }
+
+       if (index_version >= 2) {
+               unsigned int nr_large_offset = 0;
+
+               /* write the crc32 table */
+               list = sorted_by_sha;
+               for (i = 0; i < nr_objects; i++) {
+                       struct pack_idx_entry *obj = *list++;
+                       uint32_t crc32_val = htonl(obj->crc32);
+                       sha1write(f, &crc32_val, 4);
+               }
+
+               /* write the 32-bit offset table */
+               list = sorted_by_sha;
+               for (i = 0; i < nr_objects; i++) {
+                       struct pack_idx_entry *obj = *list++;
+                       uint32_t offset = (obj->offset <= pack_idx_off32_limit) ?
+                               obj->offset : (0x80000000 | nr_large_offset++);
+                       offset = htonl(offset);
+                       sha1write(f, &offset, 4);
+               }
+
+               /* write the large offset table */
+               list = sorted_by_sha;
+               while (nr_large_offset) {
+                       struct pack_idx_entry *obj = *list++;
+                       uint64_t offset = obj->offset;
+                       if (offset > pack_idx_off32_limit) {
+                               uint32_t split[2];
+                               split[0] = htonl(offset >> 32);
+                               split[1] = htonl(offset & 0xffffffff);
+                               sha1write(f, split, 8);
+                               nr_large_offset--;
+                       }
+               }
+       }
+
+       sha1write(f, sha1, 20);
+       sha1close(f, NULL, 1);
+       SHA1_Final(sha1, &ctx);
+       return index_name;
+}
 
 void fixup_pack_header_footer(int pack_fd,
                         unsigned char *pack_file_sha1,
diff --git a/pack.h b/pack.h
index d667fb8d5a49b4480beaa6f384f1f6f86b035806..f357c9f4282d5bc8bbcff6f3a44b9812415745a6 100644 (file)
--- a/pack.h
+++ b/pack.h
@@ -34,6 +34,10 @@ struct pack_header {
  */
 #define PACK_IDX_SIGNATURE 0xff744f63  /* "\377tOc" */
 
+/* These may be overridden by command-line parameters */
+extern uint32_t pack_idx_default_version;
+extern uint32_t pack_idx_off32_limit;
+
 /*
  * Packed object index header
  */
@@ -42,6 +46,16 @@ struct pack_idx_header {
        uint32_t idx_version;
 };
 
+/*
+ * Common part of object structure used for write_idx_file
+ */
+struct pack_idx_entry {
+       unsigned char sha1[20];
+       uint32_t crc32;
+       off_t offset;
+};
+
+extern const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1);
 
 extern int verify_pack(struct packed_git *, int);
 extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t);
diff --git a/pager.c b/pager.c
index 5f280ab52720772905cacbcba522ecc9c81bb529..3bfed025996bbdc31aebd4a7b096236c538a4e75 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -31,6 +31,8 @@ void setup_pager(void)
 
        if (!isatty(1))
                return;
+       if (!pager)
+               pager = pager_program;
        if (!pager)
                pager = getenv("PAGER");
        if (!pager)
index 086d2d9c68835c6a7434932f6e3b430e0906578d..9349bc5580456b378d41da7cc2518e4fa9a7e81a 100644 (file)
@@ -81,4 +81,4 @@ int main(int argc, char **argv)
 
        generate_id_list();
        return 0;
-}      
+}
index caaa5cc57b05e1a27bb4fd8f49bb74e06b9936e3..dcb4b3ac139a5a264df04d91cee17679efe55aa6 100644 (file)
@@ -100,4 +100,3 @@ void print_path_list(const char *text, const struct path_list *p)
        for (i = 0; i < p->nr; i++)
                printf("%s:%p\n", p->items[i].path, p->items[i].util);
 }
-
diff --git a/path.c b/path.c
index 6395cf23098841c16d993ae7e86b2d8dcff01cd7..c4ce96236ae043b4d997536174936abb6ac40207 100644 (file)
--- a/path.c
+++ b/path.c
@@ -252,7 +252,7 @@ char *enter_repo(char *path, int strict)
 
        if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
            validate_headref("HEAD") == 0) {
-               setenv("GIT_DIR", ".", 1);
+               setenv(GIT_DIR_ENVIRONMENT, ".", 1);
                check_repository_format();
                return path;
        }
index 96bfac498bdc58c90c9bc136a1df7bac9bfa0d92..ceb787170e17df130e26658e5a189bb63684ab3e 100644 (file)
@@ -64,7 +64,7 @@ int main(int argc, char **argv)
        if (!dest || i != argc - 1)
                usage(peek_remote_usage);
 
-       pid = git_connect(fd, dest, uploadpack);
+       pid = git_connect(fd, dest, uploadpack, 0);
        if (pid < 0)
                return 1;
        ret = peek_remote(fd, flags);
index 0d695fd2f35f91b47455dc382d86b52bb51088d2..5e079ad01126845c39fd9583fa742f54d5658b49 100644 (file)
@@ -40,4 +40,3 @@ endif
 # (even though GIT-CFLAGS aren't used yet. If ever)
 ../GIT-CFLAGS:
        $(MAKE) -C .. GIT-CFLAGS
-
index b60526869a38bd20f800c275f7b42390c8bea1ee..355546a1ad844492234dc7ee91528c525af5610a 100644 (file)
@@ -5,7 +5,7 @@
  * Write a packetized stream, where each line is preceded by
  * its length (including the header) as a 4-byte hex number.
  * A length of 'zero' means end of stream (and a length of 1-3
- * would be an error). 
+ * would be an error).
  *
  * This is all pretty stupid, but we use this packetized line
  * format to make a streaming format possible without ever
index 0820398b004dd8af93a25e7fa26be60cf4dda410..738e36c1e81def4822ccc2a66bc2761402a07f26 100644 (file)
@@ -50,7 +50,7 @@ int SHA1_Update(SHA_CTX *c, const void *ptr, unsigned long n)
                p += nb;
        }
        return 0;
-}      
+}
 
 int SHA1_Final(unsigned char *hash, SHA_CTX *c)
 {
index 05f7890314e0bd596eb2e4110cdb98eeea61c9da..4344f4eed5e46c4e013018af8ef9ab062f740d8f 100644 (file)
@@ -62,11 +62,13 @@ int display_progress(struct progress *progress, unsigned n)
                        fprintf(stderr, "%s%4u%% (%u/%u) done\r",
                                progress->prefix, percent, n, progress->total);
                        progress_update = 0;
+                       progress->need_lf = 1;
                        return 1;
                }
        } else if (progress_update) {
                fprintf(stderr, "%s%u\r", progress->prefix, n);
                progress_update = 0;
+               progress->need_lf = 1;
                return 1;
        }
        return 0;
@@ -80,6 +82,7 @@ void start_progress(struct progress *progress, const char *title,
        progress->total = total;
        progress->last_percent = -1;
        progress->delay = 0;
+       progress->need_lf = 0;
        if (snprintf(buf, sizeof(buf), title, total))
                fprintf(stderr, "%s\n", buf);
        set_progress_signal();
@@ -95,12 +98,13 @@ void start_progress_delay(struct progress *progress, const char *title,
        progress->delayed_percent_treshold = percent_treshold;
        progress->delayed_title = title;
        progress->delay = delay;
+       progress->need_lf = 0;
        set_progress_signal();
 }
 
 void stop_progress(struct progress *progress)
 {
        clear_progress_signal();
-       if (progress->total)
+       if (progress->need_lf)
                fputc('\n', stderr);
 }
index 5ae1a89e5a4669553e44d5bd0cc339c308c60c0f..a7c17ca7c4bdad953508d03c20e73022b03bd25a 100644 (file)
@@ -8,6 +8,7 @@ struct progress {
        unsigned delay;
        unsigned delayed_percent_treshold;
        const char *delayed_title;
+       int need_lf;
 };
 
 int display_progress(struct progress *progress, unsigned n);
diff --git a/quote.c b/quote.c
index fb9e4ca253ea9bcadbcb55dcdd62be614c66758f..d88bf7515932bba96c694478c3b51c85549fa92a 100644 (file)
--- a/quote.c
+++ b/quote.c
@@ -20,7 +20,7 @@ static inline int need_bs_quote(char c)
        return (c == '\'' || c == '!');
 }
 
-size_t sq_quote_buf(char *dst, size_t n, const char *src)
+static size_t sq_quote_buf(char *dst, size_t n, const char *src)
 {
        char c;
        char *bp = dst;
@@ -62,18 +62,6 @@ void sq_quote_print(FILE *stream, const char *src)
        fputc('\'', stream);
 }
 
-char *sq_quote(const char *src)
-{
-       char *buf;
-       size_t cnt;
-
-       cnt = sq_quote_buf(NULL, 0, src) + 1;
-       buf = xmalloc(cnt);
-       sq_quote_buf(buf, cnt, src);
-
-       return buf;
-}
-
 char *sq_quote_argv(const char** argv, int count)
 {
        char *buf, *to;
@@ -200,7 +188,8 @@ static int quote_c_style_counted(const char *name, int namelen,
 #define EMITQ() EMIT('\\')
 
        const char *sp;
-       int ch, count = 0, needquote = 0;
+       unsigned char ch;
+       int count = 0, needquote = 0;
 
        if (!no_dq)
                EMIT('"');
@@ -209,7 +198,7 @@ static int quote_c_style_counted(const char *name, int namelen,
                if (!ch)
                        break;
                if ((ch < ' ') || (ch == '"') || (ch == '\\') ||
-                   (ch >= 0177)) {
+                   (quote_path_fully && (ch >= 0177))) {
                        needquote = 1;
                        switch (ch) {
                        case '\a': EMITQ(); ch = 'a'; break;
diff --git a/quote.h b/quote.h
index bdc3610df51000baeda49da1eeaec20ccb2682fb..8a59cc55d1dcfba728614b2d6494272ceafbf3a1 100644 (file)
--- a/quote.h
+++ b/quote.h
@@ -28,9 +28,7 @@
  * excluding the final null regardless of the buffer size.
  */
 
-extern char *sq_quote(const char *src);
 extern void sq_quote_print(FILE *stream, const char *src);
-extern size_t sq_quote_buf(char *dst, size_t n, const char *src);
 extern char *sq_quote_argv(const char** argv, int count);
 
 /*
index c1aee603e7df68d6a12ce25b183c478d7da6ab4e..6383401e2dd6bef3251a105ac136312dfdcdeb3c 100644 (file)
@@ -55,7 +55,7 @@ static void process_tree(struct tree *tree,
        while (tree_entry(&desc, &entry)) {
                if (S_ISDIR(entry.mode))
                        process_tree(lookup_tree(entry.sha1), p, &me, entry.path);
-               else if (S_ISDIRLNK(entry.mode))
+               else if (S_ISGITLINK(entry.mode))
                        process_gitlink(entry.sha1, p, &me, entry.path);
                else
                        process_blob(lookup_blob(entry.sha1), p, &me, entry.path);
@@ -176,7 +176,7 @@ static void add_cache_refs(struct rev_info *revs)
                 * lookup_blob() on them, to avoid populating the hash table
                 * with invalid information
                 */
-               if (S_ISDIRLNK(ntohl(active_cache[i]->ce_mode)))
+               if (S_ISGITLINK(ntohl(active_cache[i]->ce_mode)))
                        continue;
 
                lookup_blob(active_cache[i]->sha1);
index d9f46da5cc547d8cfaa34c901be50a13995b120e..a363f312c7f70d2a087dc16ebfe0969a03c1be42 100644 (file)
@@ -92,7 +92,7 @@ static int ce_compare_gitlink(struct cache_entry *ce)
 
        /*
         * We don't actually require that the .git directory
-        * under DIRLNK directory be a valid git directory. It
+        * under GITLINK directory be a valid git directory. It
         * might even be missing (in case nobody populated that
         * sub-project).
         *
@@ -115,7 +115,7 @@ static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st)
                        return DATA_CHANGED;
                break;
        case S_IFDIR:
-               if (S_ISDIRLNK(ntohl(ce->ce_mode)))
+               if (S_ISGITLINK(ntohl(ce->ce_mode)))
                        return 0;
        default:
                return TYPE_CHANGED;
@@ -142,7 +142,7 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
                    (has_symlinks || !S_ISREG(st->st_mode)))
                        changed |= TYPE_CHANGED;
                break;
-       case S_IFDIRLNK:
+       case S_IFGITLINK:
                if (!S_ISDIR(st->st_mode))
                        changed |= TYPE_CHANGED;
                else if (ce_compare_gitlink(ce))
@@ -166,7 +166,7 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
                changed |= MTIME_CHANGED;
        if (ce->ce_ctime.nsec != htonl(st->st_ctim.tv_nsec))
                changed |= CTIME_CHANGED;
-#endif 
+#endif
 
        if (ce->ce_uid != htonl(st->st_uid) ||
            ce->ce_gid != htonl(st->st_gid))
@@ -350,6 +350,34 @@ int remove_file_from_index(struct index_state *istate, const char *path)
        return 0;
 }
 
+static int compare_name(struct cache_entry *ce, const char *path, int namelen)
+{
+       return namelen != ce_namelen(ce) || memcmp(path, ce->name, namelen);
+}
+
+static int index_name_pos_also_unmerged(struct index_state *istate,
+       const char *path, int namelen)
+{
+       int pos = index_name_pos(istate, path, namelen);
+       struct cache_entry *ce;
+
+       if (pos >= 0)
+               return pos;
+
+       /* maybe unmerged? */
+       pos = -1 - pos;
+       if (pos >= istate->cache_nr ||
+                       compare_name((ce = istate->cache[pos]), path, namelen))
+               return -1;
+
+       /* order of preference: stage 2, 1, 3 */
+       if (ce_stage(ce) == 1 && pos + 1 < istate->cache_nr &&
+                       ce_stage((ce = istate->cache[pos + 1])) == 2 &&
+                       !compare_name(ce, path, namelen))
+               pos++;
+       return pos;
+}
+
 int add_file_to_index(struct index_state *istate, const char *path, int verbose)
 {
        int size, namelen;
@@ -380,7 +408,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose)
                 * from it, otherwise assume unexecutable regular file.
                 */
                struct cache_entry *ent;
-               int pos = index_name_pos(istate, path, namelen);
+               int pos = index_name_pos_also_unmerged(istate, path, namelen);
 
                ent = (0 <= pos) ? istate->cache[pos] : NULL;
                ce->ce_mode = ce_mode_from_stat(ent, st.st_mode);
@@ -597,7 +625,7 @@ static int has_dir_name(struct index_state *istate,
  * is being added, or we already have path and path/file is being
  * added.  Either one would result in a nonsense tree that has path
  * twice when git-write-tree tries to write it out.  Prevent it.
- * 
+ *
  * If ok-to-replace is specified, we remove the conflicting entries
  * from the cache so the caller should recompute the insert position.
  * When this happens, we return non-zero.
@@ -970,8 +998,8 @@ static int ce_write(SHA_CTX *context, int fd, void *data, unsigned int len)
                write_buffer_len = buffered;
                len -= partial;
                data = (char *) data + partial;
-       }
-       return 0;
+       }
+       return 0;
 }
 
 static int write_index_ext_header(SHA_CTX *context, int fd,
@@ -1037,7 +1065,7 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
                 * size to zero here, then the object name recorded
                 * in index is the 6-byte file but the cached stat information
                 * becomes zero --- which would then match what we would
-                * obtain from the filesystem next time we stat("frotz"). 
+                * obtain from the filesystem next time we stat("frotz").
                 *
                 * However, the second update-index, before calling
                 * this function, notices that the cached size is 6
index 26aa26bcb5089adcf400d12b673519e328b49a23..d3c422be58c5ee1af7e75cf4186bc9bbfb19ec30 100644 (file)
@@ -209,7 +209,7 @@ static const char *update(struct command *cmd)
                return NULL; /* good */
        }
        else {
-               lock = lock_any_ref_for_update(name, old_sha1);
+               lock = lock_any_ref_for_update(name, old_sha1, 0);
                if (!lock) {
                        error("failed to lock %s", name);
                        return "failed to lock";
diff --git a/refs.c b/refs.c
index 89876bff871d007a6675f5790ce8cb34fe21fb39..4dc7e8b47659b75cc0dcf334f1bf33798b2e5157 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -150,7 +150,7 @@ static struct ref_list *sort_ref_list(struct ref_list *list)
  * Future: need to be in "struct repository"
  * when doing a full libification.
  */
-struct cached_refs {
+static struct cached_refs {
        char did_loose;
        char did_packed;
        struct ref_list *loose;
@@ -603,15 +603,20 @@ int get_ref_sha1(const char *ref, unsigned char *sha1)
 
 static inline int bad_ref_char(int ch)
 {
-       return (((unsigned) ch) <= ' ' ||
-               ch == '~' || ch == '^' || ch == ':' ||
-               /* 2.13 Pattern Matching Notation */
-               ch == '?' || ch == '*' || ch == '[');
+       if (((unsigned) ch) <= ' ' ||
+           ch == '~' || ch == '^' || ch == ':')
+               return 1;
+       /* 2.13 Pattern Matching Notation */
+       if (ch == '?' || ch == '[') /* Unsupported */
+               return 1;
+       if (ch == '*') /* Supported at the end */
+               return 2;
+       return 0;
 }
 
 int check_ref_format(const char *ref)
 {
-       int ch, level;
+       int ch, level, bad_type;
        const char *cp = ref;
 
        level = 0;
@@ -622,13 +627,19 @@ int check_ref_format(const char *ref)
                        return -1; /* should not end with slashes */
 
                /* we are at the beginning of the path component */
-               if (ch == '.' || bad_ref_char(ch))
+               if (ch == '.')
                        return -1;
+               bad_type = bad_ref_char(ch);
+               if (bad_type) {
+                       return (bad_type == 2 && !*cp) ? -3 : -1;
+               }
 
                /* scan the rest of the path component */
                while ((ch = *cp++) != 0) {
-                       if (bad_ref_char(ch))
-                               return -1;
+                       bad_type = bad_ref_char(ch);
+                       if (bad_type) {
+                               return (bad_type == 2 && !*cp) ? -3 : -1;
+                       }
                        if (ch == '/')
                                break;
                        if (ch == '.' && *cp == '.')
@@ -736,19 +747,20 @@ static int is_refname_available(const char *ref, const char *oldref,
        return 1;
 }
 
-static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char *old_sha1, int *flag)
+static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char *old_sha1, int flags, int *type_p)
 {
        char *ref_file;
        const char *orig_ref = ref;
        struct ref_lock *lock;
        struct stat st;
        int last_errno = 0;
+       int type;
        int mustexist = (old_sha1 && !is_null_sha1(old_sha1));
 
        lock = xcalloc(1, sizeof(struct ref_lock));
        lock->lock_fd = -1;
 
-       ref = resolve_ref(ref, lock->old_sha1, mustexist, flag);
+       ref = resolve_ref(ref, lock->old_sha1, mustexist, &type);
        if (!ref && errno == EISDIR) {
                /* we are trying to lock foo but we used to
                 * have foo/bar which now does not exist;
@@ -761,8 +773,10 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char
                        error("there are still refs under '%s'", orig_ref);
                        goto error_return;
                }
-               ref = resolve_ref(orig_ref, lock->old_sha1, mustexist, flag);
+               ref = resolve_ref(orig_ref, lock->old_sha1, mustexist, &type);
        }
+       if (type_p)
+           *type_p = type;
        if (!ref) {
                last_errno = errno;
                error("unable to resolve reference %s: %s",
@@ -780,10 +794,15 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char
 
        lock->lk = xcalloc(1, sizeof(struct lock_file));
 
+       if (flags & REF_NODEREF)
+               ref = orig_ref;
        lock->ref_name = xstrdup(ref);
        lock->orig_ref_name = xstrdup(orig_ref);
        ref_file = git_path("%s", ref);
-       lock->force_write = lstat(ref_file, &st) && errno == ENOENT;
+       if (lstat(ref_file, &st) && errno == ENOENT)
+               lock->force_write = 1;
+       if ((flags & REF_NODEREF) && (type & REF_ISSYMREF))
+               lock->force_write = 1;
 
        if (safe_create_leading_directories(ref_file)) {
                last_errno = errno;
@@ -806,14 +825,14 @@ struct ref_lock *lock_ref_sha1(const char *ref, const unsigned char *old_sha1)
        if (check_ref_format(ref))
                return NULL;
        strcpy(refpath, mkpath("refs/%s", ref));
-       return lock_ref_sha1_basic(refpath, old_sha1, NULL);
+       return lock_ref_sha1_basic(refpath, old_sha1, 0, NULL);
 }
 
-struct ref_lock *lock_any_ref_for_update(const char *ref, const unsigned char *old_sha1)
+struct ref_lock *lock_any_ref_for_update(const char *ref, const unsigned char *old_sha1, int flags)
 {
        if (check_ref_format(ref) == -1)
                return NULL;
-       return lock_ref_sha1_basic(ref, old_sha1, NULL);
+       return lock_ref_sha1_basic(ref, old_sha1, flags, NULL);
 }
 
 static struct lock_file packlock;
@@ -858,7 +877,7 @@ int delete_ref(const char *refname, const unsigned char *sha1)
        struct ref_lock *lock;
        int err, i, ret = 0, flag = 0;
 
-       lock = lock_ref_sha1_basic(refname, sha1, &flag);
+       lock = lock_ref_sha1_basic(refname, sha1, 0, &flag);
        if (!lock)
                return 1;
        if (!(flag & REF_ISPACKED)) {
@@ -909,7 +928,7 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
        if (!is_refname_available(newref, oldref, get_loose_refs(), 0))
                return 1;
 
-       lock = lock_ref_sha1_basic(renamed_ref, NULL, NULL);
+       lock = lock_ref_sha1_basic(renamed_ref, NULL, 0, NULL);
        if (!lock)
                return error("unable to lock %s", renamed_ref);
        lock->force_write = 1;
@@ -963,7 +982,7 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
        }
        logmoved = log;
 
-       lock = lock_ref_sha1_basic(newref, NULL, NULL);
+       lock = lock_ref_sha1_basic(newref, NULL, 0, NULL);
        if (!lock) {
                error("unable to lock %s for update", newref);
                goto rollback;
@@ -979,7 +998,7 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
        return 0;
 
  rollback:
-       lock = lock_ref_sha1_basic(oldref, NULL, NULL);
+       lock = lock_ref_sha1_basic(oldref, NULL, 0, NULL);
        if (!lock) {
                error("unable to lock %s for rollback", oldref);
                goto rollbacklog;
@@ -1087,8 +1106,7 @@ static int log_ref_write(const char *ref_name, const unsigned char *old_sha1,
                len += sprintf(logrec + len - 1, "\t%.*s\n", msglen, msg) - 1;
        written = len <= maxlen ? write_in_full(logfd, logrec, len) : -1;
        free(logrec);
-       close(logfd);
-       if (written != len)
+       if (close(logfd) != 0 || written != len)
                return error("Unable to append to %s", log_file);
        return 0;
 }
@@ -1185,8 +1203,7 @@ int create_symref(const char *ref_target, const char *refs_heads_master,
                goto error_free_return;
        }
        written = write_in_full(fd, ref, len);
-       close(fd);
-       if (written != len) {
+       if (close(fd) != 0 || written != len) {
                error("Unable to write to %s", lockpath);
                goto error_unlink_return;
        }
diff --git a/refs.h b/refs.h
index f61f6d934e80b21432f93cd3b9f138770a9d2b86..f234eb76ba5d6aba03f484fe58d11ba81a90ff5a 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -33,7 +33,8 @@ extern int get_ref_sha1(const char *ref, unsigned char *sha1);
 extern struct ref_lock *lock_ref_sha1(const char *ref, const unsigned char *old_sha1);
 
 /** Locks any ref (for 'HEAD' type refs). */
-extern struct ref_lock *lock_any_ref_for_update(const char *ref, const unsigned char *old_sha1);
+#define REF_NODEREF    0x01
+extern struct ref_lock *lock_any_ref_for_update(const char *ref, const unsigned char *old_sha1, int flags);
 
 /** Release any lock taken but not written. **/
 extern void unlock_ref(struct ref_lock *lock);
diff --git a/remote.c b/remote.c
new file mode 100644 (file)
index 0000000..cf98a44
--- /dev/null
+++ b/remote.c
@@ -0,0 +1,583 @@
+#include "cache.h"
+#include "remote.h"
+#include "refs.h"
+
+static struct remote **remotes;
+static int allocated_remotes;
+
+#define BUF_SIZE (2048)
+static char buffer[BUF_SIZE];
+
+static void add_push_refspec(struct remote *remote, const char *ref)
+{
+       int nr = remote->push_refspec_nr + 1;
+       remote->push_refspec =
+               xrealloc(remote->push_refspec, nr * sizeof(char *));
+       remote->push_refspec[nr-1] = ref;
+       remote->push_refspec_nr = nr;
+}
+
+static void add_fetch_refspec(struct remote *remote, const char *ref)
+{
+       int nr = remote->fetch_refspec_nr + 1;
+       remote->fetch_refspec =
+               xrealloc(remote->fetch_refspec, nr * sizeof(char *));
+       remote->fetch_refspec[nr-1] = ref;
+       remote->fetch_refspec_nr = nr;
+}
+
+static void add_uri(struct remote *remote, const char *uri)
+{
+       int nr = remote->uri_nr + 1;
+       remote->uri =
+               xrealloc(remote->uri, nr * sizeof(char *));
+       remote->uri[nr-1] = uri;
+       remote->uri_nr = nr;
+}
+
+static struct remote *make_remote(const char *name, int len)
+{
+       int i, empty = -1;
+
+       for (i = 0; i < allocated_remotes; i++) {
+               if (!remotes[i]) {
+                       if (empty < 0)
+                               empty = i;
+               } else {
+                       if (len ? (!strncmp(name, remotes[i]->name, len) &&
+                                  !remotes[i]->name[len]) :
+                           !strcmp(name, remotes[i]->name))
+                               return remotes[i];
+               }
+       }
+
+       if (empty < 0) {
+               empty = allocated_remotes;
+               allocated_remotes += allocated_remotes ? allocated_remotes : 1;
+               remotes = xrealloc(remotes,
+                                  sizeof(*remotes) * allocated_remotes);
+               memset(remotes + empty, 0,
+                      (allocated_remotes - empty) * sizeof(*remotes));
+       }
+       remotes[empty] = xcalloc(1, sizeof(struct remote));
+       if (len)
+               remotes[empty]->name = xstrndup(name, len);
+       else
+               remotes[empty]->name = xstrdup(name);
+       return remotes[empty];
+}
+
+static void read_remotes_file(struct remote *remote)
+{
+       FILE *f = fopen(git_path("remotes/%s", remote->name), "r");
+
+       if (!f)
+               return;
+       while (fgets(buffer, BUF_SIZE, f)) {
+               int value_list;
+               char *s, *p;
+
+               if (!prefixcmp(buffer, "URL:")) {
+                       value_list = 0;
+                       s = buffer + 4;
+               } else if (!prefixcmp(buffer, "Push:")) {
+                       value_list = 1;
+                       s = buffer + 5;
+               } else if (!prefixcmp(buffer, "Pull:")) {
+                       value_list = 2;
+                       s = buffer + 5;
+               } else
+                       continue;
+
+               while (isspace(*s))
+                       s++;
+               if (!*s)
+                       continue;
+
+               p = s + strlen(s);
+               while (isspace(p[-1]))
+                       *--p = 0;
+
+               switch (value_list) {
+               case 0:
+                       add_uri(remote, xstrdup(s));
+                       break;
+               case 1:
+                       add_push_refspec(remote, xstrdup(s));
+                       break;
+               case 2:
+                       add_fetch_refspec(remote, xstrdup(s));
+                       break;
+               }
+       }
+       fclose(f);
+}
+
+static void read_branches_file(struct remote *remote)
+{
+       const char *slash = strchr(remote->name, '/');
+       int n = slash ? slash - remote->name : 1000;
+       FILE *f = fopen(git_path("branches/%.*s", n, remote->name), "r");
+       char *s, *p;
+       int len;
+
+       if (!f)
+               return;
+       s = fgets(buffer, BUF_SIZE, f);
+       fclose(f);
+       if (!s)
+               return;
+       while (isspace(*s))
+               s++;
+       if (!*s)
+               return;
+       p = s + strlen(s);
+       while (isspace(p[-1]))
+               *--p = 0;
+       len = p - s;
+       if (slash)
+               len += strlen(slash);
+       p = xmalloc(len + 1);
+       strcpy(p, s);
+       if (slash)
+               strcat(p, slash);
+       add_uri(remote, p);
+}
+
+static char *default_remote_name = NULL;
+static const char *current_branch = NULL;
+static int current_branch_len = 0;
+
+static int handle_config(const char *key, const char *value)
+{
+       const char *name;
+       const char *subkey;
+       struct remote *remote;
+       if (!prefixcmp(key, "branch.") && current_branch &&
+           !strncmp(key + 7, current_branch, current_branch_len) &&
+           !strcmp(key + 7 + current_branch_len, ".remote")) {
+               free(default_remote_name);
+               default_remote_name = xstrdup(value);
+       }
+       if (prefixcmp(key,  "remote."))
+               return 0;
+       name = key + 7;
+       subkey = strrchr(name, '.');
+       if (!subkey)
+               return error("Config with no key for remote %s", name);
+       if (*subkey == '/') {
+               warning("Config remote shorthand cannot begin with '/': %s", name);
+               return 0;
+       }
+       remote = make_remote(name, subkey - name);
+       if (!value) {
+               /* if we ever have a boolean variable, e.g. "remote.*.disabled"
+                * [remote "frotz"]
+                *      disabled
+                * is a valid way to set it to true; we get NULL in value so
+                * we need to handle it here.
+                *
+                * if (!strcmp(subkey, ".disabled")) {
+                *      val = git_config_bool(key, value);
+                *      return 0;
+                * } else
+                *
+                */
+               return 0; /* ignore unknown booleans */
+       }
+       if (!strcmp(subkey, ".url")) {
+               add_uri(remote, xstrdup(value));
+       } else if (!strcmp(subkey, ".push")) {
+               add_push_refspec(remote, xstrdup(value));
+       } else if (!strcmp(subkey, ".fetch")) {
+               add_fetch_refspec(remote, xstrdup(value));
+       } else if (!strcmp(subkey, ".receivepack")) {
+               if (!remote->receivepack)
+                       remote->receivepack = xstrdup(value);
+               else
+                       error("more than one receivepack given, using the first");
+       }
+       return 0;
+}
+
+static void read_config(void)
+{
+       unsigned char sha1[20];
+       const char *head_ref;
+       int flag;
+       if (default_remote_name) // did this already
+               return;
+       default_remote_name = xstrdup("origin");
+       current_branch = NULL;
+       head_ref = resolve_ref("HEAD", sha1, 0, &flag);
+       if (head_ref && (flag & REF_ISSYMREF) &&
+           !prefixcmp(head_ref, "refs/heads/")) {
+               current_branch = head_ref + strlen("refs/heads/");
+               current_branch_len = strlen(current_branch);
+       }
+       git_config(handle_config);
+}
+
+static struct refspec *parse_ref_spec(int nr_refspec, const char **refspec)
+{
+       int i;
+       struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec);
+       for (i = 0; i < nr_refspec; i++) {
+               const char *sp, *ep, *gp;
+               sp = refspec[i];
+               if (*sp == '+') {
+                       rs[i].force = 1;
+                       sp++;
+               }
+               gp = strchr(sp, '*');
+               ep = strchr(sp, ':');
+               if (gp && ep && gp > ep)
+                       gp = NULL;
+               if (ep) {
+                       if (ep[1]) {
+                               const char *glob = strchr(ep + 1, '*');
+                               if (!glob)
+                                       gp = NULL;
+                               if (gp)
+                                       rs[i].dst = xstrndup(ep + 1,
+                                                            glob - ep - 1);
+                               else
+                                       rs[i].dst = xstrdup(ep + 1);
+                       }
+               } else {
+                       ep = sp + strlen(sp);
+               }
+               if (gp) {
+                       rs[i].pattern = 1;
+                       ep = gp;
+               }
+               rs[i].src = xstrndup(sp, ep - sp);
+       }
+       return rs;
+}
+
+struct remote *remote_get(const char *name)
+{
+       struct remote *ret;
+
+       read_config();
+       if (!name)
+               name = default_remote_name;
+       ret = make_remote(name, 0);
+       if (name[0] != '/') {
+               if (!ret->uri)
+                       read_remotes_file(ret);
+               if (!ret->uri)
+                       read_branches_file(ret);
+       }
+       if (!ret->uri)
+               add_uri(ret, name);
+       if (!ret->uri)
+               return NULL;
+       ret->fetch = parse_ref_spec(ret->fetch_refspec_nr, ret->fetch_refspec);
+       ret->push = parse_ref_spec(ret->push_refspec_nr, ret->push_refspec);
+       return ret;
+}
+
+int remote_has_uri(struct remote *remote, const char *uri)
+{
+       int i;
+       for (i = 0; i < remote->uri_nr; i++) {
+               if (!strcmp(remote->uri[i], uri))
+                       return 1;
+       }
+       return 0;
+}
+
+int remote_find_tracking(struct remote *remote, struct refspec *refspec)
+{
+       int i;
+       for (i = 0; i < remote->fetch_refspec_nr; i++) {
+               struct refspec *fetch = &remote->fetch[i];
+               if (!fetch->dst)
+                       continue;
+               if (fetch->pattern) {
+                       if (!prefixcmp(refspec->src, fetch->src)) {
+                               refspec->dst =
+                                       xmalloc(strlen(fetch->dst) +
+                                               strlen(refspec->src) -
+                                               strlen(fetch->src) + 1);
+                               strcpy(refspec->dst, fetch->dst);
+                               strcpy(refspec->dst + strlen(fetch->dst),
+                                      refspec->src + strlen(fetch->src));
+                               refspec->force = fetch->force;
+                               return 0;
+                       }
+               } else {
+                       if (!strcmp(refspec->src, fetch->src)) {
+                               refspec->dst = xstrdup(fetch->dst);
+                               refspec->force = fetch->force;
+                               return 0;
+                       }
+               }
+       }
+       refspec->dst = NULL;
+       return -1;
+}
+
+static int count_refspec_match(const char *pattern,
+                              struct ref *refs,
+                              struct ref **matched_ref)
+{
+       int patlen = strlen(pattern);
+       struct ref *matched_weak = NULL;
+       struct ref *matched = NULL;
+       int weak_match = 0;
+       int match = 0;
+
+       for (weak_match = match = 0; refs; refs = refs->next) {
+               char *name = refs->name;
+               int namelen = strlen(name);
+
+               if (namelen < patlen ||
+                   memcmp(name + namelen - patlen, pattern, patlen))
+                       continue;
+               if (namelen != patlen && name[namelen - patlen - 1] != '/')
+                       continue;
+
+               /* A match is "weak" if it is with refs outside
+                * heads or tags, and did not specify the pattern
+                * in full (e.g. "refs/remotes/origin/master") or at
+                * least from the toplevel (e.g. "remotes/origin/master");
+                * otherwise "git push $URL master" would result in
+                * ambiguity between remotes/origin/master and heads/master
+                * at the remote site.
+                */
+               if (namelen != patlen &&
+                   patlen != namelen - 5 &&
+                   prefixcmp(name, "refs/heads/") &&
+                   prefixcmp(name, "refs/tags/")) {
+                       /* We want to catch the case where only weak
+                        * matches are found and there are multiple
+                        * matches, and where more than one strong
+                        * matches are found, as ambiguous.  One
+                        * strong match with zero or more weak matches
+                        * are acceptable as a unique match.
+                        */
+                       matched_weak = refs;
+                       weak_match++;
+               }
+               else {
+                       matched = refs;
+                       match++;
+               }
+       }
+       if (!matched) {
+               *matched_ref = matched_weak;
+               return weak_match;
+       }
+       else {
+               *matched_ref = matched;
+               return match;
+       }
+}
+
+static void link_dst_tail(struct ref *ref, struct ref ***tail)
+{
+       **tail = ref;
+       *tail = &ref->next;
+       **tail = NULL;
+}
+
+static struct ref *try_explicit_object_name(const char *name)
+{
+       unsigned char sha1[20];
+       struct ref *ref;
+       int len;
+
+       if (!*name) {
+               ref = xcalloc(1, sizeof(*ref) + 20);
+               strcpy(ref->name, "(delete)");
+               hashclr(ref->new_sha1);
+               return ref;
+       }
+       if (get_sha1(name, sha1))
+               return NULL;
+       len = strlen(name) + 1;
+       ref = xcalloc(1, sizeof(*ref) + len);
+       memcpy(ref->name, name, len);
+       hashcpy(ref->new_sha1, sha1);
+       return ref;
+}
+
+static struct ref *make_dst(const char *name, struct ref ***dst_tail)
+{
+       struct ref *dst;
+       size_t len;
+
+       len = strlen(name) + 1;
+       dst = xcalloc(1, sizeof(*dst) + len);
+       memcpy(dst->name, name, len);
+       link_dst_tail(dst, dst_tail);
+       return dst;
+}
+
+static int match_explicit(struct ref *src, struct ref *dst,
+                         struct ref ***dst_tail,
+                         struct refspec *rs,
+                         int errs)
+{
+       struct ref *matched_src, *matched_dst;
+
+       const char *dst_value = rs->dst;
+
+       if (rs->pattern)
+               return errs;
+
+       matched_src = matched_dst = NULL;
+       switch (count_refspec_match(rs->src, src, &matched_src)) {
+       case 1:
+               break;
+       case 0:
+               /* The source could be in the get_sha1() format
+                * not a reference name.  :refs/other is a
+                * way to delete 'other' ref at the remote end.
+                */
+               matched_src = try_explicit_object_name(rs->src);
+               if (matched_src)
+                       break;
+               error("src refspec %s does not match any.",
+                     rs->src);
+               break;
+       default:
+               matched_src = NULL;
+               error("src refspec %s matches more than one.",
+                     rs->src);
+               break;
+       }
+
+       if (!matched_src)
+               errs = 1;
+
+       if (dst_value == NULL)
+               dst_value = matched_src->name;
+
+       switch (count_refspec_match(dst_value, dst, &matched_dst)) {
+       case 1:
+               break;
+       case 0:
+               if (!memcmp(dst_value, "refs/", 5))
+                       matched_dst = make_dst(dst_value, dst_tail);
+               else
+                       error("dst refspec %s does not match any "
+                             "existing ref on the remote and does "
+                             "not start with refs/.", dst_value);
+               break;
+       default:
+               matched_dst = NULL;
+               error("dst refspec %s matches more than one.",
+                     dst_value);
+               break;
+       }
+       if (errs || matched_dst == NULL)
+               return 1;
+       if (matched_dst->peer_ref) {
+               errs = 1;
+               error("dst ref %s receives from more than one src.",
+                     matched_dst->name);
+       }
+       else {
+               matched_dst->peer_ref = matched_src;
+               matched_dst->force = rs->force;
+       }
+       return errs;
+}
+
+static int match_explicit_refs(struct ref *src, struct ref *dst,
+                              struct ref ***dst_tail, struct refspec *rs,
+                              int rs_nr)
+{
+       int i, errs;
+       for (i = errs = 0; i < rs_nr; i++)
+               errs |= match_explicit(src, dst, dst_tail, &rs[i], errs);
+       return -errs;
+}
+
+static struct ref *find_ref_by_name(struct ref *list, const char *name)
+{
+       for ( ; list; list = list->next)
+               if (!strcmp(list->name, name))
+                       return list;
+       return NULL;
+}
+
+static const struct refspec *check_pattern_match(const struct refspec *rs,
+                                                int rs_nr,
+                                                const struct ref *src)
+{
+       int i;
+       for (i = 0; i < rs_nr; i++) {
+               if (rs[i].pattern && !prefixcmp(src->name, rs[i].src))
+                       return rs + i;
+       }
+       return NULL;
+}
+
+/*
+ * Note. This is used only by "push"; refspec matching rules for
+ * push and fetch are subtly different, so do not try to reuse it
+ * without thinking.
+ */
+int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
+              int nr_refspec, char **refspec, int all)
+{
+       struct refspec *rs =
+               parse_ref_spec(nr_refspec, (const char **) refspec);
+
+       if (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec))
+               return -1;
+
+       /* pick the remainder */
+       for ( ; src; src = src->next) {
+               struct ref *dst_peer;
+               const struct refspec *pat = NULL;
+               char *dst_name;
+               if (src->peer_ref)
+                       continue;
+               if (nr_refspec) {
+                       pat = check_pattern_match(rs, nr_refspec, src);
+                       if (!pat)
+                               continue;
+               }
+               else if (prefixcmp(src->name, "refs/heads/"))
+                       /*
+                        * "matching refs"; traditionally we pushed everything
+                        * including refs outside refs/heads/ hierarchy, but
+                        * that does not make much sense these days.
+                        */
+                       continue;
+
+               if (pat) {
+                       const char *dst_side = pat->dst ? pat->dst : pat->src;
+                       dst_name = xmalloc(strlen(dst_side) +
+                                          strlen(src->name) -
+                                          strlen(pat->src) + 2);
+                       strcpy(dst_name, dst_side);
+                       strcat(dst_name, src->name + strlen(pat->src));
+               } else
+                       dst_name = xstrdup(src->name);
+               dst_peer = find_ref_by_name(dst, dst_name);
+               if (dst_peer && dst_peer->peer_ref)
+                       /* We're already sending something to this ref. */
+                       goto free_name;
+               if (!dst_peer && !nr_refspec && !all)
+                       /* Remote doesn't have it, and we have no
+                        * explicit pattern, and we don't have
+                        * --all. */
+                       goto free_name;
+               if (!dst_peer) {
+                       /* Create a new one and link it */
+                       dst_peer = make_dst(dst_name, dst_tail);
+                       hashcpy(dst_peer->new_sha1, src->new_sha1);
+               }
+               dst_peer->peer_ref = src;
+       free_name:
+               free(dst_name);
+       }
+       return 0;
+}
diff --git a/remote.h b/remote.h
new file mode 100644 (file)
index 0000000..01dbcef
--- /dev/null
+++ b/remote.h
@@ -0,0 +1,41 @@
+#ifndef REMOTE_H
+#define REMOTE_H
+
+struct remote {
+       const char *name;
+
+       const char **uri;
+       int uri_nr;
+
+       const char **push_refspec;
+       struct refspec *push;
+       int push_refspec_nr;
+
+       const char **fetch_refspec;
+       struct refspec *fetch;
+       int fetch_refspec_nr;
+
+       const char *receivepack;
+};
+
+struct remote *remote_get(const char *name);
+
+int remote_has_uri(struct remote *remote, const char *uri);
+
+struct refspec {
+       unsigned force : 1;
+       unsigned pattern : 1;
+
+       const char *src;
+       char *dst;
+};
+
+int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
+              int nr_refspec, char **refspec, int all);
+
+/*
+ * For the given remote, reads the refspec's src and sets the other fields.
+ */
+int remote_find_tracking(struct remote *remote, struct refspec *refspec);
+
+#endif
index e43c6489785a61707b838df782d2859ec6654651..5184716bf0af35298d2a1bd3b9411b518be09e14 100644 (file)
@@ -114,12 +114,7 @@ void mark_parents_uninteresting(struct commit *commit)
        }
 }
 
-void add_pending_object(struct rev_info *revs, struct object *obj, const char *name)
-{
-       add_pending_object_with_mode(revs, obj, name, S_IFINVALID);
-}
-
-void add_pending_object_with_mode(struct rev_info *revs, struct object *obj, const char *name, unsigned mode)
+static void add_pending_object_with_mode(struct rev_info *revs, struct object *obj, const char *name, unsigned mode)
 {
        if (revs->no_walk && (obj->flags & UNINTERESTING))
                die("object ranges do not make sense when not walking revisions");
@@ -129,6 +124,11 @@ void add_pending_object_with_mode(struct rev_info *revs, struct object *obj, con
                                (struct commit *)obj, name);
 }
 
+void add_pending_object(struct rev_info *revs, struct object *obj, const char *name)
+{
+       add_pending_object_with_mode(revs, obj, name, S_IFINVALID);
+}
+
 static struct object *get_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags)
 {
        struct object *object;
@@ -262,7 +262,7 @@ static void file_change(struct diff_options *options,
        options->has_changes = 1;
 }
 
-int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree *t2)
+static int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree *t2)
 {
        if (!t1)
                return REV_TREE_NEW;
@@ -276,7 +276,7 @@ int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree *t2)
        return tree_difference;
 }
 
-int rev_same_tree_as_empty(struct rev_info *revs, struct tree *t1)
+static int rev_same_tree_as_empty(struct rev_info *revs, struct tree *t1)
 {
        int retval;
        void *tree;
@@ -667,7 +667,6 @@ void init_revisions(struct rev_info *revs, const char *prefix)
        revs->min_age = -1;
        revs->skip_count = -1;
        revs->max_count = -1;
-       revs->subject_prefix = "PATCH";
 
        revs->prune_fn = NULL;
        revs->prune_data = NULL;
@@ -881,6 +880,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
        const char **unrecognized = argv + 1;
        int left = 1;
        int all_match = 0;
+       int regflags = 0;
 
        /* First, search for "--" */
        seen_dashdash = 0;
@@ -1152,6 +1152,14 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
                                add_message_grep(revs, arg+7);
                                continue;
                        }
+                       if (!prefixcmp(arg, "--extended-regexp")) {
+                               regflags |= REG_EXTENDED;
+                               continue;
+                       }
+                       if (!prefixcmp(arg, "--regexp-ignore-case")) {
+                               regflags |= REG_ICASE;
+                               continue;
+                       }
                        if (!strcmp(arg, "--all-match")) {
                                all_match = 1;
                                continue;
@@ -1201,6 +1209,9 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
                }
        }
 
+       if (revs->grep_filter)
+               revs->grep_filter->regflags |= regflags;
+
        if (show_merge)
                prepare_show_merge(revs);
        if (def && !revs->pending.nr) {
@@ -1218,7 +1229,9 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
 
        if (revs->prune_data) {
                diff_tree_setup_paths(revs->prune_data, &revs->pruning);
-               revs->prune_fn = try_to_simplify_commit;
+               /* Can't prune commits with rename following: the paths change.. */
+               if (!revs->diffopt.follow_renames)
+                       revs->prune_fn = try_to_simplify_commit;
                if (!revs->full_diff)
                        diff_tree_setup_paths(revs->prune_data, &revs->diffopt);
        }
index 2845167746ce4632894fce88e840df60513933aa..f46b4d55a2c75e201b37dda8edd6d353722a96cb 100644 (file)
@@ -106,8 +106,6 @@ struct rev_info {
 #define REV_TREE_DIFFERENT     2
 
 /* revision.c */
-extern int rev_same_tree_as_empty(struct rev_info *, struct tree *t1);
-extern int rev_compare_tree(struct rev_info *, struct tree *t1, struct tree *t2);
 
 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);
@@ -131,6 +129,5 @@ extern void add_object(struct object *obj,
                       const char *name);
 
 extern void add_pending_object(struct rev_info *revs, struct object *obj, const char *name);
-extern void add_pending_object_with_mode(struct rev_info *revs, struct object *obj, const char *name, unsigned mode);
 
 #endif
diff --git a/rsh.h b/rsh.h
index 3b4194239dc419c38910012b129c4c92b72ef8ad..ee2f49929131c684bcffa3e95a1ee29521e8818b 100644 (file)
--- a/rsh.h
+++ b/rsh.h
@@ -1,7 +1,7 @@
 #ifndef RSH_H
 #define RSH_H
 
-int setup_connection(int *fd_in, int *fd_out, const char *remote_prog, 
+int setup_connection(int *fd_in, int *fd_out, const char *remote_prog,
                     char *url, int rmt_argc, char **rmt_argv);
 
 #endif
index eff523e191b35385895f6b077fc76c7c21819012..7e779d33ee9ea5f7d2e6aedc8c3a0a0476e87135 100644 (file)
@@ -73,6 +73,17 @@ int start_command(struct child_process *cmd)
                        close(cmd->out);
                }
 
+               if (cmd->dir && chdir(cmd->dir))
+                       die("exec %s: cd to %s failed (%s)", cmd->argv[0],
+                           cmd->dir, strerror(errno));
+               if (cmd->env) {
+                       for (; *cmd->env; cmd->env++) {
+                               if (strchr(*cmd->env, '='))
+                                       putenv((char*)*cmd->env);
+                               else
+                                       unsetenv(*cmd->env);
+                       }
+               }
                if (cmd->git_cmd) {
                        execv_git_cmd(cmd->argv);
                } else {
@@ -133,13 +144,37 @@ int run_command(struct child_process *cmd)
        return finish_command(cmd);
 }
 
+static void prepare_run_command_v_opt(struct child_process *cmd,
+                                     const char **argv,
+                                     int opt)
+{
+       memset(cmd, 0, sizeof(*cmd));
+       cmd->argv = argv;
+       cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
+       cmd->git_cmd = opt & RUN_GIT_CMD ? 1 : 0;
+       cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
+}
+
 int run_command_v_opt(const char **argv, int opt)
 {
        struct child_process cmd;
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.argv = argv;
-       cmd.no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
-       cmd.git_cmd = opt & RUN_GIT_CMD ? 1 : 0;
-       cmd.stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
+       prepare_run_command_v_opt(&cmd, argv, opt);
+       return run_command(&cmd);
+}
+
+int run_command_v_opt_cd(const char **argv, int opt, const char *dir)
+{
+       struct child_process cmd;
+       prepare_run_command_v_opt(&cmd, argv, opt);
+       cmd.dir = dir;
+       return run_command(&cmd);
+}
+
+int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env)
+{
+       struct child_process cmd;
+       prepare_run_command_v_opt(&cmd, argv, opt);
+       cmd.dir = dir;
+       cmd.env = env;
        return run_command(&cmd);
 }
index 3680ef9d452490c67788b0ab027839a8383ed855..7958eb1e0b7a927019460e06d7a01622eddf81df 100644 (file)
@@ -16,6 +16,8 @@ struct child_process {
        pid_t pid;
        int in;
        int out;
+       const char *dir;
+       const char *const *env;
        unsigned close_in:1;
        unsigned close_out:1;
        unsigned no_stdin:1;
@@ -32,5 +34,12 @@ int run_command(struct child_process *);
 #define RUN_GIT_CMD         2  /*If this is to be git sub-command */
 #define RUN_COMMAND_STDOUT_TO_STDERR 4
 int run_command_v_opt(const char **argv, int opt);
+int run_command_v_opt_cd(const char **argv, int opt, const char *dir);
+
+/*
+ * env (the environment) is to be formatted like environ: "VAR=VALUE".
+ * To unset an environment variable use just "VAR".
+ */
+int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const char *const *env);
 
 #endif
index d5b51628dfbcc44b22b5069df19eeac67dda1e57..fecbda981b7c6c2504abdd7afb94e35e73e18cce 100644 (file)
@@ -4,6 +4,7 @@
 #include "refs.h"
 #include "pkt-line.h"
 #include "run-command.h"
+#include "remote.h"
 
 static const char send_pack_usage[] =
 "git-send-pack [--all] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
@@ -176,7 +177,7 @@ static int receive_status(int in)
        return ret;
 }
 
-static int send_pack(int in, int out, int nr_refspec, char **refspec)
+static int send_pack(int in, int out, struct remote *remote, int nr_refspec, char **refspec)
 {
        struct ref *ref;
        int new_refs;
@@ -213,18 +214,19 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec)
        new_refs = 0;
        for (ref = remote_refs; ref; ref = ref->next) {
                char old_hex[60], *new_hex;
-               int delete_ref;
+               int will_delete_ref;
 
                if (!ref->peer_ref)
                        continue;
 
-               delete_ref = is_null_sha1(ref->peer_ref->new_sha1);
-               if (delete_ref && !allow_deleting_refs) {
+
+               will_delete_ref = is_null_sha1(ref->peer_ref->new_sha1);
+               if (will_delete_ref && !allow_deleting_refs) {
                        error("remote does not support deleting refs");
                        ret = -2;
                        continue;
                }
-               if (!delete_ref &&
+               if (!will_delete_ref &&
                    !hashcmp(ref->old_sha1, ref->peer_ref->new_sha1)) {
                        if (verbose)
                                fprintf(stderr, "'%s': up-to-date\n", ref->name);
@@ -251,7 +253,7 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec)
                 */
 
                if (!force_update &&
-                   !delete_ref &&
+                   !will_delete_ref &&
                    !is_null_sha1(ref->old_sha1) &&
                    !ref->force) {
                        if (!has_sha1_file(ref->old_sha1) ||
@@ -275,7 +277,7 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec)
                        }
                }
                hashcpy(ref->new_sha1, ref->peer_ref->new_sha1);
-               if (!delete_ref)
+               if (!will_delete_ref)
                        new_refs++;
                strcpy(old_hex, sha1_to_hex(ref->old_sha1));
                new_hex = sha1_to_hex(ref->new_sha1);
@@ -290,7 +292,7 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec)
                else
                        packet_write(out, "%s %s %s",
                                     old_hex, new_hex, ref->name);
-               if (delete_ref)
+               if (will_delete_ref)
                        fprintf(stderr, "deleting '%s'\n", ref->name);
                else {
                        fprintf(stderr, "updating '%s'", ref->name);
@@ -300,6 +302,28 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec)
                        fprintf(stderr, "\n  from %s\n  to   %s\n",
                                old_hex, new_hex);
                }
+               if (remote) {
+                       struct refspec rs;
+                       rs.src = ref->name;
+                       remote_find_tracking(remote, &rs);
+                       if (rs.dst) {
+                               struct ref_lock *lock;
+                               fprintf(stderr, " Also local %s\n", rs.dst);
+                               if (will_delete_ref) {
+                                       if (delete_ref(rs.dst, NULL)) {
+                                               error("Failed to delete");
+                                       }
+                               } else {
+                                       lock = lock_any_ref_for_update(rs.dst, NULL, 0);
+                                       if (!lock)
+                                               error("Failed to lock");
+                                       else
+                                               write_ref_sha1(lock, ref->new_sha1,
+                                                              "update by push");
+                               }
+                               free(rs.dst);
+                       }
+               }
        }
 
        packet_flush(out);
@@ -330,6 +354,7 @@ static void verify_remote_names(int nr_heads, char **heads)
                case -2: /* ok but a single level -- that is fine for
                          * a match pattern.
                          */
+               case -3: /* ok but ends with a pattern-match character */
                        continue;
                }
                die("remote part of refspec is not a valid name in %s",
@@ -344,6 +369,8 @@ int main(int argc, char **argv)
        char **heads = NULL;
        int fd[2], ret;
        pid_t pid;
+       char *remote_name = NULL;
+       struct remote *remote = NULL;
 
        setup_git_directory();
        git_config(git_default_config);
@@ -361,6 +388,10 @@ int main(int argc, char **argv)
                                receivepack = arg + 7;
                                continue;
                        }
+                       if (!prefixcmp(arg, "--remote=")) {
+                               remote_name = arg + 9;
+                               continue;
+                       }
                        if (!strcmp(arg, "--all")) {
                                send_all = 1;
                                continue;
@@ -393,10 +424,18 @@ int main(int argc, char **argv)
                usage(send_pack_usage);
        verify_remote_names(nr_heads, heads);
 
-       pid = git_connect(fd, dest, receivepack);
+       if (remote_name) {
+               remote = remote_get(remote_name);
+               if (!remote_has_uri(remote, dest)) {
+                       die("Destination %s is not a uri for %s",
+                           dest, remote_name);
+               }
+       }
+
+       pid = git_connect(fd, dest, receivepack, verbose ? CONNECT_VERBOSE : 0);
        if (pid < 0)
                return 1;
-       ret = send_pack(fd[0], fd[1], nr_heads, heads);
+       ret = send_pack(fd[0], fd[1], remote, nr_heads, heads);
        close(fd[0]);
        close(fd[1]);
        ret |= finish_connect(pid);
diff --git a/setup.c b/setup.c
index a45ea8309a9773160597f142f1208a6129885499..bb26f3af96da2a257d020c87760fa6dc74e8f1d7 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -39,7 +39,7 @@ const char *prefix_path(const char *prefix, int len, const char *path)
        if (len) {
                int speclen = strlen(path);
                char *n = xmalloc(speclen + len + 1);
-       
+
                memcpy(n, prefix, len);
                memcpy(n + len, path, speclen+1);
                path = n;
@@ -47,7 +47,7 @@ const char *prefix_path(const char *prefix, int len, const char *path)
        return path;
 }
 
-/* 
+/*
  * Unlike prefix_path, this should be used if the named file does
  * not have to interact with index entry; i.e. name of a random file
  * on the filesystem.
@@ -95,7 +95,7 @@ void verify_non_filename(const char *prefix, const char *arg)
        const char *name;
        struct stat st;
 
-       if (is_inside_git_dir())
+       if (!is_inside_work_tree() || is_inside_git_dir())
                return;
        if (*arg == '-')
                return; /* flag */
@@ -174,41 +174,96 @@ static int inside_git_dir = -1;
 
 int is_inside_git_dir(void)
 {
-       if (inside_git_dir < 0) {
-               char buffer[1024];
-
-               if (is_bare_repository())
-                       return (inside_git_dir = 1);
-               if (getcwd(buffer, sizeof(buffer))) {
-                       const char *git_dir = get_git_dir(), *cwd = buffer;
-                       while (*git_dir && *git_dir == *cwd) {
-                               git_dir++;
-                               cwd++;
-                       }
-                       inside_git_dir = !*git_dir;
-               } else
-                       inside_git_dir = 0;
+       if (inside_git_dir >= 0)
+               return inside_git_dir;
+       die("BUG: is_inside_git_dir called before setup_git_directory");
+}
+
+static int inside_work_tree = -1;
+
+int is_inside_work_tree(void)
+{
+       if (inside_git_dir >= 0)
+               return inside_work_tree;
+       die("BUG: is_inside_work_tree called before setup_git_directory");
+}
+
+static char *gitworktree_config;
+
+static int git_setup_config(const char *var, const char *value)
+{
+       if (!strcmp(var, "core.worktree")) {
+               if (gitworktree_config)
+                       strlcpy(gitworktree_config, value, PATH_MAX);
+               return 0;
        }
-       return inside_git_dir;
+       return git_default_config(var, value);
 }
 
 const char *setup_git_directory_gently(int *nongit_ok)
 {
        static char cwd[PATH_MAX+1];
-       const char *gitdirenv;
-       int len, offset;
+       char worktree[PATH_MAX+1], gitdir[PATH_MAX+1];
+       const char *gitdirenv, *gitworktree;
+       int wt_rel_gitdir = 0;
 
-       /*
-        * If GIT_DIR is set explicitly, we're not going
-        * to do any discovery, but we still do repository
-        * validation.
-        */
        gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
-       if (gitdirenv) {
-               if (PATH_MAX - 40 < strlen(gitdirenv))
-                       die("'$%s' too big", GIT_DIR_ENVIRONMENT);
-               if (is_git_directory(gitdirenv))
+       if (!gitdirenv) {
+               int len, offset;
+
+               if (!getcwd(cwd, sizeof(cwd)-1))
+                       die("Unable to read current working directory");
+
+               offset = len = strlen(cwd);
+               for (;;) {
+                       if (is_git_directory(".git"))
+                               break;
+                       if (offset == 0) {
+                               offset = -1;
+                               break;
+                       }
+                       chdir("..");
+                       while (cwd[--offset] != '/')
+                               ; /* do nothing */
+               }
+
+               if (offset >= 0) {
+                       inside_work_tree = 1;
+                       git_config(git_default_config);
+                       if (offset == len) {
+                               inside_git_dir = 0;
+                               return NULL;
+                       }
+
+                       cwd[len++] = '/';
+                       cwd[len] = '\0';
+                       inside_git_dir = !prefixcmp(cwd + offset + 1, ".git/");
+                       return cwd + offset + 1;
+               }
+
+               if (chdir(cwd))
+                       die("Cannot come back to cwd");
+               if (!is_git_directory(".")) {
+                       if (nongit_ok) {
+                               *nongit_ok = 1;
+                               return NULL;
+                       }
+                       die("Not a git repository");
+               }
+               setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
+               gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
+               if (!gitdirenv)
+                       die("getenv after setenv failed");
+       }
+
+       if (PATH_MAX - 40 < strlen(gitdirenv)) {
+               if (nongit_ok) {
+                       *nongit_ok = 1;
                        return NULL;
+               }
+               die("$%s too big", GIT_DIR_ENVIRONMENT);
+       }
+       if (!is_git_directory(gitdirenv)) {
                if (nongit_ok) {
                        *nongit_ok = 1;
                        return NULL;
@@ -216,43 +271,94 @@ const char *setup_git_directory_gently(int *nongit_ok)
                die("Not a git repository: '%s'", gitdirenv);
        }
 
-       if (!getcwd(cwd, sizeof(cwd)-1) || cwd[0] != '/')
+       if (!getcwd(cwd, sizeof(cwd)-1))
+               die("Unable to read current working directory");
+       if (chdir(gitdirenv)) {
+               if (nongit_ok) {
+                       *nongit_ok = 1;
+                       return NULL;
+               }
+               die("Cannot change directory to $%s '%s'",
+                       GIT_DIR_ENVIRONMENT, gitdirenv);
+       }
+       if (!getcwd(gitdir, sizeof(gitdir)-1))
                die("Unable to read current working directory");
+       if (chdir(cwd))
+               die("Cannot come back to cwd");
 
-       offset = len = strlen(cwd);
-       for (;;) {
-               if (is_git_directory(".git"))
-                       break;
-               chdir("..");
-               do {
-                       if (!offset) {
-                               if (is_git_directory(cwd)) {
-                                       if (chdir(cwd))
-                                               die("Cannot come back to cwd");
-                                       setenv(GIT_DIR_ENVIRONMENT, cwd, 1);
-                                       inside_git_dir = 1;
-                                       return NULL;
-                               }
-                               if (nongit_ok) {
-                                       if (chdir(cwd))
-                                               die("Cannot come back to cwd");
-                                       *nongit_ok = 1;
-                                       return NULL;
-                               }
-                               die("Not a git repository");
+       /*
+        * In case there is a work tree we may change the directory,
+        * therefore make GIT_DIR an absolute path.
+        */
+       if (gitdirenv[0] != '/') {
+               setenv(GIT_DIR_ENVIRONMENT, gitdir, 1);
+               gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
+               if (!gitdirenv)
+                       die("getenv after setenv failed");
+               if (PATH_MAX - 40 < strlen(gitdirenv)) {
+                       if (nongit_ok) {
+                               *nongit_ok = 1;
+                               return NULL;
                        }
-               } while (cwd[--offset] != '/');
+                       die("$%s too big after expansion to absolute path",
+                               GIT_DIR_ENVIRONMENT);
+               }
        }
 
-       if (offset == len)
+       strcat(cwd, "/");
+       strcat(gitdir, "/");
+       inside_git_dir = !prefixcmp(cwd, gitdir);
+
+       gitworktree = getenv(GIT_WORK_TREE_ENVIRONMENT);
+       if (!gitworktree) {
+               gitworktree_config = worktree;
+               worktree[0] = '\0';
+       }
+       git_config(git_setup_config);
+       if (!gitworktree) {
+               gitworktree_config = NULL;
+               if (worktree[0])
+                       gitworktree = worktree;
+               if (gitworktree && gitworktree[0] != '/')
+                       wt_rel_gitdir = 1;
+       }
+
+       if (wt_rel_gitdir && chdir(gitdirenv))
+               die("Cannot change directory to $%s '%s'",
+                       GIT_DIR_ENVIRONMENT, gitdirenv);
+       if (gitworktree && chdir(gitworktree)) {
+               if (nongit_ok) {
+                       if (wt_rel_gitdir && chdir(cwd))
+                               die("Cannot come back to cwd");
+                       *nongit_ok = 1;
+                       return NULL;
+               }
+               if (wt_rel_gitdir)
+                       die("Cannot change directory to working tree '%s'"
+                               " from $%s", gitworktree, GIT_DIR_ENVIRONMENT);
+               else
+                       die("Cannot change directory to working tree '%s'",
+                               gitworktree);
+       }
+       if (!getcwd(worktree, sizeof(worktree)-1))
+               die("Unable to read current working directory");
+       strcat(worktree, "/");
+       inside_work_tree = !prefixcmp(cwd, worktree);
+
+       if (gitworktree && inside_work_tree && !prefixcmp(worktree, gitdir) &&
+           strcmp(worktree, gitdir)) {
+               inside_git_dir = 0;
+       }
+
+       if (!inside_work_tree) {
+               if (chdir(cwd))
+                       die("Cannot come back to cwd");
                return NULL;
+       }
 
-       /* Make "offset" point to past the '/', and add a '/' at the end */
-       offset++;
-       cwd[len++] = '/';
-       cwd[len] = 0;
-       inside_git_dir = !prefixcmp(cwd + offset, ".git/");
-       return cwd + offset;
+       if (!strcmp(cwd, worktree))
+               return NULL;
+       return cwd+strlen(worktree);
 }
 
 int git_config_perm(const char *var, const char *value)
index 1d328c8d61d97314c4fd7f83888b0d30b22ac301..1efd9ae19a84dbc2765d4011ea06b2145e86ebb3 100644 (file)
@@ -193,7 +193,7 @@ char *sha1_pack_name(const unsigned char *sha1)
                *buf++ = hex[val >> 4];
                *buf++ = hex[val & 0xf];
        }
-       
+
        return base;
 }
 
@@ -218,7 +218,7 @@ char *sha1_pack_index_name(const unsigned char *sha1)
                *buf++ = hex[val >> 4];
                *buf++ = hex[val & 0xf];
        }
-       
+
        return base;
 }
 
@@ -380,11 +380,12 @@ void prepare_alt_odb(void)
 {
        const char *alt;
 
+       if (alt_odb_tail)
+               return;
+
        alt = getenv(ALTERNATE_DB_ENVIRONMENT);
        if (!alt) alt = "";
 
-       if (alt_odb_tail)
-               return;
        alt_odb_tail = &alt_odb_list;
        link_alt_odb_entries(alt, alt + strlen(alt), ':', NULL, 0);
 
@@ -416,7 +417,7 @@ static size_t peak_pack_mapped;
 static size_t pack_mapped;
 struct packed_git *packed_git;
 
-void pack_report()
+void pack_report(void)
 {
        fprintf(stderr,
                "pack_report: getpagesize()            = %10" SZ_FMT "\n"
@@ -537,6 +538,21 @@ static int check_packed_git_idx(const char *path,  struct packed_git *p)
        return 0;
 }
 
+int open_pack_index(struct packed_git *p)
+{
+       char *idx_name;
+       int ret;
+
+       if (p->index_data)
+               return 0;
+
+       idx_name = xstrdup(p->pack_name);
+       strcpy(idx_name + strlen(idx_name) - strlen(".pack"), ".idx");
+       ret = check_packed_git_idx(idx_name, p);
+       free(idx_name);
+       return ret;
+}
+
 static void scan_windows(struct packed_git *p,
        struct packed_git **lru_p,
        struct pack_window **lru_w,
@@ -612,6 +628,9 @@ static int open_packed_git_1(struct packed_git *p)
        unsigned char *idx_sha1;
        long fd_flag;
 
+       if (!p->index_data && open_pack_index(p))
+               return error("packfile %s index unavailable", p->pack_name);
+
        p->pack_fd = open(p->pack_name, O_RDONLY);
        if (p->pack_fd < 0 || fstat(p->pack_fd, &st))
                return -1;
@@ -764,8 +783,7 @@ struct packed_git *add_packed_git(const char *path, int path_len, int local)
                return NULL;
        memcpy(p->pack_name, path, path_len);
        strcpy(p->pack_name + path_len, ".pack");
-       if (stat(p->pack_name, &st) || !S_ISREG(st.st_mode) ||
-           check_packed_git_idx(path, p)) {
+       if (stat(p->pack_name, &st) || !S_ISREG(st.st_mode)) {
                free(p);
                return NULL;
        }
@@ -773,6 +791,10 @@ struct packed_git *add_packed_git(const char *path, int path_len, int local)
        /* ok, it looks sane as far as we can check without
         * actually mapping the pack file.
         */
+       p->index_version = 0;
+       p->index_data = NULL;
+       p->index_size = 0;
+       p->num_objects = 0;
        p->pack_size = st.st_size;
        p->next = NULL;
        p->windows = NULL;
@@ -950,7 +972,7 @@ int check_sha1_signature(const unsigned char *sha1, void *map, unsigned long siz
        return hashcmp(sha1, real_sha1) ? -1 : 0;
 }
 
-void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
+static void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
 {
        struct stat st;
        void *map;
@@ -985,7 +1007,7 @@ void *map_sha1_file(const unsigned char *sha1, unsigned long *size)
        return map;
 }
 
-int legacy_loose_object(unsigned char *map)
+static int legacy_loose_object(unsigned char *map)
 {
        unsigned int word;
 
@@ -1047,6 +1069,14 @@ static int unpack_sha1_header(z_stream *stream, unsigned char *map, unsigned lon
                return inflate(stream, 0);
        }
 
+
+       /*
+        * There used to be a second loose object header format which
+        * was meant to mimic the in-pack format, allowing for direct
+        * copy of the object data.  This format turned up not to be
+        * really worth it and we don't write it any longer.  But we
+        * can still read it.
+        */
        used = unpack_object_header_gently(map, mapsize, &type, &size);
        if (!used || !valid_loose_object_type[type])
                return -1;
@@ -1122,7 +1152,7 @@ static int parse_sha1_header(const char *hdr, unsigned long *sizep)
        unsigned long size;
 
        /*
-        * The type can be at most ten bytes (including the 
+        * The type can be at most ten bytes (including the
         * terminating '\0' that we add), and is followed by
         * a space.
         */
@@ -1577,10 +1607,15 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
        return data;
 }
 
-const unsigned char *nth_packed_object_sha1(const struct packed_git *p,
+const unsigned char *nth_packed_object_sha1(struct packed_git *p,
                                            uint32_t n)
 {
        const unsigned char *index = p->index_data;
+       if (!index) {
+               if (open_pack_index(p))
+                       return NULL;
+               index = p->index_data;
+       }
        if (n >= p->num_objects)
                return NULL;
        index += 4 * 256;
@@ -1617,6 +1652,12 @@ off_t find_pack_entry_one(const unsigned char *sha1,
        const unsigned char *index = p->index_data;
        unsigned hi, lo;
 
+       if (!index) {
+               if (open_pack_index(p))
+                       return 0;
+               level1_ofs = p->index_data;
+               index = p->index_data;
+       }
        if (p->index_version > 1) {
                level1_ofs += 2;
                index += 8;
@@ -1659,20 +1700,25 @@ static int matches_pack_name(struct packed_git *p, const char *ig)
 
 static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, const char **ignore_packed)
 {
+       static struct packed_git *last_found = (void *)1;
        struct packed_git *p;
        off_t offset;
 
        prepare_packed_git();
+       if (!packed_git)
+               return 0;
+       p = (last_found == (void *)1) ? packed_git : last_found;
 
-       for (p = packed_git; p; p = p->next) {
+       do {
                if (ignore_packed) {
                        const char **ig;
                        for (ig = ignore_packed; *ig; ig++)
                                if (!matches_pack_name(p, *ig))
                                        break;
                        if (*ig)
-                               continue;
+                               goto next;
                }
+
                offset = find_pack_entry_one(sha1, p);
                if (offset) {
                        /*
@@ -1685,18 +1731,27 @@ static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, cons
                         */
                        if (p->pack_fd == -1 && open_packed_git(p)) {
                                error("packfile %s cannot be accessed", p->pack_name);
-                               continue;
+                               goto next;
                        }
                        e->offset = offset;
                        e->p = p;
                        hashcpy(e->sha1, sha1);
+                       last_found = p;
                        return 1;
                }
-       }
+
+               next:
+               if (p == last_found)
+                       p = packed_git;
+               else
+                       p = p->next;
+               if (p == last_found)
+                       p = p->next;
+       } while (p);
        return 0;
 }
 
-struct packed_git *find_sha1_pack(const unsigned char *sha1, 
+struct packed_git *find_sha1_pack(const unsigned char *sha1,
                                  struct packed_git *packs)
 {
        struct packed_git *p;
@@ -1975,40 +2030,6 @@ static int write_buffer(int fd, const void *buf, size_t len)
        return 0;
 }
 
-static int write_binary_header(unsigned char *hdr, enum object_type type, unsigned long len)
-{
-       int hdr_len;
-       unsigned char c;
-
-       c = (type << 4) | (len & 15);
-       len >>= 4;
-       hdr_len = 1;
-       while (len) {
-               *hdr++ = c | 0x80;
-               hdr_len++;
-               c = (len & 0x7f);
-               len >>= 7;
-       }
-       *hdr = c;
-       return hdr_len;
-}
-
-static void setup_object_header(z_stream *stream, const char *type, unsigned long len)
-{
-       int obj_type, hdrlen;
-
-       if (use_legacy_headers) {
-               while (deflate(stream, 0) == Z_OK)
-                       /* nothing */;
-               return;
-       }
-       obj_type = type_from_string(type);
-       hdrlen = write_binary_header(stream->next_out, obj_type, len);
-       stream->total_out = hdrlen;
-       stream->next_out += hdrlen;
-       stream->avail_out -= hdrlen;
-}
-
 int hash_sha1_file(const void *buf, unsigned long len, const char *type,
                    unsigned char *sha1)
 {
@@ -2075,7 +2096,8 @@ int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned cha
        /* First header.. */
        stream.next_in = (unsigned char *)hdr;
        stream.avail_in = hdrlen;
-       setup_object_header(&stream, type, len);
+       while (deflate(&stream, 0) == Z_OK)
+               /* nothing */;
 
        /* Then the data itself.. */
        stream.next_in = buf;
index 55f25a2d3b49b1d565a9840b7dcfb2e22687cdd3..858f08c34a2de917b630d02974a839d626d23e7f 100644 (file)
@@ -76,8 +76,11 @@ static int find_short_packed_object(int len, const unsigned char *match, unsigne
 
        prepare_packed_git();
        for (p = packed_git; p && found < 2; p = p->next) {
-               uint32_t num = p->num_objects;
-               uint32_t first = 0, last = num;
+               uint32_t num, last;
+               uint32_t first = 0;
+               open_pack_index(p);
+               num = p->num_objects;
+               last = num;
                while (first < last) {
                        uint32_t mid = (first + last) / 2;
                        const unsigned char *now;
@@ -133,6 +136,7 @@ static int find_unique_short_object(int len, char *canonical,
        int has_unpacked, has_packed;
        unsigned char unpacked_sha1[20], packed_sha1[20];
 
+       prepare_alt_odb();
        has_unpacked = find_short_object_filename(len, canonical, unpacked_sha1);
        has_packed = find_short_packed_object(len, res, packed_sha1);
        if (!has_unpacked && !has_packed)
@@ -654,7 +658,6 @@ int get_sha1_with_mode(const char *name, unsigned char *sha1, unsigned *mode)
        const char *cp;
 
        *mode = S_IFINVALID;
-       prepare_alt_odb();
        ret = get_sha1_1(name, namelen, sha1);
        if (!ret)
                return ret;
@@ -679,8 +682,6 @@ int get_sha1_with_mode(const char *name, unsigned char *sha1, unsigned *mode)
                namelen = namelen - (cp - name);
                if (!active_cache)
                        read_cache();
-               if (active_nr < 0)
-                       return -1;
                pos = cache_name_pos(cp, namelen);
                if (pos < 0)
                        pos = -pos - 1;
index d17868929ceadbd2565549a60cb738a95c90a4bb..dbd9f5ad0ac21e70fc3a095d8e2938f245c238d3 100644 (file)
--- a/shallow.c
+++ b/shallow.c
@@ -101,4 +101,3 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
 
        return result;
 }
-
index 498d41e19b5756c82ef8e0ead779f40812f84227..20c35f03dd1fb468c7cecc71f91951657f229f5e 100644 (file)
@@ -29,24 +29,24 @@ static int serve_object(int fd_in, int fd_out) {
        }
        if (!size)
                return -1;
-       
+
        if (verbose)
                fprintf(stderr, "Serving %s\n", sha1_to_hex(sha1));
 
        remote = 0;
-       
+
        if (!has_sha1_file(sha1)) {
                fprintf(stderr, "git-ssh-upload: could not find %s\n",
                        sha1_to_hex(sha1));
                remote = -1;
        }
-       
+
        if (write_in_full(fd_out, &remote, 1) != 1)
                return 0;
-       
+
        if (remote < 0)
                return 0;
-       
+
        return write_sha1_to_fd(fd_out, sha1);
 }
 
index 7f14b0fb59bd7e14979b002f441ae84ff5b0e9a2..e33d06b87c978ad7484c9d6bf972681c3d6cdeb0 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -39,4 +39,3 @@ void read_line(struct strbuf *sb, FILE *fp, int term) {
                sb->eof = 1;
        strbuf_end(sb);
 }
-
index 19e38508a70708b78de6467df71ed36373999d6a..b25caca887103d81d406d2e8696e28e598ec8f7b 100644 (file)
@@ -28,4 +28,3 @@ full-svn-test:
 
 .PHONY: $(T) clean
 .NOTPARALLEL:
-
index d195603dfa9dc0328f1fcfd6c79c6c6cbe424f0c..168329adbc4edeedc98501575ccc9b9c81f0c061 100644 (file)
@@ -10,14 +10,14 @@ do
        echo This is Z/$p from the original tree. >Z/$p
        test_expect_success \
            "adding test file $p and Z/$p" \
-           'git-update-index --add $p &&
-           git-update-index --add Z/$p'
+           'git update-index --add $p &&
+           git update-index --add Z/$p'
     done
 done
 echo This is SS from the original tree. >SS
 test_expect_success \
     'adding test file SS' \
-    'git-update-index --add SS'
+    'git update-index --add SS'
 cat >TT <<\EOF
 This is a trivial merge sample text.
 Branch A is expected to upcase this word, here.
@@ -32,10 +32,10 @@ This concludes the trivial merge sample file.
 EOF
 test_expect_success \
     'adding test file TT' \
-    'git-update-index --add TT'
+    'git update-index --add TT'
 test_expect_success \
     'prepare initial tree' \
-    'tree_O=$(git-write-tree)'
+    'tree_O=$(git write-tree)'
 
 ################################################################
 # Branch A and B makes the changes according to the above matrix.
@@ -47,14 +47,14 @@ to_remove=$(echo D? Z/D?)
 rm -f $to_remove
 test_expect_success \
     'change in branch A (removal)' \
-    'git-update-index --remove $to_remove'
+    'git update-index --remove $to_remove'
 
 for p in M? Z/M?
 do
     echo This is modified $p in the branch A. >$p
     test_expect_success \
        'change in branch A (modification)' \
-        "git-update-index $p"
+        "git update-index $p"
 done
 
 for p in AN AA Z/AN Z/AA
@@ -62,32 +62,32 @@ do
     echo This is added $p in the branch A. >$p
     test_expect_success \
        'change in branch A (addition)' \
-       "git-update-index --add $p"
+       "git update-index --add $p"
 done
 
 echo This is SS from the modified tree. >SS
 echo This is LL from the modified tree. >LL
 test_expect_success \
     'change in branch A (addition)' \
-    'git-update-index --add LL &&
-     git-update-index SS'
+    'git update-index --add LL &&
+     git update-index SS'
 mv TT TT-
 sed -e '/Branch A/s/word/WORD/g' <TT- >TT
 rm -f TT-
 test_expect_success \
     'change in branch A (edit)' \
-    'git-update-index TT'
+    'git update-index TT'
 
 mkdir DF
 echo Branch A makes a file at DF/DF, creating a directory DF. >DF/DF
 test_expect_success \
     'change in branch A (change file to directory)' \
-    'git-update-index --add DF/DF'
+    'git update-index --add DF/DF'
 
 test_expect_success \
     'recording branch A tree' \
-    'tree_A=$(git-write-tree)'
-          
+    'tree_A=$(git write-tree)'
+
 ################################################################
 # Branch B
 # Start from O
@@ -96,21 +96,21 @@ rm -rf [NDMASLT][NDMASLT] Z DF
 mkdir Z
 test_expect_success \
     'reading original tree and checking out' \
-    'git-read-tree $tree_O &&
-     git-checkout-index -a'
+    'git read-tree $tree_O &&
+     git checkout-index -a'
 
 to_remove=$(echo ?D Z/?D)
 rm -f $to_remove
 test_expect_success \
     'change in branch B (removal)' \
-    "git-update-index --remove $to_remove"
+    "git update-index --remove $to_remove"
 
 for p in ?M Z/?M
 do
     echo This is modified $p in the branch B. >$p
     test_expect_success \
        'change in branch B (modification)' \
-       "git-update-index $p"
+       "git update-index $p"
 done
 
 for p in NA AA Z/NA Z/AA
@@ -118,41 +118,41 @@ do
     echo This is added $p in the branch B. >$p
     test_expect_success \
        'change in branch B (addition)' \
-       "git-update-index --add $p"
+       "git update-index --add $p"
 done
 echo This is SS from the modified tree. >SS
 echo This is LL from the modified tree. >LL
 test_expect_success \
     'change in branch B (addition and modification)' \
-    'git-update-index --add LL &&
-     git-update-index SS'
+    'git update-index --add LL &&
+     git update-index SS'
 mv TT TT-
 sed -e '/Branch B/s/word/WORD/g' <TT- >TT
 rm -f TT-
 test_expect_success \
     'change in branch B (modification)' \
-    'git-update-index TT'
+    'git update-index TT'
 
 echo Branch B makes a file at DF. >DF
 test_expect_success \
     'change in branch B (addition of a file to conflict with directory)' \
-    'git-update-index --add DF'
+    'git update-index --add DF'
 
 test_expect_success \
     'recording branch B tree' \
-    'tree_B=$(git-write-tree)'
+    'tree_B=$(git write-tree)'
 
 test_expect_success \
     'keep contents of 3 trees for easy access' \
     'rm -f .git/index &&
-     git-read-tree $tree_O &&
+     git read-tree $tree_O &&
      mkdir .orig-O &&
-     git-checkout-index --prefix=.orig-O/ -f -q -a &&
+     git checkout-index --prefix=.orig-O/ -f -q -a &&
      rm -f .git/index &&
-     git-read-tree $tree_A &&
+     git read-tree $tree_A &&
      mkdir .orig-A &&
-     git-checkout-index --prefix=.orig-A/ -f -q -a &&
+     git checkout-index --prefix=.orig-A/ -f -q -a &&
      rm -f .git/index &&
-     git-read-tree $tree_B &&
+     git read-tree $tree_B &&
      mkdir .orig-B &&
-     git-checkout-index --prefix=.orig-B/ -f -q -a'
+     git checkout-index --prefix=.orig-B/ -f -q -a'
index 186de7024336ca98bd5dcea6f675e1fc221d0ce0..4bba9c0717731bfc6912ac28f98c10aa0f3e17fd 100755 (executable)
@@ -31,13 +31,13 @@ fi
 . ./test-lib.sh
 
 ################################################################
-# git-init has been done in an empty repository.
+# git init has been done in an empty repository.
 # make sure it is empty.
 
 find .git/objects -type f -print >should-be-empty
 test_expect_success \
-    '.git/objects should be empty after git-init in an empty repo.' \
-    'cmp -s /dev/null should-be-empty' 
+    '.git/objects should be empty after git init in an empty repo.' \
+    'cmp -s /dev/null should-be-empty'
 
 # also it should have 2 subdirectories; no fan-out anymore, pack, and info.
 # 3 is counting "objects" itself
@@ -51,17 +51,17 @@ test_expect_success \
 
 # updating a new file without --add should fail.
 test_expect_failure \
-    'git-update-index without --add should fail adding.' \
-    'git-update-index should-be-empty'
+    'git update-index without --add should fail adding.' \
+    'git update-index should-be-empty'
 
 # and with --add it should succeed, even if it is empty (it used to fail).
 test_expect_success \
-    'git-update-index with --add should succeed.' \
-    'git-update-index --add should-be-empty'
+    'git update-index with --add should succeed.' \
+    'git update-index --add should-be-empty'
 
 test_expect_success \
-    'writing tree out with git-write-tree' \
-    'tree=$(git-write-tree)'
+    'writing tree out with git write-tree' \
+    'tree=$(git write-tree)'
 
 # we know the shape and contents of the tree and know the object ID for it.
 test_expect_success \
@@ -71,17 +71,17 @@ test_expect_success \
 # Removing paths.
 rm -f should-be-empty full-of-directories
 test_expect_failure \
-    'git-update-index without --remove should fail removing.' \
-    'git-update-index should-be-empty'
+    'git update-index without --remove should fail removing.' \
+    'git update-index should-be-empty'
 
 test_expect_success \
-    'git-update-index with --remove should be able to remove.' \
-    'git-update-index --remove should-be-empty'
+    'git update-index with --remove should be able to remove.' \
+    'git update-index --remove should-be-empty'
 
 # Empty tree can be written with recent write-tree.
 test_expect_success \
-    'git-write-tree should be able to write an empty tree.' \
-    'tree=$(git-write-tree)'
+    'git write-tree should be able to write an empty tree.' \
+    'tree=$(git write-tree)'
 
 test_expect_success \
     'validate object ID of a known tree.' \
@@ -95,13 +95,13 @@ do
     ln -s "hello $p" ${p}sym
 done
 test_expect_success \
-    'adding various types of objects with git-update-index --add.' \
-    'find path* ! -type d -print | xargs git-update-index --add'
+    'adding various types of objects with git update-index --add.' \
+    'find path* ! -type d -print | xargs git update-index --add'
 
 # Show them and see that matches what we expect.
 test_expect_success \
-    'showing stage with git-ls-files --stage' \
-    'git-ls-files --stage >current'
+    'showing stage with git ls-files --stage' \
+    'git ls-files --stage >current'
 
 cat >expected <<\EOF
 100644 f87290f8eb2cbbea7857214459a0739927eab154 0      path0
@@ -114,19 +114,19 @@ cat >expected <<\EOF
 120000 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c 0      path3/subp3/file3sym
 EOF
 test_expect_success \
-    'validate git-ls-files output for a known tree.' \
+    'validate git ls-files output for a known tree.' \
     'diff current expected'
 
 test_expect_success \
-    'writing tree out with git-write-tree.' \
-    'tree=$(git-write-tree)'
+    'writing tree out with git write-tree.' \
+    'tree=$(git write-tree)'
 test_expect_success \
     'validate object ID for a known tree.' \
     'test "$tree" = 087704a96baf1c2d1c869a8b084481e121c88b5b'
 
 test_expect_success \
-    'showing tree with git-ls-tree' \
-    'git-ls-tree $tree >current'
+    'showing tree with git ls-tree' \
+    'git ls-tree $tree >current'
 cat >expected <<\EOF
 100644 blob f87290f8eb2cbbea7857214459a0739927eab154   path0
 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01   path0sym
@@ -134,14 +134,14 @@ cat >expected <<\EOF
 040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3   path3
 EOF
 test_expect_success \
-    'git-ls-tree output for a known tree.' \
+    'git ls-tree output for a known tree.' \
     'diff current expected'
 
 # This changed in ls-tree pathspec change -- recursive does
 # not show tree nodes anymore.
 test_expect_success \
-    'showing tree with git-ls-tree -r' \
-    'git-ls-tree -r $tree >current'
+    'showing tree with git ls-tree -r' \
+    'git ls-tree -r $tree >current'
 cat >expected <<\EOF
 100644 blob f87290f8eb2cbbea7857214459a0739927eab154   path0
 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01   path0sym
@@ -153,13 +153,13 @@ cat >expected <<\EOF
 120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c   path3/subp3/file3sym
 EOF
 test_expect_success \
-    'git-ls-tree -r output for a known tree.' \
+    'git ls-tree -r output for a known tree.' \
     'diff current expected'
 
 # But with -r -t we can have both.
 test_expect_success \
-    'showing tree with git-ls-tree -r -t' \
-    'git-ls-tree -r -t $tree >current'
+    'showing tree with git ls-tree -r -t' \
+    'git ls-tree -r -t $tree >current'
 cat >expected <<\EOF
 100644 blob f87290f8eb2cbbea7857214459a0739927eab154   path0
 120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01   path0sym
@@ -174,19 +174,19 @@ cat >expected <<\EOF
 120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c   path3/subp3/file3sym
 EOF
 test_expect_success \
-    'git-ls-tree -r output for a known tree.' \
+    'git ls-tree -r output for a known tree.' \
     'diff current expected'
 
 test_expect_success \
-    'writing partial tree out with git-write-tree --prefix.' \
-    'ptree=$(git-write-tree --prefix=path3)'
+    'writing partial tree out with git write-tree --prefix.' \
+    'ptree=$(git write-tree --prefix=path3)'
 test_expect_success \
     'validate object ID for a known tree.' \
     'test "$ptree" = 21ae8269cacbe57ae09138dcc3a2887f904d02b3'
 
 test_expect_success \
-    'writing partial tree out with git-write-tree --prefix.' \
-    'ptree=$(git-write-tree --prefix=path3/subp3)'
+    'writing partial tree out with git write-tree --prefix.' \
+    'ptree=$(git write-tree --prefix=path3/subp3)'
 test_expect_success \
     'validate object ID for a known tree.' \
     'test "$ptree" = 3c5e5399f3a333eddecce7a9b9465b63f65f51e2'
@@ -202,24 +202,24 @@ EOF
 rm .git/index
 test_expect_success \
     'put invalid objects into the index.' \
-    'git-update-index --index-info < badobjects'
+    'git update-index --index-info < badobjects'
 
 test_expect_failure \
     'writing this tree without --missing-ok.' \
-    'git-write-tree'
+    'git write-tree'
 
 test_expect_success \
     'writing this tree with --missing-ok.' \
-    'git-write-tree --missing-ok'
+    'git write-tree --missing-ok'
 
 
 ################################################################
 rm .git/index
 test_expect_success \
-    'git-read-tree followed by write-tree should be idempotent.' \
-    'git-read-tree $tree &&
+    'git read-tree followed by write-tree should be idempotent.' \
+    'git read-tree $tree &&
      test -f .git/index &&
-     newtree=$(git-write-tree) &&
+     newtree=$(git write-tree) &&
      test "$newtree" = "$tree"'
 
 cat >expected <<\EOF
@@ -233,36 +233,36 @@ cat >expected <<\EOF
 :120000 120000 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c 0000000000000000000000000000000000000000 M     path3/subp3/file3sym
 EOF
 test_expect_success \
-    'validate git-diff-files output for a know cache/work tree state.' \
-    'git-diff-files >current && diff >/dev/null -b current expected'
+    'validate git diff-files output for a know cache/work tree state.' \
+    'git diff-files >current && diff >/dev/null -b current expected'
 
 test_expect_success \
-    'git-update-index --refresh should succeed.' \
-    'git-update-index --refresh'
+    'git update-index --refresh should succeed.' \
+    'git update-index --refresh'
 
 test_expect_success \
-    'no diff after checkout and git-update-index --refresh.' \
-    'git-diff-files >current && cmp -s current /dev/null'
+    'no diff after checkout and git update-index --refresh.' \
+    'git diff-files >current && cmp -s current /dev/null'
 
 ################################################################
 P=087704a96baf1c2d1c869a8b084481e121c88b5b
 test_expect_success \
-    'git-commit-tree records the correct tree in a commit.' \
-    'commit0=$(echo NO | git-commit-tree $P) &&
+    'git commit-tree records the correct tree in a commit.' \
+    'commit0=$(echo NO | git commit-tree $P) &&
      tree=$(git show --pretty=raw $commit0 |
         sed -n -e "s/^tree //p" -e "/^author /q") &&
      test "z$tree" = "z$P"'
 
 test_expect_success \
-    'git-commit-tree records the correct parent in a commit.' \
-    'commit1=$(echo NO | git-commit-tree $P -p $commit0) &&
+    'git commit-tree records the correct parent in a commit.' \
+    'commit1=$(echo NO | git commit-tree $P -p $commit0) &&
      parent=$(git show --pretty=raw $commit1 |
         sed -n -e "s/^parent //p" -e "/^author /q") &&
      test "z$commit0" = "z$parent"'
 
 test_expect_success \
-    'git-commit-tree omits duplicated parent in a commit.' \
-    'commit2=$(echo NO | git-commit-tree $P -p $commit0 -p $commit0) &&
+    'git commit-tree omits duplicated parent in a commit.' \
+    'commit2=$(echo NO | git commit-tree $P -p $commit0 -p $commit0) &&
      parent=$(git show --pretty=raw $commit2 |
         sed -n -e "s/^parent //p" -e "/^author /q" |
         sort -u) &&
diff --git a/t/t0022-crlf-rename.sh b/t/t0022-crlf-rename.sh
new file mode 100755 (executable)
index 0000000..430a1d1
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+test_description='ignore CR in CRLF sequence while computing similiarity'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+
+       cat ../t0022-crlf-rename.sh >sample &&
+       git add sample &&
+
+       test_tick &&
+       git commit -m Initial &&
+
+       sed -e "s/\$/\r/" ../t0022-crlf-rename.sh >elpmas &&
+       git add elpmas &&
+       rm -f sample &&
+
+       test_tick &&
+       git commit -a -m Second
+
+'
+
+test_expect_success 'diff -M' '
+
+       git diff-tree -M -r --name-status HEAD^ HEAD |
+       sed -e "s/R[0-9]*/RNUM/" >actual &&
+       echo "RNUM      sample  elpmas" >expect &&
+       diff -u expect actual
+
+'
+
+test_done
diff --git a/t/t0030-stripspace.sh b/t/t0030-stripspace.sh
new file mode 100755 (executable)
index 0000000..fdc9fdc
--- /dev/null
@@ -0,0 +1,355 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Carlos Rica
+#
+
+test_description='git stripspace'
+
+. ./test-lib.sh
+
+t40='A quick brown fox jumps over the lazy do'
+s40='                                        '
+sss="$s40$s40$s40$s40$s40$s40$s40$s40$s40$s40" # 400
+ttt="$t40$t40$t40$t40$t40$t40$t40$t40$t40$t40" # 400
+
+test_expect_success \
+    'long lines without spaces should be unchanged' '
+    echo "$ttt" >expect &&
+    git stripspace <expect >actual &&
+    git diff expect actual &&
+
+    echo "$ttt$ttt" >expect &&
+    git stripspace <expect >actual &&
+    git diff expect actual &&
+
+    echo "$ttt$ttt$ttt" >expect &&
+    git stripspace <expect >actual &&
+    git diff expect actual &&
+
+    echo "$ttt$ttt$ttt$ttt" >expect &&
+    git stripspace <expect >actual &&
+    git diff expect actual
+'
+
+test_expect_success \
+    'lines with spaces at the beginning should be unchanged' '
+    echo "$sss$ttt" >expect &&
+    git stripspace <expect >actual &&
+    git diff expect actual &&
+
+    echo "$sss$sss$ttt" >expect &&
+    git stripspace <expect >actual &&
+    git diff expect actual &&
+
+    echo "$sss$sss$sss$ttt" >expect &&
+    git stripspace <expect >actual &&
+    git diff expect actual
+'
+
+test_expect_success \
+    'lines with intermediate spaces should be unchanged' '
+    echo "$ttt$sss$ttt" >expect &&
+    git stripspace <expect >actual &&
+    git diff expect actual &&
+
+    echo "$ttt$sss$sss$ttt" >expect &&
+    git stripspace <expect >actual &&
+    git diff expect actual
+'
+
+test_expect_success \
+    'consecutive blank lines should be unified' '
+    printf "$ttt\n\n$ttt\n" > expect &&
+    printf "$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt$ttt\n\n$ttt\n" > expect &&
+    printf "$ttt$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt$ttt$ttt\n\n$ttt\n" > expect &&
+    printf "$ttt$ttt$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n\n$ttt\n" > expect &&
+    printf "$ttt\n\n\n\n\n$ttt\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n\n$ttt$ttt\n" > expect &&
+    printf "$ttt\n\n\n\n\n$ttt$ttt\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n\n$ttt$ttt$ttt\n" > expect &&
+    printf "$ttt\n\n\n\n\n$ttt$ttt$ttt\n" | git stripspace >actual &&
+    git diff expect actual
+'
+
+test_expect_success \
+    'consecutive blank lines at the beginning should be removed' '
+    printf "" > expect &&
+    printf "\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "" > expect &&
+    printf "\n\n\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "" > expect &&
+    printf "$sss\n$sss\n$sss\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "" > expect &&
+    printf "$sss$sss\n$sss\n\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "" > expect &&
+    printf "\n$sss\n$sss$sss\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "" > expect &&
+    printf "$sss$sss$sss$sss\n\n\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "" > expect &&
+    printf "\n$sss$sss$sss$sss\n\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "" > expect &&
+    printf "\n\n$sss$sss$sss$sss\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n" > expect &&
+    printf "\n$ttt\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n" > expect &&
+    printf "\n\n\n$ttt\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt$ttt\n" > expect &&
+    printf "\n\n\n$ttt$ttt\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt$ttt$ttt\n" > expect &&
+    printf "\n\n\n$ttt$ttt$ttt\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt$ttt$ttt$ttt\n" > expect &&
+    printf "\n\n\n$ttt$ttt$ttt$ttt\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n" > expect &&
+    printf "$sss\n$sss\n$sss\n$ttt\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n" > expect &&
+    printf "\n$sss\n$sss$sss\n$ttt\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n" > expect &&
+    printf "$sss$sss\n$sss\n\n$ttt\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n" > expect &&
+    printf "$sss$sss$sss\n\n\n$ttt\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n" > expect &&
+    printf "\n$sss$sss$sss\n\n$ttt\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n" > expect &&
+    printf "\n\n$sss$sss$sss\n$ttt\n" | git stripspace >actual &&
+    git diff expect actual
+'
+
+test_expect_success \
+    'consecutive blank lines at the end should be removed' '
+    printf "$ttt\n" > expect &&
+    printf "$ttt\n\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n" > expect &&
+    printf "$ttt\n\n\n\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt$ttt\n" > expect &&
+    printf "$ttt$ttt\n\n\n\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt$ttt$ttt\n" > expect &&
+    printf "$ttt$ttt$ttt\n\n\n\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt$ttt$ttt$ttt\n" > expect &&
+    printf "$ttt$ttt$ttt$ttt\n\n\n\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n" > expect &&
+    printf "$ttt\n$sss\n$sss\n$sss\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n" > expect &&
+    printf "$ttt\n\n$sss\n$sss$sss\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n" > expect &&
+    printf "$ttt\n$sss$sss\n$sss\n\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n" > expect &&
+    printf "$ttt\n$sss$sss$sss\n\n\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n" > expect &&
+    printf "$ttt\n\n$sss$sss$sss\n\n" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n" > expect &&
+    printf "$ttt\n\n\n$sss$sss$sss\n" | git stripspace >actual &&
+    git diff expect actual
+'
+
+test_expect_success \
+    'text without newline at end should end with newline' '
+    test `printf "$ttt" | git stripspace | wc -l` -gt 0 &&
+    test `printf "$ttt$ttt" | git stripspace | wc -l` -gt 0 &&
+    test `printf "$ttt$ttt$ttt" | git stripspace | wc -l` -gt 0 &&
+    test `printf "$ttt$ttt$ttt$ttt" | git stripspace | wc -l` -gt 0
+'
+
+# text plus spaces at the end:
+
+test_expect_success \
+    'text plus spaces without newline at end should end with newline' '
+    test `printf "$ttt$sss" | git stripspace | wc -l` -gt 0 &&
+    test `printf "$ttt$ttt$sss" | git stripspace | wc -l` -gt 0 &&
+    test `printf "$ttt$ttt$ttt$sss" | git stripspace | wc -l` -gt 0
+    test `printf "$ttt$sss$sss" | git stripspace | wc -l` -gt 0 &&
+    test `printf "$ttt$ttt$sss$sss" | git stripspace | wc -l` -gt 0 &&
+    test `printf "$ttt$sss$sss$sss" | git stripspace | wc -l` -gt 0
+'
+
+test_expect_failure \
+    'text plus spaces without newline at end should not show spaces' '
+    printf "$ttt$sss" | git stripspace | grep -q "  " ||
+    printf "$ttt$ttt$sss" | git stripspace | grep -q "  " ||
+    printf "$ttt$ttt$ttt$sss" | git stripspace | grep -q "  " ||
+    printf "$ttt$sss$sss" | git stripspace | grep -q "  " ||
+    printf "$ttt$ttt$sss$sss" | git stripspace | grep -q "  " ||
+    printf "$ttt$sss$sss$sss" | git stripspace | grep -q "  "
+'
+
+test_expect_success \
+    'text plus spaces without newline should show the correct lines' '
+    printf "$ttt\n" >expect &&
+    printf "$ttt$sss" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n" >expect &&
+    printf "$ttt$sss$sss" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt\n" >expect &&
+    printf "$ttt$sss$sss$sss" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt$ttt\n" >expect &&
+    printf "$ttt$ttt$sss" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt$ttt\n" >expect &&
+    printf "$ttt$ttt$sss$sss" | git stripspace >actual &&
+    git diff expect actual &&
+
+    printf "$ttt$ttt$ttt\n" >expect &&
+    printf "$ttt$ttt$ttt$sss" | git stripspace >actual &&
+    git diff expect actual
+'
+
+test_expect_failure \
+    'text plus spaces at end should not show spaces' '
+    echo "$ttt$sss" | git stripspace | grep -q "  " ||
+    echo "$ttt$ttt$sss" | git stripspace | grep -q "  " ||
+    echo "$ttt$ttt$ttt$sss" | git stripspace | grep -q "  " ||
+    echo "$ttt$sss$sss" | git stripspace | grep -q "  " ||
+    echo "$ttt$ttt$sss$sss" | git stripspace | grep -q "  " ||
+    echo "$ttt$sss$sss$sss" | git stripspace | grep -q "  "
+'
+
+test_expect_success \
+    'text plus spaces at end should be cleaned and newline must remain' '
+    echo "$ttt" >expect &&
+    echo "$ttt$sss" | git stripspace >actual &&
+    git diff expect actual &&
+
+    echo "$ttt" >expect &&
+    echo "$ttt$sss$sss" | git stripspace >actual &&
+    git diff expect actual &&
+
+    echo "$ttt" >expect &&
+    echo "$ttt$sss$sss$sss" | git stripspace >actual &&
+    git diff expect actual &&
+
+    echo "$ttt$ttt" >expect &&
+    echo "$ttt$ttt$sss" | git stripspace >actual &&
+    git diff expect actual &&
+
+    echo "$ttt$ttt" >expect &&
+    echo "$ttt$ttt$sss$sss" | git stripspace >actual &&
+    git diff expect actual &&
+
+    echo "$ttt$ttt$ttt" >expect &&
+    echo "$ttt$ttt$ttt$sss" | git stripspace >actual &&
+    git diff expect actual
+'
+
+# spaces only:
+
+test_expect_success \
+    'spaces with newline at end should be replaced with empty string' '
+    printf "" >expect &&
+
+    echo | git stripspace >actual &&
+    git diff expect actual &&
+
+    echo "$sss" | git stripspace >actual &&
+    git diff expect actual &&
+
+    echo "$sss$sss" | git stripspace >actual &&
+    git diff expect actual &&
+
+    echo "$sss$sss$sss" | git stripspace >actual &&
+    git diff expect actual &&
+
+    echo "$sss$sss$sss$sss" | git stripspace >actual &&
+    git diff expect actual
+'
+
+test_expect_failure \
+    'spaces without newline at end should not show spaces' '
+    printf "" | git stripspace | grep -q " " ||
+    printf "$sss" | git stripspace | grep -q " " ||
+    printf "$sss$sss" | git stripspace | grep -q " " ||
+    printf "$sss$sss$sss" | git stripspace | grep -q " " ||
+    printf "$sss$sss$sss$sss" | git stripspace | grep -q " "
+'
+
+test_expect_success \
+    'spaces without newline at end should be replaced with empty string' '
+    printf "" >expect &&
+
+    printf "" | git stripspace >actual &&
+    git diff expect actual
+
+    printf "$sss$sss" | git stripspace >actual &&
+    git diff expect actual
+
+    printf "$sss$sss$sss" | git stripspace >actual &&
+    git diff expect actual
+
+    printf "$sss$sss$sss$sss" | git stripspace >actual &&
+    git diff expect actual
+'
+
+test_done
index de4e5eb61f5cc197a51005c6cfbd3bf2b9428480..37add1b50472e23ccb6b938ac6cdadba0c097fb8 100755 (executable)
@@ -130,28 +130,28 @@ _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"
 
 check_result () {
-    git-ls-files --stage | sed -e 's/ '"$_x40"' / X /' >current &&
+    git ls-files --stage | sed -e 's/ '"$_x40"' / X /' >current &&
     git diff expected current
 }
 
 # This is done on an empty work directory, which is the normal
 # merge person behaviour.
 test_expect_success \
-    '3-way merge with git-read-tree -m, empty cache' \
+    '3-way merge with git read-tree -m, empty cache' \
     "rm -fr [NDMALTS][NDMALTSF] Z &&
      rm .git/index &&
-     git-read-tree -m $tree_O $tree_A $tree_B &&
+     git read-tree -m $tree_O $tree_A $tree_B &&
      check_result"
 
 # This starts out with the first head, which is the normal
 # patch submitter behaviour.
 test_expect_success \
-    '3-way merge with git-read-tree -m, match H' \
+    '3-way merge with git read-tree -m, match H' \
     "rm -fr [NDMALTS][NDMALTSF] Z &&
      rm .git/index &&
-     git-read-tree $tree_A &&
-     git-checkout-index -f -u -a &&
-     git-read-tree -m $tree_O $tree_A $tree_B &&
+     git read-tree $tree_A &&
+     git checkout-index -f -u -a &&
+     git read-tree -m $tree_O $tree_A $tree_B &&
      check_result"
 
 : <<\END_OF_CASE_TABLE
@@ -160,7 +160,7 @@ We have so far tested only empty index and clean-and-matching-A index
 case which are trivial.  Make sure index requirements are also
 checked.
 
-"git-read-tree -m O A B"
+"git read-tree -m O A B"
 
      O       A       B         result      index requirements
 -------------------------------------------------------------------
@@ -214,87 +214,87 @@ test_expect_failure \
     '1 - must not have an entry not in A.' \
     "rm -f .git/index XX &&
      echo XX >XX &&
-     git-update-index --add XX &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git update-index --add XX &&
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_success \
     '2 - must match B in !O && !A && B case.' \
     "rm -f .git/index NA &&
      cp .orig-B/NA NA &&
-     git-update-index --add NA &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git update-index --add NA &&
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_success \
     '2 - matching B alone is OK in !O && !A && B case.' \
     "rm -f .git/index NA &&
      cp .orig-B/NA NA &&
-     git-update-index --add NA &&
+     git update-index --add NA &&
      echo extra >>NA &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_success \
     '3 - must match A in !O && A && !B case.' \
     "rm -f .git/index AN &&
      cp .orig-A/AN AN &&
-     git-update-index --add AN &&
-     git-read-tree -m $tree_O $tree_A $tree_B &&
+     git update-index --add AN &&
+     git read-tree -m $tree_O $tree_A $tree_B &&
      check_result"
 
 test_expect_success \
     '3 - matching A alone is OK in !O && A && !B case.' \
     "rm -f .git/index AN &&
      cp .orig-A/AN AN &&
-     git-update-index --add AN &&
+     git update-index --add AN &&
      echo extra >>AN &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_failure \
     '3 (fail) - must match A in !O && A && !B case.' \
     "rm -f .git/index AN &&
      cp .orig-A/AN AN &&
      echo extra >>AN &&
-     git-update-index --add AN &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git update-index --add AN &&
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_success \
     '4 - must match and be up-to-date in !O && A && B && A!=B case.' \
     "rm -f .git/index AA &&
      cp .orig-A/AA AA &&
-     git-update-index --add AA &&
-     git-read-tree -m $tree_O $tree_A $tree_B &&
+     git update-index --add AA &&
+     git read-tree -m $tree_O $tree_A $tree_B &&
      check_result"
 
 test_expect_failure \
     '4 (fail) - must match and be up-to-date in !O && A && B && A!=B case.' \
     "rm -f .git/index AA &&
      cp .orig-A/AA AA &&
-     git-update-index --add AA &&
+     git update-index --add AA &&
      echo extra >>AA &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_failure \
     '4 (fail) - must match and be up-to-date in !O && A && B && A!=B case.' \
     "rm -f .git/index AA &&
      cp .orig-A/AA AA &&
      echo extra >>AA &&
-     git-update-index --add AA &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git update-index --add AA &&
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_success \
     '5 - must match in !O && A && B && A==B case.' \
     "rm -f .git/index LL &&
      cp .orig-A/LL LL &&
-     git-update-index --add LL &&
-     git-read-tree -m $tree_O $tree_A $tree_B &&
+     git update-index --add LL &&
+     git read-tree -m $tree_O $tree_A $tree_B &&
      check_result"
 
 test_expect_success \
     '5 - must match in !O && A && B && A==B case.' \
     "rm -f .git/index LL &&
      cp .orig-A/LL LL &&
-     git-update-index --add LL &&
+     git update-index --add LL &&
      echo extra >>LL &&
-     git-read-tree -m $tree_O $tree_A $tree_B &&
+     git read-tree -m $tree_O $tree_A $tree_B &&
      check_result"
 
 test_expect_failure \
@@ -302,117 +302,117 @@ test_expect_failure \
     "rm -f .git/index LL &&
      cp .orig-A/LL LL &&
      echo extra >>LL &&
-     git-update-index --add LL &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git update-index --add LL &&
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_failure \
     '6 - must not exist in O && !A && !B case' \
     "rm -f .git/index DD &&
      echo DD >DD
-     git-update-index --add DD &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git update-index --add DD &&
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_failure \
     '7 - must not exist in O && !A && B && O!=B case' \
     "rm -f .git/index DM &&
      cp .orig-B/DM DM &&
-     git-update-index --add DM &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git update-index --add DM &&
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_failure \
     '8 - must not exist in O && !A && B && O==B case' \
     "rm -f .git/index DN &&
      cp .orig-B/DN DN &&
-     git-update-index --add DN &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git update-index --add DN &&
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_success \
     '9 - must match and be up-to-date in O && A && !B && O!=A case' \
     "rm -f .git/index MD &&
      cp .orig-A/MD MD &&
-     git-update-index --add MD &&
-     git-read-tree -m $tree_O $tree_A $tree_B &&
+     git update-index --add MD &&
+     git read-tree -m $tree_O $tree_A $tree_B &&
      check_result"
 
 test_expect_failure \
     '9 (fail) - must match and be up-to-date in O && A && !B && O!=A case' \
     "rm -f .git/index MD &&
      cp .orig-A/MD MD &&
-     git-update-index --add MD &&
+     git update-index --add MD &&
      echo extra >>MD &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_failure \
     '9 (fail) - must match and be up-to-date in O && A && !B && O!=A case' \
     "rm -f .git/index MD &&
      cp .orig-A/MD MD &&
      echo extra >>MD &&
-     git-update-index --add MD &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git update-index --add MD &&
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_success \
     '10 - must match and be up-to-date in O && A && !B && O==A case' \
     "rm -f .git/index ND &&
      cp .orig-A/ND ND &&
-     git-update-index --add ND &&
-     git-read-tree -m $tree_O $tree_A $tree_B &&
+     git update-index --add ND &&
+     git read-tree -m $tree_O $tree_A $tree_B &&
      check_result"
 
 test_expect_failure \
     '10 (fail) - must match and be up-to-date in O && A && !B && O==A case' \
     "rm -f .git/index ND &&
      cp .orig-A/ND ND &&
-     git-update-index --add ND &&
+     git update-index --add ND &&
      echo extra >>ND &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_failure \
     '10 (fail) - must match and be up-to-date in O && A && !B && O==A case' \
     "rm -f .git/index ND &&
      cp .orig-A/ND ND &&
      echo extra >>ND &&
-     git-update-index --add ND &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git update-index --add ND &&
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_success \
     '11 - must match and be up-to-date in O && A && B && O!=A && O!=B && A!=B case' \
     "rm -f .git/index MM &&
      cp .orig-A/MM MM &&
-     git-update-index --add MM &&
-     git-read-tree -m $tree_O $tree_A $tree_B &&
+     git update-index --add MM &&
+     git read-tree -m $tree_O $tree_A $tree_B &&
      check_result"
 
 test_expect_failure \
     '11 (fail) - must match and be up-to-date in O && A && B && O!=A && O!=B && A!=B case' \
     "rm -f .git/index MM &&
      cp .orig-A/MM MM &&
-     git-update-index --add MM &&
+     git update-index --add MM &&
      echo extra >>MM &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_failure \
     '11 (fail) - must match and be up-to-date in O && A && B && O!=A && O!=B && A!=B case' \
     "rm -f .git/index MM &&
      cp .orig-A/MM MM &&
      echo extra >>MM &&
-     git-update-index --add MM &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git update-index --add MM &&
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_success \
     '12 - must match A in O && A && B && O!=A && A==B case' \
     "rm -f .git/index SS &&
      cp .orig-A/SS SS &&
-     git-update-index --add SS &&
-     git-read-tree -m $tree_O $tree_A $tree_B &&
+     git update-index --add SS &&
+     git read-tree -m $tree_O $tree_A $tree_B &&
      check_result"
 
 test_expect_success \
     '12 - must match A in O && A && B && O!=A && A==B case' \
     "rm -f .git/index SS &&
      cp .orig-A/SS SS &&
-     git-update-index --add SS &&
+     git update-index --add SS &&
      echo extra >>SS &&
-     git-read-tree -m $tree_O $tree_A $tree_B &&
+     git read-tree -m $tree_O $tree_A $tree_B &&
      check_result"
 
 test_expect_failure \
@@ -420,74 +420,74 @@ test_expect_failure \
     "rm -f .git/index SS &&
      cp .orig-A/SS SS &&
      echo extra >>SS &&
-     git-update-index --add SS &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git update-index --add SS &&
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_success \
     '13 - must match A in O && A && B && O!=A && O==B case' \
     "rm -f .git/index MN &&
      cp .orig-A/MN MN &&
-     git-update-index --add MN &&
-     git-read-tree -m $tree_O $tree_A $tree_B &&
+     git update-index --add MN &&
+     git read-tree -m $tree_O $tree_A $tree_B &&
      check_result"
 
 test_expect_success \
     '13 - must match A in O && A && B && O!=A && O==B case' \
     "rm -f .git/index MN &&
      cp .orig-A/MN MN &&
-     git-update-index --add MN &&
+     git update-index --add MN &&
      echo extra >>MN &&
-     git-read-tree -m $tree_O $tree_A $tree_B &&
+     git read-tree -m $tree_O $tree_A $tree_B &&
      check_result"
 
 test_expect_success \
     '14 - must match and be up-to-date in O && A && B && O==A && O!=B case' \
     "rm -f .git/index NM &&
      cp .orig-A/NM NM &&
-     git-update-index --add NM &&
-     git-read-tree -m $tree_O $tree_A $tree_B &&
+     git update-index --add NM &&
+     git read-tree -m $tree_O $tree_A $tree_B &&
      check_result"
 
 test_expect_success \
     '14 - may match B in O && A && B && O==A && O!=B case' \
     "rm -f .git/index NM &&
      cp .orig-B/NM NM &&
-     git-update-index --add NM &&
+     git update-index --add NM &&
      echo extra >>NM &&
-     git-read-tree -m $tree_O $tree_A $tree_B &&
+     git read-tree -m $tree_O $tree_A $tree_B &&
      check_result"
 
 test_expect_failure \
     '14 (fail) - must match and be up-to-date in O && A && B && O==A && O!=B case' \
     "rm -f .git/index NM &&
      cp .orig-A/NM NM &&
-     git-update-index --add NM &&
+     git update-index --add NM &&
      echo extra >>NM &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_failure \
     '14 (fail) - must match and be up-to-date in O && A && B && O==A && O!=B case' \
     "rm -f .git/index NM &&
      cp .orig-A/NM NM &&
      echo extra >>NM &&
-     git-update-index --add NM &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git update-index --add NM &&
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 test_expect_success \
     '15 - must match A in O && A && B && O==A && O==B case' \
     "rm -f .git/index NN &&
      cp .orig-A/NN NN &&
-     git-update-index --add NN &&
-     git-read-tree -m $tree_O $tree_A $tree_B &&
+     git update-index --add NN &&
+     git read-tree -m $tree_O $tree_A $tree_B &&
      check_result"
 
 test_expect_success \
     '15 - must match A in O && A && B && O==A && O==B case' \
     "rm -f .git/index NN &&
      cp .orig-A/NN NN &&
-     git-update-index --add NN &&
+     git update-index --add NN &&
      echo extra >>NN &&
-     git-read-tree -m $tree_O $tree_A $tree_B &&
+     git read-tree -m $tree_O $tree_A $tree_B &&
      check_result"
 
 test_expect_failure \
@@ -495,20 +495,20 @@ test_expect_failure \
     "rm -f .git/index NN &&
      cp .orig-A/NN NN &&
      echo extra >>NN &&
-     git-update-index --add NN &&
-     git-read-tree -m $tree_O $tree_A $tree_B"
+     git update-index --add NN &&
+     git read-tree -m $tree_O $tree_A $tree_B"
 
 # #16
 test_expect_success \
     '16 - A matches in one and B matches in another.' \
     'rm -f .git/index F16 &&
     echo F16 >F16 &&
-    git-update-index --add F16 &&
-    tree0=`git-write-tree` &&
+    git update-index --add F16 &&
+    tree0=`git write-tree` &&
     echo E16 >F16 &&
-    git-update-index F16 &&
-    tree1=`git-write-tree` &&
-    git-read-tree -m $tree0 $tree1 $tree1 $tree0 &&
-    git-ls-files --stage'
+    git update-index F16 &&
+    tree1=`git write-tree` &&
+    git read-tree -m $tree0 $tree1 $tree1 $tree0 &&
+    git ls-files --stage'
 
 test_done
index 030226bbfbd764a21aa59577b365868237d4f40b..b01b0037a0c4923549b5b2261ed931b3718a7671 100755 (executable)
@@ -11,7 +11,7 @@ There is the head (called H) and another commit (called M), which is
 simply ahead of H.  The index and the work tree contains a state that
 is derived from H, but may also have local changes.  This test checks
 all the combinations described in the two-tree merge "carry forward"
-rules, found in <Documentation/git-read-tree.txt>.
+rules, found in <Documentation/git read-tree.txt>.
 
 In the test, these paths are used:
         bozbar  - in H, stays in M, modified from bozbar to gnusto
@@ -23,7 +23,7 @@ In the test, these paths are used:
 . ./test-lib.sh
 
 read_tree_twoway () {
-    git-read-tree -m "$1" "$2" && git-ls-files --stage
+    git read-tree -m "$1" "$2" && git ls-files --stage
 }
 
 _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
@@ -37,7 +37,7 @@ compare_change () {
 }
 
 check_cache_at () {
-       clean_if_empty=`git-diff-files -- "$1"`
+       clean_if_empty=`git diff-files -- "$1"`
        case "$clean_if_empty" in
        '')  echo "$1: clean" ;;
        ?*)  echo "$1: dirty" ;;
@@ -68,24 +68,24 @@ test_expect_success \
      cat bozbar-old >bozbar &&
      echo rezrov >rezrov &&
      echo yomin >yomin &&
-     git-update-index --add nitfol bozbar rezrov &&
-     treeH=`git-write-tree` &&
+     git update-index --add nitfol bozbar rezrov &&
+     treeH=`git write-tree` &&
      echo treeH $treeH &&
-     git-ls-tree $treeH &&
+     git ls-tree $treeH &&
 
      cat bozbar-new >bozbar &&
-     git-update-index --add frotz bozbar --force-remove rezrov &&
-     git-ls-files --stage >M.out &&
-     treeM=`git-write-tree` &&
+     git update-index --add frotz bozbar --force-remove rezrov &&
+     git ls-files --stage >M.out &&
+     treeM=`git write-tree` &&
      echo treeM $treeM &&
-     git-ls-tree $treeM &&
-     git-diff-tree $treeH $treeM'
+     git ls-tree $treeM &&
+     git diff-tree $treeH $treeM'
 
 test_expect_success \
     '1, 2, 3 - no carry forward' \
     'rm -f .git/index &&
      read_tree_twoway $treeH $treeM &&
-     git-ls-files --stage >1-3.out &&
+     git ls-files --stage >1-3.out &&
      git diff M.out 1-3.out &&
      check_cache_at bozbar dirty &&
      check_cache_at frotz dirty &&
@@ -96,11 +96,11 @@ echo '+100644 X 0   yomin' >expected
 test_expect_success \
     '4 - carry forward local addition.' \
     'rm -f .git/index &&
-     git-read-tree $treeH &&
-     git-checkout-index -u -f -q -a &&
-     git-update-index --add yomin &&
+     git read-tree $treeH &&
+     git checkout-index -u -f -q -a &&
+     git update-index --add yomin &&
      read_tree_twoway $treeH $treeM &&
-     git-ls-files --stage >4.out || return 1
+     git ls-files --stage >4.out || return 1
      git diff M.out 4.out >4diff.out
      compare_change 4diff.out expected &&
      check_cache_at yomin clean'
@@ -108,13 +108,13 @@ test_expect_success \
 test_expect_success \
     '5 - carry forward local addition.' \
     'rm -f .git/index &&
-     git-read-tree $treeH &&
-     git-checkout-index -u -f -q -a &&
+     git read-tree $treeH &&
+     git checkout-index -u -f -q -a &&
      echo yomin >yomin &&
-     git-update-index --add yomin &&
+     git update-index --add yomin &&
      echo yomin yomin >yomin &&
      read_tree_twoway $treeH $treeM &&
-     git-ls-files --stage >5.out || return 1
+     git ls-files --stage >5.out || return 1
      git diff M.out 5.out >5diff.out
      compare_change 5diff.out expected &&
      check_cache_at yomin dirty'
@@ -122,83 +122,83 @@ test_expect_success \
 test_expect_success \
     '6 - local addition already has the same.' \
     'rm -f .git/index &&
-     git-read-tree $treeH &&
-     git-checkout-index -u -f -q -a &&
-     git-update-index --add frotz &&
+     git read-tree $treeH &&
+     git checkout-index -u -f -q -a &&
+     git update-index --add frotz &&
      read_tree_twoway $treeH $treeM &&
-     git-ls-files --stage >6.out &&
+     git ls-files --stage >6.out &&
      git diff M.out 6.out &&
      check_cache_at frotz clean'
 
 test_expect_success \
     '7 - local addition already has the same.' \
     'rm -f .git/index &&
-     git-read-tree $treeH &&
-     git-checkout-index -u -f -q -a &&
+     git read-tree $treeH &&
+     git checkout-index -u -f -q -a &&
      echo frotz >frotz &&
-     git-update-index --add frotz &&
+     git update-index --add frotz &&
      echo frotz frotz >frotz &&
      read_tree_twoway $treeH $treeM &&
-     git-ls-files --stage >7.out &&
+     git ls-files --stage >7.out &&
      git diff M.out 7.out &&
      check_cache_at frotz dirty'
 
 test_expect_success \
     '8 - conflicting addition.' \
     'rm -f .git/index &&
-     git-read-tree $treeH &&
-     git-checkout-index -u -f -q -a &&
+     git read-tree $treeH &&
+     git checkout-index -u -f -q -a &&
      echo frotz frotz >frotz &&
-     git-update-index --add frotz &&
+     git update-index --add frotz &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
 
 test_expect_success \
     '9 - conflicting addition.' \
     'rm -f .git/index &&
-     git-read-tree $treeH &&
-     git-checkout-index -u -f -q -a &&
+     git read-tree $treeH &&
+     git checkout-index -u -f -q -a &&
      echo frotz frotz >frotz &&
-     git-update-index --add frotz &&
+     git update-index --add frotz &&
      echo frotz >frotz &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
 
 test_expect_success \
     '10 - path removed.' \
     'rm -f .git/index &&
-     git-read-tree $treeH &&
-     git-checkout-index -u -f -q -a &&
+     git read-tree $treeH &&
+     git checkout-index -u -f -q -a &&
      echo rezrov >rezrov &&
-     git-update-index --add rezrov &&
+     git update-index --add rezrov &&
      read_tree_twoway $treeH $treeM &&
-     git-ls-files --stage >10.out &&
+     git ls-files --stage >10.out &&
      git diff M.out 10.out'
 
 test_expect_success \
     '11 - dirty path removed.' \
     'rm -f .git/index &&
-     git-read-tree $treeH &&
-     git-checkout-index -u -f -q -a &&
+     git read-tree $treeH &&
+     git checkout-index -u -f -q -a &&
      echo rezrov >rezrov &&
-     git-update-index --add rezrov &&
+     git update-index --add rezrov &&
      echo rezrov rezrov >rezrov &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
 
 test_expect_success \
     '12 - unmatching local changes being removed.' \
     'rm -f .git/index &&
-     git-read-tree $treeH &&
-     git-checkout-index -u -f -q -a &&
+     git read-tree $treeH &&
+     git checkout-index -u -f -q -a &&
      echo rezrov rezrov >rezrov &&
-     git-update-index --add rezrov &&
+     git update-index --add rezrov &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
 
 test_expect_success \
     '13 - unmatching local changes being removed.' \
     'rm -f .git/index &&
-     git-read-tree $treeH &&
-     git-checkout-index -u -f -q -a &&
+     git read-tree $treeH &&
+     git checkout-index -u -f -q -a &&
      echo rezrov rezrov >rezrov &&
-     git-update-index --add rezrov &&
+     git update-index --add rezrov &&
      echo rezrov >rezrov &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
 
@@ -210,12 +210,12 @@ EOF
 test_expect_success \
     '14 - unchanged in two heads.' \
     'rm -f .git/index &&
-     git-read-tree $treeH &&
-     git-checkout-index -u -f -q -a &&
+     git read-tree $treeH &&
+     git checkout-index -u -f -q -a &&
      echo nitfol nitfol >nitfol &&
-     git-update-index --add nitfol &&
+     git update-index --add nitfol &&
      read_tree_twoway $treeH $treeM &&
-     git-ls-files --stage >14.out || return 1
+     git ls-files --stage >14.out || return 1
      git diff M.out 14.out >14diff.out
      compare_change 14diff.out expected &&
      check_cache_at nitfol clean'
@@ -223,13 +223,13 @@ test_expect_success \
 test_expect_success \
     '15 - unchanged in two heads.' \
     'rm -f .git/index &&
-     git-read-tree $treeH &&
-     git-checkout-index -u -f -q -a &&
+     git read-tree $treeH &&
+     git checkout-index -u -f -q -a &&
      echo nitfol nitfol >nitfol &&
-     git-update-index --add nitfol &&
+     git update-index --add nitfol &&
      echo nitfol nitfol nitfol >nitfol &&
      read_tree_twoway $treeH $treeM &&
-     git-ls-files --stage >15.out || return 1
+     git ls-files --stage >15.out || return 1
      git diff M.out 15.out >15diff.out
      compare_change 15diff.out expected &&
      check_cache_at nitfol dirty'
@@ -237,66 +237,66 @@ test_expect_success \
 test_expect_success \
     '16 - conflicting local change.' \
     'rm -f .git/index &&
-     git-read-tree $treeH &&
-     git-checkout-index -u -f -q -a &&
+     git read-tree $treeH &&
+     git checkout-index -u -f -q -a &&
      echo bozbar bozbar >bozbar &&
-     git-update-index --add bozbar &&
+     git update-index --add bozbar &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
 
 test_expect_success \
     '17 - conflicting local change.' \
     'rm -f .git/index &&
-     git-read-tree $treeH &&
-     git-checkout-index -u -f -q -a &&
+     git read-tree $treeH &&
+     git checkout-index -u -f -q -a &&
      echo bozbar bozbar >bozbar &&
-     git-update-index --add bozbar &&
+     git update-index --add bozbar &&
      echo bozbar bozbar bozbar >bozbar &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
 
 test_expect_success \
     '18 - local change already having a good result.' \
     'rm -f .git/index &&
-     git-read-tree $treeH &&
-     git-checkout-index -u -f -q -a &&
+     git read-tree $treeH &&
+     git checkout-index -u -f -q -a &&
      cat bozbar-new >bozbar &&
-     git-update-index --add bozbar &&
+     git update-index --add bozbar &&
      read_tree_twoway $treeH $treeM &&
-     git-ls-files --stage >18.out &&
+     git ls-files --stage >18.out &&
      git diff M.out 18.out &&
      check_cache_at bozbar clean'
 
 test_expect_success \
     '19 - local change already having a good result, further modified.' \
     'rm -f .git/index &&
-     git-read-tree $treeH &&
-     git-checkout-index -u -f -q -a &&
+     git read-tree $treeH &&
+     git checkout-index -u -f -q -a &&
      cat bozbar-new >bozbar &&
-     git-update-index --add bozbar &&
+     git update-index --add bozbar &&
      echo gnusto gnusto >bozbar &&
      read_tree_twoway $treeH $treeM &&
-     git-ls-files --stage >19.out &&
+     git ls-files --stage >19.out &&
      git diff M.out 19.out &&
      check_cache_at bozbar dirty'
 
 test_expect_success \
     '20 - no local change, use new tree.' \
     'rm -f .git/index &&
-     git-read-tree $treeH &&
-     git-checkout-index -u -f -q -a &&
+     git read-tree $treeH &&
+     git checkout-index -u -f -q -a &&
      cat bozbar-old >bozbar &&
-     git-update-index --add bozbar &&
+     git update-index --add bozbar &&
      read_tree_twoway $treeH $treeM &&
-     git-ls-files --stage >20.out &&
+     git ls-files --stage >20.out &&
      git diff M.out 20.out &&
      check_cache_at bozbar dirty'
 
 test_expect_success \
     '21 - no local change, dirty cache.' \
     'rm -f .git/index &&
-     git-read-tree $treeH &&
-     git-checkout-index -u -f -q -a &&
+     git read-tree $treeH &&
+     git checkout-index -u -f -q -a &&
      cat bozbar-old >bozbar &&
-     git-update-index --add bozbar &&
+     git update-index --add bozbar &&
      echo gnusto gnusto >bozbar &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
 
@@ -304,10 +304,10 @@ test_expect_success \
 test_expect_success \
     '22 - local change cache updated.' \
     'rm -f .git/index &&
-     git-read-tree $treeH &&
-     git-checkout-index -u -f -q -a &&
+     git read-tree $treeH &&
+     git checkout-index -u -f -q -a &&
      sed -e "s/such as/SUCH AS/" bozbar-old >bozbar &&
-     git-update-index --add bozbar &&
+     git update-index --add bozbar &&
      if read_tree_twoway $treeH $treeM; then false; else :; fi'
 
 # Also make sure we did not break DF vs DF/DF case.
@@ -315,28 +315,28 @@ test_expect_success \
     'DF vs DF/DF case setup.' \
     'rm -f .git/index &&
      echo DF >DF &&
-     git-update-index --add DF &&
-     treeDF=`git-write-tree` &&
+     git update-index --add DF &&
+     treeDF=`git write-tree` &&
      echo treeDF $treeDF &&
-     git-ls-tree $treeDF &&
+     git ls-tree $treeDF &&
 
      rm -f DF &&
      mkdir DF &&
      echo DF/DF >DF/DF &&
-     git-update-index --add --remove DF DF/DF &&
-     treeDFDF=`git-write-tree` &&
+     git update-index --add --remove DF DF/DF &&
+     treeDFDF=`git write-tree` &&
      echo treeDFDF $treeDFDF &&
-     git-ls-tree $treeDFDF &&
-     git-ls-files --stage >DFDF.out'
+     git ls-tree $treeDFDF &&
+     git ls-files --stage >DFDF.out'
 
 test_expect_success \
     'DF vs DF/DF case test.' \
     'rm -f .git/index &&
      rm -fr DF &&
      echo DF >DF &&
-     git-update-index --add DF &&
+     git update-index --add DF &&
      read_tree_twoway $treeDF $treeDFDF &&
-     git-ls-files --stage >DFDFcheck.out &&
+     git ls-files --stage >DFDFcheck.out &&
      git diff DFDF.out DFDFcheck.out &&
      check_cache_at DF/DF dirty &&
      :'
index 87fe993f59e2b3843ea2abcd92a2bab77a392997..42e5cf81813a7703ff2173dcc29e35ffdc68f552 100755 (executable)
@@ -20,7 +20,7 @@ compare_change () {
 }
 
 check_cache_at () {
-       clean_if_empty=`git-diff-files -- "$1"`
+       clean_if_empty=`git diff-files -- "$1"`
        case "$clean_if_empty" in
        '')  echo "$1: clean" ;;
        ?*)  echo "$1: dirty" ;;
@@ -39,26 +39,26 @@ test_expect_success \
      echo nitfol >nitfol &&
      echo bozbar >bozbar &&
      echo rezrov >rezrov &&
-     git-update-index --add nitfol bozbar rezrov &&
-     treeH=`git-write-tree` &&
+     git update-index --add nitfol bozbar rezrov &&
+     treeH=`git write-tree` &&
      echo treeH $treeH &&
-     git-ls-tree $treeH &&
+     git ls-tree $treeH &&
 
      echo gnusto >bozbar &&
-     git-update-index --add frotz bozbar --force-remove rezrov &&
-     git-ls-files --stage >M.out &&
-     treeM=`git-write-tree` &&
+     git update-index --add frotz bozbar --force-remove rezrov &&
+     git ls-files --stage >M.out &&
+     treeM=`git write-tree` &&
      echo treeM $treeM &&
-     git-ls-tree $treeM &&
+     git ls-tree $treeM &&
      sum bozbar frotz nitfol >M.sum &&
-     git-diff-tree $treeH $treeM'
+     git diff-tree $treeH $treeM'
 
 test_expect_success \
     '1, 2, 3 - no carry forward' \
     'rm -f .git/index nitfol bozbar rezrov frotz &&
-     git-read-tree --reset -u $treeH &&
-     git-read-tree -m -u $treeH $treeM &&
-     git-ls-files --stage >1-3.out &&
+     git read-tree --reset -u $treeH &&
+     git read-tree -m -u $treeH $treeM &&
+     git ls-files --stage >1-3.out &&
      cmp M.out 1-3.out &&
      sum bozbar frotz nitfol >actual3.sum &&
      cmp M.sum actual3.sum &&
@@ -69,12 +69,12 @@ test_expect_success \
 test_expect_success \
     '4 - carry forward local addition.' \
     'rm -f .git/index nitfol bozbar rezrov frotz &&
-     git-read-tree --reset -u $treeH &&
+     git read-tree --reset -u $treeH &&
      echo "+100644 X 0 yomin" >expected &&
      echo yomin >yomin &&
-     git-update-index --add yomin &&
-     git-read-tree -m -u $treeH $treeM &&
-     git-ls-files --stage >4.out || return 1
+     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
      compare_change 4diff.out expected &&
      check_cache_at yomin clean &&
@@ -87,13 +87,13 @@ test_expect_success \
 test_expect_success \
     '5 - carry forward local addition.' \
     'rm -f .git/index nitfol bozbar rezrov frotz &&
-     git-read-tree --reset -u $treeH &&
-     git-read-tree -m -u $treeH &&
+     git read-tree --reset -u $treeH &&
+     git read-tree -m -u $treeH &&
      echo yomin >yomin &&
-     git-update-index --add yomin &&
+     git update-index --add yomin &&
      echo yomin yomin >yomin &&
-     git-read-tree -m -u $treeH $treeM &&
-     git-ls-files --stage >5.out || return 1
+     git read-tree -m -u $treeH $treeM &&
+     git ls-files --stage >5.out || return 1
      diff -U0 M.out 5.out >5diff.out
      compare_change 5diff.out expected &&
      check_cache_at yomin dirty &&
@@ -107,11 +107,11 @@ test_expect_success \
 test_expect_success \
     '6 - local addition already has the same.' \
     'rm -f .git/index nitfol bozbar rezrov frotz &&
-     git-read-tree --reset -u $treeH &&
+     git read-tree --reset -u $treeH &&
      echo frotz >frotz &&
-     git-update-index --add frotz &&
-     git-read-tree -m -u $treeH $treeM &&
-     git-ls-files --stage >6.out &&
+     git update-index --add frotz &&
+     git read-tree -m -u $treeH $treeM &&
+     git ls-files --stage >6.out &&
      diff -U0 M.out 6.out &&
      check_cache_at frotz clean &&
      sum bozbar frotz nitfol >actual3.sum &&
@@ -123,12 +123,12 @@ test_expect_success \
 test_expect_success \
     '7 - local addition already has the same.' \
     'rm -f .git/index nitfol bozbar rezrov frotz &&
-     git-read-tree --reset -u $treeH &&
+     git read-tree --reset -u $treeH &&
      echo frotz >frotz &&
-     git-update-index --add frotz &&
+     git update-index --add frotz &&
      echo frotz frotz >frotz &&
-     git-read-tree -m -u $treeH $treeM &&
-     git-ls-files --stage >7.out &&
+     git read-tree -m -u $treeH $treeM &&
+     git ls-files --stage >7.out &&
      diff -U0 M.out 7.out &&
      check_cache_at frotz dirty &&
      sum bozbar frotz nitfol >actual7.sum &&
@@ -141,28 +141,28 @@ test_expect_success \
 test_expect_success \
     '8 - conflicting addition.' \
     'rm -f .git/index nitfol bozbar rezrov frotz &&
-     git-read-tree --reset -u $treeH &&
+     git read-tree --reset -u $treeH &&
      echo frotz frotz >frotz &&
-     git-update-index --add frotz &&
-     if git-read-tree -m -u $treeH $treeM; then false; else :; fi'
+     git update-index --add frotz &&
+     if git read-tree -m -u $treeH $treeM; then false; else :; fi'
 
 test_expect_success \
     '9 - conflicting addition.' \
     'rm -f .git/index nitfol bozbar rezrov frotz &&
-     git-read-tree --reset -u $treeH &&
+     git read-tree --reset -u $treeH &&
      echo frotz frotz >frotz &&
-     git-update-index --add frotz &&
+     git update-index --add frotz &&
      echo frotz >frotz &&
-     if git-read-tree -m -u $treeH $treeM; then false; else :; fi'
+     if git read-tree -m -u $treeH $treeM; then false; else :; fi'
 
 test_expect_success \
     '10 - path removed.' \
     'rm -f .git/index nitfol bozbar rezrov frotz &&
-     git-read-tree --reset -u $treeH &&
+     git read-tree --reset -u $treeH &&
      echo rezrov >rezrov &&
-     git-update-index --add rezrov &&
-     git-read-tree -m -u $treeH $treeM &&
-     git-ls-files --stage >10.out &&
+     git update-index --add rezrov &&
+     git read-tree -m -u $treeH $treeM &&
+     git ls-files --stage >10.out &&
      cmp M.out 10.out &&
      sum bozbar frotz nitfol >actual10.sum &&
      cmp M.sum actual10.sum'
@@ -170,28 +170,28 @@ test_expect_success \
 test_expect_success \
     '11 - dirty path removed.' \
     'rm -f .git/index nitfol bozbar rezrov frotz &&
-     git-read-tree --reset -u $treeH &&
+     git read-tree --reset -u $treeH &&
      echo rezrov >rezrov &&
-     git-update-index --add rezrov &&
+     git update-index --add rezrov &&
      echo rezrov rezrov >rezrov &&
-     if git-read-tree -m -u $treeH $treeM; then false; else :; fi'
+     if git read-tree -m -u $treeH $treeM; then false; else :; fi'
 
 test_expect_success \
     '12 - unmatching local changes being removed.' \
     'rm -f .git/index nitfol bozbar rezrov frotz &&
-     git-read-tree --reset -u $treeH &&
+     git read-tree --reset -u $treeH &&
      echo rezrov rezrov >rezrov &&
-     git-update-index --add rezrov &&
-     if git-read-tree -m -u $treeH $treeM; then false; else :; fi'
+     git update-index --add rezrov &&
+     if git read-tree -m -u $treeH $treeM; then false; else :; fi'
 
 test_expect_success \
     '13 - unmatching local changes being removed.' \
     'rm -f .git/index nitfol bozbar rezrov frotz &&
-     git-read-tree --reset -u $treeH &&
+     git read-tree --reset -u $treeH &&
      echo rezrov rezrov >rezrov &&
-     git-update-index --add rezrov &&
+     git update-index --add rezrov &&
      echo rezrov >rezrov &&
-     if git-read-tree -m -u $treeH $treeM; then false; else :; fi'
+     if git read-tree -m -u $treeH $treeM; then false; else :; fi'
 
 cat >expected <<EOF
 -100644 X 0    nitfol
@@ -201,11 +201,11 @@ EOF
 test_expect_success \
     '14 - unchanged in two heads.' \
     'rm -f .git/index nitfol bozbar rezrov frotz &&
-     git-read-tree --reset -u $treeH &&
+     git read-tree --reset -u $treeH &&
      echo nitfol nitfol >nitfol &&
-     git-update-index --add nitfol &&
-     git-read-tree -m -u $treeH $treeM &&
-     git-ls-files --stage >14.out || return 1
+     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
      compare_change 14diff.out expected &&
      sum bozbar frotz >actual14.sum &&
@@ -221,12 +221,12 @@ test_expect_success \
 test_expect_success \
     '15 - unchanged in two heads.' \
     'rm -f .git/index nitfol bozbar rezrov frotz &&
-     git-read-tree --reset -u $treeH &&
+     git read-tree --reset -u $treeH &&
      echo nitfol nitfol >nitfol &&
-     git-update-index --add nitfol &&
+     git update-index --add nitfol &&
      echo nitfol nitfol nitfol >nitfol &&
-     git-read-tree -m -u $treeH $treeM &&
-     git-ls-files --stage >15.out || return 1
+     git read-tree -m -u $treeH $treeM &&
+     git ls-files --stage >15.out || return 1
      diff -U0 M.out 15.out >15diff.out
      compare_change 15diff.out expected &&
      check_cache_at nitfol dirty &&
@@ -242,28 +242,28 @@ test_expect_success \
 test_expect_success \
     '16 - conflicting local change.' \
     'rm -f .git/index nitfol bozbar rezrov frotz &&
-     git-read-tree --reset -u $treeH &&
+     git read-tree --reset -u $treeH &&
      echo bozbar bozbar >bozbar &&
-     git-update-index --add bozbar &&
-     if git-read-tree -m -u $treeH $treeM; then false; else :; fi'
+     git update-index --add bozbar &&
+     if git read-tree -m -u $treeH $treeM; then false; else :; fi'
 
 test_expect_success \
     '17 - conflicting local change.' \
     'rm -f .git/index nitfol bozbar rezrov frotz &&
-     git-read-tree --reset -u $treeH &&
+     git read-tree --reset -u $treeH &&
      echo bozbar bozbar >bozbar &&
-     git-update-index --add bozbar &&
+     git update-index --add bozbar &&
      echo bozbar bozbar bozbar >bozbar &&
-     if git-read-tree -m -u $treeH $treeM; then false; else :; fi'
+     if git read-tree -m -u $treeH $treeM; then false; else :; fi'
 
 test_expect_success \
     '18 - local change already having a good result.' \
     'rm -f .git/index nitfol bozbar rezrov frotz &&
-     git-read-tree --reset -u $treeH &&
+     git read-tree --reset -u $treeH &&
      echo gnusto >bozbar &&
-     git-update-index --add bozbar &&
-     git-read-tree -m -u $treeH $treeM &&
-     git-ls-files --stage >18.out &&
+     git update-index --add bozbar &&
+     git read-tree -m -u $treeH $treeM &&
+     git ls-files --stage >18.out &&
      diff -U0 M.out 18.out &&
      check_cache_at bozbar clean &&
      sum bozbar frotz nitfol >actual18.sum &&
@@ -272,12 +272,12 @@ test_expect_success \
 test_expect_success \
     '19 - local change already having a good result, further modified.' \
     'rm -f .git/index nitfol bozbar rezrov frotz &&
-     git-read-tree --reset -u $treeH &&
+     git read-tree --reset -u $treeH &&
      echo gnusto >bozbar &&
-     git-update-index --add bozbar &&
+     git update-index --add bozbar &&
      echo gnusto gnusto >bozbar &&
-     git-read-tree -m -u $treeH $treeM &&
-     git-ls-files --stage >19.out &&
+     git read-tree -m -u $treeH $treeM &&
+     git ls-files --stage >19.out &&
      diff -U0 M.out 19.out &&
      check_cache_at bozbar dirty &&
      sum frotz nitfol >actual19.sum &&
@@ -292,11 +292,11 @@ test_expect_success \
 test_expect_success \
     '20 - no local change, use new tree.' \
     'rm -f .git/index nitfol bozbar rezrov frotz &&
-     git-read-tree --reset -u $treeH &&
+     git read-tree --reset -u $treeH &&
      echo bozbar >bozbar &&
-     git-update-index --add bozbar &&
-     git-read-tree -m -u $treeH $treeM &&
-     git-ls-files --stage >20.out &&
+     git update-index --add bozbar &&
+     git read-tree -m -u $treeH $treeM &&
+     git ls-files --stage >20.out &&
      diff -U0 M.out 20.out &&
      check_cache_at bozbar clean &&
      sum bozbar frotz nitfol >actual20.sum &&
@@ -305,39 +305,39 @@ test_expect_success \
 test_expect_success \
     '21 - no local change, dirty cache.' \
     'rm -f .git/index nitfol bozbar rezrov frotz &&
-     git-read-tree --reset -u $treeH &&
+     git read-tree --reset -u $treeH &&
      echo bozbar >bozbar &&
-     git-update-index --add bozbar &&
+     git update-index --add bozbar &&
      echo gnusto gnusto >bozbar &&
-     if git-read-tree -m -u $treeH $treeM; then false; else :; fi'
+     if git read-tree -m -u $treeH $treeM; then false; else :; fi'
 
 # Also make sure we did not break DF vs DF/DF case.
 test_expect_success \
     'DF vs DF/DF case setup.' \
     'rm -f .git/index
      echo DF >DF &&
-     git-update-index --add DF &&
-     treeDF=`git-write-tree` &&
+     git update-index --add DF &&
+     treeDF=`git write-tree` &&
      echo treeDF $treeDF &&
-     git-ls-tree $treeDF &&
+     git ls-tree $treeDF &&
 
      rm -f DF &&
      mkdir DF &&
      echo DF/DF >DF/DF &&
-     git-update-index --add --remove DF DF/DF &&
-     treeDFDF=`git-write-tree` &&
+     git update-index --add --remove DF DF/DF &&
+     treeDFDF=`git write-tree` &&
      echo treeDFDF $treeDFDF &&
-     git-ls-tree $treeDFDF &&
-     git-ls-files --stage >DFDF.out'
+     git ls-tree $treeDFDF &&
+     git ls-files --stage >DFDF.out'
 
 test_expect_success \
     'DF vs DF/DF case test.' \
     'rm -f .git/index &&
      rm -fr DF &&
      echo DF >DF &&
-     git-update-index --add DF &&
-     git-read-tree -m -u $treeDF $treeDFDF &&
-     git-ls-files --stage >DFDFcheck.out &&
+     git update-index --add DF &&
+     git read-tree -m -u $treeDF $treeDFDF &&
+     git ls-files --stage >DFDFcheck.out &&
      diff -U0 DFDF.out DFDFcheck.out &&
      check_cache_at DF/DF clean'
 
index 48ab117d755ca606a09d848af9747e24ea13a26f..8c6d67edda1468ba0f1c7afc6d13ea3a7bbe0a90 100755 (executable)
@@ -3,15 +3,15 @@
 # Copyright (c) 2006 Junio C Hamano
 #
 
-test_description='git-read-tree --prefix test.
+test_description='git read-tree --prefix test.
 '
 
 . ./test-lib.sh
 
 test_expect_success setup '
        echo hello >one &&
-       git-update-index --add one &&
-       tree=`git-write-tree` &&
+       git update-index --add one &&
+       tree=`git write-tree` &&
        echo tree is $tree
 '
 
@@ -19,8 +19,8 @@ echo 'one
 two/one' >expect
 
 test_expect_success 'read-tree --prefix' '
-       git-read-tree --prefix=two/ $tree &&
-       git-ls-files >actual &&
+       git read-tree --prefix=two/ $tree &&
+       git ls-files >actual &&
        cmp expect actual
 '
 
index c11420a8b6ce9104f1c2ca3b4b2a23aef4f265ff..d609a551ae3b8c75714f6cf4e9cefe4f6af61c5b 100755 (executable)
@@ -84,7 +84,7 @@ test_expect_success 'three-way not complaining on an untracked path in both' '
        echo >file2 file two is untracked on the master side &&
        echo >subdir/file2 file two is untracked on the master side &&
 
-       git-read-tree -m -u branch-point master side
+       git read-tree -m -u branch-point master side
 '
 
 test_expect_success 'three-way not clobbering a working tree file' '
index 1e8f9e59dfe7e63177dea0a2e4b5c018a4756994..b9cef3422c3ba1392b32ec66f72dc4b7c34f4a43 100755 (executable)
@@ -22,19 +22,19 @@ LF='
 
 test_expect_success 'update-index and ls-files' '
        cd $HERE &&
-       git-update-index --add one &&
-       case "`git-ls-files`" in
+       git update-index --add one &&
+       case "`git ls-files`" in
        one) echo ok one ;;
        *) echo bad one; exit 1 ;;
        esac &&
        cd dir &&
-       git-update-index --add two &&
-       case "`git-ls-files`" in
+       git update-index --add two &&
+       case "`git ls-files`" in
        two) echo ok two ;;
        *) echo bad two; exit 1 ;;
        esac &&
        cd .. &&
-       case "`git-ls-files`" in
+       case "`git ls-files`" in
        dir/two"$LF"one) echo ok both ;;
        *) echo bad; exit 1 ;;
        esac
@@ -42,13 +42,13 @@ test_expect_success 'update-index and ls-files' '
 
 test_expect_success 'cat-file' '
        cd $HERE &&
-       two=`git-ls-files -s dir/two` &&
+       two=`git ls-files -s dir/two` &&
        two=`expr "$two" : "[0-7]* \\([0-9a-f]*\\)"` &&
        echo "$two" &&
-       git-cat-file -p "$two" >actual &&
+       git cat-file -p "$two" >actual &&
        cmp dir/two actual &&
        cd dir &&
-       git-cat-file -p "$two" >actual &&
+       git cat-file -p "$two" >actual &&
        cmp two actual
 '
 rm -f actual dir/actual
@@ -57,17 +57,17 @@ test_expect_success 'diff-files' '
        cd $HERE &&
        echo a >>one &&
        echo d >>dir/two &&
-       case "`git-diff-files --name-only`" in
+       case "`git diff-files --name-only`" in
        dir/two"$LF"one) echo ok top ;;
        *) echo bad top; exit 1 ;;
        esac &&
        # diff should not omit leading paths
        cd dir &&
-       case "`git-diff-files --name-only`" in
+       case "`git diff-files --name-only`" in
        dir/two"$LF"one) echo ok subdir ;;
        *) echo bad subdir; exit 1 ;;
        esac &&
-       case "`git-diff-files --name-only .`" in
+       case "`git diff-files --name-only .`" in
        dir/two) echo ok subdir limited ;;
        *) echo bad subdir limited; exit 1 ;;
        esac
@@ -75,33 +75,33 @@ test_expect_success 'diff-files' '
 
 test_expect_success 'write-tree' '
        cd $HERE &&
-       top=`git-write-tree` &&
+       top=`git write-tree` &&
        echo $top &&
        cd dir &&
-       sub=`git-write-tree` &&
+       sub=`git write-tree` &&
        echo $sub &&
        test "z$top" = "z$sub"
 '
 
 test_expect_success 'checkout-index' '
        cd $HERE &&
-       git-checkout-index -f -u one &&
+       git checkout-index -f -u one &&
        cmp one original.one &&
        cd dir &&
-       git-checkout-index -f -u two &&
+       git checkout-index -f -u two &&
        cmp two ../original.two
 '
 
 test_expect_success 'read-tree' '
        cd $HERE &&
        rm -f one dir/two &&
-       tree=`git-write-tree` &&
-       git-read-tree --reset -u "$tree" &&
+       tree=`git write-tree` &&
+       git read-tree --reset -u "$tree" &&
        cmp one original.one &&
        cmp dir/two original.two &&
        cd dir &&
        rm -f two &&
-       git-read-tree --reset -u "$tree" &&
+       git read-tree --reset -u "$tree" &&
        cmp two ../original.two &&
        cmp ../one ../original.one
 '
index 19a0ed4d20409a79c5615004ceb63a969f0414de..7f7fc36734d96de96801c59af41024db97dc614d 100755 (executable)
@@ -3,9 +3,9 @@
 # Copyright (C) 2005 Rene Scharfe
 #
 
-test_description='git-commit-tree options test
+test_description='git commit-tree options test
 
-This test checks that git-commit-tree can create a specific commit
+This test checks that git commit-tree can create a specific commit
 object by defining all environment variables that it understands.
 '
 
@@ -21,7 +21,7 @@ EOF
 
 test_expect_success \
     'test preparation: write empty tree' \
-    'git-write-tree >treeid'
+    'git write-tree >treeid'
 
 test_expect_success \
     'construct commit' \
@@ -32,11 +32,11 @@ test_expect_success \
      GIT_COMMITTER_NAME="Committer Name" \
      GIT_COMMITTER_EMAIL="committer@email" \
      GIT_COMMITTER_DATE="2005-05-26 23:30" \
-     TZ=GMT git-commit-tree `cat treeid` >commitid 2>/dev/null'
+     TZ=GMT git commit-tree `cat treeid` >commitid 2>/dev/null'
 
 test_expect_success \
     'read commit' \
-    'git-cat-file commit `cat commitid` >commit'
+    'git cat-file commit `cat commitid` >commit'
 
 test_expect_success \
     'compare commit' \
index ca2c30f7aff5beda97ea598e272750c23e34296e..991d3c5e9c5c8dc9e59b0105010f1b77d4bf3a3f 100755 (executable)
@@ -10,11 +10,11 @@ test_description='A simple turial in the form of a test case'
 echo "Hello World" > hello
 echo "Silly example" > example
 
-git-update-index --add hello example
+git update-index --add hello example
 
-test_expect_success 'blob' "test blob = \"$(git-cat-file -t 557db03)\""
+test_expect_success 'blob' "test blob = \"$(git cat-file -t 557db03)\""
 
-test_expect_success 'blob 557db03' "test \"Hello World\" = \"$(git-cat-file blob 557db03)\""
+test_expect_success 'blob 557db03' "test \"Hello World\" = \"$(git cat-file blob 557db03)\""
 
 echo "It's a new day for git" >>hello
 cat > diff.expect << EOF
@@ -26,25 +26,25 @@ index 557db03..263414f 100644
  Hello World
 +It's a new day for git
 EOF
-git-diff-files -p > diff.output
-test_expect_success 'git-diff-files -p' 'cmp diff.expect diff.output'
+git diff-files -p > diff.output
+test_expect_success 'git diff-files -p' 'cmp diff.expect diff.output'
 git diff > diff.output
 test_expect_success 'git diff' 'cmp diff.expect diff.output'
 
-tree=$(git-write-tree 2>/dev/null)
+tree=$(git write-tree 2>/dev/null)
 
 test_expect_success 'tree' "test 8988da15d077d4829fc51d8544c097def6644dbb = $tree"
 
-output="$(echo "Initial commit" | git-commit-tree $(git-write-tree) 2>&1 > .git/refs/heads/master)"
+output="$(echo "Initial commit" | git commit-tree $(git write-tree) 2>&1 > .git/refs/heads/master)"
 
-git-diff-index -p HEAD > diff.output
-test_expect_success 'git-diff-index -p HEAD' 'cmp diff.expect diff.output'
+git diff-index -p HEAD > diff.output
+test_expect_success 'git diff-index -p HEAD' 'cmp diff.expect diff.output'
 
 git diff HEAD > diff.output
 test_expect_success 'git diff HEAD' 'cmp diff.expect diff.output'
 
 #rm hello
-#test_expect_success 'git-read-tree --reset HEAD' "git-read-tree --reset HEAD ; test \"hello: needs update\" = \"$(git-update-index --refresh)\""
+#test_expect_success 'git read-tree --reset HEAD' "git read-tree --reset HEAD ; test \"hello: needs update\" = \"$(git update-index --refresh)\""
 
 cat > whatchanged.expect << EOF
 commit VARIABLE
@@ -69,11 +69,11 @@ index 0000000..557db03
 +Hello World
 EOF
 
-git-whatchanged -p --root | \
+git whatchanged -p --root | \
        sed -e "1s/^\(.\{7\}\).\{40\}/\1VARIABLE/" \
                -e "2,3s/^\(.\{8\}\).*$/\1VARIABLE/" \
 > whatchanged.output
-test_expect_success 'git-whatchanged -p --root' 'cmp whatchanged.expect whatchanged.output'
+test_expect_success 'git whatchanged -p --root' 'cmp whatchanged.expect whatchanged.output'
 
 git tag my-first-tag
 test_expect_success 'git tag my-first-tag' 'cmp .git/refs/heads/master .git/refs/tags/my-first-tag'
@@ -159,4 +159,3 @@ test_expect_success 'git prune-packed' 'git prune-packed'
 test_expect_failure '-> only packed objects' 'find -type f .git/objects/[0-9a-f][0-9a-f]'
 
 test_done
-
index f1a78b19ac6e426f4475b66cfe23b89e41c7fafa..1c43cc333d00827dd6f2b8e6aa605b3390ac6a45 100755 (executable)
@@ -3,13 +3,13 @@
 # Copyright (c) 2005 Johannes Schindelin
 #
 
-test_description='Test git-config in different settings'
+test_description='Test git config in different settings'
 
 . ./test-lib.sh
 
 test -f .git/config && rm .git/config
 
-git-config core.penguin "little blue"
+git config core.penguin "little blue"
 
 cat > expect << EOF
 [core]
@@ -18,7 +18,7 @@ EOF
 
 test_expect_success 'initial' 'cmp .git/config expect'
 
-git-config Core.Movie BadPhysics
+git config Core.Movie BadPhysics
 
 cat > expect << EOF
 [core]
@@ -28,7 +28,7 @@ EOF
 
 test_expect_success 'mixed case' 'cmp .git/config expect'
 
-git-config Cores.WhatEver Second
+git config Cores.WhatEver Second
 
 cat > expect << EOF
 [core]
@@ -40,7 +40,7 @@ EOF
 
 test_expect_success 'similar section' 'cmp .git/config expect'
 
-git-config CORE.UPPERCASE true
+git config CORE.UPPERCASE true
 
 cat > expect << EOF
 [core]
@@ -54,10 +54,10 @@ EOF
 test_expect_success 'similar section' 'cmp .git/config expect'
 
 test_expect_success 'replace with non-match' \
-       'git-config core.penguin kingpin !blue'
+       'git config core.penguin kingpin !blue'
 
 test_expect_success 'replace with non-match (actually matching)' \
-       'git-config core.penguin "very blue" !kingpin'
+       'git config core.penguin "very blue" !kingpin'
 
 cat > expect << EOF
 [core]
@@ -86,7 +86,7 @@ EOF
 cp .git/config .git/config2
 
 test_expect_success 'multiple unset' \
-       'git-config --unset-all beta.haha'
+       'git config --unset-all beta.haha'
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -102,7 +102,7 @@ test_expect_success 'multiple unset is correct' 'cmp .git/config expect'
 mv .git/config2 .git/config
 
 test_expect_success '--replace-all' \
-       'git-config --replace-all beta.haha gamma'
+       'git config --replace-all beta.haha gamma'
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -116,7 +116,7 @@ EOF
 
 test_expect_success 'all replaced' 'cmp .git/config expect'
 
-git-config beta.haha alpha
+git config beta.haha alpha
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -130,7 +130,7 @@ EOF
 
 test_expect_success 'really mean test' 'cmp .git/config expect'
 
-git-config nextsection.nonewline wow
+git config nextsection.nonewline wow
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -145,8 +145,8 @@ EOF
 
 test_expect_success 'really really mean test' 'cmp .git/config expect'
 
-test_expect_success 'get value' 'test alpha = $(git-config beta.haha)'
-git-config --unset beta.haha
+test_expect_success 'get value' 'test alpha = $(git config beta.haha)'
+git config --unset beta.haha
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -160,7 +160,7 @@ EOF
 
 test_expect_success 'unset' 'cmp .git/config expect'
 
-git-config nextsection.NoNewLine "wow2 for me" "for me$"
+git config nextsection.NoNewLine "wow2 for me" "for me$"
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -176,18 +176,18 @@ EOF
 test_expect_success 'multivar' 'cmp .git/config expect'
 
 test_expect_success 'non-match' \
-       'git-config --get nextsection.nonewline !for'
+       'git config --get nextsection.nonewline !for'
 
 test_expect_success 'non-match value' \
-       'test wow = $(git-config --get nextsection.nonewline !for)'
+       'test wow = $(git config --get nextsection.nonewline !for)'
 
 test_expect_failure 'ambiguous get' \
-       'git-config --get nextsection.nonewline'
+       'git config --get nextsection.nonewline'
 
 test_expect_success 'get multivar' \
-       'git-config --get-all nextsection.nonewline'
+       'git config --get-all nextsection.nonewline'
 
-git-config nextsection.nonewline "wow3" "wow$"
+git config nextsection.nonewline "wow3" "wow$"
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -202,15 +202,15 @@ EOF
 
 test_expect_success 'multivar replace' 'cmp .git/config expect'
 
-test_expect_failure 'ambiguous value' 'git-config nextsection.nonewline'
+test_expect_failure 'ambiguous value' 'git config nextsection.nonewline'
 
 test_expect_failure 'ambiguous unset' \
-       'git-config --unset nextsection.nonewline'
+       'git config --unset nextsection.nonewline'
 
 test_expect_failure 'invalid unset' \
-       'git-config --unset somesection.nonewline'
+       'git config --unset somesection.nonewline'
 
-git-config --unset nextsection.nonewline "wow3$"
+git config --unset nextsection.nonewline "wow3$"
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -224,12 +224,12 @@ EOF
 
 test_expect_success 'multivar unset' 'cmp .git/config expect'
 
-test_expect_failure 'invalid key' 'git-config inval.2key blabla'
+test_expect_failure 'invalid key' 'git config inval.2key blabla'
 
-test_expect_success 'correct key' 'git-config 123456.a123 987'
+test_expect_success 'correct key' 'git config 123456.a123 987'
 
 test_expect_success 'hierarchical section' \
-       'git-config Version.1.2.3eX.Alpha beta'
+       'git config Version.1.2.3eX.Alpha beta'
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -255,7 +255,7 @@ version.1.2.3eX.alpha=beta
 EOF
 
 test_expect_success 'working --list' \
-       'git-config --list > output && cmp output expect'
+       'git config --list > output && cmp output expect'
 
 cat > expect << EOF
 beta.noindent sillyValue
@@ -263,9 +263,9 @@ nextsection.nonewline wow2 for me
 EOF
 
 test_expect_success '--get-regexp' \
-       'git-config --get-regexp in > output && cmp output expect'
+       'git config --get-regexp in > output && cmp output expect'
 
-git-config --add nextsection.nonewline "wow4 for you"
+git config --add nextsection.nonewline "wow4 for you"
 
 cat > expect << EOF
 wow2 for me
@@ -273,7 +273,7 @@ wow4 for you
 EOF
 
 test_expect_success '--add' \
-       'git-config --get-all nextsection.nonewline > output && cmp output expect'
+       'git config --get-all nextsection.nonewline > output && cmp output expect'
 
 cat > .git/config << EOF
 [novalue]
@@ -281,15 +281,15 @@ cat > .git/config << EOF
 EOF
 
 test_expect_success 'get variable with no value' \
-       'git-config --get novalue.variable ^$'
+       'git config --get novalue.variable ^$'
 
 echo novalue.variable > expect
 
 test_expect_success 'get-regexp variable with no value' \
-       'git-config --get-regexp novalue > output &&
+       'git config --get-regexp novalue > output &&
         cmp output expect'
 
-git-config > output 2>&1
+git config > output 2>&1
 
 test_expect_success 'no arguments, but no crash' \
        "test $? = 129 && grep usage output"
@@ -299,7 +299,7 @@ cat > .git/config << EOF
        c = d
 EOF
 
-git-config a.x y
+git config a.x y
 
 cat > expect << EOF
 [a.b]
@@ -310,8 +310,8 @@ EOF
 
 test_expect_success 'new section is partial match of another' 'cmp .git/config expect'
 
-git-config b.x y
-git-config a.b c
+git config b.x y
+git config a.b c
 
 cat > expect << EOF
 [a.b]
@@ -334,11 +334,11 @@ cat > expect << EOF
 ein.bahn=strasse
 EOF
 
-GIT_CONFIG=other-config git-config -l > output
+GIT_CONFIG=other-config git config -l > output
 
 test_expect_success 'alternative GIT_CONFIG' 'cmp output expect'
 
-GIT_CONFIG=other-config git-config anwohner.park ausweis
+GIT_CONFIG=other-config git config anwohner.park ausweis
 
 cat > expect << EOF
 [ein]
@@ -361,7 +361,7 @@ weird
 EOF
 
 test_expect_success "rename section" \
-       "git-config --rename-section branch.eins branch.zwei"
+       "git config --rename-section branch.eins branch.zwei"
 
 cat > expect << EOF
 # Hallo
@@ -377,12 +377,12 @@ EOF
 test_expect_success "rename succeeded" "git diff expect .git/config"
 
 test_expect_failure "rename non-existing section" \
-       'git-config --rename-section branch."world domination" branch.drei'
+       'git config --rename-section branch."world domination" branch.drei'
 
 test_expect_success "rename succeeded" "git diff expect .git/config"
 
 test_expect_success "rename another section" \
-       'git-config --rename-section branch."1 234 blabl/a" branch.drei'
+       'git config --rename-section branch."1 234 blabl/a" branch.drei'
 
 cat > expect << EOF
 # Hallo
@@ -425,20 +425,20 @@ EOF
 
 test_expect_success 'section ending' '
 
-       git-config gitcvs.enabled true &&
-       git-config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite &&
-       git-config gitcvs.dbname %Ggitcvs2.%a.%m.sqlite &&
+       git config gitcvs.enabled true &&
+       git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite &&
+       git config gitcvs.dbname %Ggitcvs2.%a.%m.sqlite &&
        cmp .git/config expect
 
 '
 
 test_expect_success numbers '
 
-       git-config kilo.gram 1k &&
-       git-config mega.ton 1m &&
-       k=$(git-config --int --get kilo.gram) &&
+       git config kilo.gram 1k &&
+       git config mega.ton 1m &&
+       k=$(git config --int --get kilo.gram) &&
        test z1024 = "z$k" &&
-       m=$(git-config --int --get mega.ton) &&
+       m=$(git config --int --get mega.ton) &&
        test z1048576 = "z$m"
 '
 
@@ -455,33 +455,79 @@ EOF
 
 test_expect_success bool '
 
-       git-config bool.true1 01 &&
-       git-config bool.true2 -1 &&
-       git-config bool.true3 YeS &&
-       git-config bool.true4 true &&
-       git-config bool.false1 000 &&
-       git-config bool.false2 "" &&
-       git-config bool.false3 nO &&
-       git-config bool.false4 FALSE &&
+       git config bool.true1 01 &&
+       git config bool.true2 -1 &&
+       git config bool.true3 YeS &&
+       git config bool.true4 true &&
+       git config bool.false1 000 &&
+       git config bool.false2 "" &&
+       git config bool.false3 nO &&
+       git config bool.false4 FALSE &&
        rm -f result &&
        for i in 1 2 3 4
        do
-           git-config --bool --get bool.true$i >>result
-           git-config --bool --get bool.false$i >>result
+           git config --bool --get bool.true$i >>result
+           git config --bool --get bool.false$i >>result
         done &&
        cmp expect result'
 
-test_expect_failure 'invalid bool' '
+test_expect_failure 'invalid bool (--get)' '
 
-       git-config bool.nobool foobar &&
-       git-config --bool --get bool.nobool'
+       git config bool.nobool foobar &&
+       git config --bool --get bool.nobool'
+
+test_expect_failure 'invalid bool (set)' '
+
+       git config --bool bool.nobool foobar'
+
+rm .git/config
+
+cat > expect <<\EOF
+[bool]
+       true1 = true
+       true2 = true
+       true3 = true
+       true4 = true
+       false1 = false
+       false2 = false
+       false3 = false
+       false4 = false
+EOF
+
+test_expect_success 'set --bool' '
+
+       git config --bool bool.true1 01 &&
+       git config --bool bool.true2 -1 &&
+       git config --bool bool.true3 YeS &&
+       git config --bool bool.true4 true &&
+       git config --bool bool.false1 000 &&
+       git config --bool bool.false2 "" &&
+       git config --bool bool.false3 nO &&
+       git config --bool bool.false4 FALSE &&
+       cmp expect .git/config'
+
+rm .git/config
+
+cat > expect <<\EOF
+[int]
+       val1 = 1
+       val2 = -1
+       val3 = 5242880
+EOF
+
+test_expect_success 'set --int' '
+
+       git config --int int.val1 01 &&
+       git config --int int.val2 -1 &&
+       git config --int int.val3 5m &&
+       cmp expect .git/config'
 
 rm .git/config
 
-git-config quote.leading " test"
-git-config quote.ending "test "
-git-config quote.semicolon "test;test"
-git-config quote.hash "test#test"
+git config quote.leading " test"
+git config quote.ending "test "
+git config quote.semicolon "test;test"
+git config quote.hash "test#test"
 
 cat > expect << EOF
 [quote]
@@ -519,5 +565,34 @@ git config --list > result
 
 test_expect_success 'value continued on next line' 'cmp result expect'
 
-test_done
+cat > .git/config <<\EOF
+[section "sub=section"]
+       val1 = foo=bar
+       val2 = foo\nbar
+       val3 = \n\n
+       val4 =
+       val5
+EOF
 
+cat > expect <<\EOF
+section.sub=section.val1
+foo=barQsection.sub=section.val2
+foo
+barQsection.sub=section.val3
+
+
+Qsection.sub=section.val4
+Qsection.sub=section.val5Q
+EOF
+
+git config --null --list | tr '[\000]' 'Q' > result
+echo >>result
+
+test_expect_success '--null --list' 'cmp result expect'
+
+git config --null --get-regexp 'val[0-9]' | tr '[\000]' 'Q' > result
+echo >>result
+
+test_expect_success '--null --get-regexp' 'cmp result expect'
+
+test_done
index d0aba2c2ae1fbd5f5282de1a0ee7ed8b87b80faa..c4c0dfaab1adf7866ca82d998b6d7a040a011935 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2006 Shawn Pearce
 #
 
-test_description='Test git-update-ref and basic ref logging'
+test_description='Test git update-ref and basic ref logging'
 . ./test-lib.sh
 
 Z=0000000000000000000000000000000000000000
@@ -19,34 +19,34 @@ n=$n_dir/fixes
 
 test_expect_success \
        "create $m" \
-       "git-update-ref $m $A &&
+       "git update-ref $m $A &&
         test $A"' = $(cat .git/'"$m"')'
 test_expect_success \
        "create $m" \
-       "git-update-ref $m $B $A &&
+       "git update-ref $m $B $A &&
         test $B"' = $(cat .git/'"$m"')'
 rm -f .git/$m
 
 test_expect_success \
        "fail to create $n" \
        "touch .git/$n_dir
-        git-update-ref $n $A >out 2>err"'
+        git update-ref $n $A >out 2>err"'
         test $? != 0'
 rm -f .git/$n_dir out err
 
 test_expect_success \
        "create $m (by HEAD)" \
-       "git-update-ref HEAD $A &&
+       "git update-ref HEAD $A &&
         test $A"' = $(cat .git/'"$m"')'
 test_expect_success \
        "create $m (by HEAD)" \
-       "git-update-ref HEAD $B $A &&
+       "git update-ref HEAD $B $A &&
         test $B"' = $(cat .git/'"$m"')'
 rm -f .git/$m
 
 test_expect_failure \
        '(not) create HEAD with old sha1' \
-       "git-update-ref HEAD $A $B"
+       "git update-ref HEAD $A $B"
 test_expect_failure \
        "(not) prior created .git/$m" \
        "test -f .git/$m"
@@ -54,10 +54,10 @@ rm -f .git/$m
 
 test_expect_success \
        "create HEAD" \
-       "git-update-ref HEAD $A"
+       "git update-ref HEAD $A"
 test_expect_failure \
        '(not) change HEAD with wrong SHA1' \
-       "git-update-ref HEAD $B $Z"
+       "git update-ref HEAD $B $Z"
 test_expect_failure \
        "(not) changed .git/$m" \
        "test $B"' = $(cat .git/'"$m"')'
@@ -68,17 +68,17 @@ rm -f .git/$m
 test_expect_success \
        "create $m (logged by touch)" \
        'GIT_COMMITTER_DATE="2005-05-26 23:30" \
-        git-update-ref HEAD '"$A"' -m "Initial Creation" &&
+        git update-ref HEAD '"$A"' -m "Initial Creation" &&
         test '"$A"' = $(cat .git/'"$m"')'
 test_expect_success \
        "update $m (logged by touch)" \
        'GIT_COMMITTER_DATE="2005-05-26 23:31" \
-        git-update-ref HEAD'" $B $A "'-m "Switch" &&
+        git update-ref HEAD'" $B $A "'-m "Switch" &&
         test '"$B"' = $(cat .git/'"$m"')'
 test_expect_success \
        "set $m (logged by touch)" \
        'GIT_COMMITTER_DATE="2005-05-26 23:41" \
-        git-update-ref HEAD'" $A &&
+        git update-ref HEAD'" $A &&
         test $A"' = $(cat .git/'"$m"')'
 
 cat >expect <<EOF
@@ -93,23 +93,23 @@ rm -rf .git/$m .git/logs expect
 
 test_expect_success \
        'enable core.logAllRefUpdates' \
-       'git-config core.logAllRefUpdates true &&
-        test true = $(git-config --bool --get core.logAllRefUpdates)'
+       'git config core.logAllRefUpdates true &&
+        test true = $(git config --bool --get core.logAllRefUpdates)'
 
 test_expect_success \
        "create $m (logged by config)" \
        'GIT_COMMITTER_DATE="2005-05-26 23:32" \
-        git-update-ref HEAD'" $A "'-m "Initial Creation" &&
+        git update-ref HEAD'" $A "'-m "Initial Creation" &&
         test '"$A"' = $(cat .git/'"$m"')'
 test_expect_success \
        "update $m (logged by config)" \
        'GIT_COMMITTER_DATE="2005-05-26 23:33" \
-        git-update-ref HEAD'" $B $A "'-m "Switch" &&
+        git update-ref HEAD'" $B $A "'-m "Switch" &&
         test '"$B"' = $(cat .git/'"$m"')'
 test_expect_success \
        "set $m (logged by config)" \
        'GIT_COMMITTER_DATE="2005-05-26 23:43" \
-        git-update-ref HEAD '"$A &&
+        git update-ref HEAD '"$A &&
         test $A"' = $(cat .git/'"$m"')'
 
 cat >expect <<EOF
@@ -122,7 +122,7 @@ test_expect_success \
        'diff expect .git/logs/$m'
 rm -f .git/$m .git/logs/$m expect
 
-git-update-ref $m $D
+git update-ref $m $D
 cat >.git/logs/$m <<EOF
 $C $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150320 -0500
 $A $B $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150380 -0500
@@ -136,49 +136,49 @@ ld="Thu, 26 May 2005 18:43:00 -0500"
 test_expect_success \
        'Query "master@{May 25 2005}" (before history)' \
        'rm -f o e
-        git-rev-parse --verify "master@{May 25 2005}" >o 2>e &&
+        git rev-parse --verify "master@{May 25 2005}" >o 2>e &&
         test '"$C"' = $(cat o) &&
         test "warning: Log for '\'master\'' only goes back to $ed." = "$(cat e)"'
 test_expect_success \
        "Query master@{2005-05-25} (before history)" \
        'rm -f o e
-        git-rev-parse --verify master@{2005-05-25} >o 2>e &&
+        git rev-parse --verify master@{2005-05-25} >o 2>e &&
         test '"$C"' = $(cat o) &&
         echo test "warning: Log for '\'master\'' only goes back to $ed." = "$(cat e)"'
 test_expect_success \
        'Query "master@{May 26 2005 23:31:59}" (1 second before history)' \
        'rm -f o e
-        git-rev-parse --verify "master@{May 26 2005 23:31:59}" >o 2>e &&
+        git rev-parse --verify "master@{May 26 2005 23:31:59}" >o 2>e &&
         test '"$C"' = $(cat o) &&
         test "warning: Log for '\''master'\'' only goes back to $ed." = "$(cat e)"'
 test_expect_success \
        'Query "master@{May 26 2005 23:32:00}" (exactly history start)' \
        'rm -f o e
-        git-rev-parse --verify "master@{May 26 2005 23:32:00}" >o 2>e &&
+        git rev-parse --verify "master@{May 26 2005 23:32:00}" >o 2>e &&
         test '"$A"' = $(cat o) &&
         test "" = "$(cat e)"'
 test_expect_success \
        'Query "master@{2005-05-26 23:33:01}" (middle of history with gap)' \
        'rm -f o e
-        git-rev-parse --verify "master@{2005-05-26 23:33:01}" >o 2>e &&
+        git rev-parse --verify "master@{2005-05-26 23:33:01}" >o 2>e &&
         test '"$B"' = $(cat o) &&
         test "warning: Log .git/logs/'"$m has gap after $gd"'." = "$(cat e)"'
 test_expect_success \
        'Query "master@{2005-05-26 23:38:00}" (middle of history)' \
        'rm -f o e
-        git-rev-parse --verify "master@{2005-05-26 23:38:00}" >o 2>e &&
+        git rev-parse --verify "master@{2005-05-26 23:38:00}" >o 2>e &&
         test '"$Z"' = $(cat o) &&
         test "" = "$(cat e)"'
 test_expect_success \
        'Query "master@{2005-05-26 23:43:00}" (exact end of history)' \
        'rm -f o e
-        git-rev-parse --verify "master@{2005-05-26 23:43:00}" >o 2>e &&
+        git rev-parse --verify "master@{2005-05-26 23:43:00}" >o 2>e &&
         test '"$E"' = $(cat o) &&
         test "" = "$(cat e)"'
 test_expect_success \
        'Query "master@{2005-05-28}" (past end of history)' \
        'rm -f o e
-        git-rev-parse --verify "master@{2005-05-28}" >o 2>e &&
+        git rev-parse --verify "master@{2005-05-28}" >o 2>e &&
         test '"$D"' = $(cat o) &&
         test "warning: Log .git/logs/'"$m unexpectedly ended on $ld"'." = "$(cat e)"'
 
@@ -188,26 +188,26 @@ rm -f .git/$m .git/logs/$m expect
 test_expect_success \
     'creating initial files' \
     'echo TEST >F &&
-     git-add 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 &&
-        h_TEST=$(git-rev-parse --verify HEAD)
+        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 &&
-        h_OTHER=$(git-rev-parse --verify HEAD) &&
+        h_OTHER=$(git rev-parse --verify HEAD) &&
         echo FIXED >F &&
         GIT_AUTHOR_DATE="2005-05-26 23:44" \
         GIT_COMMITTER_DATE="2005-05-26 23:44" git-commit --amend &&
-        h_FIXED=$(git-rev-parse --verify HEAD) &&
+        h_FIXED=$(git rev-parse --verify HEAD) &&
         echo TEST+FIXED >F &&
         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 &&
-        h_MERGED=$(git-rev-parse --verify HEAD)
+        h_MERGED=$(git rev-parse --verify HEAD)
         rm -f M'
 
 cat >expect <<EOF
@@ -222,13 +222,13 @@ test_expect_success \
 unset h_TEST h_OTHER h_FIXED h_MERGED
 
 test_expect_success \
-       'git-cat-file blob master:F (expect OTHER)' \
-       'test OTHER = $(git-cat-file blob master:F)'
+       'git cat-file blob master:F (expect OTHER)' \
+       'test OTHER = $(git cat-file blob master:F)'
 test_expect_success \
-       'git-cat-file blob master@{2005-05-26 23:30}:F (expect TEST)' \
-       'test TEST = $(git-cat-file blob "master@{2005-05-26 23:30}:F")'
+       'git cat-file blob master@{2005-05-26 23:30}:F (expect TEST)' \
+       'test TEST = $(git cat-file blob "master@{2005-05-26 23:30}:F")'
 test_expect_success \
-       'git-cat-file blob master@{2005-05-26 23:42}:F (expect OTHER)' \
-       'test OTHER = $(git-cat-file blob "master@{2005-05-26 23:42}:F")'
+       'git cat-file blob master@{2005-05-26 23:42}:F (expect OTHER)' \
+       'test OTHER = $(git cat-file blob "master@{2005-05-26 23:42}:F")'
 
 test_done
diff --git a/t/t1420-lost-found.sh b/t/t1420-lost-found.sh
new file mode 100755 (executable)
index 0000000..dc9e402
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Johannes E. Schindelin
+#
+
+test_description='Test fsck --lost-found'
+. ./test-lib.sh
+
+test_expect_success setup '
+       git config core.logAllRefUpdates 0 &&
+       : > file1 &&
+       git add file1 &&
+       test_tick &&
+       git commit -m initial &&
+       echo 1 > file1 &&
+       echo 2 > file2 &&
+       git add file1 file2 &&
+       test_tick &&
+       git commit -m second &&
+       echo 3 > file3 &&
+       git add file3
+'
+
+test_expect_success 'lost and found something' '
+       git rev-parse HEAD > lost-commit &&
+       git rev-parse :file3 > lost-other &&
+       test_tick &&
+       git reset --hard HEAD^ &&
+       git fsck --lost-found &&
+       test 2 = $(ls .git/lost-found/*/* | wc -l) &&
+       test -f .git/lost-found/commit/$(cat lost-commit) &&
+       test -f .git/lost-found/other/$(cat lost-other)
+'
+
+test_done
diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh
new file mode 100755 (executable)
index 0000000..ec49966
--- /dev/null
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+test_description='test git rev-parse'
+. ./test-lib.sh
+
+test_rev_parse() {
+       name=$1
+       shift
+
+       test_expect_success "$name: is-bare-repository" \
+       "test '$1' = \"\$(git rev-parse --is-bare-repository)\""
+       shift
+       [ $# -eq 0 ] && return
+
+       test_expect_success "$name: is-inside-git-dir" \
+       "test '$1' = \"\$(git rev-parse --is-inside-git-dir)\""
+       shift
+       [ $# -eq 0 ] && return
+
+       test_expect_success "$name: is-inside-work-tree" \
+       "test '$1' = \"\$(git rev-parse --is-inside-work-tree)\""
+       shift
+       [ $# -eq 0 ] && return
+
+       test_expect_success "$name: prefix" \
+       "test '$1' = \"\$(git rev-parse --show-prefix)\""
+       shift
+       [ $# -eq 0 ] && return
+}
+
+test_rev_parse toplevel false false true ''
+
+cd .git || exit 1
+test_rev_parse .git/ false true true .git/
+cd objects || exit 1
+test_rev_parse .git/objects/ false true true .git/objects/
+cd ../.. || exit 1
+
+mkdir -p sub/dir || exit 1
+cd sub/dir || exit 1
+test_rev_parse subdirectory false false true sub/dir/
+cd ../.. || exit 1
+
+git config core.bare true
+test_rev_parse 'core.bare = true' true false true
+
+git config --unset core.bare
+test_rev_parse 'core.bare undefined' false false true
+
+mkdir work || exit 1
+cd work || exit 1
+export GIT_DIR=../.git
+export GIT_CONFIG="$GIT_DIR"/config
+
+git config core.bare false
+test_rev_parse 'GIT_DIR=../.git, core.bare = false' false false true ''
+
+git config core.bare true
+test_rev_parse 'GIT_DIR=../.git, core.bare = true' true false true ''
+
+git config --unset core.bare
+test_rev_parse 'GIT_DIR=../.git, core.bare undefined' false false true ''
+
+mv ../.git ../repo.git || exit 1
+export GIT_DIR=../repo.git
+export GIT_CONFIG="$GIT_DIR"/config
+
+git config core.bare false
+test_rev_parse 'GIT_DIR=../repo.git, core.bare = false' false false true ''
+
+git config core.bare true
+test_rev_parse 'GIT_DIR=../repo.git, core.bare = true' true false true ''
+
+git config --unset core.bare
+test_rev_parse 'GIT_DIR=../repo.git, core.bare undefined' true false true ''
+
+test_done
diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
new file mode 100755 (executable)
index 0000000..aadeeab
--- /dev/null
@@ -0,0 +1,92 @@
+#!/bin/sh
+
+test_description='test separate work tree'
+. ./test-lib.sh
+
+test_rev_parse() {
+       name=$1
+       shift
+
+       test_expect_success "$name: is-bare-repository" \
+       "test '$1' = \"\$(git rev-parse --is-bare-repository)\""
+       shift
+       [ $# -eq 0 ] && return
+
+       test_expect_success "$name: is-inside-git-dir" \
+       "test '$1' = \"\$(git rev-parse --is-inside-git-dir)\""
+       shift
+       [ $# -eq 0 ] && return
+
+       test_expect_success "$name: is-inside-work-tree" \
+       "test '$1' = \"\$(git rev-parse --is-inside-work-tree)\""
+       shift
+       [ $# -eq 0 ] && return
+
+       test_expect_success "$name: prefix" \
+       "test '$1' = \"\$(git rev-parse --show-prefix)\""
+       shift
+       [ $# -eq 0 ] && return
+}
+
+mkdir -p work/sub/dir || exit 1
+mv .git repo.git || exit 1
+
+say "core.worktree = relative path"
+export GIT_DIR=repo.git
+export GIT_CONFIG=$GIT_DIR/config
+unset GIT_WORK_TREE
+git config core.worktree ../work
+test_rev_parse 'outside'      false false false
+cd work || exit 1
+export GIT_DIR=../repo.git
+export GIT_CONFIG=$GIT_DIR/config
+test_rev_parse 'inside'       false false true ''
+cd sub/dir || exit 1
+export GIT_DIR=../../../repo.git
+export GIT_CONFIG=$GIT_DIR/config
+test_rev_parse 'subdirectory' false false true sub/dir/
+cd ../../.. || exit 1
+
+say "core.worktree = absolute path"
+export GIT_DIR=$(pwd)/repo.git
+export GIT_CONFIG=$GIT_DIR/config
+git config core.worktree "$(pwd)/work"
+test_rev_parse 'outside'      false false false
+cd work || exit 1
+test_rev_parse 'inside'       false false true ''
+cd sub/dir || exit 1
+test_rev_parse 'subdirectory' false false true sub/dir/
+cd ../../.. || exit 1
+
+say "GIT_WORK_TREE=relative path (override core.worktree)"
+export GIT_DIR=$(pwd)/repo.git
+export GIT_CONFIG=$GIT_DIR/config
+git config core.worktree non-existent
+export GIT_WORK_TREE=work
+test_rev_parse 'outside'      false false false
+cd work || exit 1
+export GIT_WORK_TREE=.
+test_rev_parse 'inside'       false false true ''
+cd sub/dir || exit 1
+export GIT_WORK_TREE=../..
+test_rev_parse 'subdirectory' false false true sub/dir/
+cd ../../.. || exit 1
+
+mv work repo.git/work
+
+say "GIT_WORK_TREE=absolute path, work tree below git dir"
+export GIT_DIR=$(pwd)/repo.git
+export GIT_CONFIG=$GIT_DIR/config
+export GIT_WORK_TREE=$(pwd)/repo.git/work
+test_rev_parse 'outside'              false false false
+cd repo.git || exit 1
+test_rev_parse 'in repo.git'              false true  false
+cd objects || exit 1
+test_rev_parse 'in repo.git/objects'      false true  false
+cd ../work || exit 1
+test_rev_parse 'in repo.git/work'         false false true ''
+cd sub/dir || exit 1
+test_rev_parse 'in repo.git/sub/dir' false false true sub/dir/
+cd ../../../.. || exit 1
+
+test_done
index 03ea4dece4b7fd3849269a0af3e960572ab5618d..ac84335b0a47fe1d26794e4c92f00d0ed051e540 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-checkout-index test.
+test_description='git checkout-index test.
 
 This test registers the following filesystem structure in the
 cache:
@@ -16,7 +16,7 @@ And then tries to checkout in a work tree that has the following:
     path0/file0 - a file in a directory
     path1       - a file
 
-The git-checkout-index command should fail when attempting to checkout
+The git checkout-index command should fail when attempting to checkout
 path0, finding it is occupied by a directory, and path1/file1, finding
 path1 is occupied by a non-directory.  With "-f" flag, it should remove
 the conflicting paths and succeed.
@@ -28,8 +28,8 @@ mkdir path1
 date >path1/file1
 
 test_expect_success \
-    'git-update-index --add various paths.' \
-    'git-update-index --add path0 path1/file1'
+    'git update-index --add various paths.' \
+    'git update-index --add path0 path1/file1'
 
 rm -fr path0 path1
 mkdir path0
@@ -37,17 +37,15 @@ date >path0/file0
 date >path1
 
 test_expect_failure \
-    'git-checkout-index without -f should fail on conflicting work tree.' \
-    'git-checkout-index -a'
+    'git checkout-index without -f should fail on conflicting work tree.' \
+    'git checkout-index -a'
 
 test_expect_success \
-    'git-checkout-index with -f should succeed.' \
-    'git-checkout-index -f -a'
+    'git checkout-index with -f should succeed.' \
+    'git checkout-index -f -a'
 
 test_expect_success \
-    'git-checkout-index conflicting paths.' \
+    'git checkout-index conflicting paths.' \
     'test -f path0 && test -d path1 && test -f path1/file1'
 
 test_done
-
-
index 0dcab8f1dea0d3d5e4bcebbc0b571fe46c2265e0..ef007532b15108d72445f7c95a2906a3039fbbbb 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-checkout-index test.
+test_description='git checkout-index test.
 
 This test registers the following filesystem structure in the cache:
 
@@ -26,46 +26,46 @@ show_files() {
        find path? -ls |
        sed -e 's/^[0-9]* * [0-9]* * \([-bcdl]\)[^ ]* *[0-9]* *[^ ]* *[^ ]* *[0-9]* [A-Z][a-z][a-z] [0-9][0-9] [^ ]* /fs: \1 /'
        # what's in the cache, just mode and name
-       git-ls-files --stage |
+       git ls-files --stage |
        sed -e 's/^\([0-9]*\) [0-9a-f]* [0-3] /ca: \1 /'
        # what's in the tree, just mode and name.
-       git-ls-tree -r "$1" |
+       git ls-tree -r "$1" |
        sed -e 's/^\([0-9]*\)   [^ ]*   [0-9a-f]*       /tr: \1 /'
 }
 
 mkdir path0
 date >path0/file0
 test_expect_success \
-    'git-update-index --add path0/file0' \
-    'git-update-index --add path0/file0'
+    'git update-index --add path0/file0' \
+    'git update-index --add path0/file0'
 test_expect_success \
-    'writing tree out with git-write-tree' \
-    'tree1=$(git-write-tree)'
+    'writing tree out with git write-tree' \
+    'tree1=$(git write-tree)'
 test_debug 'show_files $tree1'
 
 mkdir path1
 date >path1/file1
 test_expect_success \
-    'git-update-index --add path1/file1' \
-    'git-update-index --add path1/file1'
+    'git update-index --add path1/file1' \
+    'git update-index --add path1/file1'
 test_expect_success \
-    'writing tree out with git-write-tree' \
-    'tree2=$(git-write-tree)'
+    'writing tree out with git write-tree' \
+    'tree2=$(git write-tree)'
 test_debug 'show_files $tree2'
 
 rm -fr path1
 test_expect_success \
     'read previously written tree and checkout.' \
-    'git-read-tree -m $tree1 && git-checkout-index -f -a'
+    'git read-tree -m $tree1 && git checkout-index -f -a'
 test_debug 'show_files $tree1'
 
 ln -s path0 path1
 test_expect_success \
-    'git-update-index --add a symlink.' \
-    'git-update-index --add path1'
+    'git update-index --add a symlink.' \
+    'git update-index --add path1'
 test_expect_success \
-    'writing tree out with git-write-tree' \
-    'tree3=$(git-write-tree)'
+    'writing tree out with git write-tree' \
+    'tree3=$(git write-tree)'
 test_debug 'show_files $tree3'
 
 # Morten says "Got that?" here.
@@ -73,7 +73,7 @@ test_debug 'show_files $tree3'
 
 test_expect_success \
     'read previously written tree and checkout.' \
-    'git-read-tree $tree2 && git-checkout-index -f -a'
+    'git read-tree $tree2 && git checkout-index -f -a'
 test_debug 'show_files $tree2'
 
 test_expect_success \
@@ -84,4 +84,3 @@ test_expect_success \
      test ! -h path1/file1 && test -f path1/file1'
 
 test_done
-
index 4352ddb1cb78968099acacfd7cebc47febd58e5b..f7a00559209872fab5c79896ed5bc71ba64c884e 100755 (executable)
@@ -3,31 +3,31 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-checkout-index -u test.
+test_description='git checkout-index -u test.
 
-With -u flag, git-checkout-index internally runs the equivalent of
-git-update-index --refresh on the checked out entry.'
+With -u flag, git checkout-index internally runs the equivalent of
+git update-index --refresh on the checked out entry.'
 
 . ./test-lib.sh
 
 test_expect_success \
 'preparation' '
 echo frotz >path0 &&
-git-update-index --add path0 &&
-t=$(git-write-tree)'
+git update-index --add path0 &&
+t=$(git write-tree)'
 
 test_expect_failure \
-'without -u, git-checkout-index smudges stat information.' '
+'without -u, git checkout-index smudges stat information.' '
 rm -f path0 &&
-git-read-tree $t &&
-git-checkout-index -f -a &&
-git-diff-files | diff - /dev/null'
+git read-tree $t &&
+git checkout-index -f -a &&
+git diff-files | diff - /dev/null'
 
 test_expect_success \
-'with -u, git-checkout-index picks up stat information from new files.' '
+'with -u, git checkout-index picks up stat information from new files.' '
 rm -f path0 &&
-git-read-tree $t &&
-git-checkout-index -u -f -a &&
-git-diff-files | diff - /dev/null'
+git read-tree $t &&
+git checkout-index -u -f -a &&
+git diff-files | diff - /dev/null'
 
 test_done
index f9bc90aee44a799d62bb07ad70165a5d8bd34491..71894b37439bd1b9c72194cbbabe37680d2f9743 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-checkout-index --prefix test.
+test_description='git checkout-index --prefix test.
 
 This test makes sure that --prefix option works as advertised, and
 also verifies that such leading path may contain symlinks, unlike
@@ -17,14 +17,14 @@ test_expect_success \
     'mkdir path1 &&
     echo frotz >path0 &&
     echo rezrov >path1/file1 &&
-    git-update-index --add path0 path1/file1'
+    git update-index --add path0 path1/file1'
 
 test_expect_success \
     'have symlink in place where dir is expected.' \
     'rm -fr path0 path1 &&
      mkdir path2 &&
      ln -s path2 path1 &&
-     git-checkout-index -f -a &&
+     git checkout-index -f -a &&
      test ! -h path1 && test -d path1 &&
      test -f path1/file1 && test ! -f path2/file1'
 
@@ -32,7 +32,7 @@ test_expect_success \
     'use --prefix=path2/' \
     'rm -fr path0 path1 path2 &&
      mkdir path2 &&
-     git-checkout-index --prefix=path2/ -f -a &&
+     git checkout-index --prefix=path2/ -f -a &&
      test -f path2/path0 &&
      test -f path2/path1/file1 &&
      test ! -f path0 &&
@@ -41,7 +41,7 @@ test_expect_success \
 test_expect_success \
     'use --prefix=tmp-' \
     'rm -fr path0 path1 path2 tmp* &&
-     git-checkout-index --prefix=tmp- -f -a &&
+     git checkout-index --prefix=tmp- -f -a &&
      test -f tmp-path0 &&
      test -f tmp-path1/file1 &&
      test ! -f path0 &&
@@ -52,7 +52,7 @@ test_expect_success \
     'rm -fr path0 path1 path2 tmp* &&
      echo nitfol >tmp-path1 &&
      mkdir tmp-path0 &&
-     git-checkout-index --prefix=tmp- -f -a &&
+     git checkout-index --prefix=tmp- -f -a &&
      test -f tmp-path0 &&
      test -f tmp-path1/file1 &&
      test ! -f path0 &&
@@ -64,7 +64,7 @@ test_expect_success \
     'rm -fr path0 path1 path2 tmp* &&
      mkdir tmp1 tmp1/orary &&
      ln -s tmp1 tmp &&
-     git-checkout-index --prefix=tmp/orary/ -f -a &&
+     git checkout-index --prefix=tmp/orary/ -f -a &&
      test -d tmp1/orary &&
      test -f tmp1/orary/path0 &&
      test -f tmp1/orary/path1/file1 &&
@@ -76,7 +76,7 @@ test_expect_success \
     'rm -fr path0 path1 path2 tmp* &&
      mkdir tmp1 &&
      ln -s tmp1 tmp &&
-     git-checkout-index --prefix=tmp/orary- -f -a &&
+     git checkout-index --prefix=tmp/orary- -f -a &&
      test -f tmp1/orary-path0 &&
      test -f tmp1/orary-path1/file1 &&
      test -h tmp'
@@ -87,7 +87,7 @@ test_expect_success \
     'rm -fr path0 path1 path2 tmp* &&
      mkdir tmp1 &&
      ln -s tmp1 tmp-path1 &&
-     git-checkout-index --prefix=tmp- -f -a &&
+     git checkout-index --prefix=tmp- -f -a &&
      test -f tmp-path0 &&
      test ! -h tmp-path1 &&
      test -d tmp-path1 &&
index c100959cad3f017ec282c10bbc31bdc4982d5fbc..39133b8c7a4b56cb7273cec607ea89081a426eff 100755 (executable)
@@ -3,9 +3,9 @@
 # Copyright (c) 2006 Shawn Pearce
 #
 
-test_description='git-checkout-index --temp test.
+test_description='git checkout-index --temp test.
 
-With --temp flag, git-checkout-index writes to temporary merge files
+With --temp flag, git checkout-index writes to temporary merge files
 rather than the tracked path.'
 
 . ./test-lib.sh
@@ -18,28 +18,28 @@ echo tree1path1 >path1 &&
 echo tree1path3 >path3 &&
 echo tree1path4 >path4 &&
 echo tree1asubdir/path5 >asubdir/path5 &&
-git-update-index --add path0 path1 path3 path4 asubdir/path5 &&
-t1=$(git-write-tree) &&
+git update-index --add path0 path1 path3 path4 asubdir/path5 &&
+t1=$(git write-tree) &&
 rm -f path* .merge_* out .git/index &&
 echo tree2path0 >path0 &&
 echo tree2path1 >path1 &&
 echo tree2path2 >path2 &&
 echo tree2path4 >path4 &&
-git-update-index --add path0 path1 path2 path4 &&
-t2=$(git-write-tree) &&
+git update-index --add path0 path1 path2 path4 &&
+t2=$(git write-tree) &&
 rm -f path* .merge_* out .git/index &&
 echo tree2path0 >path0 &&
 echo tree3path1 >path1 &&
 echo tree3path2 >path2 &&
 echo tree3path3 >path3 &&
-git-update-index --add path0 path1 path2 path3 &&
-t3=$(git-write-tree)'
+git update-index --add path0 path1 path2 path3 &&
+t3=$(git write-tree)'
 
 test_expect_success \
 'checkout one stage 0 to temporary file' '
 rm -f path* .merge_* out .git/index &&
-git-read-tree $t1 &&
-git-checkout-index --temp -- path1 >out &&
+git read-tree $t1 &&
+git checkout-index --temp -- path1 >out &&
 test $(wc -l <out) = 1 &&
 test $(cut "-d " -f2 out) = path1 &&
 p=$(cut "-d    " -f1 out) &&
@@ -49,8 +49,8 @@ test $(cat $p) = tree1path1'
 test_expect_success \
 'checkout all stage 0 to temporary files' '
 rm -f path* .merge_* out .git/index &&
-git-read-tree $t1 &&
-git-checkout-index -a --temp >out &&
+git read-tree $t1 &&
+git checkout-index -a --temp >out &&
 test $(wc -l <out) = 5 &&
 for f in path0 path1 path3 path4 asubdir/path5
 do
@@ -63,12 +63,12 @@ done'
 test_expect_success \
 'prepare 3-way merge' '
 rm -f path* .merge_* out .git/index &&
-git-read-tree -m $t1 $t2 $t3'
+git read-tree -m $t1 $t2 $t3'
 
 test_expect_success \
 'checkout one stage 2 to temporary file' '
 rm -f path* .merge_* out &&
-git-checkout-index --stage=2 --temp -- path1 >out &&
+git checkout-index --stage=2 --temp -- path1 >out &&
 test $(wc -l <out) = 1 &&
 test $(cut "-d " -f2 out) = path1 &&
 p=$(cut "-d    " -f1 out) &&
@@ -78,7 +78,7 @@ test $(cat $p) = tree2path1'
 test_expect_success \
 'checkout all stage 2 to temporary files' '
 rm -f path* .merge_* out &&
-git-checkout-index --all --stage=2 --temp >out &&
+git checkout-index --all --stage=2 --temp >out &&
 test $(wc -l <out) = 3 &&
 for f in path1 path2 path4
 do
@@ -91,13 +91,13 @@ done'
 test_expect_success \
 'checkout all stages/one file to nothing' '
 rm -f path* .merge_* out &&
-git-checkout-index --stage=all --temp -- path0 >out &&
+git checkout-index --stage=all --temp -- path0 >out &&
 test $(wc -l <out) = 0'
 
 test_expect_success \
 'checkout all stages/one file to temporary files' '
 rm -f path* .merge_* out &&
-git-checkout-index --stage=all --temp -- path1 >out &&
+git checkout-index --stage=all --temp -- path1 >out &&
 test $(wc -l <out) = 1 &&
 test $(cut "-d " -f2 out) = path1 &&
 cut "-d        " -f1 out | (read s1 s2 s3 &&
@@ -111,7 +111,7 @@ test $(cat $s3) = tree3path1)'
 test_expect_success \
 'checkout some stages/one file to temporary files' '
 rm -f path* .merge_* out &&
-git-checkout-index --stage=all --temp -- path2 >out &&
+git checkout-index --stage=all --temp -- path2 >out &&
 test $(wc -l <out) = 1 &&
 test $(cut "-d " -f2 out) = path2 &&
 cut "-d        " -f1 out | (read s1 s2 s3 &&
@@ -124,7 +124,7 @@ test $(cat $s3) = tree3path2)'
 test_expect_success \
 'checkout all stages/all files to temporary files' '
 rm -f path* .merge_* out &&
-git-checkout-index -a --stage=all --temp >out &&
+git checkout-index -a --stage=all --temp >out &&
 test $(wc -l <out) = 5'
 
 test_expect_success \
@@ -184,7 +184,7 @@ test $(cat $s1) = tree1asubdir/path5)'
 test_expect_success \
 'checkout --temp within subdir' '
 (cd asubdir &&
- git-checkout-index -a --stage=all >out &&
+ git checkout-index -a --stage=all >out &&
  test $(wc -l <out) = 1 &&
  test $(grep path5 out | cut "-d       " -f2) = path5 &&
  grep path5 out | cut "-d      " -f1 | (read s1 s2 s3 &&
@@ -198,11 +198,11 @@ test_expect_success \
 'checkout --temp symlink' '
 rm -f path* .merge_* out .git/index &&
 ln -s b a &&
-git-update-index --add a &&
-t4=$(git-write-tree) &&
+git update-index --add a &&
+t4=$(git write-tree) &&
 rm -f .git/index &&
-git-read-tree $t4 &&
-git-checkout-index --temp -a >out &&
+git read-tree $t4 &&
+git checkout-index --temp -a >out &&
 test $(wc -l <out) = 1 &&
 test $(cut "-d " -f2 out) = a &&
 p=$(cut "-d    " -f1 out) &&
index e34a51533353e9e88a228b7ec2d88a08550f7ae8..a84c5a6af9e69ffec7689827ce1ba653a658a73f 100755 (executable)
@@ -3,22 +3,22 @@
 # Copyright (c) 2007 Johannes Sixt
 #
 
-test_description='git-checkout-index on filesystem w/o symlinks test.
+test_description='git checkout-index on filesystem w/o symlinks test.
 
-This tests that git-checkout-index creates a symbolic link as a plain
+This tests that git checkout-index creates a symbolic link as a plain
 file if core.symlinks is false.'
 
 . ./test-lib.sh
 
 test_expect_success \
 'preparation' '
-git-config core.symlinks false &&
+git config core.symlinks false &&
 l=$(echo -n file | git-hash-object -t blob -w --stdin) &&
-echo "120000 $l        symlink" | git-update-index --index-info'
+echo "120000 $l        symlink" | git update-index --index-info'
 
 test_expect_success \
 'the checked-out symlink must be a file' '
-git-checkout-index symlink &&
+git checkout-index symlink &&
 test -f symlink'
 
 test_expect_success \
index 5bc0a3bed3e9fb53639bc6a00ce4ff82e8c78ca1..04a1ed1a6b9dd4eabc2b95d348b77b0fd08b0da4 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-update-index nonsense-path test.
+test_description='git update-index nonsense-path test.
 
 This test creates the following structure in the cache:
 
@@ -12,7 +12,7 @@ This test creates the following structure in the cache:
     path2/file2 - a file in a directory
     path3/file3 - a file in a directory
 
-and tries to git-update-index --add the following:
+and tries to git update-index --add the following:
 
     path0/file0 - a file in a directory
     path1/file1 - a file in a directory
@@ -31,8 +31,8 @@ date >path2/file2
 date >path3/file3
 
 test_expect_success \
-    'git-update-index --add to add various paths.' \
-    'git-update-index --add -- path0 path1 path2/file2 path3/file3'
+    'git update-index --add to add various paths.' \
+    'git update-index --add -- path0 path1 path2/file2 path3/file3'
 
 rm -fr path?
 
@@ -45,7 +45,7 @@ date >path1/file1
 for p in path0/file0 path1/file1 path2 path3
 do
        test_expect_failure \
-           "git-update-index to add conflicting path $p should fail." \
-           "git-update-index --add -- $p"
+           "git update-index to add conflicting path $p should fail." \
+           "git update-index --add -- $p"
 done
 test_done
index a78ea7f0b0e4910407c75191fc683daaac1af2b6..59b560bfdf240e87516aadd6a31a2fe84e85d49a 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2006 Junio C Hamano
 #
 
-test_description='git-update-index --again test.
+test_description='git update-index --again test.
 '
 
 . ./test-lib.sh
@@ -15,29 +15,29 @@ EOF
 test_expect_success 'update-index --add' \
        'echo hello world >file1 &&
         echo goodbye people >file2 &&
-        git-update-index --add file1 file2 &&
-        git-ls-files -s >current &&
+        git update-index --add file1 file2 &&
+        git ls-files -s >current &&
         cmp current expected'
 
 test_expect_success 'update-index --again' \
        'rm -f file1 &&
        echo hello everybody >file2 &&
-       if git-update-index --again
+       if git update-index --again
        then
                echo should have refused to remove file1
                exit 1
        else
                echo happy - failed as expected
        fi &&
-        git-ls-files -s >current &&
+        git ls-files -s >current &&
         cmp current expected'
 
 cat > expected <<\EOF
 100644 0f1ae1422c2bf43f117d3dbd715c988a9ed2103f 0      file2
 EOF
 test_expect_success 'update-index --remove --again' \
-       'git-update-index --remove --again &&
-        git-ls-files -s >current &&
+       'git update-index --remove --again &&
+        git ls-files -s >current &&
         cmp current expected'
 
 test_expect_success 'first commit' 'git-commit -m initial'
@@ -50,11 +50,11 @@ test_expect_success 'update-index again' \
        'mkdir -p dir1 &&
        echo hello world >dir1/file3 &&
        echo goodbye people >file2 &&
-       git-update-index --add file2 dir1/file3 &&
+       git update-index --add file2 dir1/file3 &&
        echo hello everybody >file2
        echo happy >dir1/file3 &&
-       git-update-index --again &&
-       git-ls-files -s >current &&
+       git update-index --again &&
+       git ls-files -s >current &&
        cmp current expected'
 
 cat > expected <<\EOF
@@ -65,9 +65,9 @@ test_expect_success 'update-index --update from subdir' \
        'echo not so happy >file2 &&
        cd dir1 &&
        cat ../file2 >file3 &&
-       git-update-index --again &&
+       git update-index --again &&
        cd .. &&
-       git-ls-files -s >current &&
+       git ls-files -s >current &&
        cmp current expected'
 
 cat > expected <<\EOF
@@ -77,8 +77,8 @@ EOF
 test_expect_success 'update-index --update with pathspec' \
        'echo very happy >file2 &&
        cat file2 >dir1/file3 &&
-       git-update-index --again dir1/ &&
-       git-ls-files -s >current &&
+       git update-index --again dir1/ &&
+       git ls-files -s >current &&
        cmp current expected'
 
 test_done
index 969ef891d3152106e192e84595c0de9b1010cd4b..19d0894d260787d37a43199d7a3f6c3aa37d32aa 100755 (executable)
@@ -3,29 +3,29 @@
 # Copyright (c) 2007 Johannes Sixt
 #
 
-test_description='git-update-index on filesystem w/o symlinks test.
+test_description='git update-index on filesystem w/o symlinks test.
 
-This tests that git-update-index keeps the symbolic link property
+This tests that git update-index keeps the symbolic link property
 even if a plain file is in the working tree if core.symlinks is false.'
 
 . ./test-lib.sh
 
 test_expect_success \
 'preparation' '
-git-config core.symlinks false &&
+git config core.symlinks false &&
 l=$(echo -n file | git-hash-object -t blob -w --stdin) &&
-echo "120000 $l        symlink" | git-update-index --index-info'
+echo "120000 $l        symlink" | git update-index --index-info'
 
 test_expect_success \
 'modify the symbolic link' '
 echo -n new-file > symlink &&
-git-update-index symlink'
+git update-index symlink'
 
 test_expect_success \
 'the index entry must still be a symbolic link' '
-case "`git-ls-files --stage --cached symlink`" in
+case "`git ls-files --stage --cached symlink`" in
 120000" "*symlink) echo ok;;
-*) echo fail; git-ls-files --stage --cached symlink; (exit 1);;
+*) echo fail; git ls-files --stage --cached symlink; (exit 1);;
 esac'
 
 test_done
index 83005e70d00f5805e26b8873df2598225453fe83..0a703af14976d7e546e1b5fde6affbde22b724c2 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='git-add -u with path limiting
+test_description='git add -u with path limiting
 
 This test creates a working tree state with three files:
 
@@ -8,7 +8,7 @@ This test creates a working tree state with three files:
   dir/sub (previously committed, modified)
   dir/other (untracked)
 
-and issues a git-add -u with path limiting on "dir" to add
+and issues a git add -u with path limiting on "dir" to add
 only the updates to dir/sub.'
 
 . ./test-lib.sh
@@ -17,22 +17,22 @@ test_expect_success 'setup' '
 echo initial >top &&
 mkdir dir &&
 echo initial >dir/sub &&
-git-add dir/sub top &&
+git add dir/sub top &&
 git-commit -m initial &&
 echo changed >top &&
 echo changed >dir/sub &&
 echo other >dir/other
 '
 
-test_expect_success 'update' 'git-add -u dir'
+test_expect_success 'update' 'git add -u dir'
 
 test_expect_success 'update touched correct path' \
-  'test "`git-diff-files --name-status dir/sub`" = ""'
+  'test "`git diff-files --name-status dir/sub`" = ""'
 
 test_expect_success 'update did not touch other tracked files' \
-  'test "`git-diff-files --name-status top`" = "M      top"'
+  'test "`git diff-files --name-status top`" = "M      top"'
 
 test_expect_success 'update did not touch untracked files' \
-  'test "`git-diff-files --name-status dir/other`" = ""'
+  'test "`git diff-files --name-status dir/other`" = ""'
 
 test_done
index adcbe03d561b2a7295a881d923b013bbefb9c7c7..bc0a3513920cab41e4335b8c1b5163e25e8354d3 100755 (executable)
@@ -3,9 +3,9 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-ls-files test (--others should pick up symlinks).
+test_description='git ls-files test (--others should pick up symlinks).
 
-This test runs git-ls-files --others with the following on the
+This test runs git ls-files --others with the following on the
 filesystem.
 
     path0       - a file
@@ -23,7 +23,7 @@ date >path2/file2
 date >path2-junk
 date >path3/file3
 date >path3-junk
-git-update-index --add path3-junk path3/file3
+git update-index --add path3-junk path3/file3
 
 cat >expected1 <<EOF
 expected1
@@ -37,20 +37,20 @@ EOF
 sed -e 's|path2/file2|path2/|' <expected1 >expected2
 
 test_expect_success \
-    'git-ls-files --others to show output.' \
-    'git-ls-files --others >output'
+    'git ls-files --others to show output.' \
+    'git ls-files --others >output'
 
 test_expect_success \
-    'git-ls-files --others should pick up symlinks.' \
+    'git ls-files --others should pick up symlinks.' \
     'diff output expected1'
 
 test_expect_success \
-    'git-ls-files --others --directory to show output.' \
-    'git-ls-files --others --directory >output'
+    'git ls-files --others --directory to show output.' \
+    'git ls-files --others --directory >output'
 
 
 test_expect_success \
-    'git-ls-files --others --directory should not get confused.' \
+    'git ls-files --others --directory should not get confused.' \
     'diff output expected2'
 
 test_done
index fcfcfbba7df50b55df7d002bf9745b912cfcae9b..ae0639d8f3a3fa428dca31df55193487a74b5b57 100755 (executable)
@@ -3,9 +3,9 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-ls-files --others --exclude
+test_description='git ls-files --others --exclude
 
-This test runs git-ls-files --others and tests --exclude patterns.
+This test runs git ls-files --others and tests --exclude patterns.
 '
 
 . ./test-lib.sh
@@ -59,8 +59,8 @@ echo '!*.2
 !*.8' >one/two/.gitignore
 
 test_expect_success \
-    'git-ls-files --others with various exclude options.' \
-    'git-ls-files --others \
+    'git ls-files --others with various exclude options.' \
+    'git ls-files --others \
        --exclude=\*.6 \
        --exclude-per-directory=.gitignore \
        --exclude-from=.git/ignore \
@@ -71,8 +71,8 @@ test_expect_success \
 printf '*.1\r\n/*.3\r\n!*.6\r\n' >.gitignore
 
 test_expect_success \
-    'git-ls-files --others with \r\n line endings.' \
-    'git-ls-files --others \
+    'git ls-files --others with \r\n line endings.' \
+    'git ls-files --others \
        --exclude=\*.6 \
        --exclude-per-directory=.gitignore \
        --exclude-from=.git/ignore \
@@ -84,9 +84,9 @@ cat > excludes-file << EOF
 e*
 EOF
 
-git-config core.excludesFile excludes-file
+git config core.excludesFile excludes-file
 
-git-runstatus | grep "^#       " > output
+git runstatus | grep "^#       " > output
 
 cat > expect << EOF
 #      .gitignore
index cc8967d76b10e18eb6b7db69fbb31baf702f2efc..8687a01d2b169c1afafcd811d9108a85ad9fdd56 100755 (executable)
@@ -3,9 +3,9 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-ls-files test (-- to terminate the path list).
+test_description='git ls-files test (-- to terminate the path list).
 
-This test runs git-ls-files --others with the following on the
+This test runs git ls-files --others with the following on the
 filesystem.
 
     path0       - a file
@@ -21,8 +21,8 @@ test_expect_success \
        echo frotz >./--'
 
 test_expect_success \
-    'git-ls-files without path restriction.' \
-    'git-ls-files --others >output &&
+    'git ls-files without path restriction.' \
+    'git ls-files --others >output &&
      git diff output - <<EOF
 --
 -foo
@@ -32,32 +32,32 @@ EOF
 '
 
 test_expect_success \
-    'git-ls-files with path restriction.' \
-    'git-ls-files --others path0 >output &&
+    'git ls-files with path restriction.' \
+    'git ls-files --others path0 >output &&
        git diff output - <<EOF
 path0
 EOF
 '
 
 test_expect_success \
-    'git-ls-files with path restriction with --.' \
-    'git-ls-files --others -- path0 >output &&
+    'git ls-files with path restriction with --.' \
+    'git ls-files --others -- path0 >output &&
        git diff output - <<EOF
 path0
 EOF
 '
 
 test_expect_success \
-    'git-ls-files with path restriction with -- --.' \
-    'git-ls-files --others -- -- >output &&
+    'git ls-files with path restriction with -- --.' \
+    'git ls-files --others -- -- >output &&
        git diff output - <<EOF
 --
 EOF
 '
 
 test_expect_success \
-    'git-ls-files with no path restriction.' \
-    'git-ls-files --others -- >output &&
+    'git ls-files with no path restriction.' \
+    'git ls-files --others -- >output &&
        git diff output - <<EOF
 --
 -foo
index 5fc19767117fae3e0f41dd6061a69ff177ede1a4..ec1404063701eef04667d5ffbbb4bdc8051c773b 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-ls-files -k and -m flags test.
+test_description='git ls-files -k and -m flags test.
 
 This test prepares the following in the cache:
 
@@ -22,7 +22,7 @@ and the following on the filesystem:
     path5      - a symlink
     path6/file6 - a file in a directory
 
-git-ls-files -k should report that existing filesystem
+git ls-files -k should report that existing filesystem
 objects except path4, path5 and path6/file6 to be killed.
 
 Also for modification test, the cache and working tree have:
@@ -47,8 +47,8 @@ date >path8
 : >path9
 date >path10
 test_expect_success \
-    'git-update-index --add to add various paths.' \
-    "git-update-index --add -- path0 path1 path?/file? path7 path8 path9 path10"
+    'git update-index --add to add various paths.' \
+    "git update-index --add -- path0 path1 path?/file? path7 path8 path9 path10"
 
 rm -fr path? ;# leave path10 alone
 date >path2
@@ -64,8 +64,8 @@ date >path7
 touch path10
 
 test_expect_success \
-    'git-ls-files -k to show killed files.' \
-    'git-ls-files -k >.output'
+    'git ls-files -k to show killed files.' \
+    'git ls-files -k >.output'
 cat >.expected <<EOF
 path0/file0
 path1/file1
@@ -74,12 +74,12 @@ path3
 EOF
 
 test_expect_success \
-    'validate git-ls-files -k output.' \
+    'validate git ls-files -k output.' \
     'diff .output .expected'
 
 test_expect_success \
-    'git-ls-files -m to show modified files.' \
-    'git-ls-files -m >.output'
+    'git ls-files -m to show modified files.' \
+    'git ls-files -m >.output'
 cat >.expected <<EOF
 path0
 path1
@@ -90,7 +90,7 @@ path8
 EOF
 
 test_expect_success \
-    'validate git-ls-files -m output.' \
+    'validate git ls-files -m output.' \
     'diff .output .expected'
 
 test_done
index d55559e553d3bd4d9432ac9778b6bcc7888c5a04..c83f820ad2d8588b8e5e15b3cb55172b26b7c33e 100755 (executable)
@@ -3,25 +3,25 @@
 # Copyright (c) 2006 Carl D. Worth
 #
 
-test_description='git-ls-files test for --error-unmatch option
+test_description='git ls-files test for --error-unmatch option
 
-This test runs git-ls-files --error-unmatch to ensure it correctly
+This test runs git ls-files --error-unmatch to ensure it correctly
 returns an error when a non-existent path is provided on the command
 line.
 '
 . ./test-lib.sh
 
 touch foo bar
-git-update-index --add foo bar
+git update-index --add foo bar
 git-commit -m "add foo bar"
 
 test_expect_failure \
-    'git-ls-files --error-unmatch should fail with unmatched path.' \
-    'git-ls-files --error-unmatch foo bar-does-not-match'
+    'git ls-files --error-unmatch should fail with unmatched path.' \
+    'git ls-files --error-unmatch foo bar-does-not-match'
 
 test_expect_success \
-    'git-ls-files --error-unmatch should succeed eith matched paths.' \
-    'git-ls-files --error-unmatch foo bar'
+    'git ls-files --error-unmatch should succeed eith matched paths.' \
+    'git ls-files --error-unmatch foo bar'
 
 test_done
 1
index 86ee2b0bd3737f94ebab32a344a6b1c5afc5ea92..607f57ff941b7da5296ab58cbf5e30db66087669 100755 (executable)
@@ -525,4 +525,3 @@ test_expect_success 'reset and bind merge' '
 '
 
 test_done
-
index e10749245b454f4c71486e536049cbf5b09259d5..46427e3f365ad0ec09c432f8cedf2106afe4dc08 100755 (executable)
@@ -3,9 +3,9 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-ls-tree test.
+test_description='git ls-tree test.
 
-This test runs git-ls-tree with the following in a tree.
+This test runs git ls-tree with the following in a tree.
 
     path0       - a file
     path1      - a symlink
@@ -27,8 +27,8 @@ test_expect_success \
      ln -s ../path1 path2/bazbo &&
      echo Mi >path2/baz/b &&
      find path? \( -type f -o -type l \) -print |
-     xargs git-update-index --add &&
-     tree=`git-write-tree` &&
+     xargs git update-index --add &&
+     tree=`git write-tree` &&
      echo $tree'
 
 _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
@@ -40,7 +40,7 @@ test_output () {
 
 test_expect_success \
     'ls-tree plain' \
-    'git-ls-tree $tree >current &&
+    'git ls-tree $tree >current &&
      cat >expected <<\EOF &&
 100644 blob X  path0
 120000 blob X  path1
@@ -50,7 +50,7 @@ EOF
 
 test_expect_success \
     'ls-tree recursive' \
-    'git-ls-tree -r $tree >current &&
+    'git ls-tree -r $tree >current &&
      cat >expected <<\EOF &&
 100644 blob X  path0
 120000 blob X  path1
@@ -62,7 +62,7 @@ EOF
 
 test_expect_success \
     'ls-tree recursive with -t' \
-    'git-ls-tree -r -t $tree >current &&
+    'git ls-tree -r -t $tree >current &&
      cat >expected <<\EOF &&
 100644 blob X  path0
 120000 blob X  path1
@@ -76,7 +76,7 @@ EOF
 
 test_expect_success \
     'ls-tree recursive with -d' \
-    'git-ls-tree -r -d $tree >current &&
+    'git ls-tree -r -d $tree >current &&
      cat >expected <<\EOF &&
 040000 tree X  path2
 040000 tree X  path2/baz
@@ -85,7 +85,7 @@ EOF
 
 test_expect_success \
     'ls-tree filtered with path' \
-    'git-ls-tree $tree path >current &&
+    'git ls-tree $tree path >current &&
      cat >expected <<\EOF &&
 EOF
      test_output'
@@ -95,7 +95,7 @@ EOF
 # they are shown in canonical order.
 test_expect_success \
     'ls-tree filtered with path1 path0' \
-    'git-ls-tree $tree path1 path0 >current &&
+    'git ls-tree $tree path1 path0 >current &&
      cat >expected <<\EOF &&
 100644 blob X  path0
 120000 blob X  path1
@@ -104,7 +104,7 @@ EOF
 
 test_expect_success \
     'ls-tree filtered with path0/' \
-    'git-ls-tree $tree path0/ >current &&
+    'git ls-tree $tree path0/ >current &&
      cat >expected <<\EOF &&
 EOF
      test_output'
@@ -113,7 +113,7 @@ EOF
 # with pathspec semantics it shows only path2
 test_expect_success \
     'ls-tree filtered with path2' \
-    'git-ls-tree $tree path2 >current &&
+    'git ls-tree $tree path2 >current &&
      cat >expected <<\EOF &&
 040000 tree X  path2
 EOF
@@ -122,7 +122,7 @@ EOF
 # ... and path2/ shows the children.
 test_expect_success \
     'ls-tree filtered with path2/' \
-    'git-ls-tree $tree path2/ >current &&
+    'git ls-tree $tree path2/ >current &&
      cat >expected <<\EOF &&
 040000 tree X  path2/baz
 120000 blob X  path2/bazbo
@@ -134,7 +134,7 @@ EOF
 # path2/baz
 test_expect_success \
     'ls-tree filtered with path2/baz' \
-    'git-ls-tree $tree path2/baz >current &&
+    'git ls-tree $tree path2/baz >current &&
      cat >expected <<\EOF &&
 040000 tree X  path2/baz
 EOF
@@ -142,14 +142,14 @@ EOF
 
 test_expect_success \
     'ls-tree filtered with path2/bak' \
-    'git-ls-tree $tree path2/bak >current &&
+    'git ls-tree $tree path2/bak >current &&
      cat >expected <<\EOF &&
 EOF
      test_output'
 
 test_expect_success \
     'ls-tree -t filtered with path2/bak' \
-    'git-ls-tree -t $tree path2/bak >current &&
+    'git ls-tree -t $tree path2/bak >current &&
      cat >expected <<\EOF &&
 040000 tree X  path2
 EOF
index 087929a4bfdf053124f81af3bfb73ab1e9e1709a..39fe2676dcd8e22451309d2321dee45410f90963 100755 (executable)
@@ -4,9 +4,9 @@
 # Copyright (c) 2005 Robert Fitzsimons
 #
 
-test_description='git-ls-tree directory and filenames handling.
+test_description='git ls-tree directory and filenames handling.
 
-This test runs git-ls-tree with the following in a tree.
+This test runs git ls-tree with the following in a tree.
 
     1.txt              - a file
     2.txt              - a file
@@ -35,8 +35,8 @@ test_expect_success \
      echo 111 >path3/1.txt &&
      echo 222 >path3/2.txt &&
      find *.txt path* \( -type f -o -type l \) -print |
-     xargs git-update-index --add &&
-     tree=`git-write-tree` &&
+     xargs git update-index --add &&
+     tree=`git write-tree` &&
      echo $tree'
 
 _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
@@ -48,7 +48,7 @@ test_output () {
 
 test_expect_success \
     'ls-tree plain' \
-    'git-ls-tree $tree >current &&
+    'git ls-tree $tree >current &&
      cat >expected <<\EOF &&
 100644 blob X  1.txt
 100644 blob X  2.txt
@@ -62,7 +62,7 @@ EOF
 # Recursive does not show tree nodes anymore...
 test_expect_success \
     'ls-tree recursive' \
-    'git-ls-tree -r $tree >current &&
+    'git ls-tree -r $tree >current &&
      cat >expected <<\EOF &&
 100644 blob X  1.txt
 100644 blob X  2.txt
@@ -76,7 +76,7 @@ EOF
 
 test_expect_success \
     'ls-tree filter 1.txt' \
-    'git-ls-tree $tree 1.txt >current &&
+    'git ls-tree $tree 1.txt >current &&
      cat >expected <<\EOF &&
 100644 blob X  1.txt
 EOF
@@ -84,7 +84,7 @@ EOF
 
 test_expect_success \
     'ls-tree filter path1/b/c/1.txt' \
-    'git-ls-tree $tree path1/b/c/1.txt >current &&
+    'git ls-tree $tree path1/b/c/1.txt >current &&
      cat >expected <<\EOF &&
 100644 blob X  path1/b/c/1.txt
 EOF
@@ -92,7 +92,7 @@ EOF
 
 test_expect_success \
     'ls-tree filter all 1.txt files' \
-    'git-ls-tree $tree 1.txt path0/a/b/c/1.txt path1/b/c/1.txt path2/1.txt path3/1.txt >current &&
+    'git ls-tree $tree 1.txt path0/a/b/c/1.txt path1/b/c/1.txt path2/1.txt path3/1.txt >current &&
      cat >expected <<\EOF &&
 100644 blob X  1.txt
 100644 blob X  path0/a/b/c/1.txt
@@ -107,7 +107,7 @@ EOF
 # it behaves as if path0/a/b/c, path1/b/c, path2 and path3 are specified.
 test_expect_success \
     'ls-tree filter directories' \
-    'git-ls-tree $tree path3 path2 path0/a/b/c path1/b/c path0/a >current &&
+    'git ls-tree $tree path3 path2 path0/a/b/c path1/b/c path0/a >current &&
      cat >expected <<\EOF &&
 040000 tree X  path0/a/b/c
 040000 tree X  path1/b/c
@@ -120,7 +120,7 @@ EOF
 # having 1.txt and path3
 test_expect_success \
     'ls-tree filter odd names' \
-    'git-ls-tree $tree 1.txt /1.txt //1.txt path3/1.txt /path3/1.txt //path3//1.txt path3 /path3/ path3// >current &&
+    'git ls-tree $tree 1.txt /1.txt //1.txt path3/1.txt /path3/1.txt //path3//1.txt path3 /path3/ path3// >current &&
      cat >expected <<\EOF &&
 100644 blob X  1.txt
 100644 blob X  path3/1.txt
@@ -130,7 +130,7 @@ EOF
 
 test_expect_success \
     'ls-tree filter missing files and extra slashes' \
-    'git-ls-tree $tree 1.txt/ abc.txt path3//23.txt path3/2.txt/// >current &&
+    'git ls-tree $tree 1.txt/ abc.txt path3//23.txt path3/2.txt/// >current &&
      cat >expected <<\EOF &&
 EOF
      test_output'
index 6f6d8844e8628d006b1d4c11eb02a5ee14a8fd35..a19e961cb3f45b2b1b385d5b9b4f455176ed6d9f 100755 (executable)
@@ -13,22 +13,22 @@ handled.  Specifically, that a bogus branch is not created.
 test_expect_success \
     'prepare a trivial repository' \
     'echo Hello > A &&
-     git-update-index --add A &&
+     git update-index --add A &&
      git-commit -m "Initial commit." &&
-     HEAD=$(git-rev-parse --verify HEAD)'
+     HEAD=$(git rev-parse --verify HEAD)'
 
 test_expect_failure \
     'git branch --help should not have created a bogus branch' \
-    'git-branch --help </dev/null >/dev/null 2>/dev/null || :
+    'git branch --help </dev/null >/dev/null 2>/dev/null || :
      test -f .git/refs/heads/--help'
 
 test_expect_success \
     'git branch abc should create a branch' \
-    'git-branch abc && test -f .git/refs/heads/abc'
+    'git branch abc && test -f .git/refs/heads/abc'
 
 test_expect_success \
     'git branch a/b/c should create a branch' \
-    'git-branch a/b/c && test -f .git/refs/heads/a/b/c'
+    'git branch a/b/c && test -f .git/refs/heads/a/b/c'
 
 cat >expect <<EOF
 0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000     branch: Created from master
@@ -36,140 +36,158 @@ EOF
 test_expect_success \
     'git branch -l d/e/f should create a branch and a log' \
        'GIT_COMMITTER_DATE="2005-05-26 23:30" \
-     git-branch -l d/e/f &&
+     git branch -l d/e/f &&
         test -f .git/refs/heads/d/e/f &&
         test -f .git/logs/refs/heads/d/e/f &&
         diff expect .git/logs/refs/heads/d/e/f'
 
 test_expect_success \
     'git branch -d d/e/f should delete a branch and a log' \
-       'git-branch -d d/e/f &&
+       'git branch -d d/e/f &&
         test ! -f .git/refs/heads/d/e/f &&
         test ! -f .git/logs/refs/heads/d/e/f'
 
 test_expect_success \
     'git branch j/k should work after branch j has been deleted' \
-       'git-branch j &&
-        git-branch -d j &&
-        git-branch j/k'
+       'git branch j &&
+        git branch -d j &&
+        git branch j/k'
 
 test_expect_success \
     'git branch l should work after branch l/m has been deleted' \
-       'git-branch l/m &&
-        git-branch -d l/m &&
-        git-branch l'
+       'git branch l/m &&
+        git branch -d l/m &&
+        git branch l'
 
 test_expect_success \
     'git branch -m m m/m should work' \
-       'git-branch -l m &&
-        git-branch -m m m/m &&
+       'git branch -l m &&
+        git branch -m m m/m &&
         test -f .git/logs/refs/heads/m/m'
 
 test_expect_success \
     'git branch -m n/n n should work' \
-       'git-branch -l n/n &&
-        git-branch -m n/n n
+       'git branch -l n/n &&
+        git branch -m n/n n
         test -f .git/logs/refs/heads/n'
 
 test_expect_failure \
     'git branch -m o/o o should fail when o/p exists' \
-       'git-branch o/o &&
-        git-branch o/p &&
-        git-branch -m o/o o'
+       'git branch o/o &&
+        git branch o/p &&
+        git branch -m o/o o'
 
 test_expect_failure \
     'git branch -m q r/q should fail when r exists' \
-       'git-branch q &&
-         git-branch r &&
-         git-branch -m q r/q'
+       'git branch q &&
+         git branch r &&
+         git branch -m q r/q'
 
 mv .git/config .git/config-saved
 
 test_expect_success 'git branch -m q q2 without config should succeed' '
-       git-branch -m q q2 &&
-       git-branch -m q2 q
+       git branch -m q q2 &&
+       git branch -m q2 q
 '
 
 mv .git/config-saved .git/config
 
-git-config branch.s/s.dummy Hello
+git config branch.s/s.dummy Hello
 
 test_expect_success \
     'git branch -m s/s s should work when s/t is deleted' \
-       'git-branch -l s/s &&
+       'git branch -l s/s &&
         test -f .git/logs/refs/heads/s/s &&
-        git-branch -l s/t &&
+        git branch -l s/t &&
         test -f .git/logs/refs/heads/s/t &&
-        git-branch -d s/t &&
-        git-branch -m s/s s &&
+        git branch -d s/t &&
+        git branch -m s/s s &&
         test -f .git/logs/refs/heads/s'
 
 test_expect_success 'config information was renamed, too' \
-       "test $(git-config branch.s.dummy) = Hello &&
-        ! git-config branch.s/s/dummy"
+       "test $(git config branch.s.dummy) = Hello &&
+        ! git config branch.s/s/dummy"
 
 test_expect_failure \
-    'git-branch -m u v should fail when the reflog for u is a symlink' \
-    'git-branch -l u &&
+    'git branch -m u v should fail when the reflog for u is a symlink' \
+    'git branch -l u &&
      mv .git/logs/refs/heads/u real-u &&
      ln -s real-u .git/logs/refs/heads/u &&
-     git-branch -m u v'
+     git branch -m u v'
 
 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-branch --track my1 local/master &&
-     test $(git-config branch.my1.remote) = local &&
-     test $(git-config branch.my1.merge) = refs/heads/master'
+    '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 branch --track my1 local/master &&
+     test $(git config branch.my1.remote) = local &&
+     test $(git config branch.my1.merge) = refs/heads/master'
 
 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-branch --track my4 local/master &&
-     test $(git-config branch.my4.remote) = local &&
-     test $(git-config branch.my4.merge) = refs/heads/master'
+    '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 branch --track my4 local/master &&
+     test $(git config branch.my4.remote) = local &&
+     test $(git config branch.my4.merge) = refs/heads/master'
 
 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-branch --track my5 local/master &&
-     ! test "$(git-config branch.my5.remote)" = local &&
-     ! test "$(git-config branch.my5.merge)" = refs/heads/master'
+    '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 branch --track my5 local/master &&
+     ! test "$(git config branch.my5.remote)" = local &&
+     ! test "$(git config branch.my5.merge)" = refs/heads/master'
 
 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-branch my3 local/master &&
-     test $(git-config branch.my3.remote) = local &&
-     test $(git-config branch.my3.merge) = refs/heads/master'
+    '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 branch my3 local/master &&
+     test $(git config branch.my3.remote) = local &&
+     test $(git config branch.my3.merge) = refs/heads/master'
+
+test_expect_success 'autosetupmerge = all' '
+       git config branch.autosetupmerge true &&
+       git branch all1 master &&
+       test -z "$(git config branch.all1.merge)" &&
+       git config branch.autosetupmerge all &&
+       git branch all2 master &&
+       test $(git config branch.all2.merge) = refs/heads/master
+'
 
 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-branch --no-track my2 local/master &&
-     git-config branch.autosetupmerge false &&
-     ! test "$(git-config branch.my2.remote)" = local &&
-     ! test "$(git-config branch.my2.merge)" = refs/heads/master'
+    '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 branch --no-track my2 local/master &&
+     git config branch.autosetupmerge false &&
+     ! test "$(git config branch.my2.remote)" = local &&
+     ! test "$(git config branch.my2.merge)" = refs/heads/master'
 
 test_expect_success 'test local tracking setup' \
     'git branch --track my6 s &&
-     test $(git-config branch.my6.remote) = . &&
-     test $(git-config branch.my6.merge) = refs/heads/s'
+     test $(git config branch.my6.remote) = . &&
+     test $(git config branch.my6.merge) = refs/heads/s'
 
 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-branch --track my7 local/o/o &&
-     test "$(git-config branch.my7.remote)" = local &&
-     test "$(git-config branch.my7.merge)" = refs/heads/o/o'
+    '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 branch --track my7 local/o/o &&
+     test "$(git config branch.my7.remote)" = local &&
+     test "$(git config branch.my7.merge)" = refs/heads/o/o'
+
+test_expect_success 'test deleting branch deletes branch config' \
+    'git branch -d my7 &&
+     test "$(git config branch.my7.remote)" = "" &&
+     test "$(git config branch.my7.merge)" = ""'
+
+test_expect_success 'test deleting branch without config' \
+    'git branch my7 s &&
+     test "$(git branch -d my7 2>&1)" = "Deleted branch my7."'
 
 # Keep this test last, as it changes the current branch
 cat >expect <<EOF
index f0c7e22b36c66234e2a46bac659506afb454dfa7..4ddc6342a94b9e7b39153cf5ac93ae3c3fb3c31e 100755 (executable)
@@ -16,92 +16,92 @@ echo '[core] logallrefupdates = true' >>.git/config
 test_expect_success \
     'prepare a trivial repository' \
     'echo Hello > A &&
-     git-update-index --add A &&
+     git update-index --add A &&
      git-commit -m "Initial commit." &&
-     HEAD=$(git-rev-parse --verify HEAD)'
+     HEAD=$(git rev-parse --verify HEAD)'
 
 SHA1=
 
 test_expect_success \
     'see if git show-ref works as expected' \
-    'git-branch a &&
+    'git branch a &&
      SHA1=`cat .git/refs/heads/a` &&
      echo "$SHA1 refs/heads/a" >expect &&
-     git-show-ref a >result &&
+     git show-ref a >result &&
      diff expect result'
 
 test_expect_success \
     'see if a branch still exists when packed' \
-    'git-branch b &&
-     git-pack-refs --all &&
+    'git branch b &&
+     git pack-refs --all &&
      rm -f .git/refs/heads/b &&
      echo "$SHA1 refs/heads/b" >expect &&
-     git-show-ref b >result &&
+     git show-ref b >result &&
      diff expect result'
 
 test_expect_failure \
     'git branch c/d should barf if branch c exists' \
-    'git-branch c &&
-     git-pack-refs --all &&
+    'git branch c &&
+     git pack-refs --all &&
      rm .git/refs/heads/c &&
-     git-branch c/d'
+     git branch c/d'
 
 test_expect_success \
     'see if a branch still exists after git pack-refs --prune' \
-    'git-branch e &&
-     git-pack-refs --all --prune &&
+    'git branch e &&
+     git pack-refs --all --prune &&
      echo "$SHA1 refs/heads/e" >expect &&
-     git-show-ref e >result &&
+     git show-ref e >result &&
      diff expect result'
 
 test_expect_failure \
     'see if git pack-refs --prune remove ref files' \
-    'git-branch f &&
-     git-pack-refs --all --prune &&
+    'git branch f &&
+     git pack-refs --all --prune &&
      ls .git/refs/heads/f'
 
 test_expect_success \
     'git branch g should work when git branch g/h has been deleted' \
-    'git-branch g/h &&
-     git-pack-refs --all --prune &&
-     git-branch -d g/h &&
-     git-branch g &&
-     git-pack-refs --all &&
-     git-branch -d g'
+    'git branch g/h &&
+     git pack-refs --all --prune &&
+     git branch -d g/h &&
+     git branch g &&
+     git pack-refs --all &&
+     git branch -d g'
 
 test_expect_failure \
     'git branch i/j/k should barf if branch i exists' \
-    'git-branch i &&
-     git-pack-refs --all --prune &&
-     git-branch i/j/k'
+    'git branch i &&
+     git pack-refs --all --prune &&
+     git branch i/j/k'
 
 test_expect_success \
     'test git branch k after branch k/l/m and k/lm have been deleted' \
-    'git-branch k/l &&
-     git-branch k/lm &&
-     git-branch -d k/l &&
-     git-branch k/l/m &&
-     git-branch -d k/l/m &&
-     git-branch -d k/lm &&
-     git-branch k'
+    'git branch k/l &&
+     git branch k/lm &&
+     git branch -d k/l &&
+     git branch k/l/m &&
+     git branch -d k/l/m &&
+     git branch -d k/lm &&
+     git branch k'
 
 test_expect_success \
     'test git branch n after some branch deletion and pruning' \
-    'git-branch n/o &&
-     git-branch n/op &&
-     git-branch -d n/o &&
-     git-branch n/o/p &&
-     git-branch -d n/op &&
-     git-pack-refs --all --prune &&
-     git-branch -d n/o/p &&
-     git-branch n'
+    'git branch n/o &&
+     git branch n/op &&
+     git branch -d n/o &&
+     git branch n/o/p &&
+     git branch -d n/op &&
+     git pack-refs --all --prune &&
+     git branch -d n/o/p &&
+     git branch n'
 
 test_expect_success 'pack, prune and repack' '
        git-tag foo &&
-       git-pack-refs --all --prune &&
-       git-show-ref >all-of-them &&
-       git-pack-refs &&
-       git-show-ref >again &&
+       git pack-refs --all --prune &&
+       git show-ref >all-of-them &&
+       git pack-refs &&
+       git show-ref >again &&
        diff all-of-them again
 '
 
index b5a1400e18b0fa5190fde4d0b60d1563581b2a19..dc8c36931098b85d802284d33dfc8f8ebaa5e6f5 100755 (executable)
@@ -32,12 +32,12 @@ test -f "$p1" && cmp "$p0" "$p1" || {
 
 echo 'just space
 no-funny' >expected
-test_expect_success 'git-ls-files no-funny' \
-       'git-update-index --add "$p0" "$p2" &&
-       git-ls-files >current &&
+test_expect_success 'git ls-files no-funny' \
+       'git update-index --add "$p0" "$p2" &&
+       git ls-files >current &&
        git diff expected current'
 
-t0=`git-write-tree`
+t0=`git write-tree`
 echo "$t0" >t0
 
 cat > expected <<\EOF
@@ -45,19 +45,19 @@ just space
 no-funny
 "tabs\t,\" (dq) and spaces"
 EOF
-test_expect_success 'git-ls-files with-funny' \
-       'git-update-index --add "$p1" &&
-       git-ls-files >current &&
+test_expect_success 'git ls-files with-funny' \
+       'git update-index --add "$p1" &&
+       git ls-files >current &&
        git diff expected current'
 
 echo 'just space
 no-funny
 tabs   ," (dq) and spaces' >expected
-test_expect_success 'git-ls-files -z with-funny' \
-       'git-ls-files -z | tr \\0 \\012 >current &&
+test_expect_success 'git ls-files -z with-funny' \
+       'git ls-files -z | tr \\0 \\012 >current &&
        git diff expected current'
 
-t1=`git-write-tree`
+t1=`git write-tree`
 echo "$t1" >t1
 
 cat > expected <<\EOF
@@ -65,45 +65,45 @@ just space
 no-funny
 "tabs\t,\" (dq) and spaces"
 EOF
-test_expect_success 'git-ls-tree with funny' \
-       'git-ls-tree -r $t1 | sed -e "s/^[^     ]*      //" >current &&
+test_expect_success 'git ls-tree with funny' \
+       'git ls-tree -r $t1 | sed -e "s/^[^     ]*      //" >current &&
         git diff expected current'
 
 cat > expected <<\EOF
 A      "tabs\t,\" (dq) and spaces"
 EOF
-test_expect_success 'git-diff-index with-funny' \
-       'git-diff-index --name-status $t0 >current &&
+test_expect_success 'git diff-index with-funny' \
+       'git diff-index --name-status $t0 >current &&
        git diff expected current'
 
-test_expect_success 'git-diff-tree with-funny' \
-       'git-diff-tree --name-status $t0 $t1 >current &&
+test_expect_success 'git diff-tree with-funny' \
+       'git diff-tree --name-status $t0 $t1 >current &&
        git diff expected current'
 
 echo 'A
 tabs   ," (dq) and spaces' >expected
-test_expect_success 'git-diff-index -z with-funny' \
-       'git-diff-index -z --name-status $t0 | tr \\0 \\012 >current &&
+test_expect_success 'git diff-index -z with-funny' \
+       'git diff-index -z --name-status $t0 | tr \\0 \\012 >current &&
        git diff expected current'
 
-test_expect_success 'git-diff-tree -z with-funny' \
-       'git-diff-tree -z --name-status $t0 $t1 | tr \\0 \\012 >current &&
+test_expect_success 'git diff-tree -z with-funny' \
+       'git diff-tree -z --name-status $t0 $t1 | tr \\0 \\012 >current &&
        git diff expected current'
 
 cat > expected <<\EOF
 CNUM   no-funny        "tabs\t,\" (dq) and spaces"
 EOF
-test_expect_success 'git-diff-tree -C with-funny' \
-       'git-diff-tree -C --find-copies-harder --name-status \
+test_expect_success 'git diff-tree -C with-funny' \
+       'git diff-tree -C --find-copies-harder --name-status \
                $t0 $t1 | sed -e 's/^C[0-9]*/CNUM/' >current &&
        git diff expected current'
 
 cat > expected <<\EOF
 RNUM   no-funny        "tabs\t,\" (dq) and spaces"
 EOF
-test_expect_success 'git-diff-tree delete with-funny' \
-       'git-update-index --force-remove "$p0" &&
-       git-diff-index -M --name-status \
+test_expect_success 'git diff-tree delete with-funny' \
+       'git update-index --force-remove "$p0" &&
+       git diff-index -M --name-status \
                $t0 | sed -e 's/^R[0-9]*/RNUM/' >current &&
        git diff expected current'
 
@@ -113,8 +113,8 @@ similarity index NUM%
 rename from no-funny
 rename to "tabs\t,\" (dq) and spaces"
 EOF
-test_expect_success 'git-diff-tree delete with-funny' \
-       'git-diff-index -M -p $t0 |
+test_expect_success 'git diff-tree delete with-funny' \
+       'git diff-index -M -p $t0 |
         sed -e "s/index [0-9]*%/index NUM%/" >current &&
         git diff expected current'
 
@@ -127,8 +127,8 @@ similarity index NUM%
 rename from no-funny
 rename to "tabs\t,\" (dq) and spaces"
 EOF
-test_expect_success 'git-diff-tree delete with-funny' \
-       'git-diff-index -M -p $t0 |
+test_expect_success 'git diff-tree delete with-funny' \
+       'git diff-index -M -p $t0 |
         sed -e "s/index [0-9]*%/index NUM%/" >current &&
         git diff expected current'
 
@@ -136,9 +136,9 @@ cat >expected <<\EOF
  "tabs\t,\" (dq) and spaces"
  1 files changed, 0 insertions(+), 0 deletions(-)
 EOF
-test_expect_success 'git-diff-tree rename with-funny applied' \
-       'git-diff-index -M -p $t0 |
-        git-apply --stat | sed -e "s/|.*//" -e "s/ *\$//" >current &&
+test_expect_success 'git diff-tree rename with-funny applied' \
+       'git diff-index -M -p $t0 |
+        git apply --stat | sed -e "s/|.*//" -e "s/ *\$//" >current &&
         git diff expected current'
 
 cat > expected <<\EOF
@@ -146,15 +146,15 @@ cat > expected <<\EOF
  "tabs\t,\" (dq) and spaces"
  2 files changed, 3 insertions(+), 3 deletions(-)
 EOF
-test_expect_success 'git-diff-tree delete with-funny applied' \
-       'git-diff-index -p $t0 |
-        git-apply --stat | sed -e "s/|.*//" -e "s/ *\$//" >current &&
+test_expect_success 'git diff-tree delete with-funny applied' \
+       'git diff-index -p $t0 |
+        git apply --stat | sed -e "s/|.*//" -e "s/ *\$//" >current &&
         git diff expected current'
 
-test_expect_success 'git-apply non-git diff' \
-       'git-diff-index -p $t0 |
+test_expect_success 'git apply non-git diff' \
+       'git diff-index -p $t0 |
         sed -ne "/^[-+@]/p" |
-        git-apply --stat | sed -e "s/|.*//" -e "s/ *\$//" >current &&
+        git apply --stat | sed -e "s/|.*//" -e "s/ *\$//" >current &&
         git diff expected current'
 
 test_done
index b9d3131cc2167df027d4d6eebc87ad51223c8f34..62205b25312812f3197b38a655d92da4fa7c0a91 100755 (executable)
@@ -12,23 +12,60 @@ This test runs git rebase and checks that the author information is not lost.
 export GIT_AUTHOR_EMAIL=bogus_email_address
 
 test_expect_success \
-    'prepare repository with topic branch, then rebase against master' \
+    'prepare repository with topic branches' \
     'echo First > A &&
-     git-update-index --add A &&
+     git update-index --add A &&
      git-commit -m "Add A." &&
      git checkout -b my-topic-branch &&
      echo Second > B &&
-     git-update-index --add B &&
+     git update-index --add B &&
      git-commit -m "Add B." &&
      git checkout -f master &&
      echo Third >> A &&
-     git-update-index A &&
+     git update-index A &&
      git-commit -m "Modify A." &&
+     git checkout -b side my-topic-branch &&
+     echo Side >> C &&
+     git add C &&
+     git commit -m "Add C" &&
+     git checkout -b nonlinear my-topic-branch &&
+     echo Edit >> B &&
+     git add B &&
+     git commit -m "Modify B" &&
+     git merge side &&
+     git checkout -b upstream-merged-nonlinear &&
+     git merge master &&
      git checkout -f my-topic-branch &&
+     git tag topic
+'
+
+test_expect_success 'rebase against master' '
      git rebase master'
 
 test_expect_failure \
     'the rebase operation should not have destroyed author information' \
     'git log | grep "Author:" | grep "<>"'
 
+test_expect_success 'rebase after merge master' '
+     git reset --hard topic &&
+     git merge master &&
+     git rebase master &&
+     ! git show | grep "^Merge:"
+'
+
+test_expect_success 'rebase of history with merges is linearized' '
+     git checkout nonlinear &&
+     test 4 = $(git rev-list master.. | wc -l) &&
+     git rebase master &&
+     test 3 = $(git rev-list master.. | wc -l)
+'
+
+test_expect_success \
+    'rebase of history with merges after upstream merge is linearized' '
+     git checkout upstream-merged-nonlinear &&
+     test 5 = $(git rev-list master.. | wc -l) &&
+     git rebase master &&
+     test 3 = $(git rev-list master.. | wc -l)
+'
+
 test_done
index 8b19d3ccea5a0d5ff697661202347fbdfc6c330a..4934a4e01092e27e07254b10ed3e54e8699b54ac 100755 (executable)
@@ -14,37 +14,37 @@ local branch.
 test_expect_success \
     'prepare repository with topic branch' \
     'echo First > A &&
-     git-update-index --add A &&
+     git update-index --add A &&
      git-commit -m "Add A." &&
 
      git-checkout -b my-topic-branch &&
 
      echo Second > B &&
-     git-update-index --add B &&
+     git update-index --add B &&
      git-commit -m "Add B." &&
 
      echo AnotherSecond > C &&
-     git-update-index --add C &&
+     git update-index --add C &&
      git-commit -m "Add C." &&
 
      git-checkout -f master &&
 
      echo Third >> A &&
-     git-update-index A &&
+     git update-index 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 cherry-pick my-topic-branch^0 &&
      git-checkout -f my-topic-branch &&
-     git-branch master-merge master &&
-     git-branch my-topic-branch-merge my-topic-branch
+     git branch master-merge master &&
+     git branch my-topic-branch-merge my-topic-branch
 '
 
 test_debug \
-    'git-cherry master &&
-     git-format-patch -k --stdout --full-index master >/dev/null &&
+    'git cherry master &&
+     git format-patch -k --stdout --full-index master >/dev/null &&
      gitk --all & sleep 1
 '
 
index 977c498f00f2d8e2066bd586130ee84fe1a196a3..eab053c3e0e1cbe82bc7824d43109ba56acdb54d 100755 (executable)
@@ -49,9 +49,8 @@ test_expect_success 'rebase --skip with --merge' '
        '
 
 test_expect_success 'merge and reference trees equal' \
-       'test -z "`git-diff-tree skip-merge skip-reference`"'
+       'test -z "`git diff-tree skip-merge skip-reference`"'
 
 test_debug 'gitk --all & sleep 1'
 
 test_done
-
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
new file mode 100755 (executable)
index 0000000..43a6675
--- /dev/null
@@ -0,0 +1,215 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Johannes E. Schindelin
+#
+
+test_description='git rebase interactive
+
+This test runs git rebase "interactively", by faking an edit, and verifies
+that the result still makes sense.
+'
+. ./test-lib.sh
+
+# set up two branches like this:
+#
+# A - B - C - D - E
+#   \
+#     F - G - H
+#       \
+#         I
+#
+# where B, D and G touch the same file.
+
+test_expect_success 'setup' '
+       : > file1 &&
+       git add file1 &&
+       test_tick &&
+       git commit -m A &&
+       git tag A &&
+       echo 1 > file1 &&
+       test_tick &&
+       git commit -m B file1 &&
+       : > file2 &&
+       git add file2 &&
+       test_tick &&
+       git commit -m C &&
+       echo 2 > file1 &&
+       test_tick &&
+       git commit -m D file1 &&
+       : > file3 &&
+       git add file3 &&
+       test_tick &&
+       git commit -m E &&
+       git checkout -b branch1 A &&
+       : > file4 &&
+       git add file4 &&
+       test_tick &&
+       git commit -m F &&
+       git tag F &&
+       echo 3 > file1 &&
+       test_tick &&
+       git commit -m G file1 &&
+       : > file5 &&
+       git add file5 &&
+       test_tick &&
+       git commit -m H &&
+       git checkout -b branch2 F &&
+       : > file6 &&
+       git add file6 &&
+       test_tick &&
+       git commit -m I &&
+       git tag I
+'
+
+cat > fake-editor.sh << EOF
+#!/bin/sh
+test "\$1" = .git/COMMIT_EDITMSG && {
+       test -z "\$FAKE_COMMIT_MESSAGE" || echo "\$FAKE_COMMIT_MESSAGE" > "\$1"
+       exit
+}
+test -z "\$FAKE_LINES" && exit
+grep -v "^#" < "\$1" > "\$1".tmp
+rm "\$1"
+cat "\$1".tmp
+action=pick
+for line in \$FAKE_LINES; do
+       case \$line in
+       squash)
+               action="\$line";;
+       *)
+               echo sed -n "\${line}s/^pick/\$action/p"
+               sed -n "\${line}p" < "\$1".tmp
+               sed -n "\${line}s/^pick/\$action/p" < "\$1".tmp >> "\$1"
+               action=pick;;
+       esac
+done
+EOF
+
+chmod a+x fake-editor.sh
+VISUAL="$(pwd)/fake-editor.sh"
+export VISUAL
+
+test_expect_success 'no changes are a nop' '
+       git rebase -i F &&
+       test $(git rev-parse I) = $(git rev-parse HEAD)
+'
+
+test_expect_success 'rebase on top of a non-conflicting commit' '
+       git checkout branch1 &&
+       git tag original-branch1 &&
+       git rebase -i branch2 &&
+       test file6 = $(git diff --name-only original-branch1) &&
+       test $(git rev-parse I) = $(git rev-parse HEAD~2)
+'
+
+test_expect_success 'reflog for the branch shows state before rebase' '
+       test $(git rev-parse branch1@{1}) = $(git rev-parse original-branch1)
+'
+
+test_expect_success 'exchange two commits' '
+       FAKE_LINES="2 1" git rebase -i HEAD~2 &&
+       test H = $(git cat-file commit HEAD^ | tail -n 1) &&
+       test G = $(git cat-file commit HEAD | tail -n 1)
+'
+
+cat > expect << EOF
+diff --git a/file1 b/file1
+index e69de29..00750ed 100644
+--- a/file1
++++ b/file1
+@@ -0,0 +1 @@
++3
+EOF
+
+cat > expect2 << EOF
+<<<<<<< HEAD:file1
+2
+=======
+3
+>>>>>>> b7ca976... G:file1
+EOF
+
+test_expect_success 'stop on conflicting pick' '
+       git tag new-branch1 &&
+       ! git rebase -i master &&
+       diff -u expect .git/.dotest-merge/patch &&
+       diff -u expect2 file1 &&
+       test 4 = $(grep -v "^#" < .git/.dotest-merge/done | wc -l) &&
+       test 0 = $(grep -v "^#" < .git/.dotest-merge/todo | wc -l)
+'
+
+test_expect_success 'abort' '
+       git rebase --abort &&
+       test $(git rev-parse new-branch1) = $(git rev-parse HEAD) &&
+       ! test -d .git/.dotest-merge
+'
+
+test_expect_success 'retain authorship' '
+       echo A > file7 &&
+       git add file7 &&
+       test_tick &&
+       GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" &&
+       git tag twerp &&
+       git rebase -i --onto master HEAD^ &&
+       git show HEAD | grep "^Author: Twerp Snog"
+'
+
+test_expect_success 'squash' '
+       git reset --hard twerp &&
+       echo B > file7 &&
+       test_tick &&
+       GIT_AUTHOR_NAME="Nitfol" git commit -m "nitfol" file7 &&
+       echo "******************************" &&
+       FAKE_LINES="1 squash 2" git rebase -i --onto master HEAD~2 &&
+       test B = $(cat file7) &&
+       test $(git rev-parse HEAD^) = $(git rev-parse master)
+'
+
+test_expect_success 'retain authorship when squashing' '
+       git show HEAD | grep "^Author: Nitfol"
+'
+
+test_expect_success 'preserve merges with -p' '
+       git checkout -b to-be-preserved master^ &&
+       : > unrelated-file &&
+       git add unrelated-file &&
+       test_tick &&
+       git commit -m "unrelated" &&
+       git checkout -b to-be-rebased master &&
+       echo B > file1 &&
+       test_tick &&
+       git commit -m J file1 &&
+       test_tick &&
+       git merge to-be-preserved &&
+       echo C > file1 &&
+       test_tick &&
+       git commit -m K file1 &&
+       test_tick &&
+       git rebase -i -p --onto branch1 master &&
+       test $(git rev-parse HEAD^^2) = $(git rev-parse to-be-preserved) &&
+       test $(git rev-parse HEAD~3) = $(git rev-parse branch1) &&
+       test $(git show HEAD:file1) = C &&
+       test $(git show HEAD~2:file1) = B
+'
+
+test_expect_success '--continue tries to commit' '
+       test_tick &&
+       ! git rebase -i --onto new-branch1 HEAD^ &&
+       echo resolved > file1 &&
+       git add file1 &&
+       FAKE_COMMIT_MESSAGE="chouette!" git rebase --continue &&
+       test $(git rev-parse HEAD^) = $(git rev-parse new-branch1) &&
+       git show HEAD | grep chouette
+'
+
+test_expect_success 'verbose flag is heeded, even after --continue' '
+       git reset --hard HEAD@{1} &&
+       test_tick &&
+       ! git rebase -v -i --onto new-branch1 HEAD^ &&
+       echo resolved > file1 &&
+       git add file1 &&
+       git rebase --continue > output &&
+       grep "^ file1 |    2 +-$" output
+'
+
+test_done
index e83bbee07402d864a7241d4edbf5d393dcccdd4a..d0a440feba5f501a2320d52b36d1bb51ca8944dd 100755 (executable)
@@ -3,10 +3,10 @@
 # Copyright (c) 2006 Yann Dirson, based on t3400 by Amos Waterland
 #
 
-test_description='git-cherry should detect patches integrated upstream
+test_description='git cherry should detect patches integrated upstream
 
 This test cherry-picks one local change of two into master branch, and
-checks that git-cherry only returns the second patch in the local branch
+checks that git cherry only returns the second patch in the local branch
 '
 . ./test-lib.sh
 
@@ -15,40 +15,40 @@ export GIT_AUTHOR_EMAIL=bogus_email_address
 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 update-index --add A &&
      git-commit -m "Add A." &&
 
      git-checkout -b my-topic-branch &&
 
      echo Second > B &&
-     git-update-index --add B &&
+     git update-index --add B &&
      git-commit -m "Add B." &&
 
      sleep 2 &&
      echo AnotherSecond > C &&
-     git-update-index --add C &&
+     git update-index --add C &&
      git-commit -m "Add C." &&
 
      git-checkout -f master &&
      rm -f B C &&
 
      echo Third >> A &&
-     git-update-index A &&
+     git update-index A &&
      git-commit -m "Modify A." &&
 
-     expr "$(echo $(git-cherry master my-topic-branch) )" : "+ [^ ]* + .*"
+     expr "$(echo $(git cherry master my-topic-branch) )" : "+ [^ ]* + .*"
 '
 
 test_expect_success \
     'check that cherry with limit returns only the top patch'\
-    'expr "$(echo $(git-cherry master my-topic-branch my-topic-branch^1) )" : "+ [^ ]*"
+    'expr "$(echo $(git cherry master my-topic-branch my-topic-branch^1) )" : "+ [^ ]*"
 '
 
 test_expect_success \
     'cherry-pick one of the 2 patches, and check cherry recognized one and only one as new' \
-    'git-cherry-pick my-topic-branch^0 &&
-     echo $(git-cherry master my-topic-branch) &&
-     expr "$(echo $(git-cherry master my-topic-branch) )" : "+ [^ ]* - .*"
+    'git cherry-pick my-topic-branch^0 &&
+     echo $(git cherry master my-topic-branch) &&
+     expr "$(echo $(git cherry master my-topic-branch) )" : "+ [^ ]* - .*"
 '
 
 test_done
index 0a97b75288d44cf93e0a8f8d9ab1b76715f946d1..13a461f31b666e5f4abf9c4b607c8d974f0da825 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2006 Carl D. Worth
 #
 
-test_description='Test of the various options to git-rm.'
+test_description='Test of the various options to git rm.'
 
 . ./test-lib.sh
 
@@ -11,13 +11,13 @@ test_description='Test of the various options to git-rm.'
 test_expect_success \
     'Initialize test directory' \
     "touch -- foo bar baz 'space embedded' -q &&
-     git-add -- foo bar baz 'space embedded' -q &&
+     git add -- foo bar baz 'space embedded' -q &&
      git-commit -m 'add normal files' &&
      test_tabs=y &&
      if touch -- 'tab  embedded' 'newline
 embedded'
      then
-     git-add -- 'tab   embedded' 'newline
+     git add -- 'tab   embedded' 'newline
 embedded' &&
      git-commit -m 'add files with tabs and newlines'
      else
@@ -26,7 +26,7 @@ embedded' &&
      fi"
 
 # Later we will try removing an unremovable path to make sure
-# git-rm barfs, but if the test is run as root that cannot be
+# git rm barfs, but if the test is run as root that cannot be
 # arranged.
 test_expect_success \
     'Determine rm behavior' \
@@ -38,51 +38,51 @@ test_expect_success \
      rm -f test-file'
 
 test_expect_success \
-    'Pre-check that foo exists and is in index before git-rm foo' \
-    '[ -f foo ] && git-ls-files --error-unmatch foo'
+    'Pre-check that foo exists and is in index before git rm foo' \
+    '[ -f foo ] && git ls-files --error-unmatch foo'
 
 test_expect_success \
-    'Test that git-rm foo succeeds' \
-    'git-rm --cached foo'
+    'Test that git rm foo succeeds' \
+    'git rm --cached foo'
 
 test_expect_success \
-    'Post-check that foo exists but is not in index after git-rm foo' \
-    '[ -f foo ] && ! git-ls-files --error-unmatch foo'
+    'Post-check that foo exists but is not in index after git rm foo' \
+    '[ -f foo ] && ! git ls-files --error-unmatch foo'
 
 test_expect_success \
-    'Pre-check that bar exists and is in index before "git-rm bar"' \
-    '[ -f bar ] && git-ls-files --error-unmatch bar'
+    'Pre-check that bar exists and is in index before "git rm bar"' \
+    '[ -f bar ] && git ls-files --error-unmatch bar'
 
 test_expect_success \
-    'Test that "git-rm bar" succeeds' \
-    'git-rm bar'
+    'Test that "git rm bar" succeeds' \
+    'git rm bar'
 
 test_expect_success \
-    'Post-check that bar does not exist and is not in index after "git-rm -f bar"' \
-    '! [ -f bar ] && ! git-ls-files --error-unmatch bar'
+    'Post-check that bar does not exist and is not in index after "git rm -f bar"' \
+    '! [ -f bar ] && ! git ls-files --error-unmatch bar'
 
 test_expect_success \
-    'Test that "git-rm -- -q" succeeds (remove a file that looks like an option)' \
-    'git-rm -- -q'
+    'Test that "git rm -- -q" succeeds (remove a file that looks like an option)' \
+    'git rm -- -q'
 
 test "$test_tabs" = y && test_expect_success \
-    "Test that \"git-rm -f\" succeeds with embedded space, tab, or newline characters." \
-    "git-rm -f 'space embedded' 'tab   embedded' 'newline
+    "Test that \"git rm -f\" succeeds with embedded space, tab, or newline characters." \
+    "git rm -f 'space embedded' 'tab   embedded' 'newline
 embedded'"
 
 if test "$test_failed_remove" = y; then
 chmod a-w .
 test_expect_failure \
-    'Test that "git-rm -f" fails if its rm fails' \
-    'git-rm -f baz'
+    'Test that "git rm -f" fails if its rm fails' \
+    'git rm -f baz'
 chmod 775 .
 else
     test_expect_success 'skipping removal failure (perhaps running as root?)' :
 fi
 
 test_expect_success \
-    'When the rm in "git-rm -f" fails, it should not remove the file from the index' \
-    'git-ls-files --error-unmatch baz'
+    'When the rm in "git rm -f" fails, it should not remove the file from the index' \
+    'git ls-files --error-unmatch baz'
 
 test_expect_success 'Remove nonexistent file with --ignore-unmatch' '
        git rm --ignore-unmatch nonexistent
index ad8cc7d4ae88e2066d2f51b6a6a5a192780d5e9a..b52fde8577185adf962b70ad16efbcb7bfe46042 100755 (executable)
@@ -3,72 +3,72 @@
 # Copyright (c) 2006 Carl D. Worth
 #
 
-test_description='Test of git-add, including the -- option.'
+test_description='Test of git add, including the -- option.'
 
 . ./test-lib.sh
 
 test_expect_success \
-    'Test of git-add' \
-    'touch foo && git-add foo'
+    'Test of git add' \
+    'touch foo && git add foo'
 
 test_expect_success \
     'Post-check that foo is in the index' \
-    'git-ls-files foo | grep foo'
+    'git ls-files foo | grep foo'
 
 test_expect_success \
-    'Test that "git-add -- -q" works' \
-    'touch -- -q && git-add -- -q'
+    'Test that "git add -- -q" works' \
+    'touch -- -q && git add -- -q'
 
 test_expect_success \
-       'git-add: Test that executable bit is not used if core.filemode=0' \
+       'git add: Test that executable bit is not used if core.filemode=0' \
        'git config core.filemode 0 &&
         echo foo >xfoo1 &&
         chmod 755 xfoo1 &&
-        git-add xfoo1 &&
-        case "`git-ls-files --stage xfoo1`" in
+        git add xfoo1 &&
+        case "`git ls-files --stage xfoo1`" in
         100644" "*xfoo1) echo ok;;
-        *) echo fail; git-ls-files --stage xfoo1; (exit 1);;
+        *) echo fail; git ls-files --stage xfoo1; (exit 1);;
         esac'
 
-test_expect_success 'git-add: filemode=0 should not get confused by symlink' '
+test_expect_success 'git add: filemode=0 should not get confused by symlink' '
        rm -f xfoo1 &&
        ln -s foo xfoo1 &&
-       git-add xfoo1 &&
-       case "`git-ls-files --stage xfoo1`" in
+       git add xfoo1 &&
+       case "`git ls-files --stage xfoo1`" in
        120000" "*xfoo1) echo ok;;
-       *) echo fail; git-ls-files --stage xfoo1; (exit 1);;
+       *) echo fail; git ls-files --stage xfoo1; (exit 1);;
        esac
 '
 
 test_expect_success \
-       'git-update-index --add: Test that executable bit is not used...' \
+       'git update-index --add: Test that executable bit is not used...' \
        'git config core.filemode 0 &&
         echo foo >xfoo2 &&
         chmod 755 xfoo2 &&
-        git-update-index --add xfoo2 &&
-        case "`git-ls-files --stage xfoo2`" in
+        git update-index --add xfoo2 &&
+        case "`git ls-files --stage xfoo2`" in
         100644" "*xfoo2) echo ok;;
-        *) echo fail; git-ls-files --stage xfoo2; (exit 1);;
+        *) echo fail; git ls-files --stage xfoo2; (exit 1);;
         esac'
 
-test_expect_success 'git-add: filemode=0 should not get confused by symlink' '
+test_expect_success 'git add: filemode=0 should not get confused by symlink' '
        rm -f xfoo2 &&
        ln -s foo xfoo2 &&
        git update-index --add xfoo2 &&
-       case "`git-ls-files --stage xfoo2`" in
+       case "`git ls-files --stage xfoo2`" in
        120000" "*xfoo2) echo ok;;
-       *) echo fail; git-ls-files --stage xfoo2; (exit 1);;
+       *) echo fail; git ls-files --stage xfoo2; (exit 1);;
        esac
 '
 
 test_expect_success \
-       'git-update-index --add: Test that executable bit is not used...' \
+       'git update-index --add: Test that executable bit is not used...' \
        'git config core.filemode 0 &&
         ln -s xfoo2 xfoo3 &&
-        git-update-index --add xfoo3 &&
-        case "`git-ls-files --stage xfoo3`" in
+        git update-index --add xfoo3 &&
+        case "`git ls-files --stage xfoo3`" in
         120000" "*xfoo3) echo ok;;
-        *) echo fail; git-ls-files --stage xfoo3; (exit 1);;
+        *) echo fail; git ls-files --stage xfoo3; (exit 1);;
         esac'
 
 test_expect_success '.gitignore test setup' '
@@ -80,28 +80,28 @@ test_expect_success '.gitignore test setup' '
 '
 
 test_expect_success '.gitignore is honored' '
-       git-add . &&
-       ! git-ls-files | grep "\\.ig"
+       git add . &&
+       ! git ls-files | grep "\\.ig"
 '
 
 test_expect_success 'error out when attempting to add ignored ones without -f' '
-       ! git-add a.?? &&
-       ! git-ls-files | grep "\\.ig"
+       ! git add a.?? &&
+       ! git ls-files | grep "\\.ig"
 '
 
 test_expect_success 'error out when attempting to add ignored ones without -f' '
-       ! git-add d.?? &&
-       ! git-ls-files | grep "\\.ig"
+       ! git add d.?? &&
+       ! git ls-files | grep "\\.ig"
 '
 
 test_expect_success 'add ignored ones with -f' '
-       git-add -f a.?? &&
-       git-ls-files --error-unmatch a.ig
+       git add -f a.?? &&
+       git ls-files --error-unmatch a.ig
 '
 
 test_expect_success 'add ignored ones with -f' '
-       git-add -f d.??/* &&
-       git-ls-files --error-unmatch d.ig/d.if d.ig/d.ig
+       git add -f d.??/* &&
+       git ls-files --error-unmatch d.ig/d.if d.ig/d.ig
 '
 
 mkdir 1 1/2 1/3
@@ -110,4 +110,37 @@ test_expect_success 'check correct prefix detection' '
        git add 1/2/a 1/3/b 1/2/c
 '
 
+test_expect_success 'git add with filemode=0, symlinks=0, and unmerged entries' '
+       for s in 1 2 3
+       do
+               echo $s > stage$s
+               echo "100755 $(git hash-object -w stage$s) $s   file"
+               echo "120000 $(printf $s | git hash-object -w -t blob --stdin) $s       symlink"
+       done | git update-index --index-info &&
+       git config core.filemode 0 &&
+       git config core.symlinks 0 &&
+       echo new > file &&
+       echo new > symlink &&
+       git add file symlink &&
+       git ls-files --stage | grep "^100755 .* 0       file$" &&
+       git ls-files --stage | grep "^120000 .* 0       symlink$"
+'
+
+test_expect_success 'git add with filemode=0, symlinks=0 prefers stage 2 over stage 1' '
+       git rm --cached -f file symlink &&
+       (
+               echo "100644 $(git hash-object -w stage1) 1     file"
+               echo "100755 $(git hash-object -w stage2) 2     file"
+               echo "100644 $(printf $s | git hash-object -w -t blob --stdin) 1        symlink"
+               echo "120000 $(printf $s | git hash-object -w -t blob --stdin) 2        symlink"
+       ) | git update-index --index-info &&
+       git config core.filemode 0 &&
+       git config core.symlinks 0 &&
+       echo new > file &&
+       echo new > symlink &&
+       git add file symlink &&
+       git ls-files --stage | grep "^100755 .* 0       file$" &&
+       git ls-files --stage | grep "^120000 .* 0       symlink$"
+'
+
 test_done
index 7c7e4335d6e941a79d85c11502178b36331785a2..261f199a0cb32864bbb3cf103ddd2a63e62d2590 100755 (executable)
@@ -22,9 +22,9 @@ check_verify_failure () {
 # first create a commit, so we have a valid object/type
 # for the tag.
 echo Hello >A
-git-update-index --add A
+git update-index --add A
 git-commit -m "Initial commit"
-head=$(git-rev-parse --verify HEAD)
+head=$(git rev-parse --verify HEAD)
 
 ############################################################
 #  1. length check
index ffddb68db3abbf1ab14bf99f3c9514a7ee0c276b..fcbabe8ec32d61888e6cb28d393381066d1b0f3c 100755 (executable)
@@ -8,28 +8,28 @@ test_description='commit and log output encodings'
 . ./test-lib.sh
 
 compare_with () {
-       git-show -s $1 | sed -e '1,/^$/d' -e 's/^    //' -e '$d' >current &&
+       git show -s $1 | sed -e '1,/^$/d' -e 's/^    //' -e '$d' >current &&
        git diff current "$2"
 }
 
 test_expect_success setup '
        : >F &&
-       git-add F &&
-       T=$(git-write-tree) &&
-       C=$(git-commit-tree $T <../t3900/1-UTF-8.txt) &&
-       git-update-ref HEAD $C &&
+       git add F &&
+       T=$(git write-tree) &&
+       C=$(git commit-tree $T <../t3900/1-UTF-8.txt) &&
+       git update-ref HEAD $C &&
        git-tag C0
 '
 
 test_expect_success 'no encoding header for base case' '
-       E=$(git-cat-file commit C0 | sed -ne "s/^encoding //p") &&
+       E=$(git cat-file commit C0 | sed -ne "s/^encoding //p") &&
        test z = "z$E"
 '
 
 for H in ISO-8859-1 EUCJP ISO-2022-JP
 do
        test_expect_success "$H setup" '
-               git-config i18n.commitencoding $H &&
+               git config i18n.commitencoding $H &&
                git-checkout -b $H C0 &&
                echo $H >F &&
                git-commit -a -F ../t3900/$H.txt
@@ -39,21 +39,21 @@ done
 for H in ISO-8859-1 EUCJP ISO-2022-JP
 do
        test_expect_success "check encoding header for $H" '
-               E=$(git-cat-file commit '$H' | sed -ne "s/^encoding //p") &&
+               E=$(git cat-file commit '$H' | sed -ne "s/^encoding //p") &&
                test "z$E" = "z'$H'"
        '
 done
 
 test_expect_success 'config to remove customization' '
-       git-config --unset-all i18n.commitencoding &&
-       if Z=$(git-config --get-all i18n.commitencoding)
+       git config --unset-all i18n.commitencoding &&
+       if Z=$(git config --get-all i18n.commitencoding)
        then
                echo Oops, should have failed.
                false
        else
                test z = "z$Z"
        fi &&
-       git-config i18n.commitencoding utf-8
+       git config i18n.commitencoding utf-8
 '
 
 test_expect_success 'ISO-8859-1 should be shown in UTF-8 now' '
@@ -68,8 +68,8 @@ do
 done
 
 test_expect_success 'config to add customization' '
-       git-config --unset-all i18n.commitencoding &&
-       if Z=$(git-config --get-all i18n.commitencoding)
+       git config --unset-all i18n.commitencoding &&
+       if Z=$(git config --get-all i18n.commitencoding)
        then
                echo Oops, should have failed.
                false
@@ -81,13 +81,13 @@ test_expect_success 'config to add customization' '
 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' &&
+               git config i18n.commitencoding '$H' &&
                compare_with '$H' ../t3900/'$H'.txt
        '
 done
 
 test_expect_success 'config to tweak customization' '
-       git-config i18n.logoutputencoding utf-8
+       git config i18n.logoutputencoding utf-8
 '
 
 test_expect_success 'ISO-8859-1 should be shown in UTF-8 now' '
@@ -103,7 +103,7 @@ done
 
 for J in EUCJP ISO-2022-JP
 do
-       git-config i18n.logoutputencoding $J
+       git config i18n.logoutputencoding $J
        for H in EUCJP ISO-2022-JP
        do
                test_expect_success "$H should be shown in $J now" '
index 24bf0ee0184bab6f3703f17f280e413041d2a686..28e9e372f34818ab5427ef0178dc2003a8018656 100755 (executable)
@@ -14,7 +14,7 @@ check_encoding () {
        do
                git format-patch --encoding=UTF-8 --stdout HEAD~$i..HEAD~$j |
                grep "^From: =?UTF-8?q?=C3=81=C3=A9=C3=AD=20=C3=B3=C3=BA?=" &&
-               git-cat-file commit HEAD~$j |
+               git cat-file commit HEAD~$j |
                case "$header" in
                8859)
                        grep "^encoding ISO-8859-1" ;;
@@ -31,7 +31,7 @@ check_encoding () {
 }
 
 test_expect_success setup '
-       git-config i18n.commitencoding UTF-8 &&
+       git config i18n.commitencoding UTF-8 &&
 
        # use UTF-8 in author and committer name to match the
        # i18n.commitencoding settings
@@ -55,7 +55,7 @@ test_expect_success setup '
        git commit -s -m "Second on side" &&
 
        # the second one on the side branch is ISO-8859-1
-       git-config i18n.commitencoding 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_tick &&
@@ -64,11 +64,11 @@ test_expect_success setup '
        git commit -s -m "Third on side" &&
 
        # Back to default
-       git-config i18n.commitencoding UTF-8
+       git config i18n.commitencoding UTF-8
 '
 
 test_expect_success 'format-patch output (ISO-8859-1)' '
-       git-config i18n.logoutputencoding ISO-8859-1 &&
+       git config i18n.logoutputencoding ISO-8859-1 &&
 
        git format-patch --stdout master..HEAD^ >out-l1 &&
        git format-patch --stdout HEAD^ >out-l2 &&
@@ -91,7 +91,7 @@ test_expect_success 'format-patch output (UTF-8)' '
 
 test_expect_success 'rebase (U/U)' '
        # We want the result of rebase in UTF-8
-       git-config i18n.commitencoding UTF-8 &&
+       git config i18n.commitencoding UTF-8 &&
 
        # The test is about logoutputencoding not affecting the
        # final outcome -- it is used internally to generate the
@@ -109,7 +109,7 @@ test_expect_success 'rebase (U/U)' '
 '
 
 test_expect_success 'rebase (U/L)' '
-       git-config i18n.commitencoding UTF-8 &&
+       git config i18n.commitencoding UTF-8 &&
        git config i18n.logoutputencoding ISO-8859-1 &&
        . ../t3901-utf8.txt &&
 
@@ -121,7 +121,7 @@ test_expect_success 'rebase (U/L)' '
 
 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.commitencoding ISO-8859-1 &&
        git config i18n.logoutputencoding ISO-8859-1 &&
        . ../t3901-8859-1.txt &&
 
@@ -134,7 +134,7 @@ test_expect_success 'rebase (L/L)' '
 test_expect_success 'rebase (L/U)' '
        # This is pathological -- use UTF-8 as intermediate form
        # to get ISO-8859-1 results.
-       git-config i18n.commitencoding ISO-8859-1 &&
+       git config i18n.commitencoding ISO-8859-1 &&
        git config i18n.logoutputencoding UTF-8 &&
        . ../t3901-8859-1.txt &&
 
@@ -147,7 +147,7 @@ test_expect_success 'rebase (L/U)' '
 test_expect_success 'cherry-pick(U/U)' '
        # Both the commitencoding and logoutputencoding is set to UTF-8.
 
-       git-config i18n.commitencoding UTF-8 &&
+       git config i18n.commitencoding UTF-8 &&
        git config i18n.logoutputencoding UTF-8 &&
        . ../t3901-utf8.txt &&
 
@@ -162,7 +162,7 @@ test_expect_success 'cherry-pick(U/U)' '
 test_expect_success 'cherry-pick(L/L)' '
        # Both the commitencoding and logoutputencoding is set to ISO-8859-1
 
-       git-config i18n.commitencoding ISO-8859-1 &&
+       git config i18n.commitencoding ISO-8859-1 &&
        git config i18n.logoutputencoding ISO-8859-1 &&
        . ../t3901-8859-1.txt &&
 
@@ -177,7 +177,7 @@ test_expect_success 'cherry-pick(L/L)' '
 test_expect_success 'cherry-pick(U/L)' '
        # Commitencoding is set to UTF-8 but logoutputencoding is ISO-8859-1
 
-       git-config i18n.commitencoding UTF-8 &&
+       git config i18n.commitencoding UTF-8 &&
        git config i18n.logoutputencoding ISO-8859-1 &&
        . ../t3901-utf8.txt &&
 
@@ -193,7 +193,7 @@ test_expect_success 'cherry-pick(L/U)' '
        # Again, the commitencoding is set to ISO-8859-1 but
        # logoutputencoding is set to UTF-8.
 
-       git-config i18n.commitencoding ISO-8859-1 &&
+       git config i18n.commitencoding ISO-8859-1 &&
        git config i18n.logoutputencoding UTF-8 &&
        . ../t3901-8859-1.txt &&
 
@@ -206,7 +206,7 @@ test_expect_success 'cherry-pick(L/U)' '
 '
 
 test_expect_success 'rebase --merge (U/U)' '
-       git-config i18n.commitencoding UTF-8 &&
+       git config i18n.commitencoding UTF-8 &&
        git config i18n.logoutputencoding UTF-8 &&
        . ../t3901-utf8.txt &&
 
@@ -217,7 +217,7 @@ test_expect_success 'rebase --merge (U/U)' '
 '
 
 test_expect_success 'rebase --merge (U/L)' '
-       git-config i18n.commitencoding UTF-8 &&
+       git config i18n.commitencoding UTF-8 &&
        git config i18n.logoutputencoding ISO-8859-1 &&
        . ../t3901-utf8.txt &&
 
@@ -229,7 +229,7 @@ test_expect_success 'rebase --merge (U/L)' '
 
 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.commitencoding ISO-8859-1 &&
        git config i18n.logoutputencoding ISO-8859-1 &&
        . ../t3901-8859-1.txt &&
 
@@ -242,7 +242,7 @@ test_expect_success 'rebase --merge (L/L)' '
 test_expect_success 'rebase --merge (L/U)' '
        # This is pathological -- use UTF-8 as intermediate form
        # to get ISO-8859-1 results.
-       git-config i18n.commitencoding ISO-8859-1 &&
+       git config i18n.commitencoding ISO-8859-1 &&
        git config i18n.logoutputencoding UTF-8 &&
        . ../t3901-8859-1.txt &&
 
diff --git a/t/t3902-quoted.sh b/t/t3902-quoted.sh
new file mode 100755 (executable)
index 0000000..63f950b
--- /dev/null
@@ -0,0 +1,126 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Junio C Hamano
+#
+
+test_description='quoted output'
+
+. ./test-lib.sh
+
+FN='濱野'
+GN='純'
+HT='   '
+LF='
+'
+DQ='"'
+
+for_each_name () {
+       for name in \
+           Name "Name and a${LF}LF" "Name and an${HT}HT" "Name${DQ}" \
+           "$FN$HT$GN" "$FN$LF$GN" "$FN $GN" "$FN$GN" "$FN$DQ$GN" \
+           "With SP in it"
+       do
+               eval "$1"
+       done
+}
+
+test_expect_success setup '
+
+       for_each_name "echo initial >\"\$name\""
+       git add . &&
+       git commit -q -m Initial &&
+
+       for_each_name "echo second >\"\$name\"" &&
+       git commit -a -m Second
+
+       for_each_name "echo modified >\"\$name\""
+
+'
+
+cat >expect.quoted <<\EOF
+Name
+"Name and a\nLF"
+"Name and an\tHT"
+"Name\""
+With SP in it
+"\346\277\261\351\207\216\t\347\264\224"
+"\346\277\261\351\207\216\n\347\264\224"
+"\346\277\261\351\207\216 \347\264\224"
+"\346\277\261\351\207\216\"\347\264\224"
+"\346\277\261\351\207\216\347\264\224"
+EOF
+
+cat >expect.raw <<\EOF
+Name
+"Name and a\nLF"
+"Name and an\tHT"
+"Name\""
+With SP in it
+"濱野\t純"
+"濱野\n純"
+濱野 純
+"濱野\"純"
+濱野純
+EOF
+
+test_expect_success 'check fully quoted output from ls-files' '
+
+       git ls-files >current && diff -u expect.quoted current
+
+'
+
+test_expect_success 'check fully quoted output from diff-files' '
+
+       git diff --name-only >current &&
+       diff -u expect.quoted current
+
+'
+
+test_expect_success 'check fully quoted output from diff-index' '
+
+       git diff --name-only HEAD >current &&
+       diff -u expect.quoted current
+
+'
+
+test_expect_success 'check fully quoted output from diff-tree' '
+
+       git diff --name-only HEAD^ HEAD >current &&
+       diff -u expect.quoted current
+
+'
+
+test_expect_success 'setting core.quotepath' '
+
+       git config --bool core.quotepath false
+
+'
+
+test_expect_success 'check fully quoted output from ls-files' '
+
+       git ls-files >current && diff -u expect.raw current
+
+'
+
+test_expect_success 'check fully quoted output from diff-files' '
+
+       git diff --name-only >current &&
+       diff -u expect.raw current
+
+'
+
+test_expect_success 'check fully quoted output from diff-index' '
+
+       git diff --name-only HEAD >current &&
+       diff -u expect.raw current
+
+'
+
+test_expect_success 'check fully quoted output from diff-tree' '
+
+       git diff --name-only HEAD^ HEAD >current &&
+       diff -u expect.raw current
+
+'
+
+test_done
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
new file mode 100755 (executable)
index 0000000..392ac1c
--- /dev/null
@@ -0,0 +1,69 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Johannes E Schindelin
+#
+
+test_description='Test git-stash'
+
+. ./test-lib.sh
+
+test_expect_success 'stash some dirty working directory' '
+       echo 1 > file &&
+       git add file &&
+       test_tick &&
+       git commit -m initial &&
+       echo 2 > file &&
+       git add file &&
+       echo 3 > file &&
+       test_tick &&
+       git stash &&
+       git diff-files --quiet &&
+       git diff-index --cached --quiet HEAD
+'
+
+cat > expect << EOF
+diff --git a/file b/file
+index 0cfbf08..00750ed 100644
+--- a/file
++++ b/file
+@@ -1 +1 @@
+-2
++3
+EOF
+
+test_expect_success 'parents of stash' '
+       test $(git rev-parse stash^) = $(git rev-parse HEAD) &&
+       git diff stash^2..stash > output &&
+       diff -u output expect
+'
+
+test_expect_success 'apply needs clean working directory' '
+       echo 4 > other-file &&
+       git add other-file &&
+       echo 5 > other-file
+       ! git stash apply
+'
+
+test_expect_success 'apply stashed changes' '
+       git add other-file &&
+       test_tick &&
+       git commit -m other-file &&
+       git stash apply &&
+       test 3 = $(cat file) &&
+       test 1 = $(git show :file) &&
+       test 1 = $(git show HEAD:file)
+'
+
+test_expect_success 'apply stashed changes (including index)' '
+       git reset --hard HEAD^ &&
+       echo 6 > other-file &&
+       git add other-file &&
+       test_tick &&
+       git commit -m other-file &&
+       git stash apply --index &&
+       test 3 = $(cat file) &&
+       test 2 = $(git show :file) &&
+       test 1 = $(git show HEAD:file)
+'
+
+test_done
index 9c58d77cc22a062e571116e2dee2599ac13cb464..7d92ae3e996b31f8fa9e0b62f40a04ec1940cf70 100755 (executable)
@@ -17,15 +17,15 @@ chmod +x path1
 
 test_expect_success \
     'update-cache --add two files with and without +x.' \
-    'git-update-index --add path0 path1'
+    'git update-index --add path0 path1'
 
 mv path0 path0-
 sed -e 's/line/Line/' <path0- >path0
 chmod +x path0
 rm -f path1
 test_expect_success \
-    'git-diff-files -p after editing work tree.' \
-    'git-diff-files -p >current'
+    'git diff-files -p after editing work tree.' \
+    'git diff-files -p >current'
 
 # that's as far as it comes
 if [ "$(git config --get core.filemode)" = false ]
@@ -56,7 +56,7 @@ deleted file mode 100755
 EOF
 
 test_expect_success \
-    'validate git-diff-files -p output.' \
+    'validate git diff-files -p output.' \
     'compare_diff_patch current expected'
 
 test_done
index 2e3c20d6b9468bf413e97d422e7dbe13ac4238cd..063e79257a6e96d9021fa41d18a632560a272776 100755 (executable)
@@ -28,21 +28,21 @@ Line 15
 
 test_expect_success \
     'update-cache --add a file.' \
-    'git-update-index --add path0'
+    'git update-index --add path0'
 
 test_expect_success \
     'write that tree.' \
-    'tree=$(git-write-tree) && echo $tree'
+    'tree=$(git write-tree) && echo $tree'
 
 sed -e 's/line/Line/' <path0 >path1
 rm -f path0
 test_expect_success \
     'renamed and edited the file.' \
-    'git-update-index --add --remove path0 path1'
+    'git update-index --add --remove path0 path1'
 
 test_expect_success \
-    'git-diff-index -p -M after rename and editing.' \
-    'git-diff-index -p -M $tree >current'
+    'git diff-index -p -M after rename and editing.' \
+    'git diff-index -p -M $tree >current'
 cat >expected <<\EOF
 diff --git a/path0 b/path1
 rename from path0
@@ -64,4 +64,17 @@ test_expect_success \
     'validate the output.' \
     'compare_diff_patch current expected'
 
+test_expect_success 'favour same basenames over different ones' '
+       cp path1 another-path &&
+       git add another-path &&
+       git commit -m 1 &&
+       git rm path1 &&
+       mkdir subdir &&
+       git mv another-path subdir/path1 &&
+       git runstatus | grep "renamed: .*path1 -> subdir/path1"'
+
+test_expect_success  'favour same basenames even with minor differences' '
+       git show HEAD:path1 | sed "s/15/16/" > subdir/path1 &&
+       git runstatus | grep "renamed: .*path1 -> subdir/path1"'
+
 test_done
index 56eda63fc2f442a57fbe1f3877f17744b6c114d1..a4cfde6b2927a4655f582d7e92dad4568f7b5f89 100755 (executable)
@@ -140,80 +140,80 @@ cmp_diff_files_output () {
 
 test_expect_success \
     'diff-tree of known trees.' \
-    'git-diff-tree $tree_O $tree_A >.test-a &&
+    'git diff-tree $tree_O $tree_A >.test-a &&
      cmp -s .test-a .test-plain-OA'
 
 test_expect_success \
     'diff-tree of known trees.' \
-    'git-diff-tree -r $tree_O $tree_A >.test-a &&
+    'git diff-tree -r $tree_O $tree_A >.test-a &&
      cmp -s .test-a .test-recursive-OA'
 
 test_expect_success \
     'diff-tree of known trees.' \
-    'git-diff-tree $tree_O $tree_B >.test-a &&
+    'git diff-tree $tree_O $tree_B >.test-a &&
      cmp -s .test-a .test-plain-OB'
 
 test_expect_success \
     'diff-tree of known trees.' \
-    'git-diff-tree -r $tree_O $tree_B >.test-a &&
+    'git diff-tree -r $tree_O $tree_B >.test-a &&
      cmp -s .test-a .test-recursive-OB'
 
 test_expect_success \
     'diff-tree of known trees.' \
-    'git-diff-tree $tree_A $tree_B >.test-a &&
+    'git diff-tree $tree_A $tree_B >.test-a &&
      cmp -s .test-a .test-plain-AB'
 
 test_expect_success \
     'diff-tree of known trees.' \
-    'git-diff-tree -r $tree_A $tree_B >.test-a &&
+    'git diff-tree -r $tree_A $tree_B >.test-a &&
      cmp -s .test-a .test-recursive-AB'
 
 test_expect_success \
     'diff-cache O with A in cache' \
-    'git-read-tree $tree_A &&
-     git-diff-index --cached $tree_O >.test-a &&
+    'git read-tree $tree_A &&
+     git diff-index --cached $tree_O >.test-a &&
      cmp -s .test-a .test-recursive-OA'
 
 test_expect_success \
     'diff-cache O with B in cache' \
-    'git-read-tree $tree_B &&
-     git-diff-index --cached $tree_O >.test-a &&
+    'git read-tree $tree_B &&
+     git diff-index --cached $tree_O >.test-a &&
      cmp -s .test-a .test-recursive-OB'
 
 test_expect_success \
     'diff-cache A with B in cache' \
-    'git-read-tree $tree_B &&
-     git-diff-index --cached $tree_A >.test-a &&
+    'git read-tree $tree_B &&
+     git diff-index --cached $tree_A >.test-a &&
      cmp -s .test-a .test-recursive-AB'
 
 test_expect_success \
     'diff-files with O in cache and A checked out' \
     'rm -fr Z [A-Z][A-Z] &&
-     git-read-tree $tree_A &&
-     git-checkout-index -f -a &&
-     git-read-tree --reset $tree_O || return 1
-     git-update-index --refresh >/dev/null ;# this can exit non-zero
-     git-diff-files >.test-a &&
+     git read-tree $tree_A &&
+     git checkout-index -f -a &&
+     git read-tree --reset $tree_O || return 1
+     git update-index --refresh >/dev/null ;# this can exit non-zero
+     git diff-files >.test-a &&
      cmp_diff_files_output .test-a .test-recursive-OA'
 
 test_expect_success \
     'diff-files with O in cache and B checked out' \
     'rm -fr Z [A-Z][A-Z] &&
-     git-read-tree $tree_B &&
-     git-checkout-index -f -a &&
-     git-read-tree --reset $tree_O || return 1
-     git-update-index --refresh >/dev/null ;# this can exit non-zero
-     git-diff-files >.test-a &&
+     git read-tree $tree_B &&
+     git checkout-index -f -a &&
+     git read-tree --reset $tree_O || return 1
+     git update-index --refresh >/dev/null ;# this can exit non-zero
+     git diff-files >.test-a &&
      cmp_diff_files_output .test-a .test-recursive-OB'
 
 test_expect_success \
     'diff-files with A in cache and B checked out' \
     'rm -fr Z [A-Z][A-Z] &&
-     git-read-tree $tree_B &&
-     git-checkout-index -f -a &&
-     git-read-tree --reset $tree_A || return 1
-     git-update-index --refresh >/dev/null ;# this can exit non-zero
-     git-diff-files >.test-a &&
+     git read-tree $tree_B &&
+     git checkout-index -f -a &&
+     git read-tree --reset $tree_A || return 1
+     git update-index --refresh >/dev/null ;# this can exit non-zero
+     git diff-files >.test-a &&
      cmp_diff_files_output .test-a .test-recursive-AB'
 
 ################################################################
@@ -222,26 +222,26 @@ test_expect_success \
 
 test_expect_success \
     'diff-tree O A == diff-tree -R A O' \
-    'git-diff-tree $tree_O $tree_A >.test-a &&
-    git-diff-tree -R $tree_A $tree_O >.test-b &&
+    'git diff-tree $tree_O $tree_A >.test-a &&
+    git diff-tree -R $tree_A $tree_O >.test-b &&
     cmp -s .test-a .test-b'
 
 test_expect_success \
     'diff-tree -r O A == diff-tree -r -R A O' \
-    'git-diff-tree -r $tree_O $tree_A >.test-a &&
-    git-diff-tree -r -R $tree_A $tree_O >.test-b &&
+    'git diff-tree -r $tree_O $tree_A >.test-a &&
+    git diff-tree -r -R $tree_A $tree_O >.test-b &&
     cmp -s .test-a .test-b'
 
 test_expect_success \
     'diff-tree B A == diff-tree -R A B' \
-    'git-diff-tree $tree_B $tree_A >.test-a &&
-    git-diff-tree -R $tree_A $tree_B >.test-b &&
+    'git diff-tree $tree_B $tree_A >.test-a &&
+    git diff-tree -R $tree_A $tree_B >.test-b &&
     cmp -s .test-a .test-b'
 
 test_expect_success \
     'diff-tree -r B A == diff-tree -r -R A B' \
-    'git-diff-tree -r $tree_B $tree_A >.test-a &&
-    git-diff-tree -r -R $tree_A $tree_B >.test-b &&
+    'git diff-tree -r $tree_B $tree_A >.test-a &&
+    git diff-tree -r -R $tree_A $tree_B >.test-b &&
     cmp -s .test-a .test-b'
 
 test_done
index 27519704d46d95deddbe8af75f985ede16bb4aaf..8b1f875286b25b5fc1a527b5b0281f866724a82d 100755 (executable)
@@ -13,8 +13,8 @@ test_expect_success \
     'prepare reference tree' \
     'cat ../../COPYING >COPYING &&
      echo frotz >rezrov &&
-    git-update-index --add COPYING rezrov &&
-    tree=$(git-write-tree) &&
+    git update-index --add COPYING rezrov &&
+    tree=$(git write-tree) &&
     echo $tree'
 
 test_expect_success \
@@ -22,14 +22,14 @@ test_expect_success \
     'sed -e 's/HOWEVER/However/' <COPYING >COPYING.1 &&
     sed -e 's/GPL/G.P.L/g' <COPYING >COPYING.2 &&
     rm -f COPYING &&
-    git-update-index --add --remove COPYING COPYING.?'
+    git update-index --add --remove COPYING COPYING.?'
 
 # tree has COPYING and rezrov.  work tree has COPYING.1 and COPYING.2,
 # both are slightly edited, and unchanged rezrov.  So we say you
 # copy-and-edit one, and rename-and-edit the other.  We do not say
 # anything about rezrov.
 
-GIT_DIFF_OPTS=--unified=0 git-diff-index -M -p $tree >current
+GIT_DIFF_OPTS=--unified=0 git diff-index -M -p $tree >current
 cat >expected <<\EOF
 diff --git a/COPYING b/COPYING.1
 copy from COPYING
@@ -62,14 +62,14 @@ test_expect_success \
 test_expect_success \
     'prepare work tree again' \
     'mv COPYING.2 COPYING &&
-     git-update-index --add --remove COPYING COPYING.1 COPYING.2'
+     git update-index --add --remove COPYING COPYING.1 COPYING.2'
 
 # tree has COPYING and rezrov.  work tree has COPYING and COPYING.1,
 # both are slightly edited, and unchanged rezrov.  So we say you
 # edited one, and copy-and-edit the other.  We do not say
 # anything about rezrov.
 
-GIT_DIFF_OPTS=--unified=0 git-diff-index -C -p $tree >current
+GIT_DIFF_OPTS=--unified=0 git diff-index -C -p $tree >current
 cat >expected <<\EOF
 diff --git a/COPYING b/COPYING
 --- a/COPYING
@@ -100,16 +100,16 @@ test_expect_success \
 test_expect_success \
     'prepare work tree once again' \
     'cat ../../COPYING >COPYING &&
-     git-update-index --add --remove COPYING COPYING.1'
+     git update-index --add --remove COPYING COPYING.1'
 
 # tree has COPYING and rezrov.  work tree has COPYING and COPYING.1,
 # but COPYING is not edited.  We say you copy-and-edit COPYING.1; this
 # is only possible because -C mode now reports the unmodified file to
 # the diff-core.  Unchanged rezrov, although being fed to
-# git-diff-index as well, should not be mentioned.
+# git diff-index as well, should not be mentioned.
 
 GIT_DIFF_OPTS=--unified=0 \
-    git-diff-index -C --find-copies-harder -p $tree >current
+    git diff-index -C --find-copies-harder -p $tree >current
 cat >expected <<\EOF
 diff --git a/COPYING b/COPYING.1
 copy from COPYING
index a23aaa0a9471c68b233480cf34c7115d1f40e154..3d25be7a6709cdd23e0d583a8f1a3e19a3927cd8 100755 (executable)
@@ -16,8 +16,8 @@ test_expect_success \
     'prepare reference tree' \
     'echo xyzzy | tr -d '\\\\'012 >yomin &&
      ln -s xyzzy frotz &&
-    git-update-index --add frotz yomin &&
-    tree=$(git-write-tree) &&
+    git update-index --add frotz yomin &&
+    tree=$(git write-tree) &&
     echo $tree'
 
 test_expect_success \
@@ -26,7 +26,7 @@ test_expect_success \
      rm -f yomin &&
      ln -s xyzzy nitfol &&
      ln -s xzzzy bozbar &&
-    git-update-index --add --remove frotz rezrov nitfol bozbar yomin'
+    git update-index --add --remove frotz rezrov nitfol bozbar yomin'
 
 # tree has frotz pointing at xyzzy, and yomin that contains xyzzy to
 # confuse things.  work tree has rezrov (xyzzy) nitfol (xyzzy) and
@@ -34,7 +34,7 @@ test_expect_success \
 # rezrov and nitfol are rename/copy of frotz and bozbar should be
 # a new creation.
 
-GIT_DIFF_OPTS=--unified=0 git-diff-index -M -p $tree >current
+GIT_DIFF_OPTS=--unified=0 git diff-index -M -p $tree >current
 cat >expected <<\EOF
 diff --git a/bozbar b/bozbar
 new file mode 120000
index 684fd23a419a2449a1a656783b09e0566c56c916..66300173124eee8480e7214322faf8bc493ad940 100755 (executable)
@@ -13,8 +13,8 @@ test_expect_success \
     'prepare reference tree' \
     'cat ../../COPYING >COPYING &&
      echo frotz >rezrov &&
-    git-update-index --add COPYING rezrov &&
-    tree=$(git-write-tree) &&
+    git update-index --add COPYING rezrov &&
+    tree=$(git write-tree) &&
     echo $tree'
 
 test_expect_success \
@@ -22,14 +22,14 @@ test_expect_success \
     'sed -e 's/HOWEVER/However/' <COPYING >COPYING.1 &&
     sed -e 's/GPL/G.P.L/g' <COPYING >COPYING.2 &&
     rm -f COPYING &&
-    git-update-index --add --remove COPYING COPYING.?'
+    git update-index --add --remove COPYING COPYING.?'
 
 # tree has COPYING and rezrov.  work tree has COPYING.1 and COPYING.2,
 # both are slightly edited, and unchanged rezrov.  We say COPYING.1
 # and COPYING.2 are based on COPYING, and do not say anything about
 # rezrov.
 
-git-diff-index -M $tree >current
+git diff-index -M $tree >current
 
 cat >expected <<\EOF
 :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 0603b3238a076dc6c8022aedc6648fa523a17178 C1234 COPYING COPYING.1
@@ -45,14 +45,14 @@ test_expect_success \
 test_expect_success \
     'prepare work tree again' \
     'mv COPYING.2 COPYING &&
-     git-update-index --add --remove COPYING COPYING.1 COPYING.2'
+     git update-index --add --remove COPYING COPYING.1 COPYING.2'
 
 # tree has COPYING and rezrov.  work tree has COPYING and COPYING.1,
 # both are slightly edited, and unchanged rezrov.  We say COPYING.1
 # is based on COPYING and COPYING is still there, and do not say anything
 # about rezrov.
 
-git-diff-index -C $tree >current
+git diff-index -C $tree >current
 cat >expected <<\EOF
 :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 06c67961bbaed34a127f76d261f4c0bf73eda471 M     COPYING
 :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 0603b3238a076dc6c8022aedc6648fa523a17178 C1234 COPYING COPYING.1
@@ -72,9 +72,9 @@ test_expect_success \
 test_expect_success \
     'prepare work tree once again' \
     'cat ../../COPYING >COPYING &&
-     git-update-index --add --remove COPYING COPYING.1'
+     git update-index --add --remove COPYING COPYING.1'
 
-git-diff-index -C --find-copies-harder $tree >current
+git diff-index -C --find-copies-harder $tree >current
 cat >expected <<\EOF
 :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 0603b3238a076dc6c8022aedc6648fa523a17178 C1234 COPYING COPYING.1
 EOF
index e72c6fd1b4fa294e3e52fe55ab68c672bfc57e15..ab5406dd9f241edee7a6067a1426f0a65076eb10 100755 (executable)
@@ -11,24 +11,24 @@ test_description='Test mode change diffs.
 test_expect_success \
     'setup' \
     'echo frotz >rezrov &&
-     git-update-index --add rezrov &&
-     tree=`git-write-tree` &&
+     git update-index --add rezrov &&
+     tree=`git write-tree` &&
      echo $tree'
 
 if [ "$(git config --get core.filemode)" = false ]
 then
        say 'filemode disabled on the filesystem, using update-index --chmod=+x'
        test_expect_success \
-           'git-update-index --chmod=+x' \
-           'git-update-index rezrov &&
-            git-update-index --chmod=+x rezrov &&
-            git-diff-index $tree >current'
+           'git update-index --chmod=+x' \
+           'git update-index rezrov &&
+            git update-index --chmod=+x rezrov &&
+            git diff-index $tree >current'
 else
        test_expect_success \
            'chmod' \
            'chmod +x rezrov &&
-            git-update-index rezrov &&
-            git-diff-index $tree >current'
+            git update-index rezrov &&
+            git diff-index $tree >current'
 fi
 
 _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
@@ -41,4 +41,3 @@ test_expect_success \
     'git diff expected check'
 
 test_done
-
index bb6ba69258237ed40e736a0a7e218d621164998a..104a4e1492b65a64d061e1ce1df0b0a2a49fb20e 100755 (executable)
@@ -13,20 +13,20 @@ test_expect_success \
     'prepare reference tree' \
     'mkdir path0 path1 &&
      cp ../../COPYING path0/COPYING &&
-     git-update-index --add path0/COPYING &&
-    tree=$(git-write-tree) &&
+     git update-index --add path0/COPYING &&
+    tree=$(git write-tree) &&
     echo $tree'
 
 test_expect_success \
     'prepare work tree' \
     'cp path0/COPYING path1/COPYING &&
-     git-update-index --add --remove path0/COPYING path1/COPYING'
+     git update-index --add --remove path0/COPYING path1/COPYING'
 
 # In the tree, there is only path0/COPYING.  In the cache, path0 and
 # path1 both have COPYING and the latter is a copy of path0/COPYING.
 # Comparing the full tree with cache should tell us so.
 
-git-diff-index -C --find-copies-harder $tree >current
+git diff-index -C --find-copies-harder $tree >current
 
 cat >expected <<\EOF
 :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 6ff87c4664981e4397625791c8ea3bbb5f2279a3 C100  path0/COPYING   path1/COPYING
@@ -42,7 +42,7 @@ test_expect_success \
 # path1/COPYING suddenly appearing from nowhere, not detected as
 # a copy from path0/COPYING.
 
-git-diff-index -C $tree path1 >current
+git diff-index -C $tree path1 >current
 
 cat >expected <<\EOF
 :000000 100644 0000000000000000000000000000000000000000 6ff87c4664981e4397625791c8ea3bbb5f2279a3 A     path1/COPYING
@@ -55,14 +55,14 @@ test_expect_success \
 test_expect_success \
     'tweak work tree' \
     'rm -f path0/COPYING &&
-     git-update-index --remove path0/COPYING'
+     git update-index --remove path0/COPYING'
 
 # In the tree, there is only path0/COPYING.  In the cache, path0 does
 # not have COPYING anymore and path1 has COPYING which is a copy of
 # path0/COPYING.  Showing the full tree with cache should tell us about
 # the rename.
 
-git-diff-index -C $tree >current
+git diff-index -C $tree >current
 
 cat >expected <<\EOF
 :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 6ff87c4664981e4397625791c8ea3bbb5f2279a3 R100  path0/COPYING   path1/COPYING
@@ -77,7 +77,7 @@ test_expect_success \
 # path0/COPYING.  When we say we care only about path1, we should just
 # see path1/COPYING appearing from nowhere.
 
-git-diff-index -C $tree path1 >current
+git diff-index -C $tree path1 >current
 
 cat >expected <<\EOF
 :000000 100644 0000000000000000000000000000000000000000 6ff87c4664981e4397625791c8ea3bbb5f2279a3 A     path1/COPYING
index 263ac1ebf7d5ef2fa6b278c4a6694d369c283f88..5836e3a899d62c3c86482ea254eb53c015a52823 100755 (executable)
@@ -28,19 +28,19 @@ test_expect_success \
     setup \
     'cat ../../README >file0 &&
      cat ../../COPYING >file1 &&
-    git-update-index --add file0 file1 &&
-    tree=$(git-write-tree) &&
+    git update-index --add file0 file1 &&
+    tree=$(git write-tree) &&
     echo "$tree"'
 
 test_expect_success \
     'change file1 with copy-edit of file0 and remove file0' \
     'sed -e "s/git/GIT/" file0 >file1 &&
      rm -f file0 &&
-    git-update-index --remove file0 file1'
+    git update-index --remove file0 file1'
 
 test_expect_success \
     'run diff with -B' \
-    'git-diff-index -B --cached "$tree" >current'
+    'git diff-index -B --cached "$tree" >current'
 
 cat >expected <<\EOF
 :100644 000000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 0000000000000000000000000000000000000000 D     file0
@@ -53,7 +53,7 @@ test_expect_success \
 
 test_expect_success \
     'run diff with -B and -M' \
-    'git-diff-index -B -M "$tree" >current'
+    'git diff-index -B -M "$tree" >current'
 
 cat >expected <<\EOF
 :100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 08bb2fb671deff4c03a4d4a0a1315dff98d5732c R100  file0   file1
@@ -66,16 +66,16 @@ test_expect_success \
 test_expect_success \
     'swap file0 and file1' \
     'rm -f file0 file1 &&
-     git-read-tree -m $tree &&
-     git-checkout-index -f -u -a &&
+     git read-tree -m $tree &&
+     git checkout-index -f -u -a &&
      mv file0 tmp &&
      mv file1 file0 &&
      mv tmp file1 &&
-     git-update-index file0 file1'
+     git update-index file0 file1'
 
 test_expect_success \
     'run diff with -B' \
-    'git-diff-index -B "$tree" >current'
+    'git diff-index -B "$tree" >current'
 
 cat >expected <<\EOF
 :100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 6ff87c4664981e4397625791c8ea3bbb5f2279a3 M100  file0
@@ -88,7 +88,7 @@ test_expect_success \
 
 test_expect_success \
     'run diff with -B and -M' \
-    'git-diff-index -B -M "$tree" >current'
+    'git diff-index -B -M "$tree" >current'
 
 cat >expected <<\EOF
 :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 6ff87c4664981e4397625791c8ea3bbb5f2279a3 R100  file1   file0
@@ -103,11 +103,11 @@ test_expect_success \
     'make file0 into something completely different' \
     'rm -f file0 &&
      ln -s frotz file0 &&
-     git-update-index file0 file1'
+     git update-index file0 file1'
 
 test_expect_success \
     'run diff with -B' \
-    'git-diff-index -B "$tree" >current'
+    'git diff-index -B "$tree" >current'
 
 cat >expected <<\EOF
 :100644 120000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 67be421f88824578857624f7b3dc75e99a8a1481 T     file0
@@ -120,7 +120,7 @@ test_expect_success \
 
 test_expect_success \
     'run diff with -B' \
-    'git-diff-index -B -M "$tree" >current'
+    'git diff-index -B -M "$tree" >current'
 
 # This should not mistake file0 as the copy source of new file1
 # due to type differences.
@@ -135,7 +135,7 @@ test_expect_success \
 
 test_expect_success \
     'run diff with -M' \
-    'git-diff-index -M "$tree" >current'
+    'git diff-index -M "$tree" >current'
 
 # This should not mistake file0 as the copy source of new file1
 # due to type differences.
@@ -151,16 +151,16 @@ test_expect_success \
 test_expect_success \
     'file1 edited to look like file0 and file0 rename-edited to file2' \
     'rm -f file0 file1 &&
-     git-read-tree -m $tree &&
-     git-checkout-index -f -u -a &&
+     git read-tree -m $tree &&
+     git checkout-index -f -u -a &&
      sed -e "s/git/GIT/" file0 >file1 &&
      sed -e "s/git/GET/" file0 >file2 &&
      rm -f file0
-     git-update-index --add --remove file0 file1 file2'
+     git update-index --add --remove file0 file1 file2'
 
 test_expect_success \
     'run diff with -B' \
-    'git-diff-index -B "$tree" >current'
+    'git diff-index -B "$tree" >current'
 
 cat >expected <<\EOF
 :100644 000000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 0000000000000000000000000000000000000000 D     file0
@@ -174,7 +174,7 @@ test_expect_success \
 
 test_expect_success \
     'run diff with -B -M' \
-    'git-diff-index -B -M "$tree" >current'
+    'git diff-index -B -M "$tree" >current'
 
 cat >expected <<\EOF
 :100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 08bb2fb671deff4c03a4d4a0a1315dff98d5732c C095  file0   file1
index 2f2f8b121663a3647e88c308b541c6106f5d9039..d2b45e7b8fb3902cb740e0df582f92195a295f24 100755 (executable)
@@ -13,8 +13,8 @@ test_expect_success \
     'prepare reference tree' \
     'cat ../../COPYING >COPYING &&
      echo frotz >rezrov &&
-    git-update-index --add COPYING rezrov &&
-    tree=$(git-write-tree) &&
+    git update-index --add COPYING rezrov &&
+    tree=$(git write-tree) &&
     echo $tree'
 
 test_expect_success \
@@ -22,14 +22,14 @@ test_expect_success \
     'sed -e 's/HOWEVER/However/' <COPYING >COPYING.1 &&
     sed -e 's/GPL/G.P.L/g' <COPYING >COPYING.2 &&
     rm -f COPYING &&
-    git-update-index --add --remove COPYING COPYING.?'
+    git update-index --add --remove COPYING COPYING.?'
 
 # tree has COPYING and rezrov.  work tree has COPYING.1 and COPYING.2,
 # both are slightly edited, and unchanged rezrov.  We say COPYING.1
 # and COPYING.2 are based on COPYING, and do not say anything about
 # rezrov.
 
-git-diff-index -z -M $tree >current
+git diff-index -z -M $tree >current
 
 cat >expected <<\EOF
 :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 0603b3238a076dc6c8022aedc6648fa523a17178 C1234
@@ -49,14 +49,14 @@ test_expect_success \
 test_expect_success \
     'prepare work tree again' \
     'mv COPYING.2 COPYING &&
-     git-update-index --add --remove COPYING COPYING.1 COPYING.2'
+     git update-index --add --remove COPYING COPYING.1 COPYING.2'
 
 # tree has COPYING and rezrov.  work tree has COPYING and COPYING.1,
 # both are slightly edited, and unchanged rezrov.  We say COPYING.1
 # is based on COPYING and COPYING is still there, and do not say anything
 # about rezrov.
 
-git-diff-index -z -C $tree >current
+git diff-index -z -C $tree >current
 cat >expected <<\EOF
 :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 06c67961bbaed34a127f76d261f4c0bf73eda471 M
 COPYING
@@ -79,9 +79,9 @@ test_expect_success \
 test_expect_success \
     'prepare work tree once again' \
     'cat ../../COPYING >COPYING &&
-     git-update-index --add --remove COPYING COPYING.1'
+     git update-index --add --remove COPYING COPYING.1'
 
-git-diff-index -z -C --find-copies-harder $tree >current
+git diff-index -z -C --find-copies-harder $tree >current
 cat >expected <<\EOF
 :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 0603b3238a076dc6c8022aedc6648fa523a17178 C1234
 COPYING
index 9e1544df9d868b505f795c22ea9b734d6b6fc279..ad3d9e48454d2e72afce682df009cdaaee9ba3c5 100755 (executable)
@@ -17,18 +17,18 @@ test_expect_success \
     'echo frotz >file0 &&
      mkdir path1 &&
      echo rezrov >path1/file1 &&
-     git-update-index --add file0 path1/file1 &&
-     tree=`git-write-tree` &&
+     git update-index --add file0 path1/file1 &&
+     tree=`git write-tree` &&
      echo "$tree" &&
      echo nitfol >file0 &&
      echo yomin >path1/file1 &&
-     git-update-index file0 path1/file1'
+     git update-index file0 path1/file1'
 
 cat >expected <<\EOF
 EOF
 test_expect_success \
     'limit to path should show nothing' \
-    'git-diff-index --cached $tree -- path >current &&
+    'git diff-index --cached $tree -- path >current &&
      compare_diff_raw current expected'
 
 cat >expected <<\EOF
@@ -36,7 +36,7 @@ cat >expected <<\EOF
 EOF
 test_expect_success \
     'limit to path1 should show path1/file1' \
-    'git-diff-index --cached $tree -- path1 >current &&
+    'git diff-index --cached $tree -- path1 >current &&
      compare_diff_raw current expected'
 
 cat >expected <<\EOF
@@ -44,7 +44,7 @@ cat >expected <<\EOF
 EOF
 test_expect_success \
     'limit to path1/ should show path1/file1' \
-    'git-diff-index --cached $tree -- path1/ >current &&
+    'git diff-index --cached $tree -- path1/ >current &&
      compare_diff_raw current expected'
 
 cat >expected <<\EOF
@@ -52,14 +52,14 @@ cat >expected <<\EOF
 EOF
 test_expect_success \
     'limit to file0 should show file0' \
-    'git-diff-index --cached $tree -- file0 >current &&
+    'git diff-index --cached $tree -- file0 >current &&
      compare_diff_raw current expected'
 
 cat >expected <<\EOF
 EOF
 test_expect_success \
     'limit to file0/ should emit nothing.' \
-    'git-diff-index --cached $tree -- file0/ >current &&
+    'git diff-index --cached $tree -- file0/ >current &&
      compare_diff_raw current expected'
 
 test_done
index 379a831f0bd698273c695468f4d3a2c834b104c5..c6d13693ba45b594704c2ef55d40540ee3f9c25f 100755 (executable)
@@ -23,17 +23,17 @@ EOF
 test_expect_success \
     'diff new symlink' \
     'ln -s xyzzy frotz &&
-    git-update-index &&
-    tree=$(git-write-tree) &&
-    git-update-index --add frotz &&
-    GIT_DIFF_OPTS=--unified=0 git-diff-index -M -p $tree > current &&
+    git update-index &&
+    tree=$(git write-tree) &&
+    git update-index --add frotz &&
+    GIT_DIFF_OPTS=--unified=0 git diff-index -M -p $tree > current &&
     compare_diff_patch current expected'
 
 test_expect_success \
     'diff unchanged symlink' \
-    'tree=$(git-write-tree) &&
-    git-update-index frotz &&
-    test -z "$(git-diff-index --name-only $tree)"'
+    'tree=$(git write-tree) &&
+    git update-index frotz &&
+    test -z "$(git diff-index --name-only $tree)"'
 
 cat > expected << EOF
 diff --git a/frotz b/frotz
@@ -49,7 +49,7 @@ EOF
 test_expect_success \
     'diff removed symlink' \
     'rm frotz &&
-    git-diff-index -M -p $tree > current &&
+    git diff-index -M -p $tree > current &&
     compare_diff_patch current expected'
 
 cat > expected << EOF
@@ -60,7 +60,7 @@ test_expect_success \
     'diff identical, but newly created symlink' \
     'sleep 3 &&
     ln -s xyzzy frotz &&
-    git-diff-index -M -p $tree > current &&
+    git diff-index -M -p $tree > current &&
     compare_diff_patch current expected'
 
 cat > expected << EOF
@@ -79,7 +79,7 @@ test_expect_success \
     'diff different symlink' \
     'rm frotz &&
     ln -s yxyyz frotz &&
-    git-diff-index -M -p $tree > current &&
+    git diff-index -M -p $tree > current &&
     compare_diff_patch current expected'
 
 test_done
index 323606c65c424814afc4847d40af8796e39ce4cf..eced1f30fb8475739aef52230bbb79946a0f76d8 100755 (executable)
@@ -10,7 +10,7 @@ test_description='Binary diff and apply
 
 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 &&
+        git update-index --add a b c d &&
         echo git >a &&
         cat ../test4012.png >b &&
         echo git >c &&
@@ -24,18 +24,18 @@ cat > expected <<\EOF
  4 files changed, 2 insertions(+), 2 deletions(-)
 EOF
 test_expect_success 'diff without --binary' \
-       'git-diff | git-apply --stat --summary >current &&
+       'git diff | git apply --stat --summary >current &&
         cmp current expected'
 
 test_expect_success 'diff with --binary' \
-       'git-diff --binary | git-apply --stat --summary >current &&
+       'git diff --binary | git apply --stat --summary >current &&
         cmp current expected'
 
 # apply needs to be able to skip the binary material correctly
 # in order to report the line number of a corrupt patch.
 test_expect_success 'apply detecting corrupt patch correctly' \
-       'git-diff | sed -e 's/-CIT/xCIT/' >broken &&
-        if git-apply --stat --summary broken 2>detected
+       'git diff | sed -e 's/-CIT/xCIT/' >broken &&
+        if git apply --stat --summary broken 2>detected
         then
                echo unhappy - should have detected an error
                (exit 1)
@@ -48,8 +48,8 @@ test_expect_success 'apply detecting corrupt patch correctly' \
         test "$detected" = xCIT'
 
 test_expect_success 'apply detecting corrupt patch correctly' \
-       'git-diff --binary | sed -e 's/-CIT/xCIT/' >broken &&
-        if git-apply --stat --summary broken 2>detected
+       'git diff --binary | sed -e 's/-CIT/xCIT/' >broken &&
+        if git apply --stat --summary broken 2>detected
         then
                echo unhappy - should have detected an error
                (exit 1)
@@ -66,15 +66,15 @@ 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' \
        'echo AIT >a && mv b e && echo CIT >c && cat e >d &&
-        git-update-index --add --remove a b c d e &&
-        tree0=`git-write-tree` &&
-        git-diff --cached --binary >current &&
-        git-apply --stat --summary current'
+        git update-index --add --remove a b c d e &&
+        tree0=`git write-tree` &&
+        git diff --cached --binary >current &&
+        git apply --stat --summary current'
 
 test_expect_success 'apply binary patch' \
        'git-reset --hard &&
-        git-apply --binary --index <current &&
-        tree1=`git-write-tree` &&
+        git apply --binary --index <current &&
+        tree1=`git write-tree` &&
         test "$tree1" = "$tree0"'
 
 test_done
index 4e7d68dda28a54cdc4f46e11717e113fa8dd479c..9eec754221d85856613b01ec878ef4cb492aceb0 100755 (executable)
@@ -243,6 +243,8 @@ format-patch --inline --stdout initial..side
 format-patch --inline --stdout initial..master^
 format-patch --inline --stdout initial..master
 format-patch --inline --stdout --subject-prefix=TESTCASE initial..master
+config format.subjectprefix DIFFERENT_PREFIX
+format-patch --inline --stdout initial..master^^
 
 diff --abbrev initial..side
 diff -r initial..side
diff --git a/t/t4013/diff.config_format.subjectprefix_DIFFERENT_PREFIX b/t/t4013/diff.config_format.subjectprefix_DIFFERENT_PREFIX
new file mode 100644 (file)
index 0000000..78f8970
--- /dev/null
@@ -0,0 +1,2 @@
+$ git config format.subjectprefix DIFFERENT_PREFIX
+$
diff --git a/t/t4013/diff.format-patch_--inline_--stdout_initial..master^^ b/t/t4013/diff.format-patch_--inline_--stdout_initial..master^^
new file mode 100644 (file)
index 0000000..b8e81e1
--- /dev/null
@@ -0,0 +1,60 @@
+$ git format-patch --inline --stdout initial..master^^
+From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001
+From: A U Thor <author@example.com>
+Date: Mon, 26 Jun 2006 00:01:00 +0000
+Subject: [DIFFERENT_PREFIX] Second
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary="------------g-i-t--v-e-r-s-i-o-n"
+
+This is a multi-part message in MIME format.
+--------------g-i-t--v-e-r-s-i-o-n
+Content-Type: text/plain; charset=UTF-8; format=fixed
+Content-Transfer-Encoding: 8bit
+
+
+This is the second commit.
+---
+ dir/sub |    2 ++
+ file0   |    3 +++
+ file2   |    3 ---
+ 3 files changed, 5 insertions(+), 3 deletions(-)
+ delete mode 100644 file2
+--------------g-i-t--v-e-r-s-i-o-n
+Content-Type: text/x-patch; name="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff"
+Content-Transfer-Encoding: 8bit
+Content-Disposition: inline; filename="1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44.diff"
+
+diff --git a/dir/sub b/dir/sub
+index 35d242b..8422d40 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -1,2 +1,4 @@
+ A
+ B
++C
++D
+diff --git a/file0 b/file0
+index 01e79c3..b414108 100644
+--- a/file0
++++ b/file0
+@@ -1,3 +1,6 @@
+ 1
+ 2
+ 3
++4
++5
++6
+diff --git a/file2 b/file2
+deleted file mode 100644
+index 01e79c3..0000000
+--- a/file2
++++ /dev/null
+@@ -1,3 +0,0 @@
+-1
+-2
+-3
+
+--------------g-i-t--v-e-r-s-i-o-n--
+
+
+$
index 930e209d3136c855c3257e81d889e4dcf765595a..79fdff3f3a87cfe45b7fefa96e350675bd4e048c 100755 (executable)
@@ -17,7 +17,7 @@ do {
 } while (0);
 EOF
 
-git-update-index --add x
+git update-index --add x
 
 cat << EOF > x
 do
@@ -42,13 +42,13 @@ index adf3937..6edc172 100644
 +while (0);
 EOF
 
-git-diff > out
+git diff > out
 test_expect_success "Ray's example without options" 'git diff expect out'
 
-git-diff -w > out
+git diff -w > out
 test_expect_success "Ray's example with -w" 'git diff expect out'
 
-git-diff -b > out
+git diff -b > out
 test_expect_success "Ray's example with -b" 'git diff expect out'
 
 tr 'Q' '\015' << EOF > x
@@ -60,7 +60,7 @@ unchanged line
 CR at endQ
 EOF
 
-git-update-index x
+git update-index x
 
 cat << EOF > x
        whitespace at beginning
@@ -89,14 +89,14 @@ index d99af23..8b32fb5 100644
 -CR at endQ
 +CR at end
 EOF
-git-diff > out
+git diff > out
 test_expect_success 'another test, without options' 'git diff expect out'
 
 cat << EOF > expect
 diff --git a/x b/x
 index d99af23..8b32fb5 100644
 EOF
-git-diff -w > out
+git diff -w > out
 test_expect_success 'another test, with -w' 'git diff expect out'
 
 tr 'Q' '\015' << EOF > expect
@@ -114,7 +114,7 @@ index d99af23..8b32fb5 100644
  unchanged line
  CR at endQ
 EOF
-git-diff -b > out
+git diff -b > out
 test_expect_success 'another test, with -b' 'git diff expect out'
 
 test_done
diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh
new file mode 100644 (file)
index 0000000..f9db81d
--- /dev/null
@@ -0,0 +1,60 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Johannes E. Schindelin
+#
+
+test_description='Test custom diff function name patterns'
+
+. ./test-lib.sh
+
+LF='
+'
+
+cat > Beer.java << EOF
+public class Beer
+{
+       int special;
+       public static void main(String args[])
+       {
+               String s=" ";
+               for(int x = 99; x > 0; x--)
+               {
+                       System.out.print(x + " bottles of beer on the wall "
+                               + x + " bottles of beer\n"
+                               + "Take one down, pass it around, " + (x - 1)
+                               + " bottles of beer on the wall.\n");
+               }
+               System.out.print("Go to the store, buy some more,\n"
+                       + "99 bottles of beer on the wall.\n");
+       }
+}
+EOF
+
+sed 's/beer\\/beer,\\/' < Beer.java > Beer-correct.java
+
+test_expect_success 'default behaviour' '
+       git diff Beer.java Beer-correct.java |
+       grep "^@@.*@@ public class Beer"
+'
+
+test_expect_success 'preset java pattern' '
+       echo "*.java diff=java" >.gitattributes &&
+       git diff Beer.java Beer-correct.java |
+       grep "^@@.*@@ public static void main("
+'
+
+git config diff.java.funcname '!static
+!String
+[^     ].*s.*'
+
+test_expect_success 'custom pattern' '
+       git diff Beer.java Beer-correct.java |
+       grep "^@@.*@@ int special;$"
+'
+
+test_expect_success 'last regexp must not be negated' '
+       git config diff.java.funcname "!static" &&
+       ! git diff Beer.java Beer-correct.java
+'
+
+test_done
index f0045cd788a275f525bbd94912c5ad09cf6226bd..ed3bd5b3fe7c8b5ca52067e3015e0d770ee79bf2 100755 (executable)
@@ -94,4 +94,16 @@ test_expect_success 'diff attribute should apply only to diff' '
 
 '
 
+test_expect_success 'no diff with -diff' '
+       echo >.gitattributes "file -diff" &&
+       git diff | grep Binary
+'
+
+echo NULZbetweenZwords | tr Z '\0' > file
+
+test_expect_success 'force diff with "diff"' '
+       echo >.gitattributes "file diff" &&
+       git diff | grep -a second
+'
+
 test_done
index 7b81c32e57f502f2c6d952bd9b7e6b432e092372..435f65b370e8855c4aca6adfbf12c098338f3b45 100755 (executable)
@@ -3,45 +3,44 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-apply --stat --summary test.
+test_description='git apply --stat --summary test.
 
 '
 . ./test-lib.sh
 
 test_expect_success \
     'rename' \
-    'git-apply --stat --summary <../t4100/t-apply-1.patch >current &&
+    'git apply --stat --summary <../t4100/t-apply-1.patch >current &&
     git diff ../t4100/t-apply-1.expect current'
 
 test_expect_success \
     'copy' \
-    'git-apply --stat --summary <../t4100/t-apply-2.patch >current &&
+    'git apply --stat --summary <../t4100/t-apply-2.patch >current &&
     git diff ../t4100/t-apply-2.expect current'
 
 test_expect_success \
     'rewrite' \
-    'git-apply --stat --summary <../t4100/t-apply-3.patch >current &&
+    'git apply --stat --summary <../t4100/t-apply-3.patch >current &&
     git diff ../t4100/t-apply-3.expect current'
 
 test_expect_success \
     'mode' \
-    'git-apply --stat --summary <../t4100/t-apply-4.patch >current &&
+    'git apply --stat --summary <../t4100/t-apply-4.patch >current &&
     git diff ../t4100/t-apply-4.expect current'
 
 test_expect_success \
     'non git' \
-    'git-apply --stat --summary <../t4100/t-apply-5.patch >current &&
+    'git apply --stat --summary <../t4100/t-apply-5.patch >current &&
     git diff ../t4100/t-apply-5.expect current'
 
 test_expect_success \
     'non git' \
-    'git-apply --stat --summary <../t4100/t-apply-6.patch >current &&
+    'git apply --stat --summary <../t4100/t-apply-6.patch >current &&
     git diff ../t4100/t-apply-6.expect current'
 
 test_expect_success \
     'non git' \
-    'git-apply --stat --summary <../t4100/t-apply-7.patch >current &&
+    'git apply --stat --summary <../t4100/t-apply-7.patch >current &&
     git diff ../t4100/t-apply-7.expect current'
 
 test_done
-
index 026fac8c5534c5a269c1a89088bbe97a4dd30b87..da8abcf36418dbd2e9d8ec85871c245991f96fda 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-apply should handle files with incomplete lines.
+test_description='git apply should handle files with incomplete lines.
 
 '
 . ./test-lib.sh
@@ -23,7 +23,7 @@ do
     cat frotz.$i >frotz
     test_expect_success \
         "apply diff between $i and $j" \
-       "git-apply <../t4101/diff.$i-$j && diff frotz.$j frotz"
+       "git apply <../t4101/diff.$i-$j && diff frotz.$j frotz"
   done
 done
 
index b4662b03647bd2f36c07ffac24adc6b5df5eef76..d42abff1ad59343fa1c84bded9a82c3212370da0 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-apply handling copy/rename patch.
+test_description='git apply handling copy/rename patch.
 
 '
 . ./test-lib.sh
@@ -26,10 +26,10 @@ echo 'This is foo' >foo
 chmod +x foo
 
 test_expect_success setup \
-    'git-update-index --add foo'
+    'git update-index --add foo'
 
 test_expect_success apply \
-    'git-apply --index --stat --summary --apply test-patch'
+    'git apply --index --stat --summary --apply test-patch'
 
 if [ "$(git config --get core.filemode)" = false ]
 then
@@ -40,7 +40,7 @@ else
 fi
 
 test_expect_success 'apply reverse' \
-    'git-apply -R --index --stat --summary --apply test-patch &&
+    'git apply -R --index --stat --summary --apply test-patch &&
      test "$(cat foo)" = "This is foo"'
 
 cat >test-patch <<\EOF
@@ -56,7 +56,7 @@ copy to bar
 EOF
 
 test_expect_success 'apply copy' \
-    'git-apply --index --stat --summary --apply test-patch &&
+    'git apply --index --stat --summary --apply test-patch &&
      test "$(cat bar)" = "This is bar" -a "$(cat foo)" = "This is foo"'
 
 test_done
index e2b1124c78540ed9613877d10eed3641268c2c8f..011126f336d4f15600ea8905b3a5b1d4c69c9a6b 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-apply handling binary patches
+test_description='git apply handling binary patches
 
 '
 . ./test-lib.sh
@@ -20,55 +20,55 @@ EOF
 cat file1 >file2
 cat file1 >file4
 
-git-update-index --add --remove file1 file2 file4
+git update-index --add --remove file1 file2 file4
 git-commit -m 'Initial Version' 2>/dev/null
 
 git-checkout -b binary
 tr 'x' '\0' <file1 >file3
 cat file3 >file4
-git-add file2
+git add file2
 tr '\0' 'v' <file3 >file1
 rm -f file2
-git-update-index --add --remove file1 file2 file3 file4
+git update-index --add --remove file1 file2 file3 file4
 git-commit -m 'Second Version'
 
-git-diff-tree -p master binary >B.diff
-git-diff-tree -p -C master binary >C.diff
+git diff-tree -p master binary >B.diff
+git diff-tree -p -C master binary >C.diff
 
-git-diff-tree -p --binary master binary >BF.diff
-git-diff-tree -p --binary -C master binary >CF.diff
+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-apply --stat --summary B.diff'
+        git apply --stat --summary B.diff'
 
 test_expect_success 'stat binary diff (copy) -- should not fail.' \
        'git-checkout master
-        git-apply --stat --summary C.diff'
+        git apply --stat --summary C.diff'
 
 test_expect_failure 'check binary diff -- should fail.' \
        'git-checkout master
-        git-apply --check B.diff'
+        git apply --check B.diff'
 
 test_expect_failure 'check binary diff (copy) -- should fail.' \
        'git-checkout master
-        git-apply --check C.diff'
+        git apply --check C.diff'
 
 test_expect_failure 'check incomplete binary diff with replacement -- should fail.' \
        'git-checkout master
-        git-apply --check --allow-binary-replacement B.diff'
+        git apply --check --allow-binary-replacement B.diff'
 
 test_expect_failure 'check incomplete binary diff with replacement (copy) -- should fail.' \
        'git-checkout master
-        git-apply --check --allow-binary-replacement C.diff'
+        git apply --check --allow-binary-replacement C.diff'
 
 test_expect_success 'check binary diff with replacement.' \
        'git-checkout master
-        git-apply --check --allow-binary-replacement BF.diff'
+        git apply --check --allow-binary-replacement BF.diff'
 
 test_expect_success 'check binary diff with replacement (copy).' \
        'git-checkout master
-        git-apply --check --allow-binary-replacement CF.diff'
+        git apply --check --allow-binary-replacement CF.diff'
 
 # Now we start applying them.
 
@@ -80,36 +80,36 @@ do_reset () {
 
 test_expect_failure 'apply binary diff -- should fail.' \
        'do_reset
-        git-apply B.diff'
+        git apply B.diff'
 
 test_expect_failure 'apply binary diff -- should fail.' \
        'do_reset
-        git-apply --index B.diff'
+        git apply --index B.diff'
 
 test_expect_failure 'apply binary diff (copy) -- should fail.' \
        'do_reset
-        git-apply C.diff'
+        git apply C.diff'
 
 test_expect_failure 'apply binary diff (copy) -- should fail.' \
        'do_reset
-        git-apply --index C.diff'
+        git apply --index C.diff'
 
 test_expect_success 'apply binary diff without replacement.' \
        'do_reset
-        git-apply BF.diff'
+        git apply BF.diff'
 
 test_expect_success 'apply binary diff without replacement (copy).' \
        'do_reset
-        git-apply CF.diff'
+        git apply CF.diff'
 
 test_expect_success 'apply binary diff.' \
        'do_reset
-        git-apply --allow-binary-replacement --index BF.diff &&
-        test -z "$(git-diff --name-status binary)"'
+        git apply --allow-binary-replacement --index BF.diff &&
+        test -z "$(git diff --name-status binary)"'
 
 test_expect_success 'apply binary diff (copy).' \
        'do_reset
-        git-apply --allow-binary-replacement --index CF.diff &&
-        test -z "$(git-diff --name-status binary)"'
+        git apply --allow-binary-replacement --index CF.diff &&
+        test -z "$(git diff --name-status binary)"'
 
 test_done
index a5fb3ea40e4fde9126e66ed46fd3fc337b40ff66..64f34e329867cbef3c122c96a63cfd844b0953af 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-apply boundary tests
+test_description='git apply boundary tests
 
 '
 . ./test-lib.sh
index 5988e1ae4c0b394adfa743a159c32024db62bf1e..bd40a218cd81fdcb4417cb693cfbf047bc0e64c7 100755 (executable)
@@ -4,7 +4,7 @@
 # Copyright (c) 2005 Robert Fitzsimons
 #
 
-test_description='git-apply test patches with multiple fragments.
+test_description='git apply test patches with multiple fragments.
 
 '
 . ./test-lib.sh
@@ -138,8 +138,8 @@ diff --git a/main.c b/main.c
  
 EOF
 
-test_expect_success "S = git-apply (1)" \
-    'git-apply patch1.patch patch2.patch'
+test_expect_success "S = git apply (1)" \
+    'git apply patch1.patch patch2.patch'
 mv main.c main.c.git
 
 test_expect_success "S = patch (1)" \
@@ -150,8 +150,8 @@ test_expect_success "S = cmp (1)" \
 
 rm -f main.c main.c.git
 
-test_expect_success "S = git-apply (2)" \
-    'git-apply patch1.patch patch2.patch patch3.patch'
+test_expect_success "S = git apply (2)" \
+    'git apply patch1.patch patch2.patch patch3.patch'
 mv main.c main.c.git
 
 test_expect_success "S = patch (2)" \
@@ -162,8 +162,8 @@ test_expect_success "S = cmp (2)" \
 
 rm -f main.c main.c.git
 
-test_expect_success "S = git-apply (3)" \
-    'git-apply patch1.patch patch4.patch'
+test_expect_success "S = git apply (3)" \
+    'git apply patch1.patch patch4.patch'
 mv main.c main.c.git
 
 test_expect_success "S = patch (3)" \
index 005f74481625e88a4f36bd5f17d339c1924778c4..db60652a37085352837567cf8bf4b6cabb860b61 100755 (executable)
@@ -4,7 +4,7 @@
 # Copyright (c) 2005 Robert Fitzsimons
 #
 
-test_description='git-apply test for patches which require scanning forwards and backwards.
+test_description='git apply test for patches which require scanning forwards and backwards.
 
 '
 . ./test-lib.sh
@@ -86,8 +86,8 @@ diff --git a/new.txt b/new.txt
 +c2222
 EOF
 
-test_expect_success "S = git-apply scan" \
-    'git-apply patch1.patch patch2.patch patch3.patch patch4.patch patch5.patch'
+test_expect_success "S = git apply scan" \
+    'git apply patch1.patch patch2.patch patch3.patch patch4.patch patch5.patch'
 mv new.txt apply.txt
 
 test_expect_success "S = patch scan" \
@@ -98,4 +98,3 @@ test_expect_success "S = cmp" \
     'cmp apply.txt patch.txt'
 
 test_done
-
index 69e9603c784b580ff143e4249c72aea79f64f471..70a1859503c7ee6a5b1a6db19174c1c359eec13f 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-apply should not get confused with rename/copy.
+test_description='git apply should not get confused with rename/copy.
 
 '
 
@@ -49,10 +49,10 @@ copy to include/arch/cris/klibc/archsetjmp.h
 - * arch/x86_64/include/klibc/archsetjmp.h
 + * arch/cris/include/klibc/archsetjmp.h
   */
+
  #ifndef _KLIBC_ARCHSETJMP_H
  #define _KLIBC_ARCHSETJMP_H
+
  struct __jmp_buf {
 -  unsigned long __rbx;
 -  unsigned long __rsp;
@@ -74,9 +74,9 @@ copy to include/arch/cris/klibc/archsetjmp.h
 +  unsigned long __sp;
 +  unsigned long __srp;
  };
+
  typedef struct __jmp_buf jmp_buf[1];
+
 -#endif /* _SETJMP_H */
 +#endif /* _KLIBC_ARCHSETJMP_H */
 diff --git a/klibc/arch/x86_64/include/klibc/archsetjmp.h b/include/arch/m32r/klibc/archsetjmp.h
@@ -90,10 +90,10 @@ rename to include/arch/m32r/klibc/archsetjmp.h
 - * arch/x86_64/include/klibc/archsetjmp.h
 + * arch/m32r/include/klibc/archsetjmp.h
   */
+
  #ifndef _KLIBC_ARCHSETJMP_H
  #define _KLIBC_ARCHSETJMP_H
+
  struct __jmp_buf {
 -  unsigned long __rbx;
 -  unsigned long __rsp;
@@ -108,17 +108,17 @@ rename to include/arch/m32r/klibc/archsetjmp.h
    unsigned long __r15;
 -  unsigned long __rip;
  };
+
  typedef struct __jmp_buf jmp_buf[1];
+
 -#endif /* _SETJMP_H */
 +#endif /* _KLIBC_ARCHSETJMP_H */
 EOF
 
-find klibc -type f -print | xargs git-update-index --add --
+find klibc -type f -print | xargs git update-index --add --
 
-test_expect_success 'check rename/copy patch' 'git-apply --check patch'
+test_expect_success 'check rename/copy patch' 'git apply --check patch'
 
-test_expect_success 'apply rename/copy patch' 'git-apply --index patch'
+test_expect_success 'apply rename/copy patch' 'git apply --index patch'
 
 test_done
index 7fd0cf62ecd1bc0723f8ad7b619e8df4afcb0acc..1c6bec044a00faf24e275280e0b9fa667356f2b3 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2006 Catalin Marinas
 #
 
-test_description='git-apply trying to add an ending line.
+test_description='git apply trying to add an ending line.
 
 '
 . ./test-lib.sh
@@ -25,12 +25,12 @@ echo 'b' >>file
 echo 'c' >>file
 
 test_expect_success setup \
-    'git-update-index --add file'
+    'git update-index --add file'
 
 # test
 
 test_expect_failure 'apply at the end' \
-    'git-apply --index test-patch'
+    'git apply --index test-patch'
 
 cat >test-patch <<\EOF
 diff a/file b/file
@@ -45,9 +45,9 @@ EOF
 echo >file 'a
 b
 c'
-git-update-index file
+git update-index file
 
 test_expect_failure 'apply at the beginning' \
-       'git-apply --index test-patch'
+       'git apply --index test-patch'
 
 test_done
index ca81d7215710c274ca681bcb90991afa8cba5974..55334927abb33864a55f8ff49fd0c0c94a3c1769 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2006 Eric Wong
 #
 
-test_description='git-apply should not get confused with type changes.
+test_description='git apply should not get confused with type changes.
 
 '
 
index b947ed83bb1b1d61690df1140ede337b15cb04ed..a07ff42c2ff8e9a918d83435043a73f6404a9a9e 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-apply symlinks and partial files
+test_description='git apply symlinks and partial files
 
 '
 
index 11e02807a5324ad263c9b2bce53be3df9daf2117..9ae2b3a8efaad4430bbcea02152470b064263b2b 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-apply in reverse
+test_description='git apply in reverse
 
 '
 
index 91931f0e3fde4874c865aa8dd44615b415d324ee..659e17c92e474ad5828656f83d28cab2a5ecac64 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-apply with rejects
+test_description='git apply with rejects
 
 '
 
index 27cc6f2b88974051cd521755800342e375d84af7..1d531caf798b9e8dfbe17714ad1eb09be14f7f93 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2006 Junio C Hamano
 #
 
-test_description='git-apply with new style GNU diff with empty context
+test_description='git apply with new style GNU diff with empty context
 
 '
 
@@ -53,4 +53,3 @@ test_expect_success 'apply --apply' '
 '
 
 test_done
-
index 620a9207bf14f5a7e2506742f1e7d0ddb91d0a78..65571e05496eb3710cb89d93f5b95d34b77d1998 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2007 Junio C Hamano
 #
 
-test_description='git-apply --whitespace=strip and configuration file.
+test_description='git apply --whitespace=strip and configuration file.
 
 '
 
@@ -24,7 +24,7 @@ cat >gpatch.file <<\EOF &&
 +++ file1+     2007-02-21 01:07:44.000000000 -0800
 @@ -1 +1 @@
 -A
-+B 
++B
 EOF
 
 sed -e 's|file1|sub/&|' gpatch.file >gpatch-sub.file &&
index 2f672f30d424ace13d24236a0a9e90324cb2b4da..83d4ba679850c2ae2548bcfcce3f22227fcde8c7 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2007 Shawn O. Pearce
 #
 
-test_description='git-apply -p handling.'
+test_description='git apply -p handling.'
 
 . ./test-lib.sh
 
index 2b2f1eda21c647c5c8aa0f0d2b41cecf8d90f6c4..aff551a1d787477eb2db34d96217f66ca03c435d 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='git-apply for contextually independent diffs'
+test_description='git apply for contextually independent diffs'
 . ./test-lib.sh
 
 echo '1
@@ -30,4 +30,3 @@ test_expect_success \
        '( git diff test~2 test~1; git diff test~1 test~0 )| git apply'
 
 test_done
-
index 3ddfe64b02490c2fa2e8cf7445aa518e0de8bf1b..841773f75fc085d07836b39b3775f49bde5d8d19 100755 (executable)
@@ -53,4 +53,3 @@ test_expect_success 'check result' '
 '
 
 test_done
-
index c64ebbb2e9e9eaf3fbb792a4f119cd9a1c2b4352..6f55ba03bd36d25c45224688f29b36e8d7734fe0 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2006 Johannes E. Schindelin
 #
 
-test_description='git-rerere
+test_description='git rerere
 '
 
 . ./test-lib.sh
@@ -39,15 +39,32 @@ sed -e 's/To die, t/To die! T/' > a1
 echo "* END *" >>a1
 git commit -q -a -m second
 
-# activate rerere
-mkdir .git/rr-cache
+test_expect_success 'nothing recorded without rerere' '
+       (rm -rf .git/rr-cache; git config rerere.enabled false) &&
+       ! git merge first &&
+       ! test -d .git/rr-cache
+'
 
-test_expect_failure 'conflicting merge' 'git pull . first'
+# activate rerere, old style
+test_expect_success 'conflicting merge' '
+       git reset --hard &&
+       mkdir .git/rr-cache &&
+       git config --unset rerere.enabled &&
+       ! git merge first
+'
 
 sha1=$(sed -e 's/      .*//' .git/rr-cache/MERGE_RR)
 rr=.git/rr-cache/$sha1
 test_expect_success 'recorded preimage' "grep ======= $rr/preimage"
 
+test_expect_success 'rerere.enabled works, too' '
+       rm -rf .git/rr-cache &&
+       git config rerere.enabled true &&
+       git reset --hard &&
+       ! git merge first &&
+       grep ======= $rr/preimage
+'
+
 test_expect_success 'no postimage or thisimage yet' \
        "test ! -f $rr/postimage -a ! -f $rr/thisimage"
 
@@ -148,5 +165,3 @@ test_expect_success 'old records rest in peace' \
        "test ! -f $rr/preimage && test ! -f $rr2/preimage"
 
 test_done
-
-
index a48733cee03d4f4728ad12304b718f9a412c0f71..10a5fa9a3a2add68e883436ba22f47cfc36bc970 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2006 Johannes E. Schindelin
 #
 
-test_description='git-shortlog
+test_description='git shortlog
 '
 
 . ./test-lib.sh
index e223c074f043571ff868a2f4783c7cc155185004..1a4c53a031608a16785e6ac9a0531696156bacba 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (C) 2005 Rene Scharfe
 #
 
-test_description='git-tar-tree and git-get-tar-commit-id test
+test_description='git tar-tree and git get-tar-commit-id test
 
 This test covers the topics of file contents, commit date handling and
 commit id embedding:
@@ -13,13 +13,13 @@ commit id embedding:
   binary file (/bin/sh).  Only paths shorter than 99 characters are
   used.
 
-  git-tar-tree applies the commit date to every file in the archive it
+  git tar-tree applies the commit date to every file in the archive it
   creates.  The test sets the commit date to a specific value and checks
   if the tar archive contains that value.
 
-  When giving git-tar-tree a commit id (in contrast to a tree id) it
+  When giving git tar-tree a commit id (in contrast to a tree id) it
   embeds this commit id into the tar archive as a comment.  The test
-  checks the ability of git-get-tar-commit-id to figure it out from the
+  checks the ability of git get-tar-commit-id to figure it out from the
   tar file.
 
 '
@@ -42,23 +42,23 @@ test_expect_success \
 
 test_expect_success \
     'add files to repository' \
-    'find a -type f | xargs git-update-index --add &&
-     find a -type l | xargs git-update-index --add &&
-     treeid=`git-write-tree` &&
+    'find a -type f | xargs git update-index --add &&
+     find a -type l | xargs git update-index --add &&
+     treeid=`git write-tree` &&
      echo $treeid >treeid &&
-     git-update-ref HEAD $(TZ=GMT GIT_COMMITTER_DATE="2005-05-27 22:00:00" \
-     git-commit-tree $treeid </dev/null)'
+     git update-ref HEAD $(TZ=GMT GIT_COMMITTER_DATE="2005-05-27 22:00:00" \
+     git commit-tree $treeid </dev/null)'
 
 test_expect_success \
-    'git-archive' \
-    'git-archive HEAD >b.tar'
+    'git archive' \
+    'git archive HEAD >b.tar'
 
 test_expect_success \
-    'git-tar-tree' \
-    'git-tar-tree HEAD >b2.tar'
+    'git tar-tree' \
+    'git tar-tree HEAD >b2.tar'
 
 test_expect_success \
-    'git-archive vs. git-tar-tree' \
+    'git archive vs. git tar-tree' \
     'diff b.tar b2.tar'
 
 test_expect_success \
@@ -70,9 +70,9 @@ test_expect_success \
      diff expected.mtime b.mtime'
 
 test_expect_success \
-    'git-get-tar-commit-id' \
-    'git-get-tar-commit-id <b.tar >b.commitid &&
-     diff .git/$(git-symbolic-ref HEAD) b.commitid'
+    'git get-tar-commit-id' \
+    'git get-tar-commit-id <b.tar >b.commitid &&
+     diff .git/$(git symbolic-ref HEAD) b.commitid'
 
 test_expect_success \
     'extract tar archive' \
@@ -88,8 +88,8 @@ test_expect_success \
     'diff -r a b/a'
 
 test_expect_success \
-    'git-tar-tree with prefix' \
-    'git-tar-tree HEAD prefix >c.tar'
+    'git tar-tree with prefix' \
+    'git tar-tree HEAD prefix >c.tar'
 
 test_expect_success \
     'extract tar archive with prefix' \
@@ -105,8 +105,15 @@ test_expect_success \
     'diff -r a c/prefix/a'
 
 test_expect_success \
-    'git-archive --format=zip' \
-    'git-archive --format=zip HEAD >d.zip'
+    'git archive --format=zip' \
+    'git archive --format=zip HEAD >d.zip'
+
+$UNZIP -v >/dev/null 2>&1
+if [ $? -eq 127 ]; then
+       echo "Skipping ZIP tests, because unzip was not found"
+       test_done
+       exit
+fi
 
 test_expect_success \
     'extract ZIP archive' \
@@ -122,8 +129,8 @@ test_expect_success \
     'diff -r a d/a'
 
 test_expect_success \
-    'git-archive --format=zip with prefix' \
-    'git-archive --format=zip --prefix=prefix/ HEAD >e.zip'
+    'git archive --format=zip with prefix' \
+    'git archive --format=zip --prefix=prefix/ HEAD >e.zip'
 
 test_expect_success \
     'extract ZIP archive with prefix' \
@@ -139,7 +146,7 @@ test_expect_success \
     'diff -r a e/prefix/a'
 
 test_expect_success \
-    'git-archive --list outside of a git repo' \
-    'GIT_DIR=some/non-existing/directory git-archive --list'
+    'git archive --list outside of a git repo' \
+    'GIT_DIR=some/non-existing/directory git archive --list'
 
 test_done
index ca96918da2008e9036624fac67c6337961e3c2b0..9b1a74542a848ef702c1e6208d6ff2537b0f6ac0 100755 (executable)
@@ -3,12 +3,12 @@
 # Copyright (c) 2005 Junio C Hamano
 #
 
-test_description='git-mailinfo and git-mailsplit test'
+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. ../t5100/sample.mbox >last &&
        last=`cat last` &&
        echo total is $last &&
        test `cat last` = 8'
@@ -16,7 +16,7 @@ test_expect_success 'split sample box' \
 for mail in `echo 00*`
 do
        test_expect_success "mailinfo $mail" \
-               "git-mailinfo -u msg$mail patch$mail <$mail >info$mail &&
+               "git mailinfo -u msg$mail patch$mail <$mail >info$mail &&
                echo msg &&
                diff ../t5100/msg$mail msg$mail &&
                echo patch &&
index f336769836f794c390d6e0ddd19f98da5c7b6e40..ba7579c2510fc4a4d2de4d79037640b5df644bd6 100755 (executable)
@@ -16,26 +16,26 @@ test_expect_success \
      for i in a b c
      do
             dd if=/dev/zero bs=4k count=1 | tr "\\0" $i >$i &&
-            git-update-index --add $i || return 1
+            git update-index --add $i || return 1
      done &&
-     cat c >d && echo foo >>d && git-update-index --add d &&
-     tree=`git-write-tree` &&
-     commit=`git-commit-tree $tree </dev/null` && {
+     cat c >d && echo foo >>d && git update-index --add d &&
+     tree=`git write-tree` &&
+     commit=`git commit-tree $tree </dev/null` && {
         echo $tree &&
         echo $commit &&
-        git-ls-tree $tree | sed -e "s/.* \\([0-9a-f]*\\)       .*/\\1/"
+        git ls-tree $tree | sed -e "s/.* \\([0-9a-f]*\\)       .*/\\1/"
      } >obj-list && {
-        git-diff-tree --root -p $commit &&
+        git diff-tree --root -p $commit &&
         while read object
         do
-           t=`git-cat-file -t $object` &&
-           git-cat-file $t $object || return 1
+           t=`git cat-file -t $object` &&
+           git cat-file $t $object || return 1
         done <obj-list
      } >expect'
 
 test_expect_success \
     'pack without delta' \
-    'packname_1=$(git-pack-objects --window=0 test-1 <obj-list)'
+    'packname_1=$(git pack-objects --window=0 test-1 <obj-list)'
 
 rm -fr .git2
 mkdir .git2
@@ -44,9 +44,9 @@ test_expect_success \
     'unpack without delta' \
     "GIT_OBJECT_DIRECTORY=.git2/objects &&
      export GIT_OBJECT_DIRECTORY &&
-     git-init &&
-     git-unpack-objects -n <test-1-${packname_1}.pack &&
-     git-unpack-objects <test-1-${packname_1}.pack"
+     git init &&
+     git unpack-objects -n <test-1-${packname_1}.pack &&
+     git unpack-objects <test-1-${packname_1}.pack"
 
 unset GIT_OBJECT_DIRECTORY
 cd "$TRASH/.git2"
@@ -66,7 +66,7 @@ cd "$TRASH"
 test_expect_success \
     'pack with REF_DELTA' \
     'pwd &&
-     packname_2=$(git-pack-objects test-2 <obj-list)'
+     packname_2=$(git pack-objects test-2 <obj-list)'
 
 rm -fr .git2
 mkdir .git2
@@ -75,9 +75,9 @@ test_expect_success \
     'unpack with REF_DELTA' \
     'GIT_OBJECT_DIRECTORY=.git2/objects &&
      export GIT_OBJECT_DIRECTORY &&
-     git-init &&
-     git-unpack-objects -n <test-2-${packname_2}.pack &&
-     git-unpack-objects <test-2-${packname_2}.pack'
+     git init &&
+     git unpack-objects -n <test-2-${packname_2}.pack &&
+     git unpack-objects <test-2-${packname_2}.pack'
 
 unset GIT_OBJECT_DIRECTORY
 cd "$TRASH/.git2"
@@ -96,7 +96,7 @@ cd "$TRASH"
 test_expect_success \
     'pack with OFS_DELTA' \
     'pwd &&
-     packname_3=$(git-pack-objects --delta-base-offset test-3 <obj-list)'
+     packname_3=$(git pack-objects --delta-base-offset test-3 <obj-list)'
 
 rm -fr .git2
 mkdir .git2
@@ -105,9 +105,9 @@ test_expect_success \
     'unpack with OFS_DELTA' \
     'GIT_OBJECT_DIRECTORY=.git2/objects &&
      export GIT_OBJECT_DIRECTORY &&
-     git-init &&
-     git-unpack-objects -n <test-3-${packname_3}.pack &&
-     git-unpack-objects <test-3-${packname_3}.pack'
+     git init &&
+     git unpack-objects -n <test-3-${packname_3}.pack &&
+     git unpack-objects <test-3-${packname_3}.pack'
 
 unset GIT_OBJECT_DIRECTORY
 cd "$TRASH/.git2"
@@ -137,13 +137,13 @@ test_expect_success \
     'use packed objects' \
     'GIT_OBJECT_DIRECTORY=.git2/objects &&
      export GIT_OBJECT_DIRECTORY &&
-     git-init &&
+     git init &&
      cp test-1-${packname_1}.pack test-1-${packname_1}.idx .git2/objects/pack && {
-        git-diff-tree --root -p $commit &&
+        git diff-tree --root -p $commit &&
         while read object
         do
-           t=`git-cat-file -t $object` &&
-           git-cat-file $t $object || return 1
+           t=`git cat-file -t $object` &&
+           git cat-file $t $object || return 1
         done <obj-list
     } >current &&
     diff expect current'
@@ -154,11 +154,11 @@ test_expect_success \
      export GIT_OBJECT_DIRECTORY &&
      rm -f .git2/objects/pack/test-* &&
      cp test-2-${packname_2}.pack test-2-${packname_2}.idx .git2/objects/pack && {
-        git-diff-tree --root -p $commit &&
+        git diff-tree --root -p $commit &&
         while read object
         do
-           t=`git-cat-file -t $object` &&
-           git-cat-file $t $object || return 1
+           t=`git cat-file -t $object` &&
+           git cat-file $t $object || return 1
         done <obj-list
     } >current &&
     diff expect current'
@@ -169,11 +169,11 @@ test_expect_success \
      export GIT_OBJECT_DIRECTORY &&
      rm -f .git2/objects/pack/test-* &&
      cp test-3-${packname_3}.pack test-3-${packname_3}.idx .git2/objects/pack && {
-        git-diff-tree --root -p $commit &&
+        git diff-tree --root -p $commit &&
         while read object
         do
-           t=`git-cat-file -t $object` &&
-           git-cat-file $t $object || return 1
+           t=`git cat-file -t $object` &&
+           git cat-file $t $object || return 1
         done <obj-list
     } >current &&
     diff expect current'
@@ -182,7 +182,7 @@ unset GIT_OBJECT_DIRECTORY
 
 test_expect_success \
     'verify pack' \
-    'git-verify-pack   test-1-${packname_1}.idx \
+    'git verify-pack   test-1-${packname_1}.idx \
                        test-2-${packname_2}.idx \
                        test-3-${packname_3}.idx'
 
@@ -190,7 +190,7 @@ test_expect_success \
     'corrupt a pack and see if verify catches' \
     'cat test-1-${packname_1}.idx >test-3.idx &&
      cat test-2-${packname_2}.pack >test-3.pack &&
-     if git-verify-pack test-3.idx
+     if git verify-pack test-3.idx
      then false
      else :;
      fi &&
@@ -198,7 +198,7 @@ test_expect_success \
      : PACK_SIGNATURE &&
      cat test-1-${packname_1}.pack >test-3.pack &&
      dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=2 &&
-     if git-verify-pack test-3.idx
+     if git verify-pack test-3.idx
      then false
      else :;
      fi &&
@@ -206,7 +206,7 @@ test_expect_success \
      : PACK_VERSION &&
      cat test-1-${packname_1}.pack >test-3.pack &&
      dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=7 &&
-     if git-verify-pack test-3.idx
+     if git verify-pack test-3.idx
      then false
      else :;
      fi &&
@@ -214,7 +214,7 @@ test_expect_success \
      : TYPE/SIZE byte of the first packed object data &&
      cat test-1-${packname_1}.pack >test-3.pack &&
      dd if=/dev/zero of=test-3.pack count=1 bs=1 conv=notrunc seek=12 &&
-     if git-verify-pack test-3.idx
+     if git verify-pack test-3.idx
      then false
      else :;
      fi &&
@@ -224,7 +224,7 @@ test_expect_success \
      l=`expr $l - 20` &&
      cat test-1-${packname_1}.pack >test-3.pack &&
      dd if=/dev/zero of=test-3.idx count=20 bs=1 conv=notrunc seek=$l &&
-     if git-verify-pack test-3.pack
+     if git verify-pack test-3.pack
      then false
      else :;
      fi &&
index fce77f1255378b715c23be5978fcc13e56ba263d..073ac0c6f9dd3d06474b1b81c8c7b622dcfee663 100755 (executable)
@@ -13,48 +13,48 @@ test_expect_success \
      do
          echo $i >$i &&
          test-genrandom "$i" 32768 >>$i &&
-         git-update-index --add $i || return 1
+         git update-index --add $i || return 1
      done &&
-     echo d >d && cat c >>d && git-update-index --add d &&
-     tree=`git-write-tree` &&
-     commit1=`git-commit-tree $tree </dev/null` &&
-     git-update-ref HEAD $commit1 &&
+     echo d >d && cat c >>d && git update-index --add d &&
+     tree=`git write-tree` &&
+     commit1=`git commit-tree $tree </dev/null` &&
+     git update-ref HEAD $commit1 &&
      git-repack -a -d &&
-     test "`git-count-objects`" = "0 objects, 0 kilobytes" &&
+     test "`git count-objects`" = "0 objects, 0 kilobytes" &&
      pack1=`ls .git/objects/pack/*.pack` &&
      test -f "$pack1"'
 
 test_expect_success \
     'verify-pack -v, defaults' \
-    'git-verify-pack -v "$pack1"'
+    'git verify-pack -v "$pack1"'
 
 test_expect_success \
     'verify-pack -v, packedGitWindowSize == 1 page' \
-    'git-config core.packedGitWindowSize 512 &&
-     git-verify-pack -v "$pack1"'
+    'git config core.packedGitWindowSize 512 &&
+     git verify-pack -v "$pack1"'
 
 test_expect_success \
     'verify-pack -v, packedGit{WindowSize,Limit} == 1 page' \
-    'git-config core.packedGitWindowSize 512 &&
-     git-config core.packedGitLimit 512 &&
-     git-verify-pack -v "$pack1"'
+    'git config core.packedGitWindowSize 512 &&
+     git config core.packedGitLimit 512 &&
+     git verify-pack -v "$pack1"'
 
 test_expect_success \
     'repack -a -d, packedGit{WindowSize,Limit} == 1 page' \
-    'git-config core.packedGitWindowSize 512 &&
-     git-config core.packedGitLimit 512 &&
-     commit2=`git-commit-tree $tree -p $commit1 </dev/null` &&
-     git-update-ref HEAD $commit2 &&
+    'git config core.packedGitWindowSize 512 &&
+     git config core.packedGitLimit 512 &&
+     commit2=`git commit-tree $tree -p $commit1 </dev/null` &&
+     git update-ref HEAD $commit2 &&
      git-repack -a -d &&
-     test "`git-count-objects`" = "0 objects, 0 kilobytes" &&
+     test "`git count-objects`" = "0 objects, 0 kilobytes" &&
      pack2=`ls .git/objects/pack/*.pack` &&
      test -f "$pack2"
      test "$pack1" \!= "$pack2"'
 
 test_expect_success \
     'verify-pack -v, defaults' \
-    'git-config --unset core.packedGitWindowSize &&
-     git-config --unset core.packedGitLimit &&
-     git-verify-pack -v "$pack2"'
+    'git config --unset core.packedGitWindowSize &&
+     git config --unset core.packedGitLimit &&
+     git verify-pack -v "$pack2"'
 
 test_done
index 4d06eca6a58dc8f6cb404144a31451bdcd59af11..4f58c4c3f93b1629a564f8b23ad672100d64798d 100755 (executable)
@@ -9,34 +9,34 @@ test_description='pack index with 64-bit offsets and object CRC'
 test_expect_success \
     'setup' \
     'rm -rf .git
-     git-init &&
+     git init &&
      i=1 &&
         while test $i -le 100
      do
                 i=`printf '%03i' $i`
          echo $i >file_$i &&
          test-genrandom "$i" 8192 >>file_$i &&
-         git-update-index --add file_$i &&
+         git update-index --add file_$i &&
                 i=`expr $i + 1` || return 1
      done &&
      { echo 101 && test-genrandom 100 8192; } >file_101 &&
-     git-update-index --add file_101 &&
-     tree=`git-write-tree` &&
-     commit=`git-commit-tree $tree </dev/null` && {
+     git update-index --add file_101 &&
+     tree=`git write-tree` &&
+     commit=`git commit-tree $tree </dev/null` && {
         echo $tree &&
-        git-ls-tree $tree | sed -e "s/.* \\([0-9a-f]*\\)       .*/\\1/"
+        git ls-tree $tree | sed -e "s/.* \\([0-9a-f]*\\)       .*/\\1/"
      } >obj-list &&
-     git-update-ref HEAD $commit'
+     git update-ref HEAD $commit'
 
 test_expect_success \
     'pack-objects with index version 1' \
-    'pack1=$(git-pack-objects --index-version=1 test-1 <obj-list) &&
-     git-verify-pack -v "test-1-${pack1}.pack"'
+    'pack1=$(git pack-objects --index-version=1 test-1 <obj-list) &&
+     git verify-pack -v "test-1-${pack1}.pack"'
 
 test_expect_success \
     'pack-objects with index version 2' \
-    'pack2=$(git-pack-objects --index-version=2 test-2 <obj-list) &&
-     git-verify-pack -v "test-2-${pack2}.pack"'
+    'pack2=$(git pack-objects --index-version=2 test-2 <obj-list) &&
+     git verify-pack -v "test-2-${pack2}.pack"'
 
 test_expect_success \
     'both packs should be identical' \
@@ -61,8 +61,8 @@ test_expect_success \
 
 test_expect_success \
     'index v2: force some 64-bit offsets with pack-objects' \
-    'pack3=$(git-pack-objects --index-version=2,0x40000 test-3 <obj-list) &&
-     git-verify-pack -v "test-3-${pack3}.pack"'
+    'pack3=$(git pack-objects --index-version=2,0x40000 test-3 <obj-list) &&
+     git verify-pack -v "test-3-${pack3}.pack"'
 
 test_expect_failure \
     '64-bit offsets: should be different from previous index v2 results' \
@@ -79,22 +79,22 @@ 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-prune-packed &&
-     git-count-objects | ( read nr rest && test "$nr" -eq 1 ) &&
+     git prune-packed &&
+     git count-objects | ( read nr rest && test "$nr" -eq 1 ) &&
      cmp "test-1-${pack1}.pack" ".git/objects/pack/pack-${pack1}.pack" &&
      cmp "test-1-${pack1}.idx"  ".git/objects/pack/pack-${pack1}.idx"'
 
 test_expect_success \
     '[index v1] 2) create a stealth corruption in a delta base reference' \
     '# this test assumes a delta smaller than 16 bytes at the end of the pack
-     git-show-index <1.idx | sort -n | tail -n 1 | (
+     git show-index <1.idx | sort -n | tail -n 1 | (
        read delta_offs delta_sha1 &&
-       git-cat-file blob "$delta_sha1" > blob_1 &&
+       git cat-file blob "$delta_sha1" > blob_1 &&
        chmod +w ".git/objects/pack/pack-${pack1}.pack" &&
        dd of=".git/objects/pack/pack-${pack1}.pack" seek=$(($delta_offs + 1)) \
          if=".git/objects/pack/pack-${pack1}.idx" skip=$((256 * 4 + 4)) \
          bs=1 count=20 conv=notrunc &&
-       git-cat-file blob "$delta_sha1" > blob_2 )'
+       git cat-file blob "$delta_sha1" > blob_2 )'
 
 test_expect_failure \
     '[index v1] 3) corrupted delta happily returned wrong data' \
@@ -102,37 +102,37 @@ test_expect_failure \
 
 test_expect_failure \
     '[index v1] 4) confirm that the pack is actually corrupted' \
-    'git-fsck --full $commit'
+    'git fsck --full $commit'
 
 test_expect_success \
     '[index v1] 5) pack-objects happily reuses corrupted data' \
-    'pack4=$(git-pack-objects test-4 <obj-list) &&
+    'pack4=$(git pack-objects test-4 <obj-list) &&
      test -f "test-4-${pack1}.pack"'
 
 test_expect_failure \
     '[index v1] 6) newly created pack is BAD !' \
-    'git-verify-pack -v "test-4-${pack1}.pack"'
+    'git verify-pack -v "test-4-${pack1}.pack"'
 
 test_expect_success \
     '[index v2] 1) stream pack to repository' \
     'rm -f .git/objects/pack/* &&
      git-index-pack --index-version=2,0x40000 --stdin < "test-1-${pack1}.pack" &&
-     git-prune-packed &&
-     git-count-objects | ( read nr rest && test "$nr" -eq 1 ) &&
+     git prune-packed &&
+     git count-objects | ( read nr rest && test "$nr" -eq 1 ) &&
      cmp "test-1-${pack1}.pack" ".git/objects/pack/pack-${pack1}.pack" &&
      cmp "test-3-${pack1}.idx"  ".git/objects/pack/pack-${pack1}.idx"'
 
 test_expect_success \
     '[index v2] 2) create a stealth corruption in a delta base reference' \
     '# this test assumes a delta smaller than 16 bytes at the end of the pack
-     git-show-index <1.idx | sort -n | tail -n 1 | (
+     git show-index <1.idx | sort -n | tail -n 1 | (
        read delta_offs delta_sha1 delta_crc &&
-       git-cat-file blob "$delta_sha1" > blob_3 &&
+       git cat-file blob "$delta_sha1" > blob_3 &&
        chmod +w ".git/objects/pack/pack-${pack1}.pack" &&
        dd of=".git/objects/pack/pack-${pack1}.pack" seek=$(($delta_offs + 1)) \
          if=".git/objects/pack/pack-${pack1}.idx" skip=$((8 + 256 * 4)) \
          bs=1 count=20 conv=notrunc &&
-       git-cat-file blob "$delta_sha1" > blob_4 )'
+       git cat-file blob "$delta_sha1" > blob_4 )'
 
 test_expect_failure \
     '[index v2] 3) corrupted delta happily returned wrong data' \
@@ -140,10 +140,10 @@ test_expect_failure \
 
 test_expect_failure \
     '[index v2] 4) confirm that the pack is actually corrupted' \
-    'git-fsck --full $commit'
+    'git fsck --full $commit'
 
 test_expect_failure \
     '[index v2] 5) pack-objects refuses to reuse corrupted data' \
-    'git-pack-objects test-5 <obj-list'
+    'git pack-objects test-5 <obj-list'
 
 test_done
index 477b267599512fee5a5a3cf86687c3708ff967b8..6c8767e1df76323f406df56b39d4ba4596e0ab97 100755 (executable)
@@ -13,9 +13,9 @@ test_expect_success setup '
        test_tick &&
        mkdir mozart mozart/is &&
        echo "Commit #0" >mozart/is/pink &&
-       git-update-index --add mozart/is/pink &&
-       tree=$(git-write-tree) &&
-       commit=$(echo "Commit #0" | git-commit-tree $tree) &&
+       git update-index --add mozart/is/pink &&
+       tree=$(git write-tree) &&
+       commit=$(echo "Commit #0" | git commit-tree $tree) &&
        zero=$commit &&
        parent=$zero &&
        i=0 &&
@@ -24,18 +24,18 @@ test_expect_success setup '
            i=$(($i+1)) &&
            test_tick &&
            echo "Commit #$i" >mozart/is/pink &&
-           git-update-index --add mozart/is/pink &&
-           tree=$(git-write-tree) &&
-           commit=$(echo "Commit #$i" | git-commit-tree $tree -p $parent) &&
-           git-update-ref refs/tags/commit$i $commit &&
+           git update-index --add mozart/is/pink &&
+           tree=$(git write-tree) &&
+           commit=$(echo "Commit #$i" | git commit-tree $tree -p $parent) &&
+           git update-ref refs/tags/commit$i $commit &&
            parent=$commit || return 1
        done &&
-       git-update-ref HEAD "$commit" &&
+       git update-ref HEAD "$commit" &&
        git-clone ./. victim &&
        cd victim &&
-       git-log &&
+       git log &&
        cd .. &&
-       git-update-ref HEAD "$zero" &&
+       git update-ref HEAD "$zero" &&
        parent=$zero &&
        i=0 &&
        while test $i -le $cnt
@@ -43,15 +43,15 @@ test_expect_success setup '
            i=$(($i+1)) &&
            test_tick &&
            echo "Rebase #$i" >mozart/is/pink &&
-           git-update-index --add mozart/is/pink &&
-           tree=$(git-write-tree) &&
-           commit=$(echo "Rebase #$i" | git-commit-tree $tree -p $parent) &&
-           git-update-ref refs/tags/rebase$i $commit &&
+           git update-index --add mozart/is/pink &&
+           tree=$(git write-tree) &&
+           commit=$(echo "Rebase #$i" | git commit-tree $tree -p $parent) &&
+           git update-ref refs/tags/rebase$i $commit &&
            parent=$commit || return 1
        done &&
-       git-update-ref HEAD "$commit" &&
+       git update-ref HEAD "$commit" &&
        echo Rebase &&
-       git-log'
+       git log'
 
 test_expect_success 'pack the source repository' '
        git repack -a -d &&
@@ -66,7 +66,7 @@ test_expect_success 'pack the destination repository' '
 '
 
 test_expect_success \
-        'pushing rewound head should not barf but require --force' ' 
+        'pushing rewound head should not barf but require --force' '
        # should not fail but refuse to update.
        if git-send-pack ./victim/.git/ master
        then
@@ -106,9 +106,9 @@ export HOME ;# this way we force the victim/.git/config to be used.
 test_expect_success \
         'pushing with --force should be denied with denyNonFastforwards' '
        cd victim &&
-       git-config receive.denyNonFastforwards true &&
+       git config receive.denyNonFastforwards true &&
        cd .. &&
-       git-update-ref refs/heads/master master^ || return 1
+       git update-ref refs/heads/master master^ || return 1
        git-send-pack --force ./victim/.git/ master && return 1
        ! git diff .git/refs/heads/master victim/.git/refs/heads/master
 '
index f1c7ff0c0a8082d260b136fa641a3f109172b7e6..c5dd30d0a43a708722cf4868a83c48290f9b9c9b 100755 (executable)
@@ -8,19 +8,19 @@ test_description='Test the update hook infrastructure.'
 
 test_expect_success setup '
        echo This is a test. >a &&
-       git-update-index --add a &&
-       tree0=$(git-write-tree) &&
-       commit0=$(echo setup | git-commit-tree $tree0) &&
+       git update-index --add a &&
+       tree0=$(git write-tree) &&
+       commit0=$(echo setup | git commit-tree $tree0) &&
        echo We hope it works. >a &&
-       git-update-index a &&
-       tree1=$(git-write-tree) &&
-       commit1=$(echo modify | git-commit-tree $tree1 -p $commit0) &&
-       git-update-ref refs/heads/master $commit0 &&
-       git-update-ref refs/heads/tofail $commit1 &&
+       git update-index a &&
+       tree1=$(git write-tree) &&
+       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_DIR=victim/.git git-update-ref refs/heads/tofail $commit1 &&
-       git-update-ref refs/heads/master $commit1 &&
-       git-update-ref refs/heads/tofail $commit0
+       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
 '
 
 cat >victim/.git/hooks/pre-receive <<'EOF'
@@ -65,8 +65,8 @@ test_expect_failure push '
 '
 
 test_expect_success 'updated as expected' '
-       test $(GIT_DIR=victim/.git git-rev-parse master) = $commit1 &&
-       test $(GIT_DIR=victim/.git git-rev-parse tofail) = $commit1
+       test $(GIT_DIR=victim/.git git rev-parse master) = $commit1 &&
+       test $(GIT_DIR=victim/.git git rev-parse tofail) = $commit1
 '
 
 test_expect_success 'hooks ran' '
index 48e3d1705f5e4bc7f206692276b4e3e1fe1ddf66..7da515361a8af4554760f1564f72e508a9bff2a5 100755 (executable)
@@ -25,12 +25,12 @@ add () {
        done
 
        echo "$text" > test.txt
-       git-update-index --add test.txt
-       tree=$(git-write-tree)
+       git update-index --add test.txt
+       tree=$(git write-tree)
        # make sure timestamps are in correct order
        sec=$(($sec+1))
        commit=$(echo "$text" | GIT_AUTHOR_DATE=$sec \
-               git-commit-tree $tree $parents 2>>log2.txt)
+               git commit-tree $tree $parents 2>>log2.txt)
        export $name=$commit
        echo $commit > .git/refs/heads/$branch
        eval ${branch}TIP=$commit
@@ -61,19 +61,19 @@ pull_to_client () {
                "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/'`
+       git symbolic-ref HEAD refs/heads/`echo $heads | sed -e 's/^\(.\).*$/\1/'`
 
-       test_expect_success "fsck" 'git-fsck --full > fsck.txt 2>&1'
+       test_expect_success "fsck" 'git fsck --full > fsck.txt 2>&1'
 
        test_expect_success 'check downloaded results' \
        'mv .git/objects/pack/pack-* . &&
         p=`ls -1 pack-*.pack` &&
-        git-unpack-objects <$p &&
-        git-fsck --full'
+        git unpack-objects <$p &&
+        git fsck --full'
 
        test_expect_success "new object count after $number pull" \
        'idx=`echo pack-*.idx` &&
-        pack_count=`git-show-index <$idx | wc -l` &&
+        pack_count=`git show-index <$idx | wc -l` &&
         test $pack_count = $count'
        test -z "$pack_count" && pack_count=0
        if [ -z "$no_strict_count_check" ]; then
@@ -97,7 +97,7 @@ pull_to_client () {
 (
        mkdir client &&
        cd client &&
-       git-init 2>> log2.txt &&
+       git init 2>> log2.txt &&
        git config transfer.unpacklimit 0
 )
 
@@ -113,7 +113,7 @@ add B1 $A1
 
 echo $ATIP > .git/refs/heads/A
 echo $BTIP > .git/refs/heads/B
-git-symbolic-ref HEAD refs/heads/B
+git symbolic-ref HEAD refs/heads/B
 
 pull_to_client 1st "B A" $((11*3))
 
@@ -131,7 +131,7 @@ pull_to_client 3rd "A" $((1*3)) # old fails
 
 test_expect_success "clone shallow" "git-clone --depth 2 . shallow"
 
-(cd shallow; git-count-objects -v) > count.shallow
+(cd shallow; git count-objects -v) > count.shallow
 
 test_expect_success "clone shallow object count" \
        "test \"in-pack: 18\" = \"$(grep in-pack count.shallow)\""
@@ -145,7 +145,7 @@ test_expect_success "clone shallow object count (part 2)" '
 '
 
 test_expect_success "fsck in shallow repo" \
-       "(cd shallow; git-fsck --full)"
+       "(cd shallow; git fsck --full)"
 
 #test_done; exit
 
@@ -155,7 +155,7 @@ add B67 $B66
 test_expect_success "pull in shallow repo" \
        "(cd shallow; git pull .. B)"
 
-(cd shallow; git-count-objects -v) > count.shallow
+(cd shallow; git count-objects -v) > count.shallow
 test_expect_success "clone shallow object count" \
        "test \"count: 6\" = \"$(grep count count.shallow)\""
 
@@ -165,14 +165,14 @@ add B69 $B68
 test_expect_success "deepening pull in shallow repo" \
        "(cd shallow; git pull --depth 4 .. B)"
 
-(cd shallow; git-count-objects -v) > count.shallow
+(cd shallow; git count-objects -v) > count.shallow
 test_expect_success "clone shallow object count" \
        "test \"count: 12\" = \"$(grep count count.shallow)\""
 
 test_expect_success "deepening fetch in shallow repo" \
        "(cd shallow; git fetch --depth 4 .. A:A)"
 
-(cd shallow; git-count-objects -v) > count.shallow
+(cd shallow; git count-objects -v) > count.shallow
 test_expect_success "clone shallow object count" \
        "test \"count: 18\" = \"$(grep count count.shallow)\""
 
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
new file mode 100755 (executable)
index 0000000..ca46aaf
--- /dev/null
@@ -0,0 +1,247 @@
+#!/bin/sh
+
+test_description='fetching and pushing, with or without wildcard'
+
+. ./test-lib.sh
+
+D=`pwd`
+
+mk_empty () {
+       rm -fr testrepo &&
+       mkdir testrepo &&
+       (
+               cd testrepo &&
+               git init &&
+               mv .git/hooks .git/hooks-disabled
+       )
+}
+
+mk_test () {
+       mk_empty &&
+       (
+               for ref in "$@"
+               do
+                       git push testrepo $the_first_commit:refs/$ref || {
+                               echo "Oops, push refs/$ref failure"
+                               exit 1
+                       }
+               done &&
+               cd testrepo &&
+               for ref in "$@"
+               do
+                       r=$(git show-ref -s --verify refs/$ref) &&
+                       test "z$r" = "z$the_first_commit" || {
+                               echo "Oops, refs/$ref is wrong"
+                               exit 1
+                       }
+               done &&
+               git fsck --full
+       )
+}
+
+check_push_result () {
+       (
+               cd testrepo &&
+               it="$1" &&
+               shift
+               for ref in "$@"
+               do
+                       r=$(git show-ref -s --verify refs/$ref) &&
+                       test "z$r" = "z$it" || {
+                               echo "Oops, refs/$ref is wrong"
+                               exit 1
+                       }
+               done &&
+               git fsck --full
+       )
+}
+
+test_expect_success setup '
+
+       : >path1 &&
+       git add path1 &&
+       test_tick &&
+       git commit -a -m repo &&
+       the_first_commit=$(git show-ref -s --verify refs/heads/master) &&
+
+       : >path2 &&
+       git add path2 &&
+       test_tick &&
+       git commit -a -m second &&
+       the_commit=$(git show-ref -s --verify refs/heads/master)
+
+'
+
+test_expect_success 'fetch without wildcard' '
+       mk_empty &&
+       (
+               cd testrepo &&
+               git fetch .. refs/heads/master:refs/remotes/origin/master &&
+
+               r=$(git show-ref -s --verify refs/remotes/origin/master) &&
+               test "z$r" = "z$the_commit" &&
+
+               test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
+       )
+'
+
+test_expect_success 'fetch with wildcard' '
+       mk_empty &&
+       (
+               cd testrepo &&
+               git config remote.up.url .. &&
+               git config remote.up.fetch "refs/heads/*:refs/remotes/origin/*" &&
+               git fetch up &&
+
+               r=$(git show-ref -s --verify refs/remotes/origin/master) &&
+               test "z$r" = "z$the_commit" &&
+
+               test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
+       )
+'
+
+test_expect_success 'push without wildcard' '
+       mk_empty &&
+
+       git push testrepo refs/heads/master:refs/remotes/origin/master &&
+       (
+               cd testrepo &&
+               r=$(git show-ref -s --verify refs/remotes/origin/master) &&
+               test "z$r" = "z$the_commit" &&
+
+               test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
+       )
+'
+
+test_expect_success 'push with wildcard' '
+       mk_empty &&
+
+       git push testrepo "refs/heads/*:refs/remotes/origin/*" &&
+       (
+               cd testrepo &&
+               r=$(git show-ref -s --verify refs/remotes/origin/master) &&
+               test "z$r" = "z$the_commit" &&
+
+               test 1 = $(git for-each-ref refs/remotes/origin | wc -l)
+       )
+'
+
+test_expect_success 'push with matching heads' '
+
+       mk_test heads/master &&
+       git push testrepo &&
+       check_push_result $the_commit heads/master
+
+'
+
+test_expect_success 'push with no ambiguity (1)' '
+
+       mk_test heads/master &&
+       git push testrepo master:master &&
+       check_push_result $the_commit heads/master
+
+'
+
+test_expect_success 'push with no ambiguity (2)' '
+
+       mk_test remotes/origin/master &&
+       git push testrepo master:master &&
+       check_push_result $the_commit remotes/origin/master
+
+'
+
+test_expect_success 'push with weak ambiguity (1)' '
+
+       mk_test heads/master remotes/origin/master &&
+       git push testrepo master:master &&
+       check_push_result $the_commit heads/master &&
+       check_push_result $the_first_commit remotes/origin/master
+
+'
+
+test_expect_success 'push with weak ambiguity (2)' '
+
+       mk_test heads/master remotes/origin/master remotes/another/master &&
+       git push testrepo master:master &&
+       check_push_result $the_commit heads/master &&
+       check_push_result $the_first_commit remotes/origin/master remotes/another/master
+
+'
+
+test_expect_success 'push with ambiguity (1)' '
+
+       mk_test remotes/origin/master remotes/frotz/master &&
+       if git push testrepo master:master
+       then
+               echo "Oops, should have failed"
+               false
+       else
+               check_push_result $the_first_commit remotes/origin/master remotes/frotz/master
+       fi
+'
+
+test_expect_success 'push with ambiguity (2)' '
+
+       mk_test heads/frotz tags/frotz &&
+       if git push testrepo master:frotz
+       then
+               echo "Oops, should have failed"
+               false
+       else
+               check_push_result $the_first_commit heads/frotz tags/frotz
+       fi
+
+'
+
+test_expect_success 'push with colon-less refspec (1)' '
+
+       mk_test heads/frotz tags/frotz &&
+       git branch -f frotz master &&
+       git push testrepo frotz &&
+       check_push_result $the_commit heads/frotz &&
+       check_push_result $the_first_commit tags/frotz
+
+'
+
+test_expect_success 'push with colon-less refspec (2)' '
+
+       mk_test heads/frotz tags/frotz &&
+       if git show-ref --verify -q refs/heads/frotz
+       then
+               git branch -D frotz
+       fi &&
+       git tag -f frotz &&
+       git push testrepo frotz &&
+       check_push_result $the_commit tags/frotz &&
+       check_push_result $the_first_commit heads/frotz
+
+'
+
+test_expect_success 'push with colon-less refspec (3)' '
+
+       mk_test &&
+       if git show-ref --verify -q refs/tags/frotz
+       then
+               git tag -d frotz
+       fi &&
+       git branch -f frotz master &&
+       git push testrepo frotz &&
+       check_push_result $the_commit heads/frotz &&
+       test 1 = $( cd testrepo && git show-ref | wc -l )
+'
+
+test_expect_success 'push with colon-less refspec (4)' '
+
+       mk_test &&
+       if git show-ref --verify -q refs/heads/frotz
+       then
+               git branch -D frotz
+       fi &&
+       git tag -f frotz &&
+       git push testrepo frotz &&
+       check_push_result $the_commit tags/frotz &&
+       test 1 = $( cd testrepo && git show-ref | wc -l )
+
+'
+
+test_done
index 243212d3dac03c19db18e9c8fcfc3b9049137cdd..93eaf2c1544b5374dbe8043c66478a0a80b0bb82 100755 (executable)
@@ -54,4 +54,3 @@ test_expect_success 'the default remote . should not break explicit pull' '
 '
 
 test_done
-
index 2f8e97cb7ea4b8bdf56d5795d512534d504d25c0..699df6ebd8b6e76f95b255783c892de23610e504 100755 (executable)
@@ -104,4 +104,3 @@ test_valid_repo'
 cd "$base_dir"
 
 test_done
-
index d40262159bce36e78dd56d931eaf1d007ef77da8..180633e1e0e37c59eeaa571ad7f7b292f35415ec 100755 (executable)
@@ -17,17 +17,17 @@ unique_commit()
        _text=$1
         _tree=$2
        shift 2
-       echo $_text | git-commit-tree $(tag $_tree) "$@"
+       echo $_text | git commit-tree $(tag $_tree) "$@"
 }
 
 # Save the output of a command into the tag specified. Prepend
 # a substitution script for the tag onto the front of sed.script
 save_tag()
 {
-       _tag=$1 
+       _tag=$1
        [ -n "$_tag" ] || error "usage: save_tag tag commit-args ..."
        shift 1
-       "$@" >.git/refs/tags/$_tag
+       "$@" >.git/refs/tags/$_tag
 
         echo "s/$(tag $_tag)/$_tag/g" > sed.script.tmp
        cat sed.script >> sed.script.tmp
@@ -35,7 +35,7 @@ save_tag()
        mv sed.script.tmp sed.script
 }
 
-# Replace unhelpful sha1 hashses with their symbolic equivalents 
+# Replace unhelpful sha1 hashses with their symbolic equivalents
 entag()
 {
        sed -f sed.script
@@ -62,7 +62,7 @@ as_author()
 commit_date()
 {
         _commit=$1
-       git-cat-file commit $_commit | sed -n "s/^committer .*> \([0-9]*\) .*/\1/p" 
+       git cat-file commit $_commit | sed -n "s/^committer .*> \([0-9]*\) .*/\1/p"
 }
 
 on_committer_date()
@@ -103,14 +103,14 @@ name_from_description()
 
 # Execute the test described by the first argument, by eval'ing
 # command line specified in the 2nd argument. Check the status code
-# is zero and that the output matches the stream read from 
+# is zero and that the output matches the stream read from
 # stdin.
 test_output_expect_success()
-{      
+{
        _description=$1
         _test=$2
         [ $# -eq 2 ] || error "usage: test_output_expect_success description test <<EOF ... EOF"
         _name=$(echo $_description | name_from_description)
        cat > $_name.expected
-       test_expect_success "$_description" "check_output $_name \"$_test\"" 
+       test_expect_success "$_description" "check_output $_name \"$_test\""
 }
index fcb33027648b8449cba5869cbe808a4e26ff7f2d..8f5de097ecd703ae5f6f889ecb735f7277f361be 100755 (executable)
@@ -2,7 +2,7 @@
 #
 # Copyright (c) 2005 Jon Seymour
 #
-test_description='Tests git-rev-list --bisect functionality'
+test_description='Tests git rev-list --bisect functionality'
 
 . ./test-lib.sh
 . ../t6000lib.sh # t6xxx specific functions
@@ -16,17 +16,17 @@ test_bisection_diff()
        _max_diff=$1
        _bisect_option=$2
        shift 2
-       _bisection=$(git-rev-list $_bisect_option "$@")
-       _list_size=$(git-rev-list "$@" | wc -l)
+       _bisection=$(git rev-list $_bisect_option "$@")
+       _list_size=$(git rev-list "$@" | wc -l)
         _head=$1
        shift 1
-       _bisection_size=$(git-rev-list $_bisection "$@" | wc -l)
+       _bisection_size=$(git rev-list $_bisection "$@" | wc -l)
        [ -n "$_list_size" -a -n "$_bisection_size" ] ||
        error "test_bisection_diff failed"
 
        # Test if bisection size is close to half of list size within
        # tolerance.
-       # 
+       #
        _bisect_err=`expr $_list_size - $_bisection_size \* 2`
        test "$_bisect_err" -lt 0 && _bisect_err=`expr 0 - $_bisect_err`
        _bisect_err=`expr $_bisect_err / 2` ; # floor
@@ -37,8 +37,8 @@ test_bisection_diff()
 }
 
 date >path0
-git-update-index --add path0
-save_tag tree git-write-tree
+git update-index --add path0
+save_tag tree git write-tree
 on_committer_date "1971-08-16 00:00:00" hide_error save_tag root unique_commit root tree
 on_committer_date "1971-08-16 00:00:01" save_tag l0 unique_commit l0 tree -p root
 on_committer_date "1971-08-16 00:00:02" save_tag l1 unique_commit l1 tree -p l0
@@ -58,7 +58,7 @@ on_committer_date "1971-08-16 00:00:15" save_tag a4 unique_commit a4 tree -p a3
 on_committer_date "1971-08-16 00:00:16" save_tag l3 unique_commit l3 tree -p a4
 on_committer_date "1971-08-16 00:00:17" save_tag l4 unique_commit l4 tree -p l3
 on_committer_date "1971-08-16 00:00:18" save_tag l5 unique_commit l5 tree -p l4
-git-update-ref HEAD $(tag l5)
+git update-ref HEAD $(tag l5)
 
 
 #     E
@@ -116,8 +116,8 @@ on_committer_date "1971-08-16 00:00:06" save_tag V unique_commit V tree -p u1 -p
 
 test_sequence()
 {
-       _bisect_option=$1       
-       
+       _bisect_option=$1
+
        test_bisection_diff 0 $_bisect_option l0 ^root
        test_bisection_diff 0 $_bisect_option l1 ^root
        test_bisection_diff 0 $_bisect_option l2 ^root
@@ -152,7 +152,7 @@ test_sequence()
        test_bisection_diff 0 $_bisect_option u3 ^U
        test_bisection_diff 0 $_bisect_option u4 ^U
        test_bisection_diff 0 $_bisect_option u5 ^U
-       
+
 #
 # the following illustrates Linus' binary bug blatt idea.
 #
@@ -163,23 +163,23 @@ test_sequence()
 # the bisection point is the head - this is the bad point.
 #
 
-test_output_expect_success "$_bisect_option l5 ^root" 'git-rev-list $_bisect_option l5 ^root' <<EOF
+test_output_expect_success "$_bisect_option l5 ^root" 'git rev-list $_bisect_option l5 ^root' <<EOF
 c3
 EOF
 
-test_output_expect_success "$_bisect_option l5 ^root ^c3" 'git-rev-list $_bisect_option l5 ^root ^c3' <<EOF
+test_output_expect_success "$_bisect_option l5 ^root ^c3" 'git rev-list $_bisect_option l5 ^root ^c3' <<EOF
 b4
 EOF
 
-test_output_expect_success "$_bisect_option l5 ^root ^c3 ^b4" 'git-rev-list $_bisect_option l5 ^c3 ^b4' <<EOF
+test_output_expect_success "$_bisect_option l5 ^root ^c3 ^b4" 'git rev-list $_bisect_option l5 ^c3 ^b4' <<EOF
 l3
 EOF
 
-test_output_expect_success "$_bisect_option l3 ^root ^c3 ^b4" 'git-rev-list $_bisect_option l3 ^root ^c3 ^b4' <<EOF
+test_output_expect_success "$_bisect_option l3 ^root ^c3 ^b4" 'git rev-list $_bisect_option l3 ^root ^c3 ^b4' <<EOF
 a4
 EOF
 
-test_output_expect_success "$_bisect_option l5 ^b3 ^a3 ^b4 ^a4" 'git-rev-list $_bisect_option l3 ^b3 ^a3 ^a4' <<EOF
+test_output_expect_success "$_bisect_option l5 ^b3 ^a3 ^b4 ^a4" 'git rev-list $_bisect_option l3 ^b3 ^a3 ^a4' <<EOF
 l3
 EOF
 
@@ -187,11 +187,11 @@ EOF
 # if l3 is bad, then l4 is bad too - so advance the bad pointer by making b4 the known bad head
 #
 
-test_output_expect_success "$_bisect_option l4 ^a2 ^a3 ^b ^a4" 'git-rev-list $_bisect_option l4 ^a2 ^a3 ^a4' <<EOF
+test_output_expect_success "$_bisect_option l4 ^a2 ^a3 ^b ^a4" 'git rev-list $_bisect_option l4 ^a2 ^a3 ^a4' <<EOF
 l3
 EOF
 
-test_output_expect_success "$_bisect_option l3 ^a2 ^a3 ^b ^a4" 'git-rev-list $_bisect_option l3 ^a2 ^a3 ^a4' <<EOF
+test_output_expect_success "$_bisect_option l3 ^a2 ^a3 ^b ^a4" 'git rev-list $_bisect_option l3 ^a2 ^a3 ^a4' <<EOF
 l3
 EOF
 
@@ -201,15 +201,15 @@ EOF
 # as another example, let's consider a4 to be the bad head, in which case
 #
 
-test_output_expect_success "$_bisect_option a4 ^a2 ^a3 ^b4" 'git-rev-list $_bisect_option a4 ^a2 ^a3 ^b4' <<EOF
+test_output_expect_success "$_bisect_option a4 ^a2 ^a3 ^b4" 'git rev-list $_bisect_option a4 ^a2 ^a3 ^b4' <<EOF
 c2
 EOF
 
-test_output_expect_success "$_bisect_option a4 ^a2 ^a3 ^b4 ^c2" 'git-rev-list $_bisect_option a4 ^a2 ^a3 ^b4 ^c2' <<EOF
+test_output_expect_success "$_bisect_option a4 ^a2 ^a3 ^b4 ^c2" 'git rev-list $_bisect_option a4 ^a2 ^a3 ^b4 ^c2' <<EOF
 c3
 EOF
 
-test_output_expect_success "$_bisect_option a4 ^a2 ^a3 ^b4 ^c2 ^c3" 'git-rev-list $_bisect_option a4 ^a2 ^a3 ^b4 ^c2 ^c3' <<EOF
+test_output_expect_success "$_bisect_option a4 ^a2 ^a3 ^b4 ^c2 ^c3" 'git rev-list $_bisect_option a4 ^a2 ^a3 ^b4 ^c2 ^c3' <<EOF
 a4
 EOF
 
@@ -219,11 +219,11 @@ EOF
 # or consider c3 to be the bad head
 #
 
-test_output_expect_success "$_bisect_option a4 ^a2 ^a3 ^b4" 'git-rev-list $_bisect_option a4 ^a2 ^a3 ^b4' <<EOF
+test_output_expect_success "$_bisect_option a4 ^a2 ^a3 ^b4" 'git rev-list $_bisect_option a4 ^a2 ^a3 ^b4' <<EOF
 c2
 EOF
 
-test_output_expect_success "$_bisect_option c3 ^a2 ^a3 ^b4 ^c2" 'git-rev-list $_bisect_option c3 ^a2 ^a3 ^b4 ^c2' <<EOF
+test_output_expect_success "$_bisect_option c3 ^a2 ^a3 ^b4 ^c2" 'git rev-list $_bisect_option c3 ^a2 ^a3 ^b4 ^c2' <<EOF
 c3
 EOF
 
index d99a9ad39e45c0020d385799c28dcd3cdc4e1eda..5daa0be8cc856bff513905bc6583854e0b5ae53a 100755 (executable)
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Jon Seymour
 #
 
-test_description='Tests git-rev-list --topo-order functionality'
+test_description='Tests git rev-list --topo-order functionality'
 
 . ./test-lib.sh
 . ../t6000lib.sh # t6xxx specific functions
@@ -14,8 +14,8 @@ list_duplicates()
 }
 
 date >path0
-git-update-index --add path0
-save_tag tree git-write-tree
+git update-index --add path0
+save_tag tree git write-tree
 on_committer_date "1971-08-16 00:00:00" hide_error save_tag root unique_commit root tree
 on_committer_date "1971-08-16 00:00:01" save_tag l0 unique_commit l0 tree -p root
 on_committer_date "1971-08-16 00:00:02" save_tag l1 unique_commit l1 tree -p l0
@@ -77,13 +77,13 @@ save_tag h2 unique_commit g4 tree -p g2
 save_tag g3 unique_commit g5 tree -p g2
 save_tag g4 unique_commit g6 tree -p g3 -p h2
 
-git-update-ref HEAD $(tag l5)
+git update-ref HEAD $(tag l5)
 
-test_output_expect_success 'rev-list has correct number of entries' 'git-rev-list HEAD | wc -l | tr -d \" \"' <<EOF
+test_output_expect_success 'rev-list has correct number of entries' 'git rev-list HEAD | wc -l | tr -d \" \"' <<EOF
 19
 EOF
 
-test_output_expect_success 'simple topo order' 'git-rev-list --topo-order  HEAD' <<EOF
+test_output_expect_success 'simple topo order' 'git rev-list --topo-order  HEAD' <<EOF
 l5
 l4
 l3
@@ -105,7 +105,7 @@ l0
 root
 EOF
 
-test_output_expect_success 'two diamonds topo order (g6)' 'git-rev-list --topo-order  g4' <<EOF
+test_output_expect_success 'two diamonds topo order (g6)' 'git rev-list --topo-order  g4' <<EOF
 g4
 h2
 g3
@@ -115,7 +115,7 @@ g1
 g0
 EOF
 
-test_output_expect_success 'multiple heads' 'git-rev-list --topo-order a3 b3 c3' <<EOF
+test_output_expect_success 'multiple heads' 'git rev-list --topo-order a3 b3 c3' <<EOF
 a3
 a2
 a1
@@ -132,7 +132,7 @@ l0
 root
 EOF
 
-test_output_expect_success 'multiple heads, prune at a1' 'git-rev-list --topo-order a3 b3 c3 ^a1' <<EOF
+test_output_expect_success 'multiple heads, prune at a1' 'git rev-list --topo-order a3 b3 c3 ^a1' <<EOF
 a3
 a2
 c3
@@ -143,7 +143,7 @@ b2
 b1
 EOF
 
-test_output_expect_success 'multiple heads, prune at l1' 'git-rev-list --topo-order a3 b3 c3 ^l1' <<EOF
+test_output_expect_success 'multiple heads, prune at l1' 'git rev-list --topo-order a3 b3 c3 ^l1' <<EOF
 a3
 a2
 a1
@@ -157,7 +157,7 @@ a0
 l2
 EOF
 
-test_output_expect_success 'cross-epoch, head at l5, prune at l1' 'git-rev-list --topo-order l5 ^l1' <<EOF
+test_output_expect_success 'cross-epoch, head at l5, prune at l1' 'git rev-list --topo-order l5 ^l1' <<EOF
 l5
 l4
 l3
@@ -176,7 +176,7 @@ a0
 l2
 EOF
 
-test_output_expect_success 'duplicated head arguments' 'git-rev-list --topo-order l5 l5 ^l1' <<EOF
+test_output_expect_success 'duplicated head arguments' 'git rev-list --topo-order l5 l5 ^l1' <<EOF
 l5
 l4
 l3
@@ -195,7 +195,7 @@ a0
 l2
 EOF
 
-test_output_expect_success 'prune near topo' 'git-rev-list --topo-order a4 ^c3' <<EOF
+test_output_expect_success 'prune near topo' 'git rev-list --topo-order a4 ^c3' <<EOF
 a4
 b4
 a3
@@ -204,52 +204,52 @@ a1
 b3
 EOF
 
-test_output_expect_success "head has no parent" 'git-rev-list --topo-order  root' <<EOF
+test_output_expect_success "head has no parent" 'git rev-list --topo-order  root' <<EOF
 root
 EOF
 
-test_output_expect_success "two nodes - one head, one base" 'git-rev-list --topo-order  l0' <<EOF
+test_output_expect_success "two nodes - one head, one base" 'git rev-list --topo-order  l0' <<EOF
 l0
 root
 EOF
 
-test_output_expect_success "three nodes one head, one internal, one base" 'git-rev-list --topo-order  l1' <<EOF
+test_output_expect_success "three nodes one head, one internal, one base" 'git rev-list --topo-order  l1' <<EOF
 l1
 l0
 root
 EOF
 
-test_output_expect_success "linear prune l2 ^root" 'git-rev-list --topo-order  l2 ^root' <<EOF
+test_output_expect_success "linear prune l2 ^root" 'git rev-list --topo-order  l2 ^root' <<EOF
 l2
 l1
 l0
 EOF
 
-test_output_expect_success "linear prune l2 ^l0" 'git-rev-list --topo-order  l2 ^l0' <<EOF
+test_output_expect_success "linear prune l2 ^l0" 'git rev-list --topo-order  l2 ^l0' <<EOF
 l2
 l1
 EOF
 
-test_output_expect_success "linear prune l2 ^l1" 'git-rev-list --topo-order  l2 ^l1' <<EOF
+test_output_expect_success "linear prune l2 ^l1" 'git rev-list --topo-order  l2 ^l1' <<EOF
 l2
 EOF
 
-test_output_expect_success "linear prune l5 ^a4" 'git-rev-list --topo-order  l5 ^a4' <<EOF
+test_output_expect_success "linear prune l5 ^a4" 'git rev-list --topo-order  l5 ^a4' <<EOF
 l5
 l4
 l3
 EOF
 
-test_output_expect_success "linear prune l5 ^l3" 'git-rev-list --topo-order  l5 ^l3' <<EOF
+test_output_expect_success "linear prune l5 ^l3" 'git rev-list --topo-order  l5 ^l3' <<EOF
 l5
 l4
 EOF
 
-test_output_expect_success "linear prune l5 ^l4" 'git-rev-list --topo-order  l5 ^l4' <<EOF
+test_output_expect_success "linear prune l5 ^l4" 'git rev-list --topo-order  l5 ^l4' <<EOF
 l5
 EOF
 
-test_output_expect_success "max-count 10 - topo order" 'git-rev-list --topo-order  --max-count=10 l5' <<EOF
+test_output_expect_success "max-count 10 - topo order" 'git rev-list --topo-order  --max-count=10 l5' <<EOF
 l5
 l4
 l3
@@ -262,7 +262,7 @@ a3
 a2
 EOF
 
-test_output_expect_success "max-count 10 - non topo order" 'git-rev-list --max-count=10 l5' <<EOF
+test_output_expect_success "max-count 10 - non topo order" 'git rev-list --max-count=10 l5' <<EOF
 l5
 l4
 l3
@@ -275,7 +275,7 @@ c2
 b3
 EOF
 
-test_output_expect_success '--max-age=c3, no --topo-order' "git-rev-list --max-age=$(commit_date c3) l5" <<EOF
+test_output_expect_success '--max-age=c3, no --topo-order' "git rev-list --max-age=$(commit_date c3) l5" <<EOF
 l5
 l4
 l3
@@ -289,7 +289,7 @@ EOF
 #
 # this test fails on --topo-order - a fix is required
 #
-#test_output_expect_success '--max-age=c3, --topo-order' "git-rev-list --topo-order --max-age=$(commit_date c3) l5" <<EOF
+#test_output_expect_success '--max-age=c3, --topo-order' "git rev-list --topo-order --max-age=$(commit_date c3) l5" <<EOF
 #l5
 #l4
 #l3
@@ -300,31 +300,31 @@ EOF
 #a2
 #EOF
 
-test_output_expect_success 'one specified head reachable from another a4, c3, --topo-order' "list_duplicates git-rev-list --topo-order a4 c3" <<EOF
+test_output_expect_success 'one specified head reachable from another a4, c3, --topo-order' "list_duplicates git rev-list --topo-order a4 c3" <<EOF
 EOF
 
-test_output_expect_success 'one specified head reachable from another c3, a4, --topo-order' "list_duplicates git-rev-list --topo-order c3 a4" <<EOF
+test_output_expect_success 'one specified head reachable from another c3, a4, --topo-order' "list_duplicates git rev-list --topo-order c3 a4" <<EOF
 EOF
 
-test_output_expect_success 'one specified head reachable from another a4, c3, no --topo-order' "list_duplicates git-rev-list a4 c3" <<EOF
+test_output_expect_success 'one specified head reachable from another a4, c3, no --topo-order' "list_duplicates git rev-list a4 c3" <<EOF
 EOF
 
-test_output_expect_success 'one specified head reachable from another c3, a4, no --topo-order' "list_duplicates git-rev-list c3 a4" <<EOF
+test_output_expect_success 'one specified head reachable from another c3, a4, no --topo-order' "list_duplicates git rev-list c3 a4" <<EOF
 EOF
 
-test_output_expect_success 'graph with c3 and a4 parents of head' "list_duplicates git-rev-list m1" <<EOF
+test_output_expect_success 'graph with c3 and a4 parents of head' "list_duplicates git rev-list m1" <<EOF
 EOF
 
-test_output_expect_success 'graph with a4 and c3 parents of head' "list_duplicates git-rev-list m2" <<EOF
+test_output_expect_success 'graph with a4 and c3 parents of head' "list_duplicates git rev-list m2" <<EOF
 EOF
 
-test_expect_success "head ^head --topo-order" 'git-rev-list --topo-order  a3 ^a3' <<EOF
+test_expect_success "head ^head --topo-order" 'git rev-list --topo-order  a3 ^a3' <<EOF
 EOF
 
-test_expect_success "head ^head no --topo-order" 'git-rev-list a3 ^a3' <<EOF
+test_expect_success "head ^head no --topo-order" 'git rev-list a3 ^a3' <<EOF
 EOF
 
-test_output_expect_success 'simple topo order (l5r1)' 'git-rev-list --topo-order  l5r1' <<EOF
+test_output_expect_success 'simple topo order (l5r1)' 'git rev-list --topo-order  l5r1' <<EOF
 l5r1
 r1
 r0
@@ -350,7 +350,7 @@ l0
 root
 EOF
 
-test_output_expect_success 'simple topo order (r1l5)' 'git-rev-list --topo-order  r1l5' <<EOF
+test_output_expect_success 'simple topo order (r1l5)' 'git rev-list --topo-order  r1l5' <<EOF
 r1l5
 l5
 l4
@@ -376,13 +376,13 @@ r0
 alt_root
 EOF
 
-test_output_expect_success "don't print things unreachable from one branch" "git-rev-list a3 ^b3 --topo-order" <<EOF
+test_output_expect_success "don't print things unreachable from one branch" "git rev-list a3 ^b3 --topo-order" <<EOF
 a3
 a2
 a1
 EOF
 
-test_output_expect_success "--topo-order a4 l3" "git-rev-list --topo-order a4 l3" <<EOF
+test_output_expect_success "--topo-order a4 l3" "git rev-list --topo-order a4 l3" <<EOF
 l3
 a4
 c3
index 761f09b1e537ebf9c24171c646e8578d99ce95fa..80d71988b8464b6abe2b13e3052b54a4bb84604f 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='git-rev-list trivial path optimization test'
+test_description='git rev-list trivial path optimization test'
 
 . ./test-lib.sh
 
@@ -12,9 +12,9 @@ initial=$(git rev-parse --verify HEAD)
 '
 
 test_expect_success path-optimization '
-    commit=$(echo "Unchanged tree" | git-commit-tree "HEAD^{tree}" -p HEAD) &&
-    test $(git-rev-list $commit | wc -l) = 2 &&
-    test $(git-rev-list $commit -- . | wc -l) = 1
+    commit=$(echo "Unchanged tree" | git commit-tree "HEAD^{tree}" -p HEAD) &&
+    test $(git rev-list $commit | wc -l) = 2 &&
+    test $(git rev-list $commit -- . | wc -l) = 1
 '
 
 test_expect_success 'further setup' '
index 334fccf58ca01d391d553f51711a448948fe86fa..0b64822bf621dee5c9544f76013c0342412eaee6 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='git-rev-list --max-count and --skip test'
+test_description='git rev-list --max-count and --skip test'
 
 . ./test-lib.sh
 
@@ -13,39 +13,39 @@ test_expect_success 'setup' '
 '
 
 test_expect_success 'no options' '
-    test $(git-rev-list HEAD | wc -l) = 5
+    test $(git rev-list HEAD | wc -l) = 5
 '
 
 test_expect_success '--max-count' '
-    test $(git-rev-list HEAD --max-count=0 | wc -l) = 0 &&
-    test $(git-rev-list HEAD --max-count=3 | wc -l) = 3 &&
-    test $(git-rev-list HEAD --max-count=5 | wc -l) = 5 &&
-    test $(git-rev-list HEAD --max-count=10 | wc -l) = 5
+    test $(git rev-list HEAD --max-count=0 | wc -l) = 0 &&
+    test $(git rev-list HEAD --max-count=3 | wc -l) = 3 &&
+    test $(git rev-list HEAD --max-count=5 | wc -l) = 5 &&
+    test $(git rev-list HEAD --max-count=10 | wc -l) = 5
 '
 
 test_expect_success '--max-count all forms' '
-    test $(git-rev-list HEAD --max-count=1 | wc -l) = 1 &&
-    test $(git-rev-list HEAD -1 | wc -l) = 1 &&
-    test $(git-rev-list HEAD -n1 | wc -l) = 1 &&
-    test $(git-rev-list HEAD -n 1 | wc -l) = 1
+    test $(git rev-list HEAD --max-count=1 | wc -l) = 1 &&
+    test $(git rev-list HEAD -1 | wc -l) = 1 &&
+    test $(git rev-list HEAD -n1 | wc -l) = 1 &&
+    test $(git rev-list HEAD -n 1 | wc -l) = 1
 '
 
 test_expect_success '--skip' '
-    test $(git-rev-list HEAD --skip=0 | wc -l) = 5 &&
-    test $(git-rev-list HEAD --skip=3 | wc -l) = 2 &&
-    test $(git-rev-list HEAD --skip=5 | wc -l) = 0 &&
-    test $(git-rev-list HEAD --skip=10 | wc -l) = 0
+    test $(git rev-list HEAD --skip=0 | wc -l) = 5 &&
+    test $(git rev-list HEAD --skip=3 | wc -l) = 2 &&
+    test $(git rev-list HEAD --skip=5 | wc -l) = 0 &&
+    test $(git rev-list HEAD --skip=10 | wc -l) = 0
 '
 
 test_expect_success '--skip --max-count' '
-    test $(git-rev-list HEAD --skip=0 --max-count=0 | wc -l) = 0 &&
-    test $(git-rev-list HEAD --skip=0 --max-count=10 | wc -l) = 5 &&
-    test $(git-rev-list HEAD --skip=3 --max-count=0 | wc -l) = 0 &&
-    test $(git-rev-list HEAD --skip=3 --max-count=1 | wc -l) = 1 &&
-    test $(git-rev-list HEAD --skip=3 --max-count=2 | wc -l) = 2 &&
-    test $(git-rev-list HEAD --skip=3 --max-count=10 | wc -l) = 2 &&
-    test $(git-rev-list HEAD --skip=5 --max-count=10 | wc -l) = 0 &&
-    test $(git-rev-list HEAD --skip=10 --max-count=10 | wc -l) = 0
+    test $(git rev-list HEAD --skip=0 --max-count=0 | wc -l) = 0 &&
+    test $(git rev-list HEAD --skip=0 --max-count=10 | wc -l) = 5 &&
+    test $(git rev-list HEAD --skip=3 --max-count=0 | wc -l) = 0 &&
+    test $(git rev-list HEAD --skip=3 --max-count=1 | wc -l) = 1 &&
+    test $(git rev-list HEAD --skip=3 --max-count=2 | wc -l) = 2 &&
+    test $(git rev-list HEAD --skip=3 --max-count=10 | wc -l) = 2 &&
+    test $(git rev-list HEAD --skip=5 --max-count=10 | wc -l) = 0 &&
+    test $(git rev-list HEAD --skip=10 --max-count=10 | wc -l) = 0
 '
 
 test_done
index aab17face8c0b326359c250bb83684ed3b894160..ad6d0b8c9da56e22b22d4fd97898f20101964e1f 100755 (executable)
@@ -1,12 +1,12 @@
 #!/bin/sh
 
-test_description='git-rev-list --pretty=format test'
+test_description='git rev-list --pretty=format test'
 
 . ./test-lib.sh
 
 test_tick
 test_expect_success 'setup' '
-touch foo && git-add foo && git-commit -m "added foo" &&
+touch foo && git add foo && git-commit -m "added foo" &&
   echo changed >foo && git-commit -a -m "changed foo"
 '
 
@@ -14,8 +14,8 @@ touch foo && git-add foo && git-commit -m "added foo" &&
 test_format() {
        cat >expect.$1
        test_expect_success "format $1" "
-git-rev-list --pretty=format:$2 master >output.$1 &&
-git-diff expect.$1 output.$1
+git rev-list --pretty=format:$2 master >output.$1 &&
+git diff expect.$1 output.$1
 "
 }
 
@@ -113,7 +113,7 @@ and it will be encoded in iso8859-1. We should therefore
 include an iso8859 character: ¡bueno!
 EOF
 test_expect_success 'setup complex body' '
-git-config i18n.commitencoding iso8859-1 &&
+git config i18n.commitencoding iso8859-1 &&
   echo change2 >foo && git-commit -a -F commit-msg
 '
 
index 22e0893056a27b4153be3eb533887b09a0396693..96f3d355301cf9e2daf58d219c3cf6cbdd118d82 100755 (executable)
@@ -8,7 +8,7 @@ test_description='Merge base computation.
 
 . ./test-lib.sh
 
-T=$(git-write-tree)
+T=$(git write-tree)
 
 M=1130000000
 Z=+0000
@@ -29,7 +29,7 @@ doit() {
        GIT_COMMITTER_DATE="$(($M + $OFFSET)) $Z"
        GIT_AUTHOR_DATE=$GIT_COMMITTER_DATE
        export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
-       commit=$(echo $NAME | git-commit-tree $T $PARENTS)
+       commit=$(echo $NAME | git commit-tree $T $PARENTS)
        echo $commit >.git/refs/tags/$NAME
        echo $commit
 }
@@ -51,16 +51,16 @@ G=$(doit 7 G $B $E)
 H=$(doit 8 H $A $F)
 
 test_expect_success 'compute merge-base (single)' \
-    'MB=$(git-merge-base G H) &&
-     expr "$(git-name-rev "$MB")" : "[0-9a-f]* tags/B"'
+    'MB=$(git merge-base G H) &&
+     expr "$(git name-rev "$MB")" : "[0-9a-f]* tags/B"'
 
 test_expect_success 'compute merge-base (all)' \
-    'MB=$(git-merge-base --all G H) &&
-     expr "$(git-name-rev "$MB")" : "[0-9a-f]* tags/B"'
+    'MB=$(git merge-base --all G H) &&
+     expr "$(git name-rev "$MB")" : "[0-9a-f]* tags/B"'
 
 test_expect_success 'compute merge-base with show-branch' \
-    'MB=$(git-show-branch --merge-base G H) &&
-     expr "$(git-name-rev "$MB")" : "[0-9a-f]* tags/B"'
+    'MB=$(git show-branch --merge-base G H) &&
+     expr "$(git name-rev "$MB")" : "[0-9a-f]* tags/B"'
 
 # Setup for second test to demonstrate that relying on timestamps in a
 # distributed SCM to provide a _consistent_ partial ordering of commits
@@ -100,11 +100,11 @@ PL=$(doit  4 PL $L2 $C2)
 PR=$(doit  4 PR $C2 $R2)
 
 test_expect_success 'compute merge-base (single)' \
-    'MB=$(git-merge-base PL PR) &&
-     expr "$(git-name-rev "$MB")" : "[0-9a-f]* tags/C2"'
+    'MB=$(git merge-base PL PR) &&
+     expr "$(git name-rev "$MB")" : "[0-9a-f]* tags/C2"'
 
 test_expect_success 'compute merge-base (all)' \
-    'MB=$(git-merge-base --all PL PR) &&
-     expr "$(git-name-rev "$MB")" : "[0-9a-f]* tags/C2"'
+    'MB=$(git merge-base --all PL PR) &&
+     expr "$(git name-rev "$MB")" : "[0-9a-f]* tags/C2"'
 
 test_done
index 499cafb882b83b780171c8601b9f4c54b294ed43..0ab14a6e81302db6a1239d68270ab909cb2fd216 100755 (executable)
@@ -20,7 +20,7 @@ test_expect_success 'prepare repository' \
 7
 8
 9" > file &&
-git add file && 
+git add file &&
 git commit -m "Initial commit" file &&
 git branch A &&
 git branch B &&
index c76fccfb5a0811aca3bb5af67f8558745935148f..ae3b6f28315d54349601a5c4e162a25949b626ec 100755 (executable)
@@ -56,18 +56,18 @@ printf "propter nomen suum." >> new4.txt
 
 cp new1.txt test.txt
 test_expect_success "merge without conflict" \
-       "git-merge-file test.txt orig.txt new2.txt"
+       "git merge-file test.txt orig.txt new2.txt"
 
 cp new1.txt test2.txt
 test_expect_success "merge without conflict (missing LF at EOF)" \
-       "git-merge-file test2.txt orig.txt new2.txt"
+       "git merge-file test2.txt orig.txt new2.txt"
 
 test_expect_success "merge result added missing LF" \
        "git diff test.txt test2.txt"
 
 cp test.txt backup.txt
 test_expect_failure "merge with conflicts" \
-       "git-merge-file test.txt orig.txt new3.txt"
+       "git merge-file test.txt orig.txt new3.txt"
 
 cat > expect.txt << EOF
 <<<<<<< test.txt
@@ -90,7 +90,7 @@ test_expect_success "expected conflict markers" "git diff test.txt expect.txt"
 
 cp backup.txt test.txt
 test_expect_failure "merge with conflicts, using -L" \
-       "git-merge-file -L 1 -L 2 test.txt orig.txt new3.txt"
+       "git merge-file -L 1 -L 2 test.txt orig.txt new3.txt"
 
 cat > expect.txt << EOF
 <<<<<<< 1
@@ -114,7 +114,7 @@ test_expect_success "expected conflict markers, with -L" \
 
 sed "s/ tu / TU /" < new1.txt > new5.txt
 test_expect_failure "conflict in removed tail" \
-       "git-merge-file -p orig.txt new1.txt new5.txt > out"
+       "git merge-file -p orig.txt new1.txt new5.txt > out"
 
 cat > expect << EOF
 Dominus regit me,
@@ -134,5 +134,9 @@ EOF
 
 test_expect_success "expected conflict markers" "git diff expect out"
 
-test_done
+test_expect_success 'binary files cannot be merged' '
+       ! git merge-file -p orig.txt ../test4012.png new1.txt 2> merge.err &&
+       grep "Cannot merge binary files" merge.err
+'
 
+test_done
index 058db9cc52521a9ba9e408c9455645d8adc4ba79..c154f03cf5f80198b9b8d19f6b0c04db11c79965 100755 (executable)
@@ -28,7 +28,7 @@ echo B > a1 &&
 GIT_AUTHOR_DATE="2006-12-12 23:00:02" git commit -m B a1 &&
 
 git checkout -b D A &&
-git-rev-parse B > .git/MERGE_HEAD &&
+git rev-parse B > .git/MERGE_HEAD &&
 echo D > a1 &&
 git update-index a1 &&
 GIT_AUTHOR_DATE="2006-12-12 23:00:03" git commit -m D &&
@@ -42,19 +42,19 @@ echo C > a1 &&
 GIT_AUTHOR_DATE="2006-12-12 23:00:05" git commit -m C a1 &&
 
 git checkout -b E C &&
-git-rev-parse B > .git/MERGE_HEAD &&
+git rev-parse B > .git/MERGE_HEAD &&
 echo E > a1 &&
 git update-index a1 &&
 GIT_AUTHOR_DATE="2006-12-12 23:00:06" git commit -m E &&
 
 git checkout -b G E &&
-git-rev-parse A > .git/MERGE_HEAD &&
+git rev-parse A > .git/MERGE_HEAD &&
 echo G > a1 &&
 git update-index a1 &&
 GIT_AUTHOR_DATE="2006-12-12 23:00:07" git commit -m G &&
 
 git checkout -b F D &&
-git-rev-parse C > .git/MERGE_HEAD &&
+git rev-parse C > .git/MERGE_HEAD &&
 echo F > a1 &&
 git update-index a1 &&
 GIT_AUTHOR_DATE="2006-12-12 23:00:08" git commit -m F
index 3c1a6972bd05608d9ed1a244996e7eb72056ed6d..950c2e9b632f59a9405ba2100eb077836223291d 100755 (executable)
@@ -12,22 +12,22 @@ if core.symlinks is false.'
 
 test_expect_success \
 'setup' '
-git-config core.symlinks false &&
+git config core.symlinks false &&
 > file &&
-git-add file &&
+git add file &&
 git-commit -m initial &&
-git-branch b-symlink &&
-git-branch b-file &&
+git branch b-symlink &&
+git branch b-file &&
 l=$(echo -n file | git-hash-object -t blob -w --stdin) &&
-echo "120000 $l        symlink" | git-update-index --index-info &&
+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) &&
-echo "120000 $l        symlink" | git-update-index --index-info &&
+echo "120000 $l        symlink" | git update-index --index-info &&
 git-commit -m b-symlink &&
 git-checkout b-file &&
 echo plain-file > symlink &&
-git-add symlink &&
+git add symlink &&
 git-commit -m b-file'
 
 test_expect_failure \
index 30f6ade13f088df1ce6c7e3649c2afb343649d65..03cdba5808aef6fbec2d95f771e6551396ff94cf 100755 (executable)
@@ -102,4 +102,3 @@ test_expect_success \
 #
 #
 test_done
-
index 7d354a1fae774ca0e77e554dad827f1a9b781818..0724864e562a53e7079c021f8b331c5b8213ac98 100755 (executable)
@@ -3,31 +3,40 @@
 # Copyright (c) 2005 Johannes Schindelin
 #
 
-test_description='Test git-rev-parse with different parent options'
+test_description='Test git rev-parse with different parent options'
 
 . ./test-lib.sh
 . ../t6000lib.sh # t6xxx specific functions
 
 date >path0
-git-update-index --add path0
-save_tag tree git-write-tree
+git update-index --add path0
+save_tag tree git write-tree
 hide_error save_tag start unique_commit "start" tree
 save_tag second unique_commit "second" tree -p start
 hide_error save_tag start2 unique_commit "start2" tree
 save_tag two_parents unique_commit "next" tree -p second -p start2
 save_tag final unique_commit "final" tree -p two_parents
 
-test_expect_success 'start is valid' 'git-rev-parse start | grep "^[0-9a-f]\{40\}$"'
-test_expect_success 'start^0' "test $(cat .git/refs/tags/start) = $(git-rev-parse start^0)"
-test_expect_success 'start^1 not valid' "if git-rev-parse --verify start^1; then false; else :; fi"
-test_expect_success 'second^1 = second^' "test $(git-rev-parse second^1) = $(git-rev-parse second^)"
-test_expect_success 'final^1^1^1' "test $(git-rev-parse start) = $(git-rev-parse final^1^1^1)"
-test_expect_success 'final^1^1^1 = final^^^' "test $(git-rev-parse final^1^1^1) = $(git-rev-parse final^^^)"
-test_expect_success 'final^1^2' "test $(git-rev-parse start2) = $(git-rev-parse final^1^2)"
-test_expect_success 'final^1^2 != final^1^1' "test $(git-rev-parse final^1^2) != $(git-rev-parse final^1^1)"
-test_expect_success 'final^1^3 not valid' "if git-rev-parse --verify final^1^3; then false; else :; fi"
-test_expect_failure '--verify start2^1' 'git-rev-parse --verify start2^1'
-test_expect_success '--verify start2^0' 'git-rev-parse --verify start2^0'
+test_expect_success 'start is valid' 'git rev-parse start | grep "^[0-9a-f]\{40\}$"'
+test_expect_success 'start^0' "test $(cat .git/refs/tags/start) = $(git rev-parse start^0)"
+test_expect_success 'start^1 not valid' "if git rev-parse --verify start^1; then false; else :; fi"
+test_expect_success 'second^1 = second^' "test $(git rev-parse second^1) = $(git rev-parse second^)"
+test_expect_success 'final^1^1^1' "test $(git rev-parse start) = $(git rev-parse final^1^1^1)"
+test_expect_success 'final^1^1^1 = final^^^' "test $(git rev-parse final^1^1^1) = $(git rev-parse final^^^)"
+test_expect_success 'final^1^2' "test $(git rev-parse start2) = $(git rev-parse final^1^2)"
+test_expect_success 'final^1^2 != final^1^1' "test $(git rev-parse final^1^2) != $(git rev-parse final^1^1)"
+test_expect_success 'final^1^3 not valid' "if git rev-parse --verify final^1^3; then false; else :; fi"
+test_expect_failure '--verify start2^1' 'git rev-parse --verify start2^1'
+test_expect_success '--verify start2^0' 'git rev-parse --verify start2^0'
 
-test_done
+test_expect_success 'repack for next test' 'git repack -a -d'
+test_expect_success 'short SHA-1 works' '
+       start=`git rev-parse --verify start` &&
+       echo $start &&
+       abbrv=`echo $start | sed s/.\$//` &&
+       echo $abbrv &&
+       abbrv=`git rev-parse --verify $abbrv` &&
+       echo $abbrv &&
+       test $start = $abbrv'
 
+test_done
index 3e9edda1ca6a0c6c8e3022c1f639f7ec7728f90f..ae8ee11183833fd4610adb1f83763eba381f7850 100755 (executable)
@@ -28,39 +28,39 @@ check_describe () {
 test_expect_success setup '
 
        test_tick &&
-       echo one >file && git-add file && git-commit -m initial &&
-       one=$(git-rev-parse HEAD) &&
+       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 &&
-       two=$(git-rev-parse HEAD) &&
+       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 &&
 
        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 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 &&
 
        test_tick &&
        git-merge -m Merged c &&
-       merged=$(git-rev-parse HEAD) &&
+       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 &&
 
@@ -77,7 +77,7 @@ test_expect_success setup '
        git-merge -m Merged $merged &&
 
        test_tick &&
-       echo X >file && echo X >side && git-add file side &&
+       echo X >file && echo X >side && git add file side &&
        git-commit -m x
 
 '
index 344033249cc1ea3f7066d4d6007ade6cc1a2c5de..8b43fb5a27af181e30a4fd125260174b7b49e3c0 100755 (executable)
@@ -1,18 +1,18 @@
 #!/bin/sh
 
-test_description='git-mv in subdirs'
+test_description='git mv in subdirs'
 . ./test-lib.sh
 
 test_expect_success \
     'prepare reference tree' \
     'mkdir path0 path1 &&
      cp ../../COPYING path0/COPYING &&
-     git-add path0/COPYING &&
+     git add path0/COPYING &&
      git-commit -m add -a'
 
 test_expect_success \
     'moving the file out of subdirectory' \
-    'cd path0 && git-mv COPYING ../path1/COPYING'
+    'cd path0 && git mv COPYING ../path1/COPYING'
 
 # in path0 currently
 test_expect_success \
@@ -21,12 +21,12 @@ test_expect_success \
 
 test_expect_success \
     'checking the commit' \
-    'git-diff-tree -r -M --name-status  HEAD^ HEAD | \
+    'git diff-tree -r -M --name-status  HEAD^ HEAD | \
     grep -E "^R100.+path0/COPYING.+path1/COPYING"'
 
 test_expect_success \
     'moving the file back into subdirectory' \
-    'cd path0 && git-mv ../path1/COPYING COPYING'
+    'cd path0 && git mv ../path1/COPYING COPYING'
 
 # in path0 currently
 test_expect_success \
@@ -35,18 +35,18 @@ test_expect_success \
 
 test_expect_success \
     'checking the commit' \
-    'git-diff-tree -r -M --name-status  HEAD^ HEAD | \
+    'git diff-tree -r -M --name-status  HEAD^ HEAD | \
     grep -E "^R100.+path1/COPYING.+path0/COPYING"'
 
 test_expect_success \
     'adding another file' \
     'cp ../../README path0/README &&
-     git-add path0/README &&
+     git add path0/README &&
      git-commit -m add2 -a'
 
 test_expect_success \
     'moving whole subdirectory' \
-    'git-mv path0 path2'
+    'git mv path0 path2'
 
 test_expect_success \
     'commiting the change' \
@@ -54,18 +54,18 @@ test_expect_success \
 
 test_expect_success \
     'checking the commit' \
-    'git-diff-tree -r -M --name-status  HEAD^ HEAD | \
+    'git diff-tree -r -M --name-status  HEAD^ HEAD | \
      grep -E "^R100.+path0/COPYING.+path2/COPYING" &&
-     git-diff-tree -r -M --name-status  HEAD^ HEAD | \
+     git diff-tree -r -M --name-status  HEAD^ HEAD | \
      grep -E "^R100.+path0/README.+path2/README"'
 
 test_expect_success \
     'succeed when source is a prefix of destination' \
-    'git-mv path2/COPYING path2/COPYING-renamed'
+    'git mv path2/COPYING path2/COPYING-renamed'
 
 test_expect_success \
     'moving whole subdirectory into subdirectory' \
-    'git-mv path2 path1'
+    'git mv path2 path1'
 
 test_expect_success \
     'commiting the change' \
@@ -73,18 +73,18 @@ test_expect_success \
 
 test_expect_success \
     'checking the commit' \
-    'git-diff-tree -r -M --name-status  HEAD^ HEAD | \
+    'git diff-tree -r -M --name-status  HEAD^ HEAD | \
      grep -E "^R100.+path2/COPYING.+path1/path2/COPYING" &&
-     git-diff-tree -r -M --name-status  HEAD^ HEAD | \
+     git diff-tree -r -M --name-status  HEAD^ HEAD | \
      grep -E "^R100.+path2/README.+path1/path2/README"'
 
 test_expect_failure \
     'do not move directory over existing directory' \
-    'mkdir path0 && mkdir path0/path2 && git-mv path2 path0'
+    'mkdir path0 && mkdir path0/path2 && git mv path2 path0'
 
 test_expect_success \
     'move into "."' \
-    'git-mv path1/path2/ .'
+    'git mv path1/path2/ .'
 
 test_expect_success "Michael Cassar's test case" '
        rm -fr .git papers partA &&
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
new file mode 100755 (executable)
index 0000000..4ddd656
--- /dev/null
@@ -0,0 +1,151 @@
+#!/bin/sh
+
+test_description='git-filter-branch'
+. ./test-lib.sh
+
+make_commit () {
+       lower=$(echo $1 | tr A-Z a-z)
+       echo $lower > $lower
+       git add $lower
+       test_tick
+       git commit -m $1
+       git tag $1
+}
+
+test_expect_success 'setup' '
+       make_commit A
+       make_commit B
+       git checkout -b branch B
+       make_commit D
+       make_commit E
+       git checkout master
+       make_commit C
+       git checkout branch
+       git merge C
+       git tag F
+       make_commit G
+       make_commit H
+'
+
+H=$(git rev-parse H)
+
+test_expect_success 'rewrite identically' '
+       git-filter-branch H2
+'
+
+test_expect_success 'result is really identical' '
+       test $H = $(git rev-parse H2)
+'
+
+test_expect_success 'rewrite, renaming a specific file' '
+       git-filter-branch --tree-filter "mv d doh || :" H3
+'
+
+test_expect_success 'test that the file was renamed' '
+       test d = $(git show H3:doh)
+'
+
+git tag oldD H3~4
+test_expect_success 'rewrite one branch, keeping a side branch' '
+       git-filter-branch --tree-filter "mv b boh || :" modD D..oldD
+'
+
+test_expect_success 'common ancestor is still common (unchanged)' '
+       test "$(git merge-base modD D)" = "$(git rev-parse B)"
+'
+
+test_expect_success 'filter subdirectory only' '
+       mkdir subdir &&
+       touch subdir/new &&
+       git add subdir/new &&
+       test_tick &&
+       git commit -m "subdir" &&
+       echo H > a &&
+       test_tick &&
+       git commit -m "not subdir" a &&
+       echo A > subdir/new &&
+       test_tick &&
+       git commit -m "again subdir" subdir/new &&
+       git rm a &&
+       test_tick &&
+       git commit -m "again not subdir" &&
+       git-filter-branch --subdirectory-filter subdir sub
+'
+
+test_expect_success 'subdirectory filter result looks okay' '
+       test 2 = $(git rev-list sub | wc -l) &&
+       git show sub:new &&
+       ! git show sub:subdir
+'
+
+test_expect_success 'setup and filter history that requires --full-history' '
+       git checkout master &&
+       mkdir subdir &&
+       echo A > subdir/new &&
+       git add subdir/new &&
+       test_tick &&
+       git commit -m "subdir on master" subdir/new &&
+       git rm a &&
+       test_tick &&
+       git commit -m "again subdir on master" &&
+       git merge branch &&
+       git-filter-branch --subdirectory-filter subdir sub-master
+'
+
+test_expect_success 'subdirectory filter result looks okay' '
+       test 3 = $(git rev-list -1 --parents sub-master | wc -w) &&
+       git show sub-master^:new &&
+       git show sub-master^2:new &&
+       ! git show sub:subdir
+'
+
+test_expect_success 'use index-filter to move into a subdirectory' '
+       git-filter-branch --index-filter \
+                "git ls-files -s | sed \"s-\\t-&newsubdir/-\" |
+                 GIT_INDEX_FILE=\$GIT_INDEX_FILE.new \
+                       git update-index --index-info &&
+                 mv \$GIT_INDEX_FILE.new \$GIT_INDEX_FILE" directorymoved &&
+       test -z "$(git diff HEAD directorymoved:newsubdir)"'
+
+test_expect_success 'stops when msg filter fails' '
+       ! git-filter-branch --msg-filter false nonono &&
+       rm -rf .git-rewrite &&
+       ! git rev-parse nonono
+'
+
+test_expect_success 'author information is preserved' '
+       : > i &&
+       git add i &&
+       test_tick &&
+       GIT_AUTHOR_NAME="B V Uips" git commit -m bvuips &&
+       git-filter-branch --msg-filter "cat; \
+                       test \$GIT_COMMIT != $(git rev-parse master) || \
+                       echo Hallo" \
+               preserved-author &&
+       test 1 = $(git rev-list --author="B V Uips" preserved-author | wc -l)
+'
+
+test_expect_success "remove a certain author's commits" '
+       echo i > i &&
+       test_tick &&
+       git commit -m i i &&
+       git-filter-branch --commit-filter "\
+               if [ \"\$GIT_AUTHOR_NAME\" = \"B V Uips\" ];\
+               then\
+                       shift;\
+                       while [ -n \"\$1\" ];\
+                       do\
+                               shift;\
+                               echo \"\$1\";\
+                               shift;\
+                       done;\
+               else\
+                       git commit-tree \"\$@\";\
+               fi" removed-author &&
+       cnt1=$(git rev-list master | wc -l) &&
+       cnt2=$(git rev-list removed-author | wc -l) &&
+       test $cnt1 -eq $(($cnt2 + 1)) &&
+       test 0 = $(git rev-list --author="B V Uips" removed-author | wc -l)
+'
+
+test_done
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
new file mode 100755 (executable)
index 0000000..b785080
--- /dev/null
@@ -0,0 +1,697 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Carlos Rica
+#
+
+test_description='git-tag
+
+Basic tests for operations with tags.'
+
+. ./test-lib.sh
+
+# creating and listing lightweight tags:
+
+tag_exists () {
+       git show-ref --quiet --verify refs/tags/"$1"
+}
+
+# todo: git tag -l now returns always zero, when fixed, change this test
+test_expect_success 'listing all tags in an empty tree should succeed' \
+       'git tag -l'
+
+test_expect_success 'listing all tags in an empty tree should output nothing' \
+       'test `git-tag -l | wc -l` -eq 0'
+
+test_expect_failure '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' '
+       ! git-tag mynotag &&
+       ! tag_exists mynotag
+'
+
+test_expect_success 'creating a tag for HEAD in an empty tree should fail' '
+       ! git-tag mytaghead HEAD &&
+       ! tag_exists mytaghead
+'
+
+test_expect_success 'creating a tag for an unknown revision should fail' '
+       ! git-tag mytagnorev aaaaaaaaaaa &&
+       ! tag_exists mytagnorev
+'
+
+# commit used in the tests, test_tick is also called here to freeze the date:
+test_expect_success 'creating a tag using default HEAD should succeed' '
+       test_tick &&
+       echo foo >foo &&
+       git add foo &&
+       git commit -m Foo &&
+       git tag mytag
+'
+
+test_expect_success 'listing all tags if one exists should succeed' \
+       'git-tag -l'
+
+test_expect_success 'listing all tags if one exists should output that tag' \
+       'test `git-tag -l` = mytag'
+
+# pattern matching:
+
+test_expect_success 'listing a tag using a matching pattern should succeed' \
+       'git-tag -l mytag'
+
+test_expect_success \
+       'listing a tag using a matching pattern should output that tag' \
+       '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'
+
+test_expect_success \
+       'listing tags using a non-matching pattern should output nothing' \
+       'test `git-tag -l xxx | wc -l` -eq 0'
+
+# special cases for creating tags:
+
+test_expect_failure \
+       'trying to create a tag with the name of one existing should fail' \
+       'git tag mytag'
+
+test_expect_success \
+       'trying to create a tag with a non-valid name should fail' '
+       test `git-tag -l | wc -l` -eq 1 &&
+       ! git tag "" &&
+       ! git tag .othertag &&
+       ! git tag "other tag" &&
+       ! git tag "othertag^" &&
+       ! git tag "other~tag" &&
+       test `git-tag -l | wc -l` -eq 1
+'
+
+test_expect_success 'creating a tag using HEAD directly should succeed' '
+       git tag myhead HEAD &&
+       tag_exists myhead
+'
+
+# deleting tags:
+
+test_expect_success 'trying to delete an unknown tag should fail' '
+       ! tag_exists unknown-tag &&
+       ! git-tag -d unknown-tag
+'
+
+cat >expect <<EOF
+myhead
+mytag
+EOF
+test_expect_success \
+       'trying to delete tags without params should succeed and do nothing' '
+       git tag -l > actual && git diff expect actual &&
+       git-tag -d &&
+       git tag -l > actual && git diff expect actual
+'
+
+test_expect_success \
+       'deleting two existing tags in one command should succeed' '
+       tag_exists mytag &&
+       tag_exists myhead &&
+       git-tag -d mytag myhead &&
+       ! tag_exists mytag &&
+       ! tag_exists myhead
+'
+
+test_expect_success \
+       'creating a tag with the name of another deleted one should succeed' '
+       ! tag_exists mytag &&
+       git-tag mytag &&
+       tag_exists mytag
+'
+
+test_expect_success \
+       'trying to delete two tags, existing and not, should fail in the 2nd' '
+       tag_exists mytag &&
+       ! tag_exists myhead &&
+       ! git-tag -d mytag anothertag &&
+       ! tag_exists mytag &&
+       ! tag_exists myhead
+'
+
+test_expect_failure 'trying to delete an already deleted tag should fail' \
+       'git-tag -d mytag'
+
+# listing various tags with pattern matching:
+
+cat >expect <<EOF
+a1
+aa1
+cba
+t210
+t211
+v0.2.1
+v1.0
+v1.0.1
+v1.1.3
+EOF
+test_expect_success 'listing all tags should print them ordered' '
+       git tag v1.0.1 &&
+       git tag t211 &&
+       git tag aa1 &&
+       git tag v0.2.1 &&
+       git tag v1.1.3 &&
+       git tag cba &&
+       git tag a1 &&
+       git tag v1.0 &&
+       git tag t210 &&
+       git tag -l > actual
+       git diff expect actual
+'
+
+cat >expect <<EOF
+a1
+aa1
+cba
+EOF
+test_expect_success \
+       'listing tags with substring as pattern must print those matching' '
+       git-tag -l a > actual &&
+       git diff expect actual
+'
+
+cat >expect <<EOF
+v0.2.1
+v1.0.1
+v1.1.3
+EOF
+test_expect_success \
+       'listing tags with substring as pattern must print those matching' '
+       git-tag -l .1 > actual &&
+       git diff expect actual
+'
+
+cat >expect <<EOF
+t210
+t211
+EOF
+test_expect_success \
+       'listing tags with substring as pattern must print those matching' '
+       git-tag -l t21 > actual &&
+       git diff expect actual
+'
+
+cat >expect <<EOF
+a1
+aa1
+EOF
+test_expect_success \
+       'listing tags using a name as pattern must print those matching' '
+       git-tag -l a1 > actual &&
+       git diff expect actual
+'
+
+cat >expect <<EOF
+v1.0
+v1.0.1
+EOF
+test_expect_success \
+       'listing tags using a name as pattern must print those matching' '
+       git-tag -l v1.0 > actual &&
+       git diff expect actual
+'
+
+cat >expect <<EOF
+v1.1.3
+EOF
+test_expect_success \
+       'listing tags with ? in the pattern should print those matching' '
+       git-tag -l "1.1?" > actual &&
+       git diff expect actual
+'
+
+>expect
+test_expect_success \
+       'listing tags using v.* should print nothing because none have v.' '
+       git-tag -l "v.*" > actual &&
+       git diff expect actual
+'
+
+cat >expect <<EOF
+v0.2.1
+v1.0
+v1.0.1
+v1.1.3
+EOF
+test_expect_success \
+       'listing tags using v* should print only those having v' '
+       git-tag -l "v*" > actual &&
+       git diff expect actual
+'
+
+# creating and verifying lightweight tags:
+
+test_expect_success \
+       'a non-annotated tag created without parameters should point to HEAD' '
+       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_failure 'trying to verify an unknown tag should fail' \
+       'git-tag -v unknown-tag'
+
+test_expect_failure \
+       'trying to verify a non-annotated and non-signed tag should fail' \
+       'git-tag -v non-annotated-tag'
+
+# creating annotated tags:
+
+get_tag_msg () {
+       git cat-file tag "$1" | sed -e "/BEGIN PGP/q"
+}
+
+# run test_tick before committing always gives the time in that timezone
+get_tag_header () {
+cat <<EOF
+object $2
+type $3
+tag $1
+tagger C O Mitter <committer@example.com> $4 -0700
+
+EOF
+}
+
+commit=$(git rev-parse HEAD)
+time=$test_tick
+
+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 &&
+       get_tag_msg annotated-tag >actual &&
+       git diff expect actual
+'
+
+cat >msgfile <<EOF
+Another message
+in a file.
+EOF
+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 &&
+       get_tag_msg file-annotated-tag >actual &&
+       git diff expect actual
+'
+
+# blank and empty messages:
+
+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 &&
+       get_tag_msg empty-annotated-tag >actual &&
+       git diff expect actual
+'
+
+>emptyfile
+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 &&
+       get_tag_msg emptyfile-annotated-tag >actual &&
+       git diff expect actual
+'
+
+printf '\n\n  \n\t\nLeading blank lines\n' >blanksfile
+printf '\n\t \t  \nRepeated blank lines\n' >>blanksfile
+printf '\n\n\nTrailing spaces      \t  \n' >>blanksfile
+printf '\nTrailing blank lines\n\n\t \n\n' >>blanksfile
+get_tag_header blanks-annotated-tag $commit commit $time >expect
+cat >>expect <<EOF
+Leading blank lines
+
+Repeated blank lines
+
+Trailing spaces
+
+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 &&
+       get_tag_msg blanks-annotated-tag >actual &&
+       git diff expect actual
+'
+
+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 &&
+       get_tag_msg blank-annotated-tag >actual &&
+       git diff expect actual
+'
+
+echo '     ' >blankfile
+echo ''      >>blankfile
+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 &&
+       get_tag_msg blankfile-annotated-tag >actual &&
+       git diff expect actual
+'
+
+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 &&
+       get_tag_msg blanknonlfile-annotated-tag >actual &&
+       git diff expect actual
+'
+
+# messages with commented lines:
+
+cat >commentsfile <<EOF
+# A comment
+
+############
+The message.
+############
+One line.
+
+
+# commented lines
+# commented lines
+
+Another line.
+# comments
+
+Last line.
+EOF
+get_tag_header comments-annotated-tag $commit commit $time >expect
+cat >>expect <<EOF
+The message.
+One line.
+
+Another line.
+
+Last line.
+EOF
+test_expect_success \
+       'creating a tag using a -F messagefile with #comments should succeed' '
+       git-tag -F commentsfile comments-annotated-tag &&
+       get_tag_msg comments-annotated-tag >actual &&
+       git diff expect actual
+'
+
+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 &&
+       get_tag_msg comment-annotated-tag >actual &&
+       git diff expect actual
+'
+
+echo '#comment' >commentfile
+echo ''         >>commentfile
+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 &&
+       get_tag_msg commentfile-annotated-tag >actual &&
+       git diff expect actual
+'
+
+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 &&
+       get_tag_msg commentnonlfile-annotated-tag >actual &&
+       git diff expect actual
+'
+
+# trying to verify annotated non-signed tags:
+
+test_expect_success \
+       'trying to verify an annotated non-signed tag should fail' '
+       tag_exists annotated-tag &&
+       ! git-tag -v annotated-tag
+'
+
+test_expect_success \
+       'trying to verify a file-annotated non-signed tag should fail' '
+       tag_exists file-annotated-tag &&
+       ! git-tag -v file-annotated-tag
+'
+
+# creating and verifying signed tags:
+
+gpg --version >/dev/null
+if [ $? -eq 127 ]; then
+       echo "Skipping signed tags tests, because gpg was not found"
+       test_done
+       exit
+fi
+
+# As said here: http://www.gnupg.org/documentation/faqs.html#q6.19
+# the gpg version 1.0.6 didn't parse trust packets correctly, so for
+# that version, creation of signed tags using the generated key fails.
+case "$(gpg --version)" in
+'gpg (GnuPG) 1.0.6'*)
+       echo "Skipping signed tag tests, because a bug in 1.0.6 version"
+       test_done
+       exit
+       ;;
+esac
+
+# key generation info: gpg --homedir t/t7004 --gen-key
+# Type DSA and Elgamal, size 2048 bits, no expiration date.
+# Name and email: C O Mitter <committer@example.com>
+# No password given, to enable non-interactive operation.
+
+cp -R ../t7004 ./gpghome
+chmod 0700 gpghome
+export GNUPGHOME="$(pwd)/gpghome"
+
+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 &&
+       get_tag_msg signed-tag >actual &&
+       git diff expect actual
+'
+
+test_expect_success 'verifying a signed tag should succeed' \
+       'git-tag -v signed-tag'
+
+test_expect_success 'verifying a forged tag should fail' '
+       forged=$(git cat-file tag signed-tag |
+               sed -e "s/signed-tag/forged-tag/" |
+               git mktag) &&
+       git tag forged-tag $forged &&
+       ! git-tag -v forged-tag
+'
+
+# blank and empty messages for signed tags:
+
+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 &&
+       get_tag_msg empty-signed-tag >actual &&
+       git diff expect actual &&
+       git-tag -v empty-signed-tag
+'
+
+>sigemptyfile
+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 &&
+       get_tag_msg emptyfile-signed-tag >actual &&
+       git diff expect actual &&
+       git-tag -v emptyfile-signed-tag
+'
+
+printf '\n\n  \n\t\nLeading blank lines\n' > sigblanksfile
+printf '\n\t \t  \nRepeated blank lines\n' >>sigblanksfile
+printf '\n\n\nTrailing spaces      \t  \n' >>sigblanksfile
+printf '\nTrailing blank lines\n\n\t \n\n' >>sigblanksfile
+get_tag_header blanks-signed-tag $commit commit $time >expect
+cat >>expect <<EOF
+Leading blank lines
+
+Repeated blank lines
+
+Trailing spaces
+
+Trailing blank lines
+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 &&
+       get_tag_msg blanks-signed-tag >actual &&
+       git diff expect actual &&
+       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 &&
+       get_tag_msg blank-signed-tag >actual &&
+       git diff expect actual &&
+       git-tag -v blank-signed-tag
+'
+
+echo '     ' >sigblankfile
+echo ''      >>sigblankfile
+echo '  '    >>sigblankfile
+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 &&
+       get_tag_msg blankfile-signed-tag >actual &&
+       git diff expect actual &&
+       git-tag -v blankfile-signed-tag
+'
+
+printf '      ' >sigblanknonlfile
+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 &&
+       get_tag_msg blanknonlfile-signed-tag >actual &&
+       git diff expect actual &&
+       git-tag -v signed-tag
+'
+
+# messages with commented lines for signed tags:
+
+cat >sigcommentsfile <<EOF
+# A comment
+
+############
+The message.
+############
+One line.
+
+
+# commented lines
+# commented lines
+
+Another line.
+# comments
+
+Last line.
+EOF
+get_tag_header comments-signed-tag $commit commit $time >expect
+cat >>expect <<EOF
+The message.
+One line.
+
+Another line.
+
+Last line.
+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 &&
+       get_tag_msg comments-signed-tag >actual &&
+       git diff expect actual &&
+       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 &&
+       get_tag_msg comment-signed-tag >actual &&
+       git diff expect actual &&
+       git-tag -v comment-signed-tag
+'
+
+echo '#comment' >sigcommentfile
+echo ''         >>sigcommentfile
+echo '####'     >>sigcommentfile
+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 &&
+       get_tag_msg commentfile-signed-tag >actual &&
+       git diff expect actual &&
+       git-tag -v commentfile-signed-tag
+'
+
+printf '#comment' >sigcommentnonlfile
+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 &&
+       get_tag_msg commentnonlfile-signed-tag >actual &&
+       git diff expect actual &&
+       git-tag -v commentnonlfile-signed-tag
+'
+
+# tags pointing to objects different from commits:
+
+tree=$(git rev-parse HEAD^{tree})
+blob=$(git rev-parse HEAD:foo)
+tag=$(git rev-parse signed-tag)
+
+get_tag_header tree-signed-tag $tree tree $time >expect
+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} &&
+       get_tag_msg tree-signed-tag >actual &&
+       git diff expect actual
+'
+
+get_tag_header blob-signed-tag $blob blob $time >expect
+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 &&
+       get_tag_msg blob-signed-tag >actual &&
+       git diff expect actual
+'
+
+get_tag_header tag-signed-tag $tag tag $time >expect
+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 &&
+       get_tag_msg tag-signed-tag >actual &&
+       git diff expect actual
+'
+
+# try to verify without gpg:
+
+rm -rf gpghome
+test_expect_failure \
+       'verify signed tag fails when public key is not present' \
+       'git-tag -v signed-tag'
+
+test_done
diff --git a/t/t7004/pubring.gpg b/t/t7004/pubring.gpg
new file mode 100644 (file)
index 0000000..83855fa
Binary files /dev/null and b/t/t7004/pubring.gpg differ
diff --git a/t/t7004/random_seed b/t/t7004/random_seed
new file mode 100644 (file)
index 0000000..8fed133
Binary files /dev/null and b/t/t7004/random_seed differ
diff --git a/t/t7004/secring.gpg b/t/t7004/secring.gpg
new file mode 100644 (file)
index 0000000..d831cd9
Binary files /dev/null and b/t/t7004/secring.gpg differ
diff --git a/t/t7004/trustdb.gpg b/t/t7004/trustdb.gpg
new file mode 100644 (file)
index 0000000..abace96
Binary files /dev/null and b/t/t7004/trustdb.gpg differ
index a9191407f21c748f4c00bf909f670fc2b5124ec3..66d40430b293b2c1f8c7bc72416730e502c41f58 100755 (executable)
@@ -10,7 +10,7 @@ test_expect_success \
     'creating initial files' \
     'mkdir path0 &&
      cp ../../COPYING path0/COPYING &&
-     git-add path0/COPYING &&
+     git add path0/COPYING &&
      git-commit -m add -a'
 
 test_expect_success \
@@ -21,10 +21,10 @@ test_expect_success \
      cp ../../COPYING path1/COPYING &&
      cp ../../COPYING COPYING &&
      cp ../../COPYING path0/COPYING-TOO &&
-     git-add path1/path2/COPYING &&
-     git-add path1/COPYING &&
-     git-add COPYING &&
-     git-add 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'
 
 test_expect_success \
index de70b38d1cc2f8a16bd1fd68fc24d0bef82def97..eb0847afe9825f4af46065c2ee38282c44789bfb 100755 (executable)
@@ -13,10 +13,10 @@ test_expect_success 'setup' '
        touch src/part1.c Makefile &&
        echo build >.gitignore &&
        echo \*.o >>.gitignore &&
-       git-add . &&
+       git add . &&
        git-commit -m setup &&
        touch src/part2.c README &&
-       git-add .
+       git add .
 
 '
 
@@ -141,7 +141,7 @@ test_expect_success 'git-clean -d -X' '
 
 test_expect_success 'clean.requireForce' '
 
-       git-config clean.requireForce true &&
+       git config clean.requireForce true &&
        ! git-clean
 
 '
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
new file mode 100755 (executable)
index 0000000..5e91db6
--- /dev/null
@@ -0,0 +1,169 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Lars Hjemli
+#
+
+test_description='Basic porcelain support for submodules
+
+This test tries to verify basic sanity of the init, update and status
+subcommands of git-submodule.
+'
+
+. ./test-lib.sh
+
+#
+# Test setup:
+#  -create a repository in directory lib
+#  -add a couple of files
+#  -add directory lib to 'superproject', this creates a DIRLINK entry
+#  -add a couple of regular files to enable testing of submodule filtering
+#  -mv lib subrepo
+#  -add an entry to .gitmodules for submodule 'example'
+#
+test_expect_success 'Prepare submodule testing' '
+       mkdir lib &&
+       cd lib &&
+       git init &&
+       echo a >a &&
+       git add a &&
+       git-commit -m "submodule commit 1" &&
+       git-tag -a -m "rev-1" rev-1 &&
+       rev1=$(git rev-parse HEAD) &&
+       if test -z "$rev1"
+       then
+               echo "[OOPS] submodule git rev-parse returned nothing"
+               false
+       fi &&
+       cd .. &&
+       echo a >a &&
+       echo z >z &&
+       git add a lib z &&
+       git-commit -m "super commit 1" &&
+       mv lib .subrepo &&
+       GIT_CONFIG=.gitmodules git config submodule.example.url git://example.com/lib.git
+'
+
+test_expect_success 'status should fail for unmapped paths' '
+       if git-submodule status
+       then
+               echo "[OOPS] submodule status succeeded"
+               false
+       elif ! GIT_CONFIG=.gitmodules git config submodule.example.path lib
+       then
+               echo "[OOPS] git config failed to update .gitmodules"
+               false
+       fi
+'
+
+test_expect_success 'status should only print one line' '
+       lines=$(git-submodule status | wc -l) &&
+       test $lines = 1
+'
+
+test_expect_success 'status should initially be "missing"' '
+       git-submodule status | grep "^-$rev1"
+'
+
+test_expect_success 'init should register submodule url in .git/config' '
+       git-submodule init &&
+       url=$(git config submodule.example.url) &&
+       if test "$url" != "git://example.com/lib.git"
+       then
+               echo "[OOPS] init succeeded but submodule url is wrong"
+               false
+       elif ! git config submodule.example.url ./.subrepo
+       then
+               echo "[OOPS] init succeeded but update of url failed"
+               false
+       fi
+'
+
+test_expect_success 'update should fail when path is used by a file' '
+       echo "hello" >lib &&
+       if git-submodule update
+       then
+               echo "[OOPS] update should have failed"
+               false
+       elif test "$(cat lib)" != "hello"
+       then
+               echo "[OOPS] update failed but lib file was molested"
+               false
+       else
+               rm lib
+       fi
+'
+
+test_expect_success 'update should fail when path is used by a nonempty directory' '
+       mkdir lib &&
+       echo "hello" >lib/a &&
+       if git-submodule update
+       then
+               echo "[OOPS] update should have failed"
+               false
+       elif test "$(cat lib/a)" != "hello"
+       then
+               echo "[OOPS] update failed but lib/a was molested"
+               false
+       else
+               rm lib/a
+       fi
+'
+
+test_expect_success 'update should work when path is an empty dir' '
+       rm -rf lib &&
+       mkdir lib &&
+       git-submodule update &&
+       head=$(cd lib && git rev-parse HEAD) &&
+       if test -z "$head"
+       then
+               echo "[OOPS] Failed to obtain submodule head"
+               false
+       elif test "$head" != "$rev1"
+       then
+               echo "[OOPS] Submodule head is $head but should have been $rev1"
+               false
+       fi
+'
+
+test_expect_success 'status should be "up-to-date" after update' '
+       git-submodule status | grep "^ $rev1"
+'
+
+test_expect_success 'status should be "modified" after submodule commit' '
+       cd lib &&
+       echo b >b &&
+       git add b &&
+       git-commit -m "submodule commit 2" &&
+       rev2=$(git rev-parse HEAD) &&
+       cd .. &&
+       if test -z "$rev2"
+       then
+               echo "[OOPS] submodule git rev-parse returned nothing"
+               false
+       fi &&
+       git-submodule status | grep "^+$rev2"
+'
+
+test_expect_success 'the --cached sha1 should be rev1' '
+       git-submodule --cached status | grep "^+$rev1"
+'
+
+test_expect_success 'update should checkout rev1' '
+       git-submodule update &&
+       head=$(cd lib && git rev-parse HEAD) &&
+       if test -z "$head"
+       then
+               echo "[OOPS] submodule git rev-parse returned nothing"
+               false
+       elif test "$head" != "$rev1"
+       then
+               echo "[OOPS] init did not checkout correct head"
+               false
+       fi
+'
+
+test_expect_success 'status should be "up-to-date" after update' '
+       git-submodule status | grep "^ $rev1"
+'
+
+test_done
index 3a6490e8f864b3b3193a7b86d54a0e8d81d0dd20..eabec2e06e2f97fc1790cd4ce30a80e402d4a205 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='git-annotate'
+test_description='git annotate'
 . ./test-lib.sh
 
 PROG='git annotate'
index 97773939962187b4a27176e9bcb5104652ba3853..92ece30fa94784bdad8ae50fc370487e60bbcb5c 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='git-blame'
+test_description='git blame'
 . ./test-lib.sh
 
 PROG='git blame -c'
index 70c3669ee81f4c6d5dd6ce75e4c7c18e33e93553..614cf50d195bb3b055fd8166d425eeffa7106509 100755 (executable)
@@ -86,10 +86,10 @@ test_expect_failure "$name" "
        rm -f '$GIT_DIR'/index &&
        git checkout -f -b mybranch3 remotes/git-svn &&
        rm bar/zzz &&
-       git-update-index --remove bar/zzz &&
+       git update-index --remove bar/zzz &&
        mkdir bar/zzz &&
        echo yyy > bar/zzz/yyy &&
-       git-update-index --add bar/zzz/yyy &&
+       git update-index --add bar/zzz/yyy &&
        git commit -m '$name' &&
        git-svn set-tree --find-copies-harder --rmdir \
                remotes/git-svn..mybranch3" || true
@@ -191,8 +191,8 @@ 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-rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b &&
+     git rev-list --pretty=raw remotes/git-svn | grep ^tree | uniq > a &&
+     git rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b &&
      git diff a b"
 
 name='check imported tree checksums expected tree checksums'
@@ -214,7 +214,7 @@ EOF
 test_expect_success "$name" "git diff a expected"
 
 test_expect_failure 'exit if remote refs are ambigious' "
-        git-config --add svn-remote.svn.fetch \
+        git config --add svn-remote.svn.fetch \
                               bar:refs/remotes/git-svn &&
         git-svn migrate
         "
@@ -222,7 +222,7 @@ test_expect_failure 'exit if remote refs are ambigious' "
 test_expect_failure '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 \
+        git config --unset svn-remote.svn.fetch \
                                 '^bar:refs/remotes/git-svn$' &&
         git-svn init ${svnrepo}2/bar
         "
index 35aa45cb9addd862ca01f2f7eb39a863bb508364..d8f9cab35dcff89469f1974dcc7130e3d38f471e 100755 (executable)
@@ -30,31 +30,31 @@ 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 &&
-       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 |\
+       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 |\
                  sed -n -e '3p'\`\" = goodbye &&
-       test -z \"\`git-config --get svn-remote.svn.fetch \
+       test -z \"\`git config --get svn-remote.svn.fetch \
                 '^trunk:refs/remotes/thunk@2$'\`\"
        "
 
 test_expect_success 'init and fetch from one svn-remote' "
-        git-config svn-remote.svn.url $svnrepo &&
-        git-config --add svn-remote.svn.fetch \
+        git config svn-remote.svn.url $svnrepo &&
+        git config --add svn-remote.svn.fetch \
           trunk:refs/remotes/svn/trunk &&
-        git-config --add svn-remote.svn.fetch \
+        git config --add svn-remote.svn.fetch \
           thunk:refs/remotes/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 |\
+       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 |\
                  sed -n -e '3p'\`\" = goodbye
         "
 
 test_expect_success 'follow deleted parent' "
         svn cp -m 'resurrecting trunk as junk' \
                -r2 $svnrepo/trunk $svnrepo/junk &&
-        git-config --add svn-remote.svn.fetch \
+        git config --add svn-remote.svn.fetch \
           junk:refs/remotes/svn/junk &&
         git-svn fetch -i svn/thunk &&
         git-svn fetch -i svn/junk &&
@@ -71,13 +71,13 @@ test_expect_success 'follow larger parent' "
         git-svn init --minimize-url -i larger \
           $svnrepo/another-larger/trunk/thunk/bump/thud &&
         git-svn fetch -i larger &&
-        git-rev-parse --verify refs/remotes/larger &&
-        git-rev-parse --verify \
+        git rev-parse --verify refs/remotes/larger &&
+        git rev-parse --verify \
            refs/remotes/larger-parent/trunk/thunk/bump/thud &&
-        test \"\`git-merge-base \
+        test \"\`git merge-base \
                  refs/remotes/larger-parent/trunk/thunk/bump/thud \
                  refs/remotes/larger\`\" = \
-             \"\`git-rev-parse refs/remotes/larger\`\"
+             \"\`git rev-parse refs/remotes/larger\`\"
         true
         "
 
index dc2afdaa4561ce037239907297718dba1fa33ce6..67fdf7023f3aed9273eeaf5664cbd62950e32616 100755 (executable)
@@ -19,9 +19,9 @@ test_expect_success 'setup old-looking metadata' "
        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`
@@ -33,8 +33,8 @@ test_expect_success 'initialize old-style (v0) git-svn layout' "
        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-rev-parse --verify refs/remotes/svn^0 &&
+       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'
@@ -42,20 +42,20 @@ test_expect_success 'initialize old-style (v0) git-svn layout' "
 
 test_expect_success 'initialize a multi-repository repo' "
        git-svn init $svnrepo -T trunk -t tags -b branches &&
-       git-config --get-all svn-remote.svn.fetch > fetch.out &&
+       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 \
+       test -n \"\`git config --get svn-remote.svn.branches \
                    '^branches/\*:refs/remotes/\*$'\`\" &&
-       test -n \"\`git-config --get svn-remote.svn.tags \
+       test -n \"\`git config --get svn-remote.svn.tags \
                    '^tags/\*:refs/remotes/tags/\*$'\`\" &&
        git config --unset svn-remote.svn.branches \
                                '^branches/\*:refs/remotes/\*$' &&
        git config --unset svn-remote.svn.tags \
                                '^tags/\*:refs/remotes/tags/\*$' &&
-       git-config --add svn-remote.svn.fetch 'branches/a:refs/remotes/a' &&
-       git-config --add svn-remote.svn.fetch 'branches/b:refs/remotes/b' &&
+       git config --add svn-remote.svn.fetch 'branches/a:refs/remotes/a' &&
+       git config --add svn-remote.svn.fetch 'branches/b:refs/remotes/b' &&
        for i in tags/0.1 tags/0.2 tags/0.3; do
-               git-config --add svn-remote.svn.fetch \
+               git config --add svn-remote.svn.fetch \
                                 \$i:refs/remotes/\$i || exit 1; done
        "
 
@@ -86,8 +86,8 @@ test_expect_success 'migrate --minimize on old inited layout' "
                echo $svnrepo\$path > $GIT_DIR/svn/\$ref/info/url ) || exit 1;
        done &&
        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 &&
+       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 &&
        grep '^branches/a:refs/remotes/a$' fetch.out &&
        grep '^branches/b:refs/remotes/b$' fetch.out &&
@@ -109,4 +109,3 @@ test_expect_success  ".rev_db auto-converted to .rev_db.UUID" "
        "
 
 test_done
-
index 59e17f266374c837f0c1e0bd0a4a40fe22a773a6..6235af4db8b0b744d40156f90a0afed469952441 100755 (executable)
@@ -13,7 +13,7 @@ test_expect_success 'load svm repo' "
        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 config svn.useSvmProps true &&
        git-svn fetch --all
        "
 
@@ -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 | \
+       git cat-file commit refs/remotes/bar | \
           grep '^git-svn-id: $bar_url@12 $uuid$' &&
-       git-cat-file commit refs/remotes/bar~1 | \
+       git cat-file commit refs/remotes/bar~1 | \
           grep '^git-svn-id: $bar_url@11 $uuid$' &&
-       git-cat-file commit refs/remotes/bar~2 | \
+       git cat-file commit refs/remotes/bar~2 | \
           grep '^git-svn-id: $bar_url@10 $uuid$' &&
-       git-cat-file commit refs/remotes/bar~3 | \
+       git cat-file commit refs/remotes/bar~3 | \
           grep '^git-svn-id: $bar_url@9 $uuid$' &&
-       git-cat-file commit refs/remotes/bar~4 | \
+       git cat-file commit refs/remotes/bar~4 | \
           grep '^git-svn-id: $bar_url@6 $uuid$' &&
-       git-cat-file commit refs/remotes/bar~5 | \
+       git cat-file commit refs/remotes/bar~5 | \
           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 | \
+       git cat-file commit refs/remotes/e | \
           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 | \
+       git cat-file commit refs/remotes/dir | \
           grep '^git-svn-id: $dir_url@2 $uuid$' &&
-       git-cat-file commit refs/remotes/dir~1 | \
+       git cat-file commit refs/remotes/dir~1 | \
           grep '^git-svn-id: $dir_url@1 $uuid$'
        "
 
index e52321471a3f49098e61c5a2f9257d354a628d3b..ec7dedd48b0e45278b33e3c5d4f97d8df5f85ddf 100755 (executable)
@@ -12,7 +12,7 @@ test_expect_success 'load svnsync repo' "
        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 config svn.useSvnsyncProps true &&
        git-svn fetch --all
        "
 
@@ -20,31 +20,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 | \
+       git cat-file commit refs/remotes/bar | \
           grep '^git-svn-id: $bar_url@12 $uuid$' &&
-       git-cat-file commit refs/remotes/bar~1 | \
+       git cat-file commit refs/remotes/bar~1 | \
           grep '^git-svn-id: $bar_url@11 $uuid$' &&
-       git-cat-file commit refs/remotes/bar~2 | \
+       git cat-file commit refs/remotes/bar~2 | \
           grep '^git-svn-id: $bar_url@10 $uuid$' &&
-       git-cat-file commit refs/remotes/bar~3 | \
+       git cat-file commit refs/remotes/bar~3 | \
           grep '^git-svn-id: $bar_url@9 $uuid$' &&
-       git-cat-file commit refs/remotes/bar~4 | \
+       git cat-file commit refs/remotes/bar~4 | \
           grep '^git-svn-id: $bar_url@6 $uuid$' &&
-       git-cat-file commit refs/remotes/bar~5 | \
+       git cat-file commit refs/remotes/bar~5 | \
           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 | \
+       git cat-file commit refs/remotes/e | \
           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 | \
+       git cat-file commit refs/remotes/dir | \
           grep '^git-svn-id: $dir_url@2 $uuid$' &&
-       git-cat-file commit refs/remotes/dir~1 | \
+       git cat-file commit refs/remotes/dir~1 | \
           grep '^git-svn-id: $dir_url@1 $uuid$'
        "
 
index a9a46eeb2978071e44db85405b62c515e0b6c278..499fa9594fafe5d45a32005c189634b6a3048777 100644 (file)
@@ -558,5 +558,3 @@ Text-content-md5: 7abb78de7f2756ca8b511cbc879fd5e7
 Content-length: 4
 
 cba
-
-
diff --git a/t/t9113-git-svn-dcommit-new-file.sh b/t/t9113-git-svn-dcommit-new-file.sh
new file mode 100755 (executable)
index 0000000..9ef0db9
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Eric Wong
+#
+
+# Don't run this test by default unless the user really wants it
+# I don't like the idea of taking a port and possibly leaving a
+# daemon running on a users system if the test fails.
+# Not all git users will need to interact with SVN.
+test -z "$SVNSERVE_PORT" && exit 0
+
+test_description='git-svn dcommit new files over svn:// test'
+
+. ./lib-git-svn.sh
+
+start_svnserve () {
+       svnserve --listen-port $SVNSERVE_PORT \
+                --root $rawsvnrepo \
+                --listen-once \
+                --listen-host 127.0.0.1 &
+}
+
+test_expect_success 'start tracking an empty repo' "
+       svn mkdir -m 'empty dir' $svnrepo/empty-dir &&
+       echo anon-access = write >> $rawsvnrepo/conf/svnserve.conf &&
+       start_svnserve &&
+       git svn init svn://127.0.0.1:$SVNSERVE_PORT &&
+       git svn fetch
+       "
+
+test_expect_success 'create files in new directory with dcommit' "
+       mkdir git-new-dir &&
+       echo hello > git-new-dir/world &&
+       git update-index --add git-new-dir/world &&
+       git commit -m hello &&
+       start_svnserve &&
+       git svn dcommit
+       "
+
+test_done
diff --git a/t/t9114-git-svn-dcommit-merge.sh b/t/t9114-git-svn-dcommit-merge.sh
new file mode 100755 (executable)
index 0000000..d6ca955
--- /dev/null
@@ -0,0 +1,89 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Eric Wong
+# Based on a script by Joakim Tjernlund <joakim.tjernlund@transmode.se>
+
+test_description='git-svn dcommit handles merges'
+
+. ./lib-git-svn.sh
+
+big_text_block () {
+cat << EOF
+#
+# (C) Copyright 2000 - 2005
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+EOF
+}
+
+test_expect_success 'setup svn repository' "
+       svn co $svnrepo mysvnwork &&
+       mkdir -p mysvnwork/trunk &&
+       cd mysvnwork &&
+               big_text_block >> trunk/README &&
+               svn add trunk &&
+               svn ci -m 'first commit' trunk &&
+               cd ..
+       "
+
+test_expect_success 'setup git mirror and merge' "
+       git svn init $svnrepo -t tags -T trunk -b branches &&
+       git svn fetch &&
+       git checkout --track -b svn remotes/trunk &&
+       git checkout -b merge &&
+       echo new file > new_file &&
+       git add new_file &&
+       git commit -a -m 'New file' &&
+       echo hello >> README &&
+       git commit -a -m 'hello' &&
+       echo add some stuff >> new_file &&
+       git commit -a -m 'add some stuff' &&
+       git checkout svn &&
+       mv -f README tmp &&
+       echo friend > README &&
+       cat tmp >> README &&
+       git commit -a -m 'friend' &&
+       git pull . merge
+       "
+
+test_debug 'gitk --all & sleep 1'
+
+test_expect_success 'verify pre-merge ancestry' "
+       test x\`git rev-parse --verify refs/heads/svn^2\` = \
+            x\`git rev-parse --verify refs/heads/merge\` &&
+       git cat-file commit refs/heads/svn^ | grep '^friend$'
+       "
+
+test_expect_success 'git svn dcommit merges' "
+       git svn dcommit
+       "
+
+test_debug 'gitk --all & sleep 1'
+
+test_expect_success 'verify post-merge ancestry' "
+       test x\`git rev-parse --verify refs/heads/svn\` = \
+            x\`git rev-parse --verify refs/remotes/trunk \` &&
+       test x\`git rev-parse --verify refs/heads/svn^2\` = \
+            x\`git rev-parse --verify refs/heads/merge\` &&
+       git cat-file commit refs/heads/svn^ | grep '^friend$'
+       "
+
+test_done
index 72e49f5d3bebcf6509536c578cc934879ee1aa55..53774c8325ce491d09b1a2389dbb5a44870b4c17 100755 (executable)
@@ -60,10 +60,10 @@ INPUT_END
 test_expect_success \
     'A: create pack from stdin' \
     'git-fast-import --export-marks=marks.out <input &&
-        git-whatchanged master'
+        git whatchanged master'
 test_expect_success \
        'A: verify pack' \
-       'for p in .git/objects/pack/*.pack;do git-verify-pack $p||exit;done'
+       'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
 
 cat >expect <<EOF
 author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
@@ -73,7 +73,7 @@ initial
 EOF
 test_expect_success \
        'A: verify commit' \
-       'git-cat-file commit master | sed 1d >actual &&
+       'git cat-file commit master | sed 1d >actual &&
        git diff expect actual'
 
 cat >expect <<EOF
@@ -83,29 +83,29 @@ cat >expect <<EOF
 EOF
 test_expect_success \
        'A: verify tree' \
-       'git-cat-file -p master^{tree} | sed "s/ [0-9a-f]*      / /" >actual &&
+       'git cat-file -p master^{tree} | sed "s/ [0-9a-f]*      / /" >actual &&
         git diff expect actual'
 
 echo "$file2_data" >expect
 test_expect_success \
        'A: verify file2' \
-       'git-cat-file blob master:file2 >actual && git diff expect actual'
+       'git cat-file blob master:file2 >actual && git diff expect actual'
 
 echo "$file3_data" >expect
 test_expect_success \
        'A: verify file3' \
-       'git-cat-file blob master:file3 >actual && git diff expect actual'
+       'git cat-file blob master:file3 >actual && git diff expect actual'
 
 printf "$file4_data" >expect
 test_expect_success \
        'A: verify file4' \
-       'git-cat-file blob master:file4 >actual && git diff expect actual'
+       'git cat-file blob master:file4 >actual && git diff expect actual'
 
 cat >expect <<EOF
-:2 `git-rev-parse --verify master:file2`
-:3 `git-rev-parse --verify master:file3`
-:4 `git-rev-parse --verify master:file4`
-:5 `git-rev-parse --verify master^0`
+:2 `git rev-parse --verify master:file2`
+:3 `git rev-parse --verify master:file3`
+:4 `git rev-parse --verify master:file4`
+:5 `git rev-parse --verify master^0`
 EOF
 test_expect_success \
        'A: verify marks output' \
@@ -134,19 +134,19 @@ INPUT_END
 test_expect_success \
        'A: verify marks import does not crash' \
        'git-fast-import --import-marks=marks.out <input &&
-        git-whatchanged verify--import-marks'
+        git whatchanged verify--import-marks'
 test_expect_success \
        'A: verify pack' \
-       'for p in .git/objects/pack/*.pack;do git-verify-pack $p||exit;done'
+       'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
 cat >expect <<EOF
 :000000 100755 0000000000000000000000000000000000000000 7123f7f44e39be127c5eb701e5968176ee9d78b1 A     copy-of-file2
 EOF
-git-diff-tree -M -r master verify--import-marks >actual
+git diff-tree -M -r master verify--import-marks >actual
 test_expect_success \
        'A: verify diff' \
        'compare_diff_raw expect actual &&
-        test `git-rev-parse --verify master:file2` \
-           = `git-rev-parse --verify verify--import-marks:copy-of-file2`'
+        test `git rev-parse --verify master:file2` \
+           = `git rev-parse --verify verify--import-marks:copy-of-file2`'
 
 ###
 ### series B
@@ -175,7 +175,7 @@ rm -f .git/objects/pack_* .git/objects/index_*
 ###
 
 newf=`echo hi newf | git-hash-object -w --stdin`
-oldf=`git-rev-parse --verify master:file2`
+oldf=`git rev-parse --verify master:file2`
 test_tick
 cat >input <<INPUT_END
 commit refs/heads/branch
@@ -193,17 +193,17 @@ INPUT_END
 test_expect_success \
     'C: incremental import create pack from stdin' \
     'git-fast-import <input &&
-        git-whatchanged branch'
+        git whatchanged branch'
 test_expect_success \
        'C: verify pack' \
-       'for p in .git/objects/pack/*.pack;do git-verify-pack $p||exit;done'
+       'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
 test_expect_success \
        'C: validate reuse existing blob' \
-       'test $newf = `git-rev-parse --verify branch:file2/newf`
-        test $oldf = `git-rev-parse --verify branch:file2/oldf`'
+       'test $newf = `git rev-parse --verify branch:file2/newf`
+        test $oldf = `git rev-parse --verify branch:file2/oldf`'
 
 cat >expect <<EOF
-parent `git-rev-parse --verify master^0`
+parent `git rev-parse --verify master^0`
 author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
 
@@ -211,7 +211,7 @@ second
 EOF
 test_expect_success \
        'C: verify commit' \
-       'git-cat-file commit branch | sed 1d >actual &&
+       'git cat-file commit branch | sed 1d >actual &&
         git diff expect actual'
 
 cat >expect <<EOF
@@ -219,7 +219,7 @@ cat >expect <<EOF
 :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 R100  file2   file2/oldf
 :100644 000000 0d92e9f3374ae2947c23aa477cbc68ce598135f1 0000000000000000000000000000000000000000 D     file3
 EOF
-git-diff-tree -M -r master branch >actual
+git diff-tree -M -r master branch >actual
 test_expect_success \
        'C: validate rename result' \
        'compare_diff_raw expect actual'
@@ -251,16 +251,16 @@ INPUT_END
 test_expect_success \
     'D: inline data in commit' \
     'git-fast-import <input &&
-        git-whatchanged branch'
+        git whatchanged branch'
 test_expect_success \
        'D: verify pack' \
-       'for p in .git/objects/pack/*.pack;do git-verify-pack $p||exit;done'
+       'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
 
 cat >expect <<EOF
 :000000 100755 0000000000000000000000000000000000000000 35a59026a33beac1569b1c7f66f3090ce9c09afc A     newdir/exec.sh
 :000000 100644 0000000000000000000000000000000000000000 046d0371e9220107917db0d0e030628de8a1de9b A     newdir/interesting
 EOF
-git-diff-tree -M -r branch^ branch >actual
+git diff-tree -M -r branch^ branch >actual
 test_expect_success \
        'D: validate new files added' \
        'compare_diff_raw expect actual'
@@ -268,13 +268,13 @@ test_expect_success \
 echo "$file5_data" >expect
 test_expect_success \
        'D: verify file5' \
-       'git-cat-file blob branch:newdir/interesting >actual &&
+       'git cat-file blob branch:newdir/interesting >actual &&
         git diff expect actual'
 
 echo "$file6_data" >expect
 test_expect_success \
        'D: verify file6' \
-       'git-cat-file blob branch:newdir/exec.sh >actual &&
+       'git cat-file blob branch:newdir/exec.sh >actual &&
         git diff expect actual'
 
 ###
@@ -300,7 +300,7 @@ test_expect_success \
     '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'
+       'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
 
 cat >expect <<EOF
 author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 1170778938 -0500
@@ -310,14 +310,14 @@ RFC 2822 type date
 EOF
 test_expect_success \
        'E: verify commit' \
-       'git-cat-file commit branch | sed 1,2d >actual &&
+       'git cat-file commit branch | sed 1,2d >actual &&
        git diff expect actual'
 
 ###
 ### series F
 ###
 
-old_branch=`git-rev-parse --verify branch^0`
+old_branch=`git rev-parse --verify branch^0`
 test_tick
 cat >input <<INPUT_END
 commit refs/heads/branch
@@ -339,7 +339,7 @@ test_expect_success \
                echo BAD gfi did not fail
                return 1
         else
-               if test $old_branch = `git-rev-parse --verify branch^0`
+               if test $old_branch = `git rev-parse --verify branch^0`
                then
                        : branch unaffected and failure returned
                        return 0
@@ -351,11 +351,11 @@ test_expect_success \
        '
 test_expect_success \
        'F: verify pack' \
-       'for p in .git/objects/pack/*.pack;do git-verify-pack $p||exit;done'
+       'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
 
 cat >expect <<EOF
-tree `git-rev-parse branch~1^{tree}`
-parent `git-rev-parse branch~1`
+tree `git rev-parse branch~1^{tree}`
+parent `git rev-parse branch~1`
 author $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
 
@@ -363,14 +363,14 @@ losing things already?
 EOF
 test_expect_success \
        'F: verify other commit' \
-       'git-cat-file commit other >actual &&
+       'git cat-file commit other >actual &&
        git diff expect actual'
 
 ###
 ### series G
 ###
 
-old_branch=`git-rev-parse --verify branch^0`
+old_branch=`git rev-parse --verify branch^0`
 test_tick
 cat >input <<INPUT_END
 commit refs/heads/branch
@@ -387,11 +387,11 @@ test_expect_success \
     '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'
+       'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
 test_expect_success \
        'G: branch changed, but logged' \
-       'test $old_branch != `git-rev-parse --verify branch^0` &&
-        test $old_branch = `git-rev-parse --verify branch@{1}`'
+       'test $old_branch != `git rev-parse --verify branch^0` &&
+        test $old_branch = `git rev-parse --verify branch@{1}`'
 
 ###
 ### series H
@@ -421,10 +421,10 @@ INPUT_END
 test_expect_success \
     'H: deletall, add 1' \
     'git-fast-import <input &&
-        git-whatchanged H'
+        git whatchanged H'
 test_expect_success \
        'H: verify pack' \
-       'for p in .git/objects/pack/*.pack;do git-verify-pack $p||exit;done'
+       'for p in .git/objects/pack/*.pack;do git verify-pack $p||exit;done'
 
 cat >expect <<EOF
 :100755 000000 f1fb5da718392694d0076d677d6d0e364c79b0bc 0000000000000000000000000000000000000000 D     file2/newf
@@ -433,7 +433,7 @@ cat >expect <<EOF
 :100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 R100  newdir/interesting      h/e/l/lo
 :100755 000000 e74b7d465e52746be2b4bae983670711e6e66657 0000000000000000000000000000000000000000 D     newdir/exec.sh
 EOF
-git-diff-tree -M -r H^ H >actual
+git diff-tree -M -r H^ H >actual
 test_expect_success \
        'H: validate old files removed, new files added' \
        'compare_diff_raw expect actual'
@@ -441,7 +441,7 @@ test_expect_success \
 echo "$file5_data" >expect
 test_expect_success \
        'H: verify file' \
-       'git-cat-file blob H:h/e/l/lo >actual &&
+       'git cat-file blob H:h/e/l/lo >actual &&
         git diff expect actual'
 
 ###
@@ -463,7 +463,7 @@ test_expect_success \
     'git-fast-import --export-pack-edges=edges.list <input'
 
 cat >expect <<EOF
-.git/objects/pack/pack-.pack: `git-rev-parse --verify export-boundary`
+.git/objects/pack/pack-.pack: `git rev-parse --verify export-boundary`
 EOF
 test_expect_success \
        'I: verify edge list' \
@@ -497,7 +497,7 @@ test_expect_success \
     'git-fast-import <input'
 test_expect_success \
        'J: branch has 1 commit, empty tree' \
-       'test 1 = `git-rev-list J | wc -l` &&
+       'test 1 = `git rev-list J | wc -l` &&
         test 0 = `git ls-tree J | wc -l`'
 
 ###
@@ -527,8 +527,8 @@ test_expect_success \
     'git-fast-import <input'
 test_expect_success \
     'K: verify K^1 = branch^1' \
-    'test `git-rev-parse --verify branch^1` \
-               = `git-rev-parse --verify K^1`'
+    'test `git rev-parse --verify branch^1` \
+               = `git rev-parse --verify K^1`'
 
 ###
 ### series L
@@ -577,7 +577,7 @@ EXPECT_END
 test_expect_success \
     'L: verify internal tree sorting' \
        'git-fast-import <input &&
-        git-diff --raw L^ L >output &&
+        git diff --raw L^ L >output &&
         git diff expect output'
 
 test_done
index d406a8824a382433cbc8c6f499ef3bc1f00301b2..641303e0a18c1c9958e4dae86d1fcdee644dbcff 100755 (executable)
@@ -38,7 +38,7 @@ echo >empty &&
   git commit -q -m "First Commit" &&
   git clone -q --local --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 &&
   GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true &&
-  GIT_DIR="$SERVERDIR" git config --bool gitcvs.logfile "$SERVERDIR/gitcvs.log" ||
+  GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log" ||
   exit 1
 
 # note that cvs doesn't accept absolute pathnames
@@ -47,6 +47,217 @@ test_expect_success 'basic checkout' \
   'GIT_CONFIG="$git_config" cvs -Q co -d cvswork master &&
    test "$(echo $(grep -v ^D cvswork/CVS/Entries|cut -d/ -f2,3,5))" = "empty/1.1/"'
 
+#------------------------
+# PSERVER AUTHENTICATION
+#------------------------
+
+cat >request-anonymous  <<EOF
+BEGIN AUTH REQUEST
+$SERVERDIR
+anonymous
+
+END AUTH REQUEST
+EOF
+
+cat >request-git  <<EOF
+BEGIN AUTH REQUEST
+$SERVERDIR
+git
+
+END AUTH REQUEST
+EOF
+
+cat >login-anonymous <<EOF
+BEGIN VERIFICATION REQUEST
+$SERVERDIR
+anonymous
+
+END VERIFICATION REQUEST
+EOF
+
+cat >login-git <<EOF
+BEGIN VERIFICATION REQUEST
+$SERVERDIR
+git
+
+END VERIFICATION REQUEST
+EOF
+
+test_expect_success 'pserver authentication' \
+  'cat request-anonymous | git-cvsserver pserver >log 2>&1 &&
+   tail -n1 log | grep -q "^I LOVE YOU$"'
+
+test_expect_success 'pserver authentication failure (non-anonymous user)' \
+  'if cat request-git | git-cvsserver pserver >log 2>&1
+   then
+       false
+   else
+       true
+   fi &&
+   tail -n1 log | grep -q "^I HATE YOU$"'
+
+test_expect_success 'pserver authentication (login)' \
+  'cat login-anonymous | git-cvsserver pserver >log 2>&1 &&
+   tail -n1 log | grep -q "^I LOVE YOU$"'
+
+test_expect_success 'pserver authentication failure (login/non-anonymous user)' \
+  'if cat login-git | git-cvsserver pserver >log 2>&1
+   then
+       false
+   else
+       true
+   fi &&
+   tail -n1 log | grep -q "^I HATE YOU$"'
+
+
+# misuse pserver authentication for testing of req_Root
+
+cat >request-relative  <<EOF
+BEGIN AUTH REQUEST
+gitcvs.git
+anonymous
+
+END AUTH REQUEST
+EOF
+
+cat >request-conflict  <<EOF
+BEGIN AUTH REQUEST
+$SERVERDIR
+anonymous
+
+END AUTH REQUEST
+Root $WORKDIR
+EOF
+
+test_expect_success 'req_Root failure (relative pathname)' \
+  'if cat request-relative | git-cvsserver pserver >log 2>&1
+   then
+       echo unexpected success
+       false
+   else
+       true
+   fi &&
+   tail log | grep -q "^error 1 Root must be an absolute pathname$"'
+
+test_expect_success 'req_Root failure (conflicting roots)' \
+  'cat request-conflict | git-cvsserver pserver >log 2>&1 &&
+   tail log | grep -q "^error 1 Conflicting roots specified$"'
+
+test_expect_success 'req_Root (strict paths)' \
+  'cat request-anonymous | git-cvsserver --strict-paths pserver $SERVERDIR >log 2>&1 &&
+   tail -n1 log | grep -q "^I LOVE YOU$"'
+
+test_expect_failure 'req_Root failure (strict-paths)' \
+  'cat request-anonymous | git-cvsserver --strict-paths pserver $WORKDIR >log 2>&1'
+
+test_expect_success 'req_Root (w/o strict-paths)' \
+  'cat request-anonymous | git-cvsserver pserver $WORKDIR/ >log 2>&1 &&
+   tail -n1 log | grep -q "^I LOVE YOU$"'
+
+test_expect_failure 'req_Root failure (w/o strict-paths)' \
+  'cat request-anonymous | git-cvsserver pserver $WORKDIR/gitcvs >log 2>&1'
+
+cat >request-base  <<EOF
+BEGIN AUTH REQUEST
+/gitcvs.git
+anonymous
+
+END AUTH REQUEST
+Root /gitcvs.git
+EOF
+
+test_expect_success 'req_Root (base-path)' \
+  'cat request-base | git-cvsserver --strict-paths --base-path $WORKDIR/ pserver $SERVERDIR >log 2>&1 &&
+   tail -n1 log | grep -q "^I LOVE YOU$"'
+
+test_expect_failure 'req_Root failure (base-path)' \
+  'cat request-anonymous | git-cvsserver --strict-paths --base-path $WORKDIR pserver $SERVERDIR >log 2>&1'
+
+GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled false || exit 1
+
+test_expect_success 'req_Root (export-all)' \
+  'cat request-anonymous | git-cvsserver --export-all pserver $WORKDIR >log 2>&1 &&
+   tail -n1 log | grep -q "^I LOVE YOU$"'
+
+test_expect_failure 'req_Root failure (export-all w/o whitelist)' \
+  'cat request-anonymous | git-cvsserver --export-all pserver >log 2>&1 ||
+   false'
+
+test_expect_success 'req_Root (everything together)' \
+  'cat request-base | git-cvsserver --export-all --strict-paths --base-path $WORKDIR/ pserver $SERVERDIR >log 2>&1 &&
+   tail -n1 log | grep -q "^I LOVE YOU$"'
+
+GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true || exit 1
+
+#--------------
+# CONFIG TESTS
+#--------------
+
+test_expect_success 'gitcvs.enabled = false' \
+  'GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled false &&
+   if GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 master >cvs.log 2>&1
+   then
+     echo unexpected cvs success
+     false
+   else
+     true
+   fi &&
+   cat cvs.log | grep -q "GITCVS emulation disabled" &&
+   test ! -d cvswork2'
+
+rm -fr cvswork2
+test_expect_success 'gitcvs.ext.enabled = true' \
+  'GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled true &&
+   GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled false &&
+   GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 master >cvs.log 2>&1 &&
+   diff -q cvswork cvswork2'
+
+rm -fr cvswork2
+test_expect_success 'gitcvs.ext.enabled = false' \
+  'GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled false &&
+   GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true &&
+   if GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 master >cvs.log 2>&1
+   then
+     echo unexpected cvs success
+     false
+   else
+     true
+   fi &&
+   cat cvs.log | grep -q "GITCVS emulation disabled" &&
+   test ! -d cvswork2'
+
+rm -fr cvswork2
+test_expect_success 'gitcvs.dbname' \
+  'GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled true &&
+   GIT_DIR="$SERVERDIR" git config gitcvs.dbname %Ggitcvs.%a.%m.sqlite &&
+   GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 master >cvs.log 2>&1 &&
+   diff -q cvswork cvswork2 &&
+   test -f "$SERVERDIR/gitcvs.ext.master.sqlite" &&
+   cmp "$SERVERDIR/gitcvs.master.sqlite" "$SERVERDIR/gitcvs.ext.master.sqlite"'
+
+rm -fr cvswork2
+test_expect_success 'gitcvs.ext.dbname' \
+  'GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled true &&
+   GIT_DIR="$SERVERDIR" git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite &&
+   GIT_DIR="$SERVERDIR" git config gitcvs.dbname %Ggitcvs2.%a.%m.sqlite &&
+   GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 master >cvs.log 2>&1 &&
+   diff -q cvswork cvswork2 &&
+   test -f "$SERVERDIR/gitcvs1.ext.master.sqlite" &&
+   test ! -f "$SERVERDIR/gitcvs2.ext.master.sqlite" &&
+   cmp "$SERVERDIR/gitcvs.master.sqlite" "$SERVERDIR/gitcvs1.ext.master.sqlite"'
+
+
+#------------
+# CVS UPDATE
+#------------
+
+rm -fr "$SERVERDIR"
+cd "$WORKDIR" &&
+git clone -q --local --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 &&
+GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true &&
+GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log" ||
+exit 1
+
 test_expect_success 'cvs update (create new file)' \
   'echo testfile1 >testfile1 &&
    git add testfile1 &&
@@ -123,4 +334,75 @@ test_expect_success 'cvs update (re-add deleted file)' \
    test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.4/" &&
    diff -q testfile1 ../testfile1'
 
+cd "$WORKDIR"
+test_expect_success 'cvs update (merge)' \
+  'echo Line 0 >expected &&
+   for i in 1 2 3 4 5 6 7
+   do
+     echo Line $i >>merge
+     echo Line $i >>expected
+   done &&
+   echo Line 8 >>expected &&
+   git add merge &&
+   git commit -q -m "Merge test (pre-merge)" &&
+   git push gitcvs.git >/dev/null &&
+   cd cvswork &&
+   GIT_CONFIG="$git_config" cvs -Q update &&
+   test "$(echo $(grep merge CVS/Entries|cut -d/ -f2,3,5))" = "merge/1.1/" &&
+   diff -q merge ../merge &&
+   ( echo Line 0; cat merge ) >merge.tmp &&
+   mv merge.tmp merge &&
+   cd "$WORKDIR" &&
+   echo Line 8 >>merge &&
+   git add merge &&
+   git commit -q -m "Merge test (merge)" &&
+   git push gitcvs.git >/dev/null &&
+   cd cvswork &&
+   sleep 1 && touch merge &&
+   GIT_CONFIG="$git_config" cvs -Q update &&
+   diff -q merge ../expected'
+
+cd "$WORKDIR"
+
+cat >expected.C <<EOF
+<<<<<<< merge.mine
+Line 0
+=======
+LINE 0
+>>>>>>> merge.3
+EOF
+
+for i in 1 2 3 4 5 6 7 8
+do
+  echo Line $i >>expected.C
+done
+
+test_expect_success 'cvs update (conflict merge)' \
+  '( echo LINE 0; cat merge ) >merge.tmp &&
+   mv merge.tmp merge &&
+   git add merge &&
+   git commit -q -m "Merge test (conflict)" &&
+   git push gitcvs.git >/dev/null &&
+   cd cvswork &&
+   GIT_CONFIG="$git_config" cvs -Q update &&
+   diff -q merge ../expected.C'
+
+cd "$WORKDIR"
+test_expect_success 'cvs update (-C)' \
+  'cd cvswork &&
+   GIT_CONFIG="$git_config" cvs -Q update -C &&
+   diff -q merge ../merge'
+
+cd "$WORKDIR"
+test_expect_success 'cvs update (merge no-op)' \
+   'echo Line 9 >>merge &&
+    cp merge cvswork/merge &&
+    git add merge &&
+    git commit -q -m "Merge test (no-op)" &&
+    git push gitcvs.git >/dev/null &&
+    cd cvswork &&
+    sleep 1 && touch merge &&
+    GIT_CONFIG="$git_config" cvs -Q update &&
+    diff -q merge ../merge'
+
 test_done
diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh
new file mode 100755 (executable)
index 0000000..d948724
--- /dev/null
@@ -0,0 +1,524 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Jakub Narebski
+#
+
+test_description='gitweb as standalone script (basic tests).
+
+This test runs gitweb (git web interface) as CGI script from
+commandline, and checks that it would not write any errors
+or warnings to log.'
+
+gitweb_init () {
+       cat >gitweb_config.perl <<EOF
+#!/usr/bin/perl
+
+# gitweb configuration for tests
+
+our \$version = "current";
+our \$GIT = "git";
+our \$projectroot = "$(pwd)";
+our \$home_link_str = "projects";
+our \$site_name = "[localhost]";
+our \$site_header = "";
+our \$site_footer = "";
+our \$home_text = "indextext.html";
+our @stylesheets = ("file:///$(pwd)/../../gitweb/gitweb.css");
+our \$logo = "file:///$(pwd)/../../gitweb/git-logo.png";
+our \$favicon = "file:///$(pwd)/../../gitweb/git-favicon.png";
+our \$projects_list = "";
+our \$export_ok = "";
+our \$strict_export = "";
+
+CGI::Carp::set_programname("gitweb/gitweb.cgi");
+EOF
+
+       cat >.git/description <<EOF
+$0 test repository
+EOF
+}
+
+gitweb_run () {
+       export GATEWAY_INTERFACE="CGI/1.1"
+       export HTTP_ACCEPT="*/*"
+       export REQUEST_METHOD="GET"
+       export QUERY_STRING=""$1""
+       export PATH_INFO=""$2""
+
+       export GITWEB_CONFIG=$(pwd)/gitweb_config.perl
+
+       # some of git commands write to STDERR on error, but this is not
+       # 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 \
+               >/dev/null 2>gitweb.log &&
+       if grep -q -s "^[[]" gitweb.log >/dev/null; then false; else true; fi
+
+       # gitweb.log is left for debugging
+}
+
+. ./test-lib.sh
+
+perl -MEncode -e 'decode_utf8("", Encode::FB_CROAK)' >/dev/null 2>&1 || {
+    test_expect_success 'skipping gitweb tests, perl version is too old' :
+    test_done
+    exit
+}
+
+gitweb_init
+
+# ----------------------------------------------------------------------
+# no commits (empty, just initialized repository)
+
+test_expect_success \
+       'no commits: projects_list (implicit)' \
+       'gitweb_run'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'no commits: projects_index' \
+       'gitweb_run "a=project_index"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'no commits: .git summary (implicit)' \
+       'gitweb_run "p=.git"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'no commits: .git commit (implicit HEAD)' \
+       'gitweb_run "p=.git;a=commit"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'no commits: .git commitdiff (implicit HEAD)' \
+       'gitweb_run "p=.git;a=commitdiff"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'no commits: .git tree (implicit HEAD)' \
+       'gitweb_run "p=.git;a=tree"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'no commits: .git heads' \
+       'gitweb_run "p=.git;a=heads"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'no commits: .git tags' \
+       'gitweb_run "p=.git;a=tags"'
+test_debug 'cat gitweb.log'
+
+
+# ----------------------------------------------------------------------
+# initial commit
+
+test_expect_success \
+       'Make initial commit' \
+       'echo "Not an empty file." > file &&
+        git add file &&
+        git commit -a -m "Initial commit." &&
+        git branch b'
+
+test_expect_success \
+       'projects_list (implicit)' \
+       'gitweb_run'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'projects_index' \
+       'gitweb_run "a=project_index"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       '.git summary (implicit)' \
+       'gitweb_run "p=.git"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       '.git commit (implicit HEAD)' \
+       'gitweb_run "p=.git;a=commit"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       '.git commitdiff (implicit HEAD, root commit)' \
+       'gitweb_run "p=.git;a=commitdiff"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       '.git commitdiff_plain (implicit HEAD, root commit)' \
+       'gitweb_run "p=.git;a=commitdiff_plain"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       '.git commit (HEAD)' \
+       'gitweb_run "p=.git;a=commit;h=HEAD"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       '.git tree (implicit HEAD)' \
+       'gitweb_run "p=.git;a=tree"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       '.git blob (file)' \
+       'gitweb_run "p=.git;a=blob;f=file"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       '.git blob_plain (file)' \
+       'gitweb_run "p=.git;a=blob_plain;f=file"'
+test_debug 'cat gitweb.log'
+
+# ----------------------------------------------------------------------
+# nonexistent objects
+
+test_expect_success \
+       '.git commit (non-existent)' \
+       'gitweb_run "p=.git;a=commit;h=non-existent"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       '.git commitdiff (non-existent)' \
+       'gitweb_run "p=.git;a=commitdiff;h=non-existent"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       '.git commitdiff (non-existent vs HEAD)' \
+       'gitweb_run "p=.git;a=commitdiff;hp=non-existent;h=HEAD"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       '.git tree (0000000000000000000000000000000000000000)' \
+       'gitweb_run "p=.git;a=tree;h=0000000000000000000000000000000000000000"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       '.git tag (0000000000000000000000000000000000000000)' \
+       'gitweb_run "p=.git;a=tag;h=0000000000000000000000000000000000000000"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       '.git blob (non-existent)' \
+       'gitweb_run "p=.git;a=blob;f=non-existent"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       '.git blob_plain (non-existent)' \
+       'gitweb_run "p=.git;a=blob_plain;f=non-existent"'
+test_debug 'cat gitweb.log'
+
+
+# ----------------------------------------------------------------------
+# commitdiff testing (implicit, one implicit tree-ish)
+
+test_expect_success \
+       'commitdiff(0): root' \
+       'gitweb_run "p=.git;a=commitdiff"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'commitdiff(0): file added' \
+       'echo "New file" > new_file &&
+        git add new_file &&
+        git commit -a -m "File added." &&
+        gitweb_run "p=.git;a=commitdiff"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'commitdiff(0): mode change' \
+       'chmod a+x new_file &&
+        git commit -a -m "Mode changed." &&
+        gitweb_run "p=.git;a=commitdiff"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'commitdiff(0): file renamed' \
+       'git mv new_file renamed_file &&
+        git commit -a -m "File renamed." &&
+        gitweb_run "p=.git;a=commitdiff"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'commitdiff(0): file to symlink' \
+       'rm renamed_file &&
+        ln -s file renamed_file &&
+        git commit -a -m "File to symlink." &&
+        gitweb_run "p=.git;a=commitdiff"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'commitdiff(0): file deleted' \
+       'git rm renamed_file &&
+        rm -f renamed_file &&
+        git commit -a -m "File removed." &&
+        gitweb_run "p=.git;a=commitdiff"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'commitdiff(0): file copied / new file' \
+       'cp file file2 &&
+        git add file2 &&
+        git commit -a -m "File copied." &&
+        gitweb_run "p=.git;a=commitdiff"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'commitdiff(0): mode change and modified' \
+       'echo "New line" >> file2 &&
+        chmod a+x file2 &&
+        git commit -a -m "Mode change and modification." &&
+        gitweb_run "p=.git;a=commitdiff"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'commitdiff(0): renamed and modified' \
+       'cat >file2<<EOF &&
+Dominus regit me,
+et nihil mihi deerit.
+In loco pascuae ibi me collocavit,
+super aquam refectionis educavit me;
+animam meam convertit,
+deduxit me super semitas jusitiae,
+propter nomen suum.
+EOF
+        git commit -a -m "File added." &&
+        git mv file2 file3 &&
+        echo "Propter nomen suum." >> file3 &&
+        git commit -a -m "File rename and modification." &&
+        gitweb_run "p=.git;a=commitdiff"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'commitdiff(0): renamed, mode change and modified' \
+       'git mv file3 file2 &&
+        echo "Propter nomen suum." >> file2 &&
+        chmod a+x file2 &&
+        git commit -a -m "File rename, mode change and modification." &&
+        gitweb_run "p=.git;a=commitdiff"'
+test_debug 'cat gitweb.log'
+
+# ----------------------------------------------------------------------
+# commitdiff testing (taken from t4114-apply-typechange.sh)
+
+test_expect_success 'setup typechange commits' '
+       echo "hello world" > foo &&
+       echo "hi planet" > bar &&
+       git update-index --add foo bar &&
+       git commit -m initial &&
+       git branch initial &&
+       rm -f foo &&
+       ln -s bar foo &&
+       git update-index foo &&
+       git commit -m "foo symlinked to bar" &&
+       git branch foo-symlinked-to-bar &&
+       rm -f foo &&
+       echo "how far is the sun?" > foo &&
+       git update-index foo &&
+       git commit -m "foo back to file" &&
+       git branch foo-back-to-file &&
+       rm -f foo &&
+       git update-index --remove foo &&
+       mkdir foo &&
+       echo "if only I knew" > foo/baz &&
+       git update-index --add foo/baz &&
+       git commit -m "foo becomes a directory" &&
+       git branch "foo-becomes-a-directory" &&
+       echo "hello world" > foo/baz &&
+       git update-index foo/baz &&
+       git commit -m "foo/baz is the original foo" &&
+       git branch foo-baz-renamed-from-foo
+       '
+
+test_expect_success \
+       'commitdiff(2): file renamed from foo to foo/baz' \
+       'gitweb_run "p=.git;a=commitdiff;hp=initial;h=foo-baz-renamed-from-foo"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'commitdiff(2): file renamed from foo/baz to foo' \
+       'gitweb_run "p=.git;a=commitdiff;hp=foo-baz-renamed-from-foo;h=initial"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'commitdiff(2): directory becomes file' \
+       'gitweb_run "p=.git;a=commitdiff;hp=foo-becomes-a-directory;h=initial"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'commitdiff(2): file becomes directory' \
+       'gitweb_run "p=.git;a=commitdiff;hp=initial;h=foo-becomes-a-directory"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'commitdiff(2): file becomes symlink' \
+       'gitweb_run "p=.git;a=commitdiff;hp=initial;h=foo-symlinked-to-bar"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'commitdiff(2): symlink becomes file' \
+       'gitweb_run "p=.git;a=commitdiff;hp=foo-symlinked-to-bar;h=foo-back-to-file"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'commitdiff(2): symlink becomes directory' \
+       'gitweb_run "p=.git;a=commitdiff;hp=foo-symlinked-to-bar;h=foo-becomes-a-directory"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'commitdiff(2): directory becomes symlink' \
+       'gitweb_run "p=.git;a=commitdiff;hp=foo-becomes-a-directory;h=foo-symlinked-to-bar"'
+test_debug 'cat gitweb.log'
+
+# ----------------------------------------------------------------------
+# commit, commitdiff: merge, large
+test_expect_success \
+       'Create a merge' \
+       'git checkout b &&
+        echo "Branch" >> b &&
+        git add b &&
+        git commit -a -m "On branch" &&
+        git checkout master &&
+        git pull . b'
+
+test_expect_success \
+       'commit(0): merge commit' \
+       'gitweb_run "p=.git;a=commit"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'commitdiff(0): merge commit' \
+       'gitweb_run "p=.git;a=commitdiff"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'Prepare large commit' \
+       'git checkout b &&
+        echo "To be changed" > 01-change &&
+        echo "To be renamed" > 02-pure-rename-from &&
+        echo "To be deleted" > 03-delete &&
+        echo "To be renamed and changed" > 04-rename-from &&
+        echo "To have mode changed" > 05-mode-change &&
+        echo "File to symlink" > 06-file-or-symlink &&
+        echo "To be changed and have mode changed" > 07-change-mode-change     &&
+        git add 0* &&
+        git commit -a -m "Prepare large commit" &&
+        echo "Changed" > 01-change &&
+        git mv 02-pure-rename-from 02-pure-rename-to &&
+        git rm 03-delete && rm -f 03-delete &&
+        echo "A new file" > 03-new &&
+        git add 03-new &&
+        git mv 04-rename-from 04-rename-to &&
+        echo "Changed" >> 04-rename-to &&
+        chmod a+x 05-mode-change &&
+        rm -f 06-file-or-symlink && ln -s 01-change 06-file-or-symlink &&
+        echo "Changed and have mode changed" > 07-change-mode-change   &&
+        chmod a+x 07-change-mode-change &&
+        git commit -a -m "Large commit" &&
+        git checkout master'
+
+test_expect_success \
+       'commit(1): large commit' \
+       'gitweb_run "p=.git;a=commit;h=b"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'commitdiff(1): large commit' \
+       'gitweb_run "p=.git;a=commitdiff;h=b"'
+test_debug 'cat gitweb.log'
+
+# ----------------------------------------------------------------------
+# tags testing
+
+test_expect_success \
+       'tags: list of different types of tags' \
+       'git checkout master &&
+        git tag -a -m "Tag commit object" tag-commit HEAD &&
+        git tag -a -m "" tag-commit-nomessage HEAD &&
+        git tag -a -m "Tag tag object" tag-tag tag-commit &&
+        git tag -a -m "Tag tree object" tag-tree HEAD^{tree} &&
+        git tag -a -m "Tag blob object" tag-blob HEAD:file &&
+        git tag lightweight/tag-commit HEAD &&
+        git tag lightweight/tag-tag tag-commit &&
+        git tag lightweight/tag-tree HEAD^{tree} &&
+        git tag lightweight/tag-blob HEAD:file &&
+        gitweb_run "p=.git;a=tags"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'tag: Tag to commit object' \
+       'gitweb_run "p=.git;a=tag;h=tag-commit"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'tag: on lightweight tag (invalid)' \
+       'gitweb_run "p=.git;a=tag;h=lightweight/tag-commit"'
+test_debug 'cat gitweb.log'
+
+# ----------------------------------------------------------------------
+# logs
+
+test_expect_success \
+       'logs: log (implicit HEAD)' \
+       'gitweb_run "p=.git;a=log"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'logs: shortlog (implicit HEAD)' \
+       'gitweb_run "p=.git;a=shortlog"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'logs: history (implicit HEAD, file)' \
+       'gitweb_run "p=.git;a=history;f=file"'
+test_debug 'cat gitweb.log'
+
+# ----------------------------------------------------------------------
+# feed generation
+
+test_expect_success \
+       'feeds: OPML' \
+       'gitweb_run "a=opml"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'feed: RSS' \
+       'gitweb_run "p=.git;a=rss"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'feed: Atom' \
+       'gitweb_run "p=.git;a=atom"'
+test_debug 'cat gitweb.log'
+
+# ----------------------------------------------------------------------
+# encoding/decoding
+
+test_expect_success \
+       'encode(commit): utf8' \
+       '. ../t3901-utf8.txt &&
+        echo "UTF-8" >> file &&
+        git add file &&
+        git commit -F ../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 &&
+        echo "ISO-8859-1" >> file &&
+        git add file &&
+        git config i18n.commitencoding ISO-8859-1 &&
+        git commit -F ../t3900/ISO-8859-1.txt &&
+        git config --unset i18n.commitencoding &&
+        gitweb_run "p=.git;a=commit"'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
+       'encode(log): utf-8 and iso-8859-1' \
+       'gitweb_run "p=.git;a=log"'
+test_debug 'cat gitweb.log'
+
+test_done
index dee3ad76212ea95c75c8287c8d8c0f312125bd06..78d7e87e86178b90a350714c0b287353a0de20b4 100644 (file)
@@ -26,6 +26,7 @@ GIT_COMMITTER_EMAIL=committer@example.com
 GIT_COMMITTER_NAME='C O Mitter'
 unset GIT_DIFF_OPTS
 unset GIT_DIR
+unset GIT_WORK_TREE
 unset GIT_EXTERNAL_DIFF
 unset GIT_INDEX_FILE
 unset GIT_OBJECT_DIRECTORY
@@ -232,7 +233,7 @@ test_create_repo () {
        mv .git/hooks .git/hooks-disabled
        cd "$owd"
 }
-       
+
 test_done () {
        trap - exit
        case "$test_failure" in
index b8352e731bf4baffbda780a1420f52ca4670b828..aaa39d30fa57c21f15b5308f8d51de5c2e9d59c0 100644 (file)
@@ -7,7 +7,7 @@ endif
 INSTALL ?= install
 TAR ?= tar
 prefix ?= $(HOME)
-template_dir ?= $(prefix)/share/git-core/templates/
+template_dir ?= $(prefix)/share/git-core/templates
 # DESTDIR=
 
 # Shell quote (do not use $(call) to accommodate ancient setups);
index 9b04f2d69c6dc054e8e5403062fb7ef5d2117328..c5cdb9d7eeebab7edf048e77eb92437de24751bf 100644 (file)
@@ -19,4 +19,3 @@ test "" = "$(grep '^Signed-off-by: ' "$1" |
        echo >&2 Duplicate Signed-off-by lines.
        exit 1
 }
-
index 190de2688cd2ef82525a0998e0c5133f8cd45a83..b70c8fd36430fb1e0b02119d7f802c2144fa2a41 100644 (file)
@@ -14,4 +14,3 @@
 
 
 #. /usr/share/doc/git-core/contrib/hooks/post-receive-email
-
index 5f56ce8053a40919cbf02010e29f185b6f9d8784..eeccc934cad8bb74624ed388988fe79c26e6900d 100644 (file)
@@ -12,4 +12,3 @@
 test -x "$GIT_DIR/hooks/pre-commit" &&
        exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"}
 :
-
index 723a9ef210bb84c217026c2cdf9d30661f64447b..18b87309f65be23794b87260e08c547f5deeefce 100644 (file)
@@ -68,4 +68,3 @@ perl -e '
     }
     exit($found_bad);
 '
-
index 852498eb49fe0cba5e1cd21661288e8321a4b20e..26bdbdd2bfea5eab99b9f1c38936efe56f1ab45a 100644 (file)
@@ -3,6 +3,7 @@
  */
 #include "cache.h"
 #include "diff.h"
+#include "diffcore.h"
 #include "tree.h"
 
 static char *malloc_base(const char *base, int baselen, const char *path, int pathlen)
@@ -290,6 +291,78 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru
        return 0;
 }
 
+/*
+ * Does it look like the resulting diff might be due to a rename?
+ *  - single entry
+ *  - not a valid previous file
+ */
+static inline int diff_might_be_rename(void)
+{
+       return diff_queued_diff.nr == 1 &&
+               !DIFF_FILE_VALID(diff_queued_diff.queue[0]->one);
+}
+
+static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)
+{
+       struct diff_options diff_opts;
+       struct diff_queue_struct *q = &diff_queued_diff;
+       struct diff_filepair *choice;
+       const char *paths[1];
+       int i;
+
+       /* Remove the file creation entry from the diff queue, and remember it */
+       choice = q->queue[0];
+       q->nr = 0;
+
+       diff_setup(&diff_opts);
+       diff_opts.recursive = 1;
+       diff_opts.detect_rename = DIFF_DETECT_RENAME;
+       diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
+       diff_opts.single_follow = opt->paths[0];
+       paths[0] = NULL;
+       diff_tree_setup_paths(paths, &diff_opts);
+       if (diff_setup_done(&diff_opts) < 0)
+               die("unable to set up diff options to follow renames");
+       diff_tree(t1, t2, base, &diff_opts);
+       diffcore_std(&diff_opts);
+
+       /* Go through the new set of filepairing, and see if we find a more interesting one */
+       for (i = 0; i < q->nr; i++) {
+               struct diff_filepair *p = q->queue[i];
+
+               /*
+                * Found a source? Not only do we use that for the new
+                * diff_queued_diff, we will also use that as the path in
+                * the future!
+                */
+               if ((p->status == 'R' || p->status == 'C') && !strcmp(p->two->path, opt->paths[0])) {
+                       /* Switch the file-pairs around */
+                       q->queue[i] = choice;
+                       choice = p;
+
+                       /* Update the path we use from now on.. */
+                       opt->paths[0] = xstrdup(p->one->path);
+                       diff_tree_setup_paths(opt->paths, opt);
+                       break;
+               }
+       }
+
+       /*
+        * Then, discard all the non-relevane file pairs...
+        */
+       for (i = 0; i < q->nr; i++) {
+               struct diff_filepair *p = q->queue[i];
+               diff_free_filepair(p);
+       }
+
+       /*
+        * .. and re-instate the one we want (which might be either the
+        * original one, or the rename/copy we found)
+        */
+       q->queue[0] = choice;
+       q->nr = 1;
+}
+
 int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const char *base, struct diff_options *opt)
 {
        void *tree1, *tree2;
@@ -306,6 +379,11 @@ int diff_tree_sha1(const unsigned char *old, const unsigned char *new, const cha
        init_tree_desc(&t1, tree1, size1);
        init_tree_desc(&t2, tree2, size2);
        retval = diff_tree(&t1, &t2, base, opt);
+       if (opt->follow_renames && diff_might_be_rename()) {
+               init_tree_desc(&t1, tree1, size1);
+               init_tree_desc(&t2, tree2, size2);
+               try_to_follow_renames(&t1, &t2, base, opt);
+       }
        free(tree1);
        free(tree2);
        return retval;
index cbb24eb3f663cd0370f528d983a2266a55b91c4f..8d4b67317f21508a105175686c7ec98a090ed9b5 100644 (file)
@@ -206,4 +206,3 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch
        free(tree);
        return retval;
 }
-
index ee747aba0bec914bd8f5c7a5285c8395ba5f489b..db0fbdc701f1ef63cdc1a8b7d5c5e72322f91426 100644 (file)
@@ -22,7 +22,7 @@ static inline const unsigned char *tree_entry_extract(struct tree_desc *desc, co
 
 static inline int tree_entry_len(const char *name, const unsigned char *sha1)
 {
-       return (char *)sha1 - (char *)name - 1;
+       return (const char *)sha1 - name - 1;
 }
 
 void update_tree_entry(struct tree_desc *);
diff --git a/tree.c b/tree.c
index e946dac06938b44ce13d7e30dd93e26eda75e5ef..04fe653a8e25feb0fc15f76ba487d0f8dbd52f82 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -157,7 +157,7 @@ static void track_tree_refs(struct tree *item)
        /* Count how many entries there are.. */
        init_tree_desc(&desc, item->buffer, item->size);
        while (tree_entry(&desc, &entry)) {
-               if (S_ISDIRLNK(entry.mode))
+               if (S_ISGITLINK(entry.mode))
                        continue;
                n_refs++;
        }
@@ -169,7 +169,7 @@ static void track_tree_refs(struct tree *item)
        while (tree_entry(&desc, &entry)) {
                struct object *obj;
 
-               if (S_ISDIRLNK(entry.mode))
+               if (S_ISGITLINK(entry.mode))
                        continue;
                if (S_ISDIR(entry.mode))
                        obj = &lookup_tree(entry.sha1)->object;
index d3a09e78d56642db9b1fb1b1ead34ff60dd8c923..fe96ef15c43fa6e3f8f947f84ddce3c498e82859 100644 (file)
@@ -62,7 +62,7 @@ static ssize_t send_client_data(int fd, const char *data, ssize_t sz)
        return safe_write(fd, data, sz);
 }
 
-FILE *pack_pipe = NULL;
+static FILE *pack_pipe = NULL;
 static void show_commit(struct commit *commit)
 {
        if (commit->object.flags & BOUNDARY)
@@ -678,7 +678,7 @@ int main(int argc, char **argv)
                        break;
                }
        }
-       
+
        if (i != argc-1)
                usage(upload_pack_usage);
        dir = argv[i];
diff --git a/var.c b/var.c
index e585e59d315061e2e82ea8a23843c128bcce2555..4127031910c83987c8ef394e3711942e2db8a8f9 100644 (file)
--- a/var.c
+++ b/var.c
@@ -67,8 +67,8 @@ int main(int argc, char **argv)
        val = read_var(argv[1]);
        if (!val)
                usage(var_usage);
-       
+
        printf("%s\n", val);
-       
+
        return 0;
 }
index 5c4bc8515ab9484131de7e065e08657315004f8c..e125e11d3b63e3dab9077d7b414e83e7ff7d16ad 100644 (file)
@@ -1,5 +1,45 @@
 #include "cache.h"
 
+/*
+ * Some cases use stdio, but want to flush after the write
+ * to get error handling (and to get better interactive
+ * behaviour - not buffering excessively).
+ *
+ * Of course, if the flush happened within the write itself,
+ * we've already lost the error code, and cannot report it any
+ * more. So we just ignore that case instead (and hope we get
+ * the right error code on the flush).
+ *
+ * If the file handle is stdout, and stdout is a file, then skip the
+ * flush entirely since it's not needed.
+ */
+void maybe_flush_or_die(FILE *f, const char *desc)
+{
+       static int skip_stdout_flush = -1;
+       struct stat st;
+       char *cp;
+
+       if (f == stdout) {
+               if (skip_stdout_flush < 0) {
+                       cp = getenv("GIT_FLUSH");
+                       if (cp)
+                               skip_stdout_flush = (atoi(cp) == 0);
+                       else if ((fstat(fileno(stdout), &st) == 0) &&
+                                S_ISREG(st.st_mode))
+                               skip_stdout_flush = 1;
+                       else
+                               skip_stdout_flush = 0;
+               }
+               if (skip_stdout_flush && !ferror(f))
+                       return;
+       }
+       if (fflush(f)) {
+               if (errno == EPIPE)
+                       exit(0);
+               die("write failure on %s: %s", desc, strerror(errno));
+       }
+}
+
 int read_in_full(int fd, void *buf, size_t count)
 {
        char *p = buf;
index 4bfe8f15d8a0e275f1ed2d2458cda4d592f7c630..52054201c2a8729e036a5d97337a5f85bcafc782 100644 (file)
@@ -198,7 +198,7 @@ static void wt_read_cache(struct wt_status *s)
        read_cache();
 }
 
-void wt_status_print_initial(struct wt_status *s)
+static void wt_status_print_initial(struct wt_status *s)
 {
        int i;
        char buf[PATH_MAX];
index 963bb89b08e64188ba278587f63f380653b019c6..be866d12d38f6f1328f5fae8c7108176d4ecba70 100644 (file)
@@ -130,4 +130,73 @@ int buffer_is_binary(const char *ptr, unsigned long size)
        return !!memchr(ptr, 0, size);
 }
 
+struct ff_regs {
+       int nr;
+       struct ff_reg {
+               regex_t re;
+               int negate;
+       } *array;
+};
 
+static long ff_regexp(const char *line, long len,
+               char *buffer, long buffer_size, void *priv)
+{
+       char *line_buffer = xstrndup(line, len); /* make NUL terminated */
+       struct ff_regs *regs = priv;
+       regmatch_t pmatch[2];
+       int result = 0, i;
+
+       for (i = 0; i < regs->nr; i++) {
+               struct ff_reg *reg = regs->array + i;
+               if (reg->negate ^ !!regexec(&reg->re,
+                                       line_buffer, 2, pmatch, 0)) {
+                       free(line_buffer);
+                       return -1;
+               }
+       }
+       i = pmatch[1].rm_so >= 0 ? 1 : 0;
+       line += pmatch[i].rm_so;
+       result = pmatch[i].rm_eo - pmatch[i].rm_so;
+       if (result > buffer_size)
+               result = buffer_size;
+       else
+               while (result > 0 && (isspace(line[result - 1]) ||
+                                       line[result - 1] == '\n'))
+                       result--;
+       memcpy(buffer, line, result);
+       free(line_buffer);
+       return result;
+}
+
+void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value)
+{
+       int i;
+       struct ff_regs *regs;
+
+       xecfg->find_func = ff_regexp;
+       regs = xecfg->find_func_priv = xmalloc(sizeof(struct ff_regs));
+       for (i = 0, regs->nr = 1; value[i]; i++)
+               if (value[i] == '\n')
+                       regs->nr++;
+       regs->array = xmalloc(regs->nr * sizeof(struct ff_reg));
+       for (i = 0; i < regs->nr; i++) {
+               struct ff_reg *reg = regs->array + i;
+               const char *ep = strchr(value, '\n'), *expression;
+               char *buffer = NULL;
+
+               reg->negate = (*value == '!');
+               if (reg->negate && i == regs->nr - 1)
+                       die("Last expression must not be negated: %s", value);
+               if (*value == '!')
+                       value++;
+               if (ep)
+                       expression = buffer = xstrndup(value, ep - value);
+               else
+                       expression = value;
+               if (regcomp(&reg->re, expression, 0))
+                       die("Invalid regexp to look for hunk header: %s", expression);
+               if (buffer)
+                       free(buffer);
+               value = ep + 1;
+       }
+}
index 536f4e4d9784e0e5ffdc108a5be4bf758d1578ba..fb742dbb6ba2125b970b9d9510e208ec99954a2d 100644 (file)
@@ -20,4 +20,6 @@ int parse_hunk_header(char *line, int len,
 int read_mmfile(mmfile_t *ptr, const char *filename);
 int buffer_is_binary(const char *ptr, unsigned long size);
 
+extern void xdiff_set_find_func(xdemitconf_t *xecfg, const char *line);
+
 #endif
index e874a7c46a90104ebf586d0fc48964634f356763..c00ddaa6e987407743d2c8877f9ca6e772f89c86 100644 (file)
@@ -73,9 +73,13 @@ typedef struct s_xdemitcb {
        int (*outf)(void *, mmbuffer_t *, int);
 } xdemitcb_t;
 
+typedef long (*find_func_t)(const char *line, long line_len, char *buffer, long buffer_size, void *priv);
+
 typedef struct s_xdemitconf {
        long ctxlen;
        unsigned long flags;
+       find_func_t find_func;
+       void *find_func_priv;
 } xdemitconf_t;
 
 typedef struct s_bdiffparam {
@@ -103,4 +107,3 @@ int xdl_merge(mmfile_t *orig, mmfile_t *mf1, const char *name1,
 #endif /* #ifdef __cplusplus */
 
 #endif /* #if !defined(XDIFF_H) */
-
index 9aeebc473b11a3dbfa5b52930b4a8e5a35f22215..5cb7171a8f528881c6171defa5b102e87d7aa522 100644 (file)
@@ -565,4 +565,3 @@ int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
 
        return 0;
 }
-
index 472aeaecfab85e7276baaceb446d2095eeab01fd..3e099dc445d6130f6a0ce2c6270a3b06d6ee119f 100644 (file)
@@ -57,4 +57,3 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
                  xdemitconf_t const *xecfg);
 
 #endif /* #if !defined(XDIFFI_H) */
-
index e291dc7608c4ab9b54a5d049bf3b555704e37fe8..d3d9c845c6420e4881636d779c7029f900a0b067 100644 (file)
@@ -69,7 +69,24 @@ static xdchange_t *xdl_get_hunk(xdchange_t *xscr, xdemitconf_t const *xecfg) {
 }
 
 
-static void xdl_find_func(xdfile_t *xf, long i, char *buf, long sz, long *ll) {
+static long def_ff(const char *rec, long len, char *buf, long sz, void *priv)
+{
+       if (len > 0 &&
+                       (isalpha((unsigned char)*rec) || /* identifier? */
+                        *rec == '_' || /* also identifier? */
+                        *rec == '$')) { /* identifiers from VMS and other esoterico */
+               if (len > sz)
+                       len = sz;
+               while (0 < len && isspace((unsigned char)rec[len - 1]))
+                       len--;
+               memcpy(buf, rec, len);
+               return len;
+       }
+       return -1;
+}
+
+static void xdl_find_func(xdfile_t *xf, long i, char *buf, long sz, long *ll,
+               find_func_t ff, void *ff_priv) {
 
        /*
         * Be quite stupid about this for now.  Find a line in the old file
@@ -80,27 +97,17 @@ static void xdl_find_func(xdfile_t *xf, long i, char *buf, long sz, long *ll) {
        const char *rec;
        long len;
 
-       *ll = 0;
        while (i-- > 0) {
                len = xdl_get_rec(xf, i, &rec);
-               if (len > 0 &&
-                   (isalpha((unsigned char)*rec) || /* identifier? */
-                    *rec == '_' ||     /* also identifier? */
-                    *rec == '$')) {    /* mysterious GNU diff's invention */
-                       if (len > sz)
-                               len = sz;
-                       while (0 < len && isspace((unsigned char)rec[len - 1]))
-                               len--;
-                       memcpy(buf, rec, len);
-                       *ll = len;
+               if ((*ll = ff(rec, len, buf, sz, ff_priv)) >= 0)
                        return;
-               }
        }
+       *ll = 0;
 }
 
 
-int xdl_emit_common(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
-                   xdemitconf_t const *xecfg) {
+static int xdl_emit_common(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
+                           xdemitconf_t const *xecfg) {
        xdfile_t *xdf = &xe->xdf1;
        const char *rchg = xdf->rchg;
        long ix;
@@ -120,6 +127,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
        xdchange_t *xch, *xche;
        char funcbuf[80];
        long funclen = 0;
+       find_func_t ff = xecfg->find_func ?  xecfg->find_func : def_ff;
 
        if (xecfg->flags & XDL_EMIT_COMMON)
                return xdl_emit_common(xe, xscr, ecb, xecfg);
@@ -143,7 +151,8 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
 
                if (xecfg->flags & XDL_EMIT_FUNCNAMES) {
                        xdl_find_func(&xe->xdf1, s1, funcbuf,
-                                     sizeof(funcbuf), &funclen);
+                                     sizeof(funcbuf), &funclen,
+                                     ff, xecfg->find_func_priv);
                }
                if (xdl_emit_hunk_hdr(s1 + 1, e1 - s1, s2 + 1, e2 - s2,
                                      funcbuf, funclen, ecb) < 0)
@@ -194,4 +203,3 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
 
        return 0;
 }
-
index e629417dd2028be30e661fe9059a9a3af30b482d..440a7390fa4abb0411c336cfba616e3229484e86 100644 (file)
@@ -31,4 +31,3 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
 
 
 #endif /* #if !defined(XEMIT_H) */
-
index 04a9da82c9cb7a2ab24d86efb0e6c6aafdd55f3b..526ccb344d231fb978f53b80deb17ec6c8fed368 100644 (file)
@@ -40,4 +40,3 @@
 
 
 #endif /* #if !defined(XINCLUDE_H) */
-
index e2cd2023b31e794bc0c5ba28f64ae4ce4e128184..8ef232cfad12d706aaafe705bf16c546f3597182 100644 (file)
@@ -51,4 +51,3 @@ do { \
 
 
 #endif /* #if !defined(XMACROS_H) */
-
index 1be7b3195059bebffe83d17301f3ff0fb261799e..e87ab57c652b56b1a684e2a0a56885c1d1b27ef7 100644 (file)
@@ -466,4 +466,3 @@ static int xdl_optimize_ctxs(xdfile_t *xdf1, xdfile_t *xdf2) {
 
        return 0;
 }
-
index 344c569e8b4ebeec2f1e6130184a424ae1341bf6..8fb06a537451cbf3335ab4bdacb0f992e9744338 100644 (file)
@@ -32,4 +32,3 @@ void xdl_free_env(xdfenv_t *xe);
 
 
 #endif /* #if !defined(XPREPARE_H) */
-
index 3593a664fc2e58a6cdd2a5f3bdee46dd5ffdaa8e..2511aef8d89ab52be5ec6a5e46236b4b6bcd07ea 100644 (file)
@@ -65,4 +65,3 @@ typedef struct s_xdfenv {
 
 
 #endif /* #if !defined(XTYPES_H) */
-
index bf91c0f73c658637d078ac93226148faa3bb0dc4..2ade97b2574a9f77e7ae4002a4e07a6a38e46d07 100644 (file)
@@ -380,4 +380,3 @@ int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
 
        return 0;
 }
-
index 70d8b9838a7333bc5a1edb93cf0e9abdbcf146cc..d5de8292e05e7c36c4b68857c1cf9855e3d2f70a 100644 (file)
@@ -45,4 +45,3 @@ int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
 
 
 #endif /* #if !defined(XUTILS_H) */
-