Merge branch 'jk/trailing-slash-in-pathspec'
authorJunio C Hamano <gitster@pobox.com>
Thu, 17 Oct 2013 22:55:13 +0000 (15:55 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 17 Oct 2013 22:55:14 +0000 (15:55 -0700)
Code refactoring.

* jk/trailing-slash-in-pathspec:
reset: handle submodule with trailing slash
rm: re-use parse_pathspec's trailing-slash removal

240 files changed:
.mailmap
Documentation/CodingGuidelines
Documentation/Makefile
Documentation/RelNotes/1.7.11.2.txt
Documentation/RelNotes/1.8.4.1.txt [new file with mode: 0644]
Documentation/RelNotes/1.8.4.2.txt [new file with mode: 0644]
Documentation/RelNotes/1.8.5.txt
Documentation/config.txt
Documentation/diff-config.txt
Documentation/everyday.txt
Documentation/git-branch.txt
Documentation/git-cat-file.txt
Documentation/git-check-ignore.txt
Documentation/git-check-ref-format.txt
Documentation/git-checkout.txt
Documentation/git-cherry.txt
Documentation/git-credential.txt
Documentation/git-describe.txt
Documentation/git-diff.txt
Documentation/git-fast-import.txt
Documentation/git-format-patch.txt
Documentation/git-merge-tree.txt
Documentation/git-name-rev.txt
Documentation/git-prune-packed.txt
Documentation/git-pull.txt
Documentation/git-push.txt
Documentation/git-rebase.txt
Documentation/git-remote.txt
Documentation/git-replace.txt
Documentation/git-revert.txt
Documentation/git-status.txt
Documentation/git-svn.txt
Documentation/git-update-ref.txt
Documentation/git.txt
Documentation/gitcli.txt
Documentation/gitcvs-migration.txt
Documentation/gitmodules.txt
Documentation/gitremote-helpers.txt
Documentation/glossary-content.txt
Documentation/howto/revert-a-faulty-merge.txt
Documentation/howto/revert-branch-rebase.txt
Documentation/howto/setup-git-server-over-http.txt
Documentation/revisions.txt
Documentation/technical/http-protocol.txt
Documentation/technical/pack-heuristics.txt
Documentation/user-manual.txt
Makefile
bisect.c
branch.c
builtin/add.c
builtin/branch.c
builtin/check-ignore.c
builtin/clone.c
builtin/commit.c
builtin/config.c
builtin/describe.c
builtin/fast-export.c
builtin/fetch.c
builtin/fsck.c
builtin/index-pack.c
builtin/ls-files.c
builtin/merge.c
builtin/pack-objects.c
builtin/push.c
builtin/receive-pack.c
builtin/reflog.c
builtin/remote.c
builtin/replace.c
builtin/reset.c
builtin/rev-list.c
builtin/revert.c
builtin/shortlog.c
builtin/stripspace.c
builtin/tag.c
builtin/update-ref.c
bulk-checkin.c
cache.h
commit.h
compat/mingw.c
compat/mingw.h
compat/msvc.h
compat/nedmalloc/malloc.c.h
compat/poll/poll.c
compat/precompose_utf8.c
config.c
config.mak.uname
connect.c
contrib/ciabot/INSTALL [deleted file]
contrib/ciabot/README [deleted file]
contrib/ciabot/ciabot.py [deleted file]
contrib/ciabot/ciabot.sh [deleted file]
contrib/completion/git-completion.bash
contrib/contacts/git-contacts
contrib/credential/netrc/git-credential-netrc
contrib/examples/git-merge.sh
contrib/hooks/post-receive-email
contrib/mw-to-git/Makefile
contrib/mw-to-git/git-remote-mediawiki.perl
contrib/mw-to-git/t/t9365-continuing-queries.sh [new file with mode: 0755]
contrib/remote-helpers/git-remote-bzr
contrib/remote-helpers/git-remote-hg
contrib/remote-helpers/test-bzr.sh
contrib/remote-helpers/test-hg-bidi.sh
contrib/remote-helpers/test-hg-hg-git.sh
contrib/remote-helpers/test-hg.sh
diff-no-index.c
dir.c
dir.h
environment.c
fast-import.c
fetch-pack.c
git-add--interactive.perl
git-compat-util.h
git-cvsserver.perl
git-filter-branch.sh
git-mergetool--lib.sh
git-p4.py
git-pull.sh
git-rebase--interactive.sh
git-rebase.sh
git-remote-testgit.sh
git-remote-testpy.py [deleted file]
git-send-email.perl
git-submodule.sh
git-svn.perl
git.c
git_remote_helpers/.gitignore [deleted file]
git_remote_helpers/Makefile [deleted file]
git_remote_helpers/__init__.py [deleted file]
git_remote_helpers/git/__init__.py [deleted file]
git_remote_helpers/git/exporter.py [deleted file]
git_remote_helpers/git/git.py [deleted file]
git_remote_helpers/git/importer.py [deleted file]
git_remote_helpers/git/non_local.py [deleted file]
git_remote_helpers/git/repo.py [deleted file]
git_remote_helpers/setup.cfg [deleted file]
git_remote_helpers/setup.py [deleted file]
git_remote_helpers/util.py [deleted file]
gitweb/gitweb.perl
gitweb/static/gitweb.css
http-backend.c
http-push.c
list-objects.c
list-objects.h
mailmap.c
merge-recursive.c
mergetools/diffmerge [new file with mode: 0644]
notes-utils.h
object.c
pager.c
perl/Git/SVN/Ra.pm
po/da.po
po/de.po
po/fr.po
po/git.pot
po/it.po
po/nl.po
po/pt_PT.po
po/sv.po
po/vi.po
po/zh_CN.po
reachable.c
read-cache.c
refs.c
refs.h
remote.c
revision.c
sequencer.c
sha1-lookup.c
sha1_file.c
sha1_name.c
shallow.c
t/lib-git-p4.sh
t/lib-httpd.sh
t/lib-pack.sh [new file with mode: 0644]
t/t0001-init.sh
t/t0008-ignores.sh
t/t0050-filesystem.sh
t/t0056-git-C.sh [new file with mode: 0755]
t/t0060-path-utils.sh
t/t1300-repo-config.sh
t/t1400-update-ref.sh
t/t1508-at-combinations.sh
t/t1511-rev-parse-caret.sh
t/t2008-checkout-subdir.sh
t/t2024-checkout-dwim.sh
t/t3001-ls-files-others-exclude.sh
t/t3010-ls-files-killed-modified.sh
t/t3200-branch.sh
t/t3404-rebase-interactive.sh
t/t3409-rebase-preserve-merges.sh
t/t3501-revert-cherry-pick.sh
t/t3506-cherry-pick-ff.sh
t/t3509-cherry-pick-merge-df.sh
t/t3701-add-interactive.sh
t/t3910-mac-os-precompose.sh
t/t4055-diff-context.sh
t/t4201-shortlog.sh
t/t4203-mailmap.sh
t/t4254-am-corrupt.sh
t/t5308-pack-detect-duplicates.sh [new file with mode: 0755]
t/t5309-pack-delta-cycles.sh [new file with mode: 0755]
t/t5500-fetch-pack.sh
t/t5516-fetch-push.sh
t/t5520-pull.sh
t/t5530-upload-pack-error.sh
t/t5601-clone.sh
t/t5706-clone-branch.sh
t/t5800-remote-testpy.sh [deleted file]
t/t5801-remote-helpers.sh
t/t6022-merge-rename.sh
t/t6040-tracking-info.sh
t/t6050-replace.sh
t/t6101-rev-parse-parents.sh
t/t7009-filter-branch-null-sha1.sh [new file with mode: 0755]
t/t7060-wtstatus.sh
t/t7106-reset-unborn-branch.sh
t/t7400-submodule-basic.sh
t/t7401-submodule-summary.sh
t/t7406-submodule-update.sh
t/t7501-commit.sh
t/t7508-status.sh
t/t7512-status-help.sh
t/t9117-git-svn-init-clone.sh
t/t9300-fast-import.sh
t/t9500-gitweb-standalone-no-errors.sh
t/test-lib.sh
templates/hooks--pre-commit.sample
test-match-trees.c
test-path-utils.c
test-sha1.c
transport-helper.c
tree.c
tree.h
upload-pack.c
urlmatch.c
walker.c
wrapper.c
wt-status.c
wt-status.h
index 1c1f5ec6bf83ca9dd27f7dacaa05b722202e115b..11057cbcdf4c9f814189bdbf0a17980825da194c 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -218,7 +218,9 @@ Tay Ray Chuan <rctay89@gmail.com>
 Ted Percival <ted@midg3t.net> <ted.percival@quest.com>
 Theodore Ts'o <tytso@mit.edu>
 Thomas Ackermann <th.acker@arcor.de> <th.acker66@arcor.de>
-Thomas Rast <trast@inf.ethz.ch> <trast@student.ethz.ch>
+Thomas Rast <tr@thomasrast.ch> <trast@student.ethz.ch>
+Thomas Rast <tr@thomasrast.ch> <trast@inf.ethz.ch>
+Thomas Rast <tr@thomasrast.ch> <trast@google.com>
 Timo Hirvonen <tihirvon@gmail.com> <tihirvon@ee.oulu.fi>
 Toby Allsopp <Toby.Allsopp@navman.co.nz> <toby.allsopp@navman.co.nz>
 Tom Grennan <tmgrennan@gmail.com> <tgrennan@redback.com>
index e5ca3b75d3778308ee1b7b20e3a86475244f7b96..a600e35c810b74848062dee8d74e573192c09e2c 100644 (file)
@@ -145,6 +145,14 @@ For C programs:
    they were describing changes.  Often splitting a function
    into two makes the intention of the code much clearer.
 
+ - Multi-line comments include their delimiters on separate lines from
+   the text.  E.g.
+
+       /*
+        * A very long
+        * multi-line comment.
+        */
+
  - Double negation is often harder to understand than no negation
    at all.
 
index 0cfdc36b44ee51d827136c2bdd75c3d977f03742..4f13a23893047a022be23d245d2df920b1845eac 100644 (file)
@@ -103,6 +103,7 @@ MAKEINFO = makeinfo
 INSTALL_INFO = install-info
 DOCBOOK2X_TEXI = docbook2x-texi
 DBLATEX = dblatex
+ASCIIDOC_DBLATEX_DIR = /etc/asciidoc/dblatex
 ifndef PERL_PATH
        PERL_PATH = /usr/bin/perl
 endif
@@ -354,7 +355,7 @@ user-manual.texi: user-manual.xml
 
 user-manual.pdf: user-manual.xml
        $(QUIET_DBLATEX)$(RM) $@+ $@ && \
-       $(DBLATEX) -o $@+ -p /etc/asciidoc/dblatex/asciidoc-dblatex.xsl -s /etc/asciidoc/dblatex/asciidoc-dblatex.sty $< && \
+       $(DBLATEX) -o $@+ -p $(ASCIIDOC_DBLATEX_DIR)/asciidoc-dblatex.xsl -s $(ASCIIDOC_DBLATEX_DIR)/asciidoc-dblatex.sty $< && \
        mv $@+ $@
 
 gitman.texi: $(MAN_XML) cat-texi.perl
index a0d24d1270dd76b8d3226ef56c8eb246df0323b9..f0cfd02d6ff318a614333929ec130c3aac7799aa 100644 (file)
@@ -31,7 +31,7 @@ Fixes since v1.7.11.1
  * "git diff --no-index" did not work with pagers correctly.
 
  * "git diff COPYING HEAD:COPYING" gave a nonsense error message that
-   claimed that the treeish HEAD did not have COPYING in it.
+   claimed that the tree-ish HEAD did not have COPYING in it.
 
  * When "git log" gets "--simplify-merges/by-decoration" together with
    "--first-parent", the combination of these options makes the
diff --git a/Documentation/RelNotes/1.8.4.1.txt b/Documentation/RelNotes/1.8.4.1.txt
new file mode 100644 (file)
index 0000000..3aa25a2
--- /dev/null
@@ -0,0 +1,71 @@
+Git v1.8.4.1 Release Notes
+========================
+
+Fixes since v1.8.4
+------------------
+
+ * Some old versions of bash do not grok some constructs like
+   'printf -v varname' which the prompt and completion code started
+   to use recently.  The completion and prompt scripts have been
+   adjusted to work better with these old versions of bash.
+
+ * In FreeBSD's and NetBSD's "sh", a return in a dot script in a
+   function returns from the function, not only in the dot script,
+   breaking "git rebase" on these platforms (regression introduced
+   in 1.8.4-rc1).
+
+ * "git rebase -i" and other scripted commands were feeding a
+   random, data dependant error message to 'echo' and expecting it
+   to come out literally.
+
+ * Setting the "submodule.<name>.path" variable to the empty
+   "true" caused the configuration parser to segfault.
+
+ * Output from "git log --full-diff -- <pathspec>" looked strange
+   because comparison was done with the previous ancestor that
+   touched the specified <pathspec>, causing the patches for paths
+   outside the pathspec to show more than the single commit has
+   changed.
+
+ * The auto-tag-following code in "git fetch" tries to reuse the
+   same transport twice when the serving end does not cooperate and
+   does not give tags that point to commits that are asked for as
+   part of the primary transfer.  Unfortunately, Git-aware transport
+   helper interface is not designed to be used more than once, hence
+   this did not work over smart-http transfer.  Fixed.
+
+ * Send a large request to read(2)/write(2) as a smaller but still
+   reasonably large chunks, which would improve the latency when the
+   operation needs to be killed and incidentally works around broken
+   64-bit systems that cannot take a 2GB write or read in one go.
+
+ * A ".mailmap" file that ends with an incomplete line, when read
+   from a blob, was not handled properly.
+
+ * The recent "short-cut clone connectivity check" topic broke a
+   shallow repository when a fetch operation tries to auto-follow
+   tags.
+
+ * When send-email comes up with an error message to die with upon
+   failure to start an SSL session, it tried to read the error
+   string from a wrong place.
+
+ * A call to xread() was used without a loop to cope with short
+   read in the codepath to stream large blobs to a pack.
+
+ * On platforms with fgetc() and friends defined as macros, the
+   configuration parser did not compile.
+
+ * New versions of MediaWiki introduced a new API for returning
+   more than 500 results in response to a query, which would cause
+   the MediaWiki remote helper to go into an infinite loop.
+
+ * Subversion's serf access method (the only one available in
+   Subversion 1.8) for http and https URLs in skelta mode tells its
+   caller to open multiple files at a time, which made "git svn
+   fetch" complain that "Temp file with moniker 'svn_delta' already
+   in use" instead of fetching.
+
+
+Also contains a handful of trivial code clean-ups, documentation
+updates, updates to the test suite, etc.
diff --git a/Documentation/RelNotes/1.8.4.2.txt b/Documentation/RelNotes/1.8.4.2.txt
new file mode 100644 (file)
index 0000000..ebe5e68
--- /dev/null
@@ -0,0 +1,50 @@
+Git v1.8.4.2 Release Notes
+========================
+
+Fixes since v1.8.4.1
+--------------------
+
+ * When running "fetch -q", a long silence while the sender side
+   computes the set of objects to send can be mistaken by proxies as
+   dropped connection.  The server side has been taught to send a
+   small empty messages to keep the connection alive.
+
+ * When the webserver responds with "405 Method Not Allowed", "git
+   http-backend" should tell the client what methods are allowed with
+   the "Allow" header.
+
+ * "git cvsserver" computed the permission mode bits incorrectly for
+   executable files.
+
+ * The implementation of "add -i" has a crippling code to work around
+   ActiveState Perl limitation but it by mistake also triggered on Git
+   for Windows where MSYS perl is used.
+
+ * We made sure that we notice the user-supplied GIT_DIR is actually a
+   gitfile, but did not do the same when the default ".git" is a
+   gitfile.
+
+ * When an object is not found after checking the packfiles and then
+   loose object directory, read_sha1_file() re-checks the packfiles to
+   prevent racing with a concurrent repacker; teach the same logic to
+   has_sha1_file().
+
+ * "git commit --author=$name", when $name is not in the canonical
+   "A. U. Thor <au.thor@example.xz>" format, looks for a matching name
+   from existing history, but did not consult mailmap to grab the
+   preferred author name.
+
+ * The commit object names in the insn sheet that was prepared at the
+   beginning of "rebase -i" session can become ambiguous as the
+   rebasing progresses and the repository gains more commits. Make
+   sure the internal record is kept with full 40-hex object names.
+
+ * "git rebase --preserve-merges" internally used the merge machinery
+   and as a side effect, left merge summary message in the log, but
+   when rebasing, there should not be a need for merge summary.
+
+ * "git rebase -i" forgot that the comment character can be
+   configurable while reading its insn sheet.
+
+Also contains a handful of trivial code clean-ups, documentation
+updates, updates to the test suite, etc.
index 49a1c6c36b29db70d9b8bddda261a78e2d424a2c..b1fc30fef4934e12f24fedc3d5a5f121e5cb7a2f 100644 (file)
@@ -42,12 +42,25 @@ release, will keep ignoring removals, but the users who rely on this
 behaviour are encouraged to start using "git add --ignore-removal <path>"
 now before 2.0 is released.
 
+The default prefix for "git svn" will change in Git 2.0.  For a long
+time, "git svn" created its remote-tracking branches directly under
+refs/remotes, but it will place them under refs/remotes/origin/ unless
+it is told otherwise with its --prefix option.
+
 
 Updates since v1.8.4
 --------------------
 
 Foreign interfaces, subsystems and ports.
 
+ * "git-svn" used with SVN 1.8.0 when talking over https:// connection
+   dumped core due to a bug in the serf library that SVN uses.  Work
+   it around on our side, even though the SVN side is being fixed.
+
+ * On MacOS X, we detected if the filesystem needs the "pre-composed
+   unicode strings" workaround, but did not automatically enable it.
+   Now we do.
+
  * remote-hg remote helper misbehaved when interacting with a local Hg
    repository relative to the home directory, e.g. "clone hg::~/there".
 
@@ -63,6 +76,79 @@ Foreign interfaces, subsystems and ports.
 
 UI, Workflows & Features
 
+ * "git replace" helper no longer allows an object to be replaced with
+   another object of a different type to avoid confusion (you can
+   still manually craft such replacement using "git update-ref", as an
+   escape hatch).
+
+ * "git status" no longer prints dirty status information for
+   submodules for which submodule.$name.ignore is set to "all".
+
+ * "git rebase -i" honours core.abbrev when preparing the insn sheet
+   for editing.
+
+ * "git status" during a cherry-pick shows what original commit is
+   being picked.
+
+ * Instead of typing four capital letters "HEAD", you can say "@" now,
+   e.g. "git log @".
+
+ * "git check-ignore" follows the same rule as "git add" and "git
+   status" in that the ignore/exclude mechanism does not take effect
+   on paths that are already tracked.  With "--no-index" option, it
+   can be used to diagnose which paths that should have been ignored
+   have been mistakenly added to the index.
+
+ * Some irrelevant "advice" messages that are shared with "git status"
+   output have been removed from the commit log template.
+
+ * "update-refs" learnt a "--stdin" option to read multiple update
+   requests and perform them in an all-or-none fashion.
+
+ * Just like "make -C <directory>", "git -C <directory> ..." tells Git
+   to go there before doing anything else.
+
+ * Just like "git checkout -" knows to check out and "git merge -"
+   knows to merge the branch you were previously on, "git cherry-pick"
+   now understands "git cherry-pick -" to pick from the previous
+   branch.
+
+ * "git status" now omits the prefix to make its output a comment in a
+   commit log editor, which is not necessary for human consumption.
+   Scripts that parse the output of "git status" are advised to use
+   "git status --porcelain" instead, as its format is stable and easier
+   to parse.
+
+ * Make "foo^{tag}" to peel a tag to itself, i.e. no-op., and fail if
+   "foo" is not a tag.  "git rev-parse --verify v1.0^{tag}" would be
+   a more convenient way to say "test $(git cat-file -t v1.0) = tag".
+
+ * "git branch -v -v" (and "git status") did not distinguish among a
+   branch that does not build on any other branch, a branch that is in
+   sync with the branch it builds on, and a branch that is configured
+   to build on some other branch that no longer exists.
+
+ * A packfile that stores the same object more than once is broken and
+   will be rejected by "git index-pack" that is run when receiving
+   data over the wire.
+
+ * Earlier we started rejecting an attempt to add 0{40} object name to
+   the index and to tree objects, but it sometimes is necessary to
+   allow so to be able to use tools like filter-branch to correct such
+   broken tree objects.  "filter-branch" can again be used to to do
+   so.
+
+ * "git config" did not provide a way to set or access numbers larger
+   than a native "int" on the platform; it now provides 64-bit signed
+   integers on all platforms.
+
+ * "git pull --rebase" always chose to do the bog-standard flattening
+   rebase.  You can tell it to run "rebase --preserve-merges" by
+   setting "pull.rebase" configuration to "preserve".
+
+ * "git push --no-thin" actually disables the "thin pack transfer"
+   optimization.
+
  * Magic pathspecs like ":(icase)makefile" that matches both
    Makefile and makefile can be used in more places.
 
@@ -115,6 +201,12 @@ UI, Workflows & Features
 
 Performance, Internal Implementation, etc.
 
+ * Build procedure for MSVC has been updated.
+
+ * If a build-time fallback is set to "cat" instead of "less", we
+   should apply the same "no subprocess or pipe" optimization as we
+   apply to user-supplied GIT_PAGER=cat.
+
  * Many commands use --dashed-option as a operation mode selector
    (e.g. "git tag --delete") that the user can use at most one
    (e.g. "git tag --delete --verify" is a nonsense) and you cannot
@@ -144,6 +236,96 @@ Unless otherwise noted, all the fixes since v1.8.4 in the maintenance
 track are contained in this release (see release notes to them for
 details).
 
+ * "git shortlog" used to choke and die when there is a malformed
+   commit (e.g. missing authors); it now simply ignore such a commit
+   and keeps going.
+   (merge cd4f09e jk/shortlog-tolerate-broken-commit later to maint).
+
+ * "git merge-recursive" did not parse its "--diff-algorithm=" command
+   line option correctly.
+   (merge 6562928 jk/diff-algo later to maint).
+
+ * When running "fetch -q", a long silence while the sender side
+   computes the set of objects to send can be mistaken by proxies as
+   dropped connection.  The server side has been taught to send a
+   small empty messages to keep the connection alive.
+   (merge 115dedd jk/upload-pack-keepalive later to maint).
+
+ * "git rebase" had a portability regression in v1.8.4 to trigger a
+   bug in some BSD shell implementations.
+   (merge 99855dd mm/rebase-continue-freebsd-WB later to maint).
+
+ * "git branch --track" had a minor regression in v1.8.3.2 and later
+   that made it impossible to base your local work on anything but a
+   local branch of the upstream repository you are tracking from.
+   (merge b0f49ff jh/checkout-auto-tracking later to maint).
+
+ * When the webserver responds with "405 Method Not Allowed", "git
+   http-backend" should tell the client what methods are allowed with
+   the "Allow" header.
+   (merge 9247be0 bc/http-backend-allow-405 later to maint).
+
+ * When there is no sufficient overlap between old and new history
+   during a "git fetch" into a shallow repository, objects that the
+   sending side knows the receiving end has were unnecessarily sent.
+   (merge f21d2a7 nd/fetch-into-shallow later to maint).
+
+ * "git cvsserver" computed the permission mode bits incorrectly for
+   executable files.
+   (merge 1b48d56 jc/cvsserver-perm-bit-fix later to maint).
+
+ * When send-email comes up with an error message to die with upon
+   failure to start an SSL session, it tried to read the error string
+   from a wrong place.
+   (merge 6cb0c88 bc/send-email-ssl-die-message-fix later to maint).
+
+ * The implementation of "add -i" has a crippling code to work around
+   ActiveState Perl limitation but it by mistake also triggered on Git
+   for Windows where MSYS perl is used.
+   (merge df17e77 js/add-i-mingw later to maint).
+
+ * We made sure that we notice the user-supplied GIT_DIR is actually a
+   gitfile, but did not do the same when the default ".git" is a
+   gitfile.
+   (merge 487a2b7 nd/git-dir-pointing-at-gitfile later to maint).
+
+ * When an object is not found after checking the packfiles and then
+   loose object directory, read_sha1_file() re-checks the packfiles to
+   prevent racing with a concurrent repacker; teach the same logic to
+   has_sha1_file().
+   (merge 45e8a74 jk/has-sha1-file-retry-packed later to maint).
+
+ * "git commit --author=$name", when $name is not in the canonical
+   "A. U. Thor <au.thor@example.xz>" format, looks for a matching name
+   from existing history, but did not consult mailmap to grab the
+   preferred author name.
+   (merge ea16794 ap/commit-author-mailmap later to maint).
+
+ * "git ls-files -k" needs to crawl only the part of the working tree
+   that may overlap the paths in the index to find killed files, but
+   shared code with the logic to find all the untracked files, which
+   made it unnecessarily inefficient.
+   (merge 680be04 jc/ls-files-killed-optim later to maint).
+
+ * The commit object names in the insn sheet that was prepared at the
+   beginning of "rebase -i" session can become ambiguous as the
+   rebasing progresses and the repository gains more commits. Make
+   sure the internal record is kept with full 40-hex object names.
+   (merge 75c6976 es/rebase-i-no-abbrev later to maint).
+
+ * "git rebase --preserve-merges" internally used the merge machinery
+   and as a side effect, left merge summary message in the log, but
+   when rebasing, there should not be a need for merge summary.
+   (merge a9f739c rt/rebase-p-no-merge-summary later to maint).
+
+ * A call to xread() was used without a loop around to cope with short
+   read in the codepath to stream new contents to a pack.
+   (merge e92527c js/xread-in-full later to maint).
+
+ * "git rebase -i" forgot that the comment character can be
+   configurable while reading its insn sheet.
+   (merge 7bca7af es/rebase-i-respect-core-commentchar later to maint).
+
  * The mailmap support code read past the allocated buffer when the
    mailmap file ended with an incomplete line.
    (merge f972a16 jk/mailmap-incomplete-line later to maint).
index 00bde9dec54160ffc4d06e0169f2058176291928..d4d93c9732f2c2f452c7a78a487bd688db943757 100644 (file)
@@ -170,8 +170,8 @@ advice.*::
        pushNeedsForce::
                Shown when linkgit:git-push[1] rejects an update that
                tries to overwrite a remote ref that points at an
-               object that is not a committish, or make the remote
-               ref point at an object that is not a committish.
+               object that is not a commit-ish, or make the remote
+               ref point at an object that is not a commit-ish.
        statusHints::
                Show directions on how to proceed from the current
                state in the output of linkgit:git-status[1], in
@@ -553,22 +553,20 @@ sequence.editor::
        When not configured the default commit message editor is used instead.
 
 core.pager::
-       The command that Git will use to paginate output.  Can
-       be overridden with the `GIT_PAGER` environment
-       variable.  Note that Git sets the `LESS` environment
-       variable to `FRSX` if it is unset when it runs the
-       pager.  One can change these settings by setting the
-       `LESS` variable to some other value.  Alternately,
-       these settings can be overridden on a project or
-       global basis by setting the `core.pager` option.
-       Setting `core.pager` has no effect on the `LESS`
-       environment variable behaviour above, so if you want
-       to override Git's default settings this way, you need
-       to be explicit.  For example, to disable the S option
-       in a backward compatible manner, set `core.pager`
-       to `less -+S`.  This will be passed to the shell by
-       Git, which will translate the final command to
-       `LESS=FRSX less -+S`.
+       Text viewer for use by Git commands (e.g., 'less').  The value
+       is meant to be interpreted by the shell.  The order of preference
+       is the `$GIT_PAGER` environment variable, then `core.pager`
+       configuration, then `$PAGER`, and then the default chosen at
+       compile time (usually 'less').
++
+When the `LESS` environment variable is unset, Git sets it to `FRSX`
+(if `LESS` environment variable is set, Git does not change it at
+all).  If you want to selectively override Git's default setting
+for `LESS`, you can set `core.pager` to e.g. `less -+S`.  This will
+be passed to the shell by Git, which will translate the final
+command to `LESS=FRSX less -+S`. The environment tells the command
+to set the `S` option to chop long lines but the command line
+resets it to the default to fold long lines.
 
 core.whitespace::
        A comma separated list of common whitespace problems to
@@ -765,6 +763,10 @@ branch.<name>.rebase::
        instead of merging the default branch from the default remote when
        "git pull" is run. See "pull.rebase" for doing this in a non
        branch-specific manner.
++
+       When preserve, also pass `--preserve-merges` along to 'git rebase'
+       so that locally committed merge commits will not be flattened
+       by running 'git pull'.
 +
 *NOTE*: this is a possibly dangerous operation; do *not* use
 it unless you understand the implications (see linkgit:git-rebase[1]
@@ -787,8 +789,8 @@ browser.<tool>.path::
        working repository in gitweb (see linkgit:git-instaweb[1]).
 
 clean.requireForce::
-       A boolean to make git-clean do nothing unless given -f
-       or -n.   Defaults to true.
+       A boolean to make git-clean do nothing unless given -f,
+       -i or -n.   Defaults to true.
 
 color.branch::
        A boolean to enable/disable color in the output of
@@ -1878,6 +1880,10 @@ pull.rebase::
        of merging the default branch from the default remote when "git
        pull" is run. See "branch.<name>.rebase" for setting this on a
        per-branch basis.
++
+       When preserve, also pass `--preserve-merges` along to 'git rebase'
+       so that locally committed merge commits will not be flattened
+       by running 'git pull'.
 +
 *NOTE*: this is a possibly dangerous operation; do *not* use
 it unless you understand the implications (see linkgit:git-rebase[1]
@@ -2177,6 +2183,13 @@ status.branch::
        Set to true to enable --branch by default in linkgit:git-status[1].
        The option --no-branch takes precedence over this variable.
 
+status.displayCommentPrefix::
+       If set to true, linkgit:git-status[1] will insert a comment
+       prefix before each output line (starting with
+       `core.commentChar`, i.e. `#` by default). This was the
+       behavior of linkgit:git-status[1] in Git 1.8.4 and previous.
+       Defaults to false.
+
 status.showUntrackedFiles::
        By default, linkgit:git-status[1] and linkgit:git-commit[1] show
        files which are not currently tracked by Git. Directories which
@@ -2201,7 +2214,14 @@ status.submodulesummary::
        If this is set to a non zero number or true (identical to -1 or an
        unlimited number), the submodule summary will be enabled and a
        summary of commits for modified submodules will be shown (see
-       --summary-limit option of linkgit:git-submodule[1]).
+       --summary-limit option of linkgit:git-submodule[1]). Please note
+       that the summary output command will be suppressed for all
+       submodules when `diff.ignoreSubmodules` is set to 'all' or only
+       for those submodules where `submodule.<name>.ignore=all`. To
+       also view the summary for ignored submodules you can either use
+       the --ignore-submodules=dirty command line option or the 'git
+       submodule summary' command, which shows a similar output but does
+       not honor these settings.
 
 submodule.<name>.path::
 submodule.<name>.url::
@@ -2236,7 +2256,8 @@ submodule.<name>.ignore::
        submodules that have untracked files in their work tree as changed.
        This setting overrides any setting made in .gitmodules for this submodule,
        both settings can be overridden on the command line by using the
-       "--ignore-submodules" option.
+       "--ignore-submodules" option. The 'git submodule' commands are not
+       affected by this setting.
 
 tar.umask::
        This variable can be used to restrict the permission bits of
@@ -2275,6 +2296,17 @@ uploadpack.allowtipsha1inwant::
        of a hidden ref (by default, such a request is rejected).
        see also `uploadpack.hiderefs`.
 
+uploadpack.keepalive::
+       When `upload-pack` has started `pack-objects`, there may be a
+       quiet period while `pack-objects` prepares the pack. Normally
+       it would output progress information, but if `--quiet` was used
+       for the fetch, `pack-objects` will output nothing at all until
+       the pack data begins. Some clients and networks may consider
+       the server to be hung and give up. Setting this option instructs
+       `upload-pack` to send an empty keepalive packet every
+       `uploadpack.keepalive` seconds. Setting this option to 0
+       disables keepalive packets entirely. The default is 5 seconds.
+
 url.<base>.insteadOf::
        Any URL that starts with this value will be rewritten to
        start, instead, with <base>. In cases where some site serves a
@@ -2310,11 +2342,11 @@ user.name::
        environment variables.  See linkgit:git-commit-tree[1].
 
 user.signingkey::
-       If linkgit:git-tag[1] is not selecting the key you want it to
-       automatically when creating a signed tag, you can override the
-       default selection with this variable.  This option is passed
-       unchanged to gpg's --local-user parameter, so you may specify a key
-       using any method that gpg supports.
+       If linkgit:git-tag[1] or linkgit:git-commit[1] is not selecting the
+       key you want it to automatically when creating a signed tag or
+       commit, you can override the default selection with this variable.
+       This option is passed unchanged to gpg's --local-user parameter,
+       so you may specify a key using any method that gpg supports.
 
 web.browser::
        Specify a web browser that may be used by some commands.
index ac770502553d9b4d3d1176f63ad01791736602a8..223b9310df0990accdb0d43b096bd52856f56bef 100644 (file)
@@ -73,7 +73,11 @@ diff.ignoreSubmodules::
        Sets the default value of --ignore-submodules. Note that this
        affects only 'git diff' Porcelain, and not lower level 'diff'
        commands such as 'git diff-files'. 'git checkout' also honors
-       this setting when reporting uncommitted changes.
+       this setting when reporting uncommitted changes. Setting it to
+       'all' disables the submodule summary normally shown by 'git commit'
+       and 'git status' when 'status.submodulesummary' is set unless it is
+       overridden by using the --ignore-submodules command line option.
+       The 'git submodule' commands are not affected by this setting.
 
 diff.mnemonicprefix::
        If set, 'git diff' uses a prefix pair that is different from the
index e1fba85660284515816d947d48b24eb3e3f3cfec..2a18c1f6f24fbe7d78f17f662440c9b6d903e55e 100644 (file)
@@ -304,7 +304,7 @@ and maintain access to the repository by developers.
   * linkgit:git-shell[1] can be used as a 'restricted login shell'
     for shared central repository users.
 
-link:howto/update-hook-example.txt[update hook howto] has a good
+link:howto/update-hook-example.html[update hook howto] has a good
 example of managing a shared central repository.
 
 
index b7cb625b894d4ba83cb13914e1fd010e1bfaf0d3..311b33674eb2bda2c8e0bd5d2de4499a156b1719 100644 (file)
@@ -48,7 +48,8 @@ working tree to it; use "git checkout <newbranch>" to switch to the
 new branch.
 
 When a local branch is started off a remote-tracking branch, Git sets up the
-branch so that 'git pull' will appropriately merge from
+branch (specifically the `branch.<name>.remote` and `branch.<name>.merge`
+configuration entries) so that 'git pull' will appropriately merge from
 the remote-tracking branch. This behavior may be changed via the global
 `branch.autosetupmerge` configuration flag. That setting can be
 overridden by using the `--track` and `--no-track` options, and
@@ -156,7 +157,8 @@ This option is only applicable in non-verbose mode.
 
 -t::
 --track::
-       When creating a new branch, set up configuration to mark the
+       When creating a new branch, set up `branch.<name>.remote` and
+       `branch.<name>.merge` configuration entries to mark the
        start-point branch as "upstream" from the new branch. This
        configuration will tell git to show the relationship between the
        two branches in `git status` and `git branch -v`. Furthermore,
index 21cffe2bcd0d5907efda9d525228e3f78a5cff65..322f5ed3155887ef69876bd439a12c4641007c9e 100644 (file)
@@ -54,7 +54,7 @@ OPTIONS
 
 --textconv::
        Show the content as transformed by a textconv filter. In this case,
-       <object> has be of the form <treeish>:<path>, or :<path> in order
+       <object> has be of the form <tree-ish>:<path>, or :<path> in order
        to apply the filter to the content recorded in the index at <path>.
 
 --batch::
index d2df487aa20a89264afee08bcdddf681d7701fda..ee2e0917040909bd62df073e20f1120c23a43a63 100644 (file)
@@ -45,6 +45,13 @@ OPTIONS
        not be possible to distinguish between paths which match a
        pattern and those which don't.
 
+--no-index::
+       Don't look in the index when undertaking the checks. This can
+       be used to debug why a path became tracked by e.g. `git add .`
+       and was not ignored by the rules as expected by the user or when
+       developing patterns including negation to match a path previously
+       added with `git add -f`.
+
 OUTPUT
 ------
 
index a49be1bab49ddcdb65e4b45b578bd183a94657a5..fc02959ba4ab1ae6acc3dc5f707e870e42144f1c 100644 (file)
@@ -54,6 +54,8 @@ Git imposes the following rules on how references are named:
 
 . They cannot contain a sequence `@{`.
 
+. They cannot be the single character `@`.
+
 . They cannot contain a `\`.
 
 These rules make it easy for shell script based tools to parse
index ca118ac6bfff9f837d06de37f99f457f6d38916b..91294f89c89dbbfef93bbb7f38074827938f48f6 100644 (file)
@@ -9,7 +9,8 @@ SYNOPSIS
 --------
 [verse]
 'git checkout' [-q] [-f] [-m] [<branch>]
-'git checkout' [-q] [-f] [-m] [--detach] [<commit>]
+'git checkout' [-q] [-f] [-m] --detach [<branch>]
+'git checkout' [-q] [-f] [-m] [--detach] <commit>
 'git checkout' [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>]
 'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
 'git checkout' [-p|--patch] [<tree-ish>] [--] [<paths>...]
@@ -62,7 +63,7 @@ that is to say, the branch is not reset/created unless "git checkout" is
 successful.
 
 'git checkout' --detach [<branch>]::
-'git checkout' <commit>::
+'git checkout' [--detach] <commit>::
 
        Prepare to work on top of <commit>, by detaching HEAD at it
        (see "DETACHED HEAD" section), and updating the index and the
@@ -71,10 +72,11 @@ successful.
        tree will be the state recorded in the commit plus the local
        modifications.
 +
-Passing `--detach` forces this behavior in the case of a <branch> (without
-the option, giving a branch name to the command would check out the branch,
-instead of detaching HEAD at it), or the current commit,
-if no <branch> is specified.
+When the <commit> argument is a branch name, the `--detach` option can
+be used to detach HEAD at the tip of the branch (`git checkout
+<branch>` would check out that branch without detaching HEAD).
++
+Omitting <branch> detaches HEAD at the tip of the current branch.
 
 'git checkout' [-p|--patch] [<tree-ish>] [--] <pathspec>...::
 
index f6c19c734d0fad09e7f7203a69959546f4b6a052..2d0daae626dd8e58c5a5c72ef999e36f56bcdce7 100644 (file)
@@ -14,8 +14,7 @@ DESCRIPTION
 -----------
 The changeset (or "diff") of each commit between the fork-point and <head>
 is compared against each commit between the fork-point and <upstream>.
-The commits are compared with their 'patch id', obtained from
-the 'git patch-id' program.
+The diffs are compared after removing any whitespace and line numbers.
 
 Every commit that doesn't exist in the <upstream> branch
 has its id (sha1) reported, prefixed by a symbol.  The ones that have
index 7da0f13a5cb26e9e5d1cb7d9c73fd4af57443d72..b2114403731157cbb370bff1d450fd52ee56f0fb 100644 (file)
@@ -20,7 +20,7 @@ usernames and passwords. The git-credential command exposes this
 interface to scripts which may want to retrieve, store, or prompt for
 credentials in the same manner as Git. The design of this scriptable
 interface models the internal C API; see
-link:technical/api-credentials.txt[the Git credential API] for more
+link:technical/api-credentials.html[the Git credential API] for more
 background on the concepts.
 
 git-credential takes an "action" option on the command-line (one of
index 9439cd6d56b0d3aa2115b9843936b449b6765652..d20ca402a11d29cb35efa9d291755c4f9f08bf21 100644 (file)
@@ -9,7 +9,7 @@ git-describe - Show the most recent tag that is reachable from a commit
 SYNOPSIS
 --------
 [verse]
-'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] <committish>...
+'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] <commit-ish>...
 'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]
 
 DESCRIPTION
@@ -26,8 +26,8 @@ see the -a and -s options to linkgit:git-tag[1].
 
 OPTIONS
 -------
-<committish>...::
-       Committish object names to describe.
+<commit-ish>...::
+       Commit-ish object names to describe.
 
 --dirty[=<mark>]::
        Describe the working tree.
@@ -57,7 +57,7 @@ OPTIONS
 
 --candidates=<n>::
        Instead of considering only the 10 most recent tags as
-       candidates to describe the input committish consider
+       candidates to describe the input commit-ish consider
        up to <n> candidates.  Increasing <n> above 10 will take
        slightly longer but may produce a more accurate result.
        An <n> of 0 will cause only exact matches to be output.
@@ -145,7 +145,7 @@ be sufficient to disambiguate these commits.
 SEARCH STRATEGY
 ---------------
 
-For each committish supplied, 'git describe' will first look for
+For each commit-ish supplied, 'git describe' will first look for
 a tag which tags exactly that commit.  Annotated tags will always
 be preferred over lightweight tags, and tags with newer dates will
 always be preferred over tags with older dates.  If an exact match
@@ -154,12 +154,12 @@ is found, its name will be output and searching will stop.
 If an exact match was not found, 'git describe' will walk back
 through the commit history to locate an ancestor commit which
 has been tagged.  The ancestor's tag will be output along with an
-abbreviation of the input committish's SHA-1. If '--first-parent' was
+abbreviation of the input commit-ish's SHA-1. If '--first-parent' was
 specified then the walk will only consider the first parent of each
 commit.
 
 If multiple tags were found during the walk then the tag which
-has the fewest commits different from the input committish will be
+has the fewest commits different from the input commit-ish will be
 selected and output.  Here fewest commits different is defined as
 the number of commits which would be shown by `git log tag..input`
 will be the smallest number of commits possible.
index 78d6d50489502638013509fbf72c811b50bfee86..33fbd8c56f91dd306a80cbd575fb67df43143731 100644 (file)
@@ -28,10 +28,15 @@ two blob objects, or changes between two files on disk.
        words, the differences are what you _could_ tell Git to
        further add to the index but you still haven't.  You can
        stage these changes by using linkgit:git-add[1].
-+
-If exactly two paths are given and at least one points outside
-the current repository, 'git diff' will compare the two files /
-directories. This behavior can be forced by --no-index.
+
+'git diff' --no-index [--options] [--] [<path>...]::
+
+       This form is to compare the given two paths on the
+       filesystem.  You can omit the `--no-index` option when
+       running the command in a working tree controlled by Git and
+       at least one of the paths points outside the working tree,
+       or when running the command outside a working tree
+       controlled by Git.
 
 'git diff' [--options] --cached [<commit>] [--] [<path>...]::
 
index bf1a02a80d5f4a61f5bbd0d826ae7df3bce58911..73f980638e7939e8c0c6ef41920d5bb61b751632 100644 (file)
@@ -361,8 +361,8 @@ and control the current import process.  More detailed discussion
        `--cat-blob-fd` or `stdout` if unspecified.
 
 `feature`::
-       Require that fast-import supports the specified feature, or
-       abort if it does not.
+       Enable the specified feature. This requires that fast-import
+       supports the specified feature, and aborts if it does not.
 
 `option`::
        Specify any of the options listed under OPTIONS that do not
@@ -380,8 +380,8 @@ change to the project.
        ('author' (SP <name>)? SP LT <email> GT SP <when> LF)?
        'committer' (SP <name>)? SP LT <email> GT SP <when> LF
        data
-       ('from' SP <committish> LF)?
-       ('merge' SP <committish> LF)?
+       ('from' SP <commit-ish> LF)?
+       ('merge' SP <commit-ish> LF)?
        (filemodify | filedelete | filecopy | filerename | filedeleteall | notemodify)*
        LF?
 ....
@@ -460,9 +460,9 @@ as the current commit on that branch is automatically assumed to
 be the first ancestor of the new commit.
 
 As `LF` is not valid in a Git refname or SHA-1 expression, no
-quoting or escaping syntax is supported within `<committish>`.
+quoting or escaping syntax is supported within `<commit-ish>`.
 
-Here `<committish>` is any of the following:
+Here `<commit-ish>` is any of the following:
 
 * The name of an existing branch already in fast-import's internal branch
   table.  If fast-import doesn't know the name, it's treated as a SHA-1
@@ -509,7 +509,7 @@ additional ancestors (forming a 16-way merge).  For this reason
 it is suggested that frontends do not use more than 15 `merge`
 commands per commit; 16, if starting a new, empty branch.
 
-Here `<committish>` is any of the commit specification expressions
+Here `<commit-ish>` is any of the commit specification expressions
 also accepted by `from` (see above).
 
 `filemodify`
@@ -677,8 +677,8 @@ paths for a commit are encouraged to do so.
 `notemodify`
 ^^^^^^^^^^^^
 Included in a `commit` `<notes_ref>` command to add a new note
-annotating a `<committish>` or change this annotation contents.
-Internally it is similar to filemodify 100644 on `<committish>`
+annotating a `<commit-ish>` or change this annotation contents.
+Internally it is similar to filemodify 100644 on `<commit-ish>`
 path (maybe split into subdirectories). It's not advised to
 use any other commands to write to the `<notes_ref>` tree except
 `filedeleteall` to delete all existing notes in this tree.
@@ -691,7 +691,7 @@ External data format::
        commit that is to be annotated.
 +
 ....
-       'N' SP <dataref> SP <committish> LF
+       'N' SP <dataref> SP <commit-ish> LF
 ....
 +
 Here `<dataref>` can be either a mark reference (`:<idnum>`)
@@ -704,13 +704,13 @@ Inline data format::
        command.
 +
 ....
-       'N' SP 'inline' SP <committish> LF
+       'N' SP 'inline' SP <commit-ish> LF
        data
 ....
 +
 See below for a detailed description of the `data` command.
 
-In both formats `<committish>` is any of the commit specification
+In both formats `<commit-ish>` is any of the commit specification
 expressions also accepted by `from` (see above).
 
 `mark`
@@ -741,7 +741,7 @@ lightweight (non-annotated) tags see the `reset` command below.
 
 ....
        'tag' SP <name> LF
-       'from' SP <committish> LF
+       'from' SP <commit-ish> LF
        'tagger' (SP <name>)? SP LT <email> GT SP <when> LF
        data
 ....
@@ -786,11 +786,11 @@ branch from an existing commit without creating a new commit.
 
 ....
        'reset' SP <ref> LF
-       ('from' SP <committish> LF)?
+       ('from' SP <commit-ish> LF)?
        LF?
 ....
 
-For a detailed description of `<ref>` and `<committish>` see above
+For a detailed description of `<ref>` and `<commit-ish>` see above
 under `commit` and `from`.
 
 The `LF` after the command is optional (it used to be required).
index 9e0ef0eaf32f8861ba7090ae2feb6188c2c2f0b7..5c0a4ab2d6d4c123899fa32e8f147a8c077f2130 100644 (file)
@@ -438,7 +438,8 @@ Edit..Preferences..Composition, wrap plain text messages at 0
 In Thunderbird 3:
 Edit..Preferences..Advanced..Config Editor.  Search for
 "mail.wrap_long_lines".
-Toggle it to make sure it is set to `false`.
+Toggle it to make sure it is set to `false`. Also, search for
+"mailnews.wraplength" and set the value to 0.
 
 3. Disable the use of format=flowed:
 Edit..Preferences..Advanced..Config Editor.  Search for
index c5f84b649504f1708be9cd925023af3afd685337..58731c194229e7e14b4eca27465fd42894d9a710 100644 (file)
@@ -13,7 +13,7 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Reads three treeish, and output trivial merge results and
+Reads three tree-ish, and output trivial merge results and
 conflicting stages to the standard output.  This is similar to
 what three-way 'git read-tree -m' does, but instead of storing the
 results in the index, the command outputs the entries to the
index 15b00e09916fff47a8244432ce396c9b6f7fbec1..ca28fb8e2a07bebde63c896939211fbec69e93e0 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 --------
 [verse]
 'git name-rev' [--tags] [--refs=<pattern>]
-              ( --all | --stdin | <committish>... )
+              ( --all | --stdin | <commit-ish>... )
 
 DESCRIPTION
 -----------
index 80dc022edea58b76aeea2f7df0876fd98bc6dc05..6738055bd3083825c06c82d1b7678ef453854253 100644 (file)
@@ -14,7 +14,7 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-This program searches the `$GIT_OBJECT_DIR` for all objects that currently
+This program searches the `$GIT_OBJECT_DIRECTORY` for all objects that currently
 exist in a pack file as well as the independent object directories.
 
 All such extra objects are removed.
index 6ef8d599d31ac20982fa74f213b81494ceae162a..beea10b148ce9a24752222081caecb1497150b29 100644 (file)
@@ -102,12 +102,18 @@ include::merge-options.txt[]
 :git-pull: 1
 
 -r::
---rebase::
-       Rebase the current branch on top of the upstream branch after
-       fetching.  If there is a remote-tracking branch corresponding to
-       the upstream branch and the upstream branch was rebased since last
-       fetched, the rebase uses that information to avoid rebasing
-       non-local changes.
+--rebase[=false|true|preserve]::
+       When true, rebase the current branch on top of the upstream
+       branch after fetching. If there is a remote-tracking branch
+       corresponding to the upstream branch and the upstream branch
+       was rebased since last fetched, the rebase uses that information
+       to avoid rebasing non-local changes.
++
+When preserve, also rebase the current branch on top of the upstream
+branch, but pass `--preserve-merges` along to `git rebase` so that
+locally created merge commits will not be flattened.
++
+When false, merge the current branch into the upstream branch.
 +
 See `pull.rebase`, `branch.<name>.rebase` and `branch.autosetuprebase` in
 linkgit:git-config[1] if you want to make `git pull` always use
index e2992f17a0e4e0e78630ee8cbc1c723a70d855e2..9eec74091097c0ea5c9fea69a09eb63e3cebd8d9 100644 (file)
@@ -121,7 +121,7 @@ already exists on the remote side.
 --follow-tags::
        Push all the refs that would be pushed without this option,
        and also push annotated tags in `refs/tags` that are missing
-       from the remote but are pointing at committish that are
+       from the remote but are pointing at commit-ish that are
        reachable from the refs being pushed.
 
 --receive-pack=<git-receive-pack>::
index 6b2e1c86ab6c1084421e06b5f677264dc4099b6a..94e07fdab550dcac70734fb79724b00cf8d23edc 100644 (file)
@@ -322,7 +322,7 @@ You may find this (or --no-ff with an interactive rebase) helpful after
 reverting a topic branch merge, as this option recreates the topic branch with
 fresh commits so it can be remerged successfully without needing to "revert
 the reversion" (see the
-link:howto/revert-a-faulty-merge.txt[revert-a-faulty-merge How-To] for details).
+link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).
 
 --ignore-whitespace::
 --whitespace=<option>::
@@ -416,7 +416,7 @@ Without --interactive, this is a synonym for --force-rebase.
 You may find this helpful after reverting a topic branch merge, as this option
 recreates the topic branch with fresh commits so it can be remerged
 successfully without needing to "revert the reversion" (see the
-link:howto/revert-a-faulty-merge.txt[revert-a-faulty-merge How-To] for details).
+link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for details).
 
 include::merge-strategies.txt[]
 
index 9c3e3bf83a2721678a2c7a430ec88bee0d39dd0a..2507c8bd913224b21118fe38d648f2538a06c387 100644 (file)
@@ -13,7 +13,7 @@ SYNOPSIS
 'git remote add' [-t <branch>] [-m <master>] [-f] [--[no-]tags] [--mirror=<fetch|push>] <name> <url>
 'git remote rename' <old> <new>
 'git remote remove' <name>
-'git remote set-head' <name> (-a | -d | <branch>)
+'git remote set-head' <name> (-a | --auto | -d | --delete | <branch>)
 'git remote set-branches' [--add] <name> <branch>...
 'git remote set-url' [--push] <name> <newurl> [<oldurl>]
 'git remote set-url --add' [--push] <name> <newurl>
@@ -101,9 +101,9 @@ branch. For example, if the default branch for `origin` is set to
 `master`, then `origin` may be specified wherever you would normally
 specify `origin/master`.
 +
-With `-d`, the symbolic ref `refs/remotes/<name>/HEAD` is deleted.
+With `-d` or `--delete`, the symbolic ref `refs/remotes/<name>/HEAD` is deleted.
 +
-With `-a`, the remote is queried to determine its `HEAD`, then the
+With `-a` or `--auto`, the remote is queried to determine its `HEAD`, then the
 symbolic-ref `refs/remotes/<name>/HEAD` is set to the same branch. e.g., if the remote
 `HEAD` is pointed at `next`, "`git remote set-head origin -a`" will set
 the symbolic-ref `refs/remotes/origin/HEAD` to `refs/remotes/origin/next`. This will
index e0b405797630c066f57082abc98fb1c03a1b219d..f373ab48d4d575d847408e333b5bfb747d1a75a2 100644 (file)
@@ -20,8 +20,14 @@ The name of the 'replace' reference is the SHA-1 of the object that is
 replaced. The content of the 'replace' reference is the SHA-1 of the
 replacement object.
 
+The replaced object and the replacement object must be of the same type.
+This restriction can be bypassed using `-f`.
+
 Unless `-f` is given, the 'replace' reference must not yet exist.
 
+There is no other restriction on the replaced and replacement objects.
+Merge commits can be replaced by non-merge commits and vice versa.
+
 Replacement references will be used by default by all Git commands
 except those doing reachability traversal (prune, pack transfer and
 fsck).
@@ -49,18 +55,34 @@ achieve the same effect as the `--no-replace-objects` option.
 OPTIONS
 -------
 -f::
+--force::
        If an existing replace ref for the same object exists, it will
        be overwritten (instead of failing).
 
 -d::
+--delete::
        Delete existing replace refs for the given objects.
 
 -l <pattern>::
+--list <pattern>::
        List replace refs for objects that match the given pattern (or
        all if no pattern is given).
        Typing "git replace" without arguments, also lists all replace
        refs.
 
+CREATING REPLACEMENT OBJECTS
+----------------------------
+
+linkgit:git-filter-branch[1], linkgit:git-hash-object[1] and
+linkgit:git-rebase[1], among other git commands, can be used to create
+replacement objects from existing objects.
+
+If you want to replace many blobs, trees or commits that are part of a
+string of commits, you may just want to create a replacement string of
+commits and then only replace the commit at the tip of the target
+string of commits with the commit at the tip of the replacement string
+of commits.
+
 BUGS
 ----
 Comparing blobs or trees that have been replaced with those that
@@ -69,12 +91,13 @@ go back to a replaced commit will move the branch to the replacement
 commit instead of the replaced commit.
 
 There may be other problems when using 'git rev-list' related to
-pending objects. And of course things may break if an object of one
-type is replaced by an object of another type (for example a blob
-replaced by a commit).
+pending objects.
 
 SEE ALSO
 --------
+linkgit:git-hash-object[1]
+linkgit:git-filter-branch[1]
+linkgit:git-rebase[1]
 linkgit:git-tag[1]
 linkgit:git-branch[1]
 linkgit:git[1]
index f79c9d858301353043fe0878bee268d8eacde189..2de67a54962b2f04f1f497344286fd17918433f3 100644 (file)
@@ -59,7 +59,7 @@ brought in by the merge.  As a result, later merges will only bring in tree
 changes introduced by commits that are not ancestors of the previously
 reverted merge.  This may or may not be what you want.
 +
-See the link:howto/revert-a-faulty-merge.txt[revert-a-faulty-merge How-To] for
+See the link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for
 more details.
 
 --no-edit::
index 9046df98a03fe11a203f06d79be0128309a201c5..a4acaa038cd4255c91df1a03c16c6a396f0c1219 100644 (file)
@@ -210,7 +210,13 @@ directory.
 If `status.submodulesummary` is set to a non zero number or true (identical
 to -1 or an unlimited number), the submodule summary will be enabled for
 the long format and a summary of commits for modified submodules will be
-shown (see --summary-limit option of linkgit:git-submodule[1]).
+shown (see --summary-limit option of linkgit:git-submodule[1]). Please note
+that the summary output from the status command will be suppressed for all
+submodules when `diff.ignoreSubmodules` is set to 'all' or only for those
+submodules where `submodule.<name>.ignore=all`. To also view the summary for
+ignored submodules you can either use the --ignore-submodules=dirty command
+line option or the 'git submodule summary' command, which shows a similar
+output but does not honor these settings.
 
 SEE ALSO
 --------
index 4dd3bcb5117f31a76281ef09847b0171cdbf9b80..2a3847649df540242828ac1fbae4b962ff75ce94 100644 (file)
@@ -79,8 +79,21 @@ COMMANDS
        trailing slash, so be sure you include one in the
        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.
+       Setting a prefix (with a trailing slash) is strongly
+       encouraged in any case, as your SVN-tracking refs will
+       then be located at "refs/remotes/$prefix/*", which is
+       compatible with Git's own remote-tracking ref layout
+       (refs/remotes/$remote/*). Setting a prefix is also useful
+       if you wish to track multiple projects that share a common
+       repository.
++
+NOTE: In Git v2.0, the default prefix will CHANGE from "" (no prefix)
+to "origin/". This is done to put SVN-tracking refs at
+"refs/remotes/origin/*" instead of "refs/remotes/*", and make them
+more compatible with how Git's own remote-tracking refs are organized
+(i.e. refs/remotes/$remote/*). You can enjoy the same benefits today,
+by using the --prefix option.
+
 --ignore-paths=<regex>;;
        When passed to 'init' or 'clone' this regular expression will
        be preserved as a config key.  See 'fetch' for a description
@@ -104,8 +117,11 @@ COMMANDS
 'fetch'::
        Fetch unfetched revisions from the Subversion remote we are
        tracking.  The name of the [svn-remote "..."] section in the
-       .git/config file may be specified as an optional command-line
-       argument.
+       $GIT_DIR/config file may be specified as an optional
+       command-line argument.
++
+This automatically updates the rev_map if needed (see
+'$GIT_DIR/svn/\*\*/.rev_map.*' in the FILES section below for details).
 
 --localtime;;
        Store Git commit times in the local timezone instead of UTC.  This
@@ -201,6 +217,9 @@ accept.  However, '--fetch-all' only fetches from the current
 +
 Like 'git rebase'; this requires that the working tree be clean
 and have no uncommitted changes.
++
+This automatically updates the rev_map if needed (see
+'$GIT_DIR/svn/\*\*/.rev_map.*' in the FILES section below for details).
 
 -l;;
 --local;;
@@ -435,8 +454,8 @@ Any other arguments are passed directly to 'git log'
        specific revision.
 
 'gc'::
-       Compress $GIT_DIR/svn/<refname>/unhandled.log files in .git/svn
-       and remove $GIT_DIR/svn/<refname>index files in .git/svn.
+       Compress $GIT_DIR/svn/<refname>/unhandled.log files and remove
+       $GIT_DIR/svn/<refname>/index files.
 
 'reset'::
        Undoes the effects of 'fetch' back to the specified revision.
@@ -449,9 +468,10 @@ Any other arguments are passed directly to 'git log'
        file cannot be ignored forever (with --ignore-paths) the only
        way to repair the repo is to use 'reset'.
 +
-Only the rev_map and refs/remotes/git-svn are changed.  Follow 'reset'
-with a 'fetch' and then 'git reset' or 'git rebase' to move local
-branches onto the new tree.
+Only the rev_map and refs/remotes/git-svn are changed (see
+'$GIT_DIR/svn/\*\*/.rev_map.*' in the FILES section below for details).
+Follow 'reset' with a 'fetch' and then 'git reset' or 'git rebase' to
+move local branches onto the new tree.
 
 -r <n>;;
 --revision=<n>;;
@@ -684,7 +704,7 @@ svn-remote.<name>.noMetadata::
 +
 This option can only be used for one-shot imports as 'git svn'
 will not be able to fetch again without metadata. Additionally,
-if you lose your .git/svn/**/.rev_map.* files, 'git svn' will not
+if you lose your '$GIT_DIR/svn/\*\*/.rev_map.*' files, 'git svn' will not
 be able to rebuild them.
 +
 The 'git svn log' command will not work on repositories using
@@ -804,16 +824,16 @@ Tracking and contributing to an entire Subversion-managed project
 
 ------------------------------------------------------------------------
 # Clone a repo with standard SVN directory layout (like git clone):
-       git svn clone http://svn.example.com/project --stdlayout
+       git svn clone http://svn.example.com/project --stdlayout --prefix svn/
 # Or, if the repo uses a non-standard directory layout:
-       git svn clone http://svn.example.com/project -T tr -b branch -t tag
+       git svn clone http://svn.example.com/project -T tr -b branch -t tag --prefix svn/
 # View all branches and tags you have cloned:
        git branch -r
 # Create a new branch in SVN
     git svn branch waldo
 # Reset your master to trunk (or any other branch, replacing 'trunk'
 # with the appropriate name):
-       git reset --hard remotes/trunk
+       git reset --hard svn/trunk
 # You may only dcommit to one branch/tag/trunk at a time.  The usage
 # of dcommit/rebase/show-ignore should be the same as above.
 ------------------------------------------------------------------------
@@ -827,7 +847,7 @@ have each person clone that repository with 'git clone':
 
 ------------------------------------------------------------------------
 # Do the initial import on a server
-       ssh server "cd /pub && git svn clone http://svn.example.com/project
+       ssh server "cd /pub && git svn clone http://svn.example.com/project [options...]"
 # Clone locally - make sure the refs/remotes/ space matches the server
        mkdir project
        cd project
@@ -840,8 +860,9 @@ have each person clone that repository with 'git clone':
        git config --remove-section remote.origin
 # Create a local branch from one of the branches just fetched
        git checkout -b master FETCH_HEAD
-# Initialize 'git svn' locally (be sure to use the same URL and -T/-b/-t options as were used on server)
-       git svn init http://svn.example.com/project
+# Initialize 'git svn' locally (be sure to use the same URL and
+# --stdlayout/-T/-b/-t/--prefix options as were used on server)
+       git svn init http://svn.example.com/project [options...]
 # Pull the latest changes from Subversion
        git svn rebase
 ------------------------------------------------------------------------
@@ -973,12 +994,22 @@ without giving any repository layout options.  If the full history with
 branches and tags is required, the options '--trunk' / '--branches' /
 '--tags' must be used.
 
+When using the options for describing the repository layout (--trunk,
+--tags, --branches, --stdlayout), please also specify the --prefix
+option (e.g. '--prefix=origin/') to cause your SVN-tracking refs to be
+placed at refs/remotes/origin/* rather than the default refs/remotes/*.
+The former is more compatible with the layout of Git's "regular"
+remote-tracking refs (refs/remotes/$remote/*), and may potentially
+prevent similarly named SVN branches and Git remotes from clobbering
+each other. In Git v2.0 the default prefix used (i.e. when no --prefix
+is given) will change from "" (no prefix) to "origin/".
+
 When using multiple --branches or --tags, 'git svn' does not automatically
 handle name collisions (for example, if two branches from different paths have
 the same name, or if a branch and a tag have the same name).  In these cases,
 use 'init' to set up your Git repository then, before your first 'fetch', edit
-the .git/config file so that the branches and tags are associated with
-different name spaces.  For example:
+the $GIT_DIR/config file so that the branches and tags are associated
+with different name spaces.  For example:
 
        branches = stable/*:refs/remotes/svn/stable/*
        branches = debug/*:refs/remotes/svn/debug/*
@@ -1006,7 +1037,7 @@ CONFIGURATION
 -------------
 
 'git svn' stores [svn-remote] configuration information in the
-repository .git/config file.  It is similar the core Git
+repository $GIT_DIR/config file.  It is similar the core Git
 [remote] sections except 'fetch' keys do not accept glob
 arguments; but they are instead handled by the 'branches'
 and 'tags' keys.  Since some SVN repositories are oddly
@@ -1035,8 +1066,8 @@ comma-separated list of names within braces. For example:
 [svn-remote "huge-project"]
        url = http://server.org/svn
        fetch = trunk/src:refs/remotes/trunk
-       branches = branches/{red,green}/src:refs/remotes/branches/*
-       tags = tags/{1.0,2.0}/src:refs/remotes/tags/*
+       branches = branches/{red,green}/src:refs/remotes/project-a/branches/*
+       tags = tags/{1.0,2.0}/src:refs/remotes/project-a/tags/*
 ------------------------------------------------------------------------
 
 Multiple fetch, branches, and tags keys are supported:
@@ -1060,8 +1091,21 @@ $ git svn branch -d branches/server release-2-3-0
 
 Note that git-svn keeps track of the highest revision in which a branch
 or tag has appeared. If the subset of branches or tags is changed after
-fetching, then .git/svn/.metadata must be manually edited to remove (or
-reset) branches-maxRev and/or tags-maxRev as appropriate.
+fetching, then $GIT_DIR/svn/.metadata must be manually edited to remove
+(or reset) branches-maxRev and/or tags-maxRev as appropriate.
+
+FILES
+-----
+$GIT_DIR/svn/\*\*/.rev_map.*::
+       Mapping between Subversion revision numbers and Git commit
+       names.  In a repository where the noMetadata option is not set,
+       this can be rebuilt from the git-svn-id: lines that are at the
+       end of every commit (see the 'svn.noMetadata' section above for
+       details).
++
+'git svn fetch' and 'git svn rebase' automatically update the rev_map
+if it is missing or not up to date.  'git svn reset' automatically
+rewinds it.
 
 SEE ALSO
 --------
index 0df13ff6f4231779a5f0663900f34447ff2c1276..0a0a5512b3c62eb1179a3d5a9687949c39b2a9ef 100644 (file)
@@ -8,7 +8,7 @@ git-update-ref - Update the object name stored in a ref safely
 SYNOPSIS
 --------
 [verse]
-'git update-ref' [-m <reason>] (-d <ref> [<oldvalue>] | [--no-deref] <ref> <newvalue> [<oldvalue>])
+'git update-ref' [-m <reason>] (-d <ref> [<oldvalue>] | [--no-deref] <ref> <newvalue> [<oldvalue>] | --stdin [-z])
 
 DESCRIPTION
 -----------
@@ -58,6 +58,58 @@ archive by creating a symlink tree).
 With `-d` flag, it deletes the named <ref> after verifying it
 still contains <oldvalue>.
 
+With `--stdin`, update-ref reads instructions from standard input and
+performs all modifications together.  Specify commands of the form:
+
+       update SP <ref> SP <newvalue> [SP <oldvalue>] LF
+       create SP <ref> SP <newvalue> LF
+       delete SP <ref> [SP <oldvalue>] LF
+       verify SP <ref> [SP <oldvalue>] LF
+       option SP <opt> LF
+
+Quote fields containing whitespace as if they were strings in C source
+code.  Alternatively, use `-z` to specify commands without quoting:
+
+       update SP <ref> NUL <newvalue> NUL [<oldvalue>] NUL
+       create SP <ref> NUL <newvalue> NUL
+       delete SP <ref> NUL [<oldvalue>] NUL
+       verify SP <ref> NUL [<oldvalue>] NUL
+       option SP <opt> NUL
+
+Lines of any other format or a repeated <ref> produce an error.
+Command meanings are:
+
+update::
+       Set <ref> to <newvalue> after verifying <oldvalue>, if given.
+       Specify a zero <newvalue> to ensure the ref does not exist
+       after the update and/or a zero <oldvalue> to make sure the
+       ref does not exist before the update.
+
+create::
+       Create <ref> with <newvalue> after verifying it does not
+       exist.  The given <newvalue> may not be zero.
+
+delete::
+       Delete <ref> after verifying it exists with <oldvalue>, if
+       given.  If given, <oldvalue> may not be zero.
+
+verify::
+       Verify <ref> against <oldvalue> but do not change it.  If
+       <oldvalue> zero or missing, the ref must not exist.
+
+option::
+       Modify behavior of the next command naming a <ref>.
+       The only valid option is `no-deref` to avoid dereferencing
+       a symbolic ref.
+
+Use 40 "0" or the empty string to specify a zero value, except that
+with `-z` an empty <oldvalue> is considered missing.
+
+If all <ref>s can be locked with matching <oldvalue>s
+simultaneously, all modifications are performed.  Otherwise, no
+modifications are performed.  Note that while each individual
+<ref> is updated or deleted atomically, a concurrent reader may
+still see a subset of the modifications.
 
 Logging Updates
 ---------------
index c4f0ed59576b877a5eab2e36aa874d8c572bb905..da7be1fdf4d9654d962984d3b25f655439237e30 100644 (file)
@@ -9,7 +9,7 @@ git - the stupid content tracker
 SYNOPSIS
 --------
 [verse]
-'git' [--version] [--help] [-c <name>=<value>]
+'git' [--version] [--help] [-C <path>] [-c <name>=<value>]
     [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
     [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]
     [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
@@ -43,9 +43,10 @@ unreleased) version of Git, that is available from 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v1.8.4/git.html[documentation for release 1.8.4]
+* link:v1.8.4.1/git.html[documentation for release 1.8.4.1]
 
 * release notes for
+  link:RelNotes/1.8.4.1.txt[1.8.4.1],
   link:RelNotes/1.8.4.txt[1.8.4].
 
 * link:v1.8.3.4/git.html[documentation for release 1.8.3.4]
@@ -395,6 +396,20 @@ displayed. See linkgit:git-help[1] for more information,
 because `git --help ...` is converted internally into `git
 help ...`.
 
+-C <path>::
+       Run as if git was started in '<path>' instead of the current working
+       directory.  When multiple `-C` options are given, each subsequent
+       non-absolute `-C <path>` is interpreted relative to the preceding `-C
+       <path>`.
++
+This option affects options that expect path name like `--git-dir` and
+`--work-tree` in that their interpretations of the path names would be
+made relative to the working directory caused by the `-C` option. For
+example the following invocations are equivalent:
+
+    git --git-dir=a.git --work-tree=b -C c status
+    git --git-dir=c/a.git --work-tree=c/b status
+
 -c <name>=<value>::
        Pass a configuration parameter to the command. The value
        given will override values from configuration files.
@@ -461,19 +476,19 @@ help ...`.
        This is equivalent to setting the `GIT_LITERAL_PATHSPECS` environment
        variable to `1`.
 
---glob-pathspecs:
+--glob-pathspecs::
        Add "glob" magic to all pathspec. This is equivalent to setting
        the `GIT_GLOB_PATHSPECS` environment variable to `1`. Disabling
        globbing on individual pathspecs can be done using pathspec
        magic ":(literal)"
 
---noglob-pathspecs:
+--noglob-pathspecs::
        Add "literal" magic to all pathspec. This is equivalent to setting
        the `GIT_NOGLOB_PATHSPECS` environment variable to `1`. Enabling
        globbing on individual pathspecs can be done using pathspec
        magic ":(glob)"
 
---icase-pathspecs:
+--icase-pathspecs::
        Add "icase" magic to all pathspec. This is equivalent to setting
        the `GIT_ICASE_PATHSPECS` environment variable to `1`.
 
index 9ac5088acd3e0cf9541ef097c26f19c5f462b770..7d54b77f3c6c17466175632758e2936e64fe2a14 100644 (file)
@@ -106,7 +106,7 @@ couple of magic command line options:
 +
 ---------------------------------------------
 $ git describe -h
-usage: git describe [options] <committish>*
+usage: git describe [options] <commit-ish>*
    or: git describe [options] --dirty
 
     --contains            find the tag that comes after the commit
index 5ab5b0727f6ce7683fd8282449b6a9fa98b1e135..5ea94cbceb56369d155f66399fdd1f8e62d4b48a 100644 (file)
@@ -157,7 +157,7 @@ points.  You can use these, for example, to send all commits to the shared
 repository to a mailing list.  See linkgit:githooks[5].
 
 You can enforce finer grained permissions using update hooks.  See
-link:howto/update-hook-example.txt[Controlling access to branches using
+link:howto/update-hook-example.html[Controlling access to branches using
 update hooks].
 
 Providing CVS Access to a Git Repository
index 6a1ca4abad73631c13a4d074deb11102289a0d43..f7be93f6317c7170af642c43d107a6617eb33a18 100644 (file)
@@ -75,7 +75,8 @@ submodule.<name>.ignore::
        the superproject, the setting there will override the one found in
        .gitmodules.
        Both settings can be overridden on the command line by using the
-       "--ignore-submodule" option.
+       "--ignore-submodule" option. The 'git submodule' commands are not
+       affected by this setting.
 
 
 EXAMPLES
index bc069c23df85ae200d8b21fdf9a4662c72152377..f1f4ca972791892126f757b2f697758e4e5fe26d 100644 (file)
@@ -120,6 +120,11 @@ connecting (see the 'connect' command under COMMANDS).
 When choosing between 'push' and 'export', Git prefers 'push'.
 Other frontends may have some other order of preference.
 
+'no-private-update'::
+       When using the 'refspec' capability, git normally updates the
+       private ref on successful push. This update is disabled when
+       the remote-helper declares the capability 'no-private-update'.
+
 
 Capabilities for Fetching
 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -180,6 +185,12 @@ applicable refspec takes precedence.  The left-hand of refspecs
 advertised with this capability must cover all refs reported by
 the list command.  If no 'refspec' capability is advertised,
 there is an implied `refspec *:*`.
++
+When writing remote-helpers for decentralized version control
+systems, it is advised to keep a local copy of the repository to
+interact with, and to let the private namespace refs point to this
+local repository, while the refs/remotes namespace is used to track
+the remote repository.
 
 'bidi-import'::
        This modifies the 'import' capability.
index 13a64d3aac8aca7181a6735abdabd8ed6d28ddc0..e4706615be147f71a4c840e386f14d141b4436aa 100644 (file)
@@ -82,6 +82,18 @@ to point at the new commit.
        to the top <<def_directory,directory>> of the stored
        revision.
 
+[[def_commit-ish]]commit-ish (also committish)::
+       A <<def_commit_object,commit object>> or an
+       <<def_object,object>> that can be recursively dereferenced to
+       a commit object.
+       The following are all commit-ishes:
+       a commit object,
+       a <<def_tag_object,tag object>> that points to a commit
+       object,
+       a tag object that points to a tag object that points to a
+       commit object,
+       etc.
+
 [[def_core_git]]core Git::
        Fundamental data structures and utilities of Git. Exposes only limited
        source code management tools.
@@ -427,10 +439,20 @@ should not be combined with other pathspec.
        to the result.
 
 [[def_ref]]ref::
-       A 40-byte hex representation of a <<def_SHA1,SHA-1>> or a name that
-       denotes a particular <<def_object,object>>. They may be stored in
-       a file under `$GIT_DIR/refs/` directory, or
-       in the `$GIT_DIR/packed-refs` file.
+       A name that begins with `refs/` (e.g. `refs/heads/master`)
+       that points to an <<def_object_name,object name>> or another
+       ref (the latter is called a <<def_symref,symbolic ref>>).
+       For convenience, a ref can sometimes be abbreviated when used
+       as an argument to a Git command; see linkgit:gitrevisions[7]
+       for details.
+       Refs are stored in the <<def_repository,repository>>.
++
+The ref namespace is hierarchical.
+Different subhierarchies are used for different purposes (e.g. the
+`refs/heads/` hierarchy is used to represent local branches).
++
+There are a few special-purpose refs that do not begin with `refs/`.
+The most notable example is `HEAD`.
 
 [[def_reflog]]reflog::
        A reflog shows the local "history" of a ref.  In other words,
@@ -530,10 +552,19 @@ should not be combined with other pathspec.
        with refs to the associated blob and/or tree objects. A
        <<def_tree,tree>> is equivalent to a <<def_directory,directory>>.
 
-[[def_tree-ish]]tree-ish::
-       A <<def_ref,ref>> pointing to either a <<def_commit_object,commit
-       object>>, a <<def_tree_object,tree object>>, or a <<def_tag_object,tag
-       object>> pointing to a tag or commit or tree object.
+[[def_tree-ish]]tree-ish (also treeish)::
+       A <<def_tree_object,tree object>> or an <<def_object,object>>
+       that can be recursively dereferenced to a tree object.
+       Dereferencing a <<def_commit_object,commit object>> yields the
+       tree object corresponding to the <<def_revision,revision>>'s
+       top <<def_directory,directory>>.
+       The following are all tree-ishes:
+       a <<def_commit-ish,commit-ish>>,
+       a tree object,
+       a <<def_tag_object,tag object>> that points to a tree object,
+       a tag object that points to a tag object that points to a tree
+       object,
+       etc.
 
 [[def_unmerged_index]]unmerged index::
        An <<def_index,index>> which contains unmerged
index 075418eeeb9f7e5ba3308e724313054d004214a1..acf3e477e59f1bab9addde756274afe15d39a8ed 100644 (file)
@@ -37,7 +37,7 @@ where A and B are on the side development that was not so good, M is the
 merge that brings these premature changes into the mainline, x are changes
 unrelated to what the side branch did and already made on the mainline,
 and W is the "revert of the merge M" (doesn't W look M upside down?).
-IOW, "diff W^..W" is similar to "diff -R M^..M".
+IOW, `"diff W^..W"` is similar to `"diff -R M^..M"`.
 
 Such a "revert" of a merge can be made with:
 
@@ -121,9 +121,9 @@ If you reverted the revert in such a case as in the previous example:
        ---A---B                   A'--B'--C'
 
 where Y is the revert of W, A' and B' are rerolled A and B, and there may
-also be a further fix-up C' on the side branch.  "diff Y^..Y" is similar
-to "diff -R W^..W" (which in turn means it is similar to "diff M^..M"),
-and "diff A'^..C'" by definition would be similar but different from that,
+also be a further fix-up C' on the side branch.  `"diff Y^..Y"` is similar
+to `"diff -R W^..W"` (which in turn means it is similar to `"diff M^..M"`),
+and `"diff A'^..C'"` by definition would be similar but different from that,
 because it is a rerolled series of the earlier change.  There will be a
 lot of overlapping changes that result in conflicts.  So do not do "revert
 of revert" blindly without thinking..
index 0d5419e1a9a6be235069f5807da08cc4e4052247..85f69dbac9187ff504d4656cfab5efe074223161 100644 (file)
@@ -154,7 +154,7 @@ $ git pull . master
 Packing 0 objects
 Unpacking 0 objects
 
-* committish: e3a693c...       refs/heads/master from .
+* commit-ish: e3a693c...       refs/heads/master from .
 Trying to merge e3a693c... into 8c1f5f0... using 10d781b...
 Committed merge 7fb9b7262a1d1e0a47bbfdcbbcf50ce0635d3f8f
  cache.h        |    8 ++++----
index 7f4943e1025de7013715241145d2122ef16057e3..981cbddc8627fcc2322d626148e2735d6222075c 100644 (file)
@@ -81,8 +81,8 @@ Initialize a bare repository
     $ git --bare init
 
 
-Change the ownership to your web-server's credentials. Use "grep ^User
-httpd.conf" and "grep ^Group httpd.conf" to find out:
+Change the ownership to your web-server's credentials. Use `"grep ^User
+httpd.conf"` and `"grep ^Group httpd.conf"` to find out:
 
     $ chown -R www.www .
 
index d477b3f6bcb2c410952b573421d28189d1d1a790..2c06ed34ad2ed72f9cf856fb617e54a1956da599 100644 (file)
@@ -58,6 +58,9 @@ the '$GIT_DIR/refs' directory or from the '$GIT_DIR/packed-refs' file.
 While the ref name encoding is unspecified, UTF-8 is preferred as
 some output processing may assume ref names in UTF-8.
 
+'@'::
+  '@' alone is a shortcut for 'HEAD'.
+
 '<refname>@\{<date>\}', e.g. 'master@\{yesterday\}', 'HEAD@\{5 minutes ago\}'::
   A ref followed by the suffix '@' with a date specification
   enclosed in a brace
@@ -111,16 +114,23 @@ some output processing may assume ref names in UTF-8.
 
 '<rev>{caret}\{<type>\}', e.g. 'v0.99.8{caret}\{commit\}'::
   A suffix '{caret}' followed by an object type name enclosed in
-  brace pair means the object
-  could be a tag, and dereference the tag recursively until an
-  object of that type is found or the object cannot be
-  dereferenced anymore (in which case, barf).  '<rev>{caret}0'
+  brace pair means dereference the object at '<rev>' recursively until
+  an object of type '<type>' is found or the object cannot be
+  dereferenced anymore (in which case, barf).
+  For example, if '<rev>' is a commit-ish, '<rev>{caret}\{commit\}'
+  describes the corresponding commit object.
+  Similarly, if '<rev>' is a tree-ish, '<rev>{caret}\{tree\}'
+  describes the corresponding tree object.
+  '<rev>{caret}0'
   is a short-hand for '<rev>{caret}\{commit\}'.
 +
 'rev{caret}\{object\}' can be used to make sure 'rev' names an
 object that exists, without requiring 'rev' to be a tag, and
 without dereferencing 'rev'; because a tag is already an object,
 it does not have to be dereferenced even once to get to an object.
++
+'rev{caret}\{tag\}' can be used to ensure that 'rev' identifies an
+existing tag object.
 
 '<rev>{caret}\{\}', e.g. 'v0.99.8{caret}\{\}'::
   A suffix '{caret}' followed by an empty brace pair
index a1173ee266b0c3f58dd330cb9beaf5d28fa6ba0f..caf941a1c52d843ac2335bd4f7a6df7fb0f4fcc8 100644 (file)
@@ -499,5 +499,5 @@ References
 
 link:http://www.ietf.org/rfc/rfc1738.txt[RFC 1738: Uniform Resource Locators (URL)]
 link:http://www.ietf.org/rfc/rfc2616.txt[RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1]
-link:technical/pack-protocol.txt
-link:technical/protocol-capabilities.txt
+link:technical/pack-protocol.html
+link:technical/protocol-capabilities.html
index 8b7ae1c140bc9d6d5fe01ea30dfbef0d6eb7ca8e..b7bd95152ea2526cf000911d81b02fe46539816f 100644 (file)
@@ -366,12 +366,6 @@ been detailed!
 
     <linus> Yes, we always write out most recent first
 
-For the other record:
-
-    <pasky> njs`: http://pastebin.com/547965
-
-The 'net never forgets, so that should be good until the end of time.
-
     <njs`> And, yeah, I got the part about deeper-in-history stuff
         having worse IO characteristics, one sort of doesn't care.
 
index fe723e472275dc8989338be9a1bc592a4dd18425..cbb01a1ea2e05c7adb1be3d5fde1261ef9ff71e5 100644 (file)
@@ -1,6 +1,5 @@
-Git User's Manual (for version 1.5.3 or newer)
-______________________________________________
-
+Git User Manual
+_______________
 
 Git is a fast distributed revision control system.
 
@@ -220,7 +219,7 @@ of development leading to that point.
 
 The best way to see how this works is using the linkgit:gitk[1]
 command; running gitk now on a Git repository and looking for merge
-commits will help understand how the Git organizes history.
+commits will help understand how Git organizes history.
 
 In the following, we say that commit X is "reachable" from commit Y
 if commit X is an ancestor of commit Y.  Equivalently, you could say
@@ -269,27 +268,23 @@ Creating, deleting, and modifying branches is quick and easy; here's
 a summary of the commands:
 
 `git branch`::
-       list all branches
+       list all branches.
 `git branch <branch>`::
        create a new branch named `<branch>`, referencing the same
-       point in history as the current branch
+       point in history as the current branch.
 `git branch <branch> <start-point>`::
        create a new branch named `<branch>`, referencing
        `<start-point>`, which may be specified any way you like,
-       including using a branch name or a tag name
+       including using a branch name or a tag name.
 `git branch -d <branch>`::
-       delete the branch `<branch>`; if the branch you are deleting
-       points to a commit which is not reachable from the current
-       branch, this command will fail with a warning.
+       delete the branch `<branch>`; if the branch is not fully
+       merged in its upstream branch or contained in the current branch,
+       this command will fail with a warning.
 `git branch -D <branch>`::
-       even if the branch points to a commit not reachable
-       from the current branch, you may know that that commit
-       is still reachable from some other branch or tag.  In that
-       case it is safe to use this command to force Git to delete
-       the branch.
+       delete the branch `<branch>` irrespective of its merged status.
 `git checkout <branch>`::
        make the current branch `<branch>`, updating the working
-       directory to reflect the version referenced by `<branch>`
+       directory to reflect the version referenced by `<branch>`.
 `git checkout -b <new> <start-point>`::
        create a new branch `<new>` referencing `<start-point>`, and
        check it out.
@@ -313,10 +308,17 @@ referenced by a tag:
 
 ------------------------------------------------
 $ git checkout v2.6.17
-Note: moving to "v2.6.17" which isn't a local branch
-If you want to create a new branch from this checkout, you may do so
-(now or later) by using -b with the checkout command again. Example:
-  git checkout -b <new_branch_name>
+Note: checking out 'v2.6.17'.
+
+You are in 'detached HEAD' state. You can look around, make experimental
+changes and commit them, and you can discard any commits you make in this
+state without impacting any branches by performing another checkout.
+
+If you want to create a new branch to retain commits you create, you may
+do so (now or later) by using -b with the checkout command again. Example:
+
+  git checkout -b new_branch_name
+
 HEAD is now at 427abfa... Linux v2.6.17
 ------------------------------------------------
 
@@ -327,7 +329,7 @@ and git branch shows that you are no longer on a branch:
 $ cat .git/HEAD
 427abfa28afedffadfca9dd8b067eb6d36bac53f
 $ git branch
-* (no branch)
+* (detached from v2.6.17)
   master
 ------------------------------------------------
 
@@ -787,7 +789,7 @@ e05db0fd4f31dde7005f075a84f96b360d05984b
 -------------------------------------------------
 
 Or you could recall that the `...` operator selects all commits
-contained reachable from either one reference or the other but not
+reachable from either one reference or the other but not
 both; so
 
 -------------------------------------------------
@@ -814,7 +816,7 @@ You could just visually inspect the commits since e05db0fd:
 $ gitk e05db0fd..
 -------------------------------------------------
 
-Or you can use linkgit:git-name-rev[1], which will give the commit a
+or you can use linkgit:git-name-rev[1], which will give the commit a
 name based on any tag it finds pointing to one of the commit's
 descendants:
 
@@ -858,8 +860,8 @@ because it outputs only commits that are not reachable from v1.5.0-rc1.
 
 As yet another alternative, the linkgit:git-show-branch[1] command lists
 the commits reachable from its arguments with a display on the left-hand
-side that indicates which arguments that commit is reachable from.  So,
-you can run something like
+side that indicates which arguments that commit is reachable from.
+So, if you run something like
 
 -------------------------------------------------
 $ git show-branch e05db0fd v1.5.0-rc0 v1.5.0-rc1 v1.5.0-rc2
@@ -871,15 +873,15 @@ available
 ...
 -------------------------------------------------
 
-then search for a line that looks like
+then a line like
 
 -------------------------------------------------
 + ++ [e05db0fd] Fix warnings in sha1_file.c - use C99 printf format if
 available
 -------------------------------------------------
 
-Which shows that e05db0fd is reachable from itself, from v1.5.0-rc1, and
-from v1.5.0-rc2, but not from v1.5.0-rc0.
+shows that e05db0fd is reachable from itself, from v1.5.0-rc1,
+and from v1.5.0-rc2, and not from v1.5.0-rc0.
 
 [[showing-commits-unique-to-a-branch]]
 Showing commits unique to a given branch
@@ -1074,19 +1076,13 @@ produce no output at that point.
 
 Modifying the index is easy:
 
-To update the index with the new contents of a modified file, use
-
--------------------------------------------------
-$ git add path/to/file
--------------------------------------------------
-
-To add the contents of a new file to the index, use
+To update the index with the contents of a new or modified file, use
 
 -------------------------------------------------
 $ git add path/to/file
 -------------------------------------------------
 
-To remove a file from the index and from the working tree,
+To remove a file from the index and from the working tree, use
 
 -------------------------------------------------
 $ git rm path/to/file
@@ -1787,7 +1783,7 @@ $ git pull . branch
 $ git merge branch
 -------------------------------------------------
 
-are roughly equivalent.  The former is actually very commonly used.
+are roughly equivalent.
 
 [[submitting-patches]]
 Submitting patches to a project
@@ -1977,7 +1973,7 @@ $ git clone http://yourserver.com/~you/proj.git
 -------------------------------------------------
 
 (See also
-link:howto/setup-git-server-over-http.txt[setup-git-server-over-http]
+link:howto/setup-git-server-over-http.html[setup-git-server-over-http]
 for a slightly more sophisticated setup using WebDAV which also
 allows pushing over HTTP.)
 
@@ -2249,11 +2245,11 @@ commit to this branch.
 $ ... patch ... test  ... commit [ ... patch ... test ... commit ]*
 -------------------------------------------------
 
-When you are happy with the state of this change, you can pull it into the
+When you are happy with the state of this change, you can merge it into the
 "test" branch in preparation to make it public:
 
 -------------------------------------------------
-$ git checkout test && git pull . speed-up-spinlocks
+$ git checkout test && git merge speed-up-spinlocks
 -------------------------------------------------
 
 It is unlikely that you would have any conflicts here ... but you might if you
@@ -2265,7 +2261,7 @@ see the value of keeping each patch (or patch series) in its own branch.  It
 means that the patches can be moved into the `release` tree in any order.
 
 -------------------------------------------------
-$ git checkout release && git pull . speed-up-spinlocks
+$ git checkout release && git merge speed-up-spinlocks
 -------------------------------------------------
 
 After a while, you will have a number of branches, and despite the
@@ -3191,23 +3187,21 @@ those "loose" objects.
 You can save space and make Git faster by moving these loose objects in
 to a "pack file", which stores a group of objects in an efficient
 compressed format; the details of how pack files are formatted can be
-found in link:technical/pack-format.txt[technical/pack-format.txt].
+found in link:technical/pack-format.html[pack format].
 
 To put the loose objects into a pack, just run git repack:
 
 ------------------------------------------------
 $ git repack
-Generating pack...
-Done counting 6020 objects.
-Deltifying 6020 objects.
- 100% (6020/6020) done
-Writing 6020 objects.
- 100% (6020/6020) done
-Total 6020, written 6020 (delta 4070), reused 0 (delta 0)
-Pack pack-3e54ad29d5b2e05838c75df582c65257b8d08e1c created.
+Counting objects: 6020, done.
+Delta compression using up to 4 threads.
+Compressing objects: 100% (6020/6020), done.
+Writing objects: 100% (6020/6020), done.
+Total 6020 (delta 4070), reused 0 (delta 0)
 ------------------------------------------------
 
-You can then run
+This creates a single "pack file" in .git/objects/pack/
+containing all currently unpacked objects.  You can then run
 
 ------------------------------------------------
 $ git prune
@@ -3305,17 +3299,11 @@ state, you can just prune all unreachable objects:
 $ git prune
 ------------------------------------------------
 
-and they'll be gone. But you should only run `git prune` on a quiescent
+and they'll be gone. (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
-repository is a *BAD* idea).
+`git prune` is designed not to cause any harm in such cases of concurrent
+accesses to a repository but you might receive confusing or scary messages.)
 
 [[recovering-from-repository-corruption]]
 Recovering from repository corruption
@@ -3538,7 +3526,7 @@ with Git 1.5.2 can look up the submodule commits in the repository and
 manually check them out; earlier versions won't recognize the submodules at
 all.
 
-To see how submodule support works, create (for example) four example
+To see how submodule support works, create four example
 repositories that can be used later as a submodule:
 
 -------------------------------------------------
@@ -3640,7 +3628,7 @@ working on a branch.
 
 -------------------------------------------------
 $ git branch
-* (no branch)
+* (detached from d266b98)
   master
 -------------------------------------------------
 
@@ -3910,7 +3898,7 @@ fact that such a commit brings together ("merges") two or more
 previous states represented by other commits.
 
 In other words, while a "tree" represents a particular directory state
-of a working directory, a "commit" represents that state in "time",
+of a working directory, a "commit" represents that state in time,
 and explains how we got there.
 
 You create a commit object by giving it the tree that describes the
@@ -3930,8 +3918,7 @@ save the note about that state, in practice we tend to just write the
 result to the file pointed at by `.git/HEAD`, so that we can always see
 what the last committed state was.
 
-Here is an ASCII art by Jon Loeliger that illustrates how
-various pieces fit together.
+Here is a picture that illustrates how various pieces fit together:
 
 ------------
 
@@ -4010,27 +3997,26 @@ to see what the top commit was.
 Merging multiple trees
 ----------------------
 
-Git helps you do a three-way merge, which you can expand to n-way by
-repeating the merge procedure arbitrary times until you finally
-"commit" the state.  The normal situation is that you'd only do one
-three-way merge (two parents), and commit it, but if you like to, you
-can do multiple parents in one go.
+Git can help you perform a three-way merge, which can in turn be
+used for a many-way merge by repeating the merge procedure several
+times.  The usual situation is that you only do one three-way merge
+(reconciling two lines of history) and commit the result, but if
+you like to, you can merge several branches in one go.
 
-To do a three-way merge, you need the two sets of "commit" objects
-that you want to merge, use those to find the closest common parent (a
-third "commit" object), and then use those commit objects to find the
-state of the directory ("tree" object) at these points.
+To perform a three-way merge, you start with the two commits you
+want to merge, find their closest common parent (a third commit),
+and compare the trees corresponding to these three commits.
 
-To get the "base" for the merge, you first look up the common parent
-of two commits with
+To get the "base" for the merge, look up the common parent of two
+commits:
 
 -------------------------------------------------
 $ git merge-base <commit1> <commit2>
 -------------------------------------------------
 
-which will return you the commit they are both based on.  You should
-now look up the "tree" objects of those commits, which you can easily
-do with (for example)
+This prints the name of a commit they are both based on. You should
+now look up the tree objects of those commits, which you can easily
+do with
 
 -------------------------------------------------
 $ git cat-file commit <commitname> | head -1
@@ -4152,8 +4138,6 @@ about the data in the object.  It's worth noting that the SHA-1 hash
 that is used to name the object is the hash of the original data
 plus this header, so `sha1sum` 'file' does not match the object name
 for 'file'.
-(Historical note: in the dawn of the age of Git the hash
-was the SHA-1 of the 'compressed' object.)
 
 As a result, the general consistency of an object can always be tested
 independently of the contents or the type of the object: all objects can
index e2abb7b4ea3d3d02dc6e5a8f67516ad1069e31a4..4fde227f1f28b6de9c205457b7da84c9631a24a0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -485,11 +485,9 @@ SCRIPT_PERL += git-relink.perl
 SCRIPT_PERL += git-send-email.perl
 SCRIPT_PERL += git-svn.perl
 
-SCRIPT_PYTHON += git-remote-testpy.py
 SCRIPT_PYTHON += git-p4.py
 
 NO_INSTALL += git-remote-testgit
-NO_INSTALL += git-remote-testpy
 
 # Generated files for scripts
 SCRIPT_SH_GEN = $(patsubst %.sh,%,$(SCRIPT_SH))
@@ -1664,9 +1662,6 @@ ifndef NO_TCLTK
 endif
 ifndef NO_PERL
        $(QUIET_SUBDIR0)perl $(QUIET_SUBDIR1) PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' localedir='$(localedir_SQ)' all
-endif
-ifndef NO_PYTHON
-       $(QUIET_SUBDIR0)git_remote_helpers $(QUIET_SUBDIR1) PYTHON_PATH='$(PYTHON_PATH_SQ)' prefix='$(prefix_SQ)' all
 endif
        $(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) SHELL_PATH='$(SHELL_PATH_SQ)' PERL_PATH='$(PERL_PATH_SQ)'
 
@@ -1835,12 +1830,7 @@ ifndef NO_PYTHON
 $(SCRIPT_PYTHON_GEN): GIT-CFLAGS GIT-PREFIX GIT-PYTHON-VARS
 $(SCRIPT_PYTHON_GEN): % : %.py
        $(QUIET_GEN)$(RM) $@ $@+ && \
-       INSTLIBDIR=`MAKEFLAGS= $(MAKE) -C git_remote_helpers -s \
-               --no-print-directory prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' \
-               instlibdir` && \
        sed -e '1s|#!.*python|#!$(PYTHON_PATH_SQ)|' \
-           -e 's|\(os\.getenv("GITPYTHONLIB"\)[^)]*)|\1,"@@INSTLIBDIR@@")|' \
-           -e 's|@@INSTLIBDIR@@|'"$$INSTLIBDIR"'|g' \
            $< >$@+ && \
        chmod +x $@+ && \
        mv $@+ $@
@@ -2028,6 +2018,9 @@ gettext.sp gettext.s gettext.o: GIT-PREFIX
 gettext.sp gettext.s gettext.o: EXTRA_CPPFLAGS = \
        -DGIT_LOCALE_PATH='"$(localedir_SQ)"'
 
+http-push.sp http.sp http-walker.sp remote-curl.sp: SPARSE_FLAGS += \
+       -DCURL_DISABLE_TYPECHECK
+
 ifdef NO_EXPAT
 http-walker.sp http-walker.s http-walker.o: EXTRA_CPPFLAGS = -DNO_EXPAT
 endif
@@ -2347,9 +2340,6 @@ ifndef NO_PERL
        $(MAKE) -C perl prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install
        $(MAKE) -C gitweb install
 endif
-ifndef NO_PYTHON
-       $(MAKE) -C git_remote_helpers prefix='$(prefix_SQ)' DESTDIR='$(DESTDIR_SQ)' install
-endif
 ifndef NO_TCLTK
        $(MAKE) -C gitk-git install
        $(MAKE) -C git-gui gitexecdir='$(gitexec_instdir_SQ)' install
@@ -2496,9 +2486,6 @@ clean: profile-clean coverage-clean
 ifndef NO_PERL
        $(MAKE) -C gitweb clean
        $(MAKE) -C perl clean
-endif
-ifndef NO_PYTHON
-       $(MAKE) -C git_remote_helpers clean
 endif
        $(MAKE) -C templates/ clean
        $(MAKE) -C t/ clean
index 71c19581daccffc87e5128c61d9adfae0be3e7de..1e46a4f50e16f059fa768cecc4c8331a88997021 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -624,7 +624,7 @@ static void bisect_common(struct rev_info *revs)
        if (prepare_revision_walk(revs))
                die("revision walk setup failed");
        if (revs->tree_objects)
-               mark_edges_uninteresting(revs->commits, revs, NULL);
+               mark_edges_uninteresting(revs, NULL);
 }
 
 static void exit_if_skipped_commits(struct commit_list *tried,
index c5c6984cb5266c27d3c13aa6e6aacaab56e112c0..9e6c68edaf90f27cf447ad1522da6d7de7827141 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -203,8 +203,7 @@ static int check_tracking_branch(struct remote *remote, void *cb_data)
        struct refspec query;
        memset(&query, 0, sizeof(struct refspec));
        query.dst = tracking_branch;
-       return !(remote_find_tracking(remote, &query) ||
-                prefixcmp(query.src, "refs/heads/"));
+       return !remote_find_tracking(remote, &query);
 }
 
 static int validate_remote_tracking_branch(char *ref)
@@ -291,7 +290,7 @@ void create_branch(const char *head,
        hashcpy(sha1, commit->object.sha1);
 
        if (!dont_change_ref) {
-               lock = lock_any_ref_for_update(ref.buf, NULL, 0);
+               lock = lock_any_ref_for_update(ref.buf, NULL, 0, NULL);
                if (!lock)
                        die_errno(_("Failed to lock ref for update"));
        }
@@ -307,7 +306,7 @@ void create_branch(const char *head,
                         start_name);
 
        if (real_ref && track)
-               setup_tracking(ref.buf+11, real_ref, track, quiet);
+               setup_tracking(ref.buf + 11, real_ref, track, quiet);
 
        if (!dont_change_ref)
                if (write_ref_sha1(lock, sha1, msg) < 0)
index 31ddabd99472a099ccc34810a9821050883bc1fa..226f758869358444ad1c39e5e0a05c961fb76859 100644 (file)
@@ -296,7 +296,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
        git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
 
        if (read_cache() < 0)
-               die (_("Could not read the index"));
+               die(_("Could not read the index"));
 
        init_revisions(&rev, prefix);
        rev.diffopt.context = 7;
@@ -307,11 +307,11 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
        DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
        out = open(file, O_CREAT | O_WRONLY, 0666);
        if (out < 0)
-               die (_("Could not open '%s' for writing."), file);
+               die(_("Could not open '%s' for writing."), file);
        rev.diffopt.file = xfdopen(out, "w");
        rev.diffopt.close_file = 1;
        if (run_diff_files(&rev, 0))
-               die (_("Could not write patch"));
+               die(_("Could not write patch"));
 
        launch_editor(file, NULL, NULL);
 
@@ -324,7 +324,7 @@ static int edit_patch(int argc, const char **argv, const char *prefix)
        child.git_cmd = 1;
        child.argv = apply_argv;
        if (run_command(&child))
-               die (_("Could not apply '%s'"), file);
+               die(_("Could not apply '%s'"), file);
 
        unlink(file);
        free(file);
@@ -582,7 +582,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 
        unplug_bulk_checkin();
 
- finish:
+finish:
        if (active_cache_changed) {
                if (write_cache(newfd, active_cache, active_nr) ||
                    commit_locked_index(&lock_file))
index 0903763702a436dc8b3ffc89aa64b2598e257446..ad0f86de540dc394199f71c03665d0cd76371c35 100644 (file)
@@ -423,19 +423,19 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
        char *ref = NULL;
        struct branch *branch = branch_get(branch_name);
        struct strbuf fancy = STRBUF_INIT;
+       int upstream_is_gone = 0;
 
-       if (!stat_tracking_info(branch, &ours, &theirs)) {
-               if (branch && branch->merge && branch->merge[0]->dst &&
-                   show_upstream_ref) {
-                       ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
-                       if (want_color(branch_use_color))
-                               strbuf_addf(stat, "[%s%s%s] ",
-                                               branch_get_color(BRANCH_COLOR_UPSTREAM),
-                                               ref, branch_get_color(BRANCH_COLOR_RESET));
-                       else
-                               strbuf_addf(stat, "[%s] ", ref);
-               }
+       switch (stat_tracking_info(branch, &ours, &theirs)) {
+       case 0:
+               /* no base */
                return;
+       case -1:
+               /* with "gone" base */
+               upstream_is_gone = 1;
+               break;
+       default:
+               /* with base */
+               break;
        }
 
        if (show_upstream_ref) {
@@ -448,19 +448,25 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
                        strbuf_addstr(&fancy, ref);
        }
 
-       if (!ours) {
-               if (ref)
+       if (upstream_is_gone) {
+               if (show_upstream_ref)
+                       strbuf_addf(stat, _("[%s: gone]"), fancy.buf);
+       } else if (!ours && !theirs) {
+               if (show_upstream_ref)
+                       strbuf_addf(stat, _("[%s]"), fancy.buf);
+       } else if (!ours) {
+               if (show_upstream_ref)
                        strbuf_addf(stat, _("[%s: behind %d]"), fancy.buf, theirs);
                else
                        strbuf_addf(stat, _("[behind %d]"), theirs);
 
        } else if (!theirs) {
-               if (ref)
+               if (show_upstream_ref)
                        strbuf_addf(stat, _("[%s: ahead %d]"), fancy.buf, ours);
                else
                        strbuf_addf(stat, _("[ahead %d]"), ours);
        } else {
-               if (ref)
+               if (show_upstream_ref)
                        strbuf_addf(stat, _("[%s: ahead %d, behind %d]"),
                                    fancy.buf, ours, theirs);
                else
index e2a1cef6843b7db2f7ffb4b9c89003397948c748..594463a11bcba3cf99748ccdaeb055bd79283ddd 100644 (file)
@@ -5,7 +5,7 @@
 #include "pathspec.h"
 #include "parse-options.h"
 
-static int quiet, verbose, stdin_paths, show_non_matching;
+static int quiet, verbose, stdin_paths, show_non_matching, no_index;
 static const char * const check_ignore_usage[] = {
 "git check-ignore [options] pathname...",
 "git check-ignore [options] --stdin < <list-of-paths>",
@@ -24,6 +24,8 @@ static const struct option check_ignore_options[] = {
                 N_("terminate input and output records by a NUL character")),
        OPT_BOOL('n', "non-matching", &show_non_matching,
                 N_("show non-matching input paths")),
+       OPT_BOOL(0, "no-index", &no_index,
+                N_("ignore index when checking")),
        OPT_END()
 };
 
@@ -166,7 +168,7 @@ int cmd_check_ignore(int argc, const char **argv, const char *prefix)
                die(_("--non-matching is only valid with --verbose"));
 
        /* read_cache() is only necessary so we can watch out for submodules. */
-       if (read_cache() < 0)
+       if (!no_index && read_cache() < 0)
                die(_("index file corrupt"));
 
        memset(&dir, 0, sizeof(dir));
index ca3eb68d72b0ab9ee683eff3206d28012f27c4fc..b708c115a344974b79501ec896ce87ad30905450 100644 (file)
@@ -556,7 +556,7 @@ static void update_remote_refs(const struct ref *refs,
                                                              0, &rm, transport))
                        die(_("remote did not send all necessary objects"));
                if (0 <= option_verbosity)
-                       printf(_("done\n"));
+                       printf(_("done.\n"));
        }
 
        if (refs) {
@@ -945,6 +945,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                        our_head_points_at = remote_head_points_at;
        }
        else {
+               if (option_branch)
+                       die(_("Remote branch %s not found in upstream %s"),
+                                       option_branch, option_origin);
+
                warning(_("You appear to have cloned an empty repository."));
                mapped_refs = NULL;
                our_head_points_at = NULL;
index 80d886ab3af371a003ae026c19bd76ea83df9690..6ab4605cf5c2e6ef5efb37518c9c215bf8895f97 100644 (file)
@@ -30,6 +30,7 @@
 #include "column.h"
 #include "sequencer.h"
 #include "notes-utils.h"
+#include "mailmap.h"
 
 static const char * const builtin_commit_usage[] = {
        N_("git commit [options] [--] <pathspec>..."),
@@ -163,6 +164,15 @@ static void determine_whence(struct wt_status *s)
                s->whence = whence;
 }
 
+static void status_init_config(struct wt_status *s, config_fn_t fn)
+{
+       wt_status_prepare(s);
+       gitmodules_config();
+       git_config(fn, s);
+       determine_whence(s);
+       s->hints = advice_status_hints; /* must come after git_config() */
+}
+
 static void rollback_index_files(void)
 {
        switch (commit_style) {
@@ -597,6 +607,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
        const char *hook_arg2 = NULL;
        int ident_shown = 0;
        int clean_message_contents = (cleanup_mode != CLEANUP_NONE);
+       int old_display_comment_prefix;
 
        /* This checks and barfs if author is badly specified */
        determine_author_info(author_ident);
@@ -694,6 +705,16 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
        if (s->fp == NULL)
                die_errno(_("could not open '%s'"), git_path(commit_editmsg));
 
+       /* Ignore status.displayCommentPrefix: we do need comments in COMMIT_EDITMSG. */
+       old_display_comment_prefix = s->display_comment_prefix;
+       s->display_comment_prefix = 1;
+
+       /*
+        * Most hints are counter-productive when the commit has
+        * already started.
+        */
+       s->hints = 0;
+
        if (clean_message_contents)
                stripspace(&sb, 0);
 
@@ -819,6 +840,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
         */
        if (!commitable && whence != FROM_MERGE && !allow_empty &&
            !(amend && is_a_merge(current_head))) {
+               s->display_comment_prefix = old_display_comment_prefix;
                run_status(stdout, index_file, prefix, 0, s);
                if (amend)
                        fputs(_(empty_amend_advice), stderr);
@@ -933,6 +955,7 @@ static const char *find_author_by_nickname(const char *name)
        struct rev_info revs;
        struct commit *commit;
        struct strbuf buf = STRBUF_INIT;
+       struct string_list mailmap = STRING_LIST_INIT_NODUP;
        const char *av[20];
        int ac = 0;
 
@@ -943,13 +966,17 @@ static const char *find_author_by_nickname(const char *name)
        av[++ac] = buf.buf;
        av[++ac] = NULL;
        setup_revisions(ac, av, &revs, NULL);
+       revs.mailmap = &mailmap;
+       read_mailmap(revs.mailmap, NULL);
+
        prepare_revision_walk(&revs);
        commit = get_revision(&revs);
        if (commit) {
                struct pretty_print_context ctx = {0};
                ctx.date_mode = DATE_NORMAL;
                strbuf_release(&buf);
-               format_commit_message(commit, "%an <%ae>", &buf, &ctx);
+               format_commit_message(commit, "%aN <%aE>", &buf, &ctx);
+               clear_mailmap(&mailmap);
                return strbuf_detach(&buf, NULL);
        }
        die(_("No existing author found with '%s'"), name);
@@ -1180,6 +1207,10 @@ static int git_status_config(const char *k, const char *v, void *cb)
                s->use_color = git_config_colorbool(k, v);
                return 0;
        }
+       if (!strcmp(k, "status.displaycommentprefix")) {
+               s->display_comment_prefix = git_config_bool(k, v);
+               return 0;
+       }
        if (!prefixcmp(k, "status.color.") || !prefixcmp(k, "color.status.")) {
                int slot = parse_status_slot(k, 13);
                if (slot < 0)
@@ -1244,10 +1275,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage_with_options(builtin_status_usage, builtin_status_options);
 
-       wt_status_prepare(&s);
-       gitmodules_config();
-       git_config(git_status_config, &s);
-       determine_whence(&s);
+       status_init_config(&s, git_status_config);
        argc = parse_options(argc, argv, prefix,
                             builtin_status_options,
                             builtin_status_usage, 0);
@@ -1489,11 +1517,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage_with_options(builtin_commit_usage, builtin_commit_options);
 
-       wt_status_prepare(&s);
-       gitmodules_config();
-       git_config(git_commit_config, &s);
+       status_init_config(&s, git_commit_config);
        status_format = STATUS_FORMAT_NONE; /* Ignore status.short */
-       determine_whence(&s);
        s.colopts = 0;
 
        if (get_sha1("HEAD", sha1))
@@ -1615,7 +1640,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                                           !current_head
                                           ? NULL
                                           : current_head->object.sha1,
-                                          0);
+                                          0, NULL);
 
        nl = strchr(sb.buf, '\n');
        if (nl)
index fc8d8820cbd2c0fcddb69aeb3fa258cf87e96814..20e89fe4e0c7db50267e8e9358c38faea2259fab 100644 (file)
@@ -119,7 +119,8 @@ static int format_config(struct strbuf *buf, const char *key_, const char *value
                must_print_delim = 1;
        }
        if (types == TYPE_INT)
-               sprintf(value, "%d", git_config_int(key_, value_ ? value_ : ""));
+               sprintf(value, "%"PRId64,
+                       git_config_int64(key_, value_ ? value_ : ""));
        else if (types == TYPE_BOOL)
                vptr = git_config_bool(key_, value_) ? "true" : "false";
        else if (types == TYPE_BOOL_OR_INT) {
@@ -268,8 +269,8 @@ static char *normalize_value(const char *key, const char *value)
        else {
                normalized = xmalloc(64);
                if (types == TYPE_INT) {
-                       int v = git_config_int(key, value);
-                       sprintf(normalized, "%d", v);
+                       int64_t v = git_config_int64(key, value);
+                       sprintf(normalized, "%"PRId64, v);
                }
                else if (types == TYPE_BOOL)
                        sprintf(normalized, "%s",
index c94e5c30d0851080c49df2edc6d66a739085cf22..b9d36037041deac869a2fa498e823bd7f315c2ba 100644 (file)
@@ -13,7 +13,7 @@
 #define MAX_TAGS       (FLAG_BITS - 1)
 
 static const char * const describe_usage[] = {
-       N_("git describe [options] <committish>*"),
+       N_("git describe [options] <commit-ish>*"),
        N_("git describe [options] --dirty"),
        NULL
 };
@@ -486,7 +486,7 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
                }
                describe("HEAD", 1);
        } else if (dirty) {
-               die(_("--dirty is incompatible with committishes"));
+               die(_("--dirty is incompatible with commit-ishes"));
        } else {
                while (argc-- > 0) {
                        describe(*argv++, argc == 0);
index b1b9b5e52aa57b62d5edb5c55f818411e64d9c90..78250eab08abf692344277e01cb94fc5f5c2f807 100644 (file)
@@ -30,6 +30,7 @@ static int fake_missing_tagger;
 static int use_done_feature;
 static int no_data;
 static int full_tree;
+static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
 
 static int parse_opt_signed_tag_mode(const struct option *opt,
                                     const char *arg, int unset)
@@ -484,10 +485,32 @@ static void handle_tag(const char *name, struct tag *tag)
               (int)message_size, (int)message_size, message ? message : "");
 }
 
-static void get_tags_and_duplicates(struct rev_cmdline_info *info,
-                                   struct string_list *extra_refs)
+static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name)
+{
+       switch (e->item->type) {
+       case OBJ_COMMIT:
+               return (struct commit *)e->item;
+       case OBJ_TAG: {
+               struct tag *tag = (struct tag *)e->item;
+
+               /* handle nested tags */
+               while (tag && tag->object.type == OBJ_TAG) {
+                       parse_object(tag->object.sha1);
+                       string_list_append(&extra_refs, full_name)->util = tag;
+                       tag = (struct tag *)tag->tagged;
+               }
+               if (!tag)
+                       die("Tag %s points nowhere?", e->name);
+               return (struct commit *)tag;
+               break;
+       }
+       default:
+               return NULL;
+       }
+}
+
+static void get_tags_and_duplicates(struct rev_cmdline_info *info)
 {
-       struct tag *tag;
        int i;
 
        for (i = 0; i < info->nr; i++) {
@@ -502,60 +525,45 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info,
                if (dwim_ref(e->name, strlen(e->name), sha1, &full_name) != 1)
                        continue;
 
-               switch (e->item->type) {
-               case OBJ_COMMIT:
-                       commit = (struct commit *)e->item;
-                       break;
-               case OBJ_TAG:
-                       tag = (struct tag *)e->item;
-
-                       /* handle nested tags */
-                       while (tag && tag->object.type == OBJ_TAG) {
-                               parse_object(tag->object.sha1);
-                               string_list_append(extra_refs, full_name)->util = tag;
-                               tag = (struct tag *)tag->tagged;
-                       }
-                       if (!tag)
-                               die ("Tag %s points nowhere?", e->name);
-                       switch(tag->object.type) {
-                       case OBJ_COMMIT:
-                               commit = (struct commit *)tag;
-                               break;
-                       case OBJ_BLOB:
-                               export_blob(tag->object.sha1);
-                               continue;
-                       default: /* OBJ_TAG (nested tags) is already handled */
-                               warning("Tag points to object of unexpected type %s, skipping.",
-                                       typename(tag->object.type));
-                               continue;
-                       }
-                       break;
-               default:
+               commit = get_commit(e, full_name);
+               if (!commit) {
                        warning("%s: Unexpected object of type %s, skipping.",
                                e->name,
                                typename(e->item->type));
                        continue;
                }
 
+               switch(commit->object.type) {
+               case OBJ_COMMIT:
+                       break;
+               case OBJ_BLOB:
+                       export_blob(commit->object.sha1);
+                       continue;
+               default: /* OBJ_TAG (nested tags) is already handled */
+                       warning("Tag points to object of unexpected type %s, skipping.",
+                               typename(commit->object.type));
+                       continue;
+               }
+
                /*
                 * This ref will not be updated through a commit, lets make
                 * sure it gets properly updated eventually.
                 */
                if (commit->util || commit->object.flags & SHOWN)
-                       string_list_append(extra_refs, full_name)->util = commit;
+                       string_list_append(&extra_refs, full_name)->util = commit;
                if (!commit->util)
                        commit->util = full_name;
        }
 }
 
-static void handle_tags_and_duplicates(struct string_list *extra_refs)
+static void handle_tags_and_duplicates(void)
 {
        struct commit *commit;
        int i;
 
-       for (i = extra_refs->nr - 1; i >= 0; i--) {
-               const char *name = extra_refs->items[i].string;
-               struct object *object = extra_refs->items[i].util;
+       for (i = extra_refs.nr - 1; i >= 0; i--) {
+               const char *name = extra_refs.items[i].string;
+               struct object *object = extra_refs.items[i].util;
                switch (object->type) {
                case OBJ_TAG:
                        handle_tag(name, (struct tag *)object);
@@ -657,7 +665,6 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 {
        struct rev_info revs;
        struct object_array commits = OBJECT_ARRAY_INIT;
-       struct string_list extra_refs = STRING_LIST_INIT_NODUP;
        struct commit *commit;
        char *export_filename = NULL, *import_filename = NULL;
        uint32_t lastimportid;
@@ -709,7 +716,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
        if (import_filename && revs.prune_data.nr)
                full_tree = 1;
 
-       get_tags_and_duplicates(&revs.cmdline, &extra_refs);
+       get_tags_and_duplicates(&revs.cmdline);
 
        if (prepare_revision_walk(&revs))
                die("revision walk setup failed");
@@ -725,7 +732,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
                }
        }
 
-       handle_tags_and_duplicates(&extra_refs);
+       handle_tags_and_duplicates();
 
        if (export_filename && lastimportid != last_idnum)
                export_marks(export_filename);
index 9e654efa3bb725edd91f6eb7059b263668e622bc..bd7a10164f4fed8aeb6e8148e2ae8c0a793e7ee0 100644 (file)
@@ -262,7 +262,8 @@ static int s_update_ref(const char *action,
                rla = default_rla.buf;
        snprintf(msg, sizeof(msg), "%s: %s", rla, action);
        lock = lock_any_ref_for_update(ref->name,
-                                      check_old ? ref->old_sha1 : NULL, 0);
+                                      check_old ? ref->old_sha1 : NULL,
+                                      0, NULL);
        if (!lock)
                return errno == ENOTDIR ? STORE_REF_ERROR_DF_CONFLICT :
                                          STORE_REF_ERROR_OTHER;
index 39fa5e86d4d54e2f9c40d61ae78778078c56f5a8..97ce678c6ba63afeb3deedfd469c4a53a475a1be 100644 (file)
@@ -16,6 +16,7 @@
 
 #define REACHABLE 0x0001
 #define SEEN      0x0002
+#define HAS_OBJ   0x0004
 
 static int show_root;
 static int show_tags;
@@ -101,7 +102,7 @@ static int mark_object(struct object *obj, int type, void *data)
        if (obj->flags & REACHABLE)
                return 0;
        obj->flags |= REACHABLE;
-       if (!obj->parsed) {
+       if (!(obj->flags & HAS_OBJ)) {
                if (parent && !has_sha1_file(obj->sha1)) {
                        printf("broken link from %7s %s\n",
                                 typename(parent->type), sha1_to_hex(parent->sha1));
@@ -127,16 +128,13 @@ static int traverse_one_object(struct object *obj)
        struct tree *tree = NULL;
 
        if (obj->type == OBJ_TREE) {
-               obj->parsed = 0;
                tree = (struct tree *)obj;
                if (parse_tree(tree) < 0)
                        return 1; /* error already displayed */
        }
        result = fsck_walk(obj, mark_object, obj);
-       if (tree) {
-               free(tree->buffer);
-               tree->buffer = NULL;
-       }
+       if (tree)
+               free_tree_buffer(tree);
        return result;
 }
 
@@ -178,7 +176,7 @@ static void check_reachable_object(struct object *obj)
         * except if it was in a pack-file and we didn't
         * do a full fsck
         */
-       if (!obj->parsed) {
+       if (!(obj->flags & HAS_OBJ)) {
                if (has_sha1_pack(obj->sha1))
                        return; /* it is in pack - forget about it */
                printf("missing %s %s\n", typename(obj->type), sha1_to_hex(obj->sha1));
@@ -306,8 +304,7 @@ static int fsck_obj(struct object *obj)
        if (obj->type == OBJ_TREE) {
                struct tree *item = (struct tree *) obj;
 
-               free(item->buffer);
-               item->buffer = NULL;
+               free_tree_buffer(item);
        }
 
        if (obj->type == OBJ_COMMIT) {
@@ -340,6 +337,7 @@ static int fsck_sha1(const unsigned char *sha1)
                return error("%s: object corrupt or missing",
                             sha1_to_hex(sha1));
        }
+       obj->flags |= HAS_OBJ;
        return fsck_obj(obj);
 }
 
@@ -352,6 +350,7 @@ static int fsck_obj_buffer(const unsigned char *sha1, enum object_type type,
                errors_found |= ERROR_OBJECT;
                return error("%s: object corrupt or missing", sha1_to_hex(sha1));
        }
+       obj->flags = HAS_OBJ;
        return fsck_obj(obj);
 }
 
index 9c1cfac4427ef8d8fbca0834e1c8b644ceddf998..9e9eb4b74e8335f097c7cc9e261b051feda0bf0d 100644 (file)
@@ -770,6 +770,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
                        if (obj->type == OBJ_TREE) {
                                struct tree *item = (struct tree *) obj;
                                item->buffer = NULL;
+                               obj->parsed = 0;
                        }
                        if (obj->type == OBJ_COMMIT) {
                                struct commit *commit = (struct commit *) obj;
index d4823c9d38e5e22dff62d979601e0b06b9c857f3..e1cf6d8547d4aa7f548fb80f0efb8f4e7b1d9c8e 100644 (file)
@@ -220,6 +220,8 @@ static void show_files(struct dir_struct *dir)
 
        /* For cached/deleted files we don't need to even do the readdir */
        if (show_others || show_killed) {
+               if (!show_others)
+                       dir->flags |= DIR_COLLECT_KILLED_ONLY;
                fill_directory(dir, &pathspec);
                if (show_others)
                        show_other_files(dir);
index a8cf4a248492fc793c433e61e025fb7f3b3eacfe..02a69c14e6abfc51413b397a93180e0890285e2a 100644 (file)
@@ -1193,7 +1193,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
         * 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 is the same as HEAD there instead.
+        * commit-ish that is the same as HEAD there instead.
         * Traditional format never would have "-m" so it is an
         * additional safety measure to check for it.
         */
index 4eb0521c815870abb670e8ddb035caa9c6507e67..e86cd5729f38316bf6e304e4e97ce671e4ea135b 100644 (file)
@@ -2378,7 +2378,7 @@ static void get_object_list(int ac, const char **av)
 
        if (prepare_revision_walk(&revs))
                die("revision walk setup failed");
-       mark_edges_uninteresting(revs.commits, &revs, show_edge);
+       mark_edges_uninteresting(&revs, show_edge);
        traverse_commit_list(&revs, show_commit, show_object, NULL);
 
        if (keep_unreachable)
index 50bbfd62b135b6f4454c3cdd4e74cf227c24a1a5..7b1b66c36ac14cb29db9dbbbd5b6f4d27b67d91c 100644 (file)
@@ -15,7 +15,7 @@ static const char * const push_usage[] = {
        NULL,
 };
 
-static int thin;
+static int thin = 1;
 static int deleterefs;
 static const char *receivepack;
 static int verbosity;
@@ -315,8 +315,7 @@ static int push_with_options(struct transport *transport, int flags)
        if (receivepack)
                transport_set_option(transport,
                                     TRANS_OPT_RECEIVEPACK, receivepack);
-       if (thin)
-               transport_set_option(transport, TRANS_OPT_THIN, "yes");
+       transport_set_option(transport, TRANS_OPT_THIN, thin ? "yes" : NULL);
 
        if (!is_empty_cas(&cas)) {
                if (!transport->smart_options)
index 7434d9b4a2d62e619b15fc6aa238e8caa62277cd..67ce1ef105d1494e7905e66750b14676e082e11c 100644 (file)
@@ -39,6 +39,7 @@ static int quiet;
 static int prefer_ofs_delta = 1;
 static int auto_update_server_info;
 static int auto_gc = 1;
+static int fix_thin = 1;
 static const char *head_name;
 static void *head_name_to_free;
 static int sent_capabilities;
@@ -525,7 +526,8 @@ static const char *update(struct command *cmd)
                return NULL; /* good */
        }
        else {
-               lock = lock_any_ref_for_update(namespaced_name, old_sha1, 0);
+               lock = lock_any_ref_for_update(namespaced_name, old_sha1,
+                                              0, NULL);
                if (!lock) {
                        rp_error("failed to lock %s", name);
                        return "failed to lock";
@@ -870,7 +872,8 @@ static const char *unpack(int err_fd)
                keeper[i++] = "--stdin";
                if (fsck_objects)
                        keeper[i++] = "--strict";
-               keeper[i++] = "--fix-thin";
+               if (fix_thin)
+                       keeper[i++] = "--fix-thin";
                keeper[i++] = hdr_arg;
                keeper[i++] = keep_arg;
                keeper[i++] = NULL;
@@ -976,6 +979,10 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
                                stateless_rpc = 1;
                                continue;
                        }
+                       if (!strcmp(arg, "--reject-thin-pack-for-testing")) {
+                               fix_thin = 0;
+                               continue;
+                       }
 
                        usage(receive_pack_usage);
                }
index 54184b3d133bb66db272fd21ad3cad53a4a9a5cb..6eb24c8da27d265cad38628aeaa3e040dd298aab 100644 (file)
@@ -94,8 +94,7 @@ static int tree_is_complete(const unsigned char *sha1)
                        complete = 0;
                }
        }
-       free(tree->buffer);
-       tree->buffer = NULL;
+       free_tree_buffer(tree);
 
        if (complete)
                tree->object.flags |= SEEN;
@@ -366,7 +365,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, 0);
+       lock = lock_any_ref_for_update(ref, sha1, 0, NULL);
        if (!lock)
                return error("cannot lock ref '%s'", ref);
        log_file = git_pathdup("logs/%s", ref);
index eaac3e20124c48456faab48a6529ed281075ee25..4e14891095e6ea016b9f44262ae300c42a75e1b2 100644 (file)
@@ -12,7 +12,7 @@ static const char * const builtin_remote_usage[] = {
        N_("git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <name> <url>"),
        N_("git remote rename <old> <new>"),
        N_("git remote remove <name>"),
-       N_("git remote set-head <name> (-a | -d | <branch>)"),
+       N_("git remote set-head <name> (-a | --auto | -d | --delete |<branch>)"),
        N_("git remote [-v | --verbose] show [-n] <name>"),
        N_("git remote prune [-n | --dry-run] <name>"),
        N_("git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"),
@@ -39,7 +39,7 @@ static const char * const builtin_remote_rm_usage[] = {
 };
 
 static const char * const builtin_remote_sethead_usage[] = {
-       N_("git remote set-head <name> (-a | -d | <branch>)"),
+       N_("git remote set-head <name> (-a | --auto | -d | --delete | <branch>)"),
        NULL
 };
 
index 11b0a55ae7f6e3d1a04eeb4026b151144d0315ba..b1bd3ef9946761b146a38d5977a7378175cda047 100644 (file)
@@ -85,6 +85,7 @@ static int replace_object(const char *object_ref, const char *replace_ref,
                          int force)
 {
        unsigned char object[20], prev[20], repl[20];
+       enum object_type obj_type, repl_type;
        char ref[PATH_MAX];
        struct ref_lock *lock;
 
@@ -100,12 +101,21 @@ static int replace_object(const char *object_ref, const char *replace_ref,
        if (check_refname_format(ref, 0))
                die("'%s' is not a valid ref name.", ref);
 
+       obj_type = sha1_object_info(object, NULL);
+       repl_type = sha1_object_info(repl, NULL);
+       if (!force && obj_type != repl_type)
+               die("Objects must be of the same type.\n"
+                   "'%s' points to a replaced object of type '%s'\n"
+                   "while '%s' points to a replacement object of type '%s'.",
+                   object_ref, typename(obj_type),
+                   replace_ref, typename(repl_type));
+
        if (read_ref(ref, prev))
                hashclr(prev);
        else if (!force)
                die("replace ref '%s' already exists", ref);
 
-       lock = lock_any_ref_for_update(ref, prev, 0);
+       lock = lock_any_ref_for_update(ref, prev, 0, NULL);
        if (!lock)
                die("%s: cannot lock the ref", ref);
        if (write_ref_sha1(lock, repl, NULL) < 0)
@@ -118,9 +128,9 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
 {
        int list = 0, delete = 0, force = 0;
        struct option options[] = {
-               OPT_BOOL('l', NULL, &list, N_("list replace refs")),
-               OPT_BOOL('d', NULL, &delete, N_("delete replace refs")),
-               OPT_BOOL('f', NULL, &force, N_("replace the ref if it exists")),
+               OPT_BOOL('l', "list", &list, N_("list replace refs")),
+               OPT_BOOL('d', "delete", &delete, N_("delete replace refs")),
+               OPT_BOOL('f', "force", &force, N_("replace the ref if it exists")),
                OPT_END()
        };
 
index 800117f4f3685d9c333892fcae7332d1dff3208a..f2f9d55392d2193432d5a572a70cd27afcf6b136 100644 (file)
@@ -230,7 +230,7 @@ static void parse_args(struct pathspec *pathspec,
                       prefix, argv);
 }
 
-static int update_refs(const char *rev, const unsigned char *sha1)
+static int reset_refs(const char *rev, const unsigned char *sha1)
 {
        int update_ref_status;
        struct strbuf msg = STRBUF_INIT;
@@ -334,11 +334,14 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
                die_if_unmerged_cache(reset_type);
 
        if (reset_type != SOFT) {
-               struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
+               struct lock_file *lock = xcalloc(1, sizeof(*lock));
                int newfd = hold_locked_index(lock, 1);
                if (reset_type == MIXED) {
+                       int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
                        if (read_from_tree(&pathspec, sha1))
                                return 1;
+                       refresh_index(&the_index, flags, NULL, NULL,
+                                     _("Unstaged changes after reset:"));
                } else {
                        int err = reset_index(sha1, reset_type, quiet);
                        if (reset_type == KEEP && !err)
@@ -347,12 +350,6 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
                                die(_("Could not reset index file to revision '%s'."), rev);
                }
 
-               if (reset_type == MIXED) { /* Report what has not been updated. */
-                       int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
-                       refresh_index(&the_index, flags, NULL, NULL,
-                                     _("Unstaged changes after reset:"));
-               }
-
                if (write_cache(newfd, active_cache, active_nr) ||
                    commit_locked_index(lock))
                        die(_("Could not write new index file."));
@@ -361,7 +358,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
        if (!pathspec.nr && !unborn) {
                /* Any resets without paths update HEAD to the head being
                 * switched to, saving the previous head in ORIG_HEAD before. */
-               update_ref_status = update_refs(rev, sha1);
+               update_ref_status = reset_refs(rev, sha1);
 
                if (reset_type == HARD && !update_ref_status && !quiet)
                        print_new_head_line(lookup_commit_reference(sha1));
index a5ec30d74ee1945ddaf99c89307e59aec714714a..4fc16166374b86927e605ccbfe341aebe0e3240f 100644 (file)
@@ -336,7 +336,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
        if (prepare_revision_walk(&revs))
                die("revision walk setup failed");
        if (revs.tree_objects)
-               mark_edges_uninteresting(revs.commits, &revs, show_edge);
+               mark_edges_uninteresting(&revs, show_edge);
 
        if (bisect_list) {
                int reaches = reaches, all = all;
index 8e87acd12e622957df6bc0a93903898361149f91..52c35e75d90dc07f6a80362f200212e314a14ec8 100644 (file)
@@ -202,6 +202,8 @@ int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
        memset(&opts, 0, sizeof(opts));
        opts.action = REPLAY_PICK;
        git_config(git_default_config, NULL);
+       if (!strcmp(argv[1], "-"))
+               argv[1] = "@{-1}";
        parse_args(argc, argv, &opts);
        res = sequencer_pick_revisions(&opts);
        if (res < 0)
index ae73d17b6cbc22f3a7eb30aff5a14cda27c5876c..c226f767aa9b0e5633a3d5dde7b0b969fec39c7f 100644 (file)
@@ -127,9 +127,11 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
                        author = buffer + 7;
                buffer = eol;
        }
-       if (!author)
-               die(_("Missing author: %s"),
+       if (!author) {
+               warning(_("Missing author: %s"),
                    sha1_to_hex(commit->object.sha1));
+               return;
+       }
        if (log->user_format) {
                struct pretty_print_context ctx = {0};
                ctx.fmt = CMIT_FMT_USERFORMAT;
index e981dfb9f088cbbfdfb199700a6de17758bf1eca..1259ed708b6b5dd1322b6db5683cf5555f41570f 100644 (file)
@@ -89,11 +89,11 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)
 
        if (argc == 2) {
                if (!strcmp(argv[1], "-s") ||
-                       !strcmp(argv[1], "--strip-comments")) {
-                        strip_comments = 1;
+                   !strcmp(argv[1], "--strip-comments")) {
+                       strip_comments = 1;
                } else if (!strcmp(argv[1], "-c") ||
-                                        !strcmp(argv[1], "--comment-lines")) {
-                        mode = COMMENT_LINES;
+                          !strcmp(argv[1], "--comment-lines")) {
+                       mode = COMMENT_LINES;
                } else {
                        mode = INVAL;
                }
index b577af562a4a554f43c64256e112fcbc423edd3d..ea55f1d1bdd524abd46e6baa7a02ef85d56d5eb2 100644 (file)
@@ -574,7 +574,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        if (annotate)
                create_tag(object, tag, &buf, &opt, prev, object);
 
-       lock = lock_any_ref_for_update(ref.buf, prev, 0);
+       lock = lock_any_ref_for_update(ref.buf, prev, 0, NULL);
        if (!lock)
                die(_("%s: cannot lock the ref"), ref.buf);
        if (write_ref_sha1(lock, object, NULL) < 0)
index 7484d36a65ba1f722f2dda33473bf509f30727c9..702e90db2a82a0eba2ff233b9ec46690da5afc3e 100644 (file)
 #include "refs.h"
 #include "builtin.h"
 #include "parse-options.h"
+#include "quote.h"
+#include "argv-array.h"
 
 static const char * const git_update_ref_usage[] = {
        N_("git update-ref [options] -d <refname> [<oldval>]"),
        N_("git update-ref [options]    <refname> <newval> [<oldval>]"),
+       N_("git update-ref [options] --stdin [-z]"),
        NULL
 };
 
+static int updates_alloc;
+static int updates_count;
+static const struct ref_update **updates;
+
+static char line_termination = '\n';
+static int update_flags;
+
+static struct ref_update *update_alloc(void)
+{
+       struct ref_update *update;
+
+       /* Allocate and zero-init a struct ref_update */
+       update = xcalloc(1, sizeof(*update));
+       ALLOC_GROW(updates, updates_count + 1, updates_alloc);
+       updates[updates_count++] = update;
+
+       /* Store and reset accumulated options */
+       update->flags = update_flags;
+       update_flags = 0;
+
+       return update;
+}
+
+static void update_store_ref_name(struct ref_update *update,
+                                 const char *ref_name)
+{
+       if (check_refname_format(ref_name, REFNAME_ALLOW_ONELEVEL))
+               die("invalid ref format: %s", ref_name);
+       update->ref_name = xstrdup(ref_name);
+}
+
+static void update_store_new_sha1(struct ref_update *update,
+                                 const char *newvalue)
+{
+       if (*newvalue && get_sha1(newvalue, update->new_sha1))
+               die("invalid new value for ref %s: %s",
+                   update->ref_name, newvalue);
+}
+
+static void update_store_old_sha1(struct ref_update *update,
+                                 const char *oldvalue)
+{
+       if (*oldvalue && get_sha1(oldvalue, update->old_sha1))
+               die("invalid old value for ref %s: %s",
+                   update->ref_name, oldvalue);
+
+       /* We have an old value if non-empty, or if empty without -z */
+       update->have_old = *oldvalue || line_termination;
+}
+
+static const char *parse_arg(const char *next, struct strbuf *arg)
+{
+       /* Parse SP-terminated, possibly C-quoted argument */
+       if (*next != '"')
+               while (*next && !isspace(*next))
+                       strbuf_addch(arg, *next++);
+       else if (unquote_c_style(arg, next, &next))
+               die("badly quoted argument: %s", next);
+
+       /* Return position after the argument */
+       return next;
+}
+
+static const char *parse_first_arg(const char *next, struct strbuf *arg)
+{
+       /* Parse argument immediately after "command SP" */
+       strbuf_reset(arg);
+       if (line_termination) {
+               /* Without -z, use the next argument */
+               next = parse_arg(next, arg);
+       } else {
+               /* With -z, use rest of first NUL-terminated line */
+               strbuf_addstr(arg, next);
+               next = next + arg->len;
+       }
+       return next;
+}
+
+static const char *parse_next_arg(const char *next, struct strbuf *arg)
+{
+       /* Parse next SP-terminated or NUL-terminated argument, if any */
+       strbuf_reset(arg);
+       if (line_termination) {
+               /* Without -z, consume SP and use next argument */
+               if (!*next)
+                       return NULL;
+               if (*next != ' ')
+                       die("expected SP but got: %s", next);
+               next = parse_arg(next + 1, arg);
+       } else {
+               /* With -z, read the next NUL-terminated line */
+               if (*next)
+                       die("expected NUL but got: %s", next);
+               if (strbuf_getline(arg, stdin, '\0') == EOF)
+                       return NULL;
+               next = arg->buf + arg->len;
+       }
+       return next;
+}
+
+static void parse_cmd_update(const char *next)
+{
+       struct strbuf ref = STRBUF_INIT;
+       struct strbuf newvalue = STRBUF_INIT;
+       struct strbuf oldvalue = STRBUF_INIT;
+       struct ref_update *update;
+
+       update = update_alloc();
+
+       if ((next = parse_first_arg(next, &ref)) != NULL && ref.buf[0])
+               update_store_ref_name(update, ref.buf);
+       else
+               die("update line missing <ref>");
+
+       if ((next = parse_next_arg(next, &newvalue)) != NULL)
+               update_store_new_sha1(update, newvalue.buf);
+       else
+               die("update %s missing <newvalue>", ref.buf);
+
+       if ((next = parse_next_arg(next, &oldvalue)) != NULL)
+               update_store_old_sha1(update, oldvalue.buf);
+       else if(!line_termination)
+               die("update %s missing [<oldvalue>] NUL", ref.buf);
+
+       if (next && *next)
+               die("update %s has extra input: %s", ref.buf, next);
+}
+
+static void parse_cmd_create(const char *next)
+{
+       struct strbuf ref = STRBUF_INIT;
+       struct strbuf newvalue = STRBUF_INIT;
+       struct ref_update *update;
+
+       update = update_alloc();
+
+       if ((next = parse_first_arg(next, &ref)) != NULL && ref.buf[0])
+               update_store_ref_name(update, ref.buf);
+       else
+               die("create line missing <ref>");
+
+       if ((next = parse_next_arg(next, &newvalue)) != NULL)
+               update_store_new_sha1(update, newvalue.buf);
+       else
+               die("create %s missing <newvalue>", ref.buf);
+       if (is_null_sha1(update->new_sha1))
+               die("create %s given zero new value", ref.buf);
+
+       if (next && *next)
+               die("create %s has extra input: %s", ref.buf, next);
+}
+
+static void parse_cmd_delete(const char *next)
+{
+       struct strbuf ref = STRBUF_INIT;
+       struct strbuf oldvalue = STRBUF_INIT;
+       struct ref_update *update;
+
+       update = update_alloc();
+
+       if ((next = parse_first_arg(next, &ref)) != NULL && ref.buf[0])
+               update_store_ref_name(update, ref.buf);
+       else
+               die("delete line missing <ref>");
+
+       if ((next = parse_next_arg(next, &oldvalue)) != NULL)
+               update_store_old_sha1(update, oldvalue.buf);
+       else if(!line_termination)
+               die("delete %s missing [<oldvalue>] NUL", ref.buf);
+       if (update->have_old && is_null_sha1(update->old_sha1))
+               die("delete %s given zero old value", ref.buf);
+
+       if (next && *next)
+               die("delete %s has extra input: %s", ref.buf, next);
+}
+
+static void parse_cmd_verify(const char *next)
+{
+       struct strbuf ref = STRBUF_INIT;
+       struct strbuf value = STRBUF_INIT;
+       struct ref_update *update;
+
+       update = update_alloc();
+
+       if ((next = parse_first_arg(next, &ref)) != NULL && ref.buf[0])
+               update_store_ref_name(update, ref.buf);
+       else
+               die("verify line missing <ref>");
+
+       if ((next = parse_next_arg(next, &value)) != NULL) {
+               update_store_old_sha1(update, value.buf);
+               update_store_new_sha1(update, value.buf);
+       } else if(!line_termination)
+               die("verify %s missing [<oldvalue>] NUL", ref.buf);
+
+       if (next && *next)
+               die("verify %s has extra input: %s", ref.buf, next);
+}
+
+static void parse_cmd_option(const char *next)
+{
+       if (!strcmp(next, "no-deref"))
+               update_flags |= REF_NODEREF;
+       else
+               die("option unknown: %s", next);
+}
+
+static void update_refs_stdin(void)
+{
+       struct strbuf cmd = STRBUF_INIT;
+
+       /* Read each line dispatch its command */
+       while (strbuf_getline(&cmd, stdin, line_termination) != EOF)
+               if (!cmd.buf[0])
+                       die("empty command in input");
+               else if (isspace(*cmd.buf))
+                       die("whitespace before command: %s", cmd.buf);
+               else if (!prefixcmp(cmd.buf, "update "))
+                       parse_cmd_update(cmd.buf + 7);
+               else if (!prefixcmp(cmd.buf, "create "))
+                       parse_cmd_create(cmd.buf + 7);
+               else if (!prefixcmp(cmd.buf, "delete "))
+                       parse_cmd_delete(cmd.buf + 7);
+               else if (!prefixcmp(cmd.buf, "verify "))
+                       parse_cmd_verify(cmd.buf + 7);
+               else if (!prefixcmp(cmd.buf, "option "))
+                       parse_cmd_option(cmd.buf + 7);
+               else
+                       die("unknown command: %s", cmd.buf);
+
+       strbuf_release(&cmd);
+}
+
 int cmd_update_ref(int argc, const char **argv, const char *prefix)
 {
        const char *refname, *oldval, *msg = NULL;
        unsigned char sha1[20], oldsha1[20];
-       int delete = 0, no_deref = 0, flags = 0;
+       int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0, flags = 0;
        struct option options[] = {
                OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")),
                OPT_BOOL('d', NULL, &delete, N_("delete the reference")),
                OPT_BOOL( 0 , "no-deref", &no_deref,
                                        N_("update <refname> not the one it points to")),
+               OPT_BOOL('z', NULL, &end_null, N_("stdin has NUL-terminated arguments")),
+               OPT_BOOL( 0 , "stdin", &read_stdin, N_("read updates from stdin")),
                OPT_END(),
        };
 
@@ -28,6 +266,18 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
        if (msg && !*msg)
                die("Refusing to perform update with empty message.");
 
+       if (read_stdin) {
+               if (delete || no_deref || argc > 0)
+                       usage_with_options(git_update_ref_usage, options);
+               if (end_null)
+                       line_termination = '\0';
+               update_refs_stdin();
+               return update_refs(msg, updates, updates_count, DIE_ON_ERR);
+       }
+
+       if (end_null)
+               usage_with_options(git_update_ref_usage, options);
+
        if (delete) {
                if (argc < 1 || argc > 2)
                        usage_with_options(git_update_ref_usage, options);
index 6b0b6d490440cc59f8ef451c5da9bcff5b3e1563..118c62528b0bb6c919d146d60516825a5336fe75 100644 (file)
@@ -114,7 +114,7 @@ static int stream_to_pack(struct bulk_checkin_state *state,
 
                if (size && !s.avail_in) {
                        ssize_t rsize = size < sizeof(ibuf) ? size : sizeof(ibuf);
-                       if (xread(fd, ibuf, rsize) != rsize)
+                       if (read_in_full(fd, ibuf, rsize) != rsize)
                                die("failed to read %d bytes from '%s'",
                                    (int)rsize, path);
                        offset += rsize;
diff --git a/cache.h b/cache.h
index 9ef778a5a9ab1e88e595ea3b8fef1656a783093b..51d6602cd9da8f8da6b5176ea352574bcc7036f5 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -880,7 +880,7 @@ extern char *resolve_refdup(const char *ref, unsigned char *sha1, int reading, i
 
 extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
 extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
-extern int interpret_branch_name(const char *str, struct strbuf *);
+extern int interpret_branch_name(const char *str, int len, struct strbuf *);
 extern int get_sha1_mb(const char *str, unsigned char *sha1);
 
 extern int refname_match(const char *abbrev_name, const char *full_name, const char **rules);
@@ -1115,6 +1115,7 @@ extern int git_config_with_options(config_fn_t fn, void *,
 extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
 extern int git_parse_ulong(const char *, unsigned long *);
 extern int git_config_int(const char *, const char *);
+extern int64_t git_config_int64(const char *, const char *);
 extern unsigned long git_config_ulong(const char *, const char *);
 extern int git_config_bool_or_int(const char *, const char *, int *);
 extern int git_config_bool(const char *, const char *);
index 90a5a3c361e02cd7a9562eff2ca1b15f77be0941..bd841f4d0c5e2b7fb8e83d55ba0d0b7e2839bf8a 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -201,6 +201,10 @@ extern struct commit_list *get_shallow_commits(struct object_array *heads,
                int depth, int shallow_flag, int not_shallow_flag);
 extern void check_shallow_file_for_update(void);
 extern void set_alternate_shallow_file(const char *path);
+extern int write_shallow_commits(struct strbuf *out, int use_pack_protocol);
+extern void setup_alternate_shallow(struct lock_file *shallow_lock,
+                                   const char **alternate_shallow_file);
+extern char *setup_temporary_shallow(void);
 
 int is_descendant_of(struct commit *, struct commit_list *);
 int in_merge_bases(struct commit *, struct commit *);
index 22ee9ef1cfb388fdcb7a2686653a6b10359bca59..fecb98bcff74d2cbcb56e8f9f56d1f3b06339469 100644 (file)
@@ -491,7 +491,6 @@ int mingw_stat(const char *file_name, struct stat *buf)
        return do_stat_internal(1, file_name, buf);
 }
 
-#undef fstat
 int mingw_fstat(int fd, struct stat *buf)
 {
        HANDLE fh = (HANDLE)_get_osfhandle(fd);
index bd0a88bc1d19583b7dfed36fd8f7a7af7f386296..92cd728d3db2e3a21650d28f044ea4f59c2673e4 100644 (file)
@@ -32,7 +32,9 @@ typedef int socklen_t;
 #define WEXITSTATUS(x) ((x) & 0xff)
 #define WTERMSIG(x) SIGTERM
 
+#ifndef EWOULDBLOCK
 #define EWOULDBLOCK EAGAIN
+#endif
 #define SHUT_WR SD_SEND
 
 #define SIGHUP 1
@@ -46,8 +48,12 @@ typedef int socklen_t;
 #define F_SETFD 2
 #define FD_CLOEXEC 0x1
 
+#ifndef EAFNOSUPPORT
 #define EAFNOSUPPORT WSAEAFNOSUPPORT
+#endif
+#ifndef ECONNABORTED
 #define ECONNABORTED WSAECONNABORTED
+#endif
 
 struct passwd {
        char *pw_name;
@@ -258,19 +264,35 @@ static inline int getrlimit(int resource, struct rlimit *rlp)
        return 0;
 }
 
-/* Use mingw_lstat() instead of lstat()/stat() and
- * mingw_fstat() instead of fstat() on Windows.
+/*
+ * Use mingw specific stat()/lstat()/fstat() implementations on Windows.
  */
 #define off_t off64_t
 #define lseek _lseeki64
-#ifndef ALREADY_DECLARED_STAT_FUNCS
+
+/* use struct stat with 64 bit st_size */
+#ifdef stat
+#undef stat
+#endif
 #define stat _stati64
 int mingw_lstat(const char *file_name, struct stat *buf);
 int mingw_stat(const char *file_name, struct stat *buf);
 int mingw_fstat(int fd, struct stat *buf);
+#ifdef fstat
+#undef fstat
+#endif
 #define fstat mingw_fstat
+#ifdef lstat
+#undef lstat
+#endif
 #define lstat mingw_lstat
-#define _stati64(x,y) mingw_stat(x,y)
+
+#ifndef _stati64
+# define _stati64(x,y) mingw_stat(x,y)
+#elif defined (_USE_32BIT_TIME_T)
+# define _stat32i64(x,y) mingw_stat(x,y)
+#else
+# define _stat64(x,y) mingw_stat(x,y)
 #endif
 
 int mingw_utime(const char *file_name, const struct utimbuf *times);
@@ -322,6 +344,7 @@ static inline char *mingw_find_last_dir_sep(const char *path)
 #define find_last_dir_sep mingw_find_last_dir_sep
 #define PATH_SEP ';'
 #define PRIuMAX "I64u"
+#define PRId64 "I64d"
 
 void mingw_open_html(const char *path);
 #define open_html mingw_open_html
index 96b6d605dad3872f02933581e501ee4380cb8f68..580bb55bf4a71d9a968a0875e2af827c94785313 100644 (file)
@@ -24,21 +24,6 @@ static __inline int strcasecmp (const char *s1, const char *s2)
 
 #undef ERROR
 
-/* Use mingw_lstat() instead of lstat()/stat() and mingw_fstat() instead
- * of fstat(). We add the declaration of these functions here, suppressing
- * the corresponding declarations in mingw.h, so that we can use the
- * appropriate structure type (and function) names from the msvc headers.
- */
-#define stat _stat64
-int mingw_lstat(const char *file_name, struct stat *buf);
-int mingw_fstat(int fd, struct stat *buf);
-#define fstat mingw_fstat
-#define lstat mingw_lstat
-#define _stat64(x,y) mingw_lstat(x,y)
-#define ALREADY_DECLARED_STAT_FUNCS
-
 #include "compat/mingw.h"
 
-#undef ALREADY_DECLARED_STAT_FUNCS
-
 #endif
index ed4f1fa5af8d911382101116c8ee522ef1e9b629..f216a2a7d3d57b5ca7e791494b01f9604ba51e3e 100644 (file)
@@ -499,7 +499,9 @@ MAX_RELEASE_CHECK_RATE   default: 4095 unless not HAVE_MMAP
 #endif  /* WIN32 */
 #ifdef WIN32
 #define WIN32_LEAN_AND_MEAN
+#ifndef _WIN32_WINNT
 #define _WIN32_WINNT 0x403
+#endif
 #include <windows.h>
 #define HAVE_MMAP 1
 #define HAVE_MORECORE 0
index 44103103a4a71ff25e5e8e1d106221a9dd2e9908..31163f2ae7b71857889f561dea0b3ffecff61989 100644 (file)
@@ -39,7 +39,7 @@
 
 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
 # define WIN32_NATIVE
-# if defined (_MSC_VER)
+# if defined (_MSC_VER) && !defined(_WIN32_WINNT)
 #  define _WIN32_WINNT 0x0502
 # endif
 # include <winsock2.h>
index 7980abd1a71d0676f35eb300c46a30a7298e82f3..95fe849e42d3b9e1f7bc9590fcfac93016f38146 100644 (file)
@@ -48,11 +48,8 @@ void probe_utf8_pathname_composition(char *path, int len)
        if (output_fd >= 0) {
                close(output_fd);
                strcpy(path + len, auml_nfd);
-               /* Indicate to the user, that we can configure it to true */
-               if (!access(path, R_OK))
-                       git_config_set("core.precomposeunicode", "false");
-               /* To be backward compatible, set precomposed_unicode to 0 */
-               precomposed_unicode = 0;
+               precomposed_unicode = access(path, R_OK) ? 0 : 1;
+               git_config_set("core.precomposeunicode", precomposed_unicode ? "true" : "false");
                strcpy(path + len, auml_nfc);
                if (unlink(path))
                        die_errno(_("failed to unlink '%s'"), path);
index 9f9bf0cc9a1405e938fddbedc44468782ad61021..e1d66a145b756c49c4e4902200c354499532a428 100644 (file)
--- a/config.c
+++ b/config.c
@@ -468,7 +468,7 @@ static int parse_unit_factor(const char *end, uintmax_t *val)
        return 0;
 }
 
-static int git_parse_long(const char *value, long *ret)
+static int git_parse_signed(const char *value, intmax_t *ret, intmax_t max)
 {
        if (value && *value) {
                char *end;
@@ -480,21 +480,25 @@ static int git_parse_long(const char *value, long *ret)
                val = strtoimax(value, &end, 0);
                if (errno == ERANGE)
                        return 0;
-               if (!parse_unit_factor(end, &factor))
+               if (!parse_unit_factor(end, &factor)) {
+                       errno = EINVAL;
                        return 0;
+               }
                uval = abs(val);
                uval *= factor;
-               if ((uval > maximum_signed_value_of_type(long)) ||
-                   (abs(val) > uval))
+               if (uval > max || abs(val) > uval) {
+                       errno = ERANGE;
                        return 0;
+               }
                val *= factor;
                *ret = val;
                return 1;
        }
+       errno = EINVAL;
        return 0;
 }
 
-int git_parse_ulong(const char *value, unsigned long *ret)
+static int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max)
 {
        if (value && *value) {
                char *end;
@@ -506,29 +510,75 @@ int git_parse_ulong(const char *value, unsigned long *ret)
                if (errno == ERANGE)
                        return 0;
                oldval = val;
-               if (!parse_unit_factor(end, &val))
+               if (!parse_unit_factor(end, &val)) {
+                       errno = EINVAL;
                        return 0;
-               if ((val > maximum_unsigned_value_of_type(long)) ||
-                   (oldval > val))
+               }
+               if (val > max || oldval > val) {
+                       errno = ERANGE;
                        return 0;
+               }
                *ret = val;
                return 1;
        }
+       errno = EINVAL;
        return 0;
 }
 
-static void die_bad_config(const char *name)
+static int git_parse_int(const char *value, int *ret)
 {
+       intmax_t tmp;
+       if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int)))
+               return 0;
+       *ret = tmp;
+       return 1;
+}
+
+static int git_parse_int64(const char *value, int64_t *ret)
+{
+       intmax_t tmp;
+       if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int64_t)))
+               return 0;
+       *ret = tmp;
+       return 1;
+}
+
+int git_parse_ulong(const char *value, unsigned long *ret)
+{
+       uintmax_t tmp;
+       if (!git_parse_unsigned(value, &tmp, maximum_unsigned_value_of_type(long)))
+               return 0;
+       *ret = tmp;
+       return 1;
+}
+
+static void die_bad_number(const char *name, const char *value)
+{
+       const char *reason = errno == ERANGE ?
+                            "out of range" :
+                            "invalid unit";
+       if (!value)
+               value = "";
+
        if (cf && cf->name)
-               die("bad config value for '%s' in %s", name, cf->name);
-       die("bad config value for '%s'", name);
+               die("bad numeric config value '%s' for '%s' in %s: %s",
+                   value, name, cf->name, reason);
+       die("bad numeric config value '%s' for '%s': %s", value, name, reason);
 }
 
 int git_config_int(const char *name, const char *value)
 {
-       long ret = 0;
-       if (!git_parse_long(value, &ret))
-               die_bad_config(name);
+       int ret;
+       if (!git_parse_int(value, &ret))
+               die_bad_number(name, value);
+       return ret;
+}
+
+int64_t git_config_int64(const char *name, const char *value)
+{
+       int64_t ret;
+       if (!git_parse_int64(value, &ret))
+               die_bad_number(name, value);
        return ret;
 }
 
@@ -536,7 +586,7 @@ unsigned long git_config_ulong(const char *name, const char *value)
 {
        unsigned long ret;
        if (!git_parse_ulong(value, &ret))
-               die_bad_config(name);
+               die_bad_number(name, value);
        return ret;
 }
 
@@ -559,10 +609,10 @@ static int git_config_maybe_bool_text(const char *name, const char *value)
 
 int git_config_maybe_bool(const char *name, const char *value)
 {
-       long v = git_config_maybe_bool_text(name, value);
+       int v = git_config_maybe_bool_text(name, value);
        if (0 <= v)
                return v;
-       if (git_parse_long(value, &v))
+       if (git_parse_int(value, &v))
                return !!v;
        return -1;
 }
index 7d615314f41f33df245efcecbe49f2aee3c90ad7..82d549e48ba796469a27ef41ad0c9ad2a8d96cbc 100644 (file)
@@ -339,6 +339,7 @@ ifeq ($(uname_S),Windows)
        OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
        NO_REGEX = YesPlease
        NO_CURL = YesPlease
+       NO_GETTEXT = YesPlease
        NO_PYTHON = YesPlease
        BLK_SHA1 = YesPlease
        ETAGS_TARGET = ETAGS
@@ -499,7 +500,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
        NO_INET_NTOP = YesPlease
        NO_POSIX_GOODIES = UnfortunatelyYes
        DEFAULT_HELP_FORMAT = html
-       COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/win32
+       COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -D_USE_32BIT_TIME_T -DNOGDI -Icompat -Icompat/win32
        COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
        COMPAT_OBJS += compat/mingw.o compat/winansi.o \
                compat/win32/pthread.o compat/win32/syslog.o \
index a80ebd316c34bb0f0cf3d5a04c33123bb2847421..40868610ab1c02d10cc7cdc927fdf97a5e010414 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -552,7 +552,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
        path = strchr(end, c);
        if (path && !has_dos_drive_prefix(end)) {
                if (c == ':') {
-                       if (path < strchrnul(host, '/')) {
+                       if (host != url || path < strchrnul(host, '/')) {
                                protocol = PROTO_SSH;
                                *path++ = '\0';
                        } else /* '/' in the host part, assume local path */
diff --git a/contrib/ciabot/INSTALL b/contrib/ciabot/INSTALL
deleted file mode 100644 (file)
index 7222961..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-= Installation instructions =
-
-Two scripts are included.  The Python one (ciabot.py) is faster and
-more capable; the shell one (ciabot.sh) is a fallback in case Python
-gives your git hosting site indigestion. (I know of no such sites.)
-
-It is no longer necessary to modify the script in order to put it
-in place; in fact, this is now discouraged. It is entirely
-configurable with the following git config variables:
-
-ciabot.project = name of the project
-ciabot.repo = name of the project repo for gitweb/cgit purposes
-ciabot.xmlrpc  = if true, ship notifications via XML-RPC
-ciabot.revformat = format in which the revision is shown
-
-The revformat variable may have the following values
-raw -> full hex ID of commit
-short -> first 12 chars of hex ID
-describe -> describe relative to last tag, falling back to short
-
-ciabot.project defaults to the directory name of the repository toplevel.
-ciabot.repo defaults to ciabot.project lowercased.
-ciabot.xmlrpc defaults to True
-ciabot.revformat defaults to 'describe'.
-
-This means that in the normal case you need not do any configuration at all,
-however setting ciabot.project will allow the hook to run slightly faster.
-
-Once you've set these variables, try your script with -n to see the
-notification message dumped to stdout and verify that it looks sane.
-
-To live-test these scripts, your project needs to have been registered with
-the CIA site.  Here are the steps:
-
-1. Open an IRC window on irc://freenode/commits or your registered
-   project IRC channel.
-
-2. Run ciabot.py and/or ciabot.sh from any directory under git
-   control.
-
-You should see a notification on the channel for your most recent commit.
-
-After verifying correct function, install one of these scripts either
-in a post-commit hook or in an update hook.
-
-In post-commit, run it without arguments. It will query for
-current HEAD and the latest commit ID to get the information it
-needs.
-
-In update, call it with a refname followed by a list of commits:
-You want to reverse the order git rev-list emits because it lists
-from most recent to oldest.
-
-/path/to/ciabot.py ${refname} $(git rev-list ${oldhead}..${newhead} | tac)
diff --git a/contrib/ciabot/README b/contrib/ciabot/README
deleted file mode 100644 (file)
index 2dfe1f9..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-These are hook scripts for the CIA notification service at <http://cia.vc/>
-
-They are maintained by Eric S. Raymond <esr@thyrsus.com>.  There is an
-upstream resource page for them at <http://www.catb.org/esr/ciabot/>,
-but they are unlikely to change rapidly.
-
-You probably want the Python version; it's faster, more capable, and
-better documented.  The shell version is maintained only as a fallback
-for use on hosting sites that don't permit Python hook scripts.
-
-See the file INSTALL for installation instructions.
diff --git a/contrib/ciabot/ciabot.py b/contrib/ciabot/ciabot.py
deleted file mode 100755 (executable)
index befa0c3..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2010 Eric S. Raymond <esr@thyrsus.com>
-# Distributed under BSD terms.
-#
-# This script contains porcelain and porcelain byproducts.
-# It's Python because the Python standard libraries avoid portability/security
-# issues raised by callouts in the ancestral Perl and sh scripts.  It should
-# be compatible back to Python 2.1.5
-#
-# usage: ciabot.py [-V] [-n] [-p projectname]  [refname [commits...]]
-#
-# This script is meant to be run either in a post-commit hook or in an
-# update hook. Try it with -n to see the notification mail dumped to
-# stdout and verify that it looks sane. With -V it dumps its version
-# and exits.
-#
-# In post-commit, run it without arguments. It will query for
-# current HEAD and the latest commit ID to get the information it
-# needs.
-#
-# In update, call it with a refname followed by a list of commits:
-# You want to reverse the order git rev-list emits because it lists
-# from most recent to oldest.
-#
-# /path/to/ciabot.py ${refname} $(git rev-list ${oldhead}..${newhead} | tac)
-#
-# Configuration variables affecting this script:
-#
-# ciabot.project = name of the project
-# ciabot.repo = name of the project repo for gitweb/cgit purposes
-# ciabot.xmlrpc  = if true (default), ship notifications via XML-RPC
-# ciabot.revformat = format in which the revision is shown
-#
-# ciabot.project defaults to the directory name of the repository toplevel.
-# ciabot.repo defaults to ciabot.project lowercased.
-#
-# This means that in the normal case you need not do any configuration at all,
-# but setting the project name will speed it up slightly.
-#
-# The revformat variable may have the following values
-# raw -> full hex ID of commit
-# short -> first 12 chars of hex ID
-# describe = -> describe relative to last tag, falling back to short
-# The default is 'describe'.
-#
-# Note: the CIA project now says only XML-RPC is reliable, so
-# we default to that.
-#
-
-import sys
-if sys.hexversion < 0x02000000:
-        # The limiter is the xml.sax module
-        sys.stderr.write("ciabot.py: requires Python 2.0.0 or later.\n")
-        sys.exit(1)
-
-import os, commands, socket, urllib
-from xml.sax.saxutils import escape
-
-# Changeset URL prefix for your repo: when the commit ID is appended
-# to this, it should point at a CGI that will display the commit
-# through gitweb or something similar. The defaults will probably
-# work if you have a typical gitweb/cgit setup.
-#
-#urlprefix="http://%(host)s/cgi-bin/gitweb.cgi?p=%(repo)s;a=commit;h="
-urlprefix="http://%(host)s/cgi-bin/cgit.cgi/%(repo)s/commit/?id="
-
-# The service used to turn your gitwebbish URL into a tinyurl so it
-# will take up less space on the IRC notification line.
-tinyifier = "http://tinyurl.com/api-create.php?url="
-
-# The template used to generate the XML messages to CIA.  You can make
-# visible changes to the IRC-bot notification lines by hacking this.
-# The default will produce a notification line that looks like this:
-#
-# ${project}: ${author} ${repo}:${branch} * ${rev} ${files}: ${logmsg} ${url}
-#
-# By omitting $files you can collapse the files part to a single slash.
-xml = '''\
-<message>
-  <generator>
-    <name>CIA Python client for Git</name>
-    <version>%(version)s</version>
-    <url>%(generator)s</url>
-  </generator>
-  <source>
-    <project>%(project)s</project>
-    <branch>%(repo)s:%(branch)s</branch>
-  </source>
-  <timestamp>%(ts)s</timestamp>
-  <body>
-    <commit>
-      <author>%(author)s</author>
-      <revision>%(rev)s</revision>
-      <files>
-        %(files)s
-      </files>
-      <log>%(logmsg)s %(url)s</log>
-      <url>%(url)s</url>
-    </commit>
-  </body>
-</message>
-'''
-
-#
-# No user-serviceable parts below this line:
-#
-
-# Where to ship e-mail notifications.
-toaddr = "cia@cia.vc"
-
-# Identify the generator script.
-# Should only change when the script itself gets a new home and maintainer.
-generator = "http://www.catb.org/~esr/ciabot.py"
-version = "3.6"
-
-def do(command):
-    return commands.getstatusoutput(command)[1]
-
-def report(refname, merged, xmlrpc=True):
-    "Generate a commit notification to be reported to CIA"
-
-    # Try to tinyfy a reference to a web view for this commit.
-    try:
-        url = open(urllib.urlretrieve(tinyifier + urlprefix + merged)[0]).read()
-    except:
-        url = urlprefix + merged
-
-    branch = os.path.basename(refname)
-
-    # Compute a description for the revision
-    if revformat == 'raw':
-        rev = merged
-    elif revformat == 'short':
-        rev = ''
-    else: # revformat == 'describe'
-        rev = do("git describe %s 2>/dev/null" % merged)
-    if not rev:
-        rev = merged[:12]
-
-    # Extract the meta-information for the commit
-    files=do("git diff-tree -r --name-only '"+ merged +"' | sed -e '1d' -e 's-.*-<file>&</file>-'")
-    metainfo = do("git log -1 '--pretty=format:%an <%ae>%n%at%n%s' " + merged)
-    (author, ts, logmsg) = metainfo.split("\n")
-    logmsg = escape(logmsg)
-
-    # This discards the part of the author's address after @.
-    # Might be be nice to ship the full email address, if not
-    # for spammers' address harvesters - getting this wrong
-    # would make the freenode #commits channel into harvester heaven.
-    author = escape(author.replace("<", "").split("@")[0].split()[-1])
-
-    # This ignores the timezone.  Not clear what to do with it...
-    ts = ts.strip().split()[0]
-
-    context = locals()
-    context.update(globals())
-
-    out = xml % context
-    mail = '''\
-Message-ID: <%(merged)s.%(author)s@%(project)s>
-From: %(fromaddr)s
-To: %(toaddr)s
-Content-type: text/xml
-Subject: DeliverXML
-
-%(out)s''' % locals()
-
-    if xmlrpc:
-        return out
-    else:
-        return mail
-
-if __name__ == "__main__":
-    import getopt
-
-    # Get all config variables
-    revformat = do("git config --get ciabot.revformat")
-    project = do("git config --get ciabot.project")
-    repo = do("git config --get ciabot.repo")
-    xmlrpc = do("git config --get ciabot.xmlrpc")
-    xmlrpc = not (xmlrpc and xmlrpc == "false")
-
-    host = socket.getfqdn()
-    fromaddr = "CIABOT-NOREPLY@" + host
-
-    try:
-        (options, arguments) = getopt.getopt(sys.argv[1:], "np:xV")
-    except getopt.GetoptError, msg:
-        print "ciabot.py: " + str(msg)
-        raise SystemExit, 1
-
-    notify = True
-    for (switch, val) in options:
-        if switch == '-p':
-            project = val
-        elif switch == '-n':
-            notify = False
-        elif switch == '-x':
-            xmlrpc = True
-        elif switch == '-V':
-            print "ciabot.py: version", version
-            sys.exit(0)
-
-    # The project variable defaults to the name of the repository toplevel.
-    if not project:
-        here = os.getcwd()
-        while True:
-            if os.path.exists(os.path.join(here, ".git")):
-                project = os.path.basename(here)
-                break
-            elif here == '/':
-                sys.stderr.write("ciabot.py: no .git below root!\n")
-                sys.exit(1)
-            here = os.path.dirname(here)
-
-    if not repo:
-        repo = project.lower()
-
-    urlprefix = urlprefix % globals()
-
-    # The script wants a reference to head followed by the list of
-    # commit ID to report about.
-    if len(arguments) == 0:
-        refname = do("git symbolic-ref HEAD 2>/dev/null")
-        merges = [do("git rev-parse HEAD")]
-    else:
-        refname = arguments[0]
-        merges = arguments[1:]
-
-    if notify:
-        if xmlrpc:
-            import xmlrpclib
-            server = xmlrpclib.Server('http://cia.vc/RPC2');
-        else:
-            import smtplib
-            server = smtplib.SMTP('localhost')
-
-    for merged in merges:
-        message = report(refname, merged, xmlrpc)
-        if not notify:
-            print message
-        elif xmlrpc:
-            try:
-                # RPC server is flaky, this can fail due to timeout.
-                server.hub.deliver(message)
-            except socket.error, e:
-                sys.stderr.write("%s\n" % e)
-        else:
-            server.sendmail(fromaddr, [toaddr], message)
-
-    if notify:
-        if not xmlrpc:
-            server.quit()
-
-#End
diff --git a/contrib/ciabot/ciabot.sh b/contrib/ciabot/ciabot.sh
deleted file mode 100755 (executable)
index dfb71a1..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-#!/bin/sh
-# Distributed under the terms of the GNU General Public License v2
-# Copyright (c) 2006 Fernando J. Pereda <ferdy@gentoo.org>
-# Copyright (c) 2008 Natanael Copa <natanael.copa@gmail.com>
-# Copyright (c) 2010 Eric S. Raymond <esr@thyrsus.com>
-# Assistance and review by Petr Baudis, author of ciabot.pl,
-# is gratefully acknowledged.
-#
-# This is a version 3.x of ciabot.sh; use -V to find the exact
-# version.  Versions 1 and 2 were shipped in 2006 and 2008 and are not
-# version-stamped.  The version 2 maintainer has passed the baton.
-#
-# Note: This script should be considered obsolete.
-# There is a faster, better-documented rewrite in Python: find it as ciabot.py
-# Use this only if your hosting site forbids Python hooks.
-# It requires: git(1), hostname(1), cut(1), sendmail(1), and wget(1).
-#
-# Originally based on Git ciabot.pl by Petr Baudis.
-# This script contains porcelain and porcelain byproducts.
-#
-# usage: ciabot.sh [-V] [-n] [-p projectname] [refname commit]
-#
-# This script is meant to be run either in a post-commit hook or in an
-# update hook. Try it with -n to see the notification mail dumped to
-# stdout and verify that it looks sane. With -V it dumps its version
-# and exits.
-#
-# In post-commit, run it without arguments. It will query for
-# current HEAD and the latest commit ID to get the information it
-# needs.
-#
-# In update, you have to call it once per merged commit:
-#
-#       refname=$1
-#       oldhead=$2
-#       newhead=$3
-#       for merged in $(git rev-list ${oldhead}..${newhead} | tac) ; do
-#               /path/to/ciabot.sh ${refname} ${merged}
-#       done
-#
-# The reason for the tac call is that git rev-list emits commits from
-# most recent to least - better to ship notifications from oldest to newest.
-#
-# Configuration variables affecting this script:
-#
-# ciabot.project = name of the project
-# ciabot.repo = name of the project repo for gitweb/cgit purposes
-# ciabot.revformat = format in which the revision is shown
-#
-# ciabot.project defaults to the directory name of the repository toplevel.
-# ciabot.repo defaults to ciabot.project lowercased.
-#
-# This means that in the normal case you need not do any configuration at all,
-# but setting the project name will speed it up slightly.
-#
-# The revformat variable may have the following values
-# raw -> full hex ID of commit
-# short -> first 12 chars of hex ID
-# describe = -> describe relative to last tag, falling back to short
-# The default is 'describe'.
-#
-# Note: the shell ancestors of this script used mail, not XML-RPC, in
-# order to avoid stalling until timeout when the CIA XML-RPC server is
-# down. It is unknown whether this is still an issue in 2010, but
-# XML-RPC would be annoying to do from sh in any case. (XML-RPC does
-# have the advantage that it guarantees notification of multiple commits
-# shipped from an update in their actual order.)
-#
-
-# The project as known to CIA. You can set this with a -p option,
-# or let it default to the directory name of the repo toplevel.
-project=$(git config --get ciabot.project)
-
-if [ -z $project ]
-then
-    here=`pwd`;
-    while :; do
-       if [ -d $here/.git ]
-       then
-           project=`basename $here`
-           break
-       elif [ $here = '/' ]
-       then
-           echo "ciabot.sh: no .git below root!"
-           exit 1
-       fi
-       here=`dirname $here`
-    done
-fi
-
-# Name of the repo for gitweb/cgit purposes
-repo=$(git config --get ciabot.repo)
-[ -z $repo] && repo=$(echo "${project}" | tr '[A-Z]' '[a-z]')
-
-# What revision format do we want in the summary?
-revformat=$(git config --get ciabot.revformat)
-
-# Fully qualified domain name of the repo host.  You can hardwire this
-# to make the script faster. The -f option works under Linux and FreeBSD,
-# but not OpenBSD and NetBSD. But under OpenBSD and NetBSD,
-# hostname without options gives the FQDN.
-if hostname -f >/dev/null 2>&1
-then
-    hostname=`hostname -f`
-else
-    hostname=`hostname`
-fi
-
-# Changeset URL prefix for your repo: when the commit ID is appended
-# to this, it should point at a CGI that will display the commit
-# through gitweb or something similar. The defaults will probably
-# work if you have a typical gitweb/cgit setup.
-#urlprefix="http://${host}/cgi-bin/gitweb.cgi?p=${repo};a=commit;h="
-urlprefix="http://${host}/cgi-bin/cgit.cgi/${repo}/commit/?id="
-
-#
-# You probably will not need to change the following:
-#
-
-# Identify the script. The 'generator' variable should change only
-# when the script itself gets a new home and maintainer.
-generator="http://www.catb.org/~esr/ciabot/ciabot.sh"
-version=3.5
-
-# Addresses for the e-mail
-from="CIABOT-NOREPLY@${hostname}"
-to="cia@cia.vc"
-
-# SMTP client to use - may need to edit the absolute pathname for your system
-sendmail="sendmail -t -f ${from}"
-
-#
-# No user-serviceable parts below this line:
-#
-
-# Should include all places sendmail is likely to lurk.
-PATH="$PATH:/usr/sbin/"
-
-mode=mailit
-while getopts pnV opt
-do
-    case $opt in
-       p) project=$2; shift ; shift ;;
-       n) mode=dumpit; shift ;;
-       V) echo "ciabot.sh: version $version"; exit 0; shift ;;
-    esac
-done
-
-# Cough and die if user has not specified a project
-if [ -z "$project" ]
-then
-    echo "ciabot.sh: no project specified, bailing out." >&2
-    exit 1
-fi
-
-if [ $# -eq 0 ] ; then
-       refname=$(git symbolic-ref HEAD 2>/dev/null)
-       merged=$(git rev-parse HEAD)
-else
-       refname=$1
-       merged=$2
-fi
-
-# This tries to turn your gitwebbish URL into a tinyurl so it will take up
-# less space on the IRC notification line. Some repo sites (I'm looking at
-# you, berlios.de!) forbid wget calls for security reasons.  On these,
-# the code will fall back to the full un-tinyfied URL.
-longurl=${urlprefix}${merged}
-url=$(wget -O - -q http://tinyurl.com/api-create.php?url=${longurl} 2>/dev/null)
-if [ -z "$url" ]; then
-       url="${longurl}"
-fi
-
-refname=${refname##refs/heads/}
-
-case $revformat in
-raw) rev=$merged ;;
-short) rev='' ;;
-*) rev=$(git describe ${merged} 2>/dev/null) ;;
-esac
-[ -z ${rev} ] && rev=$(echo "$merged" | cut -c 1-12)
-
-# We discard the part of the author's address after @.
-# Might be nice to ship the full email address, if not
-# for spammers' address harvesters - getting this wrong
-# would make the freenode #commits channel into harvester heaven.
-author=$(git log -1 '--pretty=format:%an <%ae>' $merged)
-author=$(echo "$author" | sed -n -e '/^.*<\([^@]*\).*$/s--\1-p')
-
-logmessage=$(git log -1 '--pretty=format:%s' $merged)
-ts=$(git log -1 '--pretty=format:%at' $merged)
-files=$(git diff-tree -r --name-only ${merged} | sed -e '1d' -e 's-.*-<file>&</file>-')
-
-out="
-<message>
-  <generator>
-    <name>CIA Shell client for Git</name>
-    <version>${version}</version>
-    <url>${generator}</url>
-  </generator>
-  <source>
-    <project>${project}</project>
-    <branch>$repo:${refname}</branch>
-  </source>
-  <timestamp>${ts}</timestamp>
-  <body>
-    <commit>
-      <author>${author}</author>
-      <revision>${rev}</revision>
-      <files>
-       ${files}
-      </files>
-      <log>${logmessage} ${url}</log>
-      <url>${url}</url>
-    </commit>
-  </body>
-</message>"
-
-if [ "$mode" = "dumpit" ]
-then
-    sendmail=cat
-fi
-
-${sendmail} << EOM
-Message-ID: <${merged}.${author}@${project}>
-From: ${from}
-To: ${to}
-Content-type: text/xml
-Subject: DeliverXML
-${out}
-EOM
-
-# vim: set tw=70 :
index e1b73130723a57e7f641236331699e67bb0d4d82..dba3c15700fae1ae8a7a43fd7a6ad7a5b9cbd5dd 100644 (file)
@@ -901,7 +901,7 @@ _git_add ()
        esac
 
        # XXX should we check for --update and --all options ?
-       __git_complete_index_file "--others --modified"
+       __git_complete_index_file "--others --modified --directory --no-empty-directory"
 }
 
 _git_archive ()
@@ -1063,7 +1063,7 @@ _git_clean ()
        esac
 
        # XXX should we check for -x option ?
-       __git_complete_index_file "--others"
+       __git_complete_index_file "--others --directory"
 }
 
 _git_clone ()
@@ -1188,7 +1188,7 @@ _git_diff ()
        __git_complete_revlist_file
 }
 
-__git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff
+__git_mergetools_common="diffuse diffmerge ecmerge emerge kdiff3 meld opendiff
                        tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3 codecompare
 "
 
index fb6429b64be3cf7011ce69950987a8b328e0e758..428cc1a9a1367e36c2739cb226a0ffdd2704ce82 100755 (executable)
@@ -181,6 +181,10 @@ if (@rev_args) {
        scan_rev_args(\%sources, \@rev_args)
 }
 
+my $toplevel = `git rev-parse --show-toplevel`;
+chomp $toplevel;
+chdir($toplevel) or die "chdir failure: $toplevel: $!\n";
+
 my %commits;
 blame_sources(\%sources, \%commits);
 import_commits(\%commits);
index 6c51c438858e8ac34c5c75c72fbd5cb7a4defd9d..1571a7b2693e50ac93828a76a01366da1e8a6983 100755 (executable)
@@ -369,7 +369,9 @@ sub find_netrc_entry {
        {
                my $entry_text = join ', ', map { "$_=$entry->{$_}" } keys %$entry;
                foreach my $check (sort keys %$query) {
-                       if (defined $query->{$check}) {
+                       if (!defined $entry->{$check}) {
+                               log_debug("OK: entry has no $check token, so any value satisfies check $check");
+                       } elsif (defined $query->{$check}) {
                                log_debug("compare %s [%s] to [%s] (entry: %s)",
                                          $check,
                                          $entry->{$check},
index 7b922c39480c8b78d0687cbabac59672f9ae6ede..a5e42a9f0124afcced9b639879f24916e0714e1c 100755 (executable)
@@ -263,7 +263,7 @@ 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
+# people might have misused the interface and used a commit-ish that
 # is the same as HEAD there instead.  Traditional format never would
 # have "-m" so it is an additional safety measure to check for it.
 
index 153115029df0764a3f42812a9a2bd8992360c4bd..8ee410f8435c8794ca7f4fabd8ebdead439891c1 100755 (executable)
@@ -242,6 +242,9 @@ generate_email_header()
        cat <<-EOF
        To: $recipients
        Subject: ${emailprefix}$projectdesc $refname_type $short_refname ${change_type}d. $describe
+       MIME-Version: 1.0
+       Content-Type: text/plain; charset=utf-8
+       Content-Transfer-Encoding: 8bit
        X-Git-Refname: $refname
        X-Git-Reftype: $refname_type
        X-Git-Oldrev: $oldrev
@@ -471,7 +474,7 @@ generate_delete_branch_email()
        echo "       was  $oldrev"
        echo ""
        echo $LOGBEGIN
-       git show -s --pretty=oneline $oldrev
+       git diff-tree -s --always --encoding=UTF-8 --pretty=oneline $oldrev
        echo $LOGEND
 }
 
@@ -547,11 +550,11 @@ generate_atag_email()
                # performed on them
                if [ -n "$prevtag" ]; then
                        # Show changes since the previous release
-                       git rev-list --pretty=short "$prevtag..$newrev" | git shortlog
+                       git shortlog "$prevtag..$newrev"
                else
                        # No previous tag, show all the changes since time
                        # began
-                       git rev-list --pretty=short $newrev | git shortlog
+                       git shortlog $newrev
                fi
                ;;
        *)
@@ -571,7 +574,7 @@ generate_delete_atag_email()
        echo "       was  $oldrev"
        echo ""
        echo $LOGBEGIN
-       git show -s --pretty=oneline $oldrev
+       git diff-tree -s --always --encoding=UTF-8 --pretty=oneline $oldrev
        echo $LOGEND
 }
 
@@ -617,7 +620,7 @@ generate_general_email()
        echo ""
        if [ "$newrev_type" = "commit" ]; then
                echo $LOGBEGIN
-               git show --no-color --root -s --pretty=medium $newrev
+               git diff-tree -s --always --encoding=UTF-8 --pretty=medium $newrev
                echo $LOGEND
        else
                # What can we do here?  The tag marks an object that is not
@@ -636,7 +639,7 @@ generate_delete_general_email()
        echo "       was  $oldrev"
        echo ""
        echo $LOGBEGIN
-       git show -s --pretty=oneline $oldrev
+       git diff-tree -s --always --encoding=UTF-8 --pretty=oneline $oldrev
        echo $LOGEND
 }
 
index 76fcd4defcc3ac751aa0c85b6388f6d408b476ca..f206f9655b4c078c66cb885fd079c4a7b95f7949 100644 (file)
@@ -24,6 +24,11 @@ INSTLIBDIR=$(shell $(MAKE) -C $(GIT_ROOT_DIR)/perl \
 
 all: build
 
+test: all
+       $(MAKE) -C t
+
+check: perlcritic test
+
 install_pm:
        install $(GIT_MEDIAWIKI_PM) $(INSTLIBDIR)/$(GIT_MEDIAWIKI_PM)
 
@@ -41,4 +46,7 @@ clean:
        rm $(INSTLIBDIR)/$(GIT_MEDIAWIKI_PM)
 
 perlcritic:
-       perlcritic -2 *.perl
+       perlcritic -5 $(SCRIPT_PERL)
+       -perlcritic -2 $(SCRIPT_PERL)
+
+.PHONY: all test check install_pm install clean perlcritic
index f8d7d2ca6c0926912200ddcadf8359c1b9bfef44..476e0a2bc02d0708e01c63f6e0fc524a840d4c77 100755 (executable)
@@ -590,6 +590,9 @@ sub mw_capabilities {
        print {*STDOUT} "import\n";
        print {*STDOUT} "list\n";
        print {*STDOUT} "push\n";
+       if ($dumb_push) {
+               print {*STDOUT} "no-private-update\n";
+       }
        print {*STDOUT} "\n";
        return;
 }
@@ -622,6 +625,9 @@ sub fetch_mw_revisions_for_page {
                rvstartid => $fetch_from,
                rvlimit => 500,
                pageids => $id,
+
+               # Let MediaWiki know that we support the latest API.
+               continue => '',
        };
 
        my $revnum = 0;
@@ -637,8 +643,15 @@ sub fetch_mw_revisions_for_page {
                        push(@page_revs, $page_rev_ids);
                        $revnum++;
                }
-               last if (!$result->{'query-continue'});
-               $query->{rvstartid} = $result->{'query-continue'}->{revisions}->{rvstartid};
+
+               if ($result->{'query-continue'}) { # For legacy APIs
+                       $query->{rvstartid} = $result->{'query-continue'}->{revisions}->{rvstartid};
+               } elsif ($result->{continue}) { # For newer APIs
+                       $query->{rvstartid} = $result->{continue}->{rvcontinue};
+                       $query->{continue} = $result->{continue}->{continue};
+               } else {
+                       last;
+               }
        }
        if ($shallow_import && @page_revs) {
                print {*STDERR} "  Found 1 revision (shallow import).\n";
@@ -1211,7 +1224,6 @@ sub mw_push_revision {
                }
                if (!$dumb_push) {
                        run_git(qq(notes --ref=${remotename}/mediawiki add -f -m "mediawiki_revision: ${mw_revision}" ${sha1_commit}));
-                       run_git(qq(update-ref -m "Git-MediaWiki push" refs/mediawiki/${remotename}/master ${sha1_commit} ${sha1_child}));
                }
        }
 
diff --git a/contrib/mw-to-git/t/t9365-continuing-queries.sh b/contrib/mw-to-git/t/t9365-continuing-queries.sh
new file mode 100755 (executable)
index 0000000..27e267f
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+test_description='Test the Git Mediawiki remote helper: queries w/ more than 500 results'
+
+. ./test-gitmw-lib.sh
+. $TEST_DIRECTORY/test-lib.sh
+
+test_check_precond
+
+test_expect_success 'creating page w/ >500 revisions' '
+       wiki_reset &&
+       for i in `test_seq 501`
+       do
+               echo "creating revision $i" &&
+               wiki_editpage foo "revision $i<br/>" true
+       done
+'
+
+test_expect_success 'cloning page w/ >500 revisions' '
+       git clone mediawiki::'"$WIKI_URL"' mw_dir
+'
+
+test_done
index 1e0044b69fc5c87ec03833b6fb1bf434a9e0acc0..054161ae21b0c884d314c984992a6c7aa8276a96 100755 (executable)
 # or
 # % git clone bzr::lp:myrepo
 #
-# If you want to specify which branches you want track (per repo):
-# git config remote-bzr.branches 'trunk, devel, test'
+# If you want to specify which branches you want to track (per repo):
+# % git config remote.origin.bzr-branches 'trunk, devel, test'
+#
+# Where 'origin' is the name of the repository you want to specify the
+# branches.
 #
 
 import sys
@@ -168,17 +171,16 @@ class Parser:
         if not m:
             return None
         _, name, email, date, tz = m.groups()
+        name = name.decode('utf-8')
         committer = '%s <%s>' % (name, email)
         tz = int(tz)
         tz = ((tz / 100) * 3600) + ((tz % 100) * 60)
         return (committer, int(date), tz)
 
 def rev_to_mark(rev):
-    global marks
     return marks.from_rev(rev)
 
 def mark_to_rev(mark):
-    global marks
     return marks.to_rev(mark)
 
 def fixup_user(user):
@@ -233,8 +235,6 @@ def get_filechanges(cur, prev):
     return modified, removed
 
 def export_files(tree, files):
-    global marks, filenodes
-
     final = []
     for path, fid in files.iteritems():
         kind = tree.kind(fid)
@@ -276,8 +276,6 @@ def export_files(tree, files):
     return final
 
 def export_branch(repo, name):
-    global prefix
-
     ref = '%s/heads/%s' % (prefix, name)
     tip = marks.get_tip(name)
 
@@ -378,16 +376,12 @@ def export_branch(repo, name):
     marks.set_tip(name, revid)
 
 def export_tag(repo, name):
-    global tags, prefix
-
     ref = '%s/tags/%s' % (prefix, name)
     print "reset %s" % ref
     print "from :%u" % rev_to_mark(tags[name])
     print
 
 def do_import(parser):
-    global dirname
-
     repo = parser.repo
     path = os.path.join(dirname, 'marks-git')
 
@@ -413,8 +407,6 @@ def do_import(parser):
     sys.stdout.flush()
 
 def parse_blob(parser):
-    global blob_marks
-
     parser.next()
     mark = parser.get_mark()
     parser.next()
@@ -425,8 +417,6 @@ def parse_blob(parser):
 class CustomTree():
 
     def __init__(self, branch, revid, parents, files):
-        global files_cache
-
         self.updates = {}
         self.branch = branch
 
@@ -484,7 +474,7 @@ class CustomTree():
             add_entry(fid, dirname, 'directory')
             return fid
 
-        def add_entry(fid, path, kind, mode = None):
+        def add_entry(fid, path, kind, mode=None):
             dirname, basename = os.path.split(path)
             parent_fid = get_parent(dirname, basename)
 
@@ -505,7 +495,7 @@ class CustomTree():
             self.files[path] = [change[0], None]
             changes.append(change)
 
-        def update_entry(fid, path, kind, mode = None):
+        def update_entry(fid, path, kind, mode=None):
             dirname, basename = os.path.split(path)
             parent_fid = get_parent(dirname, basename)
 
@@ -583,9 +573,6 @@ def c_style_unescape(string):
     return string
 
 def parse_commit(parser):
-    global marks, blob_marks, parsed_refs
-    global mode
-
     parents = []
 
     ref = parser[1]
@@ -657,8 +644,6 @@ def parse_commit(parser):
     marks.new_mark(revid, commit_mark)
 
 def parse_reset(parser):
-    global parsed_refs
-
     ref = parser[1]
     parser.next()
 
@@ -674,8 +659,6 @@ def parse_reset(parser):
     parsed_refs[ref] = mark_to_rev(from_mark)
 
 def do_export(parser):
-    global parsed_refs, dirname, transports
-
     parser.next()
 
     for line in parser.each_block('done'):
@@ -725,8 +708,6 @@ def do_export(parser):
     print
 
 def do_capabilities(parser):
-    global dirname
-
     print "import"
     print "export"
     print "refspec refs/heads/*:%s/heads/*" % prefix
@@ -744,8 +725,6 @@ def ref_is_valid(name):
     return not True in [c in name for c in '~^: \\']
 
 def do_list(parser):
-    global tags
-
     master_branch = None
 
     for name in branches:
@@ -770,7 +749,6 @@ def do_list(parser):
     print
 
 def clone(path, remote_branch):
-    global transports
     try:
         bdir = bzrlib.bzrdir.BzrDir.create(path, possible_transports=transports)
     except bzrlib.errors.AlreadyControlDirError:
@@ -780,8 +758,6 @@ def clone(path, remote_branch):
     return remote_branch.sprout(bdir, repository=repo)
 
 def get_remote_branch(name):
-    global dirname, branches, transports
-
     remote_branch = bzrlib.branch.Branch.open(branches[name],
                                               possible_transports=transports)
     if isinstance(remote_branch.user_transport, bzrlib.transport.local.LocalTransport):
@@ -825,8 +801,6 @@ def find_branches(repo):
             yield name, branch.base
 
 def get_repo(url, alias):
-    global dirname, peer, branches, transports
-
     normal_url = bzrlib.urlutils.normalize_url(url)
     origin = bzrlib.bzrdir.BzrDir.open(url, possible_transports=transports)
     is_local = isinstance(origin.transport, bzrlib.transport.local.LocalTransport)
@@ -858,9 +832,13 @@ def get_repo(url, alias):
             except bzrlib.errors.NoRepositoryPresent:
                 pass
 
-    wanted = get_config('remote-bzr.branches').rstrip().split(', ')
+    wanted = get_config('remote.%s.bzr-branches' % alias).rstrip().split(', ')
     # stupid python
     wanted = [e for e in wanted if e]
+    if not wanted:
+        wanted = get_config('remote-bzr.branches').rstrip().split(', ')
+        # stupid python
+        wanted = [e for e in wanted if e]
 
     if not wanted:
         try:
index c27603965ab6970dd71003603d6a77e637a22ab5..92d994e470f05db8536ba443a6afb192be8c2452 100755 (executable)
@@ -23,7 +23,11 @@ import subprocess
 import urllib
 import atexit
 import urlparse, hashlib
+import time as ptime
 
+#
+# If you want to see Mercurial revisions as Git commit notes:
+# git config core.notesRef refs/notes/hg
 #
 # If you are not in hg-git-compat mode and want to disable the tracking of
 # named branches:
@@ -126,6 +130,7 @@ class Marks:
         self.rev_marks = {}
         self.last_mark = 0
         self.version = 0
+        self.last_note = 0
 
     def load(self):
         if not os.path.exists(self.path):
@@ -137,6 +142,7 @@ class Marks:
         self.marks = tmp['marks']
         self.last_mark = tmp['last-mark']
         self.version = tmp.get('version', 1)
+        self.last_note = tmp.get('last-note', 0)
 
         for rev, mark in self.marks.iteritems():
             self.rev_marks[mark] = rev
@@ -150,7 +156,7 @@ class Marks:
         self.version = 2
 
     def dict(self):
-        return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark, 'version' : self.version }
+        return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark, 'version' : self.version, 'last-note' : self.last_note }
 
     def store(self):
         json.dump(self.dict(), open(self.path, 'w'))
@@ -227,8 +233,6 @@ class Parser:
         return sys.stdin.read(size)
 
     def get_author(self):
-        global bad_mail
-
         ex = None
         m = RAW_AUTHOR_RE.match(self.line)
         if not m:
@@ -261,8 +265,6 @@ def fix_file_path(path):
     return os.path.relpath(path, '/')
 
 def export_files(files):
-    global marks, filenodes
-
     final = []
     for f in files:
         fid = node.hex(f.filenode())
@@ -344,8 +346,6 @@ def fixup_user_hg(user):
     return (name, mail)
 
 def fixup_user(user):
-    global mode, bad_mail
-
     if mode == 'git':
         name, mail = fixup_user_git(user)
     else:
@@ -374,7 +374,7 @@ def updatebookmarks(repo, peer):
         bookmarks.write(repo)
 
 def get_repo(url, alias):
-    global dirname, peer
+    global peer
 
     myui = ui.ui()
     myui.setconfig('ui', 'interactive', 'off')
@@ -429,16 +429,12 @@ def get_repo(url, alias):
     return repo
 
 def rev_to_mark(rev):
-    global marks
     return marks.from_rev(rev.hex())
 
 def mark_to_rev(mark):
-    global marks
     return marks.to_rev(mark)
 
 def export_ref(repo, name, kind, head):
-    global prefix, marks, mode
-
     ename = '%s/%s' % (kind, name)
     try:
         tip = marks.get_tip(ename)
@@ -535,6 +531,31 @@ def export_ref(repo, name, kind, head):
     print "from :%u" % rev_to_mark(head)
     print
 
+    pending_revs = set(revs) - notes
+    if pending_revs:
+        note_mark = marks.next_mark()
+        ref = "refs/notes/hg"
+
+        print "commit %s" % ref
+        print "mark :%d" % (note_mark)
+        print "committer remote-hg <> %s" % (ptime.strftime('%s %z'))
+        desc = "Notes for %s\n" % (name)
+        print "data %d" % (len(desc))
+        print desc
+        if marks.last_note:
+            print "from :%u" % marks.last_note
+
+        for rev in pending_revs:
+            notes.add(rev)
+            c = repo[rev]
+            print "N inline :%u" % rev_to_mark(c)
+            msg = c.hex()
+            print "data %d" % (len(msg))
+            print msg
+        print
+
+        marks.last_note = note_mark
+
     marks.set_tip(ename, head.hex())
 
 def export_tag(repo, tag):
@@ -550,12 +571,9 @@ def export_branch(repo, branch):
     export_ref(repo, branch, 'branches', head)
 
 def export_head(repo):
-    global g_head
     export_ref(repo, g_head[0], 'bookmarks', g_head[1])
 
 def do_capabilities(parser):
-    global prefix, dirname
-
     print "import"
     print "export"
     print "refspec refs/heads/branches/*:%s/branches/*" % prefix
@@ -575,8 +593,6 @@ def branch_tip(branch):
     return branches[branch][-1]
 
 def get_branch_tip(repo, branch):
-    global branches
-
     heads = branches.get(hgref(branch), None)
     if not heads:
         return None
@@ -589,7 +605,7 @@ def get_branch_tip(repo, branch):
     return heads[0]
 
 def list_head(repo, cur):
-    global g_head, bmarks, fake_bmark
+    global g_head, fake_bmark
 
     if 'default' not in branches:
         # empty repo
@@ -605,8 +621,6 @@ def list_head(repo, cur):
     g_head = (head, node)
 
 def do_list(parser):
-    global branches, bmarks, track_branches
-
     repo = parser.repo
     for bmark, node in bookmarks.listbookmarks(repo).iteritems():
         bmarks[bmark] = repo[node]
@@ -674,8 +688,6 @@ def do_import(parser):
     print 'done'
 
 def parse_blob(parser):
-    global blob_marks
-
     parser.next()
     mark = parser.get_mark()
     parser.next()
@@ -692,9 +704,6 @@ def get_merge_files(repo, p1, p2, files):
             files[e] = f
 
 def parse_commit(parser):
-    global marks, blob_marks, parsed_refs
-    global mode
-
     from_mark = merge_mark = None
 
     ref = parser[1]
@@ -812,8 +821,6 @@ def parse_commit(parser):
     marks.new_mark(node, commit_mark)
 
 def parse_reset(parser):
-    global parsed_refs
-
     ref = parser[1]
     parser.next()
     # ugh
@@ -1006,8 +1013,6 @@ def check_tip(ref, kind, name, heads):
         return tip in heads
 
 def do_export(parser):
-    global parsed_refs, bmarks, peer
-
     p_bmarks = []
     p_revs = {}
 
@@ -1079,7 +1084,7 @@ def do_export(parser):
             author, msg = parsed_tags.get(tag, (None, None))
             if mode == 'git':
                 if not msg:
-                    msg = 'Added tag %s for changeset %s' % (tag, node[:12]);
+                    msg = 'Added tag %s for changeset %s' % (tag, node[:12])
                 tagnode, branch = write_tag(parser.repo, tag, node, msg, author)
                 p_revs[tagnode] = 'refs/heads/branches/' + gitref(branch)
             else:
@@ -1152,6 +1157,7 @@ def main(args):
     global filenodes
     global fake_bmark, hg_version
     global dry_run
+    global notes, alias
 
     alias = args[1]
     url = args[2]
@@ -1191,6 +1197,7 @@ def main(args):
     except:
         hg_version = None
     dry_run = False
+    notes = set()
 
     repo = get_repo(url, alias)
     prefix = 'refs/hg/%s' % alias
index dce281f91195cde4937b935910ec73f597bb826a..5c5025178370813aabec64c8bfbd7ac59c6186a5 100755 (executable)
@@ -7,19 +7,21 @@ test_description='Test remote-bzr'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PYTHON; then
+if ! test_have_prereq PYTHON
+then
        skip_all='skipping remote-bzr tests; python not available'
        test_done
 fi
 
-if ! python -c 'import bzrlib'; then
+if ! python -c 'import bzrlib'
+then
        skip_all='skipping remote-bzr tests; bzr not available'
        test_done
 fi
 
 check () {
-       echo $3 > expected &&
-       git --git-dir=$1/.git log --format='%s' -1 $2 > actual
+       echo $3 >expected &&
+       git --git-dir=$1/.git log --format='%s' -1 $2 >actual
        test_cmp expected actual
 }
 
@@ -29,7 +31,7 @@ test_expect_success 'cloning' '
        (
        bzr init bzrrepo &&
        cd bzrrepo &&
-       echo one > content &&
+       echo one >content &&
        bzr add content &&
        bzr commit -m one
        ) &&
@@ -41,7 +43,7 @@ test_expect_success 'cloning' '
 test_expect_success 'pulling' '
        (
        cd bzrrepo &&
-       echo two > content &&
+       echo two >content &&
        bzr commit -m two
        ) &&
 
@@ -53,13 +55,13 @@ test_expect_success 'pulling' '
 test_expect_success 'pushing' '
        (
        cd gitrepo &&
-       echo three > content &&
+       echo three >content &&
        git commit -a -m three &&
        git push
        ) &&
 
-       echo three > expected &&
-       cat bzrrepo/content > actual &&
+       echo three >expected &&
+       cat bzrrepo/content >actual &&
        test_cmp expected actual
 '
 
@@ -67,16 +69,16 @@ test_expect_success 'roundtrip' '
        (
        cd gitrepo &&
        git pull &&
-       git log --format="%s" -1 origin/master > actual
+       git log --format="%s" -1 origin/master >actual
        ) &&
-       echo three > expected &&
+       echo three >expected &&
        test_cmp expected actual &&
 
        (cd gitrepo && git push && git pull) &&
 
        (
        cd bzrrepo &&
-       echo four > content &&
+       echo four >content &&
        bzr commit -m four
        ) &&
 
@@ -86,19 +88,19 @@ test_expect_success 'roundtrip' '
 
        (
        cd gitrepo &&
-       echo five > content &&
+       echo five >content &&
        git commit -a -m five &&
        git push && git pull
        ) &&
 
        (cd bzrrepo && bzr revert) &&
 
-       echo five > expected &&
-       cat bzrrepo/content > actual &&
+       echo five >expected &&
+       cat bzrrepo/content >actual &&
        test_cmp expected actual
 '
 
-cat > expected <<EOF
+cat >expected <<\EOF
 100644 blob 54f9d6da5c91d556e6b54340b1327573073030af   content
 100755 blob 68769579c3eaadbe555379b9c3538e6628bae1eb   executable
 120000 blob 6b584e8ece562ebffc15d38808cd6b98fc3d97ea   link
@@ -107,7 +109,7 @@ EOF
 test_expect_success 'special modes' '
        (
        cd bzrrepo &&
-       echo exec > executable
+       echo exec >executable
        chmod +x executable &&
        bzr add executable
        bzr commit -m exec &&
@@ -122,21 +124,21 @@ test_expect_success 'special modes' '
        (
        cd gitrepo &&
        git pull
-       git ls-tree HEAD > ../actual
+       git ls-tree HEAD >../actual
        ) &&
 
        test_cmp expected actual &&
 
        (
        cd gitrepo &&
-       git cat-file -p HEAD:link > ../actual
+       git cat-file -p HEAD:link >../actual
        ) &&
 
-       printf content > expected &&
+       printf content >expected &&
        test_cmp expected actual
 '
 
-cat > expected <<EOF
+cat >expected <<\EOF
 100644 blob 54f9d6da5c91d556e6b54340b1327573073030af   content
 100755 blob 68769579c3eaadbe555379b9c3538e6628bae1eb   executable
 120000 blob 6b584e8ece562ebffc15d38808cd6b98fc3d97ea   link
@@ -147,8 +149,8 @@ test_expect_success 'moving directory' '
        (
        cd bzrrepo &&
        mkdir movedir &&
-       echo one > movedir/one &&
-       echo two > movedir/two &&
+       echo one >movedir/one &&
+       echo two >movedir/two &&
        bzr add movedir &&
        bzr commit -m movedir &&
        bzr mv movedir movedir-new &&
@@ -158,7 +160,7 @@ test_expect_success 'moving directory' '
        (
        cd gitrepo &&
        git pull &&
-       git ls-tree HEAD > ../actual
+       git ls-tree HEAD >../actual
        ) &&
 
        test_cmp expected actual
@@ -167,7 +169,7 @@ test_expect_success 'moving directory' '
 test_expect_success 'different authors' '
        (
        cd bzrrepo &&
-       echo john >> content &&
+       echo john >>content &&
        bzr commit -m john \
          --author "Jane Rey <jrey@example.com>" \
          --author "John Doe <jdoe@example.com>"
@@ -176,10 +178,10 @@ test_expect_success 'different authors' '
        (
        cd gitrepo &&
        git pull &&
-       git show --format="%an <%ae>, %cn <%ce>" --quiet > ../actual
+       git show --format="%an <%ae>, %cn <%ce>" --quiet >../actual
        ) &&
 
-       echo "Jane Rey <jrey@example.com>, A U Thor <author@example.com>" > expected &&
+       echo "Jane Rey <jrey@example.com>, A U Thor <author@example.com>" >expected &&
        test_cmp expected actual
 '
 
@@ -196,12 +198,12 @@ test_expect_success 'fetch utf-8 filenames' '
        bzr init bzrrepo &&
        cd bzrrepo &&
 
-       echo test >> "ærø" &&
+       echo test >>"ærø" &&
        bzr add "ærø" &&
-       echo test >> "ø~?" &&
+       echo test >>"ø~?" &&
        bzr add "ø~?" &&
        bzr commit -m add-utf-8 &&
-       echo test >> "ærø" &&
+       echo test >>"ærø" &&
        bzr commit -m test-utf-8 &&
        bzr rm "ø~?" &&
        bzr mv "ærø" "ø~?" &&
@@ -211,9 +213,9 @@ test_expect_success 'fetch utf-8 filenames' '
        (
        git clone "bzr::bzrrepo" gitrepo &&
        cd gitrepo &&
-       git -c core.quotepath=false ls-files > ../actual
+       git -c core.quotepath=false ls-files >../actual
        ) &&
-       echo "ø~?" > expected &&
+       echo "ø~?" >expected &&
        test_cmp expected actual
 '
 
@@ -229,7 +231,7 @@ test_expect_success 'push utf-8 filenames' '
        bzr init bzrrepo &&
        cd bzrrepo &&
 
-       echo one >> content &&
+       echo one >>content &&
        bzr add content &&
        bzr commit -m one
        ) &&
@@ -238,15 +240,15 @@ test_expect_success 'push utf-8 filenames' '
        git clone "bzr::bzrrepo" gitrepo &&
        cd gitrepo &&
 
-       echo test >> "ærø" &&
+       echo test >>"ærø" &&
        git add "ærø" &&
        git commit -m utf-8 &&
 
        git push
        ) &&
 
-       (cd bzrrepo && bzr ls > ../actual) &&
-       printf "content\nærø\n" > expected &&
+       (cd bzrrepo && bzr ls >../actual) &&
+       printf "content\nærø\n" >expected &&
        test_cmp expected actual
 '
 
@@ -256,7 +258,7 @@ test_expect_success 'pushing a merge' '
        (
        bzr init bzrrepo &&
        cd bzrrepo &&
-       echo one > content &&
+       echo one >content &&
        bzr add content &&
        bzr commit -m one
        ) &&
@@ -265,27 +267,27 @@ test_expect_success 'pushing a merge' '
 
        (
        cd bzrrepo &&
-       echo two > content &&
+       echo two >content &&
        bzr commit -m two
        ) &&
 
        (
        cd gitrepo &&
-       echo three > content &&
+       echo three >content &&
        git commit -a -m three &&
        git fetch &&
        git merge origin/master || true &&
-       echo three > content &&
+       echo three >content &&
        git commit -a --no-edit &&
        git push
        ) &&
 
-       echo three > expected &&
-       cat bzrrepo/content > actual &&
+       echo three >expected &&
+       cat bzrrepo/content >actual &&
        test_cmp expected actual
 '
 
-cat > expected <<EOF
+cat >expected <<\EOF
 origin/HEAD
 origin/branch
 origin/trunk
@@ -299,7 +301,7 @@ test_expect_success 'proper bzr repo' '
        (
        bzr init bzrrepo/trunk &&
        cd bzrrepo/trunk &&
-       echo one >> content &&
+       echo one >>content &&
        bzr add content &&
        bzr commit -m one
        ) &&
@@ -307,14 +309,14 @@ test_expect_success 'proper bzr repo' '
        (
        bzr branch bzrrepo/trunk bzrrepo/branch &&
        cd bzrrepo/branch &&
-       echo two >> content &&
+       echo two >>content &&
        bzr commit -m one
        ) &&
 
        (
        git clone "bzr::bzrrepo" gitrepo &&
        cd gitrepo &&
-       git for-each-ref --format "%(refname:short)" refs/remotes/origin > ../actual
+       git for-each-ref --format "%(refname:short)" refs/remotes/origin >../actual
        ) &&
 
        test_cmp expected actual
@@ -327,11 +329,11 @@ test_expect_success 'strip' '
        bzr init bzrrepo &&
        cd bzrrepo &&
 
-       echo one >> content &&
+       echo one >>content &&
        bzr add content &&
        bzr commit -m one &&
 
-       echo two >> content &&
+       echo two >>content &&
        bzr commit -m two
        ) &&
 
@@ -341,21 +343,51 @@ test_expect_success 'strip' '
        cd bzrrepo &&
        bzr uncommit --force &&
 
-       echo three >> content &&
+       echo three >>content &&
        bzr commit -m three &&
 
-       echo four >> content &&
+       echo four >>content &&
        bzr commit -m four &&
-       bzr log --line | sed -e "s/^[0-9][0-9]*: //" > ../expected
+       bzr log --line | sed -e "s/^[0-9][0-9]*: //" >../expected
        ) &&
 
        (
        cd gitrepo &&
        git fetch &&
-       git log --format="%an %ad %s" --date=short origin/master > ../actual
+       git log --format="%an %ad %s" --date=short origin/master >../actual
        ) &&
 
        test_cmp expected actual
 '
 
+test_expect_success 'export utf-8 authors' '
+       test_when_finished "rm -rf bzrrepo gitrepo && LC_ALL=C && unset GIT_COMMITTER_NAME" &&
+
+       LC_ALL=en_US.UTF-8
+       export LC_ALL
+
+       GIT_COMMITTER_NAME="Grégoire"
+       export GIT_COMMITTER_NAME
+
+       bzr init bzrrepo &&
+
+       (
+       git init gitrepo &&
+       cd gitrepo &&
+       echo greg >>content &&
+       git add content &&
+       git commit -m one &&
+       git remote add bzr "bzr::../bzrrepo" &&
+       git push bzr
+       ) &&
+
+       (
+       cd bzrrepo &&
+       bzr log | grep "^committer: " >../actual
+       ) &&
+
+       echo "committer: Grégoire <committer@example.com>" >expected &&
+       test_cmp expected actual
+'
+
 test_done
index f83d67d74fc97cb597388ab556d7a31e9d01835b..e24c51daad1038184bd6113ceee77c042dc26f17 100755 (executable)
@@ -10,12 +10,14 @@ test_description='Test bidirectionality of remote-hg'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PYTHON; then
+if ! test_have_prereq PYTHON
+then
        skip_all='skipping remote-hg tests; python not available'
        test_done
 fi
 
-if ! python -c 'import mercurial'; then
+if ! python -c 'import mercurial'
+then
        skip_all='skipping remote-hg tests; mercurial not available'
        test_done
 fi
@@ -43,7 +45,7 @@ hg_push () {
        git checkout -q -b tmp &&
        git fetch -q "hg::../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' &&
        git checkout -q @{-1} &&
-       git branch -q -D tmp 2> /dev/null || true
+       git branch -q -D tmp 2>/dev/null || true
        )
 }
 
@@ -62,7 +64,7 @@ setup () {
        echo "tag = -d \"0 0\""
        echo "[extensions]"
        echo "graphlog ="
-       ) >> "$HOME"/.hgrc &&
+       ) >>"$HOME"/.hgrc &&
        git config --global remote-hg.hg-git-compat true
        git config --global remote-hg.track-branches true
 
@@ -81,22 +83,22 @@ test_expect_success 'encoding' '
        git init -q gitrepo &&
        cd gitrepo &&
 
-       echo alpha > alpha &&
+       echo alpha >alpha &&
        git add alpha &&
        git commit -m "add älphà" &&
 
        GIT_AUTHOR_NAME="tést èncödîng" &&
        export GIT_AUTHOR_NAME &&
-       echo beta > beta &&
+       echo beta >beta &&
        git add beta &&
        git commit -m "add beta" &&
 
-       echo gamma > gamma &&
+       echo gamma >gamma &&
        git add gamma &&
        git commit -m "add gämmâ" &&
 
        : TODO git config i18n.commitencoding latin-1 &&
-       echo delta > delta &&
+       echo delta >delta &&
        git add delta &&
        git commit -m "add déltà"
        ) &&
@@ -105,8 +107,8 @@ test_expect_success 'encoding' '
        git_clone hgrepo gitrepo2 &&
        hg_clone gitrepo2 hgrepo2 &&
 
-       HGENCODING=utf-8 hg_log hgrepo > expected &&
-       HGENCODING=utf-8 hg_log hgrepo2 > actual &&
+       HGENCODING=utf-8 hg_log hgrepo >expected &&
+       HGENCODING=utf-8 hg_log hgrepo2 >actual &&
 
        test_cmp expected actual
 '
@@ -117,14 +119,14 @@ test_expect_success 'file removal' '
        (
        git init -q gitrepo &&
        cd gitrepo &&
-       echo alpha > alpha &&
+       echo alpha >alpha &&
        git add alpha &&
        git commit -m "add alpha" &&
-       echo beta > beta &&
+       echo beta >beta &&
        git add beta &&
        git commit -m "add beta"
        mkdir foo &&
-       echo blah > foo/bar &&
+       echo blah >foo/bar &&
        git add foo &&
        git commit -m "add foo" &&
        git rm alpha &&
@@ -137,8 +139,8 @@ test_expect_success 'file removal' '
        git_clone hgrepo gitrepo2 &&
        hg_clone gitrepo2 hgrepo2 &&
 
-       hg_log hgrepo > expected &&
-       hg_log hgrepo2 > actual &&
+       hg_log hgrepo >expected &&
+       hg_log hgrepo2 >actual &&
 
        test_cmp expected actual
 '
@@ -150,12 +152,12 @@ test_expect_success 'git tags' '
        git init -q gitrepo &&
        cd gitrepo &&
        git config receive.denyCurrentBranch ignore &&
-       echo alpha > alpha &&
+       echo alpha >alpha &&
        git add alpha &&
        git commit -m "add alpha" &&
        git tag alpha &&
 
-       echo beta > beta &&
+       echo beta >beta &&
        git add beta &&
        git commit -m "add beta" &&
        git tag -a -m "added tag beta" beta
@@ -165,8 +167,8 @@ test_expect_success 'git tags' '
        git_clone hgrepo gitrepo2 &&
        hg_clone gitrepo2 hgrepo2 &&
 
-       hg_log hgrepo > expected &&
-       hg_log hgrepo2 > actual &&
+       hg_log hgrepo >expected &&
+       hg_log hgrepo2 >actual &&
 
        test_cmp expected actual
 '
@@ -178,7 +180,7 @@ test_expect_success 'hg branch' '
        git init -q gitrepo &&
        cd gitrepo &&
 
-       echo alpha > alpha &&
+       echo alpha >alpha &&
        git add alpha &&
        git commit -q -m "add alpha" &&
        git checkout -q -b not-master
@@ -201,8 +203,8 @@ test_expect_success 'hg branch' '
        : Back to the common revision &&
        (cd hgrepo && hg checkout default) &&
 
-       hg_log hgrepo > expected &&
-       hg_log hgrepo2 > actual &&
+       hg_log hgrepo >expected &&
+       hg_log hgrepo2 >actual &&
 
        test_cmp expected actual
 '
@@ -214,7 +216,7 @@ test_expect_success 'hg tags' '
        git init -q gitrepo &&
        cd gitrepo &&
 
-       echo alpha > alpha &&
+       echo alpha >alpha &&
        git add alpha &&
        git commit -m "add alpha" &&
        git checkout -q -b not-master
@@ -231,8 +233,8 @@ test_expect_success 'hg tags' '
        hg_push hgrepo gitrepo &&
        hg_clone gitrepo hgrepo2 &&
 
-       hg_log hgrepo > expected &&
-       hg_log hgrepo2 > actual &&
+       hg_log hgrepo >expected &&
+       hg_log hgrepo2 >actual &&
 
        test_cmp expected actual
 '
index 2219284382f0e987423ae00e5bd89e9b7a4b0046..6dcd95d10f618ee3ac4920f5f2ae684c0b8d4d36 100755 (executable)
@@ -10,17 +10,20 @@ test_description='Test remote-hg output compared to hg-git'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PYTHON; then
+if ! test_have_prereq PYTHON
+then
        skip_all='skipping remote-hg tests; python not available'
        test_done
 fi
 
-if ! python -c 'import mercurial'; then
+if ! python -c 'import mercurial'
+then
        skip_all='skipping remote-hg tests; mercurial not available'
        test_done
 fi
 
-if ! python -c 'import hggit'; then
+if ! python -c 'import hggit'
+then
        skip_all='skipping remote-hg tests; hg-git not available'
        test_done
 fi
@@ -66,7 +69,7 @@ hg_push_git () {
        git fetch -q "hg::../$1" 'refs/tags/*:refs/tags/*' 'refs/heads/*:refs/heads/*' &&
        git branch -D default &&
        git checkout -q @{-1} &&
-       git branch -q -D tmp 2> /dev/null || true
+       git branch -q -D tmp 2>/dev/null || true
        )
 }
 
@@ -100,7 +103,7 @@ setup () {
        echo "hgext.bookmarks ="
        echo "hggit ="
        echo "graphlog ="
-       ) >> "$HOME"/.hgrc &&
+       ) >>"$HOME"/.hgrc &&
        git config --global receive.denycurrentbranch warn
        git config --global remote-hg.hg-git-compat true
        git config --global remote-hg.track-branches false
@@ -121,7 +124,7 @@ test_expect_success 'executable bit' '
        (
        git init -q gitrepo &&
        cd gitrepo &&
-       echo alpha > alpha &&
+       echo alpha >alpha &&
        chmod 0644 alpha &&
        git add alpha &&
        git commit -m "add alpha" &&
@@ -133,17 +136,18 @@ test_expect_success 'executable bit' '
        git commit -m "clear executable bit"
        ) &&
 
-       for x in hg git; do
+       for x in hg git
+       do
                (
                hg_clone_$x gitrepo hgrepo-$x &&
                cd hgrepo-$x &&
                hg_log . &&
                hg manifest -r 1 -v &&
                hg manifest -v
-               ) > output-$x &&
+               ) >"output-$x" &&
 
                git_clone_$x hgrepo-$x gitrepo2-$x &&
-               git_log gitrepo2-$x > log-$x
+               git_log gitrepo2-$x >"log-$x"
        done &&
 
        test_cmp output-hg output-git &&
@@ -156,7 +160,7 @@ test_expect_success 'symlink' '
        (
        git init -q gitrepo &&
        cd gitrepo &&
-       echo alpha > alpha &&
+       echo alpha >alpha &&
        git add alpha &&
        git commit -m "add alpha" &&
        ln -s alpha beta &&
@@ -164,16 +168,17 @@ test_expect_success 'symlink' '
        git commit -m "add beta"
        ) &&
 
-       for x in hg git; do
+       for x in hg git
+       do
                (
                hg_clone_$x gitrepo hgrepo-$x &&
                cd hgrepo-$x &&
                hg_log . &&
                hg manifest -v
-               ) > output-$x &&
+               ) >"output-$x" &&
 
                git_clone_$x hgrepo-$x gitrepo2-$x &&
-               git_log gitrepo2-$x > log-$x
+               git_log gitrepo2-$x >"log-$x"
        done &&
 
        test_cmp output-hg output-git &&
@@ -186,28 +191,29 @@ test_expect_success 'merge conflict 1' '
        (
        hg init hgrepo1 &&
        cd hgrepo1 &&
-       echo A > afile &&
+       echo A >afile &&
        hg add afile &&
        hg ci -m "origin" &&
 
-       echo B > afile &&
+       echo B >afile &&
        hg ci -m "A->B" &&
 
        hg up -r0 &&
-       echo C > afile &&
+       echo C >afile &&
        hg ci -m "A->C" &&
 
        hg merge -r1 &&
-       echo C > afile &&
+       echo C >afile &&
        hg resolve -m afile &&
        hg ci -m "merge to C"
        ) &&
 
-       for x in hg git; do
+       for x in hg git
+       do
                git_clone_$x hgrepo1 gitrepo-$x &&
                hg_clone_$x gitrepo-$x hgrepo2-$x &&
-               hg_log hgrepo2-$x > hg-log-$x &&
-               git_log gitrepo-$x > git-log-$x
+               hg_log hgrepo2-$x >"hg-log-$x" &&
+               git_log gitrepo-$x >"git-log-$x"
        done &&
 
        test_cmp hg-log-hg hg-log-git &&
@@ -220,28 +226,29 @@ test_expect_success 'merge conflict 2' '
        (
        hg init hgrepo1 &&
        cd hgrepo1 &&
-       echo A > afile &&
+       echo A >afile &&
        hg add afile &&
        hg ci -m "origin" &&
 
-       echo B > afile &&
+       echo B >afile &&
        hg ci -m "A->B" &&
 
        hg up -r0 &&
-       echo C > afile &&
+       echo C >afile &&
        hg ci -m "A->C" &&
 
        hg merge -r1 || true &&
-       echo B > afile &&
+       echo B >afile &&
        hg resolve -m afile &&
        hg ci -m "merge to B"
        ) &&
 
-       for x in hg git; do
+       for x in hg git
+       do
                git_clone_$x hgrepo1 gitrepo-$x &&
                hg_clone_$x gitrepo-$x hgrepo2-$x &&
-               hg_log hgrepo2-$x > hg-log-$x &&
-               git_log gitrepo-$x > git-log-$x
+               hg_log hgrepo2-$x >"hg-log-$x" &&
+               git_log gitrepo-$x >"git-log-$x"
        done &&
 
        test_cmp hg-log-hg hg-log-git &&
@@ -254,29 +261,30 @@ test_expect_success 'converged merge' '
        (
        hg init hgrepo1 &&
        cd hgrepo1 &&
-       echo A > afile &&
+       echo A >afile &&
        hg add afile &&
        hg ci -m "origin" &&
 
-       echo B > afile &&
+       echo B >afile &&
        hg ci -m "A->B" &&
 
-       echo C > afile &&
+       echo C >afile &&
        hg ci -m "B->C" &&
 
        hg up -r0 &&
-       echo C > afile &&
+       echo C >afile &&
        hg ci -m "A->C" &&
 
        hg merge -r2 || true &&
        hg ci -m "merge"
        ) &&
 
-       for x in hg git; do
+       for x in hg git
+       do
                git_clone_$x hgrepo1 gitrepo-$x &&
                hg_clone_$x gitrepo-$x hgrepo2-$x &&
-               hg_log hgrepo2-$x > hg-log-$x &&
-               git_log gitrepo-$x > git-log-$x
+               hg_log hgrepo2-$x >"hg-log-$x" &&
+               git_log gitrepo-$x >"git-log-$x"
        done &&
 
        test_cmp hg-log-hg hg-log-git &&
@@ -290,32 +298,33 @@ test_expect_success 'encoding' '
        git init -q gitrepo &&
        cd gitrepo &&
 
-       echo alpha > alpha &&
+       echo alpha >alpha &&
        git add alpha &&
        git commit -m "add älphà" &&
 
        GIT_AUTHOR_NAME="tést èncödîng" &&
        export GIT_AUTHOR_NAME &&
-       echo beta > beta &&
+       echo beta >beta &&
        git add beta &&
        git commit -m "add beta" &&
 
-       echo gamma > gamma &&
+       echo gamma >gamma &&
        git add gamma &&
        git commit -m "add gämmâ" &&
 
        : TODO git config i18n.commitencoding latin-1 &&
-       echo delta > delta &&
+       echo delta >delta &&
        git add delta &&
        git commit -m "add déltà"
        ) &&
 
-       for x in hg git; do
+       for x in hg git
+       do
                hg_clone_$x gitrepo hgrepo-$x &&
                git_clone_$x hgrepo-$x gitrepo2-$x &&
 
-               HGENCODING=utf-8 hg_log hgrepo-$x > hg-log-$x &&
-               git_log gitrepo2-$x > git-log-$x
+               HGENCODING=utf-8 hg_log hgrepo-$x >"hg-log-$x" &&
+               git_log gitrepo2-$x >"git-log-$x"
        done &&
 
        test_cmp hg-log-hg hg-log-git &&
@@ -328,14 +337,14 @@ test_expect_success 'file removal' '
        (
        git init -q gitrepo &&
        cd gitrepo &&
-       echo alpha > alpha &&
+       echo alpha >alpha &&
        git add alpha &&
        git commit -m "add alpha" &&
-       echo beta > beta &&
+       echo beta >beta &&
        git add beta &&
        git commit -m "add beta"
        mkdir foo &&
-       echo blah > foo/bar &&
+       echo blah >foo/bar &&
        git add foo &&
        git commit -m "add foo" &&
        git rm alpha &&
@@ -344,17 +353,18 @@ test_expect_success 'file removal' '
        git commit -m "remove foo/bar"
        ) &&
 
-       for x in hg git; do
+       for x in hg git
+       do
                (
                hg_clone_$x gitrepo hgrepo-$x &&
                cd hgrepo-$x &&
                hg_log . &&
                hg manifest -r 3 &&
                hg manifest
-               ) > output-$x &&
+               ) >"output-$x" &&
 
                git_clone_$x hgrepo-$x gitrepo2-$x &&
-               git_log gitrepo2-$x > log-$x
+               git_log gitrepo2-$x >"log-$x"
        done &&
 
        test_cmp output-hg output-git &&
@@ -368,20 +378,21 @@ test_expect_success 'git tags' '
        git init -q gitrepo &&
        cd gitrepo &&
        git config receive.denyCurrentBranch ignore &&
-       echo alpha > alpha &&
+       echo alpha >alpha &&
        git add alpha &&
        git commit -m "add alpha" &&
        git tag alpha &&
 
-       echo beta > beta &&
+       echo beta >beta &&
        git add beta &&
        git commit -m "add beta" &&
        git tag -a -m "added tag beta" beta
        ) &&
 
-       for x in hg git; do
+       for x in hg git
+       do
                hg_clone_$x gitrepo hgrepo-$x &&
-               hg_log hgrepo-$x > log-$x
+               hg_log hgrepo-$x >"log-$x"
        done &&
 
        test_cmp log-hg log-git
@@ -390,12 +401,13 @@ test_expect_success 'git tags' '
 test_expect_success 'hg author' '
        test_when_finished "rm -rf gitrepo* hgrepo*" &&
 
-       for x in hg git; do
+       for x in hg git
+       do
                (
                git init -q gitrepo-$x &&
                cd gitrepo-$x &&
 
-               echo alpha > alpha &&
+               echo alpha >alpha &&
                git add alpha &&
                git commit -m "add alpha" &&
                git checkout -q -b not-master
@@ -406,38 +418,38 @@ test_expect_success 'hg author' '
                cd hgrepo-$x &&
 
                hg co master &&
-               echo beta > beta &&
+               echo beta >beta &&
                hg add beta &&
                hg commit -u "test" -m "add beta" &&
 
-               echo gamma >> beta &&
+               echo gamma >>beta &&
                hg commit -u "test <test@example.com> (comment)" -m "modify beta" &&
 
-               echo gamma > gamma &&
+               echo gamma >gamma &&
                hg add gamma &&
                hg commit -u "<test@example.com>" -m "add gamma" &&
 
-               echo delta > delta &&
+               echo delta >delta &&
                hg add delta &&
                hg commit -u "name<test@example.com>" -m "add delta" &&
 
-               echo epsilon > epsilon &&
+               echo epsilon >epsilon &&
                hg add epsilon &&
                hg commit -u "name <test@example.com" -m "add epsilon" &&
 
-               echo zeta > zeta &&
+               echo zeta >zeta &&
                hg add zeta &&
                hg commit -u " test " -m "add zeta" &&
 
-               echo eta > eta &&
+               echo eta >eta &&
                hg add eta &&
                hg commit -u "test < test@example.com >" -m "add eta" &&
 
-               echo theta > theta &&
+               echo theta >theta &&
                hg add theta &&
                hg commit -u "test >test@example.com>" -m "add theta" &&
 
-               echo iota > iota &&
+               echo iota >iota &&
                hg add iota &&
                hg commit -u "test <test <at> example <dot> com>" -m "add iota"
                ) &&
@@ -445,8 +457,8 @@ test_expect_success 'hg author' '
                hg_push_$x hgrepo-$x gitrepo-$x &&
                hg_clone_$x gitrepo-$x hgrepo2-$x &&
 
-               hg_log hgrepo2-$x > hg-log-$x &&
-               git_log gitrepo-$x > git-log-$x
+               hg_log hgrepo2-$x >"hg-log-$x" &&
+               git_log gitrepo-$x >"git-log-$x"
        done &&
 
        test_cmp hg-log-hg hg-log-git &&
@@ -456,12 +468,13 @@ test_expect_success 'hg author' '
 test_expect_success 'hg branch' '
        test_when_finished "rm -rf gitrepo* hgrepo*" &&
 
-       for x in hg git; do
+       for x in hg git
+       do
                (
                git init -q gitrepo-$x &&
                cd gitrepo-$x &&
 
-               echo alpha > alpha &&
+               echo alpha >alpha &&
                git add alpha &&
                git commit -q -m "add alpha" &&
                git checkout -q -b not-master
@@ -481,8 +494,8 @@ test_expect_success 'hg branch' '
                hg_push_$x hgrepo-$x gitrepo-$x &&
                hg_clone_$x gitrepo-$x hgrepo2-$x &&
 
-               hg_log hgrepo2-$x > hg-log-$x &&
-               git_log gitrepo-$x > git-log-$x
+               hg_log hgrepo2-$x >"hg-log-$x" &&
+               git_log gitrepo-$x >"git-log-$x"
        done &&
 
        test_cmp hg-log-hg hg-log-git &&
@@ -492,12 +505,13 @@ test_expect_success 'hg branch' '
 test_expect_success 'hg tags' '
        test_when_finished "rm -rf gitrepo* hgrepo*" &&
 
-       for x in hg git; do
+       for x in hg git
+       do
                (
                git init -q gitrepo-$x &&
                cd gitrepo-$x &&
 
-               echo alpha > alpha &&
+               echo alpha >alpha &&
                git add alpha &&
                git commit -m "add alpha" &&
                git checkout -q -b not-master
@@ -518,7 +532,7 @@ test_expect_success 'hg tags' '
                git --git-dir=gitrepo-$x/.git tag -l &&
                hg_log hgrepo2-$x &&
                cat hgrepo2-$x/.hgtags
-               ) > output-$x
+               ) >"output-$x"
        done &&
 
        test_cmp output-hg output-git
index f7ce8aa853d5ad9689f49a9cadf0d43ce16ed34f..72f745d63f2f225b4976b27875d726b4652198ed 100755 (executable)
@@ -10,40 +10,44 @@ test_description='Test remote-hg'
 
 . ./test-lib.sh
 
-if ! test_have_prereq PYTHON; then
+if ! test_have_prereq PYTHON
+then
        skip_all='skipping remote-hg tests; python not available'
        test_done
 fi
 
-if ! python -c 'import mercurial'; then
+if ! python -c 'import mercurial'
+then
        skip_all='skipping remote-hg tests; mercurial not available'
        test_done
 fi
 
 check () {
-       echo $3 > expected &&
-       git --git-dir=$1/.git log --format='%s' -1 $2 > actual
+       echo $3 >expected &&
+       git --git-dir=$1/.git log --format='%s' -1 $2 >actual
        test_cmp expected actual
 }
 
 check_branch () {
-       if [ -n "$3" ]; then
-               echo $3 > expected &&
-               hg -R $1 log -r $2 --template '{desc}\n' > actual &&
+       if test -n "$3"
+       then
+               echo $3 >expected &&
+               hg -R $1 log -r $2 --template '{desc}\n' >actual &&
                test_cmp expected actual
        else
-               hg -R $1 branches > out &&
+               hg -R $1 branches >out &&
                ! grep $2 out
        fi
 }
 
 check_bookmark () {
-       if [ -n "$3" ]; then
-               echo $3 > expected &&
-               hg -R $1 log -r "bookmark('$2')" --template '{desc}\n' > actual &&
+       if test -n "$3"
+       then
+               echo $3 >expected &&
+               hg -R $1 log -r "bookmark('$2')" --template '{desc}\n' >actual &&
                test_cmp expected actual
        else
-               hg -R $1 bookmarks > out &&
+               hg -R $1 bookmarks >out &&
                ! grep $2 out
        fi
 }
@@ -52,7 +56,7 @@ check_push () {
        local expected_ret=$1 ret=0 ref_ret=0 IFS=':'
 
        shift
-       git push origin "$@" 2> error
+       git push origin "$@" 2>error
        ret=$?
        cat error
 
@@ -75,10 +79,10 @@ check_push () {
                        grep "^   [a-f0-9]*\.\.[a-f0-9]* *${branch} -> ${branch}$" error || ref_ret=1
                        ;;
                esac
-               let 'ref_ret' && echo "match for '$branch' failed" && break
+               test $ref_ret -ne 0 && echo "match for '$branch' failed" && break
        done
 
-       if let 'expected_ret != ret || ref_ret'
+       if test $expected_ret -ne $ret -o $ref_ret -ne 0
        then
                return 1
        fi
@@ -92,7 +96,7 @@ setup () {
        echo "username = H G Wells <wells@example.com>"
        echo "[extensions]"
        echo "mq ="
-       ) >> "$HOME"/.hgrc &&
+       ) >>"$HOME"/.hgrc &&
 
        GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0230" &&
        GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE" &&
@@ -107,7 +111,7 @@ test_expect_success 'cloning' '
        (
        hg init hgrepo &&
        cd hgrepo &&
-       echo zero > content &&
+       echo zero >content &&
        hg add content &&
        hg commit -m zero
        ) &&
@@ -122,7 +126,7 @@ test_expect_success 'cloning with branches' '
        (
        cd hgrepo &&
        hg branch next &&
-       echo next > content &&
+       echo next >content &&
        hg commit -m next
        ) &&
 
@@ -137,7 +141,7 @@ test_expect_success 'cloning with bookmarks' '
        cd hgrepo &&
        hg checkout default &&
        hg bookmark feature-a &&
-       echo feature-a > content &&
+       echo feature-a >content &&
        hg commit -m feature-a
        ) &&
 
@@ -157,7 +161,7 @@ test_expect_success 'update bookmark' '
        git clone "hg::hgrepo" gitrepo &&
        cd gitrepo &&
        git checkout --quiet devel &&
-       echo devel > content &&
+       echo devel >content &&
        git commit -a -m devel &&
        git push --quiet
        ) &&
@@ -172,7 +176,7 @@ test_expect_success 'new bookmark' '
        git clone "hg::hgrepo" gitrepo &&
        cd gitrepo &&
        git checkout --quiet -b feature-b &&
-       echo feature-b > content &&
+       echo feature-b >content &&
        git commit -a -m feature-b &&
        git push --quiet origin feature-b
        ) &&
@@ -184,9 +188,9 @@ test_expect_success 'new bookmark' '
 rm -rf hgrepo
 
 author_test () {
-       echo $1 >> content &&
+       echo $1 >>content &&
        hg commit -u "$2" -m "add $1" &&
-       echo "$3" >> ../expected
+       echo "$3" >>../expected
 }
 
 test_expect_success 'authors' '
@@ -199,7 +203,7 @@ test_expect_success 'authors' '
        touch content &&
        hg add content &&
 
-       > ../expected &&
+       >../expected &&
        author_test alpha "" "H G Wells <wells@example.com>" &&
        author_test beta "test" "test <unknown>" &&
        author_test beta "test <test@example.com> (comment)" "test <test@example.com>" &&
@@ -214,7 +218,7 @@ test_expect_success 'authors' '
        ) &&
 
        git clone "hg::hgrepo" gitrepo &&
-       git --git-dir=gitrepo/.git log --reverse --format="%an <%ae>" > actual &&
+       git --git-dir=gitrepo/.git log --reverse --format="%an <%ae>" >actual &&
 
        test_cmp expected actual
 '
@@ -226,11 +230,11 @@ test_expect_success 'strip' '
        hg init hgrepo &&
        cd hgrepo &&
 
-       echo one >> content &&
+       echo one >>content &&
        hg add content &&
        hg commit -m one &&
 
-       echo two >> content &&
+       echo two >>content &&
        hg commit -m two
        ) &&
 
@@ -240,20 +244,20 @@ test_expect_success 'strip' '
        cd hgrepo &&
        hg strip 1 &&
 
-       echo three >> content &&
+       echo three >>content &&
        hg commit -m three &&
 
-       echo four >> content &&
+       echo four >>content &&
        hg commit -m four
        ) &&
 
        (
        cd gitrepo &&
        git fetch &&
-       git log --format="%s" origin/master > ../actual
+       git log --format="%s" origin/master >../actual
        ) &&
 
-       hg -R hgrepo log --template "{desc}\n" > expected &&
+       hg -R hgrepo log --template "{desc}\n" >expected &&
        test_cmp actual expected
 '
 
@@ -263,18 +267,18 @@ test_expect_success 'remote push with master bookmark' '
        (
        hg init hgrepo &&
        cd hgrepo &&
-       echo zero > content &&
+       echo zero >content &&
        hg add content &&
        hg commit -m zero &&
        hg bookmark master &&
-       echo one > content &&
+       echo one >content &&
        hg commit -m one
        ) &&
 
        (
        git clone "hg::hgrepo" gitrepo &&
        cd gitrepo &&
-       echo two > content &&
+       echo two >content &&
        git commit -a -m two &&
        git push
        ) &&
@@ -282,7 +286,7 @@ test_expect_success 'remote push with master bookmark' '
        check_branch hgrepo default two
 '
 
-cat > expected <<EOF
+cat >expected <<\EOF
 changeset:   0:6e2126489d3d
 tag:         tip
 user:        A U Thor <author@example.com>
@@ -300,13 +304,13 @@ test_expect_success 'remote push from master branch' '
        git init gitrepo &&
        cd gitrepo &&
        git remote add origin "hg::../hgrepo" &&
-       echo one > content &&
+       echo one >content &&
        git add content &&
        git commit -a -m one &&
        git push origin master
        ) &&
 
-       hg -R hgrepo log > actual &&
+       hg -R hgrepo log >actual &&
        cat actual &&
        test_cmp expected actual &&
 
@@ -322,7 +326,7 @@ test_expect_success 'remote cloning' '
        (
        hg init hgrepo &&
        cd hgrepo &&
-       echo zero > content &&
+       echo zero >content &&
        hg add content &&
        hg commit -m zero
        ) &&
@@ -343,7 +347,7 @@ test_expect_success 'remote update bookmark' '
        git clone "hg::hgrepo" gitrepo &&
        cd gitrepo &&
        git checkout --quiet devel &&
-       echo devel > content &&
+       echo devel >content &&
        git commit -a -m devel &&
        git push --quiet
        ) &&
@@ -358,7 +362,7 @@ test_expect_success 'remote new bookmark' '
        git clone "hg::hgrepo" gitrepo &&
        cd gitrepo &&
        git checkout --quiet -b feature-b &&
-       echo feature-b > content &&
+       echo feature-b >content &&
        git commit -a -m feature-b &&
        git push --quiet origin feature-b
        ) &&
@@ -374,15 +378,15 @@ test_expect_success 'remote push diverged' '
        (
        cd hgrepo &&
        hg checkout default &&
-       echo bump > content &&
+       echo bump >content &&
        hg commit -m bump
        ) &&
 
        (
        cd gitrepo &&
-       echo diverge > content &&
+       echo diverge >content &&
        git commit -a -m diverged &&
-       check_push 1 <<-EOF
+       check_push 1 <<-\EOF
        master:non-fast-forward
        EOF
        ) &&
@@ -403,16 +407,16 @@ test_expect_success 'remote update bookmark diverge' '
 
        (
        cd hgrepo &&
-       echo "bump bookmark" > content &&
+       echo "bump bookmark" >content &&
        hg commit -m "bump bookmark"
        ) &&
 
        (
        cd gitrepo &&
        git checkout --quiet diverge &&
-       echo diverge > content &&
+       echo diverge >content &&
        git commit -a -m diverge &&
-       check_push 1 <<-EOF
+       check_push 1 <<-\EOF
        diverge:fetch-first
        EOF
        ) &&
@@ -427,7 +431,7 @@ test_expect_success 'remote new bookmark multiple branch head' '
        git clone "hg::hgrepo" gitrepo &&
        cd gitrepo &&
        git checkout --quiet -b feature-c HEAD^ &&
-       echo feature-c > content &&
+       echo feature-c >content &&
        git commit -a -m feature-c &&
        git push --quiet origin feature-c
        ) &&
@@ -442,20 +446,20 @@ setup_big_push () {
        (
        hg init hgrepo &&
        cd hgrepo &&
-       echo zero > content &&
+       echo zero >content &&
        hg add content &&
        hg commit -m zero &&
        hg bookmark bad_bmark1 &&
-       echo one > content &&
+       echo one >content &&
        hg commit -m one &&
        hg bookmark bad_bmark2 &&
        hg bookmark good_bmark &&
        hg bookmark -i good_bmark &&
        hg -q branch good_branch &&
-       echo "good branch" > content &&
+       echo "good branch" >content &&
        hg commit -m "good branch" &&
        hg -q branch bad_branch &&
-       echo "bad branch" > content &&
+       echo "bad branch" >content &&
        hg commit -m "bad branch"
        ) &&
 
@@ -463,40 +467,40 @@ setup_big_push () {
 
        (
        cd gitrepo &&
-       echo two > content &&
+       echo two >content &&
        git commit -q -a -m two &&
 
        git checkout -q good_bmark &&
-       echo three > content &&
+       echo three >content &&
        git commit -q -a -m three &&
 
        git checkout -q bad_bmark1 &&
        git reset --hard HEAD^ &&
-       echo four > content &&
+       echo four >content &&
        git commit -q -a -m four &&
 
        git checkout -q bad_bmark2 &&
        git reset --hard HEAD^ &&
-       echo five > content &&
+       echo five >content &&
        git commit -q -a -m five &&
 
        git checkout -q -b new_bmark master &&
-       echo six > content &&
+       echo six >content &&
        git commit -q -a -m six &&
 
        git checkout -q branches/good_branch &&
-       echo seven > content &&
+       echo seven >content &&
        git commit -q -a -m seven &&
-       echo eight > content &&
+       echo eight >content &&
        git commit -q -a -m eight &&
 
        git checkout -q branches/bad_branch &&
        git reset --hard HEAD^ &&
-       echo nine > content &&
+       echo nine >content &&
        git commit -q -a -m nine &&
 
        git checkout -q -b branches/new_branch master &&
-       echo ten > content &&
+       echo ten >content &&
        git commit -q -a -m ten
        )
 }
@@ -509,7 +513,7 @@ test_expect_success 'remote big push' '
        (
        cd gitrepo &&
 
-       check_push 1 --all <<-EOF
+       check_push 1 --all <<-\EOF
        master
        good_bmark
        branches/good_branch
@@ -537,17 +541,17 @@ test_expect_success 'remote big push fetch first' '
        (
        hg init hgrepo &&
        cd hgrepo &&
-       echo zero > content &&
+       echo zero >content &&
        hg add content &&
        hg commit -m zero &&
        hg bookmark bad_bmark &&
        hg bookmark good_bmark &&
        hg bookmark -i good_bmark &&
        hg -q branch good_branch &&
-       echo "good branch" > content &&
+       echo "good branch" >content &&
        hg commit -m "good branch" &&
        hg -q branch bad_branch &&
-       echo "bad branch" > content &&
+       echo "bad branch" >content &&
        hg commit -m "bad branch"
        ) &&
 
@@ -556,39 +560,37 @@ test_expect_success 'remote big push fetch first' '
        (
        cd hgrepo &&
        hg bookmark -f bad_bmark &&
-       echo update_bmark > content &&
+       echo update_bmark >content &&
        hg commit -m "update bmark"
        ) &&
 
        (
        cd gitrepo &&
-       echo two > content &&
+       echo two >content &&
        git commit -q -a -m two &&
 
        git checkout -q good_bmark &&
-       echo three > content &&
+       echo three >content &&
        git commit -q -a -m three &&
 
        git checkout -q bad_bmark &&
-       echo four > content &&
+       echo four >content &&
        git commit -q -a -m four &&
 
        git checkout -q branches/bad_branch &&
-       echo five > content &&
+       echo five >content &&
        git commit -q -a -m five &&
 
-       check_push 1 --all <<-EOF
+       check_push 1 --all <<-\EOF &&
        master
        good_bmark
-       new_bmark:new
-       new_branch:new
        bad_bmark:fetch-first
        branches/bad_branch:festch-first
        EOF
 
        git fetch &&
 
-       check_push 1 --all <<-EOF
+       check_push 1 --all <<-\EOF
        master
        good_bmark
        bad_bmark:non-fast-forward
@@ -605,7 +607,7 @@ test_expect_failure 'remote big push force' '
        (
        cd gitrepo &&
 
-       check_push 0 --force --all <<-EOF
+       check_push 0 --force --all <<-\EOF
        master
        good_bmark
        branches/good_branch
@@ -635,7 +637,7 @@ test_expect_failure 'remote big push dry-run' '
        (
        cd gitrepo &&
 
-       check_push 0 --dry-run --all <<-EOF
+       check_push 1 --dry-run --all <<-\EOF &&
        master
        good_bmark
        branches/good_branch
@@ -646,7 +648,7 @@ test_expect_failure 'remote big push dry-run' '
        branches/bad_branch:non-fast-forward
        EOF
 
-       check_push 0 --dry-run master good_bmark new_bmark branches/good_branch branches/new_branch <<-EOF
+       check_push 0 --dry-run master good_bmark new_bmark branches/good_branch branches/new_branch <<-\EOF
        master
        good_bmark
        branches/good_branch
@@ -671,10 +673,10 @@ test_expect_success 'remote double failed push' '
        (
        hg init hgrepo &&
        cd hgrepo &&
-       echo zero > content &&
+       echo zero >content &&
        hg add content &&
        hg commit -m zero &&
-       echo one > content &&
+       echo one >content &&
        hg commit -m one
        ) &&
 
@@ -682,7 +684,7 @@ test_expect_success 'remote double failed push' '
        git clone "hg::hgrepo" gitrepo &&
        cd gitrepo &&
        git reset --hard HEAD^ &&
-       echo two > content &&
+       echo two >content &&
        git commit -a -m two &&
        test_expect_code 1 git push &&
        test_expect_code 1 git push
index e301aafff9ff230313425eea5987b18056b72c98..00a8eefde9aeb96592f5ed6455dbf5d3b16747c4 100644 (file)
@@ -215,9 +215,21 @@ void diff_no_index(struct rev_info *revs,
                     path_inside_repo(prefix, argv[i+1])))
                        return;
        }
-       if (argc != i + 2)
+       if (argc != i + 2) {
+               if (!no_index) {
+                       /*
+                        * There was no --no-index and there were not two
+                        * paths. It is possible that the user intended
+                        * to do an inside-repository operation.
+                        */
+                       fprintf(stderr, "Not a git repository\n");
+                       fprintf(stderr,
+                               "To compare two paths outside a working tree:\n");
+               }
+               /* Give the usage message for non-repository usage and exit. */
                usagef("git diff %s <path> <path>",
                       no_index ? "--no-index" : "[--no-index]");
+       }
 
        diff_setup(&revs->diffopt);
        for (i = 1; i < argc - 2; ) {
diff --git a/dir.c b/dir.c
index 1128110a441538215e5bc046183b11b6b49f129e..b439ff0e63481bebb4039901b029bad978b46929 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -429,15 +429,14 @@ static void *read_skip_worktree_file_from_index(const char *path, size_t *size)
        unsigned long sz;
        enum object_type type;
        void *data;
-       struct index_state *istate = &the_index;
 
        len = strlen(path);
-       pos = index_name_pos(istate, path, len);
+       pos = cache_name_pos(path, len);
        if (pos < 0)
                return NULL;
-       if (!ce_skip_worktree(istate->cache[pos]))
+       if (!ce_skip_worktree(active_cache[pos]))
                return NULL;
-       data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
+       data = read_sha1_file(active_cache[pos]->sha1, &type, &sz);
        if (!data || type != OBJ_BLOB) {
                free(data);
                return NULL;
@@ -884,13 +883,13 @@ enum exist_status {
 };
 
 /*
- * Do not use the alphabetically stored index to look up
+ * Do not use the alphabetically sorted index to look up
  * the directory name; instead, use the case insensitive
  * name hash.
  */
 static enum exist_status directory_exists_in_index_icase(const char *dirname, int len)
 {
-       const struct cache_entry *ce = index_name_exists(&the_index, dirname, len + 1, ignore_case);
+       const struct cache_entry *ce = cache_name_exists(dirname, len + 1, ignore_case);
        unsigned char endchar;
 
        if (!ce)
@@ -1132,14 +1131,51 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
                                          int dtype, struct dirent *de)
 {
        int exclude;
+       int has_path_in_index = !!cache_name_exists(path->buf, path->len, ignore_case);
+
        if (dtype == DT_UNKNOWN)
                dtype = get_dtype(de, path->buf, path->len);
 
        /* Always exclude indexed files */
-       if (dtype != DT_DIR &&
-           cache_name_exists(path->buf, path->len, ignore_case))
+       if (dtype != DT_DIR && has_path_in_index)
                return path_none;
 
+       /*
+        * When we are looking at a directory P in the working tree,
+        * there are three cases:
+        *
+        * (1) P exists in the index.  Everything inside the directory P in
+        * the working tree needs to go when P is checked out from the
+        * index.
+        *
+        * (2) P does not exist in the index, but there is P/Q in the index.
+        * We know P will stay a directory when we check out the contents
+        * of the index, but we do not know yet if there is a directory
+        * P/Q in the working tree to be killed, so we need to recurse.
+        *
+        * (3) P does not exist in the index, and there is no P/Q in the index
+        * to require P to be a directory, either.  Only in this case, we
+        * know that everything inside P will not be killed without
+        * recursing.
+        */
+       if ((dir->flags & DIR_COLLECT_KILLED_ONLY) &&
+           (dtype == DT_DIR) &&
+           !has_path_in_index) {
+               /*
+                * NEEDSWORK: directory_exists_in_index_icase()
+                * assumes that one byte past the given path is
+                * readable and has '/', which needs to be fixed, but
+                * until then, work it around in the caller.
+                */
+               strbuf_addch(path, '/');
+               if (directory_exists_in_index(path->buf, path->len - 1) ==
+                   index_nonexistent) {
+                       strbuf_setlen(path, path->len - 1);
+                       return path_none;
+               }
+               strbuf_setlen(path, path->len - 1);
+       }
+
        exclude = is_excluded(dir, path->buf, &dtype);
 
        /*
diff --git a/dir.h b/dir.h
index 343ec7aa3188a904f4517241b31250a57f11eddb..9b7e4e77d8b11bab92a91a6ce3e8920e50d23f9b 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -80,7 +80,8 @@ struct dir_struct {
                DIR_HIDE_EMPTY_DIRECTORIES = 1<<2,
                DIR_NO_GITLINKS = 1<<3,
                DIR_COLLECT_IGNORED = 1<<4,
-               DIR_SHOW_IGNORED_TOO = 1<<5
+               DIR_SHOW_IGNORED_TOO = 1<<5,
+               DIR_COLLECT_KILLED_ONLY = 1<<6
        } flags;
        struct dir_entry **entries;
        struct dir_entry **ignored;
index 5398c36dd4dc2c1d7ded3f92c217a99a240a0a23..378254c77a00f93ef667c0510fa11b75988ef05a 100644 (file)
@@ -123,14 +123,13 @@ static char *expand_namespace(const char *raw_namespace)
 
 static void setup_git_env(void)
 {
+       const char *gitfile;
+
        git_dir = getenv(GIT_DIR_ENVIRONMENT);
-       git_dir = git_dir ? xstrdup(git_dir) : NULL;
-       if (!git_dir) {
-               git_dir = read_gitfile(DEFAULT_GIT_DIR_ENVIRONMENT);
-               git_dir = git_dir ? xstrdup(git_dir) : NULL;
-       }
        if (!git_dir)
                git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
+       gitfile = read_gitfile(git_dir);
+       git_dir = xstrdup(gitfile ? gitfile : git_dir);
        git_object_dir = getenv(DB_ENVIRONMENT);
        if (!git_object_dir) {
                git_object_dir = xmalloc(strlen(git_dir) + 9);
index 21db3fc46d58231fd1345d65ae6cf1104901e55e..f4d9969e5c81f9c1415f0908f090bf62b156e179 100644 (file)
@@ -22,8 +22,8 @@ Format of STDIN stream:
     ('author' (sp name)? sp '<' email '>' sp when lf)?
     'committer' (sp name)? sp '<' email '>' sp when lf
     commit_msg
-    ('from' sp committish lf)?
-    ('merge' sp committish lf)*
+    ('from' sp commit-ish lf)?
+    ('merge' sp commit-ish lf)*
     (file_change | ls)*
     lf?;
   commit_msg ::= data;
@@ -43,18 +43,18 @@ Format of STDIN stream:
   file_obm ::= 'M' sp mode sp (hexsha1 | idnum) sp path_str lf;
   file_inm ::= 'M' sp mode sp 'inline' sp path_str lf
     data;
-  note_obm ::= 'N' sp (hexsha1 | idnum) sp committish lf;
-  note_inm ::= 'N' sp 'inline' sp committish lf
+  note_obm ::= 'N' sp (hexsha1 | idnum) sp commit-ish lf;
+  note_inm ::= 'N' sp 'inline' sp commit-ish lf
     data;
 
   new_tag ::= 'tag' sp tag_str lf
-    'from' sp committish lf
+    'from' sp commit-ish lf
     ('tagger' (sp name)? sp '<' email '>' sp when lf)?
     tag_msg;
   tag_msg ::= data;
 
   reset_branch ::= 'reset' sp ref_str lf
-    ('from' sp committish lf)?
+    ('from' sp commit-ish lf)?
     lf?;
 
   checkpoint ::= 'checkpoint' lf
@@ -93,7 +93,7 @@ Format of STDIN stream:
      # stream formatting is: \, " and LF.  Otherwise these values
      # are UTF8.
      #
-  committish  ::= (ref_str | hexsha1 | sha1exp_str | idnum);
+  commit-ish  ::= (ref_str | hexsha1 | sha1exp_str | idnum);
   ref_str     ::= ref;
   sha1exp_str ::= sha1exp;
   tag_str     ::= tag;
@@ -1694,7 +1694,7 @@ static int update_branch(struct branch *b)
                return 0;
        if (read_ref(b->name, old_sha1))
                hashclr(old_sha1);
-       lock = lock_any_ref_for_update(b->name, old_sha1, 0);
+       lock = lock_any_ref_for_update(b->name, old_sha1, 0, NULL);
        if (!lock)
                return error("Unable to lock %s", b->name);
        if (!force_update && !is_null_sha1(old_sha1)) {
@@ -2494,7 +2494,7 @@ static void note_change_n(struct branch *b, unsigned char *old_fanout)
        assert(*p == ' ');
        p++;  /* skip space */
 
-       /* <committish> */
+       /* <commit-ish> */
        s = lookup_branch(p);
        if (s) {
                if (is_null_sha1(s->sha1))
@@ -2973,7 +2973,7 @@ static struct object_entry *dereference(struct object_entry *oe,
        case OBJ_TAG:
                break;
        default:
-               die("Not a treeish: %s", command_buf.buf);
+               die("Not a tree-ish: %s", command_buf.buf);
        }
 
        if (oe->pack_id != MAX_PACK_ID) {       /* in a pack being written */
@@ -3057,7 +3057,7 @@ static void parse_ls(struct branch *b)
        struct tree_entry *root = NULL;
        struct tree_entry leaf = {NULL};
 
-       /* ls SP (<treeish> SP)? <path> */
+       /* ls SP (<tree-ish> SP)? <path> */
        p = command_buf.buf + strlen("ls ");
        if (*p == '"') {
                if (!b)
index 094267fd80cdb09feec75c89aa2f4931f11e583d..a0e0350ae6bdf338b3c11c21fc050edb60c88569 100644 (file)
@@ -185,36 +185,6 @@ static void consume_shallow_list(struct fetch_pack_args *args, int fd)
        }
 }
 
-struct write_shallow_data {
-       struct strbuf *out;
-       int use_pack_protocol;
-       int count;
-};
-
-static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
-{
-       struct write_shallow_data *data = cb_data;
-       const char *hex = sha1_to_hex(graft->sha1);
-       data->count++;
-       if (data->use_pack_protocol)
-               packet_buf_write(data->out, "shallow %s", hex);
-       else {
-               strbuf_addstr(data->out, hex);
-               strbuf_addch(data->out, '\n');
-       }
-       return 0;
-}
-
-static int write_shallow_commits(struct strbuf *out, int use_pack_protocol)
-{
-       struct write_shallow_data data;
-       data.out = out;
-       data.use_pack_protocol = use_pack_protocol;
-       data.count = 0;
-       for_each_commit_graft(write_one_shallow, &data);
-       return data.count;
-}
-
 static enum ack_type get_ack(int fd, unsigned char *result_sha1)
 {
        int len;
@@ -689,7 +659,7 @@ static int get_pack(struct fetch_pack_args *args,
        const char *argv[22];
        char keep_arg[256];
        char hdr_arg[256];
-       const char **av;
+       const char **av, *cmd_name;
        int do_keep = args->keep_pack;
        struct child_process cmd;
        int ret;
@@ -736,7 +706,7 @@ static int get_pack(struct fetch_pack_args *args,
        if (do_keep) {
                if (pack_lockfile)
                        cmd.out = -1;
-               *av++ = "index-pack";
+               *av++ = cmd_name = "index-pack";
                *av++ = "--stdin";
                if (!args->quiet && !args->no_progress)
                        *av++ = "-v";
@@ -753,7 +723,7 @@ static int get_pack(struct fetch_pack_args *args,
                        *av++ = "--check-self-contained-and-connected";
        }
        else {
-               *av++ = "unpack-objects";
+               *av++ = cmd_name = "unpack-objects";
                if (args->quiet || args->no_progress)
                        *av++ = "-q";
                args->check_self_contained_and_connected = 0;
@@ -771,7 +741,7 @@ static int get_pack(struct fetch_pack_args *args,
        cmd.in = demux.out;
        cmd.git_cmd = 1;
        if (start_command(&cmd))
-               die("fetch-pack: unable to fork off %s", argv[0]);
+               die("fetch-pack: unable to fork off %s", cmd_name);
        if (do_keep && pack_lockfile) {
                *pack_lockfile = index_pack_lockfile(cmd.out);
                close(cmd.out);
@@ -783,7 +753,7 @@ static int get_pack(struct fetch_pack_args *args,
                        args->check_self_contained_and_connected &&
                        ret == 0;
        else
-               die("%s failed", argv[0]);
+               die("%s failed", cmd_name);
        if (use_sideband && finish_async(&demux))
                die("error in sideband demultiplexer");
        return 0;
@@ -796,27 +766,6 @@ static int cmp_ref_by_name(const void *a_, const void *b_)
        return strcmp(a->name, b->name);
 }
 
-static void setup_alternate_shallow(void)
-{
-       struct strbuf sb = STRBUF_INIT;
-       int fd;
-
-       check_shallow_file_for_update();
-       fd = hold_lock_file_for_update(&shallow_lock, git_path("shallow"),
-                                      LOCK_DIE_ON_ERROR);
-       if (write_shallow_commits(&sb, 0)) {
-               if (write_in_full(fd, sb.buf, sb.len) != sb.len)
-                       die_errno("failed to write to %s", shallow_lock.filename);
-               alternate_shallow_file = shallow_lock.filename;
-       } else
-               /*
-                * is_repository_shallow() sees empty string as "no
-                * shallow file".
-                */
-               alternate_shallow_file = "";
-       strbuf_release(&sb);
-}
-
 static struct ref *do_fetch_pack(struct fetch_pack_args *args,
                                 int fd[2],
                                 const struct ref *orig_ref,
@@ -897,7 +846,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
        if (args->stateless_rpc)
                packet_flush(fd[1]);
        if (args->depth > 0)
-               setup_alternate_shallow();
+               setup_alternate_shallow(&shallow_lock, &alternate_shallow_file);
        else
                alternate_shallow_file = NULL;
        if (get_pack(args, fd, pack_lockfile))
index 75a991f7ec8a2e4926cb925ad9ff23be2f6aedeb..51563840f49089cf250992fd47fe70a45cef0c52 100755 (executable)
@@ -169,7 +169,7 @@ sub colored {
 my %patch_mode_flavour = %{$patch_modes{stage}};
 
 sub run_cmd_pipe {
-       if ($^O eq 'MSWin32' || $^O eq 'msys') {
+       if ($^O eq 'MSWin32') {
                my @invalid = grep {m/[":*]/} @_;
                die "$^O does not support: @invalid\n" if @invalid;
                my @args = map { m/ /o ? "\"$_\"": $_ } @_;
index 9549de6318147839c73b60b1fc72ceb44d9adb47..7776f126d3bd4facfe987bd844a339c8a17b102a 100644 (file)
@@ -86,7 +86,7 @@
 #define _SGI_SOURCE 1
 
 #if defined(WIN32) && !defined(__CYGWIN__) /* Both MinGW and MSVC */
-# if defined (_MSC_VER)
+# if defined (_MSC_VER) && !defined(_WIN32_WINNT)
 #  define _WIN32_WINNT 0x0502
 # endif
 #define WIN32_LEAN_AND_MEAN  /* stops windows.h including winsock.h */
index a0d796e57087e0ca5bac94520997ecacec9fd295..74d1cc7db040c4d4fa736567be9340e4b4070863 100755 (executable)
@@ -4167,7 +4167,7 @@ sub convertToDbMode
     #  this half-converted form, but it isn't currently worth the
     #  backwards compatibility headaches.
 
-    $mode=~/^\d\d(\d)\d{3}$/;
+    $mode=~/^\d{3}(\d)\d\d$/;
     my $userBits=$1;
 
     my $dbMode = "";
@@ -4338,7 +4338,7 @@ sub getAnyHead
 =head2 getRevisionDirMap
 
 A "revision dir map" contains all the plain-file filenames associated
-with a particular revision (treeish), organized by directory:
+with a particular revision (tree-ish), organized by directory:
 
   $type = $out->{$dir}{$fullName}
 
index ac2a005fdb23c48d8451188ffd7b1c8194b0295f..86d6994619151fb63327848e6763b07971017ad7 100755 (executable)
@@ -255,7 +255,7 @@ else
        remap_to_ancestor=t
 fi
 
-rev_args=$(git rev-parse --revs-only "$@")
+git rev-parse --revs-only "$@" >../parse
 
 case "$filter_subdir" in
 "")
@@ -268,7 +268,7 @@ case "$filter_subdir" in
 esac
 
 git rev-list --reverse --topo-order --default HEAD \
-       --parents --simplify-merges $rev_args "$@" > ../revs ||
+       --parents --simplify-merges --stdin "$@" <../parse >../revs ||
        die "Could not get the commits"
 commits=$(wc -l <../revs | tr -d " ")
 
@@ -283,11 +283,12 @@ while read commit parents; do
 
        case "$filter_subdir" in
        "")
-               git read-tree -i -m $commit
+               GIT_ALLOW_NULL_SHA1=1 git read-tree -i -m $commit
                ;;
        *)
                # The commit may not have the subdirectory at all
-               err=$(git read-tree -i -m $commit:"$filter_subdir" 2>&1) || {
+               err=$(GIT_ALLOW_NULL_SHA1=1 \
+                     git read-tree -i -m $commit:"$filter_subdir" 2>&1) || {
                        if ! git rev-parse -q --verify $commit:"$filter_subdir"
                        then
                                rm -f "$GIT_INDEX_FILE"
index feee6a4a0d3a970c94fe506070ddc497c4b40658..a280f498179eb2747b32ba5de4111ccb32024848 100644 (file)
@@ -250,7 +250,8 @@ list_merge_tool_candidates () {
                else
                        tools="opendiff kdiff3 tkdiff xxdiff meld $tools"
                fi
-               tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3 codecompare"
+               tools="$tools gvimdiff diffuse diffmerge ecmerge"
+               tools="$tools p4merge araxis bc3 codecompare"
        fi
        case "${VISUAL:-$EDITOR}" in
        *vim*)
@@ -263,7 +264,7 @@ list_merge_tool_candidates () {
 }
 
 show_tool_help () {
-       tool_opt="'git ${TOOL_MODE}tool --tool-<tool>'"
+       tool_opt="'git ${TOOL_MODE}tool --tool=<tool>'"
 
        tab='   '
        LF='
index a53a6dc406c26daaf263944d38b53b27db271072..06a3cc6122410efcccf0fd77f359ffc2e809aff9 100755 (executable)
--- a/git-p4.py
+++ b/git-p4.py
@@ -780,11 +780,14 @@ def getClientSpec():
     # dictionary of all client parameters
     entry = specList[0]
 
+    # the //client/ name
+    client_name = entry["Client"]
+
     # just the keys that start with "View"
     view_keys = [ k for k in entry.keys() if k.startswith("View") ]
 
     # hold this new View
-    view = View()
+    view = View(client_name)
 
     # append the lines, in order, to the view
     for view_num in range(len(view_keys)):
@@ -1555,8 +1558,8 @@ def exportGitTags(self, gitTags):
             for b in body:
                 labelTemplate += "\t" + b + "\n"
             labelTemplate += "View:\n"
-            for mapping in clientSpec.mappings:
-                labelTemplate += "\t%s\n" % mapping.depot_side.path
+            for depot_side in clientSpec.mappings:
+                labelTemplate += "\t%s\n" % depot_side
 
             if self.dry_run:
                 print "Would create p4 label %s for tag" % name
@@ -1568,7 +1571,7 @@ def exportGitTags(self, gitTags):
 
                 # Use the label
                 p4_system(["tag", "-l", name] +
-                          ["%s@%s" % (mapping.depot_side.path, changelist) for mapping in clientSpec.mappings])
+                          ["%s@%s" % (depot_side, changelist) for depot_side in clientSpec.mappings])
 
                 if verbose:
                     print "created p4 label for tag %s" % name
@@ -1796,117 +1799,16 @@ class View(object):
     """Represent a p4 view ("p4 help views"), and map files in a
        repo according to the view."""
 
-    class Path(object):
-        """A depot or client path, possibly containing wildcards.
-           The only one supported is ... at the end, currently.
-           Initialize with the full path, with //depot or //client."""
-
-        def __init__(self, path, is_depot):
-            self.path = path
-            self.is_depot = is_depot
-            self.find_wildcards()
-            # remember the prefix bit, useful for relative mappings
-            m = re.match("(//[^/]+/)", self.path)
-            if not m:
-                die("Path %s does not start with //prefix/" % self.path)
-            prefix = m.group(1)
-            if not self.is_depot:
-                # strip //client/ on client paths
-                self.path = self.path[len(prefix):]
-
-        def find_wildcards(self):
-            """Make sure wildcards are valid, and set up internal
-               variables."""
-
-            self.ends_triple_dot = False
-            # There are three wildcards allowed in p4 views
-            # (see "p4 help views").  This code knows how to
-            # handle "..." (only at the end), but cannot deal with
-            # "%%n" or "*".  Only check the depot_side, as p4 should
-            # validate that the client_side matches too.
-            if re.search(r'%%[1-9]', self.path):
-                die("Can't handle %%n wildcards in view: %s" % self.path)
-            if self.path.find("*") >= 0:
-                die("Can't handle * wildcards in view: %s" % self.path)
-            triple_dot_index = self.path.find("...")
-            if triple_dot_index >= 0:
-                if triple_dot_index != len(self.path) - 3:
-                    die("Can handle only single ... wildcard, at end: %s" %
-                        self.path)
-                self.ends_triple_dot = True
-
-        def ensure_compatible(self, other_path):
-            """Make sure the wildcards agree."""
-            if self.ends_triple_dot != other_path.ends_triple_dot:
-                 die("Both paths must end with ... if either does;\n" +
-                     "paths: %s %s" % (self.path, other_path.path))
-
-        def match_wildcards(self, test_path):
-            """See if this test_path matches us, and fill in the value
-               of the wildcards if so.  Returns a tuple of
-               (True|False, wildcards[]).  For now, only the ... at end
-               is supported, so at most one wildcard."""
-            if self.ends_triple_dot:
-                dotless = self.path[:-3]
-                if test_path.startswith(dotless):
-                    wildcard = test_path[len(dotless):]
-                    return (True, [ wildcard ])
-            else:
-                if test_path == self.path:
-                    return (True, [])
-            return (False, [])
-
-        def match(self, test_path):
-            """Just return if it matches; don't bother with the wildcards."""
-            b, _ = self.match_wildcards(test_path)
-            return b
-
-        def fill_in_wildcards(self, wildcards):
-            """Return the relative path, with the wildcards filled in
-               if there are any."""
-            if self.ends_triple_dot:
-                return self.path[:-3] + wildcards[0]
-            else:
-                return self.path
-
-    class Mapping(object):
-        def __init__(self, depot_side, client_side, overlay, exclude):
-            # depot_side is without the trailing /... if it had one
-            self.depot_side = View.Path(depot_side, is_depot=True)
-            self.client_side = View.Path(client_side, is_depot=False)
-            self.overlay = overlay  # started with "+"
-            self.exclude = exclude  # started with "-"
-            assert not (self.overlay and self.exclude)
-            self.depot_side.ensure_compatible(self.client_side)
-
-        def __str__(self):
-            c = " "
-            if self.overlay:
-                c = "+"
-            if self.exclude:
-                c = "-"
-            return "View.Mapping: %s%s -> %s" % \
-                   (c, self.depot_side.path, self.client_side.path)
-
-        def map_depot_to_client(self, depot_path):
-            """Calculate the client path if using this mapping on the
-               given depot path; does not consider the effect of other
-               mappings in a view.  Even excluded mappings are returned."""
-            matches, wildcards = self.depot_side.match_wildcards(depot_path)
-            if not matches:
-                return ""
-            client_path = self.client_side.fill_in_wildcards(wildcards)
-            return client_path
-
-    #
-    # View methods
-    #
-    def __init__(self):
+    def __init__(self, client_name):
         self.mappings = []
+        self.client_prefix = "//%s/" % client_name
+        # cache results of "p4 where" to lookup client file locations
+        self.client_spec_path_cache = {}
 
     def append(self, view_line):
         """Parse a view line, splitting it into depot and client
-           sides.  Append to self.mappings, preserving order."""
+           sides.  Append to self.mappings, preserving order.  This
+           is only needed for tag creation."""
 
         # Split the view line into exactly two words.  P4 enforces
         # structure on these lines that simplifies this quite a bit.
@@ -1934,76 +1836,62 @@ def append(self, view_line):
             depot_side = view_line[0:space_index]
             rhs_index = space_index + 1
 
-        if view_line[rhs_index] == '"':
-            # Second word is double quoted.  Make sure there is a
-            # double quote at the end too.
-            if not view_line.endswith('"'):
-                die("View line with rhs quote should end with one: %s" %
-                    view_line)
-            # skip the quotes
-            client_side = view_line[rhs_index+1:-1]
-        else:
-            client_side = view_line[rhs_index:]
-
         # prefix + means overlay on previous mapping
-        overlay = False
         if depot_side.startswith("+"):
-            overlay = True
             depot_side = depot_side[1:]
 
-        # prefix - means exclude this path
+        # prefix - means exclude this path, leave out of mappings
         exclude = False
         if depot_side.startswith("-"):
             exclude = True
             depot_side = depot_side[1:]
 
-        m = View.Mapping(depot_side, client_side, overlay, exclude)
-        self.mappings.append(m)
+        if not exclude:
+            self.mappings.append(depot_side)
 
-    def map_in_client(self, depot_path):
-        """Return the relative location in the client where this
-           depot file should live.  Returns "" if the file should
-           not be mapped in the client."""
+    def convert_client_path(self, clientFile):
+        # chop off //client/ part to make it relative
+        if not clientFile.startswith(self.client_prefix):
+            die("No prefix '%s' on clientFile '%s'" %
+                (self.client_prefix, clientFile))
+        return clientFile[len(self.client_prefix):]
 
-        paths_filled = []
-        client_path = ""
+    def update_client_spec_path_cache(self, files):
+        """ Caching file paths by "p4 where" batch query """
 
-        # look at later entries first
-        for m in self.mappings[::-1]:
+        # List depot file paths exclude that already cached
+        fileArgs = [f['path'] for f in files if f['path'] not in self.client_spec_path_cache]
 
-            # see where will this path end up in the client
-            p = m.map_depot_to_client(depot_path)
+        if len(fileArgs) == 0:
+            return  # All files in cache
 
-            if p == "":
-                # Depot path does not belong in client.  Must remember
-                # this, as previous items should not cause files to
-                # exist in this path either.  Remember that the list is
-                # being walked from the end, which has higher precedence.
-                # Overlap mappings do not exclude previous mappings.
-                if not m.overlay:
-                    paths_filled.append(m.client_side)
+        where_result = p4CmdList(["-x", "-", "where"], stdin=fileArgs)
+        for res in where_result:
+            if "code" in res and res["code"] == "error":
+                # assume error is "... file(s) not in client view"
+                continue
+            if "clientFile" not in res:
+                die("No clientFile from 'p4 where %s'" % depot_path)
+            if "unmap" in res:
+                # it will list all of them, but only one not unmap-ped
+                continue
+            self.client_spec_path_cache[res['depotFile']] = self.convert_client_path(res["clientFile"])
 
-            else:
-                # This mapping matched; no need to search any further.
-                # But, the mapping could be rejected if the client path
-                # has already been claimed by an earlier mapping (i.e.
-                # one later in the list, which we are walking backwards).
-                already_mapped_in_client = False
-                for f in paths_filled:
-                    # this is View.Path.match
-                    if f.match(p):
-                        already_mapped_in_client = True
-                        break
-                if not already_mapped_in_client:
-                    # Include this file, unless it is from a line that
-                    # explicitly said to exclude it.
-                    if not m.exclude:
-                        client_path = p
+        # not found files or unmap files set to ""
+        for depotFile in fileArgs:
+            if depotFile not in self.client_spec_path_cache:
+                self.client_spec_path_cache[depotFile] = ""
 
-                # a match, even if rejected, always stops the search
-                break
+    def map_in_client(self, depot_path):
+        """Return the relative location in the client where this
+           depot file should live.  Returns "" if the file should
+           not be mapped in the client."""
 
-        return client_path
+        if depot_path in self.client_spec_path_cache:
+            return self.client_spec_path_cache[depot_path]
+
+        die( "Error: %s is not found in client spec path" % depot_path )
+        return ""
 
 class P4Sync(Command, P4UserMap):
     delete_actions = ( "delete", "move/delete", "purge" )
@@ -2130,6 +2018,10 @@ def splitFilesIntoBranches(self, commit):
         """Look at each depotFile in the commit to figure out to what
            branch it belongs."""
 
+        if self.clientSpecDirs:
+            files = self.extractFilesFromCommit(commit)
+            self.clientSpecDirs.update_client_spec_path_cache(files)
+
         branches = {}
         fnum = 0
         while commit.has_key("depotFile%s" % fnum):
@@ -2383,6 +2275,9 @@ def commit(self, details, files, branch, parent = ""):
             else:
                 sys.stderr.write("Ignoring file outside of prefix: %s\n" % f['path'])
 
+        if self.clientSpecDirs:
+            self.clientSpecDirs.update_client_spec_path_cache(files)
+
         self.gitStream.write("commit %s\n" % branch)
 #        gitStream.write("mark :%s\n" % details["change"])
         self.committedChanges.add(int(details["change"]))
index f0df41c841644208c89230516677db162498be26..b946fd975bacae7b73645e0dba8ae61da716ccfc 100755 (executable)
@@ -4,7 +4,7 @@
 #
 # Fetch one or more remote refs and merge it/them into the current HEAD.
 
-USAGE='[-n | --no-stat] [--[no-]commit] [--[no-]squash] [--[no-]ff] [-s strategy]... [<fetch-options>] <repo> <head>...'
+USAGE='[-n | --no-stat] [--[no-]commit] [--[no-]squash] [--[no-]ff] [--[no-]rebase|--rebase=preserve] [-s strategy]... [<fetch-options>] <repo> <head>...'
 LONG_USAGE='Fetch one or more remote refs and integrate it/them with the current HEAD.'
 SUBDIRECTORY_OK=Yes
 OPTIONS_SPEC=
@@ -38,15 +38,19 @@ Please, commit your changes before you can merge.")"
 test -z "$(git ls-files -u)" || die_conflict
 test -f "$GIT_DIR/MERGE_HEAD" && die_merge
 
+bool_or_string_config () {
+       git config --bool "$1" 2>/dev/null || git config "$1"
+}
+
 strategy_args= diffstat= no_commit= squash= no_ff= ff_only=
 log_arg= verbosity= progress= recurse_submodules= verify_signatures=
-merge_args= edit=
+merge_args= edit= rebase_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
-rebase=$(git config --bool branch.$curr_branch_short.rebase)
+rebase=$(bool_or_string_config branch.$curr_branch_short.rebase)
 if test -z "$rebase"
 then
-       rebase=$(git config --bool pull.rebase)
+       rebase=$(bool_or_string_config pull.rebase)
 fi
 dry_run=
 while :
@@ -110,6 +114,9 @@ do
                esac
                merge_args="$merge_args$xx "
                ;;
+       -r=*|--r=*|--re=*|--reb=*|--reba=*|--rebas=*|--rebase=*)
+               rebase="${1#*=}"
+               ;;
        -r|--r|--re|--reb|--reba|--rebas|--rebase)
                rebase=true
                ;;
@@ -145,6 +152,20 @@ do
        shift
 done
 
+case "$rebase" in
+preserve)
+       rebase=true
+       rebase_args=--preserve-merges
+       ;;
+true|false|'')
+       ;;
+*)
+       echo "Invalid value for --rebase, should be true, false, or preserve"
+       usage
+       exit 1
+       ;;
+esac
+
 error_on_no_merge_candidates () {
        exec >&2
        for opt
@@ -166,9 +187,8 @@ error_on_no_merge_candidates () {
                op_prep=with
        fi
 
-       curr_branch=${curr_branch#refs/heads/}
-       upstream=$(git config "branch.$curr_branch.merge")
-       remote=$(git config "branch.$curr_branch.remote")
+       upstream=$(git config "branch.$curr_branch_short.merge")
+       remote=$(git config "branch.$curr_branch_short.remote")
 
        if [ $# -gt 1 ]; then
                if [ "$rebase" = true ]; then
@@ -292,7 +312,7 @@ fi
 merge_name=$(git fmt-merge-msg $log_arg <"$GIT_DIR/FETCH_HEAD") || exit
 case "$rebase" in
 true)
-       eval="git-rebase $diffstat $strategy_args $merge_args $verbosity"
+       eval="git-rebase $diffstat $strategy_args $merge_args $rebase_args $verbosity"
        eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
        ;;
 *)
index 83d6d4676bc1cadcec5ea5889fcf4a0769ee8d31..3c6bed9a28f7ff96fa619a9acbfc42e4a2c78828 100644 (file)
@@ -352,8 +352,9 @@ pick_one_preserving_merges () {
                        msg_content="$(commit_message $sha1)"
                        # No point in merging the first parent, that's HEAD
                        new_parents=${new_parents# $first_parent}
+                       merge_args="--no-log --no-ff"
                        if ! do_with_author output eval \
-                       'git merge --no-ff $strategy_args -m "$msg_content" $new_parents'
+                       'git merge $merge_args $strategy_args -m "$msg_content" $new_parents'
                        then
                                printf "%s\n" "$msg_content" > "$GIT_DIR"/MERGE_MSG
                                die_with_patch $sha1 "Error redoing merge $sha1"
@@ -671,7 +672,7 @@ skip_unnecessary_picks () {
                                ;;
                        esac
                        ;;
-               3,#*|3,)
+               3,"$comment_char"*|3,)
                        # copy comments
                        ;;
                *)
@@ -689,6 +690,32 @@ skip_unnecessary_picks () {
        die "Could not skip unnecessary pick commands"
 }
 
+transform_todo_ids () {
+       while read -r command rest
+       do
+               case "$command" in
+               "$comment_char"* | exec)
+                       # Be careful for oddball commands like 'exec'
+                       # that do not have a SHA-1 at the beginning of $rest.
+                       ;;
+               *)
+                       sha1=$(git rev-parse --verify --quiet "$@" ${rest%% *}) &&
+                       rest="$sha1 ${rest#* }"
+                       ;;
+               esac
+               printf '%s\n' "$command${rest:+ }$rest"
+       done <"$todo" >"$todo.new" &&
+       mv -f "$todo.new" "$todo"
+}
+
+expand_todo_ids() {
+       transform_todo_ids
+}
+
+collapse_todo_ids() {
+       transform_todo_ids --short
+}
+
 # Rearrange the todo list that has both "pick sha1 msg" and
 # "pick sha1 fixup!/squash! msg" appears in it so that the latter
 # comes immediately after the former, and change "pick" to
@@ -841,6 +868,7 @@ skip)
 edit-todo)
        git stripspace --strip-comments <"$todo" >"$todo".new
        mv -f "$todo".new "$todo"
+       collapse_todo_ids
        append_todo_help
        git stripspace --comment-lines >>"$todo" <<\EOF
 
@@ -852,6 +880,7 @@ EOF
 
        git_sequence_editor "$todo" ||
                die "Could not execute editor"
+       expand_todo_ids
 
        exit
        ;;
@@ -1008,6 +1037,8 @@ git_sequence_editor "$todo" ||
 has_action "$todo" ||
        die_abort "Nothing to do"
 
+expand_todo_ids
+
 test -d "$rewritten" || test -n "$force_rebase" || skip_unnecessary_picks
 
 GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name"
index 8d7659a22c253b9f9535aee38e3bf0ce380cef75..226752fbff62f4f27da95f7d711c898503fd7148 100755 (executable)
@@ -167,13 +167,22 @@ You can run "git stash pop" or "git stash drop" at any time.
        rm -rf "$state_dir"
 }
 
-run_specific_rebase () {
+run_specific_rebase_internal () {
        if [ "$interactive_rebase" = implied ]; then
                GIT_EDITOR=:
                export GIT_EDITOR
                autosquash=
        fi
+       # On FreeBSD, the shell's "return" returns from the current
+       # function, not from the current file inclusion.
+       # run_specific_rebase_internal has the file inclusion as a
+       # last statement, so POSIX and FreeBSD's return will do the
+       # same thing.
        . git-rebase--$type
+}
+
+run_specific_rebase () {
+       run_specific_rebase_internal
        ret=$?
        if test $ret -eq 0
        then
index 2109070d00411dbd9f1ba70e55587091d50a8a08..6d2f282d32212b605a1237bae224ecbba05cacd1 100755 (executable)
@@ -38,6 +38,7 @@ do
                        echo "*export-marks $gitmarks"
                fi
                test -n "$GIT_REMOTE_TESTGIT_SIGNED_TAGS" && echo "signed-tags"
+               test -n "$GIT_REMOTE_TESTGIT_NO_PRIVATE_UPDATE" && echo "no-private-update"
                echo
                ;;
        list)
diff --git a/git-remote-testpy.py b/git-remote-testpy.py
deleted file mode 100644 (file)
index ca67899..0000000
+++ /dev/null
@@ -1,305 +0,0 @@
-#!/usr/bin/env python
-
-# This command is a simple remote-helper, that is used both as a
-# testcase for the remote-helper functionality, and as an example to
-# show remote-helper authors one possible implementation.
-#
-# This is a Git <-> Git importer/exporter, that simply uses git
-# fast-import and git fast-export to consume and produce fast-import
-# streams.
-#
-# To understand better the way things work, one can activate debug
-# traces by setting (to any value) the environment variables
-# GIT_TRANSPORT_HELPER_DEBUG and GIT_DEBUG_TESTGIT, to see messages
-# from the transport-helper side, or from this example remote-helper.
-
-# hashlib is only available in python >= 2.5
-try:
-    import hashlib
-    _digest = hashlib.sha1
-except ImportError:
-    import sha
-    _digest = sha.new
-import sys
-import os
-import time
-sys.path.insert(0, os.getenv("GITPYTHONLIB","."))
-
-from git_remote_helpers.util import die, debug, warn
-from git_remote_helpers.git.repo import GitRepo
-from git_remote_helpers.git.exporter import GitExporter
-from git_remote_helpers.git.importer import GitImporter
-from git_remote_helpers.git.non_local import NonLocalGit
-
-if sys.hexversion < 0x02000000:
-    # string.encode() is the limiter
-    sys.stderr.write("git-remote-testgit: requires Python 2.0 or later.\n")
-    sys.exit(1)
-
-
-def encode_filepath(path):
-    """Encodes a Unicode file path to a byte string.
-
-    On Python 2 this is a no-op; on Python 3 we encode the string as
-    suggested by [1] which allows an exact round-trip from the command line
-    to the filesystem.
-
-    [1] http://docs.python.org/3/c-api/unicode.html#file-system-encoding
-
-    """
-    if sys.hexversion < 0x03000000:
-        return path
-    return path.encode(sys.getfilesystemencoding(), 'surrogateescape')
-
-
-def get_repo(alias, url):
-    """Returns a git repository object initialized for usage.
-    """
-
-    repo = GitRepo(url)
-    repo.get_revs()
-    repo.get_head()
-
-    hasher = _digest()
-    hasher.update(encode_filepath(repo.path))
-    repo.hash = hasher.hexdigest()
-
-    repo.get_base_path = lambda base: os.path.join(
-        base, 'info', 'fast-import', repo.hash)
-
-    prefix = 'refs/testgit/%s/' % alias
-    debug("prefix: '%s'", prefix)
-
-    repo.gitdir = os.environ["GIT_DIR"]
-    repo.alias = alias
-    repo.prefix = prefix
-
-    repo.exporter = GitExporter(repo)
-    repo.importer = GitImporter(repo)
-    repo.non_local = NonLocalGit(repo)
-
-    return repo
-
-
-def local_repo(repo, path):
-    """Returns a git repository object initalized for usage.
-    """
-
-    local = GitRepo(path)
-
-    local.non_local = None
-    local.gitdir = repo.gitdir
-    local.alias = repo.alias
-    local.prefix = repo.prefix
-    local.hash = repo.hash
-    local.get_base_path = repo.get_base_path
-    local.exporter = GitExporter(local)
-    local.importer = GitImporter(local)
-
-    return local
-
-
-def do_capabilities(repo, args):
-    """Prints the supported capabilities.
-    """
-
-    print("import")
-    print("export")
-    print("refspec refs/heads/*:%s*" % repo.prefix)
-
-    dirname = repo.get_base_path(repo.gitdir)
-
-    if not os.path.exists(dirname):
-        os.makedirs(dirname)
-
-    path = os.path.join(dirname, 'git.marks')
-
-    print("*export-marks %s" % path)
-    if os.path.exists(path):
-        print("*import-marks %s" % path)
-
-    print('') # end capabilities
-
-
-def do_list(repo, args):
-    """Lists all known references.
-
-    Bug: This will always set the remote head to master for non-local
-    repositories, since we have no way of determining what the remote
-    head is at clone time.
-    """
-
-    for ref in repo.revs:
-        debug("? refs/heads/%s", ref)
-        print("? refs/heads/%s" % ref)
-
-    if repo.head:
-        debug("@refs/heads/%s HEAD" % repo.head)
-        print("@refs/heads/%s HEAD" % repo.head)
-    else:
-        debug("@refs/heads/master HEAD")
-        print("@refs/heads/master HEAD")
-
-    print('') # end list
-
-
-def update_local_repo(repo):
-    """Updates (or clones) a local repo.
-    """
-
-    if repo.local:
-        return repo
-
-    path = repo.non_local.clone(repo.gitdir)
-    repo.non_local.update(repo.gitdir)
-    repo = local_repo(repo, path)
-    return repo
-
-
-def do_import(repo, args):
-    """Exports a fast-import stream from testgit for git to import.
-    """
-
-    if len(args) != 1:
-        die("Import needs exactly one ref")
-
-    if not repo.gitdir:
-        die("Need gitdir to import")
-
-    ref = args[0]
-    refs = [ref]
-
-    while True:
-        line = sys.stdin.readline().decode()
-        if line == '\n':
-            break
-        if not line.startswith('import '):
-            die("Expected import line.")
-
-        # strip of leading 'import '
-        ref = line[7:].strip()
-        refs.append(ref)
-
-    print("feature done")
-
-    if os.environ.get("GIT_REMOTE_TESTGIT_FAILURE"):
-        die('Told to fail')
-
-    repo = update_local_repo(repo)
-    repo.exporter.export_repo(repo.gitdir, refs)
-
-    print("done")
-
-
-def do_export(repo, args):
-    """Imports a fast-import stream from git to testgit.
-    """
-
-    if not repo.gitdir:
-        die("Need gitdir to export")
-
-    if os.environ.get("GIT_REMOTE_TESTGIT_FAILURE"):
-        die('Told to fail')
-
-    update_local_repo(repo)
-    changed = repo.importer.do_import(repo.gitdir)
-
-    if not repo.local:
-        repo.non_local.push(repo.gitdir)
-
-    for ref in changed:
-        print("ok %s" % ref)
-    print('')
-
-
-COMMANDS = {
-    'capabilities': do_capabilities,
-    'list': do_list,
-    'import': do_import,
-    'export': do_export,
-}
-
-
-def sanitize(value):
-    """Cleans up the url.
-    """
-
-    if value.startswith('testgit::'):
-        value = value[9:]
-
-    return value
-
-
-def read_one_line(repo):
-    """Reads and processes one command.
-    """
-
-    sleepy = os.environ.get("GIT_REMOTE_TESTGIT_SLEEPY")
-    if sleepy:
-        debug("Sleeping %d sec before readline" % int(sleepy))
-        time.sleep(int(sleepy))
-
-    line = sys.stdin.readline()
-
-    cmdline = line.decode()
-
-    if not cmdline:
-        warn("Unexpected EOF")
-        return False
-
-    cmdline = cmdline.strip().split()
-    if not cmdline:
-        # Blank line means we're about to quit
-        return False
-
-    cmd = cmdline.pop(0)
-    debug("Got command '%s' with args '%s'", cmd, ' '.join(cmdline))
-
-    if cmd not in COMMANDS:
-        die("Unknown command, %s", cmd)
-
-    func = COMMANDS[cmd]
-    func(repo, cmdline)
-    sys.stdout.flush()
-
-    return True
-
-
-def main(args):
-    """Starts a new remote helper for the specified repository.
-    """
-
-    if len(args) != 3:
-        die("Expecting exactly three arguments.")
-        sys.exit(1)
-
-    if os.getenv("GIT_DEBUG_TESTGIT"):
-        import git_remote_helpers.util
-        git_remote_helpers.util.DEBUG = True
-
-    alias = sanitize(args[1])
-    url = sanitize(args[2])
-
-    if not alias.isalnum():
-        warn("non-alnum alias '%s'", alias)
-        alias = "tmp"
-
-    args[1] = alias
-    args[2] = url
-
-    repo = get_repo(alias, url)
-
-    debug("Got arguments %s", args[1:])
-
-    more = True
-
-    # Use binary mode since Python 3 does not permit unbuffered I/O in text
-    # mode.  Unbuffered I/O is required to avoid data that should be going
-    # to git-fast-import after an "export" command getting caught in our
-    # stdin buffer instead.
-    sys.stdin = os.fdopen(sys.stdin.fileno(), 'rb', 0)
-    while (more):
-        more = read_one_line(repo)
-
-if __name__ == '__main__':
-    sys.exit(main(sys.argv))
index 2162478392728f156ba6c541cdc69447aa9b0119..3782c3b0cb4f9356790ae581c0d408dc4f4cae75 100755 (executable)
@@ -1234,7 +1234,7 @@ sub send_message {
                                if ($smtp->code == 220) {
                                        $smtp = Net::SMTP::SSL->start_SSL($smtp,
                                                                          ssl_verify_params())
-                                               or die "STARTTLS failed! ".$smtp->message;
+                                               or die "STARTTLS failed! ".IO::Socket::SSL::errstr();
                                        $smtp_encryption = '';
                                        # Send EHLO again to receive fresh
                                        # supported commands
index 2979197087f2c6d97e2945008394d50c16a195a5..896f1c9b820b6627da8d591469172d749bf0e700 100755 (executable)
@@ -1032,13 +1032,20 @@ cmd_summary() {
        # Get modified modules cared by user
        modules=$(git $diff_cmd $cached --ignore-submodules=dirty --raw $head -- "$@" |
                sane_egrep '^:([0-7]* )?160000' |
-               while read mod_src mod_dst sha1_src sha1_dst status name
+               while read mod_src mod_dst sha1_src sha1_dst status sm_path
                do
                        # Always show modules deleted or type-changed (blob<->module)
-                       test $status = D -o $status = T && echo "$name" && continue
+                       test $status = D -o $status = T && echo "$sm_path" && continue
+                       # Respect the ignore setting for --for-status.
+                       if test -n "$for_status"
+                       then
+                               name=$(module_name "$sm_path")
+                               ignore_config=$(get_submodule_config "$name" ignore none)
+                               test $status != A -a $ignore_config = all && continue
+                       fi
                        # Also show added or modified modules which are checked out
-                       GIT_DIR="$name/.git" git-rev-parse --git-dir >/dev/null 2>&1 &&
-                       echo "$name"
+                       GIT_DIR="$sm_path/.git" git-rev-parse --git-dir >/dev/null 2>&1 &&
+                       echo "$sm_path"
                done
        )
 
@@ -1149,18 +1156,7 @@ cmd_summary() {
                        echo
                fi
                echo
-       done |
-       if test -n "$for_status"; then
-               if [ -n "$files" ]; then
-                       gettextln "Submodules changed but not updated:" | git stripspace -c
-               else
-                       gettextln "Submodule changes to be committed:" | git stripspace -c
-               fi
-               printf "\n" | git stripspace -c
-               git stripspace -c
-       else
-               cat
-       fi
+       done
 }
 #
 # List all submodules, prefixed with:
index ff1ce3d351c8e4e175321d45b7284070f9ce691a..7349ffea5ad36f5677e7127fd693a72d155b1fa5 100755 (executable)
@@ -1389,7 +1389,17 @@ sub cmd_multi_init {
                usage(1);
        }
 
-       $_prefix = '' unless defined $_prefix;
+       unless (defined $_prefix) {
+               $_prefix = '';
+               warn <<EOF
+WARNING: --prefix is not given, defaulting to empty prefix.
+         This is probably not what you want! In order to stay compatible
+         with regular remote-tracking refs, provide a prefix like
+         --prefix=origin/ (remember the trailing slash), which will cause
+         the SVN-tracking refs to be placed at refs/remotes/origin/*.
+NOTE: In Git v2.0, the default prefix will change from empty to 'origin/'.
+EOF
+       }
        if (defined $url) {
                $url = canonicalize_url($url);
                init_subdir(@_);
@@ -1759,7 +1769,7 @@ sub get_commit_entry {
                my $msgbuf = "";
                while (<$msg_fh>) {
                        if (!$in_msg) {
-                               $in_msg = 1 if (/^\s*$/);
+                               $in_msg = 1 if (/^$/);
                                $author = $1 if (/^author (.*>)/);
                        } elsif (/^git-svn-id: /) {
                                # skip this for now, we regenerate the
diff --git a/git.c b/git.c
index b3893e73c93c59431516bccb86e12e8f64d39319..1188979465654248c5936e8246886341846cc6f1 100644 (file)
--- a/git.c
+++ b/git.c
@@ -7,7 +7,7 @@
 #include "commit.h"
 
 const char git_usage_string[] =
-       "git [--version] [--help] [-c name=value]\n"
+       "git [--version] [--help] [-C <path>] [-c name=value]\n"
        "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
        "           [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]\n"
        "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
@@ -165,6 +165,17 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
                        set_alternate_shallow_file((*argv)[0]);
                        if (envchanged)
                                *envchanged = 1;
+               } else if (!strcmp(cmd, "-C")) {
+                       if (*argc < 2) {
+                               fprintf(stderr, "No directory given for -C.\n" );
+                               usage(git_usage_string);
+                       }
+                       if (chdir((*argv)[1]))
+                               die_errno("Cannot change to '%s'", (*argv)[1]);
+                       if (envchanged)
+                               *envchanged = 1;
+                       (*argv)++;
+                       (*argc)--;
                } else {
                        fprintf(stderr, "Unknown option: %s\n", cmd);
                        usage(git_usage_string);
diff --git a/git_remote_helpers/.gitignore b/git_remote_helpers/.gitignore
deleted file mode 100644 (file)
index cf040af..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-/GIT-PYTHON-VERSION
-/build
-/dist
diff --git a/git_remote_helpers/Makefile b/git_remote_helpers/Makefile
deleted file mode 100644 (file)
index 3d12232..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#
-# Makefile for the git_remote_helpers python support modules
-#
-pysetupfile:=setup.py
-
-# Shell quote (do not use $(call) to accommodate ancient setups);
-DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
-
-ifndef PYTHON_PATH
-       ifeq ($(uname_S),FreeBSD)
-               PYTHON_PATH = /usr/local/bin/python
-       else
-               PYTHON_PATH = /usr/bin/python
-       endif
-endif
-ifndef prefix
-       prefix = $(HOME)
-endif
-ifndef V
-       QUIET = @
-       QUIETSETUP = --quiet
-endif
-
-PYLIBDIR=$(shell $(PYTHON_PATH) -c \
-        "import sys; \
-        print('lib/python%i.%i/site-packages' % sys.version_info[:2])")
-
-py_version=$(shell $(PYTHON_PATH) -c \
-       'import sys; print("%i.%i" % sys.version_info[:2])')
-
-all: $(pysetupfile)
-       $(QUIET)test "$$(cat GIT-PYTHON-VERSION 2>/dev/null)" = "$(py_version)" || \
-       flags=--force; \
-       $(PYTHON_PATH) $(pysetupfile) $(QUIETSETUP) build $$flags
-       $(QUIET)echo "$(py_version)" >GIT-PYTHON-VERSION
-
-install: $(pysetupfile)
-       $(PYTHON_PATH) $(pysetupfile) install --prefix $(DESTDIR_SQ)$(prefix)
-
-instlibdir: $(pysetupfile)
-       @echo "$(DESTDIR_SQ)$(prefix)/$(PYLIBDIR)"
-
-clean:
-       $(QUIET)$(PYTHON_PATH) $(pysetupfile) $(QUIETSETUP) clean -a
-       $(RM) *.pyo *.pyc GIT-PYTHON-VERSION
diff --git a/git_remote_helpers/__init__.py b/git_remote_helpers/__init__.py
deleted file mode 100644 (file)
index 00f69cb..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env python
-
-"""Support library package for git remote helpers.
-
-Git remote helpers are helper commands that interfaces with a non-git
-repository to provide automatic import of non-git history into a Git
-repository.
-
-This package provides the support library needed by these helpers..
-The following modules are included:
-
-- git.git - Interaction with Git repositories
-
-- util - General utility functionality use by the other modules in
-         this package, and also used directly by the helpers.
-"""
diff --git a/git_remote_helpers/git/__init__.py b/git_remote_helpers/git/__init__.py
deleted file mode 100644 (file)
index 1dbb1b0..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-import sys
-if sys.hexversion < 0x02040000:
-    # The limiter is the subprocess module
-    sys.stderr.write("git_remote_helpers: requires Python 2.4 or later.\n")
-    sys.exit(1)
diff --git a/git_remote_helpers/git/exporter.py b/git_remote_helpers/git/exporter.py
deleted file mode 100644 (file)
index 9ee5f96..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-import os
-import subprocess
-import sys
-
-from git_remote_helpers.util import check_call
-
-
-class GitExporter(object):
-    """An exporter for testgit repositories.
-
-    The exporter simply delegates to git fast-export.
-    """
-
-    def __init__(self, repo):
-        """Creates a new exporter for the specified repo.
-        """
-
-        self.repo = repo
-
-    def export_repo(self, base, refs=None):
-        """Exports a fast-export stream for the given directory.
-
-        Simply delegates to git fast-epxort and pipes it through sed
-        to make the refs show up under the prefix rather than the
-        default refs/heads. This is to demonstrate how the export
-        data can be stored under it's own ref (using the refspec
-        capability).
-
-        If None, refs defaults to ["HEAD"].
-        """
-
-        if not refs:
-            refs = ["HEAD"]
-
-        dirname = self.repo.get_base_path(base)
-        path = os.path.abspath(os.path.join(dirname, 'testgit.marks'))
-
-        if not os.path.exists(dirname):
-            os.makedirs(dirname)
-
-        print "feature relative-marks"
-        if os.path.exists(os.path.join(dirname, 'git.marks')):
-            print "feature import-marks=%s/git.marks" % self.repo.hash
-        print "feature export-marks=%s/git.marks" % self.repo.hash
-        sys.stdout.flush()
-
-        args = ["git", "--git-dir=" + self.repo.gitpath, "fast-export", "--export-marks=" + path]
-
-        if os.path.exists(path):
-            args.append("--import-marks=" + path)
-
-        args.extend(refs)
-
-        p1 = subprocess.Popen(args, stdout=subprocess.PIPE)
-
-        args = ["sed", "s_refs/heads/_" + self.repo.prefix + "_g"]
-
-        check_call(args, stdin=p1.stdout)
diff --git a/git_remote_helpers/git/git.py b/git_remote_helpers/git/git.py
deleted file mode 100644 (file)
index 007a1bf..0000000
+++ /dev/null
@@ -1,678 +0,0 @@
-#!/usr/bin/env python
-
-"""Functionality for interacting with Git repositories.
-
-This module provides classes for interfacing with a Git repository.
-"""
-
-import os
-import re
-import time
-from binascii import hexlify
-from cStringIO import StringIO
-import unittest
-
-from git_remote_helpers.util import debug, error, die, start_command, run_command
-
-
-def get_git_dir ():
-    """Return the path to the GIT_DIR for this repo."""
-    args = ("git", "rev-parse", "--git-dir")
-    exit_code, output, errors = run_command(args)
-    if exit_code:
-        die("Failed to retrieve git dir")
-    assert not errors
-    return output.strip()
-
-
-def parse_git_config ():
-    """Return a dict containing the parsed version of 'git config -l'."""
-    exit_code, output, errors = run_command(("git", "config", "-z", "-l"))
-    if exit_code:
-        die("Failed to retrieve git configuration")
-    assert not errors
-    return dict([e.split('\n', 1) for e in output.split("\0") if e])
-
-
-def git_config_bool (value):
-    """Convert the given git config string value to True or False.
-
-    Raise ValueError if the given string was not recognized as a
-    boolean value.
-
-    """
-    norm_value = str(value).strip().lower()
-    if norm_value in ("true", "1", "yes", "on", ""):
-        return True
-    if norm_value in ("false", "0", "no", "off", "none"):
-        return False
-    raise ValueError("Failed to parse '%s' into a boolean value" % (value))
-
-
-def valid_git_ref (ref_name):
-    """Return True iff the given ref name is a valid git ref name."""
-    # The following is a reimplementation of the git check-ref-format
-    # command.  The rules were derived from the git check-ref-format(1)
-    # manual page.  This code should be replaced by a call to
-    # check_refname_format() in the git library, when such is available.
-    if ref_name.endswith('/') or \
-       ref_name.startswith('.') or \
-       ref_name.count('/.') or \
-       ref_name.count('..') or \
-       ref_name.endswith('.lock'):
-        return False
-    for c in ref_name:
-        if ord(c) < 0x20 or ord(c) == 0x7f or c in " ~^:?*[":
-            return False
-    return True
-
-
-class GitObjectFetcher(object):
-
-    """Provide parsed access to 'git cat-file --batch'.
-
-    This provides a read-only interface to the Git object database.
-
-    """
-
-    def __init__ (self):
-        """Initiate a 'git cat-file --batch' session."""
-        self.queue = []  # List of object names to be submitted
-        self.in_transit = None  # Object name currently in transit
-
-        # 'git cat-file --batch' produces binary output which is likely
-        # to be corrupted by the default "rU"-mode pipe opened by
-        # start_command.  (Mode == "rU" does universal new-line
-        # conversion, which mangles carriage returns.) Therefore, we
-        # open an explicitly binary-safe pipe for transferring the
-        # output from 'git cat-file --batch'.
-        pipe_r_fd, pipe_w_fd = os.pipe()
-        pipe_r = os.fdopen(pipe_r_fd, "rb")
-        pipe_w = os.fdopen(pipe_w_fd, "wb")
-        self.proc = start_command(("git", "cat-file", "--batch"),
-                                  stdout = pipe_w)
-        self.f = pipe_r
-
-    def __del__ (self):
-        """Verify completed communication with 'git cat-file --batch'."""
-        assert not self.queue
-        assert self.in_transit is None
-        self.proc.stdin.close()
-        assert self.proc.wait() == 0  # Zero exit code
-        assert self.f.read() == ""  # No remaining output
-
-    def _submit_next_object (self):
-        """Submit queue items to the 'git cat-file --batch' process.
-
-        If there are items in the queue, and there is currently no item
-        currently in 'transit', then pop the first item off the queue,
-        and submit it.
-
-        """
-        if self.queue and self.in_transit is None:
-            self.in_transit = self.queue.pop(0)
-            print >> self.proc.stdin, self.in_transit[0]
-
-    def push (self, obj, callback):
-        """Push the given object name onto the queue.
-
-        The given callback function will at some point in the future
-        be called exactly once with the following arguments:
-        - self - this GitObjectFetcher instance
-        - obj  - the object name provided to push()
-        - sha1 - the SHA1 of the object, if 'None' obj is missing
-        - t    - the type of the object (tag/commit/tree/blob)
-        - size - the size of the object in bytes
-        - data - the object contents
-
-        """
-        self.queue.append((obj, callback))
-        self._submit_next_object()  # (Re)start queue processing
-
-    def process_next_entry (self):
-        """Read the next entry off the queue and invoke callback."""
-        obj, cb = self.in_transit
-        self.in_transit = None
-        header = self.f.readline()
-        if header == "%s missing\n" % (obj):
-            cb(self, obj, None, None, None, None)
-            return
-        sha1, t, size = header.split(" ")
-        assert len(sha1) == 40
-        assert t in ("tag", "commit", "tree", "blob")
-        assert size.endswith("\n")
-        size = int(size.strip())
-        data = self.f.read(size)
-        assert self.f.read(1) == "\n"
-        cb(self, obj, sha1, t, size, data)
-        self._submit_next_object()
-
-    def process (self):
-        """Process the current queue until empty."""
-        while self.in_transit is not None:
-            self.process_next_entry()
-
-    # High-level convenience methods:
-
-    def get_sha1 (self, objspec):
-        """Return the SHA1 of the object specified by 'objspec'.
-
-        Return None if 'objspec' does not specify an existing object.
-
-        """
-        class _ObjHandler(object):
-            """Helper class for getting the returned SHA1."""
-            def __init__ (self, parser):
-                self.parser = parser
-                self.sha1 = None
-
-            def __call__ (self, parser, obj, sha1, t, size, data):
-                # FIXME: Many unused arguments. Could this be cheaper?
-                assert parser == self.parser
-                self.sha1 = sha1
-
-        handler = _ObjHandler(self)
-        self.push(objspec, handler)
-        self.process()
-        return handler.sha1
-
-    def open_obj (self, objspec):
-        """Return a file object wrapping the contents of a named object.
-
-        The caller is responsible for calling .close() on the returned
-        file object.
-
-        Raise KeyError if 'objspec' does not exist in the repo.
-
-        """
-        class _ObjHandler(object):
-            """Helper class for parsing the returned git object."""
-            def __init__ (self, parser):
-                """Set up helper."""
-                self.parser = parser
-                self.contents = StringIO()
-                self.err = None
-
-            def __call__ (self, parser, obj, sha1, t, size, data):
-                """Git object callback (see GitObjectFetcher documentation)."""
-                assert parser == self.parser
-                if not sha1:  # Missing object
-                    self.err = "Missing object '%s'" % obj
-                else:
-                    assert size == len(data)
-                    self.contents.write(data)
-
-        handler = _ObjHandler(self)
-        self.push(objspec, handler)
-        self.process()
-        if handler.err:
-            raise KeyError(handler.err)
-        handler.contents.seek(0)
-        return handler.contents
-
-    def walk_tree (self, tree_objspec, callback, prefix = ""):
-        """Recursively walk the given Git tree object.
-
-        Recursively walk all subtrees of the given tree object, and
-        invoke the given callback passing three arguments:
-        (path, mode, data) with the path, permission bits, and contents
-        of all the blobs found in the entire tree structure.
-
-        """
-        class _ObjHandler(object):
-            """Helper class for walking a git tree structure."""
-            def __init__ (self, parser, cb, path, mode = None):
-                """Set up helper."""
-                self.parser = parser
-                self.cb = cb
-                self.path = path
-                self.mode = mode
-                self.err = None
-
-            def parse_tree (self, treedata):
-                """Parse tree object data, yield tree entries.
-
-                Each tree entry is a 3-tuple (mode, sha1, path)
-
-                self.path is prepended to all paths yielded
-                from this method.
-
-                """
-                while treedata:
-                    mode = int(treedata[:6], 10)
-                    # Turn 100xxx into xxx
-                    if mode > 100000:
-                        mode -= 100000
-                    assert treedata[6] == " "
-                    i = treedata.find("\0", 7)
-                    assert i > 0
-                    path = treedata[7:i]
-                    sha1 = hexlify(treedata[i + 1: i + 21])
-                    yield (mode, sha1, self.path + path)
-                    treedata = treedata[i + 21:]
-
-            def __call__ (self, parser, obj, sha1, t, size, data):
-                """Git object callback (see GitObjectFetcher documentation)."""
-                assert parser == self.parser
-                if not sha1:  # Missing object
-                    self.err = "Missing object '%s'" % (obj)
-                    return
-                assert size == len(data)
-                if t == "tree":
-                    if self.path:
-                        self.path += "/"
-                    # Recurse into all blobs and subtrees
-                    for m, s, p in self.parse_tree(data):
-                        parser.push(s,
-                                    self.__class__(self.parser, self.cb, p, m))
-                elif t == "blob":
-                    self.cb(self.path, self.mode, data)
-                else:
-                    raise ValueError("Unknown object type '%s'" % (t))
-
-        self.push(tree_objspec, _ObjHandler(self, callback, prefix))
-        self.process()
-
-
-class GitRefMap(object):
-
-    """Map Git ref names to the Git object names they currently point to.
-
-    Behaves like a dictionary of Git ref names -> Git object names.
-
-    """
-
-    def __init__ (self, obj_fetcher):
-        """Create a new Git ref -> object map."""
-        self.obj_fetcher = obj_fetcher
-        self._cache = {}  # dict: refname -> objname
-
-    def _load (self, ref):
-        """Retrieve the object currently bound to the given ref.
-
-        The name of the object pointed to by the given ref is stored
-        into this mapping, and also returned.
-
-        """
-        if ref not in self._cache:
-            self._cache[ref] = self.obj_fetcher.get_sha1(ref)
-        return self._cache[ref]
-
-    def __contains__ (self, refname):
-        """Return True if the given refname is present in this cache."""
-        return bool(self._load(refname))
-
-    def __getitem__ (self, refname):
-        """Return the git object name pointed to by the given refname."""
-        commit = self._load(refname)
-        if commit is None:
-            raise KeyError("Unknown ref '%s'" % (refname))
-        return commit
-
-    def get (self, refname, default = None):
-        """Return the git object name pointed to by the given refname."""
-        commit = self._load(refname)
-        if commit is None:
-            return default
-        return commit
-
-
-class GitFICommit(object):
-
-    """Encapsulate the data in a Git fast-import commit command."""
-
-    SHA1RE = re.compile(r'^[0-9a-f]{40}$')
-
-    @classmethod
-    def parse_mode (cls, mode):
-        """Verify the given git file mode, and return it as a string."""
-        assert mode in (644, 755, 100644, 100755, 120000)
-        return "%i" % (mode)
-
-    @classmethod
-    def parse_objname (cls, objname):
-        """Return the given object name (or mark number) as a string."""
-        if isinstance(objname, int):  # Object name is a mark number
-            assert objname > 0
-            return ":%i" % (objname)
-
-        # No existence check is done, only checks for valid format
-        assert cls.SHA1RE.match(objname)  # Object name is valid SHA1
-        return objname
-
-    @classmethod
-    def quote_path (cls, path):
-        """Return a quoted version of the given path."""
-        path = path.replace("\\", "\\\\")
-        path = path.replace("\n", "\\n")
-        path = path.replace('"', '\\"')
-        return '"%s"' % (path)
-
-    @classmethod
-    def parse_path (cls, path):
-        """Verify that the given path is valid, and quote it, if needed."""
-        assert not isinstance(path, int)  # Cannot be a mark number
-
-        # These checks verify the rules on the fast-import man page
-        assert not path.count("//")
-        assert not path.endswith("/")
-        assert not path.startswith("/")
-        assert not path.count("/./")
-        assert not path.count("/../")
-        assert not path.endswith("/.")
-        assert not path.endswith("/..")
-        assert not path.startswith("./")
-        assert not path.startswith("../")
-
-        if path.count('"') + path.count('\n') + path.count('\\'):
-            return cls.quote_path(path)
-        return path
-
-    def __init__ (self, name, email, timestamp, timezone, message):
-        """Create a new Git fast-import commit, with the given metadata."""
-        self.name = name
-        self.email = email
-        self.timestamp = timestamp
-        self.timezone = timezone
-        self.message = message
-        self.pathops = []  # List of path operations in this commit
-
-    def modify (self, mode, blobname, path):
-        """Add a file modification to this Git fast-import commit."""
-        self.pathops.append(("M",
-                             self.parse_mode(mode),
-                             self.parse_objname(blobname),
-                             self.parse_path(path)))
-
-    def delete (self, path):
-        """Add a file deletion to this Git fast-import commit."""
-        self.pathops.append(("D", self.parse_path(path)))
-
-    def copy (self, path, newpath):
-        """Add a file copy to this Git fast-import commit."""
-        self.pathops.append(("C",
-                             self.parse_path(path),
-                             self.parse_path(newpath)))
-
-    def rename (self, path, newpath):
-        """Add a file rename to this Git fast-import commit."""
-        self.pathops.append(("R",
-                             self.parse_path(path),
-                             self.parse_path(newpath)))
-
-    def note (self, blobname, commit):
-        """Add a note object to this Git fast-import commit."""
-        self.pathops.append(("N",
-                             self.parse_objname(blobname),
-                             self.parse_objname(commit)))
-
-    def deleteall (self):
-        """Delete all files in this Git fast-import commit."""
-        self.pathops.append("deleteall")
-
-
-class TestGitFICommit(unittest.TestCase):
-
-    """GitFICommit selftests."""
-
-    def test_basic (self):
-        """GitFICommit basic selftests."""
-
-        def expect_fail (method, data):
-            """Verify that the method(data) raises an AssertionError."""
-            try:
-                method(data)
-            except AssertionError:
-                return
-            raise AssertionError("Failed test for invalid data '%s(%s)'" %
-                                 (method.__name__, repr(data)))
-
-    def test_parse_mode (self):
-        """GitFICommit.parse_mode() selftests."""
-        self.assertEqual(GitFICommit.parse_mode(644), "644")
-        self.assertEqual(GitFICommit.parse_mode(755), "755")
-        self.assertEqual(GitFICommit.parse_mode(100644), "100644")
-        self.assertEqual(GitFICommit.parse_mode(100755), "100755")
-        self.assertEqual(GitFICommit.parse_mode(120000), "120000")
-        self.assertRaises(AssertionError, GitFICommit.parse_mode, 0)
-        self.assertRaises(AssertionError, GitFICommit.parse_mode, 123)
-        self.assertRaises(AssertionError, GitFICommit.parse_mode, 600)
-        self.assertRaises(AssertionError, GitFICommit.parse_mode, "644")
-        self.assertRaises(AssertionError, GitFICommit.parse_mode, "abc")
-
-    def test_parse_objname (self):
-        """GitFICommit.parse_objname() selftests."""
-        self.assertEqual(GitFICommit.parse_objname(1), ":1")
-        self.assertRaises(AssertionError, GitFICommit.parse_objname, 0)
-        self.assertRaises(AssertionError, GitFICommit.parse_objname, -1)
-        self.assertEqual(GitFICommit.parse_objname("0123456789" * 4),
-                         "0123456789" * 4)
-        self.assertEqual(GitFICommit.parse_objname("2468abcdef" * 4),
-                         "2468abcdef" * 4)
-        self.assertRaises(AssertionError, GitFICommit.parse_objname,
-                          "abcdefghij" * 4)
-
-    def test_parse_path (self):
-        """GitFICommit.parse_path() selftests."""
-        self.assertEqual(GitFICommit.parse_path("foo/bar"), "foo/bar")
-        self.assertEqual(GitFICommit.parse_path("path/with\n and \" in it"),
-                         '"path/with\\n and \\" in it"')
-        self.assertRaises(AssertionError, GitFICommit.parse_path, 1)
-        self.assertRaises(AssertionError, GitFICommit.parse_path, 0)
-        self.assertRaises(AssertionError, GitFICommit.parse_path, -1)
-        self.assertRaises(AssertionError, GitFICommit.parse_path, "foo//bar")
-        self.assertRaises(AssertionError, GitFICommit.parse_path, "foo/bar/")
-        self.assertRaises(AssertionError, GitFICommit.parse_path, "/foo/bar")
-        self.assertRaises(AssertionError, GitFICommit.parse_path, "foo/./bar")
-        self.assertRaises(AssertionError, GitFICommit.parse_path, "foo/../bar")
-        self.assertRaises(AssertionError, GitFICommit.parse_path, "foo/bar/.")
-        self.assertRaises(AssertionError, GitFICommit.parse_path, "foo/bar/..")
-        self.assertRaises(AssertionError, GitFICommit.parse_path, "./foo/bar")
-        self.assertRaises(AssertionError, GitFICommit.parse_path, "../foo/bar")
-
-
-class GitFastImport(object):
-
-    """Encapsulate communication with git fast-import."""
-
-    def __init__ (self, f, obj_fetcher, last_mark = 0):
-        """Set up self to communicate with a fast-import process through f."""
-        self.f = f  # File object where fast-import stream is written
-        self.obj_fetcher = obj_fetcher  # GitObjectFetcher instance
-        self.next_mark = last_mark + 1  # Next mark number
-        self.refs = set()  # Keep track of the refnames we've seen
-
-    def comment (self, s):
-        """Write the given comment in the fast-import stream."""
-        assert "\n" not in s, "Malformed comment: '%s'" % (s)
-        self.f.write("# %s\n" % (s))
-
-    def commit (self, ref, commitdata):
-        """Make a commit on the given ref, with the given GitFICommit.
-
-        Return the mark number identifying this commit.
-
-        """
-        self.f.write("""\
-commit %(ref)s
-mark :%(mark)i
-committer %(name)s <%(email)s> %(timestamp)i %(timezone)s
-data %(msgLength)i
-%(msg)s
-""" % {
-    'ref': ref,
-    'mark': self.next_mark,
-    'name': commitdata.name,
-    'email': commitdata.email,
-    'timestamp': commitdata.timestamp,
-    'timezone': commitdata.timezone,
-    'msgLength': len(commitdata.message),
-    'msg': commitdata.message,
-})
-
-        if ref not in self.refs:
-            self.refs.add(ref)
-            parent = ref + "^0"
-            if self.obj_fetcher.get_sha1(parent):
-                self.f.write("from %s\n" % (parent))
-
-        for op in commitdata.pathops:
-            self.f.write(" ".join(op))
-            self.f.write("\n")
-        self.f.write("\n")
-        retval = self.next_mark
-        self.next_mark += 1
-        return retval
-
-    def blob (self, data):
-        """Import the given blob.
-
-        Return the mark number identifying this blob.
-
-        """
-        self.f.write("blob\nmark :%i\ndata %i\n%s\n" %
-                     (self.next_mark, len(data), data))
-        retval = self.next_mark
-        self.next_mark += 1
-        return retval
-
-    def reset (self, ref, objname):
-        """Reset the given ref to point at the given Git object."""
-        self.f.write("reset %s\nfrom %s\n\n" %
-                     (ref, GitFICommit.parse_objname(objname)))
-        if ref not in self.refs:
-            self.refs.add(ref)
-
-
-class GitNotes(object):
-
-    """Encapsulate access to Git notes.
-
-    Simulates a dictionary of object name (SHA1) -> Git note mappings.
-
-    """
-
-    def __init__ (self, notes_ref, obj_fetcher):
-        """Create a new Git notes interface, bound to the given notes ref."""
-        self.notes_ref = notes_ref
-        self.obj_fetcher = obj_fetcher  # Used to get objects from repo
-        self.imports = []  # list: (objname, note data blob name) tuples
-
-    def __del__ (self):
-        """Verify that self.commit_notes() was called before destruction."""
-        if self.imports:
-            error("Missing call to self.commit_notes().")
-            error("%i notes are not committed!", len(self.imports))
-
-    def _load (self, objname):
-        """Return the note data associated with the given git object.
-
-        The note data is returned in string form. If no note is found
-        for the given object, None is returned.
-
-        """
-        try:
-            f = self.obj_fetcher.open_obj("%s:%s" % (self.notes_ref, objname))
-            ret = f.read()
-            f.close()
-        except KeyError:
-            ret = None
-        return ret
-
-    def __getitem__ (self, objname):
-        """Return the note contents associated with the given object.
-
-        Raise KeyError if given object has no associated note.
-
-        """
-        blobdata = self._load(objname)
-        if blobdata is None:
-            raise KeyError("Object '%s' has no note" % (objname))
-        return blobdata
-
-    def get (self, objname, default = None):
-        """Return the note contents associated with the given object.
-
-        Return given default if given object has no associated note.
-
-        """
-        blobdata = self._load(objname)
-        if blobdata is None:
-            return default
-        return blobdata
-
-    def import_note (self, objname, data, gfi):
-        """Tell git fast-import to store data as a note for objname.
-
-        This method uses the given GitFastImport object to create a
-        blob containing the given note data.  Also an entry mapping the
-        given object name to the created blob is stored until
-        commit_notes() is called.
-
-        Note that this method only works if it is later followed by a
-        call to self.commit_notes() (which produces the note commit
-        that refers to the blob produced here).
-
-        """
-        if not data.endswith("\n"):
-            data += "\n"
-        gfi.comment("Importing note for object %s" % (objname))
-        mark = gfi.blob(data)
-        self.imports.append((objname, mark))
-
-    def commit_notes (self, gfi, author, message):
-        """Produce a git fast-import note commit for the imported notes.
-
-        This method uses the given GitFastImport object to create a
-        commit on the notes ref, introducing the notes previously
-        submitted to import_note().
-
-        """
-        if not self.imports:
-            return
-        commitdata = GitFICommit(author[0], author[1],
-                                 time.time(), "0000", message)
-        for objname, blobname in self.imports:
-            assert isinstance(objname, int) and objname > 0
-            assert isinstance(blobname, int) and blobname > 0
-            commitdata.note(blobname, objname)
-        gfi.commit(self.notes_ref, commitdata)
-        self.imports = []
-
-
-class GitCachedNotes(GitNotes):
-
-    """Encapsulate access to Git notes (cached version).
-
-    Only use this class if no caching is done at a higher level.
-
-    Simulates a dictionary of object name (SHA1) -> Git note mappings.
-
-    """
-
-    def __init__ (self, notes_ref, obj_fetcher):
-        """Set up a caching wrapper around GitNotes."""
-        GitNotes.__init__(self, notes_ref, obj_fetcher)
-        self._cache = {}  # Cache: object name -> note data
-
-    def __del__ (self):
-        """Verify that GitNotes' destructor is called."""
-        GitNotes.__del__(self)
-
-    def _load (self, objname):
-        """Extend GitNotes._load() with a local objname -> note cache."""
-        if objname not in self._cache:
-            self._cache[objname] = GitNotes._load(self, objname)
-        return self._cache[objname]
-
-    def import_note (self, objname, data, gfi):
-        """Extend GitNotes.import_note() with a local objname -> note cache."""
-        if not data.endswith("\n"):
-            data += "\n"
-        assert objname not in self._cache
-        self._cache[objname] = data
-        GitNotes.import_note(self, objname, data, gfi)
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/git_remote_helpers/git/importer.py b/git_remote_helpers/git/importer.py
deleted file mode 100644 (file)
index d3f90e1..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-import os
-import subprocess
-
-from git_remote_helpers.util import check_call, check_output
-
-
-class GitImporter(object):
-    """An importer for testgit repositories.
-
-    This importer simply delegates to git fast-import.
-    """
-
-    def __init__(self, repo):
-        """Creates a new importer for the specified repo.
-        """
-
-        self.repo = repo
-
-    def get_refs(self, gitdir):
-        """Returns a dictionary with refs.
-
-        Note that the keys in the returned dictionary are byte strings as
-        read from git.
-        """
-        args = ["git", "--git-dir=" + gitdir, "for-each-ref", "refs/heads"]
-        lines = check_output(args).strip().split('\n'.encode('ascii'))
-        refs = {}
-        for line in lines:
-            value, name = line.split(' '.encode('ascii'))
-            name = name.strip('commit\t'.encode('ascii'))
-            refs[name] = value
-        return refs
-
-    def do_import(self, base):
-        """Imports a fast-import stream to the given directory.
-
-        Simply delegates to git fast-import.
-        """
-
-        dirname = self.repo.get_base_path(base)
-        if self.repo.local:
-            gitdir = self.repo.gitpath
-        else:
-            gitdir = os.path.abspath(os.path.join(dirname, '.git'))
-        path = os.path.abspath(os.path.join(dirname, 'testgit.marks'))
-
-        if not os.path.exists(dirname):
-            os.makedirs(dirname)
-
-        refs_before = self.get_refs(gitdir)
-
-        args = ["git", "--git-dir=" + gitdir, "fast-import", "--quiet", "--export-marks=" + path]
-
-        if os.path.exists(path):
-            args.append("--import-marks=" + path)
-
-        check_call(args)
-
-        refs_after = self.get_refs(gitdir)
-
-        changed = {}
-
-        for name, value in refs_after.iteritems():
-            if refs_before.get(name) == value:
-                continue
-
-            changed[name] = value
-
-        return changed
diff --git a/git_remote_helpers/git/non_local.py b/git_remote_helpers/git/non_local.py
deleted file mode 100644 (file)
index e700250..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-import os
-import subprocess
-
-from git_remote_helpers.util import check_call, die, warn
-
-
-class NonLocalGit(object):
-    """Handler to interact with non-local repos.
-    """
-
-    def __init__(self, repo):
-        """Creates a new non-local handler for the specified repo.
-        """
-
-        self.repo = repo
-
-    def clone(self, base):
-        """Clones the non-local repo to base.
-
-        Does nothing if a clone already exists.
-        """
-
-        path = os.path.join(self.repo.get_base_path(base), '.git')
-
-        # already cloned
-        if os.path.exists(path):
-            return path
-
-        os.makedirs(path)
-        args = ["git", "clone", "--bare", "--quiet", self.repo.gitpath, path]
-
-        check_call(args)
-
-        return path
-
-    def update(self, base):
-        """Updates checkout of the non-local repo in base.
-        """
-
-        path = os.path.join(self.repo.get_base_path(base), '.git')
-
-        if not os.path.exists(path):
-            die("could not find repo at %s", path)
-
-        args = ["git", "--git-dir=" + path, "fetch", "--quiet", self.repo.gitpath]
-        check_call(args)
-
-        args = ["git", "--git-dir=" + path, "update-ref", "refs/heads/master", "FETCH_HEAD"]
-        child = check_call(args)
-
-    def push(self, base):
-        """Pushes from the non-local repo to base.
-        """
-
-        path = os.path.join(self.repo.get_base_path(base), '.git')
-
-        if not os.path.exists(path):
-            die("could not find repo at %s", path)
-
-        args = ["git", "--git-dir=" + path, "push", "--quiet", self.repo.gitpath, "--all"]
-        child = check_call(args)
diff --git a/git_remote_helpers/git/repo.py b/git_remote_helpers/git/repo.py
deleted file mode 100644 (file)
index acbf8d7..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-import os
-import subprocess
-
-from git_remote_helpers.util import check_call
-
-
-def sanitize(rev, sep='\t'):
-    """Converts a for-each-ref line to a name/value pair.
-    """
-
-    splitrev = rev.split(sep)
-    branchval = splitrev[0]
-    branchname = splitrev[1].strip()
-    if branchname.startswith("refs/heads/"):
-        branchname = branchname[11:]
-
-    return branchname, branchval
-
-def is_remote(url):
-    """Checks whether the specified value is a remote url.
-    """
-
-    prefixes = ["http", "file", "git"]
-
-    for prefix in prefixes:
-        if url.startswith(prefix):
-            return True
-    return False
-
-class GitRepo(object):
-    """Repo object representing a repo.
-    """
-
-    def __init__(self, path):
-        """Initializes a new repo at the given path.
-        """
-
-        self.path = path
-        self.head = None
-        self.revmap = {}
-        self.local = not is_remote(self.path)
-
-        if(self.path.endswith('.git')):
-            self.gitpath = self.path
-        else:
-            self.gitpath = os.path.join(self.path, '.git')
-
-        if self.local and not os.path.exists(self.gitpath):
-            os.makedirs(self.gitpath)
-
-    def get_revs(self):
-        """Fetches all revs from the remote.
-        """
-
-        args = ["git", "ls-remote", self.gitpath]
-        path = ".cached_revs"
-        ofile = open(path, "w")
-
-        check_call(args, stdout=ofile)
-        output = open(path).readlines()
-        self.revmap = dict(sanitize(i) for i in output)
-        if "HEAD" in self.revmap:
-            del self.revmap["HEAD"]
-        self.revs = self.revmap.keys()
-        ofile.close()
-
-    def get_head(self):
-        """Determines the head of a local repo.
-        """
-
-        if not self.local:
-            return
-
-        path = os.path.join(self.gitpath, "HEAD")
-        head = open(path).readline()
-        self.head, _ = sanitize(head, ' ')
diff --git a/git_remote_helpers/setup.cfg b/git_remote_helpers/setup.cfg
deleted file mode 100644 (file)
index 4bff887..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-[build]
-build_purelib = build/lib
-build_platlib = build/lib
diff --git a/git_remote_helpers/setup.py b/git_remote_helpers/setup.py
deleted file mode 100644 (file)
index 6de41de..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env python
-
-"""Distutils build/install script for the git_remote_helpers package."""
-
-from distutils.core import setup
-
-# If building under Python3 we need to run 2to3 on the code, do this by
-# trying to import distutils' 2to3 builder, which is only available in
-# Python3.
-try:
-    from distutils.command.build_py import build_py_2to3 as build_py
-except ImportError:
-    # 2.x
-    from distutils.command.build_py import build_py
-
-setup(
-    name = 'git_remote_helpers',
-    version = '0.1.0',
-    description = 'Git remote helper program for non-git repositories',
-    license = 'GPLv2',
-    author = 'The Git Community',
-    author_email = 'git@vger.kernel.org',
-    url = 'http://www.git-scm.com/',
-    package_dir = {'git_remote_helpers': ''},
-    packages = ['git_remote_helpers', 'git_remote_helpers.git'],
-    cmdclass = {'build_py': build_py},
-)
diff --git a/git_remote_helpers/util.py b/git_remote_helpers/util.py
deleted file mode 100644 (file)
index fbbb01b..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-#!/usr/bin/env python
-
-"""Misc. useful functionality used by the rest of this package.
-
-This module provides common functionality used by the other modules in
-this package.
-
-"""
-
-import sys
-import os
-import subprocess
-
-try:
-    from subprocess import CalledProcessError
-except ImportError:
-    # from python2.7:subprocess.py
-    # Exception classes used by this module.
-    class CalledProcessError(Exception):
-        """This exception is raised when a process run by check_call() returns
-        a non-zero exit status.  The exit status will be stored in the
-        returncode attribute."""
-        def __init__(self, returncode, cmd):
-            self.returncode = returncode
-            self.cmd = cmd
-        def __str__(self):
-            return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
-
-
-# Whether or not to show debug messages
-DEBUG = False
-
-def notify(msg, *args):
-    """Print a message to stderr."""
-    print >> sys.stderr, msg % args
-
-def debug (msg, *args):
-    """Print a debug message to stderr when DEBUG is enabled."""
-    if DEBUG:
-        print >> sys.stderr, msg % args
-
-def error (msg, *args):
-    """Print an error message to stderr."""
-    print >> sys.stderr, "ERROR:", msg % args
-
-def warn(msg, *args):
-    """Print a warning message to stderr."""
-    print >> sys.stderr, "warning:", msg % args
-
-def die (msg, *args):
-    """Print as error message to stderr and exit the program."""
-    error(msg, *args)
-    sys.exit(1)
-
-
-class ProgressIndicator(object):
-
-    """Simple progress indicator.
-
-    Displayed as a spinning character by default, but can be customized
-    by passing custom messages that overrides the spinning character.
-
-    """
-
-    States = ("|", "/", "-", "\\")
-
-    def __init__ (self, prefix = "", f = sys.stdout):
-        """Create a new ProgressIndicator, bound to the given file object."""
-        self.n = 0  # Simple progress counter
-        self.f = f  # Progress is written to this file object
-        self.prev_len = 0  # Length of previous msg (to be overwritten)
-        self.prefix = prefix  # Prefix prepended to each progress message
-        self.prefix_lens = [] # Stack of prefix string lengths
-
-    def pushprefix (self, prefix):
-        """Append the given prefix onto the prefix stack."""
-        self.prefix_lens.append(len(self.prefix))
-        self.prefix += prefix
-
-    def popprefix (self):
-        """Remove the last prefix from the prefix stack."""
-        prev_len = self.prefix_lens.pop()
-        self.prefix = self.prefix[:prev_len]
-
-    def __call__ (self, msg = None, lf = False):
-        """Indicate progress, possibly with a custom message."""
-        if msg is None:
-            msg = self.States[self.n % len(self.States)]
-        msg = self.prefix + msg
-        print >> self.f, "\r%-*s" % (self.prev_len, msg),
-        self.prev_len = len(msg.expandtabs())
-        if lf:
-            print >> self.f
-            self.prev_len = 0
-        self.n += 1
-
-    def finish (self, msg = "done", noprefix = False):
-        """Finalize progress indication with the given message."""
-        if noprefix:
-            self.prefix = ""
-        self(msg, True)
-
-
-def start_command (args, cwd = None, shell = False, add_env = None,
-                   stdin = subprocess.PIPE, stdout = subprocess.PIPE,
-                   stderr = subprocess.PIPE):
-    """Start the given command, and return a subprocess object.
-
-    This provides a simpler interface to the subprocess module.
-
-    """
-    env = None
-    if add_env is not None:
-        env = os.environ.copy()
-        env.update(add_env)
-    return subprocess.Popen(args, bufsize = 1, stdin = stdin, stdout = stdout,
-                            stderr = stderr, cwd = cwd, shell = shell,
-                            env = env, universal_newlines = True)
-
-
-def run_command (args, cwd = None, shell = False, add_env = None,
-                 flag_error = True):
-    """Run the given command to completion, and return its results.
-
-    This provides a simpler interface to the subprocess module.
-
-    The results are formatted as a 3-tuple: (exit_code, output, errors)
-
-    If flag_error is enabled, Error messages will be produced if the
-    subprocess terminated with a non-zero exit code and/or stderr
-    output.
-
-    The other arguments are passed on to start_command().
-
-    """
-    process = start_command(args, cwd, shell, add_env)
-    (output, errors) = process.communicate()
-    exit_code = process.returncode
-    if flag_error and errors:
-        error("'%s' returned errors:\n---\n%s---", " ".join(args), errors)
-    if flag_error and exit_code:
-        error("'%s' returned exit code %i", " ".join(args), exit_code)
-    return (exit_code, output, errors)
-
-
-# from python2.7:subprocess.py
-def call(*popenargs, **kwargs):
-    """Run command with arguments.  Wait for command to complete, then
-    return the returncode attribute.
-
-    The arguments are the same as for the Popen constructor.  Example:
-
-    retcode = call(["ls", "-l"])
-    """
-    return subprocess.Popen(*popenargs, **kwargs).wait()
-
-
-# from python2.7:subprocess.py
-def check_call(*popenargs, **kwargs):
-    """Run command with arguments.  Wait for command to complete.  If
-    the exit code was zero then return, otherwise raise
-    CalledProcessError.  The CalledProcessError object will have the
-    return code in the returncode attribute.
-
-    The arguments are the same as for the Popen constructor.  Example:
-
-    check_call(["ls", "-l"])
-    """
-    retcode = call(*popenargs, **kwargs)
-    if retcode:
-        cmd = kwargs.get("args")
-        if cmd is None:
-            cmd = popenargs[0]
-        raise CalledProcessError(retcode, cmd)
-    return 0
-
-
-# from python2.7:subprocess.py
-def check_output(*popenargs, **kwargs):
-    r"""Run command with arguments and return its output as a byte string.
-
-    If the exit code was non-zero it raises a CalledProcessError.  The
-    CalledProcessError object will have the return code in the returncode
-    attribute and output in the output attribute.
-
-    The arguments are the same as for the Popen constructor.  Example:
-
-    >>> check_output(["ls", "-l", "/dev/null"])
-    'crw-rw-rw- 1 root root 1, 3 Oct 18  2007 /dev/null\n'
-
-    The stdout argument is not allowed as it is used internally.
-    To capture standard error in the result, use stderr=STDOUT.
-
-    >>> check_output(["/bin/sh", "-c",
-    ...               "ls -l non_existent_file ; exit 0"],
-    ...              stderr=STDOUT)
-    'ls: non_existent_file: No such file or directory\n'
-    """
-    if 'stdout' in kwargs:
-        raise ValueError('stdout argument not allowed, it will be overridden.')
-    process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
-    output, unused_err = process.communicate()
-    retcode = process.poll()
-    if retcode:
-        cmd = kwargs.get("args")
-        if cmd is None:
-            cmd = popenargs[0]
-        raise subprocess.CalledProcessError(retcode, cmd)
-    return output
-
-
-def file_reader_method (missing_ok = False):
-    """Decorator for simplifying reading of files.
-
-    If missing_ok is True, a failure to open a file for reading will
-    not raise the usual IOError, but instead the wrapped method will be
-    called with f == None.  The method must in this case properly
-    handle f == None.
-
-    """
-    def _wrap (method):
-        """Teach given method to handle both filenames and file objects.
-
-        The given method must take a file object as its second argument
-        (the first argument being 'self', of course).  This decorator
-        will take a filename given as the second argument and promote
-        it to a file object.
-
-        """
-        def _wrapped_method (self, filename, *args, **kwargs):
-            if isinstance(filename, file):
-                f = filename
-            else:
-                try:
-                    f = open(filename, 'r')
-                except IOError:
-                    if missing_ok:
-                        f = None
-                    else:
-                        raise
-            try:
-                return method(self, f, *args, **kwargs)
-            finally:
-                if not isinstance(filename, file) and f:
-                    f.close()
-        return _wrapped_method
-    return _wrap
-
-
-def file_writer_method (method):
-    """Decorator for simplifying writing of files.
-
-    Enables the given method to handle both filenames and file objects.
-
-    The given method must take a file object as its second argument
-    (the first argument being 'self', of course).  This decorator will
-    take a filename given as the second argument and promote it to a
-    file object.
-
-    """
-    def _new_method (self, filename, *args, **kwargs):
-        if isinstance(filename, file):
-            f = filename
-        else:
-            # Make sure the containing directory exists
-            parent_dir = os.path.dirname(filename)
-            if not os.path.isdir(parent_dir):
-                os.makedirs(parent_dir)
-            f = open(filename, 'w')
-        try:
-            return method(self, f, *args, **kwargs)
-        finally:
-            if not isinstance(filename, file):
-                f.close()
-    return _new_method
index f429f75897ed10684d017aeaeb93f1c9d9478e0b..68c77f6f8ffd120f0011eb07accdc2849afca834 100755 (executable)
@@ -4035,8 +4035,8 @@ sub print_search_form {
              $cgi->input({-name=>"h", -value=>$search_hash, -type=>"hidden"}) . "\n" .
              $cgi->popup_menu(-name => 'st', -default => 'commit',
                               -values => ['commit', 'grep', 'author', 'committer', 'pickaxe']) .
-             $cgi->sup($cgi->a({-href => href(action=>"search_help")}, "?")) .
-             " search:\n",
+             " " . $cgi->a({-href => href(action=>"search_help"),
+                            -title => "search help" }, "?") . " search:\n",
              $cgi->textfield(-name => "s", -value => $searchtext, -override => 1) . "\n" .
              "<span title=\"Extended regular expression\">" .
              $cgi->checkbox(-name => 'sr', -value => 1, -label => 're',
@@ -6468,7 +6468,7 @@ sub git_summary {
        print "<div class=\"title\">&nbsp;</div>\n";
        print "<table class=\"projects_list\">\n" .
              "<tr id=\"metadata_desc\"><td>description</td><td>" . esc_html($descr) . "</td></tr>\n";
-        unless ($omit_owner) {
+        if ($owner and not $omit_owner) {
                print  "<tr id=\"metadata_owner\"><td>owner</td><td>" . esc_html($owner) . "</td></tr>\n";
         }
        if (defined $cd{'rfc2822'}) {
@@ -6631,6 +6631,7 @@ sub git_blame_common {
                        $hash_base, '--', $file_name
                        or die_error(500, "Open git-blame --porcelain failed");
        }
+       binmode $fd, ':utf8';
 
        # incremental blame data returns early
        if ($format eq 'data') {
index cb86d2d029637ec64f70cc9e1cdbeeea972e8771..3b4d83382306772ac0b62743b0e23094f3d9f257 100644 (file)
@@ -68,12 +68,13 @@ div.page_path {
 }
 
 div.page_footer {
-       height: 17px;
+       height: 22px;
        padding: 4px 8px;
        background-color: #d9d8d1;
 }
 
 div.page_footer_text {
+       line-height: 22px;
        float: left;
        color: #555555;
        font-style: italic;
@@ -548,8 +549,7 @@ a.linenr {
 
 a.rss_logo {
        float: right;
-       padding: 3px 0px;
-       width: 35px;
+       padding: 3px 5px;
        line-height: 10px;
        border: 1px solid;
        border-color: #fcc7a5 #7d3302 #3e1a01 #ff954e;
index 03244172977ba44399383c5b22f90877c94da964..8c464bd8051ed813175b01f832e5e78a91bba8ea 100644 (file)
@@ -594,9 +594,11 @@ int main(int argc, char **argv)
 
                        if (strcmp(method, c->method)) {
                                const char *proto = getenv("SERVER_PROTOCOL");
-                               if (proto && !strcmp(proto, "HTTP/1.1"))
+                               if (proto && !strcmp(proto, "HTTP/1.1")) {
                                        http_status(405, "Method Not Allowed");
-                               else
+                                       hdr_str("Allow", !strcmp(c->method, "GET") ?
+                                               "GET, HEAD" : c->method);
+                               } else
                                        http_status(400, "Bad Request");
                                hdr_nocache();
                                end_headers();
index 6dad188b5f31d47fdce86e5104aa3c6b899ebed7..69200baf7651c2bcb99d6bc2068429e22865f900 100644 (file)
@@ -1330,8 +1330,7 @@ static struct object_list **process_tree(struct tree *tree,
                        break;
                }
 
-       free(tree->buffer);
-       tree->buffer = NULL;
+       free_tree_buffer(tree);
        return p;
 }
 
@@ -1976,7 +1975,7 @@ int main(int argc, char **argv)
                pushing = 0;
                if (prepare_revision_walk(&revs))
                        die("revision walk setup failed");
-               mark_edges_uninteresting(revs.commits, &revs, NULL);
+               mark_edges_uninteresting(&revs, NULL);
                objects_to_send = get_delta(&revs, ref_lock);
                finish_all_active_slots();
 
index 3dd4a960190a1b0016b26dec9187692111b73e3f..6cbedf0280076d8fe6e49241d89938955ecddead 100644 (file)
@@ -123,8 +123,7 @@ static void process_tree(struct rev_info *revs,
                                     cb_data);
        }
        strbuf_setlen(base, baselen);
-       free(tree->buffer);
-       tree->buffer = NULL;
+       free_tree_buffer(tree);
 }
 
 static void mark_edge_parents_uninteresting(struct commit *commit,
@@ -145,19 +144,35 @@ static void mark_edge_parents_uninteresting(struct commit *commit,
        }
 }
 
-void mark_edges_uninteresting(struct commit_list *list,
-                             struct rev_info *revs,
-                             show_edge_fn show_edge)
+void mark_edges_uninteresting(struct rev_info *revs, show_edge_fn show_edge)
 {
-       for ( ; list; list = list->next) {
+       struct commit_list *list;
+       int i;
+
+       for (list = revs->commits; list; list = list->next) {
                struct commit *commit = list->item;
 
                if (commit->object.flags & UNINTERESTING) {
                        mark_tree_uninteresting(commit->tree);
+                       if (revs->edge_hint && !(commit->object.flags & SHOWN)) {
+                               commit->object.flags |= SHOWN;
+                               show_edge(commit);
+                       }
                        continue;
                }
                mark_edge_parents_uninteresting(commit, revs, show_edge);
        }
+       for (i = 0; i < revs->cmdline.nr; i++) {
+               struct object *obj = revs->cmdline.rev[i].item;
+               struct commit *commit = (struct commit *)obj;
+               if (obj->type != OBJ_COMMIT || !(obj->flags & UNINTERESTING))
+                       continue;
+               mark_tree_uninteresting(commit->tree);
+               if (revs->edge_hint && !(obj->flags & SHOWN)) {
+                       obj->flags |= SHOWN;
+                       show_edge(commit);
+               }
+       }
 }
 
 static void add_pending_tree(struct rev_info *revs, struct tree *tree)
index 3db7bb6fa386df2ccb73b78ee72881f32074a1b8..136a1da5a6f048c0f4645112cdbf29c7b0982526 100644 (file)
@@ -6,6 +6,6 @@ typedef void (*show_object_fn)(struct object *, const struct name_path *, const
 void traverse_commit_list(struct rev_info *, show_commit_fn, show_object_fn, void *);
 
 typedef void (*show_edge_fn)(struct commit *);
-void mark_edges_uninteresting(struct commit_list *, struct rev_info *, show_edge_fn);
+void mark_edges_uninteresting(struct rev_info *, show_edge_fn);
 
 #endif
index 30614343213442806c5fbc28e904639d35c670cf..81890a6680029ec1d369a7eef11a4ec112847fb7 100644 (file)
--- a/mailmap.c
+++ b/mailmap.c
@@ -52,6 +52,20 @@ static void free_mailmap_entry(void *p, const char *s)
        string_list_clear_func(&me->namemap, free_mailmap_info);
 }
 
+/*
+ * On some systems (e.g. MinGW 4.0), string.h has _only_ inline
+ * definition of strcasecmp and no non-inline implementation is
+ * supplied anywhere, which is, eh, "unusual"; we cannot take an
+ * address of such a function to store it in namemap.cmp.  This is
+ * here as a workaround---do not assign strcasecmp directly to
+ * namemap.cmp until we know no systems that matter have such an
+ * "unusual" string.h.
+ */
+static int namemap_cmp(const char *a, const char *b)
+{
+       return strcasecmp(a, b);
+}
+
 static void add_mapping(struct string_list *map,
                        char *new_name, char *new_email,
                        char *old_name, char *old_email)
@@ -75,7 +89,7 @@ static void add_mapping(struct string_list *map,
                item = string_list_insert_at_index(map, index, old_email);
                me = xcalloc(1, sizeof(struct mailmap_entry));
                me->namemap.strdup_strings = 1;
-               me->namemap.cmp = strcasecmp;
+               me->namemap.cmp = namemap_cmp;
                item->util = me;
        }
 
@@ -153,8 +167,7 @@ static void read_mailmap_line(struct string_list *map, char *buffer,
                if (!strncmp(buffer, abbrev, abblen)) {
                        char *cp;
 
-                       if (repo_abbrev)
-                               free(*repo_abbrev);
+                       free(*repo_abbrev);
                        *repo_abbrev = xmalloc(len);
 
                        for (cp = buffer + abblen; isspace(*cp); cp++)
@@ -238,7 +251,7 @@ int read_mailmap(struct string_list *map, char **repo_abbrev)
        int err = 0;
 
        map->strdup_strings = 1;
-       map->cmp = strcasecmp;
+       map->cmp = namemap_cmp;
 
        if (!git_mailmap_blob && is_bare_repository())
                git_mailmap_blob = "HEAD:.mailmap";
index 40eb840a52acce0d21a17ce5a898e93f164aef97..dbb7104c043b14f2a43d67e1ca87ce88f4a55408 100644 (file)
@@ -2069,8 +2069,8 @@ int parse_merge_opt(struct merge_options *o, const char *s)
                o->xdl_opts = DIFF_WITH_ALG(o, PATIENCE_DIFF);
        else if (!strcmp(s, "histogram"))
                o->xdl_opts = DIFF_WITH_ALG(o, HISTOGRAM_DIFF);
-       else if (!strcmp(s, "diff-algorithm=")) {
-               long value = parse_algorithm_value(s+15);
+       else if (!prefixcmp(s, "diff-algorithm=")) {
+               long value = parse_algorithm_value(s + strlen("diff-algorithm="));
                if (value < 0)
                        return -1;
                /* clear out previous settings */
diff --git a/mergetools/diffmerge b/mergetools/diffmerge
new file mode 100644 (file)
index 0000000..85ac720
--- /dev/null
@@ -0,0 +1,15 @@
+diff_cmd () {
+       "$merge_tool_path" "$LOCAL" "$REMOTE" >/dev/null 2>&1
+}
+
+merge_cmd () {
+       if $base_present
+       then
+               "$merge_tool_path" --merge --result="$MERGED" \
+                       "$LOCAL" "$BASE" "$REMOTE"
+       else
+               "$merge_tool_path" --merge \
+                       --result="$MERGED" "$LOCAL" "$REMOTE"
+       fi
+       status=$?
+}
index b4cb1bfb4332a7e370071ac6699a9cf48e4da44c..564e30cccd550f9acbd493f43c940bab1abba427 100644 (file)
@@ -9,7 +9,7 @@
  * Properties of the created commit:
  * - tree: the result of converting t to a tree object with write_notes_tree().
  * - parents: the given parents OR (if NULL) the commit referenced by t->ref.
- * - author/committer: the default determined by commmit_tree().
+ * - author/committer: the default determined by commit_tree().
  * - commit message: msg
  *
  * The resulting commit SHA1 is stored in result_sha1.
index d8a4b1ffbe68d6e9f720e979168f9d010c9c5a06..5f792cbfd38c0b30d763902ba5f9399992ddab89 100644 (file)
--- a/object.c
+++ b/object.c
@@ -43,16 +43,17 @@ int type_from_string(const char *str)
        die("invalid object type \"%s\"", str);
 }
 
-static unsigned int hash_obj(struct object *obj, unsigned int n)
+static unsigned int hash_obj(const unsigned char *sha1, unsigned int n)
 {
        unsigned int hash;
-       memcpy(&hash, obj->sha1, sizeof(unsigned int));
-       return hash % n;
+       memcpy(&hash, sha1, sizeof(unsigned int));
+       /* Assumes power-of-2 hash sizes in grow_object_hash */
+       return hash & (n - 1);
 }
 
 static void insert_obj_hash(struct object *obj, struct object **hash, unsigned int size)
 {
-       unsigned int j = hash_obj(obj, size);
+       unsigned int j = hash_obj(obj->sha1, size);
 
        while (hash[j]) {
                j++;
@@ -62,13 +63,6 @@ static void insert_obj_hash(struct object *obj, struct object **hash, unsigned i
        hash[j] = obj;
 }
 
-static unsigned int hashtable_index(const unsigned char *sha1)
-{
-       unsigned int i;
-       memcpy(&i, sha1, sizeof(unsigned int));
-       return i % obj_hash_size;
-}
-
 struct object *lookup_object(const unsigned char *sha1)
 {
        unsigned int i, first;
@@ -77,7 +71,7 @@ struct object *lookup_object(const unsigned char *sha1)
        if (!obj_hash)
                return NULL;
 
-       first = i = hashtable_index(sha1);
+       first = i = hash_obj(sha1, obj_hash_size);
        while ((obj = obj_hash[i]) != NULL) {
                if (!hashcmp(sha1, obj->sha1))
                        break;
@@ -101,6 +95,10 @@ struct object *lookup_object(const unsigned char *sha1)
 static void grow_object_hash(void)
 {
        int i;
+       /*
+        * Note that this size must always be power-of-2 to match hash_obj
+        * above.
+        */
        int new_hash_size = obj_hash_size < 32 ? 32 : 2 * obj_hash_size;
        struct object **new_hash;
 
diff --git a/pager.c b/pager.c
index c1ecf657fdb32c1fa669f08ba33e358f15c5a07b..fa19765eb9e60d2dbc17887773fff4ad66a32c37 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -54,7 +54,7 @@ const char *git_pager(int stdout_is_tty)
                pager = getenv("PAGER");
        if (!pager)
                pager = DEFAULT_PAGER;
-       else if (!*pager || !strcmp(pager, "cat"))
+       if (!*pager || !strcmp(pager, "cat"))
                pager = NULL;
 
        return pager;
index 75ecc425b6ebbf2cb1941b6b6bca78f8d0b70d62..a7b0119ee5945e062aee27a8bb21bf7c818fb8c6 100644 (file)
@@ -32,6 +32,14 @@ BEGIN
        }
 }
 
+# serf has a bug that leads to a coredump upon termination if the
+# remote access object is left around (not fixed yet in serf 1.3.1).
+# Explicitly free it to work around the issue.
+END {
+       $RA = undef;
+       $ra_invalid = 1;
+}
+
 sub _auth_providers () {
        my @rv = (
          SVN::Client::get_simple_provider(),
index 20a88ea529d3bc86eb1f7f7de9d05a113095dab4..898b18d1155d549f82a786c8b63ee9f9cd758c3a 100644 (file)
--- a/po/da.po
+++ b/po/da.po
@@ -1674,7 +1674,7 @@ msgid "No names found, cannot describe anything."
 msgstr ""
 
 #: builtin/describe.c:482
-msgid "--dirty is incompatible with committishes"
+msgid "--dirty is incompatible with commit-ishes"
 msgstr ""
 
 #: builtin/diff.c:77
index 11dde114f3b682e782090bfd903953a327d9bc12..35a44b94630e2d90d9cdbf819b4a354e2d368cd0 100644 (file)
--- a/po/de.po
+++ b/po/de.po
@@ -4684,8 +4684,8 @@ msgid "print sizes in human readable format"
 msgstr "gibt Größenangaben in menschenlesbaren Format aus"
 
 #: builtin/describe.c:16
-msgid "git describe [options] <committish>*"
-msgstr "git describe [Optionen] <committish>*"
+msgid "git describe [options] <commit-ish>*"
+msgstr "git describe [Optionen] <commit-ish>*"
 
 #: builtin/describe.c:17
 msgid "git describe [options] --dirty"
@@ -4694,12 +4694,12 @@ msgstr "git describe [Optionen] --dirty"
 #: builtin/describe.c:237
 #, c-format
 msgid "annotated tag %s not available"
-msgstr "annotierter Tag %s ist nicht verfügbar"
+msgstr "annotiertes Tag %s ist nicht verfügbar"
 
 #: builtin/describe.c:241
 #, c-format
 msgid "annotated tag %s has no embedded name"
-msgstr "annotierter Tag %s hat keinen eingebetteten Namen"
+msgstr "annotiertes Tag %s hat keinen eingebetteten Namen"
 
 #: builtin/describe.c:243
 #, c-format
@@ -4765,7 +4765,7 @@ msgstr ""
 
 #: builtin/describe.c:409
 msgid "find the tag that comes after the commit"
-msgstr "findet den Tag, die nach Commit kommt"
+msgstr "findet das Tag, das nach Commit kommt"
 
 #: builtin/describe.c:410
 msgid "debug search strategy on stderr"
@@ -4777,7 +4777,7 @@ msgstr "verwendet alle Referenzen"
 
 #: builtin/describe.c:412
 msgid "use any tag, even unannotated"
-msgstr "verwendet jeden Tag, auch nicht-annotierte"
+msgstr "verwendet jedes Tag, auch nicht-annotierte"
 
 #: builtin/describe.c:413
 msgid "always use long format"
@@ -4822,7 +4822,7 @@ msgid "No names found, cannot describe anything."
 msgstr "Keine Namen gefunden, kann nichts beschreiben."
 
 #: builtin/describe.c:489
-msgid "--dirty is incompatible with committishes"
+msgid "--dirty is incompatible with commit-ishes"
 msgstr "Die Option --dirty kann nicht mit Commits verwendet werden."
 
 #: builtin/diff.c:79
@@ -4880,7 +4880,7 @@ msgstr "Importiert Kennzeichen von dieser Datei"
 
 #: builtin/fast-export.c:678
 msgid "Fake a tagger when tags lack one"
-msgstr "erzeugt künstlich einen Tag-Ersteller, wenn der Tag keinen hat"
+msgstr "erzeugt künstlich einen Tag-Ersteller, wenn das Tag keinen hat"
 
 #: builtin/fast-export.c:680
 msgid "Output full tree for each commit"
@@ -5013,7 +5013,7 @@ msgstr "  (kann lokale Referenz nicht aktualisieren)"
 
 #: builtin/fetch.c:324
 msgid "[new tag]"
-msgstr "[neuer Tag]"
+msgstr "[neues Tag]"
 
 #: builtin/fetch.c:327
 msgid "[new branch]"
@@ -7831,7 +7831,7 @@ msgstr ""
 #: builtin/push.c:257
 msgid "Updates were rejected because the tag already exists in the remote."
 msgstr ""
-"Aktualisierungen wurden zurückgewiesen, weil der Tag bereits\n"
+"Aktualisierungen wurden zurückgewiesen, weil das Tag bereits\n"
 "im Remote-Repository existiert."
 
 #: builtin/push.c:260
@@ -9244,7 +9244,7 @@ msgstr "Optionen für Erstellung von Tags"
 
 #: builtin/tag.c:454
 msgid "annotated tag, needs a message"
-msgstr "annotierter Tag, benötigt eine Beschreibung"
+msgstr "annotiertes Tag, benötigt eine Beschreibung"
 
 #: builtin/tag.c:456
 msgid "tag message"
@@ -9252,15 +9252,15 @@ msgstr "Tag-Beschreibung"
 
 #: builtin/tag.c:458
 msgid "annotated and GPG-signed tag"
-msgstr "annotierter und GPG-signierter Tag"
+msgstr "annotiertes und GPG-signiertes Tag"
 
 #: builtin/tag.c:462
 msgid "use another key to sign the tag"
-msgstr "verwendet einen anderen Schlüssel um den Tag zu signieren"
+msgstr "verwendet einen anderen Schlüssel um das Tag zu signieren"
 
 #: builtin/tag.c:463
 msgid "replace the tag if exists"
-msgstr "ersetzt den Tag, wenn er existiert"
+msgstr "ersetzt das Tag, wenn es existiert"
 
 #: builtin/tag.c:464
 msgid "show tag list in columns"
index 2cdb6f93a3b683ff4d25bdc711b330844e24d7d0..49e0ec14ab105dce3d457ae3898542cd146aecc9 100644 (file)
--- a/po/fr.po
+++ b/po/fr.po
@@ -4291,7 +4291,7 @@ msgid "print sizes in human readable format"
 msgstr ""
 
 #: builtin/describe.c:15
-msgid "git describe [options] <committish>*"
+msgid "git describe [options] <commit-ish>*"
 msgstr ""
 
 #: builtin/describe.c:16
@@ -4417,7 +4417,7 @@ msgid "No names found, cannot describe anything."
 msgstr ""
 
 #: builtin/describe.c:481
-msgid "--dirty is incompatible with committishes"
+msgid "--dirty is incompatible with commit-ishes"
 msgstr ""
 
 #: builtin/diff.c:79
index cf1e44633079895608a3b0da3ff27c986e8903ac..c91e1975214f07ab6e6264764082511e01e569c0 100644 (file)
@@ -4335,7 +4335,7 @@ msgid "print sizes in human readable format"
 msgstr ""
 
 #: builtin/describe.c:16
-msgid "git describe [options] <committish>*"
+msgid "git describe [options] <commit-ish>*"
 msgstr ""
 
 #: builtin/describe.c:17
@@ -4465,7 +4465,7 @@ msgid "No names found, cannot describe anything."
 msgstr ""
 
 #: builtin/describe.c:489
-msgid "--dirty is incompatible with committishes"
+msgid "--dirty is incompatible with commit-ishes"
 msgstr ""
 
 #: builtin/diff.c:79
index fe61f1a3f368d1c10920a7afe38364f2d2df661d..9080219446b4361018e2fb4349d7dac667403fbc 100644 (file)
--- a/po/it.po
+++ b/po/it.po
@@ -2476,7 +2476,7 @@ msgid "No names found, cannot describe anything."
 msgstr ""
 
 #: builtin/describe.c:482
-msgid "--dirty is incompatible with committishes"
+msgid "--dirty is incompatible with commit-ishes"
 msgstr ""
 
 #: builtin/diff.c:77
index e1399e2b6dcbab07e2373ea787d07310fd0cc633..ad31c66cdf7eb3d2bf9cc6291f8fd2f601220c38 100644 (file)
--- a/po/nl.po
+++ b/po/nl.po
@@ -1669,7 +1669,7 @@ msgid "No names found, cannot describe anything."
 msgstr ""
 
 #: builtin/describe.c:482
-msgid "--dirty is incompatible with committishes"
+msgid "--dirty is incompatible with commit-ishes"
 msgstr ""
 
 #: builtin/diff.c:77
index 517ec29a4a3f6337e07ed411e7d86db160398fe9..689ad1b0fee552e64dc2b3cf3f7eb1da89fd65ac 100644 (file)
@@ -2312,7 +2312,7 @@ msgid "No names found, cannot describe anything."
 msgstr "Nenhum nome encontrado, não descreve nada."
 
 #: builtin/describe.c:482
-msgid "--dirty is incompatible with committishes"
+msgid "--dirty is incompatible with commit-ishes"
 msgstr ""
 
 #: builtin/diff.c:77
index 12dfca92f4a829247ef1e62f05cd43915b911e7b..dcf579b8d41285fda59a57804d7710bda3616b88 100644 (file)
--- a/po/sv.po
+++ b/po/sv.po
@@ -4560,7 +4560,7 @@ msgid "print sizes in human readable format"
 msgstr "skriv storlekar i människoläsbart format"
 
 #: builtin/describe.c:16
-msgid "git describe [options] <committish>*"
+msgid "git describe [options] <commit-ish>*"
 msgstr "git describe [flaggor] <incheckning-igt>*"
 
 #: builtin/describe.c:17
@@ -4696,8 +4696,8 @@ msgid "No names found, cannot describe anything."
 msgstr "Inga namn hittades, kan inte beskriva något."
 
 #: builtin/describe.c:489
-msgid "--dirty is incompatible with committishes"
-msgstr "--dirty är inkompatibelt med \"committish\"-värden"
+msgid "--dirty is incompatible with commit-ishes"
+msgstr "--dirty är inkompatibelt med \"commit-ish\"-värden"
 
 #: builtin/diff.c:79
 #, c-format
index dd2d2a73193c1bcb47d53f713c426ef4f0a0233f..11b491279158f50ae39dd5f3db4ea4e1771ec0fc 100644 (file)
--- a/po/vi.po
+++ b/po/vi.po
@@ -4663,8 +4663,8 @@ msgid "print sizes in human readable format"
 msgstr "hiển thị kích cỡ theo định dạng dành cho người đọc"
 
 #: builtin/describe.c:16
-msgid "git describe [options] <committish>*"
-msgstr "git describe [các-tùy-chọn] <committish>*"
+msgid "git describe [options] <commit-ish>*"
+msgstr "git describe [các-tùy-chọn] <commit-ish>*"
 
 #: builtin/describe.c:17
 msgid "git describe [options] --dirty"
@@ -4799,7 +4799,7 @@ msgid "No names found, cannot describe anything."
 msgstr "Không tìm thấy các tên, không thể mô tả gì cả."
 
 #: builtin/describe.c:489
-msgid "--dirty is incompatible with committishes"
+msgid "--dirty is incompatible with commit-ishes"
 msgstr "--dirty là xung khắc với các tùy chọn dành cho chuyển giao (commit)"
 
 #: builtin/diff.c:79
index b7b46f14f0d15f02e6c7e3166e860f89a4a9681f..1a042af1114127a4145c4150b895dbdbb45a2c88 100644 (file)
@@ -4562,7 +4562,7 @@ msgid "print sizes in human readable format"
 msgstr "以用户可读的格式显示大小"
 
 #: builtin/describe.c:16
-msgid "git describe [options] <committish>*"
+msgid "git describe [options] <commit-ish>*"
 msgstr "git describe [选项] <提交号>*"
 
 #: builtin/describe.c:17
@@ -4698,7 +4698,7 @@ msgid "No names found, cannot describe anything."
 msgstr "没有发现名称,无法描述任何东西。"
 
 #: builtin/describe.c:489
-msgid "--dirty is incompatible with committishes"
+msgid "--dirty is incompatible with commit-ishes"
 msgstr "--dirty 不能与提交同时使用"
 
 #: builtin/diff.c:79
index e7e6a1e342200bbf4c37bd561e6a68222349418e..654a8c58d689daf43f2ba4c40e4fe54d31c7826a 100644 (file)
@@ -80,8 +80,7 @@ static void process_tree(struct tree *tree,
                else
                        process_blob(lookup_blob(entry.sha1), p, &me, entry.path, cp);
        }
-       free(tree->buffer);
-       tree->buffer = NULL;
+       free_tree_buffer(tree);
 }
 
 static void process_tag(struct tag *tag, struct object_array *p,
index 885943a6df77da646481c34d2876d7fdaa5c12b8..6bbe1b1fb3435247e1114cbf496cd9d7640f3def 100644 (file)
@@ -1818,8 +1818,17 @@ int write_index(struct index_state *istate, int newfd)
                        continue;
                if (!ce_uptodate(ce) && is_racy_timestamp(istate, ce))
                        ce_smudge_racily_clean_entry(ce);
-               if (is_null_sha1(ce->sha1))
-                       return error("cache entry has null sha1: %s", ce->name);
+               if (is_null_sha1(ce->sha1)) {
+                       static const char msg[] = "cache entry has null sha1: %s";
+                       static int allow = -1;
+
+                       if (allow < 0)
+                               allow = git_env_bool("GIT_ALLOW_NULL_SHA1", 0);
+                       if (allow)
+                               warning(msg, ce->name);
+                       else
+                               return error(msg, ce->name);
+               }
                if (ce_write_entry(&c, newfd, ce, previous_name) < 0)
                        return -1;
        }
diff --git a/refs.c b/refs.c
index d78860c46d95ea9785c83c08824355275393ed99..3710748ab88d8fa4639c3a0a436ca0e2b0c25552 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -72,6 +72,10 @@ int check_refname_format(const char *refname, int flags)
 {
        int component_len, component_count = 0;
 
+       if (!strcmp(refname, "@"))
+               /* Refname is a single character '@'. */
+               return -1;
+
        while (1) {
                /* We are at the start of a path component. */
                component_len = check_refname_component(refname, flags);
@@ -1951,7 +1955,7 @@ static int remove_empty_directories(const char *file)
 static char *substitute_branch_name(const char **string, int *len)
 {
        struct strbuf buf = STRBUF_INIT;
-       int ret = interpret_branch_name(*string, &buf);
+       int ret = interpret_branch_name(*string, *len, &buf);
 
        if (ret == *len) {
                size_t size;
@@ -2121,11 +2125,12 @@ struct ref_lock *lock_ref_sha1(const char *refname, const unsigned char *old_sha
 }
 
 struct ref_lock *lock_any_ref_for_update(const char *refname,
-                                        const unsigned char *old_sha1, int flags)
+                                        const unsigned char *old_sha1,
+                                        int flags, int *type_p)
 {
        if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
                return NULL;
-       return lock_ref_sha1_basic(refname, old_sha1, flags, NULL);
+       return lock_ref_sha1_basic(refname, old_sha1, flags, type_p);
 }
 
 /*
@@ -2413,60 +2418,82 @@ static int curate_packed_ref_fn(struct ref_entry *entry, void *cb_data)
        return 0;
 }
 
-static int repack_without_ref(const char *refname)
+static int repack_without_refs(const char **refnames, int n)
 {
        struct ref_dir *packed;
        struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
        struct string_list_item *ref_to_delete;
+       int i, removed = 0;
+
+       /* Look for a packed ref */
+       for (i = 0; i < n; i++)
+               if (get_packed_ref(refnames[i]))
+                       break;
 
-       if (!get_packed_ref(refname))
-               return 0; /* refname does not exist in packed refs */
+       /* Avoid locking if we have nothing to do */
+       if (i == n)
+               return 0; /* no refname exists in packed refs */
 
        if (lock_packed_refs(0)) {
                unable_to_lock_error(git_path("packed-refs"), errno);
-               return error("cannot delete '%s' from packed refs", refname);
+               return error("cannot delete '%s' from packed refs", refnames[i]);
        }
        packed = get_packed_refs(&ref_cache);
 
-       /* Remove refname from the cache: */
-       if (remove_entry(packed, refname) == -1) {
+       /* Remove refnames from the cache */
+       for (i = 0; i < n; i++)
+               if (remove_entry(packed, refnames[i]) != -1)
+                       removed = 1;
+       if (!removed) {
                /*
-                * The packed entry disappeared while we were
+                * All packed entries disappeared while we were
                 * acquiring the lock.
                 */
                rollback_packed_refs();
                return 0;
        }
 
-       /* Remove any other accumulated cruft: */
+       /* Remove any other accumulated cruft */
        do_for_each_entry_in_dir(packed, 0, curate_packed_ref_fn, &refs_to_delete);
        for_each_string_list_item(ref_to_delete, &refs_to_delete) {
                if (remove_entry(packed, ref_to_delete->string) == -1)
                        die("internal error");
        }
 
-       /* Write what remains: */
+       /* Write what remains */
        return commit_packed_refs();
 }
 
-int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
+static int repack_without_ref(const char *refname)
 {
-       struct ref_lock *lock;
-       int err, i = 0, ret = 0, flag = 0;
+       return repack_without_refs(&refname, 1);
+}
 
-       lock = lock_ref_sha1_basic(refname, sha1, delopt, &flag);
-       if (!lock)
-               return 1;
+static int delete_ref_loose(struct ref_lock *lock, int flag)
+{
        if (!(flag & REF_ISPACKED) || flag & REF_ISSYMREF) {
                /* loose */
-               i = strlen(lock->lk->filename) - 5; /* .lock */
+               int err, i = strlen(lock->lk->filename) - 5; /* .lock */
+
                lock->lk->filename[i] = 0;
                err = unlink_or_warn(lock->lk->filename);
-               if (err && errno != ENOENT)
-                       ret = 1;
-
                lock->lk->filename[i] = '.';
+               if (err && errno != ENOENT)
+                       return 1;
        }
+       return 0;
+}
+
+int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
+{
+       struct ref_lock *lock;
+       int ret = 0, flag = 0;
+
+       lock = lock_ref_sha1_basic(refname, sha1, delopt, &flag);
+       if (!lock)
+               return 1;
+       ret |= delete_ref_loose(lock, flag);
+
        /* removing the loose one could have resurrected an earlier
         * packed one.  Also, if it was not loose we need to repack
         * without it.
@@ -3169,12 +3196,13 @@ int for_each_reflog(each_ref_fn fn, void *cb_data)
        return retval;
 }
 
-int update_ref(const char *action, const char *refname,
-               const unsigned char *sha1, const unsigned char *oldval,
-               int flags, enum action_on_err onerr)
+static struct ref_lock *update_ref_lock(const char *refname,
+                                       const unsigned char *oldval,
+                                       int flags, int *type_p,
+                                       enum action_on_err onerr)
 {
-       static struct ref_lock *lock;
-       lock = lock_any_ref_for_update(refname, oldval, flags);
+       struct ref_lock *lock;
+       lock = lock_any_ref_for_update(refname, oldval, flags, type_p);
        if (!lock) {
                const char *str = "Cannot lock the ref '%s'.";
                switch (onerr) {
@@ -3182,8 +3210,14 @@ int update_ref(const char *action, const char *refname,
                case DIE_ON_ERR: die(str, refname); break;
                case QUIET_ON_ERR: break;
                }
-               return 1;
        }
+       return lock;
+}
+
+static int update_ref_write(const char *action, const char *refname,
+                           const unsigned char *sha1, struct ref_lock *lock,
+                           enum action_on_err onerr)
+{
        if (write_ref_sha1(lock, sha1, action) < 0) {
                const char *str = "Cannot update the ref '%s'.";
                switch (onerr) {
@@ -3196,6 +3230,117 @@ int update_ref(const char *action, const char *refname,
        return 0;
 }
 
+int update_ref(const char *action, const char *refname,
+              const unsigned char *sha1, const unsigned char *oldval,
+              int flags, enum action_on_err onerr)
+{
+       struct ref_lock *lock;
+       lock = update_ref_lock(refname, oldval, flags, NULL, onerr);
+       if (!lock)
+               return 1;
+       return update_ref_write(action, refname, sha1, lock, onerr);
+}
+
+static int ref_update_compare(const void *r1, const void *r2)
+{
+       const struct ref_update * const *u1 = r1;
+       const struct ref_update * const *u2 = r2;
+       return strcmp((*u1)->ref_name, (*u2)->ref_name);
+}
+
+static int ref_update_reject_duplicates(struct ref_update **updates, int n,
+                                       enum action_on_err onerr)
+{
+       int i;
+       for (i = 1; i < n; i++)
+               if (!strcmp(updates[i - 1]->ref_name, updates[i]->ref_name)) {
+                       const char *str =
+                               "Multiple updates for ref '%s' not allowed.";
+                       switch (onerr) {
+                       case MSG_ON_ERR:
+                               error(str, updates[i]->ref_name); break;
+                       case DIE_ON_ERR:
+                               die(str, updates[i]->ref_name); break;
+                       case QUIET_ON_ERR:
+                               break;
+                       }
+                       return 1;
+               }
+       return 0;
+}
+
+int update_refs(const char *action, const struct ref_update **updates_orig,
+               int n, enum action_on_err onerr)
+{
+       int ret = 0, delnum = 0, i;
+       struct ref_update **updates;
+       int *types;
+       struct ref_lock **locks;
+       const char **delnames;
+
+       if (!updates_orig || !n)
+               return 0;
+
+       /* Allocate work space */
+       updates = xmalloc(sizeof(*updates) * n);
+       types = xmalloc(sizeof(*types) * n);
+       locks = xcalloc(n, sizeof(*locks));
+       delnames = xmalloc(sizeof(*delnames) * n);
+
+       /* Copy, sort, and reject duplicate refs */
+       memcpy(updates, updates_orig, sizeof(*updates) * n);
+       qsort(updates, n, sizeof(*updates), ref_update_compare);
+       ret = ref_update_reject_duplicates(updates, n, onerr);
+       if (ret)
+               goto cleanup;
+
+       /* Acquire all locks while verifying old values */
+       for (i = 0; i < n; i++) {
+               locks[i] = update_ref_lock(updates[i]->ref_name,
+                                          (updates[i]->have_old ?
+                                           updates[i]->old_sha1 : NULL),
+                                          updates[i]->flags,
+                                          &types[i], onerr);
+               if (!locks[i]) {
+                       ret = 1;
+                       goto cleanup;
+               }
+       }
+
+       /* Perform updates first so live commits remain referenced */
+       for (i = 0; i < n; i++)
+               if (!is_null_sha1(updates[i]->new_sha1)) {
+                       ret = update_ref_write(action,
+                                              updates[i]->ref_name,
+                                              updates[i]->new_sha1,
+                                              locks[i], onerr);
+                       locks[i] = NULL; /* freed by update_ref_write */
+                       if (ret)
+                               goto cleanup;
+               }
+
+       /* Perform deletes now that updates are safely completed */
+       for (i = 0; i < n; i++)
+               if (locks[i]) {
+                       delnames[delnum++] = locks[i]->ref_name;
+                       ret |= delete_ref_loose(locks[i], types[i]);
+               }
+       ret |= repack_without_refs(delnames, delnum);
+       for (i = 0; i < delnum; i++)
+               unlink_or_warn(git_path("logs/%s", delnames[i]));
+       clear_loose_ref_cache(&ref_cache);
+
+cleanup:
+       for (i = 0; i < n; i++)
+               if (locks[i])
+                       unlock_ref(locks[i]);
+       free(updates);
+       free(types);
+       free(locks);
+       free(delnames);
+       return ret;
+}
+
 /*
  * generate a format suitable for scanf from a ref_rev_parse_rules
  * rule, that is replace the "%.*s" spec with a "%s" spec
diff --git a/refs.h b/refs.h
index 9e5db3ae26ec7898d8ee9083c37562d3af05c0ab..b113377c4806423af2cad13f1b38284b5f5e5f2f 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -10,6 +10,20 @@ struct ref_lock {
        int force_write;
 };
 
+/**
+ * Information needed for a single ref update.  Set new_sha1 to the
+ * new value or to zero to delete the ref.  To check the old value
+ * while locking the ref, set have_old to 1 and set old_sha1 to the
+ * value or to zero to ensure the ref does not exist before update.
+ */
+struct ref_update {
+       const char *ref_name;
+       unsigned char new_sha1[20];
+       unsigned char old_sha1[20];
+       int flags; /* REF_NODEREF? */
+       int have_old; /* 1 if old_sha1 is valid, 0 otherwise */
+};
+
 /*
  * Bit values set in the flags argument passed to each_ref_fn():
  */
@@ -137,7 +151,7 @@ extern struct ref_lock *lock_ref_sha1(const char *refname, const unsigned char *
 #define REF_NODEREF    0x01
 extern struct ref_lock *lock_any_ref_for_update(const char *refname,
                                                const unsigned char *old_sha1,
-                                               int flags);
+                                               int flags, int *type_p);
 
 /** Close the file descriptor owned by a lock and return the status */
 extern int close_ref(struct ref_lock *lock);
@@ -214,6 +228,12 @@ int update_ref(const char *action, const char *refname,
                const unsigned char *sha1, const unsigned char *oldval,
                int flags, enum action_on_err onerr);
 
+/**
+ * Lock all refs and then perform all modifications.
+ */
+int update_refs(const char *action, const struct ref_update **updates,
+               int n, enum action_on_err onerr);
+
 extern int parse_hide_refs_config(const char *var, const char *value, const char *);
 extern int ref_is_hidden(const char *);
 
index 24334679e0971e3af5e168d1cf7259da55d21d50..e9fedfa918d6806532184b8735d2761951fd4a2e 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -1729,7 +1729,11 @@ int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)
 }
 
 /*
- * Return true if there is anything to report, otherwise false.
+ * Compare a branch with its upstream, and save their differences (number
+ * of commits) in *num_ours and *num_theirs.
+ *
+ * Return 0 if branch has no upstream (no base), -1 if upstream is missing
+ * (with "gone" base), otherwise 1 (with base).
  */
 int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
 {
@@ -1740,34 +1744,30 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
        const char *rev_argv[10], *base;
        int rev_argc;
 
-       /*
-        * Nothing to report unless we are marked to build on top of
-        * somebody else.
-        */
+       /* Cannot stat unless we are marked to build on top of somebody else. */
        if (!branch ||
            !branch->merge || !branch->merge[0] || !branch->merge[0]->dst)
                return 0;
 
-       /*
-        * If what we used to build on no longer exists, there is
-        * nothing to report.
-        */
+       /* Cannot stat if what we used to build on no longer exists */
        base = branch->merge[0]->dst;
        if (read_ref(base, sha1))
-               return 0;
+               return -1;
        theirs = lookup_commit_reference(sha1);
        if (!theirs)
-               return 0;
+               return -1;
 
        if (read_ref(branch->refname, sha1))
-               return 0;
+               return -1;
        ours = lookup_commit_reference(sha1);
        if (!ours)
-               return 0;
+               return -1;
 
        /* are we the same? */
-       if (theirs == ours)
-               return 0;
+       if (theirs == ours) {
+               *num_theirs = *num_ours = 0;
+               return 1;
+       }
 
        /* Run "rev-list --left-right ours...theirs" internally... */
        rev_argc = 0;
@@ -1809,31 +1809,53 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs)
  */
 int format_tracking_info(struct branch *branch, struct strbuf *sb)
 {
-       int num_ours, num_theirs;
+       int ours, theirs;
        const char *base;
+       int upstream_is_gone = 0;
 
-       if (!stat_tracking_info(branch, &num_ours, &num_theirs))
+       switch (stat_tracking_info(branch, &ours, &theirs)) {
+       case 0:
+               /* no base */
                return 0;
+       case -1:
+               /* with "gone" base */
+               upstream_is_gone = 1;
+               break;
+       default:
+               /* with base */
+               break;
+       }
 
        base = branch->merge[0]->dst;
        base = shorten_unambiguous_ref(base, 0);
-       if (!num_theirs) {
+       if (upstream_is_gone) {
+               strbuf_addf(sb,
+                       _("Your branch is based on '%s', but the upstream is gone.\n"),
+                       base);
+               if (advice_status_hints)
+                       strbuf_addf(sb,
+                               _("  (use \"git branch --unset-upstream\" to fixup)\n"));
+       } else if (!ours && !theirs) {
+               strbuf_addf(sb,
+                       _("Your branch is up-to-date with '%s'.\n"),
+                       base);
+       } else if (!theirs) {
                strbuf_addf(sb,
                        Q_("Your branch is ahead of '%s' by %d commit.\n",
                           "Your branch is ahead of '%s' by %d commits.\n",
-                          num_ours),
-                       base, num_ours);
+                          ours),
+                       base, ours);
                if (advice_status_hints)
                        strbuf_addf(sb,
                                _("  (use \"git push\" to publish your local commits)\n"));
-       } else if (!num_ours) {
+       } else if (!ours) {
                strbuf_addf(sb,
                        Q_("Your branch is behind '%s' by %d commit, "
                               "and can be fast-forwarded.\n",
                           "Your branch is behind '%s' by %d commits, "
                               "and can be fast-forwarded.\n",
-                          num_theirs),
-                       base, num_theirs);
+                          theirs),
+                       base, theirs);
                if (advice_status_hints)
                        strbuf_addf(sb,
                                _("  (use \"git pull\" to update your local branch)\n"));
@@ -1845,8 +1867,8 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)
                           "Your branch and '%s' have diverged,\n"
                               "and have %d and %d different commits each, "
                               "respectively.\n",
-                          num_theirs),
-                       base, num_ours, num_theirs);
+                          theirs),
+                       base, ours, theirs);
                if (advice_status_hints)
                        strbuf_addf(sb,
                                _("  (use \"git pull\" to merge the remote branch into yours)\n"));
index 6230a80a77bf261d47adcb97a8bd62bef4f37087..0173e0148b850bd1a3e2e7e5c652050ade6d5ba4 100644 (file)
@@ -139,8 +139,7 @@ void mark_tree_uninteresting(struct tree *tree)
         * We don't care about the tree any more
         * after it has been marked uninteresting.
         */
-       free(tree->buffer);
-       tree->buffer = NULL;
+       free_tree_buffer(tree);
 }
 
 void mark_parents_uninteresting(struct commit *commit)
@@ -201,7 +200,7 @@ static void add_pending_object_with_mode(struct rev_info *revs,
                revs->no_walk = 0;
        if (revs->reflog_info && obj->type == OBJ_COMMIT) {
                struct strbuf buf = STRBUF_INIT;
-               int len = interpret_branch_name(name, &buf);
+               int len = interpret_branch_name(name, 0, &buf);
                int st;
 
                if (0 < len && name[len] && buf.len)
index 351548f57db61e62b47584020464aee877b48d8d..06e52b4c83ffc0ce2b9414afe3fb1b4ee91d4335 100644 (file)
@@ -279,7 +279,8 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from,
        read_cache();
        if (checkout_fast_forward(from, to, 1))
                exit(1); /* the callee should have complained already */
-       ref_lock = lock_any_ref_for_update("HEAD", unborn ? null_sha1 : from, 0);
+       ref_lock = lock_any_ref_for_update("HEAD", unborn ? null_sha1 : from,
+                                          0, NULL);
        strbuf_addf(&sb, "%s: fast-forward", action_name(opts));
        ret = write_ref_sha1(ref_lock, to, sb.buf);
        strbuf_release(&sb);
index c4dc55d1f5cd07adcf46865354f841cc587c51f6..2dd851598a9d1444fe479d149ee3c2cb93e8cba9 100644 (file)
@@ -204,7 +204,54 @@ int sha1_entry_pos(const void *table,
                         * byte 0 thru (ofs-1) are the same between
                         * lo and hi; ofs is the first byte that is
                         * different.
+                        *
+                        * If ofs==20, then no bytes are different,
+                        * meaning we have entries with duplicate
+                        * keys. We know that we are in a solid run
+                        * of this entry (because the entries are
+                        * sorted, and our lo and hi are the same,
+                        * there can be nothing but this single key
+                        * in between). So we can stop the search.
+                        * Either one of these entries is it (and
+                        * we do not care which), or we do not have
+                        * it.
+                        *
+                        * Furthermore, we know that one of our
+                        * endpoints must be the edge of the run of
+                        * duplicates. For example, given this
+                        * sequence:
+                        *
+                        *     idx 0 1 2 3 4 5
+                        *     key A C C C C D
+                        *
+                        * If we are searching for "B", we might
+                        * hit the duplicate run at lo=1, hi=3
+                        * (e.g., by first mi=3, then mi=0). But we
+                        * can never have lo > 1, because B < C.
+                        * That is, if our key is less than the
+                        * run, we know that "lo" is the edge, but
+                        * we can say nothing of "hi". Similarly,
+                        * if our key is greater than the run, we
+                        * know that "hi" is the edge, but we can
+                        * say nothing of "lo".
+                        *
+                        * Therefore if we do not find it, we also
+                        * know where it would go if it did exist:
+                        * just on the far side of the edge that we
+                        * know about.
                         */
+                       if (ofs == 20) {
+                               mi = lo;
+                               mi_key = base + elem_size * mi + key_offset;
+                               cmp = memcmp(mi_key, key, 20);
+                               if (!cmp)
+                                       return mi;
+                               if (cmp < 0)
+                                       return -1 - hi;
+                               else
+                                       return -1 - lo;
+                       }
+
                        hiv = hi_key[ofs_0];
                        if (ofs_0 < 19)
                                hiv = (hiv << 8) | hi_key[ofs_0+1];
index 8c2d1ed52d6663507ff5b03bc7e5b4f4070403d1..f80bbe467437a4ffc161a4cdd09f97cf5436d4f9 100644 (file)
@@ -2126,6 +2126,16 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
                int i;
                struct delta_base_cache_entry *ent;
 
+               ent = get_delta_base_cache_entry(p, curpos);
+               if (eq_delta_base_cache_entry(ent, p, curpos)) {
+                       type = ent->type;
+                       data = ent->data;
+                       size = ent->size;
+                       clear_delta_base_cache_entry(ent);
+                       base_from_cache = 1;
+                       break;
+               }
+
                if (do_check_packed_object_crc && p->index_version > 1) {
                        struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
                        unsigned long len = revidx[1].offset - obj_offset;
@@ -2140,16 +2150,6 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset,
                        }
                }
 
-               ent = get_delta_base_cache_entry(p, curpos);
-               if (eq_delta_base_cache_entry(ent, p, curpos)) {
-                       type = ent->type;
-                       data = ent->data;
-                       size = ent->size;
-                       clear_delta_base_cache_entry(ent);
-                       base_from_cache = 1;
-                       break;
-               }
-
                type = unpack_object_header(p, &w_curs, &curpos, &size);
                if (type != OBJ_OFS_DELTA && type != OBJ_REF_DELTA)
                        break;
@@ -2995,7 +2995,10 @@ int has_sha1_file(const unsigned char *sha1)
 
        if (find_pack_entry(sha1, &e))
                return 1;
-       return has_loose_object(sha1);
+       if (has_loose_object(sha1))
+               return 1;
+       reprepare_packed_git();
+       return find_pack_entry(sha1, &e);
 }
 
 static void check_tree(const void *buf, size_t size)
index 65ad066d9bb4efd9b61142b40d790bac9543de1d..0e5fe7f9371d2e6ae5aa9ce99c4b6c2dfb7a456f 100644 (file)
@@ -677,11 +677,13 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
                return -1;
 
        sp++; /* beginning of type name, or closing brace for empty */
-       if (!strncmp(commit_type, sp, 6) && sp[6] == '}')
+       if (!prefixcmp(sp, "commit}"))
                expected_type = OBJ_COMMIT;
-       else if (!strncmp(tree_type, sp, 4) && sp[4] == '}')
+       else if (!prefixcmp(sp, "tag}"))
+               expected_type = OBJ_TAG;
+       else if (!prefixcmp(sp, "tree}"))
                expected_type = OBJ_TREE;
-       else if (!strncmp(blob_type, sp, 4) && sp[4] == '}')
+       else if (!prefixcmp(sp, "blob}"))
                expected_type = OBJ_BLOB;
        else if (!prefixcmp(sp, "object}"))
                expected_type = OBJ_ANY;
@@ -1004,6 +1006,28 @@ int get_sha1_mb(const char *name, unsigned char *sha1)
        return st;
 }
 
+/* parse @something syntax, when 'something' is not {.*} */
+static int interpret_empty_at(const char *name, int namelen, int len, struct strbuf *buf)
+{
+       const char *next;
+
+       if (len || name[1] == '{')
+               return -1;
+
+       /* make sure it's a single @, or @@{.*}, not @foo */
+       next = strchr(name + len + 1, '@');
+       if (next && next[1] != '{')
+               return -1;
+       if (!next)
+               next = name + namelen;
+       if (next != name + 1)
+               return -1;
+
+       strbuf_reset(buf);
+       strbuf_add(buf, "HEAD", 4);
+       return 1;
+}
+
 static int reinterpret(const char *name, int namelen, int len, struct strbuf *buf)
 {
        /* we have extra data, which might need further processing */
@@ -1012,7 +1036,7 @@ static int reinterpret(const char *name, int namelen, int len, struct strbuf *bu
        int ret;
 
        strbuf_add(buf, name + len, namelen - len);
-       ret = interpret_branch_name(buf->buf, &tmp);
+       ret = interpret_branch_name(buf->buf, buf->len, &tmp);
        /* that data was not interpreted, remove our cruft */
        if (ret < 0) {
                strbuf_setlen(buf, used);
@@ -1046,14 +1070,16 @@ static int reinterpret(const char *name, int namelen, int len, struct strbuf *bu
  * If the input was ok but there are not N branch switches in the
  * reflog, it returns 0.
  */
-int interpret_branch_name(const char *name, struct strbuf *buf)
+int interpret_branch_name(const char *name, int namelen, struct strbuf *buf)
 {
        char *cp;
        struct branch *upstream;
-       int namelen = strlen(name);
        int len = interpret_nth_prior_checkout(name, buf);
        int tmp_len;
 
+       if (!namelen)
+               namelen = strlen(name);
+
        if (!len) {
                return len; /* syntax Ok, not enough switches */
        } else if (len > 0) {
@@ -1066,9 +1092,15 @@ int interpret_branch_name(const char *name, struct strbuf *buf)
        cp = strchr(name, '@');
        if (!cp)
                return -1;
+
+       len = interpret_empty_at(name, namelen, cp - name, buf);
+       if (len > 0)
+               return reinterpret(name, namelen, len, buf);
+
        tmp_len = upstream_mark(cp, namelen - (cp - name));
        if (!tmp_len)
                return -1;
+
        len = cp + tmp_len - name;
        cp = xstrndup(name, cp - name);
        upstream = branch_get(*cp ? cp : NULL);
@@ -1100,7 +1132,7 @@ int interpret_branch_name(const char *name, struct strbuf *buf)
 int strbuf_branchname(struct strbuf *sb, const char *name)
 {
        int len = strlen(name);
-       int used = interpret_branch_name(name, sb);
+       int used = interpret_branch_name(name, len, sb);
 
        if (used == len)
                return 0;
@@ -1130,13 +1162,13 @@ int get_sha1(const char *name, unsigned char *sha1)
 }
 
 /*
- * Many callers know that the user meant to name a committish by
+ * Many callers know that the user meant to name a commit-ish by
  * syntactical positions where the object name appears.  Calling this
  * function allows the machinery to disambiguate shorter-than-unique
- * abbreviated object names between committish and others.
+ * abbreviated object names between commit-ish and others.
  *
  * Note that this does NOT error out when the named object is not a
- * committish. It is merely to give a hint to the disambiguation
+ * commit-ish. It is merely to give a hint to the disambiguation
  * machinery.
  */
 int get_sha1_committish(const char *name, unsigned char *sha1)
index 8a9c96d019a1b3df4942f370fe0d312467a36799..cdf37d694de175adcce10fa2e2a79c6579603b0b 100644 (file)
--- a/shallow.c
+++ b/shallow.c
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "commit.h"
 #include "tag.h"
+#include "pkt-line.h"
 
 static int is_shallow = -1;
 static struct stat shallow_stat;
@@ -141,3 +142,81 @@ void check_shallow_file_for_update(void)
                   )
                die("shallow file was changed during fetch");
 }
+
+struct write_shallow_data {
+       struct strbuf *out;
+       int use_pack_protocol;
+       int count;
+};
+
+static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
+{
+       struct write_shallow_data *data = cb_data;
+       const char *hex = sha1_to_hex(graft->sha1);
+       if (graft->nr_parent != -1)
+               return 0;
+       data->count++;
+       if (data->use_pack_protocol)
+               packet_buf_write(data->out, "shallow %s", hex);
+       else {
+               strbuf_addstr(data->out, hex);
+               strbuf_addch(data->out, '\n');
+       }
+       return 0;
+}
+
+int write_shallow_commits(struct strbuf *out, int use_pack_protocol)
+{
+       struct write_shallow_data data;
+       data.out = out;
+       data.use_pack_protocol = use_pack_protocol;
+       data.count = 0;
+       for_each_commit_graft(write_one_shallow, &data);
+       return data.count;
+}
+
+char *setup_temporary_shallow(void)
+{
+       struct strbuf sb = STRBUF_INIT;
+       int fd;
+
+       if (write_shallow_commits(&sb, 0)) {
+               struct strbuf path = STRBUF_INIT;
+               strbuf_addstr(&path, git_path("shallow_XXXXXX"));
+               fd = xmkstemp(path.buf);
+               if (write_in_full(fd, sb.buf, sb.len) != sb.len)
+                       die_errno("failed to write to %s",
+                                 path.buf);
+               close(fd);
+               strbuf_release(&sb);
+               return strbuf_detach(&path, NULL);
+       }
+       /*
+        * is_repository_shallow() sees empty string as "no shallow
+        * file".
+        */
+       return xstrdup("");
+}
+
+void setup_alternate_shallow(struct lock_file *shallow_lock,
+                            const char **alternate_shallow_file)
+{
+       struct strbuf sb = STRBUF_INIT;
+       int fd;
+
+       check_shallow_file_for_update();
+       fd = hold_lock_file_for_update(shallow_lock, git_path("shallow"),
+                                      LOCK_DIE_ON_ERROR);
+       if (write_shallow_commits(&sb, 0)) {
+               if (write_in_full(fd, sb.buf, sb.len) != sb.len)
+                       die_errno("failed to write to %s",
+                                 shallow_lock->filename);
+               *alternate_shallow_file = shallow_lock->filename;
+       } else
+               /*
+                * is_repository_shallow() sees empty string as "no
+                * shallow file".
+                */
+               *alternate_shallow_file = "";
+       strbuf_release(&sb);
+}
index 2098b9ba053b09b00ed4382aa55ea0802d749d89..ccd918e79ef4fa7962984c5ed4890ec07e92f03a 100644 (file)
@@ -48,7 +48,8 @@ P4DPORT=$((10669 + ($testid - $git_p4_test_start)))
 P4PORT=localhost:$P4DPORT
 P4CLIENT=client
 P4EDITOR=:
-export P4PORT P4CLIENT P4EDITOR
+unset P4CHARSET
+export P4PORT P4CLIENT P4EDITOR P4CHARSET
 
 db="$TRASH_DIRECTORY/db"
 cli="$TRASH_DIRECTORY/cli"
index dab405d57479fe95dcb71b16a7a059410d2ae005..54dbbfe5ceeb9bf91cdad3393c2fdfe95c06fd18 100644 (file)
@@ -169,7 +169,7 @@ test_http_push_nonff () {
                test_i18ngrep "Updates were rejected because" output
        '
 
-       test_expect_failure 'force with lease aka cas' '
+       test_expect_${EXPECT_CAS_RESULT} 'force with lease aka cas' '
                HEAD=$( cd "$REMOTE_REPO" && git rev-parse --verify HEAD ) &&
                test_when_finished '\''
                        (cd "$REMOTE_REPO" && git update-ref HEAD "$HEAD")
diff --git a/t/lib-pack.sh b/t/lib-pack.sh
new file mode 100644 (file)
index 0000000..7e8685b
--- /dev/null
@@ -0,0 +1,100 @@
+#!/bin/sh
+#
+# Support routines for hand-crafting weird or malicious packs.
+#
+# You can make a complete pack like:
+#
+#   pack_header 2 >foo.pack &&
+#   pack_obj e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 >>foo.pack &&
+#   pack_obj e68fe8129b546b101aee9510c5328e7f21ca1d18 >>foo.pack &&
+#   pack_trailer foo.pack
+
+# Print the big-endian 4-byte octal representation of $1
+uint32_octal () {
+       n=$1
+       printf '\%o' $(($n / 16777216)); n=$((n % 16777216))
+       printf '\%o' $(($n /    65536)); n=$((n %    65536))
+       printf '\%o' $(($n /      256)); n=$((n %      256))
+       printf '\%o' $(($n           ));
+}
+
+# Print the big-endian 4-byte binary representation of $1
+uint32_binary () {
+       printf "$(uint32_octal "$1")"
+}
+
+# Print a pack header, version 2, for a pack with $1 objects
+pack_header () {
+       printf 'PACK' &&
+       printf '\0\0\0\2' &&
+       uint32_binary "$1"
+}
+
+# Print the pack data for object $1, as a delta against object $2 (or as a full
+# object if $2 is missing or empty). The output is suitable for including
+# directly in the packfile, and represents the entirety of the object entry.
+# Doing this on the fly (especially picking your deltas) is quite tricky, so we
+# have hardcoded some well-known objects. See the case statements below for the
+# complete list.
+pack_obj () {
+       case "$1" in
+       # empty blob
+       e69de29bb2d1d6434b8b29ae775ad8c2e48c5391)
+               case "$2" in
+               '')
+                       printf '\060\170\234\003\0\0\0\0\1'
+                       return
+                       ;;
+               esac
+               ;;
+
+       # blob containing "\7\76"
+       e68fe8129b546b101aee9510c5328e7f21ca1d18)
+               case "$2" in
+               '')
+                       printf '\062\170\234\143\267\3\0\0\116\0\106'
+                       return
+                       ;;
+               01d7713666f4de822776c7622c10f1b07de280dc)
+                       printf '\165\1\327\161\66\146\364\336\202\47\166' &&
+                       printf '\307\142\54\20\361\260\175\342\200\334\170' &&
+                       printf '\234\143\142\142\142\267\003\0\0\151\0\114'
+                       return
+                       ;;
+               esac
+               ;;
+
+       # blob containing "\7\0"
+       01d7713666f4de822776c7622c10f1b07de280dc)
+               case "$2" in
+               '')
+                       printf '\062\170\234\143\147\0\0\0\20\0\10'
+                       return
+                       ;;
+               e68fe8129b546b101aee9510c5328e7f21ca1d18)
+                       printf '\165\346\217\350\22\233\124\153\20\32\356' &&
+                       printf '\225\20\305\62\216\177\41\312\35\30\170\234' &&
+                       printf '\143\142\142\142\147\0\0\0\53\0\16'
+                       return
+                       ;;
+               esac
+               ;;
+       esac
+
+       echo >&2 "BUG: don't know how to print $1${2:+ (from $2)}"
+       return 1
+}
+
+# Compute and append pack trailer to "$1"
+pack_trailer () {
+       test-sha1 -b <"$1" >trailer.tmp &&
+       cat trailer.tmp >>"$1" &&
+       rm -f trailer.tmp
+}
+
+# Remove any existing packs to make sure that
+# whatever we index next will be the pack that we
+# actually use.
+clear_packs () {
+       rm -f .git/objects/pack/*
+}
index ad664105646d4579a4e31ea5d230268acc33c0f5..9fb582b192e7d44856d3687234de922217e511f4 100755 (executable)
@@ -379,6 +379,10 @@ test_expect_success 'init with separate gitdir' '
        test -d realgitdir/refs
 '
 
+test_expect_success 're-init on .git file' '
+       ( cd newdir && git init )
+'
+
 test_expect_success 're-init to update git link' '
        (
        cd newdir &&
index 96f40fedfb7285b50243a1c1bbe64649ef7f8edb..181513ab4fba47750b3e6b25eb105f2c8a4a011f 100755 (executable)
@@ -66,11 +66,11 @@ test_check_ignore () {
 
        init_vars &&
        rm -f "$HOME/stdout" "$HOME/stderr" "$HOME/cmd" &&
-       echo git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $args \
+       echo git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $no_index_opt $args \
                >"$HOME/cmd" &&
        echo "$expect_code" >"$HOME/expected-exit-code" &&
        test_expect_code "$expect_code" \
-               git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $args \
+               git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $no_index_opt $args \
                >"$HOME/stdout" 2>"$HOME/stderr" &&
        test_cmp "$HOME/expected-stdout" "$HOME/stdout" &&
        stderr_empty_on_success "$expect_code"
@@ -87,6 +87,9 @@ test_check_ignore () {
 # check-ignore --verbose output is the same as normal output except
 # for the extra first column.
 #
+# A parameter is used to determine if the tests are run with the
+# normal case (using the index), or with the --no-index option.
+#
 # Arguments:
 #   - (optional) prereqs for this test, e.g. 'SYMLINKS'
 #   - test name
@@ -94,19 +97,26 @@ test_check_ignore () {
 #     from the other verbosity modes is automatically inferred
 #     from this value)
 #   - code to run (should invoke test_check_ignore)
-test_expect_success_multi () {
+#   - index option: --index or --no-index
+test_expect_success_multiple () {
        prereq=
-       if test $# -eq 4
+       if test $# -eq 5
        then
                prereq=$1
                shift
        fi
+       if test "$4" = "--index"
+       then
+               no_index_opt=
+       else
+               no_index_opt=$4
+       fi
        testname="$1" expect_all="$2" code="$3"
 
        expect_verbose=$( echo "$expect_all" | grep -v '^::     ' )
        expect=$( echo "$expect_verbose" | sed -e 's/.* //' )
 
-       test_expect_success $prereq "$testname" '
+       test_expect_success $prereq "$testname${no_index_opt:+ with $no_index_opt}" '
                expect "$expect" &&
                eval "$code"
        '
@@ -116,7 +126,8 @@ test_expect_success_multi () {
        then
                for quiet_opt in '-q' '--quiet'
                do
-                       test_expect_success $prereq "$testname${quiet_opt:+ with $quiet_opt}" "
+                       opts="${no_index_opt:+$no_index_opt }$quiet_opt"
+                       test_expect_success $prereq "$testname${opts:+ with $opts}" "
                        expect '' &&
                        $code
                "
@@ -126,7 +137,7 @@ test_expect_success_multi () {
 
        for verbose_opt in '-v' '--verbose'
        do
-               for non_matching_opt in '' ' -n' ' --non-matching'
+               for non_matching_opt in '' '-n' '--non-matching'
                do
                        if test -n "$non_matching_opt"
                        then
@@ -139,12 +150,21 @@ test_expect_success_multi () {
                                expect '$my_expect' &&
                                $code
                        "
-                       opts="$verbose_opt$non_matching_opt"
+                       opts="${no_index_opt:+$no_index_opt }$verbose_opt${non_matching_opt:+ $non_matching_opt}"
                        test_expect_success $prereq "$testname${opts:+ with $opts}" "$test_code"
                done
        done
        verbose_opt=
        non_matching_opt=
+       no_index_opt=
+}
+
+test_expect_success_multi () {
+       test_expect_success_multiple "$@" "--index"
+}
+
+test_expect_success_no_index_multi () {
+       test_expect_success_multiple "$@" "--no-index"
 }
 
 test_expect_success 'setup' '
@@ -288,7 +308,7 @@ test_expect_success_multi 'needs work tree' '' '
 
 # First make sure that the presence of a file in the working tree
 # does not impact results, but that the presence of a file in the
-# index does.
+# index does unless the --no-index option is used.
 
 for subdir in '' 'a/'
 do
@@ -303,27 +323,61 @@ do
                "::     ${subdir}non-existent" \
                "test_check_ignore '${subdir}non-existent' 1"
 
+       test_expect_success_no_index_multi "non-existent file $where not ignored" \
+               "::     ${subdir}non-existent" \
+               "test_check_ignore '${subdir}non-existent' 1"
+
        test_expect_success_multi "non-existent file $where ignored" \
                ".gitignore:1:one       ${subdir}one" \
                "test_check_ignore '${subdir}one'"
 
+       test_expect_success_no_index_multi "non-existent file $where ignored" \
+               ".gitignore:1:one       ${subdir}one" \
+               "test_check_ignore '${subdir}one'"
+
        test_expect_success_multi "existing untracked file $where not ignored" \
                "::     ${subdir}not-ignored" \
                "test_check_ignore '${subdir}not-ignored' 1"
 
+       test_expect_success_no_index_multi "existing untracked file $where not ignored" \
+               "::     ${subdir}not-ignored" \
+               "test_check_ignore '${subdir}not-ignored' 1"
+
        test_expect_success_multi "existing tracked file $where not ignored" \
                "::     ${subdir}ignored-but-in-index" \
                "test_check_ignore '${subdir}ignored-but-in-index' 1"
 
+       test_expect_success_no_index_multi "existing tracked file $where shown as ignored" \
+               ".gitignore:2:ignored-* ${subdir}ignored-but-in-index" \
+               "test_check_ignore '${subdir}ignored-but-in-index'"
+
        test_expect_success_multi "existing untracked file $where ignored" \
                ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
                "test_check_ignore '${subdir}ignored-and-untracked'"
 
+       test_expect_success_no_index_multi "existing untracked file $where ignored" \
+               ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
+               "test_check_ignore '${subdir}ignored-and-untracked'"
+
        test_expect_success_multi "mix of file types $where" \
 "::    ${subdir}non-existent
 .gitignore:1:one       ${subdir}one
 ::     ${subdir}not-ignored
 ::     ${subdir}ignored-but-in-index
+.gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
+               "test_check_ignore '
+                       ${subdir}non-existent
+                       ${subdir}one
+                       ${subdir}not-ignored
+                       ${subdir}ignored-but-in-index
+                       ${subdir}ignored-and-untracked'
+               "
+
+       test_expect_success_no_index_multi "mix of file types $where" \
+"::    ${subdir}non-existent
+.gitignore:1:one       ${subdir}one
+::     ${subdir}not-ignored
+.gitignore:2:ignored-* ${subdir}ignored-but-in-index
 .gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
                "test_check_ignore '
                        ${subdir}non-existent
index 05d78d22a6d0fa5534ae3f37cb3c289595b6c1c5..6b3cedcf24613b9c72c67b02c0b731db67055a26 100755 (executable)
@@ -91,6 +91,7 @@ test_expect_failure CASE_INSENSITIVE_FS 'add (with different case)' '
 test_expect_success "setup unicode normalization tests" '
        test_create_repo unicode &&
        cd unicode &&
+       git config core.precomposeunicode false &&
        touch "$aumlcdiar" &&
        git add "$aumlcdiar" &&
        git commit -m initial &&
diff --git a/t/t0056-git-C.sh b/t/t0056-git-C.sh
new file mode 100755 (executable)
index 0000000..99c0377
--- /dev/null
@@ -0,0 +1,84 @@
+#!/bin/sh
+
+test_description='"-C <path>" option and its effects on other path-related options'
+
+. ./test-lib.sh
+
+test_expect_success '"git -C <path>" runs git from the directory <path>' '
+       test_create_repo dir1 &&
+       echo 1 >dir1/a.txt &&
+       msg="initial in dir1" &&
+       (cd dir1 && git add a.txt && git commit -m "$msg") &&
+       echo "$msg" >expected &&
+       git -C dir1 log --format=%s >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'Multiple -C options: "-C dir1 -C dir2" is equivalent to "-C dir1/dir2"' '
+       test_create_repo dir1/dir2 &&
+       echo 1 >dir1/dir2/b.txt &&
+       git -C dir1/dir2 add b.txt &&
+       msg="initial in dir1/dir2" &&
+       echo "$msg" >expected &&
+       git -C dir1/dir2 commit -m "$msg" &&
+       git -C dir1 -C dir2 log --format=%s >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'Effect on --git-dir option: "-C c --git-dir=a.git" is equivalent to "--git-dir c/a.git"' '
+       mkdir c &&
+       mkdir c/a &&
+       mkdir c/a.git &&
+       (cd c/a.git && git init --bare) &&
+       echo 1 >c/a/a.txt &&
+       git --git-dir c/a.git --work-tree=c/a add a.txt &&
+       git --git-dir c/a.git --work-tree=c/a commit -m "initial" &&
+       git --git-dir=c/a.git log -1 --format=%s >expected &&
+       git -C c --git-dir=a.git log -1 --format=%s >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'Order should not matter: "--git-dir=a.git -C c" is equivalent to "-C c --git-dir=a.git"' '
+       git -C c --git-dir=a.git log -1 --format=%s >expected &&
+       git --git-dir=a.git -C c log -1 --format=%s >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'Effect on --work-tree option: "-C c/a.git --work-tree=../a"  is equivalent to "--work-tree=c/a --git-dir=c/a.git"' '
+       rm c/a/a.txt &&
+       git --git-dir=c/a.git --work-tree=c/a status >expected &&
+       git -C c/a.git --work-tree=../a status >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'Order should not matter: "--work-tree=../a -C c/a.git" is equivalent to "-C c/a.git --work-tree=../a"' '
+       git -C c/a.git --work-tree=../a status >expected &&
+       git --work-tree=../a -C c/a.git status >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'Effect on --git-dir and --work-tree options - "-C c --git-dir=a.git --work-tree=a" is equivalent to "--git-dir=c/a.git --work-tree=c/a"' '
+       git --git-dir=c/a.git --work-tree=c/a status >expected &&
+       git -C c --git-dir=a.git --work-tree=a status >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'Order should not matter: "-C c --git-dir=a.git --work-tree=a" is equivalent to "--git-dir=a.git -C c --work-tree=a"' '
+       git -C c --git-dir=a.git --work-tree=a status >expected &&
+       git --git-dir=a.git -C c --work-tree=a status >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'Order should not matter: "-C c --git-dir=a.git --work-tree=a" is equivalent to "--git-dir=a.git --work-tree=a -C c"' '
+       git -C c --git-dir=a.git --work-tree=a status >expected &&
+       git --git-dir=a.git --work-tree=a -C c status >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'Relative followed by fullpath: "-C ./here -C /there" is equivalent to "-C /there"' '
+       echo "initial in dir1/dir2" >expected &&
+       git -C dir1 -C "$(pwd)/dir1/dir2" log --format=%s >actual &&
+       test_cmp expected actual
+'
+
+test_done
index 3a48de20d8e0d63a6901cb8df037805e97c5c3f3..2bd5e3274549c7a50375e90e58fa5a4dc393491d 100755 (executable)
@@ -8,13 +8,13 @@ test_description='Test various path utilities'
 . ./test-lib.sh
 
 norm_path() {
-       expected=$(test-path-utils mingw_path "$2")
+       expected=$(test-path-utils print_path "$2")
        test_expect_success $3 "normalize path: $1 => $2" \
        "test \"\$(test-path-utils normalize_path_copy '$1')\" = '$expected'"
 }
 
 relative_path() {
-       expected=$(test-path-utils mingw_path "$3")
+       expected=$(test-path-utils print_path "$3")
        test_expect_success $4 "relative path: $1 $2 => $3" \
        "test \"\$(test-path-utils relative_path '$1' '$2')\" = '$expected'"
 }
index c23f4781e102425d3bcc1de69cf48fc79e15509b..967359344dab8118dfd55816ef08f4809a9f33ad 100755 (executable)
@@ -652,16 +652,23 @@ test_expect_success numbers '
        test_cmp expect actual
 '
 
+test_expect_success '--int is at least 64 bits' '
+       git config giga.watts 121g &&
+       echo 129922760704 >expect &&
+       git config --int --get giga.watts >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'invalid unit' '
        git config aninvalid.unit "1auto" &&
        echo 1auto >expect &&
        git config aninvalid.unit >actual &&
        test_cmp expect actual &&
-       cat > expect <<-\EOF
-       fatal: bad config value for '\''aninvalid.unit'\'' in .git/config
+       cat >expect <<-\EOF
+       fatal: bad numeric config value '\''1auto'\'' for '\''aninvalid.unit'\'' in .git/config: invalid unit
        EOF
        test_must_fail git config --int --get aninvalid.unit 2>actual &&
-       test_cmp actual expect
+       test_i18ncmp expect actual
 '
 
 cat > expect << EOF
index e415ee0bbf1dcf45f3ee771d0fefedb1c8fa4246..6ffd82fe321cd3154d6f193c21198218e762f1b2 100755 (executable)
@@ -302,4 +302,636 @@ 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")'
 
+a=refs/heads/a
+b=refs/heads/b
+c=refs/heads/c
+E='""'
+F='%s\0'
+pws='path with space'
+
+test_expect_success 'stdin test setup' '
+       echo "$pws" >"$pws" &&
+       git add -- "$pws" &&
+       git commit -m "$pws"
+'
+
+test_expect_success '-z fails without --stdin' '
+       test_must_fail git update-ref -z $m $m $m 2>err &&
+       grep "usage: git update-ref" err
+'
+
+test_expect_success 'stdin works with no input' '
+       >stdin &&
+       git update-ref --stdin <stdin &&
+       git rev-parse --verify -q $m
+'
+
+test_expect_success 'stdin fails on empty line' '
+       echo "" >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: empty command in input" err
+'
+
+test_expect_success 'stdin fails on only whitespace' '
+       echo " " >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: whitespace before command:  " err
+'
+
+test_expect_success 'stdin fails on leading whitespace' '
+       echo " create $a $m" >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: whitespace before command:  create $a $m" err
+'
+
+test_expect_success 'stdin fails on unknown command' '
+       echo "unknown $a" >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: unknown command: unknown $a" err
+'
+
+test_expect_success 'stdin fails on badly quoted input' '
+       echo "create $a \"master" >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: badly quoted argument: \\\"master" err
+'
+
+test_expect_success 'stdin fails on arguments not separated by space' '
+       echo "create \"$a\"master" >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: expected SP but got: master" err
+'
+
+test_expect_success 'stdin fails create with no ref' '
+       echo "create " >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: create line missing <ref>" err
+'
+
+test_expect_success 'stdin fails create with bad ref name' '
+       echo "create ~a $m" >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: invalid ref format: ~a" err
+'
+
+test_expect_success 'stdin fails create with no new value' '
+       echo "create $a" >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: create $a missing <newvalue>" err
+'
+
+test_expect_success 'stdin fails create with too many arguments' '
+       echo "create $a $m $m" >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: create $a has extra input:  $m" err
+'
+
+test_expect_success 'stdin fails update with no ref' '
+       echo "update " >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: update line missing <ref>" err
+'
+
+test_expect_success 'stdin fails update with bad ref name' '
+       echo "update ~a $m" >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: invalid ref format: ~a" err
+'
+
+test_expect_success 'stdin fails update with no new value' '
+       echo "update $a" >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: update $a missing <newvalue>" err
+'
+
+test_expect_success 'stdin fails update with too many arguments' '
+       echo "update $a $m $m $m" >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: update $a has extra input:  $m" err
+'
+
+test_expect_success 'stdin fails delete with no ref' '
+       echo "delete " >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: delete line missing <ref>" err
+'
+
+test_expect_success 'stdin fails delete with bad ref name' '
+       echo "delete ~a $m" >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: invalid ref format: ~a" err
+'
+
+test_expect_success 'stdin fails delete with too many arguments' '
+       echo "delete $a $m $m" >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: delete $a has extra input:  $m" err
+'
+
+test_expect_success 'stdin fails verify with too many arguments' '
+       echo "verify $a $m $m" >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: verify $a has extra input:  $m" err
+'
+
+test_expect_success 'stdin fails option with unknown name' '
+       echo "option unknown" >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: option unknown: unknown" err
+'
+
+test_expect_success 'stdin fails with duplicate refs' '
+       cat >stdin <<-EOF &&
+       create $a $m
+       create $b $m
+       create $a $m
+       EOF
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: Multiple updates for ref '"'"'$a'"'"' not allowed." err
+'
+
+test_expect_success 'stdin create ref works' '
+       echo "create $a $m" >stdin &&
+       git update-ref --stdin <stdin &&
+       git rev-parse $m >expect &&
+       git rev-parse $a >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin update ref creates with zero old value' '
+       echo "update $b $m $Z" >stdin &&
+       git update-ref --stdin <stdin &&
+       git rev-parse $m >expect &&
+       git rev-parse $b >actual &&
+       test_cmp expect actual &&
+       git update-ref -d $b
+'
+
+test_expect_success 'stdin update ref creates with empty old value' '
+       echo "update $b $m $E" >stdin &&
+       git update-ref --stdin <stdin &&
+       git rev-parse $m >expect &&
+       git rev-parse $b >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin create ref works with path with space to blob' '
+       echo "create refs/blobs/pws \"$m:$pws\"" >stdin &&
+       git update-ref --stdin <stdin &&
+       git rev-parse "$m:$pws" >expect &&
+       git rev-parse refs/blobs/pws >actual &&
+       test_cmp expect actual &&
+       git update-ref -d refs/blobs/pws
+'
+
+test_expect_success 'stdin update ref fails with wrong old value' '
+       echo "update $c $m $m~1" >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: Cannot lock the ref '"'"'$c'"'"'" err &&
+       test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin update ref fails with bad old value' '
+       echo "update $c $m does-not-exist" >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: invalid old value for ref $c: does-not-exist" err &&
+       test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin create ref fails with bad new value' '
+       echo "create $c does-not-exist" >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: invalid new value for ref $c: does-not-exist" err &&
+       test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin create ref fails with zero new value' '
+       echo "create $c " >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: create $c given zero new value" err &&
+       test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin update ref works with right old value' '
+       echo "update $b $m~1 $m" >stdin &&
+       git update-ref --stdin <stdin &&
+       git rev-parse $m~1 >expect &&
+       git rev-parse $b >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin delete ref fails with wrong old value' '
+       echo "delete $a $m~1" >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: Cannot lock the ref '"'"'$a'"'"'" err &&
+       git rev-parse $m >expect &&
+       git rev-parse $a >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin delete ref fails with zero old value' '
+       echo "delete $a " >stdin &&
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: delete $a given zero old value" err &&
+       git rev-parse $m >expect &&
+       git rev-parse $a >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin update symref works option no-deref' '
+       git symbolic-ref TESTSYMREF $b &&
+       cat >stdin <<-EOF &&
+       option no-deref
+       update TESTSYMREF $a $b
+       EOF
+       git update-ref --stdin <stdin &&
+       git rev-parse TESTSYMREF >expect &&
+       git rev-parse $a >actual &&
+       test_cmp expect actual &&
+       git rev-parse $m~1 >expect &&
+       git rev-parse $b >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin delete symref works option no-deref' '
+       git symbolic-ref TESTSYMREF $b &&
+       cat >stdin <<-EOF &&
+       option no-deref
+       delete TESTSYMREF $b
+       EOF
+       git update-ref --stdin <stdin &&
+       test_must_fail git rev-parse --verify -q TESTSYMREF &&
+       git rev-parse $m~1 >expect &&
+       git rev-parse $b >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin delete ref works with right old value' '
+       echo "delete $b $m~1" >stdin &&
+       git update-ref --stdin <stdin &&
+       test_must_fail git rev-parse --verify -q $b
+'
+
+test_expect_success 'stdin update/create/verify combination works' '
+       cat >stdin <<-EOF &&
+       update $a $m
+       create $b $m
+       verify $c
+       EOF
+       git update-ref --stdin <stdin &&
+       git rev-parse $m >expect &&
+       git rev-parse $a >actual &&
+       test_cmp expect actual &&
+       git rev-parse $b >actual &&
+       test_cmp expect actual &&
+       test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin update refs works with identity updates' '
+       cat >stdin <<-EOF &&
+       update $a $m $m
+       update $b $m $m
+       update $c $Z $E
+       EOF
+       git update-ref --stdin <stdin &&
+       git rev-parse $m >expect &&
+       git rev-parse $a >actual &&
+       test_cmp expect actual &&
+       git rev-parse $b >actual &&
+       test_cmp expect actual &&
+       test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin update refs fails with wrong old value' '
+       git update-ref $c $m &&
+       cat >stdin <<-EOF &&
+       update $a $m $m
+       update $b $m $m
+       update $c  ''
+       EOF
+       test_must_fail git update-ref --stdin <stdin 2>err &&
+       grep "fatal: Cannot lock the ref '"'"'$c'"'"'" err &&
+       git rev-parse $m >expect &&
+       git rev-parse $a >actual &&
+       test_cmp expect actual &&
+       git rev-parse $b >actual &&
+       test_cmp expect actual &&
+       git rev-parse $c >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin delete refs works with packed and loose refs' '
+       git pack-refs --all &&
+       git update-ref $c $m~1 &&
+       cat >stdin <<-EOF &&
+       delete $a $m
+       update $b $Z $m
+       update $c $E $m~1
+       EOF
+       git update-ref --stdin <stdin &&
+       test_must_fail git rev-parse --verify -q $a &&
+       test_must_fail git rev-parse --verify -q $b &&
+       test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin -z works on empty input' '
+       >stdin &&
+       git update-ref -z --stdin <stdin &&
+       git rev-parse --verify -q $m
+'
+
+test_expect_success 'stdin -z fails on empty line' '
+       echo "" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: whitespace before command: " err
+'
+
+test_expect_success 'stdin -z fails on empty command' '
+       printf $F "" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: empty command in input" err
+'
+
+test_expect_success 'stdin -z fails on only whitespace' '
+       printf $F " " >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: whitespace before command:  " err
+'
+
+test_expect_success 'stdin -z fails on leading whitespace' '
+       printf $F " create $a" "$m" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: whitespace before command:  create $a" err
+'
+
+test_expect_success 'stdin -z fails on unknown command' '
+       printf $F "unknown $a" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: unknown command: unknown $a" err
+'
+
+test_expect_success 'stdin -z fails create with no ref' '
+       printf $F "create " >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: create line missing <ref>" err
+'
+
+test_expect_success 'stdin -z fails create with bad ref name' '
+       printf $F "create ~a " "$m" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: invalid ref format: ~a " err
+'
+
+test_expect_success 'stdin -z fails create with no new value' '
+       printf $F "create $a" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: create $a missing <newvalue>" err
+'
+
+test_expect_success 'stdin -z fails create with too many arguments' '
+       printf $F "create $a" "$m" "$m" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: unknown command: $m" err
+'
+
+test_expect_success 'stdin -z fails update with no ref' '
+       printf $F "update " >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: update line missing <ref>" err
+'
+
+test_expect_success 'stdin -z fails update with bad ref name' '
+       printf $F "update ~a" "$m" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: invalid ref format: ~a" err
+'
+
+test_expect_success 'stdin -z fails update with no new value' '
+       printf $F "update $a" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: update $a missing <newvalue>" err
+'
+
+test_expect_success 'stdin -z fails update with no old value' '
+       printf $F "update $a" "$m" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: update $a missing \\[<oldvalue>\\] NUL" err
+'
+
+test_expect_success 'stdin -z fails update with too many arguments' '
+       printf $F "update $a" "$m" "$m" "$m" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: unknown command: $m" err
+'
+
+test_expect_success 'stdin -z fails delete with no ref' '
+       printf $F "delete " >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: delete line missing <ref>" err
+'
+
+test_expect_success 'stdin -z fails delete with bad ref name' '
+       printf $F "delete ~a" "$m" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: invalid ref format: ~a" err
+'
+
+test_expect_success 'stdin -z fails delete with no old value' '
+       printf $F "delete $a" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: delete $a missing \\[<oldvalue>\\] NUL" err
+'
+
+test_expect_success 'stdin -z fails delete with too many arguments' '
+       printf $F "delete $a" "$m" "$m" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: unknown command: $m" err
+'
+
+test_expect_success 'stdin -z fails verify with too many arguments' '
+       printf $F "verify $a" "$m" "$m" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: unknown command: $m" err
+'
+
+test_expect_success 'stdin -z fails verify with no old value' '
+       printf $F "verify $a" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: verify $a missing \\[<oldvalue>\\] NUL" err
+'
+
+test_expect_success 'stdin -z fails option with unknown name' '
+       printf $F "option unknown" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: option unknown: unknown" err
+'
+
+test_expect_success 'stdin -z fails with duplicate refs' '
+       printf $F "create $a" "$m" "create $b" "$m" "create $a" "$m" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: Multiple updates for ref '"'"'$a'"'"' not allowed." err
+'
+
+test_expect_success 'stdin -z create ref works' '
+       printf $F "create $a" "$m" >stdin &&
+       git update-ref -z --stdin <stdin &&
+       git rev-parse $m >expect &&
+       git rev-parse $a >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin -z update ref creates with zero old value' '
+       printf $F "update $b" "$m" "$Z" >stdin &&
+       git update-ref -z --stdin <stdin &&
+       git rev-parse $m >expect &&
+       git rev-parse $b >actual &&
+       test_cmp expect actual &&
+       git update-ref -d $b
+'
+
+test_expect_success 'stdin -z update ref creates with empty old value' '
+       printf $F "update $b" "$m" "" >stdin &&
+       git update-ref -z --stdin <stdin &&
+       git rev-parse $m >expect &&
+       git rev-parse $b >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin -z create ref works with path with space to blob' '
+       printf $F "create refs/blobs/pws" "$m:$pws" >stdin &&
+       git update-ref -z --stdin <stdin &&
+       git rev-parse "$m:$pws" >expect &&
+       git rev-parse refs/blobs/pws >actual &&
+       test_cmp expect actual &&
+       git update-ref -d refs/blobs/pws
+'
+
+test_expect_success 'stdin -z update ref fails with wrong old value' '
+       printf $F "update $c" "$m" "$m~1" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: Cannot lock the ref '"'"'$c'"'"'" err &&
+       test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin -z update ref fails with bad old value' '
+       printf $F "update $c" "$m" "does-not-exist" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: invalid old value for ref $c: does-not-exist" err &&
+       test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin -z create ref fails with bad new value' '
+       printf $F "create $c" "does-not-exist" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: invalid new value for ref $c: does-not-exist" err &&
+       test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin -z create ref fails with zero new value' '
+       printf $F "create $c" "" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: create $c given zero new value" err &&
+       test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin -z update ref works with right old value' '
+       printf $F "update $b" "$m~1" "$m" >stdin &&
+       git update-ref -z --stdin <stdin &&
+       git rev-parse $m~1 >expect &&
+       git rev-parse $b >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin -z delete ref fails with wrong old value' '
+       printf $F "delete $a" "$m~1" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: Cannot lock the ref '"'"'$a'"'"'" err &&
+       git rev-parse $m >expect &&
+       git rev-parse $a >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin -z delete ref fails with zero old value' '
+       printf $F "delete $a" "$Z" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: delete $a given zero old value" err &&
+       git rev-parse $m >expect &&
+       git rev-parse $a >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin -z update symref works option no-deref' '
+       git symbolic-ref TESTSYMREF $b &&
+       printf $F "option no-deref" "update TESTSYMREF" "$a" "$b" >stdin &&
+       git update-ref -z --stdin <stdin &&
+       git rev-parse TESTSYMREF >expect &&
+       git rev-parse $a >actual &&
+       test_cmp expect actual &&
+       git rev-parse $m~1 >expect &&
+       git rev-parse $b >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin -z delete symref works option no-deref' '
+       git symbolic-ref TESTSYMREF $b &&
+       printf $F "option no-deref" "delete TESTSYMREF" "$b" >stdin &&
+       git update-ref -z --stdin <stdin &&
+       test_must_fail git rev-parse --verify -q TESTSYMREF &&
+       git rev-parse $m~1 >expect &&
+       git rev-parse $b >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin -z delete ref works with right old value' '
+       printf $F "delete $b" "$m~1" >stdin &&
+       git update-ref -z --stdin <stdin &&
+       test_must_fail git rev-parse --verify -q $b
+'
+
+test_expect_success 'stdin -z update/create/verify combination works' '
+       printf $F "update $a" "$m" "" "create $b" "$m" "verify $c" "" >stdin &&
+       git update-ref -z --stdin <stdin &&
+       git rev-parse $m >expect &&
+       git rev-parse $a >actual &&
+       test_cmp expect actual &&
+       git rev-parse $b >actual &&
+       test_cmp expect actual &&
+       test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin -z update refs works with identity updates' '
+       printf $F "update $a" "$m" "$m" "update $b" "$m" "$m" "update $c" "$Z" "" >stdin &&
+       git update-ref -z --stdin <stdin &&
+       git rev-parse $m >expect &&
+       git rev-parse $a >actual &&
+       test_cmp expect actual &&
+       git rev-parse $b >actual &&
+       test_cmp expect actual &&
+       test_must_fail git rev-parse --verify -q $c
+'
+
+test_expect_success 'stdin -z update refs fails with wrong old value' '
+       git update-ref $c $m &&
+       printf $F "update $a" "$m" "$m" "update $b" "$m" "$m" "update $c" "" "$Z" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin 2>err &&
+       grep "fatal: Cannot lock the ref '"'"'$c'"'"'" err &&
+       git rev-parse $m >expect &&
+       git rev-parse $a >actual &&
+       test_cmp expect actual &&
+       git rev-parse $b >actual &&
+       test_cmp expect actual &&
+       git rev-parse $c >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin -z delete refs works with packed and loose refs' '
+       git pack-refs --all &&
+       git update-ref $c $m~1 &&
+       printf $F "delete $a" "$m" "update $b" "$Z" "$m" "update $c" "" "$m~1" >stdin &&
+       git update-ref -z --stdin <stdin &&
+       test_must_fail git rev-parse --verify -q $a &&
+       test_must_fail git rev-parse --verify -q $b &&
+       test_must_fail git rev-parse --verify -q $c
+'
+
 test_done
index e5aea3b89602fdaf5ed3a9a230a604dd3f48cda0..ceb844985f97e9472ffcc3fe2f375912d126a4e8 100755 (executable)
@@ -32,6 +32,9 @@ test_expect_success 'setup' '
        git checkout -b upstream-branch &&
        test_commit upstream-one &&
        test_commit upstream-two &&
+       git checkout -b @/at-test &&
+       git checkout -b @@/at-test &&
+       git checkout -b @at-test &&
        git checkout -b old-branch &&
        test_commit old-one &&
        test_commit old-two &&
@@ -55,6 +58,11 @@ check "HEAD@{u}" ref refs/heads/upstream-branch
 check "@{u}@{1}" commit upstream-one
 check "@{-1}@{u}" ref refs/heads/master
 check "@{-1}@{u}@{1}" commit master-one
+check "@" commit new-two
+check "@@{u}" ref refs/heads/upstream-branch
+check "@@/at-test" ref refs/heads/@@/at-test
+check "@/at-test" ref refs/heads/@/at-test
+check "@at-test" ref refs/heads/@at-test
 nonsense "@{u}@{-1}"
 nonsense "@{0}@{0}"
 nonsense "@{1}@{u}"
index eaefc777bd98aeb4cae2ba34eec0e5fe2c2fbd72..15973f20945769fd7661cd4b203e96032495a60e 100755 (executable)
@@ -54,6 +54,13 @@ test_expect_success 'ref^{tree}' '
        test_must_fail git rev-parse blob-tag^{tree}
 '
 
+test_expect_success 'ref^{tag}' '
+       test_must_fail git rev-parse HEAD^{tag} &&
+       git rev-parse commit-tag >expected &&
+       git rev-parse commit-tag^{tag} >actual &&
+       test_cmp expected actual
+'
+
 test_expect_success 'ref^{/.}' '
        git rev-parse master >expected &&
        git rev-parse master^{/.} >actual &&
index 3e098ab31e1944abe8e5815c0f219947620b6618..eadb9434ae764cc0ca57085a6ce28dd5bee4bb77 100755 (executable)
@@ -58,13 +58,13 @@ test_expect_success 'checkout with simple prefix' '
 
 '
 
-# This is not expected to work as ls-files was not designed
-# to deal with such.  Enable it when ls-files is updated.
-: test_expect_success 'checkout with complex relative path' '
-
-       rm file1 &&
-       git checkout HEAD -- ../dir1/../dir1/file1 && test -f ./file1
-
+test_expect_success 'checkout with complex relative path' '
+       (
+               cd dir1 &&
+               rm file1 &&
+               git checkout HEAD -- ../dir1/../dir1/file1 &&
+               test "hello" = "$(cat file1)"
+       )
 '
 
 test_expect_success 'relative path outside tree should fail' \
index dee55e428f07eeac9c2d2c329ff2c1aca3f4ea98..094b92ef489156980dc1429136d5dad25d01ac7d 100755 (executable)
@@ -104,7 +104,7 @@ test_expect_success 'setup more remotes with unconventional refspecs' '
                cd repo_c &&
                test_commit c_master &&
                git checkout -b bar &&
-               test_commit c_bar
+               test_commit c_bar &&
                git checkout -b spam &&
                test_commit c_spam
        ) &&
@@ -113,9 +113,9 @@ test_expect_success 'setup more remotes with unconventional refspecs' '
                cd repo_d &&
                test_commit d_master &&
                git checkout -b baz &&
-               test_commit f_baz
+               test_commit d_baz &&
                git checkout -b eggs &&
-               test_commit c_eggs
+               test_commit d_eggs
        ) &&
        git remote add repo_c repo_c &&
        git config remote.repo_c.fetch \
index f0421c09c700bc1203d2ef563c54157e94c83b33..b2798feef7316e74584058f594e97af01cb5065e 100755 (executable)
@@ -115,7 +115,7 @@ EOF
 
 git config core.excludesFile excludes-file
 
-git status | grep "^#  " > output
+git -c status.displayCommentPrefix=true status | grep "^#      " > output
 
 cat > expect << EOF
 #      .gitignore
index f611d799b690457e306571adf16813b238a27dc9..6d3b828a951e4c03b886087393269dbe4d5c5c8f 100755 (executable)
@@ -11,6 +11,7 @@ This test prepares the following in the cache:
     path1       - a symlink
     path2/file2 - a file in a directory
     path3/file3 - a file in a directory
+    pathx/ju    - a file in a directory
     submod1/   - a submodule
     submod2/   - another submodule
 
@@ -23,6 +24,7 @@ and the following on the filesystem:
     path4      - a file
     path5      - a symlink
     path6/file6 - a file in a directory
+    pathx/ju/nk - a file in a directory to be killed
     submod1/   - a submodule (modified from the cache)
     submod2/   - a submodule (matches the cache)
 
@@ -44,14 +46,15 @@ modified without reporting path9 and path10.  submod1 is also modified.
 test_expect_success 'git update-index --add to add various paths.' '
        date >path0 &&
        test_ln_s_add xyzzy path1 &&
-       mkdir path2 path3 &&
+       mkdir path2 path3 pathx &&
        date >path2/file2 &&
        date >path3/file3 &&
+       >pathx/ju &&
        : >path7 &&
        date >path8 &&
        : >path9 &&
        date >path10 &&
-       git update-index --add -- path0 path?/file? path7 path8 path9 path10 &&
+       git update-index --add -- path0 path?/file? pathx/ju path7 path8 path9 path10 &&
        for i in 1 2
        do
                git init submod$i &&
@@ -77,7 +80,7 @@ test_expect_success 'git ls-files -k to show killed files.' '
                date >path3 &&
                date >path5
        fi &&
-       mkdir path0 path1 path6 &&
+       mkdir -p path0 path1 path6 pathx/ju &&
        date >path0/file0 &&
        date >path1/file1 &&
        date >path6/file6 &&
@@ -85,16 +88,23 @@ test_expect_success 'git ls-files -k to show killed files.' '
        : >path8 &&
        : >path9 &&
        touch path10 &&
-       git ls-files -k >.output
-'
-
-test_expect_success 'validate git ls-files -k output.' '
-       cat >.expected <<-\EOF &&
+       >pathx/ju/nk &&
+       cat >.expected <<-\EOF
        path0/file0
        path1/file1
        path2
        path3
+       pathx/ju/nk
        EOF
+'
+
+test_expect_success 'git ls-files -k output (w/o icase)' '
+       git ls-files -k >.output
+       test_cmp .expected .output
+'
+
+test_expect_success 'git ls-files -k output (w/ icase)' '
+       git -c core.ignorecase=true ls-files -k >.output
        test_cmp .expected .output
 '
 
@@ -110,6 +120,7 @@ test_expect_success 'validate git ls-files -m output.' '
        path3/file3
        path7
        path8
+       pathx/ju
        submod1
        EOF
        test_cmp .expected .output
index 44ec6a45f473ffe47aca6945c0e0aab445728f67..0fe7647928b9d20963e60e56009f72c54ee488e2 100755 (executable)
@@ -14,7 +14,8 @@ test_expect_success 'prepare a trivial repository' '
        echo World >>A &&
        git update-index --add A &&
        git commit -m "Second commit." &&
-       HEAD=$(git rev-parse --verify HEAD)'
+       HEAD=$(git rev-parse --verify HEAD)
+'
 
 test_expect_success 'git branch --help should not have created a bogus branch' '
        test_might_fail git branch --help </dev/null >/dev/null 2>/dev/null &&
@@ -319,8 +320,9 @@ test_expect_success 'test tracking setup (non-wildcard, matching)' '
 
 test_expect_success 'tracking setup fails on non-matching refspec' '
        git config remote.local.url . &&
-       git config remote.local.fetch refs/heads/s:refs/remotes/local/s &&
+       git config remote.local.fetch refs/heads/*:refs/remotes/local/* &&
        (git show-ref -q refs/remotes/local/master || git fetch local) &&
+       git config remote.local.fetch refs/heads/s:refs/remotes/local/s &&
        test_must_fail git branch --track my5 local/master &&
        test_must_fail git config branch.my5.remote &&
        test_must_fail git config branch.my5.merge
@@ -350,7 +352,7 @@ test_expect_success 'test overriding tracking setup via --no-track' '
 test_expect_success 'no tracking without .fetch entries' '
        git config branch.autosetupmerge true &&
        git branch my6 s &&
-       git config branch.automsetupmerge false &&
+       git config branch.autosetupmerge false &&
        test -z "$(git config branch.my6.remote)" &&
        test -z "$(git config branch.my6.merge)"
 '
@@ -424,14 +426,14 @@ test_expect_success '--set-upstream-to fails on a non-ref' '
 test_expect_success 'use --set-upstream-to modify HEAD' '
        test_config branch.master.remote foo &&
        test_config branch.master.merge foo &&
-       git branch my12
+       git branch my12 &&
        git branch --set-upstream-to my12 &&
        test "$(git config branch.master.remote)" = "." &&
        test "$(git config branch.master.merge)" = "refs/heads/my12"
 '
 
 test_expect_success 'use --set-upstream-to modify a particular branch' '
-       git branch my13
+       git branch my13 &&
        git branch --set-upstream-to master my13 &&
        test "$(git config branch.my13.remote)" = "." &&
        test "$(git config branch.my13.merge)" = "refs/heads/master"
@@ -442,7 +444,7 @@ test_expect_success '--unset-upstream should fail if given a non-existent branch
 '
 
 test_expect_success 'test --unset-upstream on HEAD' '
-       git branch my14
+       git branch my14 &&
        test_config branch.master.remote foo &&
        test_config branch.master.merge foo &&
        git branch --set-upstream-to my14 &&
@@ -464,7 +466,7 @@ test_expect_success '--unset-upstream should fail on detached HEAD' '
 '
 
 test_expect_success 'test --unset-upstream on a particular branch' '
-       git branch my15
+       git branch my15 &&
        git branch --set-upstream-to master my14 &&
        git branch --unset-upstream my14 &&
        test_must_fail git config branch.my14.remote &&
@@ -870,4 +872,39 @@ test_expect_success '--merged catches invalid object names' '
        test_must_fail git branch --merged 0000000000000000000000000000000000000000
 '
 
+test_expect_success 'tracking with unexpected .fetch refspec' '
+       rm -rf a b c d &&
+       git init a &&
+       (
+               cd a &&
+               test_commit a
+       ) &&
+       git init b &&
+       (
+               cd b &&
+               test_commit b
+       ) &&
+       git init c &&
+       (
+               cd c &&
+               test_commit c &&
+               git remote add a ../a &&
+               git remote add b ../b &&
+               git fetch --all
+       ) &&
+       git init d &&
+       (
+               cd d &&
+               git remote add c ../c &&
+               git config remote.c.fetch "+refs/remotes/*:refs/remotes/*" &&
+               git fetch c &&
+               git branch --track local/a/master remotes/a/master &&
+               test "$(git config branch.local/a/master.remote)" = "c" &&
+               test "$(git config branch.local/a/master.merge)" = "refs/remotes/a/master" &&
+               git rev-parse --verify a >expect &&
+               git rev-parse --verify local/a/master >actual &&
+               test_cmp expect actual
+       )
+'
+
 test_done
index 4dbeddb0de17eb9fa87fbed98daabcb180235555..50e22b1cadff4252dfb552a4db930f49544952aa 100755 (executable)
@@ -29,8 +29,6 @@ Initial setup:
 
 . "$TEST_DIRECTORY"/lib-rebase.sh
 
-set_fake_editor
-
 # WARNING: Modifications to the initial repository can change the SHA ID used
 # in the expect2 file for the 'stop on conflicting pick' test.
 
@@ -72,6 +70,7 @@ export SHELL
 test_expect_success 'rebase -i with the exec command' '
        git checkout master &&
        (
+       set_fake_editor &&
        FAKE_LINES="1 exec_>touch-one
                2 exec_>touch-two exec_false exec_>touch-three
                3 4 exec_>\"touch-file__name_with_spaces\";_>touch-after-semicolon 5" &&
@@ -93,6 +92,7 @@ test_expect_success 'rebase -i with the exec command' '
 test_expect_success 'rebase -i with the exec command runs from tree root' '
        git checkout master &&
        mkdir subdir && (cd subdir &&
+       set_fake_editor &&
        FAKE_LINES="1 exec_>touch-subdir" \
                git rebase -i HEAD^
        ) &&
@@ -103,6 +103,7 @@ test_expect_success 'rebase -i with the exec command runs from tree root' '
 test_expect_success 'rebase -i with the exec command checks tree cleanness' '
        git checkout master &&
        (
+       set_fake_editor &&
        FAKE_LINES="exec_echo_foo_>file1 1" &&
        export FAKE_LINES &&
        test_must_fail git rebase -i HEAD^
@@ -116,6 +117,7 @@ test_expect_success 'rebase -i with exec of inexistent command' '
        git checkout master &&
        test_when_finished "git rebase --abort" &&
        (
+       set_fake_editor &&
        FAKE_LINES="exec_this-command-does-not-exist 1" &&
        export FAKE_LINES &&
        test_must_fail git rebase -i HEAD^ >actual 2>&1
@@ -125,6 +127,7 @@ test_expect_success 'rebase -i with exec of inexistent command' '
 
 test_expect_success 'no changes are a nop' '
        git checkout branch2 &&
+       set_fake_editor &&
        git rebase -i F &&
        test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" &&
        test $(git rev-parse I) = $(git rev-parse HEAD)
@@ -134,6 +137,7 @@ test_expect_success 'test the [branch] option' '
        git checkout -b dead-end &&
        git rm file6 &&
        git commit -m "stop here" &&
+       set_fake_editor &&
        git rebase -i F branch2 &&
        test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch2" &&
        test $(git rev-parse I) = $(git rev-parse branch2) &&
@@ -142,6 +146,7 @@ test_expect_success 'test the [branch] option' '
 
 test_expect_success 'test --onto <branch>' '
        git checkout -b test-onto branch2 &&
+       set_fake_editor &&
        git rebase -i --onto branch1 F &&
        test "$(git symbolic-ref -q HEAD)" = "refs/heads/test-onto" &&
        test $(git rev-parse HEAD^) = $(git rev-parse branch1) &&
@@ -151,6 +156,7 @@ test_expect_success 'test --onto <branch>' '
 test_expect_success 'rebase on top of a non-conflicting commit' '
        git checkout branch1 &&
        git tag original-branch1 &&
+       set_fake_editor &&
        git rebase -i branch2 &&
        test file6 = $(git diff --name-only original-branch1) &&
        test "$(git symbolic-ref -q HEAD)" = "refs/heads/branch1" &&
@@ -163,6 +169,7 @@ test_expect_success 'reflog for the branch shows state before rebase' '
 '
 
 test_expect_success 'exchange two commits' '
+       set_fake_editor &&
        FAKE_LINES="2 1" git rebase -i HEAD~2 &&
        test H = $(git cat-file commit HEAD^ | sed -ne \$p) &&
        test G = $(git cat-file commit HEAD | sed -ne \$p)
@@ -188,6 +195,7 @@ EOF
 
 test_expect_success 'stop on conflicting pick' '
        git tag new-branch1 &&
+       set_fake_editor &&
        test_must_fail git rebase -i master &&
        test "$(git rev-parse HEAD~3)" = "$(git rev-parse master)" &&
        test_cmp expect .git/rebase-merge/patch &&
@@ -208,6 +216,7 @@ test_expect_success 'abort' '
 test_expect_success 'abort with error when new base cannot be checked out' '
        git rm --cached file1 &&
        git commit -m "remove file in base" &&
+       set_fake_editor &&
        test_must_fail git rebase -i master > output 2>&1 &&
        grep "The following untracked working tree files would be overwritten by checkout:" \
                output &&
@@ -222,6 +231,7 @@ test_expect_success 'retain authorship' '
        test_tick &&
        GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" &&
        git tag twerp &&
+       set_fake_editor &&
        git rebase -i --onto master HEAD^ &&
        git show HEAD | grep "^Author: Twerp Snog"
 '
@@ -232,6 +242,7 @@ test_expect_success 'squash' '
        test_tick &&
        GIT_AUTHOR_NAME="Nitfol" git commit -m "nitfol" file7 &&
        echo "******************************" &&
+       set_fake_editor &&
        FAKE_LINES="1 squash 2" EXPECT_HEADER_COUNT=2 \
                git rebase -i --onto master HEAD~2 &&
        test B = $(cat file7) &&
@@ -244,6 +255,7 @@ test_expect_success 'retain authorship when squashing' '
 
 test_expect_success '-p handles "no changes" gracefully' '
        HEAD=$(git rev-parse HEAD) &&
+       set_fake_editor &&
        git rebase -i -p HEAD^ &&
        git update-index --refresh &&
        git diff-files --quiet &&
@@ -253,6 +265,7 @@ test_expect_success '-p handles "no changes" gracefully' '
 
 test_expect_failure 'exchange two commits with -p' '
        git checkout H &&
+       set_fake_editor &&
        FAKE_LINES="2 1" git rebase -i -p HEAD~2 &&
        test H = $(git cat-file commit HEAD^ | sed -ne \$p) &&
        test G = $(git cat-file commit HEAD | sed -ne \$p)
@@ -287,6 +300,7 @@ test_expect_success 'preserve merges with -p' '
        git commit -m M file1 &&
        git checkout -b to-be-rebased &&
        test_tick &&
+       set_fake_editor &&
        git rebase -i -p --onto branch1 master &&
        git update-index --refresh &&
        git diff-files --quiet &&
@@ -301,6 +315,7 @@ test_expect_success 'preserve merges with -p' '
 '
 
 test_expect_success 'edit ancestor with -p' '
+       set_fake_editor &&
        FAKE_LINES="1 2 edit 3 4" git rebase -i -p HEAD~3 &&
        echo 2 > unrelated-file &&
        test_tick &&
@@ -314,6 +329,7 @@ test_expect_success 'edit ancestor with -p' '
 
 test_expect_success '--continue tries to commit' '
        test_tick &&
+       set_fake_editor &&
        test_must_fail git rebase -i --onto new-branch1 HEAD^ &&
        echo resolved > file1 &&
        git add file1 &&
@@ -325,6 +341,7 @@ test_expect_success '--continue tries to commit' '
 test_expect_success 'verbose flag is heeded, even after --continue' '
        git reset --hard master@{1} &&
        test_tick &&
+       set_fake_editor &&
        test_must_fail git rebase -v -i --onto new-branch1 HEAD^ &&
        echo resolved > file1 &&
        git add file1 &&
@@ -334,6 +351,7 @@ test_expect_success 'verbose flag is heeded, even after --continue' '
 
 test_expect_success 'multi-squash only fires up editor once' '
        base=$(git rev-parse HEAD~4) &&
+       set_fake_editor &&
        FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 squash 2 squash 3 squash 4" \
                EXPECT_HEADER_COUNT=4 \
                git rebase -i $base &&
@@ -344,6 +362,7 @@ test_expect_success 'multi-squash only fires up editor once' '
 test_expect_success 'multi-fixup does not fire up editor' '
        git checkout -b multi-fixup E &&
        base=$(git rev-parse HEAD~4) &&
+       set_fake_editor &&
        FAKE_COMMIT_AMEND="NEVER" FAKE_LINES="1 fixup 2 fixup 3 fixup 4" \
                git rebase -i $base &&
        test $base = $(git rev-parse HEAD^) &&
@@ -355,6 +374,7 @@ test_expect_success 'multi-fixup does not fire up editor' '
 test_expect_success 'commit message used after conflict' '
        git checkout -b conflict-fixup conflict-branch &&
        base=$(git rev-parse HEAD~4) &&
+       set_fake_editor &&
        (
                FAKE_LINES="1 fixup 3 fixup 4" &&
                export FAKE_LINES &&
@@ -373,6 +393,7 @@ test_expect_success 'commit message used after conflict' '
 test_expect_success 'commit message retained after conflict' '
        git checkout -b conflict-squash conflict-branch &&
        base=$(git rev-parse HEAD~4) &&
+       set_fake_editor &&
        (
                FAKE_LINES="1 fixup 3 squash 4" &&
                export FAKE_LINES &&
@@ -399,6 +420,7 @@ EOF
 test_expect_success 'squash and fixup generate correct log messages' '
        git checkout -b squash-fixup E &&
        base=$(git rev-parse HEAD~4) &&
+       set_fake_editor &&
        FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="1 fixup 2 squash 3 fixup 4" \
                EXPECT_HEADER_COUNT=4 \
                git rebase -i $base &&
@@ -411,6 +433,7 @@ test_expect_success 'squash and fixup generate correct log messages' '
 test_expect_success 'squash ignores comments' '
        git checkout -b skip-comments E &&
        base=$(git rev-parse HEAD~4) &&
+       set_fake_editor &&
        FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="# 1 # squash 2 # squash 3 # squash 4 #" \
                EXPECT_HEADER_COUNT=4 \
                git rebase -i $base &&
@@ -423,6 +446,7 @@ test_expect_success 'squash ignores comments' '
 test_expect_success 'squash ignores blank lines' '
        git checkout -b skip-blank-lines E &&
        base=$(git rev-parse HEAD~4) &&
+       set_fake_editor &&
        FAKE_COMMIT_AMEND="ONCE" FAKE_LINES="> 1 > squash 2 > squash 3 > squash 4 >" \
                EXPECT_HEADER_COUNT=4 \
                git rebase -i $base &&
@@ -435,6 +459,7 @@ test_expect_success 'squash ignores blank lines' '
 test_expect_success 'squash works as expected' '
        git checkout -b squash-works no-conflict-branch &&
        one=$(git rev-parse HEAD~3) &&
+       set_fake_editor &&
        FAKE_LINES="1 squash 3 2" EXPECT_HEADER_COUNT=2 \
                git rebase -i HEAD~3 &&
        test $one = $(git rev-parse HEAD~2)
@@ -443,6 +468,7 @@ test_expect_success 'squash works as expected' '
 test_expect_success 'interrupted squash works as expected' '
        git checkout -b interrupted-squash conflict-branch &&
        one=$(git rev-parse HEAD~3) &&
+       set_fake_editor &&
        (
                FAKE_LINES="1 squash 3 2" &&
                export FAKE_LINES &&
@@ -460,6 +486,7 @@ test_expect_success 'interrupted squash works as expected' '
 test_expect_success 'interrupted squash works as expected (case 2)' '
        git checkout -b interrupted-squash2 conflict-branch &&
        one=$(git rev-parse HEAD~3) &&
+       set_fake_editor &&
        (
                FAKE_LINES="3 squash 1 2" &&
                export FAKE_LINES &&
@@ -484,6 +511,7 @@ test_expect_success '--continue tries to commit, even for "edit"' '
        git commit -m "unrelated change" &&
        parent=$(git rev-parse HEAD^) &&
        test_tick &&
+       set_fake_editor &&
        FAKE_LINES="edit 1" git rebase -i HEAD^ &&
        echo edited > file7 &&
        git add file7 &&
@@ -496,6 +524,7 @@ test_expect_success '--continue tries to commit, even for "edit"' '
 test_expect_success 'aborted --continue does not squash commits after "edit"' '
        old=$(git rev-parse HEAD) &&
        test_tick &&
+       set_fake_editor &&
        FAKE_LINES="edit 1" git rebase -i HEAD^ &&
        echo "edited again" > file7 &&
        git add file7 &&
@@ -510,6 +539,7 @@ test_expect_success 'aborted --continue does not squash commits after "edit"' '
 
 test_expect_success 'auto-amend only edited commits after "edit"' '
        test_tick &&
+       set_fake_editor &&
        FAKE_LINES="edit 1" git rebase -i HEAD^ &&
        echo "edited again" > file7 &&
        git add file7 &&
@@ -528,6 +558,7 @@ test_expect_success 'auto-amend only edited commits after "edit"' '
 test_expect_success 'clean error after failed "exec"' '
        test_tick &&
        test_when_finished "git rebase --abort || :" &&
+       set_fake_editor &&
        (
                FAKE_LINES="1 exec_false" &&
                export FAKE_LINES &&
@@ -543,6 +574,7 @@ test_expect_success 'rebase a detached HEAD' '
        grandparent=$(git rev-parse HEAD~2) &&
        git checkout $(git rev-parse HEAD) &&
        test_tick &&
+       set_fake_editor &&
        FAKE_LINES="2 1" git rebase -i HEAD~2 &&
        test $grandparent = $(git rev-parse HEAD~2)
 '
@@ -559,6 +591,7 @@ test_expect_success 'rebase a commit violating pre-commit' '
        test_must_fail git commit -m doesnt-verify file1 &&
        git commit -m doesnt-verify --no-verify file1 &&
        test_tick &&
+       set_fake_editor &&
        FAKE_LINES=2 git rebase -i HEAD~2
 
 '
@@ -580,6 +613,7 @@ test_expect_success 'rebase with a file named HEAD in worktree' '
                git commit -m "Add body"
        ) &&
 
+       set_fake_editor &&
        FAKE_LINES="1 squash 2" git rebase -i to-be-rebased &&
        test "$(git show -s --pretty=format:%an)" = "Squashed Away"
 
@@ -591,6 +625,7 @@ test_expect_success 'do "noop" when there is nothing to cherry-pick' '
        GIT_EDITOR=: git commit --amend \
                --author="Somebody else <somebody@else.com>" &&
        test $(git rev-parse branch3) != $(git rev-parse branch4) &&
+       set_fake_editor &&
        git rebase -i branch3 &&
        test $(git rev-parse branch3) = $(git rev-parse branch4)
 
@@ -615,10 +650,12 @@ test_expect_success 'submodule rebase setup' '
                git commit -a -m "submodule second"
        ) &&
        test_tick &&
+       set_fake_editor &&
        git commit -a -m "Three changes submodule"
 '
 
 test_expect_success 'submodule rebase -i' '
+       set_fake_editor &&
        FAKE_LINES="1 squash 2 3" git rebase -i A
 '
 
@@ -636,6 +673,7 @@ test_expect_success 'submodule conflict setup' '
 '
 
 test_expect_success 'rebase -i continue with only submodule staged' '
+       set_fake_editor &&
        test_must_fail git rebase -i submodule-base &&
        git add sub &&
        git rebase --continue &&
@@ -645,6 +683,7 @@ test_expect_success 'rebase -i continue with only submodule staged' '
 test_expect_success 'rebase -i continue with unstaged submodule' '
        git checkout submodule-topic &&
        git reset --hard &&
+       set_fake_editor &&
        test_must_fail git rebase -i submodule-base &&
        git reset &&
        git rebase --continue &&
@@ -657,6 +696,7 @@ test_expect_success 'avoid unnecessary reset' '
        test-chmtime =123456789 file3 &&
        git update-index --refresh &&
        HEAD=$(git rev-parse HEAD) &&
+       set_fake_editor &&
        git rebase -i HEAD~4 &&
        test $HEAD = $(git rev-parse HEAD) &&
        MTIME=$(test-chmtime -v +0 file3 | sed 's/[^0-9].*$//') &&
@@ -665,6 +705,7 @@ test_expect_success 'avoid unnecessary reset' '
 
 test_expect_success 'reword' '
        git checkout -b reword-branch master &&
+       set_fake_editor &&
        FAKE_LINES="1 2 3 reword 4" FAKE_COMMIT_MESSAGE="E changed" git rebase -i A &&
        git show HEAD | grep "E changed" &&
        test $(git rev-parse master) != $(git rev-parse HEAD) &&
@@ -684,6 +725,7 @@ test_expect_success 'rebase -i can copy notes' '
        test_commit n2 &&
        test_commit n3 &&
        git notes add -m"a note" n3 &&
+       set_fake_editor &&
        git rebase -i --onto n1 n2 &&
        test "a note" = "$(git notes show HEAD)"
 '
@@ -697,6 +739,7 @@ EOF
 test_expect_success 'rebase -i can copy notes over a fixup' '
        git reset --hard n3 &&
        git notes add -m"an earlier note" n2 &&
+       set_fake_editor &&
        GIT_NOTES_REWRITE_MODE=concatenate FAKE_LINES="1 fixup 2" git rebase -i n1 &&
        git notes show > output &&
        test_cmp expect output
@@ -706,6 +749,7 @@ test_expect_success 'rebase while detaching HEAD' '
        git symbolic-ref HEAD &&
        grandparent=$(git rev-parse HEAD~2) &&
        test_tick &&
+       set_fake_editor &&
        FAKE_LINES="2 1" git rebase -i HEAD~2 HEAD^0 &&
        test $grandparent = $(git rev-parse HEAD~2) &&
        test_must_fail git symbolic-ref HEAD
@@ -715,6 +759,7 @@ test_tick # Ensure that the rebased commits get a different timestamp.
 test_expect_success 'always cherry-pick with --no-ff' '
        git checkout no-ff-branch &&
        git tag original-no-ff-branch &&
+       set_fake_editor &&
        git rebase -i --no-ff A &&
        touch empty &&
        for p in 0 1 2
@@ -747,6 +792,7 @@ test_expect_success 'set up commits with funny messages' '
 test_expect_success 'rebase-i history with funny messages' '
        git rev-list A..funny >expect &&
        test_tick &&
+       set_fake_editor &&
        FAKE_LINES="1 2 3 4" git rebase -i A &&
        git rev-list A.. >actual &&
        test_cmp expect actual
@@ -763,6 +809,7 @@ test_expect_success 'prepare for rebase -i --exec' '
 
 
 test_expect_success 'running "git rebase -i --exec git show HEAD"' '
+       set_fake_editor &&
        git rebase -i --exec "git show HEAD" HEAD~2 >actual &&
        (
                FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
@@ -776,6 +823,7 @@ test_expect_success 'running "git rebase -i --exec git show HEAD"' '
 
 test_expect_success 'running "git rebase --exec git show HEAD -i"' '
        git reset --hard execute &&
+       set_fake_editor &&
        git rebase --exec "git show HEAD" -i HEAD~2 >actual &&
        (
                FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
@@ -789,6 +837,7 @@ test_expect_success 'running "git rebase --exec git show HEAD -i"' '
 
 test_expect_success 'running "git rebase -ix git show HEAD"' '
        git reset --hard execute &&
+       set_fake_editor &&
        git rebase -ix "git show HEAD" HEAD~2 >actual &&
        (
                FAKE_LINES="1 exec_git_show_HEAD 2 exec_git_show_HEAD" &&
@@ -802,6 +851,7 @@ test_expect_success 'running "git rebase -ix git show HEAD"' '
 
 test_expect_success 'rebase -ix with several <CMD>' '
        git reset --hard execute &&
+       set_fake_editor &&
        git rebase -ix "git show HEAD; pwd" HEAD~2 >actual &&
        (
                FAKE_LINES="1 exec_git_show_HEAD;_pwd 2 exec_git_show_HEAD;_pwd" &&
@@ -815,6 +865,7 @@ test_expect_success 'rebase -ix with several <CMD>' '
 
 test_expect_success 'rebase -ix with several instances of --exec' '
        git reset --hard execute &&
+       set_fake_editor &&
        git rebase -i --exec "git show HEAD" --exec "pwd" HEAD~2 >actual &&
        (
                FAKE_LINES="1 exec_git_show_HEAD exec_pwd 2
@@ -836,6 +887,7 @@ test_expect_success 'rebase -ix with --autosquash' '
        echo bis >bis.txt &&
        git add bis.txt &&
        git commit -m "fixup! two_exec" &&
+       set_fake_editor &&
        (
                git checkout -b autosquash_actual &&
                git rebase -i --exec "git show HEAD" --autosquash HEAD~4 >actual
@@ -854,6 +906,7 @@ test_expect_success 'rebase -ix with --autosquash' '
 
 test_expect_success 'rebase --exec without -i shows error message' '
        git reset --hard execute &&
+       set_fake_editor &&
        test_must_fail git rebase --exec "git show HEAD" HEAD~2 2>actual &&
        echo "The --exec option must be used with the --interactive option" >expected &&
        test_i18ncmp expected actual
@@ -862,6 +915,7 @@ test_expect_success 'rebase --exec without -i shows error message' '
 
 test_expect_success 'rebase -i --exec without <CMD>' '
        git reset --hard execute &&
+       set_fake_editor &&
        test_must_fail git rebase -i --exec 2>tmp &&
        sed -e "1d" tmp >actual &&
        test_must_fail git rebase -h >expected &&
@@ -871,6 +925,7 @@ test_expect_success 'rebase -i --exec without <CMD>' '
 
 test_expect_success 'rebase -i --root re-order and drop commits' '
        git checkout E &&
+       set_fake_editor &&
        FAKE_LINES="3 1 2 5" git rebase -i --root &&
        test E = $(git cat-file commit HEAD | sed -ne \$p) &&
        test B = $(git cat-file commit HEAD^ | sed -ne \$p) &&
@@ -884,6 +939,7 @@ test_expect_success 'rebase -i --root retain root commit author and message' '
        echo B >file7 &&
        git add file7 &&
        GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" &&
+       set_fake_editor &&
        FAKE_LINES="2" git rebase -i --root &&
        git cat-file commit HEAD | grep -q "^author Twerp Snog" &&
        git cat-file commit HEAD | grep -q "^different author$"
@@ -892,6 +948,7 @@ test_expect_success 'rebase -i --root retain root commit author and message' '
 test_expect_success 'rebase -i --root temporary sentinel commit' '
        git checkout B &&
        (
+               set_fake_editor &&
                FAKE_LINES="2" &&
                export FAKE_LINES &&
                test_must_fail git rebase -i --root
@@ -902,6 +959,7 @@ test_expect_success 'rebase -i --root temporary sentinel commit' '
 
 test_expect_success 'rebase -i --root fixup root commit' '
        git checkout B &&
+       set_fake_editor &&
        FAKE_LINES="1 fixup 2" git rebase -i --root &&
        test A = $(git cat-file commit HEAD | sed -ne \$p) &&
        test B = $(git show HEAD:file1) &&
@@ -911,6 +969,7 @@ test_expect_success 'rebase -i --root fixup root commit' '
 test_expect_success 'rebase --edit-todo does not works on non-interactive rebase' '
        git reset --hard &&
        git checkout conflict-branch &&
+       set_fake_editor &&
        test_must_fail git rebase --onto HEAD~2 HEAD~ &&
        test_must_fail git rebase --edit-todo &&
        git rebase --abort
@@ -919,6 +978,7 @@ test_expect_success 'rebase --edit-todo does not works on non-interactive rebase
 test_expect_success 'rebase --edit-todo can be used to modify todo' '
        git reset --hard &&
        git checkout no-conflict-branch^0 &&
+       set_fake_editor &&
        FAKE_LINES="edit 1 2 3" git rebase -i HEAD~3 &&
        FAKE_LINES="2 1" git rebase --edit-todo &&
        git rebase --continue
@@ -929,6 +989,7 @@ test_expect_success 'rebase --edit-todo can be used to modify todo' '
 test_expect_success 'rebase -i produces readable reflog' '
        git reset --hard &&
        git branch -f branch-reflog-test H &&
+       set_fake_editor &&
        git rebase -i --onto I F branch-reflog-test &&
        cat >expect <<-\EOF &&
        rebase -i (start): checkout I
@@ -989,4 +1050,28 @@ test_expect_success 'rebase -i error on commits with \ in message' '
        test_expect_code 1 grep  "      emp" error
 '
 
+test_expect_success 'short SHA-1 setup' '
+       test_when_finished "git checkout master" &&
+       git checkout --orphan collide &&
+       git rm -rf . &&
+       (
+       unset test_tick &&
+       test_commit collide1 collide &&
+       test_commit --notick collide2 collide &&
+       test_commit --notick collide3 collide
+       )
+'
+
+test_expect_success 'short SHA-1 collide' '
+       test_when_finished "reset_rebase && git checkout master" &&
+       git checkout collide &&
+       (
+       unset test_tick &&
+       test_tick &&
+       set_fake_editor &&
+       FAKE_COMMIT_MESSAGE="collide2 ac4f2ee" \
+       FAKE_LINES="reword 1 2" git rebase -i HEAD~2
+       )
+'
+
 test_done
index 2e0c36415fe525663fdcc64675fd081c642732ed..8c251c57a6827317a9c17fac2a0e99df3c9becf8 100755 (executable)
@@ -28,6 +28,8 @@ export GIT_AUTHOR_EMAIL
 #     \--A3    <-- topic2
 #      \
 #       B2     <-- origin/topic
+#
+# Clone 4 (same as Clone 3)
 
 test_expect_success 'setup for merge-preserving rebase' \
        'echo First > A &&
@@ -64,6 +66,16 @@ test_expect_success 'setup for merge-preserving rebase' \
                git merge --no-ff topic2
        ) &&
 
+       git clone ./. clone4 &&
+       (
+               cd clone4 &&
+               git checkout -b topic2 origin/topic &&
+               echo Sixth > A &&
+               git commit -a -m "Modify A3" &&
+               git checkout -b topic origin/topic &&
+               git merge --no-ff topic2
+       ) &&
+
        git checkout topic &&
        echo Fourth >> B &&
        git commit -a -m "Modify B2"
@@ -96,4 +108,15 @@ test_expect_success 'rebase -p preserves no-ff merges' '
        )
 '
 
+test_expect_success 'rebase -p ignores merge.log config' '
+       (
+       cd clone4 &&
+       git fetch &&
+       git -c merge.log=1 rebase -p origin/topic &&
+       echo >expected &&
+       git log --format="%b" -1 >current &&
+       test_cmp expected current
+       )
+'
+
 test_done
index 6f489e20eecb48c6e1a2dc2b1fe90e47e7b3e7ad..bff6ffe08817ed0c057909aa1d3f93140cf6a3e0 100755 (executable)
@@ -100,7 +100,7 @@ test_expect_success 'revert forbidden on dirty working tree' '
 
 '
 
-test_expect_success 'chery-pick on unborn branch' '
+test_expect_success 'cherry-pick on unborn branch' '
        git checkout --orphan unborn &&
        git rm --cached -r . &&
        rm -rf * &&
@@ -109,4 +109,24 @@ test_expect_success 'chery-pick on unborn branch' '
        ! test_cmp_rev initial HEAD
 '
 
+test_expect_success 'cherry-pick "-" to pick from previous branch' '
+       git checkout unborn &&
+       test_commit to-pick actual content &&
+       git checkout master &&
+       git cherry-pick - &&
+       echo content >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'cherry-pick "-" is meaningless without checkout' '
+       test_create_repo afresh &&
+       (
+               cd afresh &&
+               test_commit one &&
+               test_commit two &&
+               test_commit three &&
+               test_must_fail git cherry-pick -
+       )
+'
+
 test_done
index 373aad623c8f02f6f9753eb38c6393a69c027001..fb889ac6f05a3243b09fbb7ec05356ed61ff9cb0 100755 (executable)
@@ -105,7 +105,7 @@ test_expect_success 'cherry pick a root commit with --ff' '
        test "$(git rev-parse --verify HEAD)" = "1df192cd8bc58a2b275d842cede4d221ad9000d1"
 '
 
-test_expect_success 'chery-pick --ff on unborn branch' '
+test_expect_success 'cherry-pick --ff on unborn branch' '
        git checkout --orphan unborn &&
        git rm --cached -r . &&
        rm -rf * &&
index a5b6a5f3310316d289aee0961fcb6a2ae26fca99..1e5b3948dfc5d28a070ba83db361163002e7c3ae 100755 (executable)
@@ -74,7 +74,7 @@ test_expect_success 'Setup rename with file on one side matching different dirna
        echo content > sub/file &&
        echo foo > othersub/whatever &&
        git add -A &&
-       git commit -m "Common commmit" &&
+       git commit -m "Common commit" &&
 
        git rm -rf othersub &&
        git mv sub/file othersub &&
index 9fab25cc96b079349a3ca3caffbd8d2bc322265c..9dc91d09d7ef3c66c39bcf930bb486312cf291af 100755 (executable)
@@ -4,18 +4,24 @@ test_description='add -i basic tests'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-prereq-FILEMODE.sh
 
-test_expect_success PERL 'setup (initial)' '
+if ! test_have_prereq PERL
+then
+       skip_all='skipping add -i tests, perl not available'
+       test_done
+fi
+
+test_expect_success 'setup (initial)' '
        echo content >file &&
        git add file &&
        echo more >>file &&
        echo lines >>file
 '
-test_expect_success PERL 'status works (initial)' '
+test_expect_success 'status works (initial)' '
        git add -i </dev/null >output &&
        grep "+1/-0 *+2/-0 file" output
 '
 
-test_expect_success PERL 'setup expected' '
+test_expect_success 'setup expected' '
 cat >expected <<EOF
 new file mode 100644
 index 0000000..d95f3ad
@@ -26,19 +32,19 @@ index 0000000..d95f3ad
 EOF
 '
 
-test_expect_success PERL 'diff works (initial)' '
+test_expect_success 'diff works (initial)' '
        (echo d; echo 1) | git add -i >output &&
        sed -ne "/new file/,/content/p" <output >diff &&
        test_cmp expected diff
 '
-test_expect_success PERL 'revert works (initial)' '
+test_expect_success 'revert works (initial)' '
        git add file &&
        (echo r; echo 1) | git add -i &&
        git ls-files >output &&
        ! grep . output
 '
 
-test_expect_success PERL 'setup (commit)' '
+test_expect_success 'setup (commit)' '
        echo baseline >file &&
        git add file &&
        git commit -m commit &&
@@ -47,12 +53,12 @@ test_expect_success PERL 'setup (commit)' '
        echo more >>file &&
        echo lines >>file
 '
-test_expect_success PERL 'status works (commit)' '
+test_expect_success 'status works (commit)' '
        git add -i </dev/null >output &&
        grep "+1/-0 *+2/-0 file" output
 '
 
-test_expect_success PERL 'setup expected' '
+test_expect_success 'setup expected' '
 cat >expected <<EOF
 index 180b47c..b6f2c08 100644
 --- a/file
@@ -63,12 +69,12 @@ index 180b47c..b6f2c08 100644
 EOF
 '
 
-test_expect_success PERL 'diff works (commit)' '
+test_expect_success 'diff works (commit)' '
        (echo d; echo 1) | git add -i >output &&
        sed -ne "/^index/,/content/p" <output >diff &&
        test_cmp expected diff
 '
-test_expect_success PERL 'revert works (commit)' '
+test_expect_success 'revert works (commit)' '
        git add file &&
        (echo r; echo 1) | git add -i &&
        git add -i </dev/null >output &&
@@ -76,24 +82,24 @@ test_expect_success PERL 'revert works (commit)' '
 '
 
 
-test_expect_success PERL 'setup expected' '
+test_expect_success 'setup expected' '
 cat >expected <<EOF
 EOF
 '
 
-test_expect_success PERL 'setup fake editor' '
+test_expect_success 'setup fake editor' '
        >fake_editor.sh &&
        chmod a+x fake_editor.sh &&
        test_set_editor "$(pwd)/fake_editor.sh"
 '
 
-test_expect_success PERL 'dummy edit works' '
+test_expect_success 'dummy edit works' '
        (echo e; echo a) | git add -p &&
        git diff > diff &&
        test_cmp expected diff
 '
 
-test_expect_success PERL 'setup patch' '
+test_expect_success 'setup patch' '
 cat >patch <<EOF
 @@ -1,1 +1,4 @@
  this
@@ -103,7 +109,7 @@ cat >patch <<EOF
 EOF
 '
 
-test_expect_success PERL 'setup fake editor' '
+test_expect_success 'setup fake editor' '
        echo "#!$SHELL_PATH" >fake_editor.sh &&
        cat >>fake_editor.sh <<\EOF &&
 mv -f "$1" oldpatch &&
@@ -113,26 +119,26 @@ EOF
        test_set_editor "$(pwd)/fake_editor.sh"
 '
 
-test_expect_success PERL 'bad edit rejected' '
+test_expect_success 'bad edit rejected' '
        git reset &&
        (echo e; echo n; echo d) | git add -p >output &&
        grep "hunk does not apply" output
 '
 
-test_expect_success PERL 'setup patch' '
+test_expect_success 'setup patch' '
 cat >patch <<EOF
 this patch
 is garbage
 EOF
 '
 
-test_expect_success PERL 'garbage edit rejected' '
+test_expect_success 'garbage edit rejected' '
        git reset &&
        (echo e; echo n; echo d) | git add -p >output &&
        grep "hunk does not apply" output
 '
 
-test_expect_success PERL 'setup patch' '
+test_expect_success 'setup patch' '
 cat >patch <<EOF
 @@ -1,0 +1,0 @@
  baseline
@@ -142,7 +148,7 @@ cat >patch <<EOF
 EOF
 '
 
-test_expect_success PERL 'setup expected' '
+test_expect_success 'setup expected' '
 cat >expected <<EOF
 diff --git a/file b/file
 index b5dd6c9..f910ae9 100644
@@ -157,13 +163,13 @@ index b5dd6c9..f910ae9 100644
 EOF
 '
 
-test_expect_success PERL 'real edit works' '
+test_expect_success 'real edit works' '
        (echo e; echo n; echo d) | git add -p &&
        git diff >output &&
        test_cmp expected output
 '
 
-test_expect_success PERL 'skip files similarly as commit -a' '
+test_expect_success 'skip files similarly as commit -a' '
        git reset &&
        echo file >.gitignore &&
        echo changed >file &&
@@ -177,7 +183,7 @@ test_expect_success PERL 'skip files similarly as commit -a' '
 '
 rm -f .gitignore
 
-test_expect_success PERL,FILEMODE 'patch does not affect mode' '
+test_expect_success FILEMODE 'patch does not affect mode' '
        git reset --hard &&
        echo content >>file &&
        chmod +x file &&
@@ -186,7 +192,7 @@ test_expect_success PERL,FILEMODE 'patch does not affect mode' '
        git diff file | grep "new mode"
 '
 
-test_expect_success PERL,FILEMODE 'stage mode but not hunk' '
+test_expect_success FILEMODE 'stage mode but not hunk' '
        git reset --hard &&
        echo content >>file &&
        chmod +x file &&
@@ -196,7 +202,7 @@ test_expect_success PERL,FILEMODE 'stage mode but not hunk' '
 '
 
 
-test_expect_success PERL,FILEMODE 'stage mode and hunk' '
+test_expect_success FILEMODE 'stage mode and hunk' '
        git reset --hard &&
        echo content >>file &&
        chmod +x file &&
@@ -208,14 +214,14 @@ test_expect_success PERL,FILEMODE 'stage mode and hunk' '
 
 # end of tests disabled when filemode is not usable
 
-test_expect_success PERL 'setup again' '
+test_expect_success 'setup again' '
        git reset --hard &&
        test_chmod +x file &&
        echo content >>file
 '
 
 # Write the patch file with a new line at the top and bottom
-test_expect_success PERL 'setup patch' '
+test_expect_success 'setup patch' '
 cat >patch <<EOF
 index 180b47c..b6f2c08 100644
 --- a/file
@@ -229,7 +235,7 @@ EOF
 '
 
 # Expected output, similar to the patch but w/ diff at the top
-test_expect_success PERL 'setup expected' '
+test_expect_success 'setup expected' '
 cat >expected <<EOF
 diff --git a/file b/file
 index b6f2c08..61b9053 100755
@@ -244,7 +250,7 @@ EOF
 '
 
 # Test splitting the first patch, then adding both
-test_expect_success PERL 'add first line works' '
+test_expect_success 'add first line works' '
        git commit -am "clear local changes" &&
        git apply patch &&
        (echo s; echo y; echo y) | git add -p file &&
@@ -252,7 +258,7 @@ test_expect_success PERL 'add first line works' '
        test_cmp expected diff
 '
 
-test_expect_success PERL 'setup expected' '
+test_expect_success 'setup expected' '
 cat >expected <<EOF
 diff --git a/non-empty b/non-empty
 deleted file mode 100644
@@ -264,7 +270,7 @@ index d95f3ad..0000000
 EOF
 '
 
-test_expect_success PERL 'deleting a non-empty file' '
+test_expect_success 'deleting a non-empty file' '
        git reset --hard &&
        echo content >non-empty &&
        git add non-empty &&
@@ -275,7 +281,7 @@ test_expect_success PERL 'deleting a non-empty file' '
        test_cmp expected diff
 '
 
-test_expect_success PERL 'setup expected' '
+test_expect_success 'setup expected' '
 cat >expected <<EOF
 diff --git a/empty b/empty
 deleted file mode 100644
@@ -283,7 +289,7 @@ index e69de29..0000000
 EOF
 '
 
-test_expect_success PERL 'deleting an empty file' '
+test_expect_success 'deleting an empty file' '
        git reset --hard &&
        > empty &&
        git add empty &&
@@ -294,7 +300,7 @@ test_expect_success PERL 'deleting an empty file' '
        test_cmp expected diff
 '
 
-test_expect_success PERL 'split hunk setup' '
+test_expect_success 'split hunk setup' '
        git reset --hard &&
        for i in 10 20 30 40 50 60
        do
@@ -310,7 +316,7 @@ test_expect_success PERL 'split hunk setup' '
        done >test
 '
 
-test_expect_success PERL 'split hunk "add -p (edit)"' '
+test_expect_success 'split hunk "add -p (edit)"' '
        # Split, say Edit and do nothing.  Then:
        #
        # 1. Broken version results in a patch that does not apply and
index 5fe57c5438e72150639fd6b970471a1689d30911..e4ba6013e41927bc0ec3ff3876648a71a71ce6e1 100755 (executable)
@@ -36,7 +36,7 @@ Alongc=$Alongc$AEligatu$AEligatu                     #254 Byte
 
 test_expect_success "detect if nfd needed" '
        precomposeunicode=`git config core.precomposeunicode` &&
-       test "$precomposeunicode" = false &&
+       test "$precomposeunicode" = true &&
        git config core.precomposeunicode true
 '
 test_expect_success "setup" '
index 97172b46b2afd52ca8f278f9525da01a56823e59..cd0454356a6ea26c630f76748dd2c4f73bed8526 100755 (executable)
@@ -73,7 +73,7 @@ test_expect_success 'plumbing not affected' '
 test_expect_success 'non-integer config parsing' '
        git config diff.context no &&
        test_must_fail git diff 2>output &&
-       test_i18ngrep "bad config value" output
+       test_i18ngrep "bad numeric config value" output
 '
 
 test_expect_success 'negative integer config parsing' '
index 5493500ef15d2f561bd14ca0bdf5f519ec6f49be..42866992cfe65657019dced508d3490b3851a6c7 100755 (executable)
@@ -172,4 +172,20 @@ test_expect_success 'shortlog encoding' '
        git shortlog HEAD~2.. > out &&
 test_cmp expect out'
 
+test_expect_success 'shortlog ignores commits with missing authors' '
+       git commit --allow-empty -m normal &&
+       git commit --allow-empty -m soon-to-be-broken &&
+       git cat-file commit HEAD >commit.tmp &&
+       sed "/^author/d" commit.tmp >broken.tmp &&
+       commit=$(git hash-object -w -t commit --stdin <broken.tmp) &&
+       git update-ref HEAD $commit &&
+       cat >expect <<-\EOF &&
+       A U Thor (1):
+             normal
+
+       EOF
+       git shortlog HEAD~2.. >actual &&
+       test_cmp expect actual
+'
+
 test_done
index ce3eace065be81612e1ab2f994909b9352d5a06c..0dd8b65d7cdec2ada739d7e0b524fd3c66dd5ef4 100755 (executable)
@@ -484,4 +484,15 @@ test_expect_success 'Blame output (complex mapping)' '
        test_cmp expect actual.fuzz
 '
 
+cat >expect <<\EOF
+Some Dude <some@dude.xx>
+EOF
+
+test_expect_success 'commit --author honors mailmap' '
+       test_must_fail git commit --author "nick" --allow-empty -meight &&
+       git commit --author "Some Dude" --allow-empty -meight &&
+       git show --pretty=format:"%an <%ae>%n" >actual &&
+       test_cmp expect actual
+'
+
 test_done
index b7da95fac578b58b7405386eb16f4288a253b95f..85716dd6ec566f34f7c4e0b30477bb1531c6030e 100755 (executable)
@@ -3,20 +3,19 @@
 test_description='git am with corrupt input'
 . ./test-lib.sh
 
-# Note the missing "+++" line:
-cat > bad-patch.diff <<'EOF'
-From: A U Thor <au.thor@example.com>
-diff --git a/f b/f
-index 7898192..6178079 100644
---- a/f
-@@ -1 +1 @@
--a
-+b
-EOF
-
 test_expect_success setup '
-       test $? = 0 &&
-       echo a > f &&
+       # Note the missing "+++" line:
+       cat >bad-patch.diff <<-\EOF &&
+       From: A U Thor <au.thor@example.com>
+       diff --git a/f b/f
+       index 7898192..6178079 100644
+       --- a/f
+       @@ -1 +1 @@
+       -a
+       +b
+       EOF
+
+       echo a >f &&
        git add f &&
        test_tick &&
        git commit -m initial
@@ -26,17 +25,12 @@ test_expect_success setup '
 #   fatal: unable to write file '(null)' mode 100644: Bad address
 # Also, it had the unwanted side-effect of deleting f.
 test_expect_success 'try to apply corrupted patch' '
-       git am bad-patch.diff 2> actual
-       test $? = 1
+       test_must_fail git am bad-patch.diff 2>actual
 '
 
-cat > expected <<EOF
-fatal: git diff header lacks filename information (line 4)
-EOF
-
 test_expect_success 'compare diagnostic; ensure file is still here' '
-       test $? = 0 &&
-       test -f f &&
+       echo "fatal: git diff header lacks filename information (line 4)" >expected &&
+       test_path_is_file f &&
        test_cmp expected actual
 '
 
diff --git a/t/t5308-pack-detect-duplicates.sh b/t/t5308-pack-detect-duplicates.sh
new file mode 100755 (executable)
index 0000000..9c5a876
--- /dev/null
@@ -0,0 +1,80 @@
+#!/bin/sh
+
+test_description='handling of duplicate objects in incoming packfiles'
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-pack.sh
+
+# The sha1s we have in our pack. It's important that these have the same
+# starting byte, so that they end up in the same fanout section of the index.
+# That lets us make sure we are exercising the binary search with both sets.
+LO_SHA1=e68fe8129b546b101aee9510c5328e7f21ca1d18
+HI_SHA1=e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
+
+# And here's a "missing sha1" which will produce failed lookups. It must also
+# be in the same fanout section, and should be between the two (so that during
+# our binary search, we are sure to end up looking at one or the other of the
+# duplicate runs).
+MISSING_SHA1='e69d000000000000000000000000000000000000'
+
+# git will never intentionally create packfiles with
+# duplicate objects, so we have to construct them by hand.
+#
+# $1 is the name of the packfile to create
+#
+# $2 is the number of times to duplicate each object
+create_pack () {
+       pack_header "$((2 * $2))" >"$1" &&
+       for i in $(test_seq 1 "$2"); do
+               pack_obj $LO_SHA1 &&
+               pack_obj $HI_SHA1
+       done >>"$1" &&
+       pack_trailer "$1"
+}
+
+# double-check that create_pack actually works
+test_expect_success 'pack with no duplicates' '
+       create_pack no-dups.pack 1 &&
+       git index-pack --stdin <no-dups.pack
+'
+
+test_expect_success 'index-pack will allow duplicate objects by default' '
+       clear_packs &&
+       create_pack dups.pack 100 &&
+       git index-pack --stdin <dups.pack
+'
+
+test_expect_success 'create batch-check test vectors' '
+       cat >input <<-EOF &&
+       $LO_SHA1
+       $HI_SHA1
+       $MISSING_SHA1
+       EOF
+       cat >expect <<-EOF
+       $LO_SHA1 blob 2
+       $HI_SHA1 blob 0
+       $MISSING_SHA1 missing
+       EOF
+'
+
+test_expect_success 'lookup in duplicated pack (binary search)' '
+       git cat-file --batch-check <input >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'lookup in duplicated pack (GIT_USE_LOOKUP)' '
+       (
+               GIT_USE_LOOKUP=1 &&
+               export GIT_USE_LOOKUP &&
+               git cat-file --batch-check <input >actual
+       ) &&
+       test_cmp expect actual
+'
+
+test_expect_success 'index-pack can reject packs with duplicates' '
+       clear_packs &&
+       create_pack dups.pack 2 &&
+       test_must_fail git index-pack --strict --stdin <dups.pack &&
+       test_expect_code 1 git cat-file -e $LO_SHA1
+'
+
+test_done
diff --git a/t/t5309-pack-delta-cycles.sh b/t/t5309-pack-delta-cycles.sh
new file mode 100755 (executable)
index 0000000..3e7861b
--- /dev/null
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+test_description='test index-pack handling of delta cycles in packfiles'
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-pack.sh
+
+# Two similar-ish objects that we have computed deltas between.
+A=01d7713666f4de822776c7622c10f1b07de280dc
+B=e68fe8129b546b101aee9510c5328e7f21ca1d18
+
+# double-check our hand-constucted packs
+test_expect_success 'index-pack works with a single delta (A->B)' '
+       clear_packs &&
+       {
+               pack_header 2 &&
+               pack_obj $A $B &&
+               pack_obj $B
+       } >ab.pack &&
+       pack_trailer ab.pack &&
+       git index-pack --stdin <ab.pack &&
+       git cat-file -t $A &&
+       git cat-file -t $B
+'
+
+test_expect_success 'index-pack works with a single delta (B->A)' '
+       clear_packs &&
+       {
+               pack_header 2 &&
+               pack_obj $A &&
+               pack_obj $B $A
+       } >ba.pack &&
+       pack_trailer ba.pack &&
+       git index-pack --stdin <ba.pack &&
+       git cat-file -t $A &&
+       git cat-file -t $B
+'
+
+test_expect_success 'index-pack detects missing base objects' '
+       clear_packs &&
+       {
+               pack_header 1 &&
+               pack_obj $A $B
+       } >missing.pack &&
+       pack_trailer missing.pack &&
+       test_must_fail git index-pack --fix-thin --stdin <missing.pack
+'
+
+test_expect_success 'index-pack detects REF_DELTA cycles' '
+       clear_packs &&
+       {
+               pack_header 2 &&
+               pack_obj $A $B &&
+               pack_obj $B $A
+       } >cycle.pack &&
+       pack_trailer cycle.pack &&
+       test_must_fail git index-pack --fix-thin --stdin <cycle.pack
+'
+
+test_expect_failure 'failover to an object in another pack' '
+       clear_packs &&
+       git index-pack --stdin <ab.pack &&
+       git index-pack --stdin --fix-thin <cycle.pack
+'
+
+test_expect_failure 'failover to a duplicate object in the same pack' '
+       clear_packs &&
+       {
+               pack_header 3 &&
+               pack_obj $A $B &&
+               pack_obj $B $A &&
+               pack_obj $A
+       } >recoverable.pack &&
+       pack_trailer recoverable.pack &&
+       git index-pack --fix-thin --stdin <recoverable.pack
+'
+
+test_done
index a80584ea0eaba854ff21318e3c9646f72325bee7..d87ddf73b7127bc624ca739653db9389831b817e 100755 (executable)
@@ -393,6 +393,17 @@ test_expect_success 'fetch in shallow repo unreachable shallow objects' '
                git fsck --no-dangling
        )
 '
+test_expect_success 'fetch creating new shallow root' '
+       (
+               git clone "file://$(pwd)/." shallow10 &&
+               git commit --allow-empty -m empty &&
+               cd shallow10 &&
+               git fetch --depth=1 --progress 2>actual &&
+               # This should fetch only the empty commit, no tree or
+               # blob objects
+               grep "remote: Total 1" actual
+       )
+'
 
 test_expect_success 'setup tests for the --stdin parameter' '
        for head in C D E F
index 4691d51b8cde48dbb97ac5dfc1e3b75fe90f8da3..99c32d75391bb02fae779ad831879903abca5d25 100755 (executable)
@@ -1172,4 +1172,21 @@ test_expect_success 'push --follow-tag only pushes relevant tags' '
        test_cmp expect actual
 '
 
+test_expect_success 'push --no-thin must produce non-thin pack' '
+       cat >>path1 <<\EOF &&
+keep base version of path1 big enough, compared to the new changes
+later, in order to pass size heuristics in
+builtin/pack-objects.c:try_delta()
+EOF
+       git commit -am initial &&
+       git init no-thin &&
+       git --git-dir=no-thin/.git config receive.unpacklimit 0 &&
+       git push no-thin/.git refs/heads/master:refs/heads/foo &&
+       echo modified >> path1 &&
+       git commit -am modified &&
+       git repack -adf &&
+       rcvpck="git receive-pack --reject-thin-pack-for-testing" &&
+       git push --no-thin --receive-pack="$rcvpck" no-thin/.git refs/heads/master:refs/heads/foo
+'
+
 test_done
index ed4d9c83181bc45456074f053ed5a0f137fc7e27..227d29335020f3e52a40b03b2f933f4d63942b91 100755 (executable)
@@ -148,6 +148,95 @@ test_expect_success 'branch.to-rebase.rebase should override pull.rebase' '
        test new = $(git show HEAD:file2)
 '
 
+# add a feature branch, keep-merge, that is merged into master, so the
+# test can try preserving the merge commit (or not) with various
+# --rebase flags/pull.rebase settings.
+test_expect_success 'preserve merge setup' '
+       git reset --hard before-rebase &&
+       git checkout -b keep-merge second^ &&
+       test_commit file3 &&
+       git checkout to-rebase &&
+       git merge keep-merge &&
+       git tag before-preserve-rebase
+'
+
+test_expect_success 'pull.rebase=false create a new merge commit' '
+       git reset --hard before-preserve-rebase &&
+       test_config pull.rebase false &&
+       git pull . copy &&
+       test $(git rev-parse HEAD^1) = $(git rev-parse before-preserve-rebase) &&
+       test $(git rev-parse HEAD^2) = $(git rev-parse copy) &&
+       test file3 = $(git show HEAD:file3.t)
+'
+
+test_expect_success 'pull.rebase=true flattens keep-merge' '
+       git reset --hard before-preserve-rebase &&
+       test_config pull.rebase true &&
+       git pull . copy &&
+       test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
+       test file3 = $(git show HEAD:file3.t)
+'
+
+test_expect_success 'pull.rebase=1 is treated as true and flattens keep-merge' '
+       git reset --hard before-preserve-rebase &&
+       test_config pull.rebase 1 &&
+       git pull . copy &&
+       test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
+       test file3 = $(git show HEAD:file3.t)
+'
+
+test_expect_success 'pull.rebase=preserve rebases and merges keep-merge' '
+       git reset --hard before-preserve-rebase &&
+       test_config pull.rebase preserve &&
+       git pull . copy &&
+       test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
+       test $(git rev-parse HEAD^2) = $(git rev-parse keep-merge)
+'
+
+test_expect_success 'pull.rebase=invalid fails' '
+       git reset --hard before-preserve-rebase &&
+       test_config pull.rebase invalid &&
+       ! git pull . copy
+'
+
+test_expect_success '--rebase=false create a new merge commit' '
+       git reset --hard before-preserve-rebase &&
+       test_config pull.rebase true &&
+       git pull --rebase=false . copy &&
+       test $(git rev-parse HEAD^1) = $(git rev-parse before-preserve-rebase) &&
+       test $(git rev-parse HEAD^2) = $(git rev-parse copy) &&
+       test file3 = $(git show HEAD:file3.t)
+'
+
+test_expect_success '--rebase=true rebases and flattens keep-merge' '
+       git reset --hard before-preserve-rebase &&
+       test_config pull.rebase preserve &&
+       git pull --rebase=true . copy &&
+       test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
+       test file3 = $(git show HEAD:file3.t)
+'
+
+test_expect_success '--rebase=preserve rebases and merges keep-merge' '
+       git reset --hard before-preserve-rebase &&
+       test_config pull.rebase true &&
+       git pull --rebase=preserve . copy &&
+       test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
+       test $(git rev-parse HEAD^2) = $(git rev-parse keep-merge)
+'
+
+test_expect_success '--rebase=invalid fails' '
+       git reset --hard before-preserve-rebase &&
+       ! git pull --rebase=invalid . copy
+'
+
+test_expect_success '--rebase overrides pull.rebase=preserve and flattens keep-merge' '
+       git reset --hard before-preserve-rebase &&
+       test_config pull.rebase preserve &&
+       git pull --rebase . copy &&
+       test $(git rev-parse HEAD^^) = $(git rev-parse copy) &&
+       test file3 = $(git show HEAD:file3.t)
+'
+
 test_expect_success '--rebase with rebased upstream' '
 
        git remote add -f me . &&
index c983d3694c74cf6de6b7bd9a74c28d41462171f0..3932e797f7f60545e6e8c140824a5ca5ee16832a 100755 (executable)
@@ -54,9 +54,6 @@ test_expect_success 'upload-pack fails due to error in rev-list' '
        printf "0032want %s\n0034shallow %s00000009done\n0000" \
                $(git rev-parse HEAD) $(git rev-parse HEAD^) >input &&
        test_must_fail git upload-pack . <input >/dev/null 2>output.err &&
-       # pack-objects survived
-       grep "Total.*, reused" output.err &&
-       # but there was an error, which must have been in rev-list
        grep "bad tree object" output.err
 '
 
index 0629149eddcff4e6e724ab82479504deda141141..a3e3d489ec9db3c3ca0e53ffd2307dd3652c3713 100755 (executable)
@@ -280,9 +280,53 @@ test_expect_success 'clone checking out a tag' '
        test_cmp fetch.expected fetch.actual
 '
 
+test_expect_success 'setup ssh wrapper' '
+       write_script "$TRASH_DIRECTORY/ssh-wrapper" <<-\EOF &&
+       echo >>"$TRASH_DIRECTORY/ssh-output" "ssh: $*" &&
+       # throw away all but the last argument, which should be the
+       # command
+       while test $# -gt 1; do shift; done
+       eval "$1"
+       EOF
+
+       GIT_SSH="$TRASH_DIRECTORY/ssh-wrapper" &&
+       export GIT_SSH &&
+       export TRASH_DIRECTORY
+'
+
+clear_ssh () {
+       >"$TRASH_DIRECTORY/ssh-output"
+}
+
+expect_ssh () {
+       {
+               case "$1" in
+               none)
+                       ;;
+               *)
+                       echo "ssh: $1 git-upload-pack '$2'"
+               esac
+       } >"$TRASH_DIRECTORY/ssh-expect" &&
+       (cd "$TRASH_DIRECTORY" && test_cmp ssh-expect ssh-output)
+}
+
+test_expect_success 'cloning myhost:src uses ssh' '
+       clear_ssh &&
+       git clone myhost:src ssh-clone &&
+       expect_ssh myhost src
+'
+
 test_expect_success NOT_MINGW,NOT_CYGWIN 'clone local path foo:bar' '
+       clear_ssh &&
        cp -R src "foo:bar" &&
-       git clone "./foo:bar" foobar
+       git clone "./foo:bar" foobar &&
+       expect_ssh none
+'
+
+test_expect_success 'bracketed hostnames are still ssh' '
+       clear_ssh &&
+       git clone "[myhost:123]:src" ssh-bracket-clone &&
+       expect_ssh myhost:123 src
 '
 
 test_done
index 56be67e07e3c20f029a0bdeb2179e219ebc0bda1..6e7a7be052276613bf5f83551d93b4d90536ea4e 100755 (executable)
@@ -20,7 +20,9 @@ test_expect_success 'setup' '
         echo one >file && git add file && git commit -m one &&
         git checkout -b two &&
         echo two >file && git add file && git commit -m two &&
-        git checkout master)
+        git checkout master) &&
+       mkdir empty &&
+       (cd empty && git init)
 '
 
 test_expect_success 'vanilla clone chooses HEAD' '
@@ -61,4 +63,8 @@ test_expect_success 'clone -b with bogus branch' '
        test_must_fail git clone -b bogus parent clone-bogus
 '
 
+test_expect_success 'clone -b not allowed with empty repos' '
+       test_must_fail git clone -b branch empty clone-branch-empty
+'
+
 test_done
diff --git a/t/t5800-remote-testpy.sh b/t/t5800-remote-testpy.sh
deleted file mode 100755 (executable)
index 1e683d4..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2010 Sverre Rabbelier
-#
-
-test_description='Test python remote-helper framework'
-
-. ./test-lib.sh
-
-if ! test_have_prereq PYTHON ; then
-       skip_all='skipping python remote-helper tests, python not available'
-       test_done
-fi
-
-"$PYTHON_PATH" -c '
-import sys
-if sys.hexversion < 0x02040000:
-    sys.exit(1)
-' || {
-       skip_all='skipping python remote-helper tests, python version < 2.4'
-       test_done
-}
-
-compare_refs() {
-       git --git-dir="$1/.git" rev-parse --verify $2 >expect &&
-       git --git-dir="$3/.git" rev-parse --verify $4 >actual &&
-       test_cmp expect actual
-}
-
-test_expect_success 'setup repository' '
-       git init --bare server/.git &&
-       git clone server public &&
-       (cd public &&
-        echo content >file &&
-        git add file &&
-        git commit -m one &&
-        git push origin master)
-'
-
-test_expect_success 'cloning from local repo' '
-       git clone "testpy::${PWD}/server" localclone &&
-       test_cmp public/file localclone/file
-'
-
-test_expect_success 'cloning from remote repo' '
-       git clone "testpy::file://${PWD}/server" clone &&
-       test_cmp public/file clone/file
-'
-
-test_expect_success 'create new commit on remote' '
-       (cd public &&
-        echo content >>file &&
-        git commit -a -m two &&
-        git push)
-'
-
-test_expect_success 'pulling from local repo' '
-       (cd localclone && git pull) &&
-       test_cmp public/file localclone/file
-'
-
-test_expect_success 'pulling from remote remote' '
-       (cd clone && git pull) &&
-       test_cmp public/file clone/file
-'
-
-test_expect_success 'pushing to local repo' '
-       (cd localclone &&
-       echo content >>file &&
-       git commit -a -m three &&
-       git push) &&
-       compare_refs localclone HEAD server HEAD
-'
-
-# Generally, skip this test.  It demonstrates a now-fixed race in
-# git-remote-testpy, but is too slow to leave in for general use.
-: test_expect_success 'racily pushing to local repo' '
-       test_when_finished "rm -rf server2 localclone2" &&
-       cp -R server server2 &&
-       git clone "testpy::${PWD}/server2" localclone2 &&
-       (cd localclone2 &&
-       echo content >>file &&
-       git commit -a -m three &&
-       GIT_REMOTE_TESTGIT_SLEEPY=2 git push) &&
-       compare_refs localclone2 HEAD server2 HEAD
-'
-
-test_expect_success 'synch with changes from localclone' '
-       (cd clone &&
-        git pull)
-'
-
-test_expect_success 'pushing remote local repo' '
-       (cd clone &&
-       echo content >>file &&
-       git commit -a -m four &&
-       git push) &&
-       compare_refs clone HEAD server HEAD
-'
-
-test_expect_success 'fetch new branch' '
-       (cd public &&
-        git checkout -b new &&
-        echo content >>file &&
-        git commit -a -m five &&
-        git push origin new
-       ) &&
-       (cd localclone &&
-        git fetch origin new
-       ) &&
-       compare_refs public HEAD localclone FETCH_HEAD
-'
-
-test_expect_success 'fetch multiple branches' '
-       (cd localclone &&
-        git fetch
-       ) &&
-       compare_refs server master localclone refs/remotes/origin/master &&
-       compare_refs server new localclone refs/remotes/origin/new
-'
-
-test_expect_success 'push when remote has extra refs' '
-       (cd clone &&
-        echo content >>file &&
-        git commit -a -m six &&
-        git push
-       ) &&
-       compare_refs clone master server master
-'
-
-test_expect_success 'push new branch by name' '
-       (cd clone &&
-        git checkout -b new-name  &&
-        echo content >>file &&
-        git commit -a -m seven &&
-        git push origin new-name
-       ) &&
-       compare_refs clone HEAD server refs/heads/new-name
-'
-
-test_expect_failure 'push new branch with old:new refspec' '
-       (cd clone &&
-        git push origin new-name:new-refspec
-       ) &&
-       compare_refs clone HEAD server refs/heads/new-refspec
-'
-
-test_expect_success 'proper failure checks for fetching' '
-       (GIT_REMOTE_TESTGIT_FAILURE=1 &&
-       export GIT_REMOTE_TESTGIT_FAILURE &&
-       cd localclone &&
-       test_must_fail git fetch 2>&1 | \
-               grep "Error while running fast-import"
-       )
-'
-
-# We sleep to give fast-export a chance to catch the SIGPIPE
-test_expect_failure 'proper failure checks for pushing' '
-       (GIT_REMOTE_TESTGIT_FAILURE=1 &&
-       export GIT_REMOTE_TESTGIT_FAILURE &&
-       GIT_REMOTE_TESTGIT_SLEEPY=1 &&
-       export GIT_REMOTE_TESTGIT_SLEEPY &&
-       cd localclone &&
-       test_must_fail git push --all 2>&1 | \
-               grep "Error while running fast-export"
-       )
-'
-
-test_done
index 8c4c5396a8447fc39d6f0c697af761631b08b3f7..613f69a254bab23e1f09126b4a7f3dca8692deaa 100755 (executable)
@@ -182,6 +182,17 @@ test_expect_success 'push update refs' '
        )
 '
 
+test_expect_success 'push update refs disabled by no-private-update' '
+       (cd local &&
+       echo more-update >>file &&
+       git commit -a -m more-update &&
+       git rev-parse --verify testgit/origin/heads/update >expect &&
+       GIT_REMOTE_TESTGIT_NO_PRIVATE_UPDATE=t git push origin update &&
+       git rev-parse --verify testgit/origin/heads/update >actual &&
+       test_cmp expect actual
+       )
+'
+
 test_expect_success 'push update refs failure' '
        (cd local &&
        git checkout update &&
index c680f789a7028f5300a4665ca068c9a7e87bb22a..a89dfbef08a5a9ff2d4c8727b67b44279fe522e5 100755 (executable)
@@ -259,7 +259,7 @@ test_expect_success 'setup for rename + d/f conflicts' '
        printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >sub/file &&
        echo foo >dir/file-in-the-way &&
        git add -A &&
-       git commit -m "Common commmit" &&
+       git commit -m "Common commit" &&
 
        echo 11 >>sub/file &&
        echo more >>dir/file-in-the-way &&
@@ -439,7 +439,7 @@ test_expect_success 'setup both rename source and destination involved in D/F co
        mkdir one &&
        echo stuff >one/file &&
        git add -A &&
-       git commit -m "Common commmit" &&
+       git commit -m "Common commit" &&
 
        git mv one/file destdir &&
        git commit -m "Renamed to destdir" &&
@@ -479,7 +479,7 @@ test_expect_success 'setup pair rename to parent of other (D/F conflicts)' '
        echo stuff >one/file &&
        echo other >two/file &&
        git add -A &&
-       git commit -m "Common commmit" &&
+       git commit -m "Common commit" &&
 
        git rm -rf one &&
        git mv two/file one &&
@@ -539,7 +539,7 @@ test_expect_success 'setup rename of one file to two, with directories in the wa
 
        echo stuff >original &&
        git add -A &&
-       git commit -m "Common commmit" &&
+       git commit -m "Common commit" &&
 
        mkdir two &&
        >two/file &&
@@ -583,7 +583,7 @@ test_expect_success 'setup rename one file to two; directories moving out of the
        mkdir one two &&
        touch one/file two/file &&
        git add -A &&
-       git commit -m "Common commmit" &&
+       git commit -m "Common commit" &&
 
        git rm -rf one &&
        git mv original one &&
@@ -618,7 +618,7 @@ test_expect_success 'setup avoid unnecessary update, normal rename' '
 
        printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >original &&
        git add -A &&
-       git commit -m "Common commmit" &&
+       git commit -m "Common commit" &&
 
        git mv original rename &&
        echo 11 >>rename &&
@@ -649,7 +649,7 @@ test_expect_success 'setup to test avoiding unnecessary update, with D/F conflic
        mkdir df &&
        printf "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n" >df/file &&
        git add -A &&
-       git commit -m "Common commmit" &&
+       git commit -m "Common commit" &&
 
        git mv df/file temp &&
        rm -rf df &&
index ec2b516c3f79901ca5593f1edb97455e3fa8389e..ba26cfe9239306035c2496f922055eaea6b46a31 100755 (executable)
@@ -28,10 +28,15 @@ test_expect_success setup '
                git reset --hard HEAD^ &&
                git checkout -b b4 origin &&
                advance e &&
-               advance f
+               advance f &&
+               git checkout -b brokenbase origin &&
+               git checkout -b b5 --track brokenbase &&
+               advance g &&
+               git branch -d brokenbase &&
+               git checkout -b b6 origin
        ) &&
        git checkout -b follower --track master &&
-       advance g
+       advance h
 '
 
 script='s/^..\(b.\)[    0-9a-f]*\[\([^]]*\)\].*/\1 \2/p'
@@ -56,6 +61,8 @@ b1 origin/master: ahead 1, behind 1
 b2 origin/master: ahead 1, behind 1
 b3 origin/master: behind 1
 b4 origin/master: ahead 2
+b5 brokenbase: gone
+b6 origin/master
 EOF
 
 test_expect_success 'branch -vv' '
@@ -67,7 +74,7 @@ test_expect_success 'branch -vv' '
        test_i18ncmp expect actual
 '
 
-test_expect_success 'checkout' '
+test_expect_success 'checkout (diverged from upstream)' '
        (
                cd test && git checkout b1
        ) >actual &&
@@ -80,7 +87,22 @@ test_expect_success 'checkout with local tracked branch' '
        test_i18ngrep "is ahead of" actual
 '
 
-test_expect_success 'status' '
+test_expect_success 'checkout (upstream is gone)' '
+       (
+               cd test &&
+               git checkout b5
+       ) >actual &&
+       test_i18ngrep "is based on .*, but the upstream is gone." actual
+'
+
+test_expect_success 'checkout (up-to-date with upstream)' '
+       (
+               cd test && git checkout b6
+       ) >actual &&
+       test_i18ngrep "Your branch is up-to-date with .origin/master" actual
+'
+
+test_expect_success 'status (diverged from upstream)' '
        (
                cd test &&
                git checkout b1 >/dev/null &&
@@ -90,6 +112,65 @@ test_expect_success 'status' '
        test_i18ngrep "have 1 and 1 different" actual
 '
 
+test_expect_success 'status (upstream is gone)' '
+       (
+               cd test &&
+               git checkout b5 >/dev/null &&
+               # reports nothing to commit
+               test_must_fail git commit --dry-run
+       ) >actual &&
+       test_i18ngrep "is based on .*, but the upstream is gone." actual
+'
+
+test_expect_success 'status (up-to-date with upstream)' '
+       (
+               cd test &&
+               git checkout b6 >/dev/null &&
+               # reports nothing to commit
+               test_must_fail git commit --dry-run
+       ) >actual &&
+       test_i18ngrep "Your branch is up-to-date with .origin/master" actual
+'
+
+cat >expect <<\EOF
+## b1...origin/master [ahead 1, behind 1]
+EOF
+
+test_expect_success 'status -s -b (diverged from upstream)' '
+       (
+               cd test &&
+               git checkout b1 >/dev/null &&
+               git status -s -b | head -1
+       ) >actual &&
+       test_i18ncmp expect actual
+'
+
+cat >expect <<\EOF
+## b5...brokenbase [gone]
+EOF
+
+test_expect_success 'status -s -b (upstream is gone)' '
+       (
+               cd test &&
+               git checkout b5 >/dev/null &&
+               git status -s -b | head -1
+       ) >actual &&
+       test_i18ncmp expect actual
+'
+
+cat >expect <<\EOF
+## b6...origin/master
+EOF
+
+test_expect_success 'status -s -b (up-to-date with upstream)' '
+       (
+               cd test &&
+               git checkout b6 >/dev/null &&
+               git status -s -b | head -1
+       ) >actual &&
+       test_i18ncmp expect actual
+'
+
 test_expect_success 'fail to track lightweight tags' '
        git checkout master &&
        git tag light &&
index decdc33c522568e98346d085acdf873c995eb762..7d479843522e3b183fdb4d72d86909b53e0edbda 100755 (executable)
@@ -122,9 +122,9 @@ test_expect_success '"git replace" listing and deleting' '
      test "$HASH2" = "$(git replace -l)" &&
      test "$HASH2" = "$(git replace)" &&
      aa=${HASH2%??????????????????????????????????????} &&
-     test "$HASH2" = "$(git replace -l "$aa*")" &&
+     test "$HASH2" = "$(git replace --list "$aa*")" &&
      test_must_fail git replace -d $R &&
-     test_must_fail git replace -d &&
+     test_must_fail git replace --delete &&
      test_must_fail git replace -l -d $HASH2 &&
      git replace -d $HASH2 &&
      git show $HASH2 | grep "A U Thor" &&
@@ -147,7 +147,7 @@ test_expect_success '"git replace" resolves sha1' '
      git show $HASH2 | grep "O Thor" &&
      test_must_fail git replace $HASH2 $R &&
      git replace -f $HASH2 $R &&
-     test_must_fail git replace -f &&
+     test_must_fail git replace --force &&
      test "$HASH2" = "$(git replace)"
 '
 
@@ -263,4 +263,23 @@ test_expect_success 'not just commits' '
        test_cmp file.replaced file
 '
 
+test_expect_success 'replaced and replacement objects must be of the same type' '
+       test_must_fail git replace mytag $HASH1 &&
+       test_must_fail git replace HEAD^{tree} HEAD~1 &&
+       BLOB=$(git rev-parse :file) &&
+       test_must_fail git replace HEAD^ $BLOB
+'
+
+test_expect_success '-f option bypasses the type check' '
+       git replace -f mytag $HASH1 &&
+       git replace --force HEAD^{tree} HEAD~1 &&
+       git replace -f HEAD^ $BLOB
+'
+
+test_expect_success 'replace ref cleanup' '
+       test -n "$(git replace)" &&
+       git replace -d $(git replace) &&
+       test -z "$(git replace)"
+'
+
 test_done
index e673c25e943f77430d7f61b0ab9e0b21e38e6915..7ea14ced313d3f0dd20d4afd2fc2a0d3309b938f 100755 (executable)
@@ -6,39 +6,86 @@
 test_description='Test git rev-parse with different parent options'
 
 . ./test-lib.sh
-. "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
-
-date >path0
-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_success '--verify start2^1' 'test_must_fail git rev-parse --verify start2^1'
-test_expect_success '--verify start2^0' 'git rev-parse --verify start2^0'
-test_expect_success 'final^1^@ = final^1^1 final^1^2' "test \"$(git rev-parse final^1^@)\" = \"$(git rev-parse final^1^1 final^1^2)\""
-test_expect_success 'final^1^! = final^1 ^final^1^1 ^final^1^2' "test \"$(git rev-parse final^1^\!)\" = \"$(git rev-parse final^1 ^final^1^1 ^final^1^2)\""
-
-test_expect_success 'repack for next test' 'git repack -a -d'
+
+test_cmp_rev_output () {
+       git rev-parse --verify "$1" >expect &&
+       eval "$2" >actual &&
+       test_cmp expect actual
+}
+
+test_expect_success 'setup' '
+       test_commit start &&
+       test_commit second &&
+       git checkout --orphan tmp &&
+       test_commit start2 &&
+       git checkout master &&
+       git merge -m next start2 &&
+       test_commit final
+'
+
+test_expect_success 'start is valid' '
+       git rev-parse start | grep "^[0-9a-f]\{40\}$"
+'
+
+test_expect_success 'start^0' '
+       test_cmp_rev_output tags/start "git rev-parse start^0"
+'
+
+test_expect_success 'start^1 not valid' '
+       test_must_fail git rev-parse --verify start^1
+'
+
+test_expect_success 'second^1 = second^' '
+       test_cmp_rev_output second^ "git rev-parse second^1"
+'
+
+test_expect_success 'final^1^1^1' '
+       test_cmp_rev_output start "git rev-parse final^1^1^1"
+'
+
+test_expect_success 'final^1^1^1 = final^^^' '
+       test_cmp_rev_output final^^^ "git rev-parse final^1^1^1"
+'
+
+test_expect_success 'final^1^2' '
+       test_cmp_rev_output 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' '
+       test_must_fail git rev-parse --verify final^1^3
+'
+
+test_expect_success '--verify start2^1' '
+       test_must_fail git rev-parse --verify start2^1
+'
+
+test_expect_success '--verify start2^0' '
+       git rev-parse --verify start2^0
+'
+
+test_expect_success 'final^1^@ = final^1^1 final^1^2' '
+       git rev-parse final^1^1 final^1^2 >expect &&
+       git rev-parse final^1^@ >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'final^1^! = final^1 ^final^1^1 ^final^1^2' '
+       git rev-parse final^1 ^final^1^1 ^final^1^2 >expect &&
+       git rev-parse final^1^! >actual &&
+       test_cmp expect actual
+'
+
+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'
+       start=$(git rev-parse --verify start) &&
+       test_cmp_rev_output start "git rev-parse ${start%?}"
+'
 
 test_done
diff --git a/t/t7009-filter-branch-null-sha1.sh b/t/t7009-filter-branch-null-sha1.sh
new file mode 100755 (executable)
index 0000000..a997f7a
--- /dev/null
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+test_description='filter-branch removal of trees with null sha1'
+. ./test-lib.sh
+
+test_expect_success 'setup: base commits' '
+       test_commit one &&
+       test_commit two &&
+       test_commit three
+'
+
+test_expect_success 'setup: a commit with a bogus null sha1 in the tree' '
+       {
+               git ls-tree HEAD &&
+               printf "160000 commit $_z40\\tbroken\\n"
+       } >broken-tree
+       echo "add broken entry" >msg &&
+
+       tree=$(git mktree <broken-tree) &&
+       test_tick &&
+       commit=$(git commit-tree $tree -p HEAD <msg) &&
+       git update-ref HEAD "$commit"
+'
+
+# we have to make one more commit on top removing the broken
+# entry, since otherwise our index does not match HEAD (and filter-branch will
+# complain). We could make the index match HEAD, but doing so would involve
+# writing a null sha1 into the index.
+test_expect_success 'setup: bring HEAD and index in sync' '
+       test_tick &&
+       git commit -a -m "back to normal"
+'
+
+test_expect_success 'filter commands are still checked' '
+       test_must_fail git filter-branch \
+               --force --prune-empty \
+               --index-filter "git rm --cached --ignore-unmatch three.t"
+'
+
+test_expect_success 'removing the broken entry works' '
+       echo three >expect &&
+       git filter-branch \
+               --force --prune-empty \
+               --index-filter "git rm --cached --ignore-unmatch broken" &&
+       git log -1 --format=%s >actual &&
+       test_cmp expect actual
+'
+
+test_done
index 52ef06b0005aabf2a201d20dbb5f232e3a26766a..7d467c034a27f50e8b60b4b0f390f08fdf126e55 100755 (executable)
@@ -29,20 +29,19 @@ test_expect_success 'Report new path with conflict' '
        test_cmp expect actual
 '
 
-cat >expect <<EOF
-# On branch side
-# You have unmerged paths.
-#   (fix conflicts and run "git commit")
-#
-# Unmerged paths:
-#   (use "git add/rm <file>..." as appropriate to mark resolution)
-#
-#      deleted by us:      foo
-#
+test_expect_success 'M/D conflict does not segfault' '
+       cat >expect <<EOF &&
+On branch side
+You have unmerged paths.
+  (fix conflicts and run "git commit")
+
+Unmerged paths:
+  (use "git add/rm <file>..." as appropriate to mark resolution)
+
+       deleted by us:      foo
+
 no changes added to commit (use "git add" and/or "git commit -a")
 EOF
-
-test_expect_success 'M/D conflict does not segfault' '
        mkdir mdconflict &&
        (
                cd mdconflict &&
@@ -135,19 +134,19 @@ test_expect_success 'status when conflicts with add and rm advice (deleted by th
        test_commit on_second main.txt on_second &&
        test_commit master conflict.txt master &&
        test_must_fail git merge second_branch &&
-       cat >expected <<-\EOF &&
-       # On branch master
-       # You have unmerged paths.
-       #   (fix conflicts and run "git commit")
-       #
-       # Unmerged paths:
-       #   (use "git add/rm <file>..." as appropriate to mark resolution)
-       #
-       #       both added:         conflict.txt
-       #       deleted by them:    main.txt
-       #
-       no changes added to commit (use "git add" and/or "git commit -a")
-       EOF
+       cat >expected <<\EOF &&
+On branch master
+You have unmerged paths.
+  (fix conflicts and run "git commit")
+
+Unmerged paths:
+  (use "git add/rm <file>..." as appropriate to mark resolution)
+
+       both added:         conflict.txt
+       deleted by them:    main.txt
+
+no changes added to commit (use "git add" and/or "git commit -a")
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -168,20 +167,20 @@ test_expect_success 'prepare for conflicts' '
 
 test_expect_success 'status when conflicts with add and rm advice (both deleted)' '
        test_must_fail git merge conflict &&
-       cat >expected <<-\EOF &&
-       # On branch conflict_second
-       # You have unmerged paths.
-       #   (fix conflicts and run "git commit")
-       #
-       # Unmerged paths:
-       #   (use "git add/rm <file>..." as appropriate to mark resolution)
-       #
-       #       both deleted:       main.txt
-       #       added by them:      sub_master.txt
-       #       added by us:        sub_second.txt
-       #
-       no changes added to commit (use "git add" and/or "git commit -a")
-       EOF
+       cat >expected <<\EOF &&
+On branch conflict_second
+You have unmerged paths.
+  (fix conflicts and run "git commit")
+
+Unmerged paths:
+  (use "git add/rm <file>..." as appropriate to mark resolution)
+
+       both deleted:       main.txt
+       added by them:      sub_master.txt
+       added by us:        sub_second.txt
+
+no changes added to commit (use "git add" and/or "git commit -a")
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -192,22 +191,22 @@ test_expect_success 'status when conflicts with only rm advice (both deleted)' '
        test_must_fail git merge conflict &&
        git add sub_master.txt &&
        git add sub_second.txt &&
-       cat >expected <<-\EOF &&
-       # On branch conflict_second
-       # You have unmerged paths.
-       #   (fix conflicts and run "git commit")
-       #
-       # Changes to be committed:
-       #
-       #       new file:   sub_master.txt
-       #
-       # Unmerged paths:
-       #   (use "git rm <file>..." to mark resolution)
-       #
-       #       both deleted:       main.txt
-       #
-       # Untracked files not listed (use -u option to show untracked files)
-       EOF
+       cat >expected <<\EOF &&
+On branch conflict_second
+You have unmerged paths.
+  (fix conflicts and run "git commit")
+
+Changes to be committed:
+
+       new file:   sub_master.txt
+
+Unmerged paths:
+  (use "git rm <file>..." to mark resolution)
+
+       both deleted:       main.txt
+
+Untracked files not listed (use -u option to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual &&
        git reset --hard &&
index 8062cf502bc473cee0d0788145f978b534246679..af00ab4d88cc75ec720e31da3a0d5d3a1ef8df40 100755 (executable)
@@ -11,7 +11,10 @@ test_expect_success 'setup' '
 test_expect_success 'reset' '
        git add a b &&
        git reset &&
-       test "$(git ls-files)" = ""
+
+       >expect &&
+       git ls-files >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'reset HEAD' '
@@ -24,28 +27,42 @@ test_expect_success 'reset $file' '
        rm .git/index &&
        git add a b &&
        git reset a &&
-       test "$(git ls-files)" = "b"
+
+       echo b >expect &&
+       git ls-files >actual &&
+       test_cmp expect actual
 '
 
-test_expect_success 'reset -p' '
+test_expect_success PERL 'reset -p' '
        rm .git/index &&
        git add a &&
-       echo y | git reset -p &&
-       test "$(git ls-files)" = ""
+       echo y >yes &&
+       git reset -p <yes &&
+
+       >expect &&
+       git ls-files >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'reset --soft is a no-op' '
        rm .git/index &&
        git add a &&
-       git reset --soft
-       test "$(git ls-files)" = "a"
+       git reset --soft &&
+
+       echo a >expect &&
+       git ls-files >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'reset --hard' '
        rm .git/index &&
        git add a &&
+       test_when_finished "echo a >a" &&
        git reset --hard &&
-       test "$(git ls-files)" = "" &&
+
+       >expect &&
+       git ls-files >actual &&
+       test_cmp expect actual &&
        test_path_is_missing a
 '
 
index c268d3c9a2838105703daeeb89c68b10d5c71b04..c28e8d8ada68f37bc0090e07f7baf21c17c2de0b 100755 (executable)
@@ -964,7 +964,6 @@ test_expect_success 'submodule with UTF-8 name' '
                git add sub &&
                git commit -m "init sub"
        ) &&
-       test_config core.precomposeunicode true &&
        git submodule add ./"$svname" &&
        git submodule >&2 &&
        test -n "$(git submodule | grep "$svname")"
index ac2434c0dbdaf837d8dd7f896e680fbb7b6ab954..366746f0d41342b38126eccc0f58c4ece64cb210 100755 (executable)
@@ -104,6 +104,24 @@ EOF
        test_cmp expected actual
 "
 
+test_expect_success 'no ignore=all setting has any effect' "
+       git config -f .gitmodules submodule.sm1.path sm1 &&
+       git config -f .gitmodules submodule.sm1.ignore all &&
+       git config submodule.sm1.ignore all &&
+       git config diff.ignoreSubmodules all &&
+       git submodule summary >actual &&
+       cat >expected <<-EOF &&
+* sm1 $head1...$head2 (1):
+  > Add foo3
+
+EOF
+       test_cmp expected actual &&
+       git config --unset diff.ignoreSubmodules &&
+       git config --remove-section submodule.sm1 &&
+       git config -f .gitmodules --remove-section submodule.sm1
+"
+
+
 commit_file sm1 &&
 head3=$(
        cd sm1 &&
@@ -265,13 +283,11 @@ EOF
 test_expect_success '--for-status' "
        git submodule summary --for-status HEAD^ >actual &&
        test_i18ncmp actual - <<EOF
-# Submodule changes to be committed:
-#
-# * sm1 $head6...0000000:
-#
-# * sm2 0000000...$head7 (2):
-#   > Add foo9
-#
+* sm1 $head6...0000000:
+
+* sm2 0000000...$head7 (2):
+  > Add foo9
+
 EOF
 "
 
index b192f936bcbe794f0691550d1bf38714b1359d01..f0b33053ab01c692a4dda15c0f631aaa45fb81b9 100755 (executable)
@@ -58,7 +58,7 @@ test_expect_success 'setup a submodule tree' '
         git submodule add ../merging merging &&
         test_tick &&
         git commit -m "rebasing"
-       )
+       ) &&
        (cd super &&
         git submodule add ../none none &&
         test_tick &&
index 99ce36f5ef91ae91c0f2ebd02ae70c4cba4c937c..f04798f87232fbbf705dd8a24300a76a2a6e435a 100755 (executable)
@@ -53,7 +53,7 @@ test_expect_success PERL 'can use paths with --interactive' '
 '
 
 test_expect_success 'using invalid commit with -C' '
-       test_must_fail git commit -C bogus
+       test_must_fail git commit --allow-empty -C bogus
 '
 
 test_expect_success 'nothing to commit' '
index ac3d0fe44507328f6363edc1d614bc9d8369899b..6fb59f32937102b4b5cdb014774bee5dbfe5a1f0 100755 (executable)
@@ -60,8 +60,13 @@ test_expect_success 'status (1)' '
        test_i18ngrep "use \"git rm --cached <file>\.\.\.\" to unstage" output
 '
 
+strip_comments () {
+       tab='   '
+       sed "s/^\# //; s/^\#$//; s/^#$tab/$tab/" <"$1" >"$1".tmp &&
+       rm "$1" && mv "$1".tmp "$1"
+}
+
 test_expect_success 'status --column' '
-       COLUMNS=50 git status --column="column dense" >output &&
        cat >expect <<\EOF &&
 # On branch master
 # Changes to be committed:
@@ -78,9 +83,17 @@ test_expect_success 'status --column' '
 # Untracked files:
 #   (use "git add <file>..." to include in what will be committed)
 #
-#      dir1/untracked dir2/untracked untracked
-#      dir2/modified  output
+#      dir1/untracked dir2/untracked output
+#      dir2/modified  expect         untracked
+#
 EOF
+       COLUMNS=50 git -c status.displayCommentPrefix=true status --column="column dense" >output &&
+       test_i18ncmp expect output
+'
+
+test_expect_success 'status --column status.displayCommentPrefix=false' '
+       strip_comments expect &&
+       COLUMNS=49 git -c status.displayCommentPrefix=false status --column="column dense" >output &&
        test_i18ncmp expect output
 '
 
@@ -106,28 +119,58 @@ cat >expect <<\EOF
 #      expect
 #      output
 #      untracked
+#
 EOF
 
-test_expect_success 'status (2)' '
-       git status >output &&
+test_expect_success 'status with status.displayCommentPrefix=true' '
+       git -c status.displayCommentPrefix=true status >output &&
+       test_i18ncmp expect output
+'
+
+test_expect_success 'status with status.displayCommentPrefix=false' '
+       strip_comments expect &&
+       git -c status.displayCommentPrefix=false status >output &&
        test_i18ncmp expect output
 '
 
+test_expect_success 'setup fake editor' '
+       cat >.git/editor <<-\EOF &&
+       #! /bin/sh
+       cp "$1" output
+EOF
+       chmod 755 .git/editor
+'
+
+commit_template_commented () {
+       (
+               EDITOR=.git/editor &&
+               export EDITOR &&
+               # Fails due to empty message
+               test_must_fail git commit
+       ) &&
+       ! grep '^[^#]' output
+}
+
+test_expect_success 'commit ignores status.displayCommentPrefix=false in COMMIT_EDITMSG' '
+       commit_template_commented
+'
+
 cat >expect <<\EOF
-# On branch master
-# Changes to be committed:
-#      new file:   dir2/added
-#
-# Changes not staged for commit:
-#      modified:   dir1/modified
-#
-# Untracked files:
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      expect
-#      output
-#      untracked
+On branch master
+Changes to be committed:
+       new file:   dir2/added
+
+Changes not staged for commit:
+       modified:   dir1/modified
+
+Untracked files:
+       dir1/untracked
+       dir2/modified
+       dir2/untracked
+       expect
+       output
+       untracked
+
 EOF
 
 test_expect_success 'status (advice.statusHints false)' '
@@ -185,33 +228,35 @@ test_expect_success 'status with gitignore' '
        git status -s --ignored >output &&
        test_cmp expect output &&
 
-       cat >expect <<-\EOF &&
-       # On branch master
-       # Changes to be committed:
-       #   (use "git reset HEAD <file>..." to unstage)
-       #
-       #       new file:   dir2/added
-       #
-       # Changes not staged for commit:
-       #   (use "git add <file>..." to update what will be committed)
-       #   (use "git checkout -- <file>..." to discard changes in working directory)
-       #
-       #       modified:   dir1/modified
-       #
-       # Untracked files:
-       #   (use "git add <file>..." to include in what will be committed)
-       #
-       #       dir2/modified
-       # Ignored files:
-       #   (use "git add -f <file>..." to include in what will be committed)
-       #
-       #       .gitignore
-       #       dir1/untracked
-       #       dir2/untracked
-       #       expect
-       #       output
-       #       untracked
-       EOF
+       cat >expect <<\EOF &&
+On branch master
+Changes to be committed:
+  (use "git reset HEAD <file>..." to unstage)
+
+       new file:   dir2/added
+
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+
+       modified:   dir1/modified
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+
+       dir2/modified
+
+Ignored files:
+  (use "git add -f <file>..." to include in what will be committed)
+
+       .gitignore
+       dir1/untracked
+       dir2/untracked
+       expect
+       output
+       untracked
+
+EOF
        git status --ignored >output &&
        test_i18ncmp expect output
 '
@@ -246,30 +291,31 @@ test_expect_success 'status with gitignore (nothing untracked)' '
        git status -s --ignored >output &&
        test_cmp expect output &&
 
-       cat >expect <<-\EOF &&
-       # On branch master
-       # Changes to be committed:
-       #   (use "git reset HEAD <file>..." to unstage)
-       #
-       #       new file:   dir2/added
-       #
-       # Changes not staged for commit:
-       #   (use "git add <file>..." to update what will be committed)
-       #   (use "git checkout -- <file>..." to discard changes in working directory)
-       #
-       #       modified:   dir1/modified
-       #
-       # Ignored files:
-       #   (use "git add -f <file>..." to include in what will be committed)
-       #
-       #       .gitignore
-       #       dir1/untracked
-       #       dir2/modified
-       #       dir2/untracked
-       #       expect
-       #       output
-       #       untracked
-       EOF
+       cat >expect <<\EOF &&
+On branch master
+Changes to be committed:
+  (use "git reset HEAD <file>..." to unstage)
+
+       new file:   dir2/added
+
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+
+       modified:   dir1/modified
+
+Ignored files:
+  (use "git add -f <file>..." to include in what will be committed)
+
+       .gitignore
+       dir1/untracked
+       dir2/modified
+       dir2/untracked
+       expect
+       output
+       untracked
+
+EOF
        git status --ignored >output &&
        test_i18ncmp expect output
 '
@@ -310,22 +356,22 @@ test_expect_success 'setup dir3' '
        : >dir3/untracked2
 '
 
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      new file:   dir2/added
-#
-# Changes not staged for commit:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#
-# Untracked files not listed (use -u option to show untracked files)
-EOF
 test_expect_success 'status -uno' '
+       cat >expect <<EOF &&
+On branch master
+Changes to be committed:
+  (use "git reset HEAD <file>..." to unstage)
+
+       new file:   dir2/added
+
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+
+       modified:   dir1/modified
+
+Untracked files not listed (use -u option to show untracked files)
+EOF
        git status -uno >output &&
        test_i18ncmp expect output
 '
@@ -336,17 +382,17 @@ test_expect_success 'status (status.showUntrackedFiles no)' '
        test_i18ncmp expect output
 '
 
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-#      new file:   dir2/added
-#
-# Changes not staged for commit:
-#      modified:   dir1/modified
-#
-# Untracked files not listed
-EOF
 test_expect_success 'status -uno (advice.statusHints false)' '
+       cat >expect <<EOF &&
+On branch master
+Changes to be committed:
+       new file:   dir2/added
+
+Changes not staged for commit:
+       modified:   dir1/modified
+
+Untracked files not listed
+EOF
        test_config advice.statusHints false &&
        git status -uno >output &&
        test_i18ncmp expect output
@@ -367,31 +413,32 @@ test_expect_success 'status -s (status.showUntrackedFiles no)' '
        test_cmp expect output
 '
 
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      new file:   dir2/added
-#
-# Changes not staged for commit:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      dir3/
-#      expect
-#      output
-#      untracked
-EOF
 test_expect_success 'status -unormal' '
+       cat >expect <<EOF &&
+On branch master
+Changes to be committed:
+  (use "git reset HEAD <file>..." to unstage)
+
+       new file:   dir2/added
+
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+
+       modified:   dir1/modified
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+
+       dir1/untracked
+       dir2/modified
+       dir2/untracked
+       dir3/
+       expect
+       output
+       untracked
+
+EOF
        git status -unormal >output &&
        test_i18ncmp expect output
 '
@@ -424,32 +471,33 @@ test_expect_success 'status -s (status.showUntrackedFiles normal)' '
        test_cmp expect output
 '
 
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      new file:   dir2/added
-#
-# Changes not staged for commit:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      dir3/untracked1
-#      dir3/untracked2
-#      expect
-#      output
-#      untracked
-EOF
 test_expect_success 'status -uall' '
+       cat >expect <<EOF &&
+On branch master
+Changes to be committed:
+  (use "git reset HEAD <file>..." to unstage)
+
+       new file:   dir2/added
+
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+
+       modified:   dir1/modified
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+
+       dir1/untracked
+       dir2/modified
+       dir2/untracked
+       dir3/untracked1
+       dir3/untracked2
+       expect
+       output
+       untracked
+
+EOF
        git status -uall >output &&
        test_i18ncmp expect output
 '
@@ -486,31 +534,31 @@ test_expect_success 'status -s (status.showUntrackedFiles all)' '
        test_cmp expect output
 '
 
-cat >expect <<\EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      new file:   ../dir2/added
-#
-# Changes not staged for commit:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   modified
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      untracked
-#      ../dir2/modified
-#      ../dir2/untracked
-#      ../expect
-#      ../output
-#      ../untracked
-EOF
-
 test_expect_success 'status with relative paths' '
+       cat >expect <<\EOF &&
+On branch master
+Changes to be committed:
+  (use "git reset HEAD <file>..." to unstage)
+
+       new file:   ../dir2/added
+
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+
+       modified:   modified
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+
+       untracked
+       ../dir2/modified
+       ../dir2/untracked
+       ../expect
+       ../output
+       ../untracked
+
+EOF
        (cd dir1 && git status) >output &&
        test_i18ncmp expect output
 '
@@ -557,31 +605,31 @@ test_expect_success 'setup unique colors' '
 
 '
 
-cat >expect <<\EOF
-# On branch <GREEN>master<RESET>
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      <GREEN>new file:   dir2/added<RESET>
-#
-# Changes not staged for commit:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      <RED>modified:   dir1/modified<RESET>
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      <BLUE>dir1/untracked<RESET>
-#      <BLUE>dir2/modified<RESET>
-#      <BLUE>dir2/untracked<RESET>
-#      <BLUE>expect<RESET>
-#      <BLUE>output<RESET>
-#      <BLUE>untracked<RESET>
-EOF
-
 test_expect_success 'status with color.ui' '
+       cat >expect <<\EOF &&
+On branch <GREEN>master<RESET>
+Changes to be committed:
+  (use "git reset HEAD <file>..." to unstage)
+
+       <GREEN>new file:   dir2/added<RESET>
+
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+
+       <RED>modified:   dir1/modified<RESET>
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+
+       <BLUE>dir1/untracked<RESET>
+       <BLUE>dir2/modified<RESET>
+       <BLUE>dir2/untracked<RESET>
+       <BLUE>expect<RESET>
+       <BLUE>output<RESET>
+       <BLUE>untracked<RESET>
+
+EOF
        test_config color.ui always &&
        git status | test_decode_color >output &&
        test_i18ncmp expect output
@@ -685,33 +733,33 @@ test_expect_success 'status --porcelain respects -b' '
 
 '
 
-cat >expect <<\EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      new file:   dir2/added
-#
-# Changes not staged for commit:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      expect
-#      output
-#      untracked
-EOF
 
 
 test_expect_success 'status without relative paths' '
+       cat >expect <<\EOF &&
+On branch master
+Changes to be committed:
+  (use "git reset HEAD <file>..." to unstage)
+
+       new file:   dir2/added
 
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+
+       modified:   dir1/modified
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+
+       dir1/untracked
+       dir2/modified
+       dir2/untracked
+       expect
+       output
+       untracked
+
+EOF
        test_config status.relativePaths false &&
        (cd dir1 && git status) >output &&
        test_i18ncmp expect output
@@ -737,23 +785,24 @@ test_expect_success 'status -s without relative paths' '
 
 '
 
-cat <<EOF >expect
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      modified:   dir1/modified
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      dir1/untracked
-#      dir2/
-#      expect
-#      output
-#      untracked
-EOF
 test_expect_success 'dry-run of partial commit excluding new file in index' '
+       cat >expect <<EOF &&
+On branch master
+Changes to be committed:
+  (use "git reset HEAD <file>..." to unstage)
+
+       modified:   dir1/modified
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+
+       dir1/untracked
+       dir2/
+       expect
+       output
+       untracked
+
+EOF
        git commit --dry-run dir1/modified >output &&
        test_i18ncmp expect output
 '
@@ -778,31 +827,32 @@ test_expect_success 'setup status submodule summary' '
        git add sm
 '
 
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      new file:   dir2/added
-#      new file:   sm
-#
-# Changes not staged for commit:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      expect
-#      output
-#      untracked
-EOF
 test_expect_success 'status submodule summary is disabled by default' '
+       cat >expect <<EOF &&
+On branch master
+Changes to be committed:
+  (use "git reset HEAD <file>..." to unstage)
+
+       new file:   dir2/added
+       new file:   sm
+
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+
+       modified:   dir1/modified
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+
+       dir1/untracked
+       dir2/modified
+       dir2/untracked
+       expect
+       output
+       untracked
+
+EOF
        git status >output &&
        test_i18ncmp expect output
 '
@@ -837,41 +887,52 @@ test_expect_success 'status -s --untracked-files=all does not show submodule' '
 
 head=$(cd sm && git rev-parse --short=7 --verify HEAD)
 
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      new file:   dir2/added
-#      new file:   sm
-#
-# Changes not staged for commit:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#
-# Submodule changes to be committed:
-#
-# * sm 0000000...$head (1):
-#   > Add foo
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      expect
-#      output
-#      untracked
-EOF
 test_expect_success 'status submodule summary' '
+       cat >expect <<EOF &&
+On branch master
+Changes to be committed:
+  (use "git reset HEAD <file>..." to unstage)
+
+       new file:   dir2/added
+       new file:   sm
+
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+
+       modified:   dir1/modified
+
+Submodule changes to be committed:
+
+* sm 0000000...$head (1):
+  > Add foo
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+
+       dir1/untracked
+       dir2/modified
+       dir2/untracked
+       expect
+       output
+       untracked
+
+EOF
        git config status.submodulesummary 10 &&
        git status >output &&
        test_i18ncmp expect output
 '
 
+test_expect_success 'status submodule summary with status.displayCommentPrefix=false' '
+       strip_comments expect &&
+       git -c status.displayCommentPrefix=false status >output &&
+       test_i18ncmp expect output
+'
+
+test_expect_success 'commit with submodule summary ignores status.displayCommentPrefix' '
+       commit_template_commented
+'
+
 cat >expect <<EOF
  M dir1/modified
 A  dir2/added
@@ -888,26 +949,27 @@ test_expect_success 'status -s submodule summary' '
        test_cmp expect output
 '
 
-cat >expect <<EOF
-# On branch master
-# Changes not staged for commit:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      expect
-#      output
-#      untracked
+test_expect_success 'status submodule summary (clean submodule): commit' '
+       cat >expect <<EOF &&
+On branch master
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+
+       modified:   dir1/modified
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+
+       dir1/untracked
+       dir2/modified
+       dir2/untracked
+       expect
+       output
+       untracked
+
 no changes added to commit (use "git add" and/or "git commit -a")
 EOF
-test_expect_success 'status submodule summary (clean submodule): commit' '
        git commit -m "commit submodule" &&
        git config status.submodulesummary 10 &&
        test_must_fail git commit --dry-run >output &&
@@ -937,36 +999,37 @@ test_expect_success 'status -z implies porcelain' '
        test_cmp expect output
 '
 
-cat >expect <<EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD^1 <file>..." to unstage)
-#
-#      new file:   dir2/added
-#      new file:   sm
-#
-# Changes not staged for commit:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#
-# Submodule changes to be committed:
-#
-# * sm 0000000...$head (1):
-#   > Add foo
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      expect
-#      output
-#      untracked
-EOF
 test_expect_success 'commit --dry-run submodule summary (--amend)' '
+       cat >expect <<EOF &&
+On branch master
+Changes to be committed:
+  (use "git reset HEAD^1 <file>..." to unstage)
+
+       new file:   dir2/added
+       new file:   sm
+
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+
+       modified:   dir1/modified
+
+Submodule changes to be committed:
+
+* sm 0000000...$head (1):
+  > Add foo
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+
+       dir1/untracked
+       dir2/modified
+       dir2/untracked
+       expect
+       output
+       untracked
+
+EOF
        git config status.submodulesummary 10 &&
        git commit --dry-run --amend >output &&
        test_i18ncmp expect output
@@ -991,37 +1054,37 @@ test_expect_success POSIXPERM,SANITY 'status succeeds in a read-only repository'
 new_head=$(cd sm && git rev-parse --short=7 --verify HEAD)
 touch .gitmodules
 
-cat > expect << EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      modified:   sm
-#
-# Changes not staged for commit:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#
-# Submodule changes to be committed:
-#
-# * sm $head...$new_head (1):
-#   > Add bar
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      .gitmodules
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      expect
-#      output
-#      untracked
-EOF
-
 test_expect_success '--ignore-submodules=untracked suppresses submodules with untracked content' '
+       cat > expect << EOF &&
+On branch master
+Changes to be committed:
+  (use "git reset HEAD <file>..." to unstage)
+
+       modified:   sm
+
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+
+       modified:   dir1/modified
+
+Submodule changes to be committed:
+
+* sm $head...$new_head (1):
+  > Add bar
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+
+       .gitmodules
+       dir1/untracked
+       dir2/modified
+       dir2/untracked
+       expect
+       output
+       untracked
+
+EOF
        echo modified  sm/untracked &&
        git status --ignore-submodules=untracked >output &&
        test_i18ncmp expect output
@@ -1101,39 +1164,39 @@ test_expect_success '.git/config ignore=dirty suppresses submodules with modifie
        git config -f .gitmodules  --remove-section submodule.subname
 '
 
-cat > expect << EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      modified:   sm
-#
-# Changes not staged for commit:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#   (commit or discard the untracked or modified content in submodules)
-#
-#      modified:   dir1/modified
-#      modified:   sm (modified content)
-#
-# Submodule changes to be committed:
-#
-# * sm $head...$new_head (1):
-#   > Add bar
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      .gitmodules
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      expect
-#      output
-#      untracked
-EOF
-
 test_expect_success "--ignore-submodules=untracked doesn't suppress submodules with modified content" '
+       cat > expect << EOF &&
+On branch master
+Changes to be committed:
+  (use "git reset HEAD <file>..." to unstage)
+
+       modified:   sm
+
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+  (commit or discard the untracked or modified content in submodules)
+
+       modified:   dir1/modified
+       modified:   sm (modified content)
+
+Submodule changes to be committed:
+
+* sm $head...$new_head (1):
+  > Add bar
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+
+       .gitmodules
+       dir1/untracked
+       dir2/modified
+       dir2/untracked
+       expect
+       output
+       untracked
+
+EOF
        git status --ignore-submodules=untracked > output &&
        test_i18ncmp expect output
 '
@@ -1159,43 +1222,43 @@ test_expect_success ".git/config ignore=untracked doesn't suppress submodules wi
 
 head2=$(cd sm && git commit -q -m "2nd commit" foo && git rev-parse --short=7 --verify HEAD)
 
-cat > expect << EOF
-# On branch master
-# Changes to be committed:
-#   (use "git reset HEAD <file>..." to unstage)
-#
-#      modified:   sm
-#
-# Changes not staged for commit:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#      modified:   sm (new commits)
-#
-# Submodule changes to be committed:
-#
-# * sm $head...$new_head (1):
-#   > Add bar
-#
-# Submodules changed but not updated:
-#
-# * sm $new_head...$head2 (1):
-#   > 2nd commit
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      .gitmodules
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      expect
-#      output
-#      untracked
-EOF
-
 test_expect_success "--ignore-submodules=untracked doesn't suppress submodule summary" '
+       cat > expect << EOF &&
+On branch master
+Changes to be committed:
+  (use "git reset HEAD <file>..." to unstage)
+
+       modified:   sm
+
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+
+       modified:   dir1/modified
+       modified:   sm (new commits)
+
+Submodule changes to be committed:
+
+* sm $head...$new_head (1):
+  > Add bar
+
+Submodules changed but not updated:
+
+* sm $new_head...$head2 (1):
+  > 2nd commit
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+
+       .gitmodules
+       dir1/untracked
+       dir2/modified
+       dir2/untracked
+       expect
+       output
+       untracked
+
+EOF
        git status --ignore-submodules=untracked > output &&
        test_i18ncmp expect output
 '
@@ -1276,47 +1339,48 @@ cat > expect << EOF
 ;      expect
 ;      output
 ;      untracked
+;
 EOF
 
 test_expect_success "status (core.commentchar with submodule summary)" '
        test_config core.commentchar ";" &&
-       git status >output &&
+       git -c status.displayCommentPrefix=true status >output &&
        test_i18ncmp expect output
 '
 
 test_expect_success "status (core.commentchar with two chars with submodule summary)" '
        test_config core.commentchar ";;" &&
-       git status >output &&
+       git -c status.displayCommentPrefix=true status >output &&
        test_i18ncmp expect output
 '
 
-cat > expect << EOF
-# On branch master
-# Changes not staged for commit:
-#   (use "git add <file>..." to update what will be committed)
-#   (use "git checkout -- <file>..." to discard changes in working directory)
-#
-#      modified:   dir1/modified
-#
-# Untracked files:
-#   (use "git add <file>..." to include in what will be committed)
-#
-#      .gitmodules
-#      dir1/untracked
-#      dir2/modified
-#      dir2/untracked
-#      expect
-#      output
-#      untracked
+test_expect_success "--ignore-submodules=all suppresses submodule summary" '
+       cat > expect << EOF &&
+On branch master
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+
+       modified:   dir1/modified
+
+Untracked files:
+  (use "git add <file>..." to include in what will be committed)
+
+       .gitmodules
+       dir1/untracked
+       dir2/modified
+       dir2/untracked
+       expect
+       output
+       untracked
+
 no changes added to commit (use "git add" and/or "git commit -a")
 EOF
-
-test_expect_success "--ignore-submodules=all suppresses submodule summary" '
        git status --ignore-submodules=all > output &&
        test_i18ncmp expect output
 '
 
-test_expect_failure '.gitmodules ignore=all suppresses submodule summary' '
+test_expect_success '.gitmodules ignore=all suppresses submodule summary' '
        git config --add -f .gitmodules submodule.subname.ignore all &&
        git config --add -f .gitmodules submodule.subname.path sm &&
        git status > output &&
@@ -1324,7 +1388,7 @@ test_expect_failure '.gitmodules ignore=all suppresses submodule summary' '
        git config -f .gitmodules  --remove-section submodule.subname
 '
 
-test_expect_failure '.git/config ignore=all suppresses submodule summary' '
+test_expect_success '.git/config ignore=all suppresses submodule summary' '
        git config --add -f .gitmodules submodule.subname.ignore none &&
        git config --add -f .gitmodules submodule.subname.path sm &&
        git config --add submodule.subname.ignore all &&
index 31a798fda21f178cbbedf47ee92dbd997f9c4e42..3cec57af1ee0ca8ccbbbdc47871cd4ff07e0d034 100755 (executable)
@@ -25,18 +25,18 @@ test_expect_success 'prepare for conflicts' '
 
 test_expect_success 'status when conflicts unresolved' '
        test_must_fail git merge master &&
-       cat >expected <<-\EOF &&
-       # On branch conflicts
-       # You have unmerged paths.
-       #   (fix conflicts and run "git commit")
-       #
-       # Unmerged paths:
-       #   (use "git add <file>..." to mark resolution)
-       #
-       #       both modified:      main.txt
-       #
-       no changes added to commit (use "git add" and/or "git commit -a")
-       EOF
+       cat >expected <<\EOF &&
+On branch conflicts
+You have unmerged paths.
+  (fix conflicts and run "git commit")
+
+Unmerged paths:
+  (use "git add <file>..." to mark resolution)
+
+       both modified:      main.txt
+
+no changes added to commit (use "git add" and/or "git commit -a")
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -47,17 +47,17 @@ test_expect_success 'status when conflicts resolved before commit' '
        test_must_fail git merge master &&
        echo one >main.txt &&
        git add main.txt &&
-       cat >expected <<-\EOF &&
-       # On branch conflicts
-       # All conflicts fixed but you are still merging.
-       #   (use "git commit" to conclude merge)
-       #
-       # Changes to be committed:
-       #
-       #       modified:   main.txt
-       #
-       # Untracked files not listed (use -u option to show untracked files)
-       EOF
+       cat >expected <<\EOF &&
+On branch conflicts
+All conflicts fixed but you are still merging.
+  (use "git commit" to conclude merge)
+
+Changes to be committed:
+
+       modified:   main.txt
+
+Untracked files not listed (use -u option to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -76,21 +76,21 @@ test_expect_success 'status when rebase in progress before resolving conflicts'
        test_when_finished "git rebase --abort" &&
        ONTO=$(git rev-parse --short HEAD^^) &&
        test_must_fail git rebase HEAD^ --onto HEAD^^ &&
-       cat >expected <<-EOF &&
-       # rebase in progress; onto $ONTO
-       # You are currently rebasing branch '\''rebase_conflicts'\'' on '\''$ONTO'\''.
-       #   (fix conflicts and then run "git rebase --continue")
-       #   (use "git rebase --skip" to skip this patch)
-       #   (use "git rebase --abort" to check out the original branch)
-       #
-       # Unmerged paths:
-       #   (use "git reset HEAD <file>..." to unstage)
-       #   (use "git add <file>..." to mark resolution)
-       #
-       #       both modified:      main.txt
-       #
-       no changes added to commit (use "git add" and/or "git commit -a")
-       EOF
+       cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently rebasing branch '\''rebase_conflicts'\'' on '\''$ONTO'\''.
+  (fix conflicts and then run "git rebase --continue")
+  (use "git rebase --skip" to skip this patch)
+  (use "git rebase --abort" to check out the original branch)
+
+Unmerged paths:
+  (use "git reset HEAD <file>..." to unstage)
+  (use "git add <file>..." to mark resolution)
+
+       both modified:      main.txt
+
+no changes added to commit (use "git add" and/or "git commit -a")
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -103,18 +103,18 @@ test_expect_success 'status when rebase in progress before rebase --continue' '
        test_must_fail git rebase HEAD^ --onto HEAD^^ &&
        echo three >main.txt &&
        git add main.txt &&
-       cat >expected <<-EOF &&
-       # rebase in progress; onto $ONTO
-       # You are currently rebasing branch '\''rebase_conflicts'\'' on '\''$ONTO'\''.
-       #   (all conflicts fixed: run "git rebase --continue")
-       #
-       # Changes to be committed:
-       #   (use "git reset HEAD <file>..." to unstage)
-       #
-       #       modified:   main.txt
-       #
-       # Untracked files not listed (use -u option to show untracked files)
-       EOF
+       cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently rebasing branch '\''rebase_conflicts'\'' on '\''$ONTO'\''.
+  (all conflicts fixed: run "git rebase --continue")
+
+Changes to be committed:
+  (use "git reset HEAD <file>..." to unstage)
+
+       modified:   main.txt
+
+Untracked files not listed (use -u option to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -135,21 +135,21 @@ test_expect_success 'status during rebase -i when conflicts unresolved' '
        test_when_finished "git rebase --abort" &&
        ONTO=$(git rev-parse --short rebase_i_conflicts) &&
        test_must_fail git rebase -i rebase_i_conflicts &&
-       cat >expected <<-EOF &&
-       # rebase in progress; onto $ONTO
-       # You are currently rebasing branch '\''rebase_i_conflicts_second'\'' on '\''$ONTO'\''.
-       #   (fix conflicts and then run "git rebase --continue")
-       #   (use "git rebase --skip" to skip this patch)
-       #   (use "git rebase --abort" to check out the original branch)
-       #
-       # Unmerged paths:
-       #   (use "git reset HEAD <file>..." to unstage)
-       #   (use "git add <file>..." to mark resolution)
-       #
-       #       both modified:      main.txt
-       #
-       no changes added to commit (use "git add" and/or "git commit -a")
-       EOF
+       cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently rebasing branch '\''rebase_i_conflicts_second'\'' on '\''$ONTO'\''.
+  (fix conflicts and then run "git rebase --continue")
+  (use "git rebase --skip" to skip this patch)
+  (use "git rebase --abort" to check out the original branch)
+
+Unmerged paths:
+  (use "git reset HEAD <file>..." to unstage)
+  (use "git add <file>..." to mark resolution)
+
+       both modified:      main.txt
+
+no changes added to commit (use "git add" and/or "git commit -a")
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -161,18 +161,18 @@ test_expect_success 'status during rebase -i after resolving conflicts' '
        ONTO=$(git rev-parse --short rebase_i_conflicts) &&
        test_must_fail git rebase -i rebase_i_conflicts &&
        git add main.txt &&
-       cat >expected <<-EOF &&
-       # rebase in progress; onto $ONTO
-       # You are currently rebasing branch '\''rebase_i_conflicts_second'\'' on '\''$ONTO'\''.
-       #   (all conflicts fixed: run "git rebase --continue")
-       #
-       # Changes to be committed:
-       #   (use "git reset HEAD <file>..." to unstage)
-       #
-       #       modified:   main.txt
-       #
-       # Untracked files not listed (use -u option to show untracked files)
-       EOF
+       cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently rebasing branch '\''rebase_i_conflicts_second'\'' on '\''$ONTO'\''.
+  (all conflicts fixed: run "git rebase --continue")
+
+Changes to be committed:
+  (use "git reset HEAD <file>..." to unstage)
+
+       modified:   main.txt
+
+Untracked files not listed (use -u option to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -189,14 +189,14 @@ test_expect_success 'status when rebasing -i in edit mode' '
        test_when_finished "git rebase --abort" &&
        ONTO=$(git rev-parse --short HEAD~2) &&
        git rebase -i HEAD~2 &&
-       cat >expected <<-EOF &&
-       # rebase in progress; onto $ONTO
-       # You are currently editing a commit while rebasing branch '\''rebase_i_edit'\'' on '\''$ONTO'\''.
-       #   (use "git commit --amend" to amend the current commit)
-       #   (use "git rebase --continue" once you are satisfied with your changes)
-       #
-       nothing to commit (use -u to show untracked files)
-       EOF
+       cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently editing a commit while rebasing branch '\''rebase_i_edit'\'' on '\''$ONTO'\''.
+  (use "git commit --amend" to amend the current commit)
+  (use "git rebase --continue" once you are satisfied with your changes)
+
+nothing to commit (use -u to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -215,19 +215,19 @@ test_expect_success 'status when splitting a commit' '
        ONTO=$(git rev-parse --short HEAD~3) &&
        git rebase -i HEAD~3 &&
        git reset HEAD^ &&
-       cat >expected <<-EOF &&
-       # rebase in progress; onto $ONTO
-       # You are currently splitting a commit while rebasing branch '\''split_commit'\'' on '\''$ONTO'\''.
-       #   (Once your working directory is clean, run "git rebase --continue")
-       #
-       # Changes not staged for commit:
-       #   (use "git add <file>..." to update what will be committed)
-       #   (use "git checkout -- <file>..." to discard changes in working directory)
-       #
-       #       modified:   main.txt
-       #
-       no changes added to commit (use "git add" and/or "git commit -a")
-       EOF
+       cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently splitting a commit while rebasing branch '\''split_commit'\'' on '\''$ONTO'\''.
+  (Once your working directory is clean, run "git rebase --continue")
+
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+
+       modified:   main.txt
+
+no changes added to commit (use "git add" and/or "git commit -a")
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -246,14 +246,14 @@ test_expect_success 'status after editing the last commit with --amend during a
        ONTO=$(git rev-parse --short HEAD~3) &&
        git rebase -i HEAD~3 &&
        git commit --amend -m "foo" &&
-       cat >expected <<-EOF &&
-       # rebase in progress; onto $ONTO
-       # You are currently editing a commit while rebasing branch '\''amend_last'\'' on '\''$ONTO'\''.
-       #   (use "git commit --amend" to amend the current commit)
-       #   (use "git rebase --continue" once you are satisfied with your changes)
-       #
-       nothing to commit (use -u to show untracked files)
-       EOF
+       cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently editing a commit while rebasing branch '\''amend_last'\'' on '\''$ONTO'\''.
+  (use "git commit --amend" to amend the current commit)
+  (use "git rebase --continue" once you are satisfied with your changes)
+
+nothing to commit (use -u to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -276,14 +276,14 @@ test_expect_success 'status: (continue first edit) second edit' '
        ONTO=$(git rev-parse --short HEAD~3) &&
        git rebase -i HEAD~3 &&
        git rebase --continue &&
-       cat >expected <<-EOF &&
-       # rebase in progress; onto $ONTO
-       # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
-       #   (use "git commit --amend" to amend the current commit)
-       #   (use "git rebase --continue" once you are satisfied with your changes)
-       #
-       nothing to commit (use -u to show untracked files)
-       EOF
+       cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
+  (use "git commit --amend" to amend the current commit)
+  (use "git rebase --continue" once you are satisfied with your changes)
+
+nothing to commit (use -u to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -298,19 +298,19 @@ test_expect_success 'status: (continue first edit) second edit and split' '
        git rebase -i HEAD~3 &&
        git rebase --continue &&
        git reset HEAD^ &&
-       cat >expected <<-EOF &&
-       # rebase in progress; onto $ONTO
-       # You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
-       #   (Once your working directory is clean, run "git rebase --continue")
-       #
-       # Changes not staged for commit:
-       #   (use "git add <file>..." to update what will be committed)
-       #   (use "git checkout -- <file>..." to discard changes in working directory)
-       #
-       #       modified:   main.txt
-       #
-       no changes added to commit (use "git add" and/or "git commit -a")
-       EOF
+       cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
+  (Once your working directory is clean, run "git rebase --continue")
+
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+
+       modified:   main.txt
+
+no changes added to commit (use "git add" and/or "git commit -a")
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -325,14 +325,14 @@ test_expect_success 'status: (continue first edit) second edit and amend' '
        git rebase -i HEAD~3 &&
        git rebase --continue &&
        git commit --amend -m "foo" &&
-       cat >expected <<-EOF &&
-       # rebase in progress; onto $ONTO
-       # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
-       #   (use "git commit --amend" to amend the current commit)
-       #   (use "git rebase --continue" once you are satisfied with your changes)
-       #
-       nothing to commit (use -u to show untracked files)
-       EOF
+       cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
+  (use "git commit --amend" to amend the current commit)
+  (use "git rebase --continue" once you are satisfied with your changes)
+
+nothing to commit (use -u to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -347,14 +347,14 @@ test_expect_success 'status: (amend first edit) second edit' '
        git rebase -i HEAD~3 &&
        git commit --amend -m "a" &&
        git rebase --continue &&
-       cat >expected <<-EOF &&
-       # rebase in progress; onto $ONTO
-       # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
-       #   (use "git commit --amend" to amend the current commit)
-       #   (use "git rebase --continue" once you are satisfied with your changes)
-       #
-       nothing to commit (use -u to show untracked files)
-       EOF
+       cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
+  (use "git commit --amend" to amend the current commit)
+  (use "git rebase --continue" once you are satisfied with your changes)
+
+nothing to commit (use -u to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -370,19 +370,19 @@ test_expect_success 'status: (amend first edit) second edit and split' '
        git commit --amend -m "b" &&
        git rebase --continue &&
        git reset HEAD^ &&
-       cat >expected <<-EOF &&
-       # rebase in progress; onto $ONTO
-       # You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
-       #   (Once your working directory is clean, run "git rebase --continue")
-       #
-       # Changes not staged for commit:
-       #   (use "git add <file>..." to update what will be committed)
-       #   (use "git checkout -- <file>..." to discard changes in working directory)
-       #
-       #       modified:   main.txt
-       #
-       no changes added to commit (use "git add" and/or "git commit -a")
-       EOF
+       cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
+  (Once your working directory is clean, run "git rebase --continue")
+
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+
+       modified:   main.txt
+
+no changes added to commit (use "git add" and/or "git commit -a")
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -398,14 +398,14 @@ test_expect_success 'status: (amend first edit) second edit and amend' '
        git commit --amend -m "c" &&
        git rebase --continue &&
        git commit --amend -m "d" &&
-       cat >expected <<-EOF &&
-       # rebase in progress; onto $ONTO
-       # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
-       #   (use "git commit --amend" to amend the current commit)
-       #   (use "git rebase --continue" once you are satisfied with your changes)
-       #
-       nothing to commit (use -u to show untracked files)
-       EOF
+       cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
+  (use "git commit --amend" to amend the current commit)
+  (use "git rebase --continue" once you are satisfied with your changes)
+
+nothing to commit (use -u to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -422,14 +422,14 @@ test_expect_success 'status: (split first edit) second edit' '
        git add main.txt &&
        git commit -m "e" &&
        git rebase --continue &&
-       cat >expected <<-EOF &&
-       # rebase in progress; onto $ONTO
-       # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
-       #   (use "git commit --amend" to amend the current commit)
-       #   (use "git rebase --continue" once you are satisfied with your changes)
-       #
-       nothing to commit (use -u to show untracked files)
-       EOF
+       cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
+  (use "git commit --amend" to amend the current commit)
+  (use "git rebase --continue" once you are satisfied with your changes)
+
+nothing to commit (use -u to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -447,19 +447,19 @@ test_expect_success 'status: (split first edit) second edit and split' '
        git commit --amend -m "f" &&
        git rebase --continue &&
        git reset HEAD^ &&
-       cat >expected <<-EOF &&
-       # rebase in progress; onto $ONTO
-       # You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
-       #   (Once your working directory is clean, run "git rebase --continue")
-       #
-       # Changes not staged for commit:
-       #   (use "git add <file>..." to update what will be committed)
-       #   (use "git checkout -- <file>..." to discard changes in working directory)
-       #
-       #       modified:   main.txt
-       #
-       no changes added to commit (use "git add" and/or "git commit -a")
-       EOF
+       cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
+  (Once your working directory is clean, run "git rebase --continue")
+
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git checkout -- <file>..." to discard changes in working directory)
+
+       modified:   main.txt
+
+no changes added to commit (use "git add" and/or "git commit -a")
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -477,14 +477,14 @@ test_expect_success 'status: (split first edit) second edit and amend' '
        git commit --amend -m "g" &&
        git rebase --continue &&
        git commit --amend -m "h" &&
-       cat >expected <<-EOF &&
-       # rebase in progress; onto $ONTO
-       # You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
-       #   (use "git commit --amend" to amend the current commit)
-       #   (use "git rebase --continue" once you are satisfied with your changes)
-       #
-       nothing to commit (use -u to show untracked files)
-       EOF
+       cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
+  (use "git commit --amend" to amend the current commit)
+  (use "git rebase --continue" once you are satisfied with your changes)
+
+nothing to commit (use -u to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -504,15 +504,15 @@ test_expect_success 'status in an am session: file already exists' '
        test_when_finished "rm Maildir/* && git am --abort" &&
        git format-patch -1 -oMaildir &&
        test_must_fail git am Maildir/*.patch &&
-       cat >expected <<-\EOF &&
-       # On branch am_already_exists
-       # You are in the middle of an am session.
-       #   (fix conflicts and then run "git am --continue")
-       #   (use "git am --skip" to skip this patch)
-       #   (use "git am --abort" to restore the original branch)
-       #
-       nothing to commit (use -u to show untracked files)
-       EOF
+       cat >expected <<\EOF &&
+On branch am_already_exists
+You are in the middle of an am session.
+  (fix conflicts and then run "git am --continue")
+  (use "git am --skip" to skip this patch)
+  (use "git am --abort" to restore the original branch)
+
+nothing to commit (use -u to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -526,15 +526,15 @@ test_expect_success 'status in an am session: file does not exist' '
        test_when_finished "rm Maildir/* && git am --abort" &&
        git format-patch -1 -oMaildir &&
        test_must_fail git am Maildir/*.patch &&
-       cat >expected <<-\EOF &&
-       # On branch am_not_exists
-       # You are in the middle of an am session.
-       #   (fix conflicts and then run "git am --continue")
-       #   (use "git am --skip" to skip this patch)
-       #   (use "git am --abort" to restore the original branch)
-       #
-       nothing to commit (use -u to show untracked files)
-       EOF
+       cat >expected <<\EOF &&
+On branch am_not_exists
+You are in the middle of an am session.
+  (fix conflicts and then run "git am --continue")
+  (use "git am --skip" to skip this patch)
+  (use "git am --abort" to restore the original branch)
+
+nothing to commit (use -u to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -549,15 +549,15 @@ test_expect_success 'status in an am session: empty patch' '
        git commit -m "delete all am_empty" &&
        echo error >Maildir/0002-two_am.patch &&
        test_must_fail git am Maildir/*.patch &&
-       cat >expected <<-\EOF &&
-       # On branch am_empty
-       # You are in the middle of an am session.
-       # The current patch is empty.
-       #   (use "git am --skip" to skip this patch)
-       #   (use "git am --abort" to restore the original branch)
-       #
-       nothing to commit (use -u to show untracked files)
-       EOF
+       cat >expected <<\EOF &&
+On branch am_empty
+You are in the middle of an am session.
+The current patch is empty.
+  (use "git am --skip" to skip this patch)
+  (use "git am --abort" to restore the original branch)
+
+nothing to commit (use -u to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -574,13 +574,13 @@ test_expect_success 'status when bisecting' '
        git bisect bad &&
        git bisect good one_bisect &&
        TGT=$(git rev-parse --short two_bisect) &&
-       cat >expected <<-EOF &&
-       # HEAD detached at $TGT
-       # You are currently bisecting, started from branch '\''bisect'\''.
-       #   (use "git bisect reset" to get back to the original branch)
-       #
-       nothing to commit (use -u to show untracked files)
-       EOF
+       cat >expected <<EOF &&
+HEAD detached at $TGT
+You are currently bisecting, started from branch '\''bisect'\''.
+  (use "git bisect reset" to get back to the original branch)
+
+nothing to commit (use -u to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -597,15 +597,15 @@ test_expect_success 'status when rebase conflicts with statushints disabled' '
        test_when_finished "git rebase --abort" &&
        ONTO=$(git rev-parse --short HEAD^^) &&
        test_must_fail git rebase HEAD^ --onto HEAD^^ &&
-       cat >expected <<-EOF &&
-       # rebase in progress; onto $ONTO
-       # You are currently rebasing branch '\''statushints_disabled'\'' on '\''$ONTO'\''.
-       #
-       # Unmerged paths:
-       #       both modified:      main.txt
-       #
-       no changes added to commit
-       EOF
+       cat >expected <<EOF &&
+rebase in progress; onto $ONTO
+You are currently rebasing branch '\''statushints_disabled'\'' on '\''$ONTO'\''.
+
+Unmerged paths:
+       both modified:      main.txt
+
+no changes added to commit
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -626,19 +626,20 @@ test_expect_success 'prepare for cherry-pick conflicts' '
 test_expect_success 'status when cherry-picking before resolving conflicts' '
        test_when_finished "git cherry-pick --abort" &&
        test_must_fail git cherry-pick cherry_branch_second &&
-       cat >expected <<-\EOF &&
-       # On branch cherry_branch
-       # You are currently cherry-picking.
-       #   (fix conflicts and run "git cherry-pick --continue")
-       #   (use "git cherry-pick --abort" to cancel the cherry-pick operation)
-       #
-       # Unmerged paths:
-       #   (use "git add <file>..." to mark resolution)
-       #
-       #       both modified:      main.txt
-       #
-       no changes added to commit (use "git add" and/or "git commit -a")
-       EOF
+       TO_CHERRY_PICK=$(git rev-parse --short CHERRY_PICK_HEAD) &&
+       cat >expected <<EOF &&
+On branch cherry_branch
+You are currently cherry-picking commit $TO_CHERRY_PICK.
+  (fix conflicts and run "git cherry-pick --continue")
+  (use "git cherry-pick --abort" to cancel the cherry-pick operation)
+
+Unmerged paths:
+  (use "git add <file>..." to mark resolution)
+
+       both modified:      main.txt
+
+no changes added to commit (use "git add" and/or "git commit -a")
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -648,20 +649,21 @@ test_expect_success 'status when cherry-picking after resolving conflicts' '
        git reset --hard cherry_branch &&
        test_when_finished "git cherry-pick --abort" &&
        test_must_fail git cherry-pick cherry_branch_second &&
+       TO_CHERRY_PICK=$(git rev-parse --short CHERRY_PICK_HEAD) &&
        echo end >main.txt &&
        git add main.txt &&
-       cat >expected <<-\EOF &&
-       # On branch cherry_branch
-       # You are currently cherry-picking.
-       #   (all conflicts fixed: run "git cherry-pick --continue")
-       #   (use "git cherry-pick --abort" to cancel the cherry-pick operation)
-       #
-       # Changes to be committed:
-       #
-       #       modified:   main.txt
-       #
-       # Untracked files not listed (use -u option to show untracked files)
-       EOF
+       cat >expected <<EOF &&
+On branch cherry_branch
+You are currently cherry-picking commit $TO_CHERRY_PICK.
+  (all conflicts fixed: run "git cherry-pick --continue")
+  (use "git cherry-pick --abort" to cancel the cherry-pick operation)
+
+Changes to be committed:
+
+       modified:   main.txt
+
+Untracked files not listed (use -u option to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -669,18 +671,18 @@ test_expect_success 'status when cherry-picking after resolving conflicts' '
 test_expect_success 'status showing detached at and from a tag' '
        test_commit atag tagging &&
        git checkout atag &&
-       cat >expected <<-\EOF
-       # HEAD detached at atag
-       nothing to commit (use -u to show untracked files)
-       EOF
+       cat >expected <<\EOF &&
+HEAD detached at atag
+nothing to commit (use -u to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual &&
 
        git reset --hard HEAD^ &&
-       cat >expected <<-\EOF
-       # HEAD detached from atag
-       nothing to commit (use -u to show untracked files)
-       EOF
+       cat >expected <<\EOF &&
+HEAD detached from atag
+nothing to commit (use -u to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -695,20 +697,20 @@ test_expect_success 'status while reverting commit (conflicts)' '
        test_commit new to-revert.txt &&
        TO_REVERT=$(git rev-parse --short HEAD^) &&
        test_must_fail git revert $TO_REVERT &&
-       cat >expected <<-EOF
-       # On branch master
-       # You are currently reverting commit $TO_REVERT.
-       #   (fix conflicts and run "git revert --continue")
-       #   (use "git revert --abort" to cancel the revert operation)
-       #
-       # Unmerged paths:
-       #   (use "git reset HEAD <file>..." to unstage)
-       #   (use "git add <file>..." to mark resolution)
-       #
-       #       both modified:      to-revert.txt
-       #
-       no changes added to commit (use "git add" and/or "git commit -a")
-       EOF
+       cat >expected <<EOF &&
+On branch master
+You are currently reverting commit $TO_REVERT.
+  (fix conflicts and run "git revert --continue")
+  (use "git revert --abort" to cancel the revert operation)
+
+Unmerged paths:
+  (use "git reset HEAD <file>..." to unstage)
+  (use "git add <file>..." to mark resolution)
+
+       both modified:      to-revert.txt
+
+no changes added to commit (use "git add" and/or "git commit -a")
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
@@ -716,29 +718,29 @@ test_expect_success 'status while reverting commit (conflicts)' '
 test_expect_success 'status while reverting commit (conflicts resolved)' '
        echo reverted >to-revert.txt &&
        git add to-revert.txt &&
-       cat >expected <<-EOF
-       # On branch master
-       # You are currently reverting commit $TO_REVERT.
-       #   (all conflicts fixed: run "git revert --continue")
-       #   (use "git revert --abort" to cancel the revert operation)
-       #
-       # Changes to be committed:
-       #   (use "git reset HEAD <file>..." to unstage)
-       #
-       #       modified:   to-revert.txt
-       #
-       # Untracked files not listed (use -u option to show untracked files)
-       EOF
+       cat >expected <<EOF &&
+On branch master
+You are currently reverting commit $TO_REVERT.
+  (all conflicts fixed: run "git revert --continue")
+  (use "git revert --abort" to cancel the revert operation)
+
+Changes to be committed:
+  (use "git reset HEAD <file>..." to unstage)
+
+       modified:   to-revert.txt
+
+Untracked files not listed (use -u option to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
 
 test_expect_success 'status after reverting commit' '
        git revert --continue &&
-       cat >expected <<-\EOF
-       # On branch master
-       nothing to commit (use -u to show untracked files)
-       EOF
+       cat >expected <<\EOF &&
+On branch master
+nothing to commit (use -u to show untracked files)
+EOF
        git status --untracked-files=no >actual &&
        test_i18ncmp expected actual
 '
index b7ef9e25895550e8749952e2ed54d7827737242e..69e9c0db5d79c3c4c15db35970d61a91419c4fd7 100755 (executable)
@@ -52,4 +52,71 @@ test_expect_success 'clone to target directory with --stdlayout' '
        rm -rf target
        '
 
+test_expect_success 'init without -s/-T/-b/-t does not warn' '
+       test ! -d trunk &&
+       git svn init "$svnrepo"/project/trunk trunk 2>warning &&
+       test_must_fail grep -q prefix warning &&
+       rm -rf trunk &&
+       rm -f warning
+       '
+
+test_expect_success 'clone without -s/-T/-b/-t does not warn' '
+       test ! -d trunk &&
+       git svn clone "$svnrepo"/project/trunk 2>warning &&
+       test_must_fail grep -q prefix warning &&
+       rm -rf trunk &&
+       rm -f warning
+       '
+
+test_svn_configured_prefix () {
+       prefix=$1 &&
+       cat >expect <<EOF &&
+project/trunk:refs/remotes/${prefix}trunk
+project/branches/*:refs/remotes/${prefix}*
+project/tags/*:refs/remotes/${prefix}tags/*
+EOF
+       test ! -f actual &&
+       git --git-dir=project/.git config svn-remote.svn.fetch >>actual &&
+       git --git-dir=project/.git config svn-remote.svn.branches >>actual &&
+       git --git-dir=project/.git config svn-remote.svn.tags >>actual &&
+       test_cmp expect actual &&
+       rm -f expect actual
+}
+
+test_expect_success 'init with -s/-T/-b/-t without --prefix warns' '
+       test ! -d project &&
+       git svn init -s "$svnrepo"/project project 2>warning &&
+       grep -q prefix warning &&
+       test_svn_configured_prefix "" &&
+       rm -rf project &&
+       rm -f warning
+       '
+
+test_expect_success 'clone with -s/-T/-b/-t without --prefix warns' '
+       test ! -d project &&
+       git svn clone -s "$svnrepo"/project 2>warning &&
+       grep -q prefix warning &&
+       test_svn_configured_prefix "" &&
+       rm -rf project &&
+       rm -f warning
+       '
+
+test_expect_success 'init with -s/-T/-b/-t and --prefix does not warn' '
+       test ! -d project &&
+       git svn init -s "$svnrepo"/project project --prefix="" 2>warning &&
+       test_must_fail grep -q prefix warning &&
+       test_svn_configured_prefix "" &&
+       rm -rf project &&
+       rm -f warning
+       '
+
+test_expect_success 'clone with -s/-T/-b/-t and --prefix does not warn' '
+       test ! -d project &&
+       git svn clone -s "$svnrepo"/project --prefix="" 2>warning &&
+       test_must_fail grep -q prefix warning &&
+       test_svn_configured_prefix "" &&
+       rm -rf project &&
+       rm -f warning
+       '
+
 test_done
index 31a770d9bc58d7c01d69f7817fcbc06622859662..88fc407ed6aa96acd21eb249d10832fe3ff8723d 100755 (executable)
@@ -2864,14 +2864,14 @@ test_expect_success 'S: notemodify with garbage after sha1 dataref must fail' '
 '
 
 #
-# notemodify, mark in committish
+# notemodify, mark in commit-ish
 #
-test_expect_success 'S: notemodify with garbarge after mark committish must fail' '
+test_expect_success 'S: notemodify with garbarge after mark commit-ish must fail' '
        test_must_fail git fast-import --import-marks=marks <<-EOF 2>err &&
        commit refs/heads/Snotes
        committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
        data <<COMMIT
-       commit S note committish
+       commit S note commit-ish
        COMMIT
        N :202 :302x
        EOF
index 6fca19353d7308f88e63806f7187d9d379412d18..718014d5dead8f36b2dde6ce38de63316ec57fdb 100755 (executable)
@@ -683,9 +683,11 @@ test_expect_success \
 # syntax highlighting
 
 
-highlight --version >/dev/null 2>&1
+highlight_version=$(highlight --version </dev/null 2>/dev/null)
 if [ $? -eq 127 ]; then
-       say "Skipping syntax highlighting test, because 'highlight' was not found"
+       say "Skipping syntax highlighting tests: 'highlight' not found"
+elif test -z "$highlight_version"; then
+       say "Skipping syntax highlighting tests: incorrect 'highlight' found"
 else
        test_set_prereq HIGHLIGHT
        cat >>gitweb_config.perl <<-\EOF
index 1aa27bdbbf39bd937a6bb66a7eafeda16bb76246..0fa7dfde7bbf201d4756202f3797854b54030ea8 100644 (file)
@@ -700,15 +700,6 @@ test -d "$GIT_BUILD_DIR"/templates/blt || {
        error "You haven't built things yet, have you?"
 }
 
-if test -z "$GIT_TEST_INSTALLED" && test -z "$NO_PYTHON"
-then
-       GITPYTHONLIB="$GIT_BUILD_DIR/git_remote_helpers/build/lib"
-       export GITPYTHONLIB
-       test -d "$GIT_BUILD_DIR"/git_remote_helpers/build || {
-               error "You haven't built git_remote_helpers yet, have you?"
-       }
-fi
-
 if ! test -x "$GIT_BUILD_DIR"/test-chmtime
 then
        echo >&2 'You need to build test-chmtime:'
index 586e3bf94da1a2d69a061fe98aa1604f9223280b..68d62d5446d963dc69006ad9a83907c6690f92c1 100755 (executable)
@@ -16,7 +16,7 @@ else
 fi
 
 # If you want to allow non-ASCII filenames set this variable to true.
-allownonascii=$(git config hooks.allownonascii)
+allownonascii=$(git config --bool hooks.allownonascii)
 
 # Redirect output to stderr.
 exec 1>&2
index a3c4688778d9db28c83c9149c9cff1609b69b93f..2ef725e5ff94c4db59fdc4b389ee2399854cb83b 100644 (file)
@@ -12,10 +12,10 @@ int main(int ac, char **av)
                die("cannot parse %s as an object name", av[2]);
        one = parse_tree_indirect(hash1);
        if (!one)
-               die("not a treeish %s", av[1]);
+               die("not a tree-ish %s", av[1]);
        two = parse_tree_indirect(hash2);
        if (!two)
-               die("not a treeish %s", av[2]);
+               die("not a tree-ish %s", av[2]);
 
        shift_tree(one->object.sha1, two->object.sha1, shifted, -1);
        printf("shifted: %s\n", sha1_to_hex(shifted));
index bb975e4d3eaf54bb162ecdad8b4b8995c84fb035..3dd3744a57cffd2a98be5cd551cda475c746e646 100644 (file)
@@ -116,7 +116,7 @@ int main(int argc, char **argv)
                return 0;
        }
 
-       if (argc == 3 && !strcmp(argv[1], "mingw_path")) {
+       if (argc == 3 && !strcmp(argv[1], "print_path")) {
                puts(argv[2]);
                return 0;
        }
index 80daba980ecd85852ee3a23c155602e4cd1ba07a..e57eae10bf73baac79fd8b95ddb0ff1b4c8c0cd6 100644 (file)
@@ -5,10 +5,15 @@ int main(int ac, char **av)
        git_SHA_CTX ctx;
        unsigned char sha1[20];
        unsigned bufsz = 8192;
+       int binary = 0;
        char *buffer;
 
-       if (ac == 2)
-               bufsz = strtoul(av[1], NULL, 10) * 1024 * 1024;
+       if (ac == 2) {
+               if (!strcmp(av[1], "-b"))
+                       binary = 1;
+               else
+                       bufsz = strtoul(av[1], NULL, 10) * 1024 * 1024;
+       }
 
        if (!bufsz)
                bufsz = 8192;
@@ -42,6 +47,10 @@ int main(int ac, char **av)
                git_SHA1_Update(&ctx, buffer, this_sz);
        }
        git_SHA1_Final(sha1, &ctx);
-       puts(sha1_to_hex(sha1));
+
+       if (binary)
+               fwrite(sha1, 1, 20, stdout);
+       else
+               puts(sha1_to_hex(sha1));
        exit(0);
 }
index 4c2a39e8ff03df5285657a5c0f9b7746c28d76a6..b32e2d64dd344c3f8c4d5f42b6c48dd6bdb8d29f 100644 (file)
@@ -28,7 +28,8 @@ struct helper_data {
                connect : 1,
                signed_tags : 1,
                check_connectivity : 1,
-               no_disconnect_req : 1;
+               no_disconnect_req : 1,
+               no_private_update : 1;
        char *export_marks;
        char *import_marks;
        /* These go from remote name (as in "list") to private name */
@@ -208,6 +209,8 @@ static struct child_process *get_helper(struct transport *transport)
                        strbuf_addstr(&arg, "--import-marks=");
                        strbuf_addstr(&arg, capname + strlen("import-marks "));
                        data->import_marks = strbuf_detach(&arg, NULL);
+               } else if (!prefixcmp(capname, "no-private-update")) {
+                       data->no_private_update = 1;
                } else if (mandatory) {
                        die("Unknown mandatory capability %s. This remote "
                            "helper probably needs newer version of Git.",
@@ -738,7 +741,7 @@ static void push_update_refs_status(struct helper_data *data,
                if (push_update_ref_status(&buf, &ref, remote_refs))
                        continue;
 
-               if (!data->refspecs)
+               if (!data->refspecs || data->no_private_update)
                        continue;
 
                /* propagate back the update to the remote namespace */
diff --git a/tree.c b/tree.c
index 549e5883a01bb31010861aad991993772d238309..c8c49d7b78174199da94d802e1ca7037866b5f04 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -225,6 +225,14 @@ int parse_tree(struct tree *item)
        return parse_tree_buffer(item, buffer, size);
 }
 
+void free_tree_buffer(struct tree *tree)
+{
+       free(tree->buffer);
+       tree->buffer = NULL;
+       tree->size = 0;
+       tree->object.parsed = 0;
+}
+
 struct tree *parse_tree_indirect(const unsigned char *sha1)
 {
        struct object *obj = parse_object(sha1);
diff --git a/tree.h b/tree.h
index 9dc90bac38dff0970840e507af980092af78d31d..d84ac63e511c30ae4e1c8ee2b9719d67fd9424da 100644 (file)
--- a/tree.h
+++ b/tree.h
@@ -16,6 +16,7 @@ struct tree *lookup_tree(const unsigned char *sha1);
 int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size);
 
 int parse_tree(struct tree *tree);
+void free_tree_buffer(struct tree *tree);
 
 /* Parses and returns the tree in the given ent, chasing tags and commits. */
 struct tree *parse_tree_indirect(const unsigned char *sha1);
index b03492e664daa53f09d13787494c925af702d949..a6c54e06bb4c4725ace576740912cbb6133e291e 100644 (file)
@@ -41,6 +41,7 @@ static struct object_array have_obj;
 static struct object_array want_obj;
 static struct object_array extra_edge_obj;
 static unsigned int timeout;
+static int keepalive = 5;
 /* 0 for no sideband,
  * otherwise maximum packet size (up to 65520 bytes).
  */
@@ -69,87 +70,28 @@ static ssize_t send_client_data(int fd, const char *data, ssize_t sz)
        return sz;
 }
 
-static FILE *pack_pipe = NULL;
-static void show_commit(struct commit *commit, void *data)
-{
-       if (commit->object.flags & BOUNDARY)
-               fputc('-', pack_pipe);
-       if (fputs(sha1_to_hex(commit->object.sha1), pack_pipe) < 0)
-               die("broken output pipe");
-       fputc('\n', pack_pipe);
-       fflush(pack_pipe);
-       free(commit->buffer);
-       commit->buffer = NULL;
-}
-
-static void show_object(struct object *obj,
-                       const struct name_path *path, const char *component,
-                       void *cb_data)
-{
-       show_object_with_name(pack_pipe, obj, path, component);
-}
-
-static void show_edge(struct commit *commit)
-{
-       fprintf(pack_pipe, "-%s\n", sha1_to_hex(commit->object.sha1));
-}
-
-static int do_rev_list(int in, int out, void *user_data)
-{
-       int i;
-       struct rev_info revs;
-
-       pack_pipe = xfdopen(out, "w");
-       init_revisions(&revs, NULL);
-       revs.tag_objects = 1;
-       revs.tree_objects = 1;
-       revs.blob_objects = 1;
-       if (use_thin_pack)
-               revs.edge_hint = 1;
-
-       for (i = 0; i < want_obj.nr; i++) {
-               struct object *o = want_obj.objects[i].item;
-               /* why??? */
-               o->flags &= ~UNINTERESTING;
-               add_pending_object(&revs, o, NULL);
-       }
-       for (i = 0; i < have_obj.nr; i++) {
-               struct object *o = have_obj.objects[i].item;
-               o->flags |= UNINTERESTING;
-               add_pending_object(&revs, o, NULL);
-       }
-       setup_revisions(0, NULL, &revs, NULL);
-       if (prepare_revision_walk(&revs))
-               die("revision walk setup failed");
-       mark_edges_uninteresting(revs.commits, &revs, show_edge);
-       if (use_thin_pack)
-               for (i = 0; i < extra_edge_obj.nr; i++)
-                       fprintf(pack_pipe, "-%s\n", sha1_to_hex(
-                                       extra_edge_obj.objects[i].item->sha1));
-       traverse_commit_list(&revs, show_commit, show_object, NULL);
-       fflush(pack_pipe);
-       fclose(pack_pipe);
-       return 0;
-}
-
 static void create_pack_file(void)
 {
-       struct async rev_list;
        struct child_process pack_objects;
        char data[8193], progress[128];
        char abort_msg[] = "aborting due to possible repository "
                "corruption on the remote side.";
        int buffered = -1;
        ssize_t sz;
-       const char *argv[10];
-       int arg = 0;
+       const char *argv[12];
+       int i, arg = 0;
+       FILE *pipe_fd;
+       char *shallow_file = NULL;
 
-       argv[arg++] = "pack-objects";
-       if (!shallow_nr) {
-               argv[arg++] = "--revs";
-               if (use_thin_pack)
-                       argv[arg++] = "--thin";
+       if (shallow_nr) {
+               shallow_file = setup_temporary_shallow();
+               argv[arg++] = "--shallow-file";
+               argv[arg++] = shallow_file;
        }
+       argv[arg++] = "pack-objects";
+       argv[arg++] = "--revs";
+       if (use_thin_pack)
+               argv[arg++] = "--thin";
 
        argv[arg++] = "--stdout";
        if (!no_progress)
@@ -170,29 +112,21 @@ static void create_pack_file(void)
        if (start_command(&pack_objects))
                die("git upload-pack: unable to fork git-pack-objects");
 
-       if (shallow_nr) {
-               memset(&rev_list, 0, sizeof(rev_list));
-               rev_list.proc = do_rev_list;
-               rev_list.out = pack_objects.in;
-               if (start_async(&rev_list))
-                       die("git upload-pack: unable to fork git-rev-list");
-       }
-       else {
-               FILE *pipe_fd = xfdopen(pack_objects.in, "w");
-               int i;
-
-               for (i = 0; i < want_obj.nr; i++)
-                       fprintf(pipe_fd, "%s\n",
-                               sha1_to_hex(want_obj.objects[i].item->sha1));
-               fprintf(pipe_fd, "--not\n");
-               for (i = 0; i < have_obj.nr; i++)
-                       fprintf(pipe_fd, "%s\n",
-                               sha1_to_hex(have_obj.objects[i].item->sha1));
-               fprintf(pipe_fd, "\n");
-               fflush(pipe_fd);
-               fclose(pipe_fd);
-       }
-
+       pipe_fd = xfdopen(pack_objects.in, "w");
+
+       for (i = 0; i < want_obj.nr; i++)
+               fprintf(pipe_fd, "%s\n",
+                       sha1_to_hex(want_obj.objects[i].item->sha1));
+       fprintf(pipe_fd, "--not\n");
+       for (i = 0; i < have_obj.nr; i++)
+               fprintf(pipe_fd, "%s\n",
+                       sha1_to_hex(have_obj.objects[i].item->sha1));
+       for (i = 0; i < extra_edge_obj.nr; i++)
+               fprintf(pipe_fd, "%s\n",
+                       sha1_to_hex(extra_edge_obj.objects[i].item->sha1));
+       fprintf(pipe_fd, "\n");
+       fflush(pipe_fd);
+       fclose(pipe_fd);
 
        /* We read from pack_objects.err to capture stderr output for
         * progress bar, and pack_objects.out to capture the pack data.
@@ -201,6 +135,7 @@ static void create_pack_file(void)
        while (1) {
                struct pollfd pfd[2];
                int pe, pu, pollsize;
+               int ret;
 
                reset_timeout();
 
@@ -223,7 +158,8 @@ static void create_pack_file(void)
                if (!pollsize)
                        break;
 
-               if (poll(pfd, pollsize, -1) < 0) {
+               ret = poll(pfd, pollsize, 1000 * keepalive);
+               if (ret < 0) {
                        if (errno != EINTR) {
                                error("poll failed, resuming: %s",
                                      strerror(errno));
@@ -285,14 +221,32 @@ static void create_pack_file(void)
                        if (sz < 0)
                                goto fail;
                }
+
+               /*
+                * We hit the keepalive timeout without saying anything; send
+                * an empty message on the data sideband just to let the other
+                * side know we're still working on it, but don't have any data
+                * yet.
+                *
+                * If we don't have a sideband channel, there's no room in the
+                * protocol to say anything, so those clients are just out of
+                * luck.
+                */
+               if (!ret && use_sideband) {
+                       static const char buf[] = "0005\1";
+                       write_or_die(1, buf, 5);
+               }
        }
 
        if (finish_command(&pack_objects)) {
                error("git upload-pack: git-pack-objects died with error.");
                goto fail;
        }
-       if (shallow_nr && finish_async(&rev_list))
-               goto fail;      /* error was already reported */
+       if (shallow_file) {
+               if (*shallow_file)
+                       unlink(shallow_file);
+               free(shallow_file);
+       }
 
        /* flush the data */
        if (0 <= buffered) {
@@ -786,6 +740,11 @@ static int upload_pack_config(const char *var, const char *value, void *unused)
 {
        if (!strcmp("uploadpack.allowtipsha1inwant", var))
                allow_tip_sha1_in_want = git_config_bool(var, value);
+       else if (!strcmp("uploadpack.keepalive", var)) {
+               keepalive = git_config_int(var, value);
+               if (!keepalive)
+                       keepalive = -1;
+       }
        return parse_hide_refs_config(var, value, "uploadpack");
 }
 
index 1db76c89bc2183855da5d6e3bc54f4fdef471462..ec87cba75099ebe05e936430ca3b688275e01a4a 100644 (file)
@@ -281,9 +281,11 @@ char *url_normalize(const char *url, struct url_info *out_info)
                url_len--;
        }
        for (;;) {
-               const char *seg_start = norm.buf + norm.len;
+               const char *seg_start;
+               size_t seg_start_off = norm.len;
                const char *next_slash = url + strcspn(url, "/?#");
                int skip_add_slash = 0;
+
                /*
                 * RFC 3689 indicates that any . or .. segments should be
                 * unescaped before being checked for.
@@ -297,6 +299,8 @@ char *url_normalize(const char *url, struct url_info *out_info)
                        strbuf_release(&norm);
                        return NULL;
                }
+
+               seg_start = norm.buf + seg_start_off;
                if (!strcmp(seg_start, ".")) {
                        /* ignore a . segment; be careful not to remove initial '/' */
                        if (seg_start == path_start + 1) {
index be389dc9bf5161c31be29e3a72264fd6120a0bbc..633596e06fcaa1154980f95c858c61379c968d49 100644 (file)
--- a/walker.c
+++ b/walker.c
@@ -56,10 +56,7 @@ static int process_tree(struct walker *walker, struct tree *tree)
                if (!obj || process(walker, obj))
                        return -1;
        }
-       free(tree->buffer);
-       tree->buffer = NULL;
-       tree->size = 0;
-       tree->object.parsed = 0;
+       free_tree_buffer(tree);
        return 0;
 }
 
index f92b14759833b1ae77070b4188d8ad8ea8d3799e..9a6aaafaf35bbd6d2a7a97589edfd9b0b12102c7 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -360,10 +360,12 @@ int git_mkstemp_mode(char *pattern, int mode)
        return git_mkstemps_mode(pattern, 0, mode);
 }
 
+#ifdef NO_MKSTEMPS
 int gitmkstemps(char *pattern, int suffix_len)
 {
        return git_mkstemps_mode(pattern, suffix_len, 0600);
 }
+#endif
 
 int xmkstemp_mode(char *template, int mode)
 {
index ff4b32426a36db38fba9e4cc51e09a988efe34a6..b4e44baa2917dfcf33824c3d6fc08756886b9ae1 100644 (file)
@@ -9,6 +9,7 @@
 #include "diffcore.h"
 #include "quote.h"
 #include "run-command.h"
+#include "argv-array.h"
 #include "remote.h"
 #include "refs.h"
 #include "submodule.h"
@@ -46,9 +47,11 @@ static void status_vprintf(struct wt_status *s, int at_bol, const char *color,
 
        strbuf_vaddf(&sb, fmt, ap);
        if (!sb.len) {
-               strbuf_addch(&sb, comment_line_char);
-               if (!trail)
-                       strbuf_addch(&sb, ' ');
+               if (s->display_comment_prefix) {
+                       strbuf_addch(&sb, comment_line_char);
+                       if (!trail)
+                               strbuf_addch(&sb, ' ');
+               }
                color_print_strbuf(s->fp, color, &sb);
                if (trail)
                        fprintf(s->fp, "%s", trail);
@@ -59,7 +62,7 @@ static void status_vprintf(struct wt_status *s, int at_bol, const char *color,
                eol = strchr(line, '\n');
 
                strbuf_reset(&linebuf);
-               if (at_bol) {
+               if (at_bol && s->display_comment_prefix) {
                        strbuf_addch(&linebuf, comment_line_char);
                        if (*line != '\n' && *line != '\t')
                                strbuf_addch(&linebuf, ' ');
@@ -129,6 +132,7 @@ void wt_status_prepare(struct wt_status *s)
        s->untracked.strdup_strings = 1;
        s->ignored.strdup_strings = 1;
        s->show_branch = -1;  /* unspecified */
+       s->display_comment_prefix = 0;
 }
 
 static void wt_status_print_unmerged_header(struct wt_status *s)
@@ -161,7 +165,7 @@ static void wt_status_print_unmerged_header(struct wt_status *s)
                }
        }
 
-       if (!advice_status_hints)
+       if (!s->hints)
                return;
        if (s->whence != FROM_COMMIT)
                ;
@@ -188,7 +192,7 @@ static void wt_status_print_cached_header(struct wt_status *s)
        const char *c = color(WT_STATUS_HEADER, s);
 
        status_printf_ln(s, c, _("Changes to be committed:"));
-       if (!advice_status_hints)
+       if (!s->hints)
                return;
        if (s->whence != FROM_COMMIT)
                ; /* NEEDSWORK: use "git reset --unresolve"??? */
@@ -206,7 +210,7 @@ static void wt_status_print_dirty_header(struct wt_status *s,
        const char *c = color(WT_STATUS_HEADER, s);
 
        status_printf_ln(s, c, _("Changes not staged for commit:"));
-       if (!advice_status_hints)
+       if (!s->hints)
                return;
        if (!has_deleted)
                status_printf_ln(s, c, _("  (use \"git add <file>...\" to update what will be committed)"));
@@ -224,7 +228,7 @@ static void wt_status_print_other_header(struct wt_status *s,
 {
        const char *c = color(WT_STATUS_HEADER, s);
        status_printf_ln(s, c, "%s:", what);
-       if (!advice_status_hints)
+       if (!s->hints)
                return;
        status_printf_ln(s, c, _("  (use \"git %s <file>...\" to include in what will be committed)"), how);
        status_printf_ln(s, c, "");
@@ -661,29 +665,57 @@ static void wt_status_print_submodule_summary(struct wt_status *s, int uncommitt
        char summary_limit[64];
        char index[PATH_MAX];
        const char *env[] = { NULL, NULL };
-       const char *argv[8];
-
-       env[0] =        index;
-       argv[0] =       "submodule";
-       argv[1] =       "summary";
-       argv[2] =       uncommitted ? "--files" : "--cached";
-       argv[3] =       "--for-status";
-       argv[4] =       "--summary-limit";
-       argv[5] =       summary_limit;
-       argv[6] =       uncommitted ? NULL : (s->amend ? "HEAD^" : "HEAD");
-       argv[7] =       NULL;
+       struct argv_array argv = ARGV_ARRAY_INIT;
+       struct strbuf cmd_stdout = STRBUF_INIT;
+       struct strbuf summary = STRBUF_INIT;
+       char *summary_content;
+       size_t len;
 
        sprintf(summary_limit, "%d", s->submodule_summary);
        snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", s->index_file);
 
+       env[0] = index;
+       argv_array_push(&argv, "submodule");
+       argv_array_push(&argv, "summary");
+       argv_array_push(&argv, uncommitted ? "--files" : "--cached");
+       argv_array_push(&argv, "--for-status");
+       argv_array_push(&argv, "--summary-limit");
+       argv_array_push(&argv, summary_limit);
+       if (!uncommitted)
+               argv_array_push(&argv, s->amend ? "HEAD^" : "HEAD");
+
        memset(&sm_summary, 0, sizeof(sm_summary));
-       sm_summary.argv = argv;
+       sm_summary.argv = argv.argv;
        sm_summary.env = env;
        sm_summary.git_cmd = 1;
        sm_summary.no_stdin = 1;
        fflush(s->fp);
-       sm_summary.out = dup(fileno(s->fp));    /* run_command closes it */
+       sm_summary.out = -1;
+
        run_command(&sm_summary);
+       argv_array_clear(&argv);
+
+       len = strbuf_read(&cmd_stdout, sm_summary.out, 1024);
+
+       /* prepend header, only if there's an actual output */
+       if (len) {
+               if (uncommitted)
+                       strbuf_addstr(&summary, _("Submodules changed but not updated:"));
+               else
+                       strbuf_addstr(&summary, _("Submodule changes to be committed:"));
+               strbuf_addstr(&summary, "\n\n");
+       }
+       strbuf_addbuf(&summary, &cmd_stdout);
+       strbuf_release(&cmd_stdout);
+
+       if (s->display_comment_prefix) {
+               summary_content = strbuf_detach(&summary, &len);
+               strbuf_add_commented_lines(&summary, summary_content, len);
+               free(summary_content);
+       }
+
+       fputs(summary.buf, s->fp);
+       strbuf_release(&summary);
 }
 
 static void wt_status_print_other(struct wt_status *s,
@@ -717,10 +749,11 @@ static void wt_status_print_other(struct wt_status *s,
 
        strbuf_release(&buf);
        if (!column_active(s->colopts))
-               return;
+               goto conclude;
 
-       strbuf_addf(&buf, "%s#\t%s",
+       strbuf_addf(&buf, "%s%s\t%s",
                    color(WT_STATUS_HEADER, s),
+                   s->display_comment_prefix ? "#" : "",
                    color(WT_STATUS_UNTRACKED, s));
        memset(&copts, 0, sizeof(copts));
        copts.padding = 1;
@@ -730,6 +763,8 @@ static void wt_status_print_other(struct wt_status *s,
        print_columns(&output, s->colopts, &copts);
        string_list_clear(&output, 0);
        strbuf_release(&buf);
+conclude:
+       status_printf_ln(s, GIT_COLOR_NORMAL, "");
 }
 
 static void wt_status_print_verbose(struct wt_status *s)
@@ -764,6 +799,8 @@ static void wt_status_print_tracking(struct wt_status *s)
        struct strbuf sb = STRBUF_INIT;
        const char *cp, *ep;
        struct branch *branch;
+       char comment_line_string[3];
+       int i;
 
        assert(s->branch && !s->is_initial);
        if (prefixcmp(s->branch, "refs/heads/"))
@@ -772,12 +809,22 @@ static void wt_status_print_tracking(struct wt_status *s)
        if (!format_tracking_info(branch, &sb))
                return;
 
+       i = 0;
+       if (s->display_comment_prefix) {
+               comment_line_string[i++] = comment_line_char;
+               comment_line_string[i++] = ' ';
+       }
+       comment_line_string[i] = '\0';
+
        for (cp = sb.buf; (ep = strchr(cp, '\n')) != NULL; cp = ep + 1)
                color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s),
-                                "%c %.*s", comment_line_char,
+                                "%s%.*s", comment_line_string,
                                 (int)(ep - cp), cp);
-       color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "%c",
-                        comment_line_char);
+       if (s->display_comment_prefix)
+               color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "%c",
+                                comment_line_char);
+       else
+               fprintf_ln(s->fp, "");
 }
 
 static int has_unmerged(struct wt_status *s)
@@ -799,13 +846,13 @@ static void show_merge_in_progress(struct wt_status *s,
 {
        if (has_unmerged(s)) {
                status_printf_ln(s, color, _("You have unmerged paths."));
-               if (advice_status_hints)
+               if (s->hints)
                        status_printf_ln(s, color,
                                _("  (fix conflicts and run \"git commit\")"));
        } else {
                status_printf_ln(s, color,
                        _("All conflicts fixed but you are still merging."));
-               if (advice_status_hints)
+               if (s->hints)
                        status_printf_ln(s, color,
                                _("  (use \"git commit\" to conclude merge)"));
        }
@@ -821,7 +868,7 @@ static void show_am_in_progress(struct wt_status *s,
        if (state->am_empty_patch)
                status_printf_ln(s, color,
                        _("The current patch is empty."));
-       if (advice_status_hints) {
+       if (s->hints) {
                if (!state->am_empty_patch)
                        status_printf_ln(s, color,
                                _("  (fix conflicts and then run \"git am --continue\")"));
@@ -894,7 +941,7 @@ static void show_rebase_in_progress(struct wt_status *s,
                else
                        status_printf_ln(s, color,
                                         _("You are currently rebasing."));
-               if (advice_status_hints) {
+               if (s->hints) {
                        status_printf_ln(s, color,
                                _("  (fix conflicts and then run \"git rebase --continue\")"));
                        status_printf_ln(s, color,
@@ -911,7 +958,7 @@ static void show_rebase_in_progress(struct wt_status *s,
                else
                        status_printf_ln(s, color,
                                         _("You are currently rebasing."));
-               if (advice_status_hints)
+               if (s->hints)
                        status_printf_ln(s, color,
                                _("  (all conflicts fixed: run \"git rebase --continue\")"));
        } else if (split_commit_in_progress(s)) {
@@ -923,7 +970,7 @@ static void show_rebase_in_progress(struct wt_status *s,
                else
                        status_printf_ln(s, color,
                                         _("You are currently splitting a commit during a rebase."));
-               if (advice_status_hints)
+               if (s->hints)
                        status_printf_ln(s, color,
                                _("  (Once your working directory is clean, run \"git rebase --continue\")"));
        } else {
@@ -935,7 +982,7 @@ static void show_rebase_in_progress(struct wt_status *s,
                else
                        status_printf_ln(s, color,
                                         _("You are currently editing a commit during a rebase."));
-               if (advice_status_hints && !s->amend) {
+               if (s->hints && !s->amend) {
                        status_printf_ln(s, color,
                                _("  (use \"git commit --amend\" to amend the current commit)"));
                        status_printf_ln(s, color,
@@ -949,8 +996,9 @@ static void show_cherry_pick_in_progress(struct wt_status *s,
                                        struct wt_status_state *state,
                                        const char *color)
 {
-       status_printf_ln(s, color, _("You are currently cherry-picking."));
-       if (advice_status_hints) {
+       status_printf_ln(s, color, _("You are currently cherry-picking commit %s."),
+                       find_unique_abbrev(state->cherry_pick_head_sha1, DEFAULT_ABBREV));
+       if (s->hints) {
                if (has_unmerged(s))
                        status_printf_ln(s, color,
                                _("  (fix conflicts and run \"git cherry-pick --continue\")"));
@@ -969,7 +1017,7 @@ static void show_revert_in_progress(struct wt_status *s,
 {
        status_printf_ln(s, color, _("You are currently reverting commit %s."),
                         find_unique_abbrev(state->revert_head_sha1, DEFAULT_ABBREV));
-       if (advice_status_hints) {
+       if (s->hints) {
                if (has_unmerged(s))
                        status_printf_ln(s, color,
                                _("  (fix conflicts and run \"git revert --continue\")"));
@@ -993,7 +1041,7 @@ static void show_bisect_in_progress(struct wt_status *s,
        else
                status_printf_ln(s, color,
                                 _("You are currently bisecting."));
-       if (advice_status_hints)
+       if (s->hints)
                status_printf_ln(s, color,
                        _("  (use \"git bisect reset\" to get back to the original branch)"));
        wt_status_print_trailer(s);
@@ -1122,8 +1170,10 @@ void wt_status_get_state(struct wt_status_state *state,
                        state->rebase_in_progress = 1;
                state->branch = read_and_strip_branch("rebase-merge/head-name");
                state->onto = read_and_strip_branch("rebase-merge/onto");
-       } else if (!stat(git_path("CHERRY_PICK_HEAD"), &st)) {
+       } else if (!stat(git_path("CHERRY_PICK_HEAD"), &st) &&
+                       !get_sha1("CHERRY_PICK_HEAD", sha1)) {
                state->cherry_pick_in_progress = 1;
+               hashcpy(state->cherry_pick_head_sha1, sha1);
        }
        if (!stat(git_path("BISECT_LOG"), &st)) {
                state->bisect_in_progress = 1;
@@ -1231,7 +1281,7 @@ void wt_status_print(struct wt_status *s)
                }
        } else if (s->commitable)
                status_printf_ln(s, GIT_COLOR_NORMAL, _("Untracked files not listed%s"),
-                       advice_status_hints
+                       s->hints
                        ? _(" (use -u option to show untracked files)") : "");
 
        if (s->verbose)
@@ -1242,25 +1292,25 @@ void wt_status_print(struct wt_status *s)
                else if (s->nowarn)
                        ; /* nothing */
                else if (s->workdir_dirty) {
-                       if (advice_status_hints)
+                       if (s->hints)
                                printf(_("no changes added to commit "
                                         "(use \"git add\" and/or \"git commit -a\")\n"));
                        else
                                printf(_("no changes added to commit\n"));
                } else if (s->untracked.nr) {
-                       if (advice_status_hints)
+                       if (s->hints)
                                printf(_("nothing added to commit but untracked files "
                                         "present (use \"git add\" to track)\n"));
                        else
                                printf(_("nothing added to commit but untracked files present\n"));
                } else if (s->is_initial) {
-                       if (advice_status_hints)
+                       if (s->hints)
                                printf(_("nothing to commit (create/copy files "
                                         "and use \"git add\" to track)\n"));
                        else
                                printf(_("nothing to commit\n"));
                } else if (!s->show_untracked_files) {
-                       if (advice_status_hints)
+                       if (s->hints)
                                printf(_("nothing to commit (use -u to show untracked files)\n"));
                        else
                                printf(_("nothing to commit\n"));
@@ -1363,6 +1413,7 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
        const char *base;
        const char *branch_name;
        int num_ours, num_theirs;
+       int upstream_is_gone = 0;
 
        color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "## ");
 
@@ -1380,20 +1431,37 @@ static void wt_shortstatus_print_tracking(struct wt_status *s)
        branch = branch_get(s->branch + 11);
        if (s->is_initial)
                color_fprintf(s->fp, header_color, _("Initial commit on "));
-       if (!stat_tracking_info(branch, &num_ours, &num_theirs)) {
-               color_fprintf(s->fp, branch_color_local, "%s", branch_name);
+
+       color_fprintf(s->fp, branch_color_local, "%s", branch_name);
+
+       switch (stat_tracking_info(branch, &num_ours, &num_theirs)) {
+       case 0:
+               /* no base */
                fputc(s->null_termination ? '\0' : '\n', s->fp);
                return;
+       case -1:
+               /* with "gone" base */
+               upstream_is_gone = 1;
+               break;
+       default:
+               /* with base */
+               break;
        }
 
        base = branch->merge[0]->dst;
        base = shorten_unambiguous_ref(base, 0);
-       color_fprintf(s->fp, branch_color_local, "%s", branch_name);
        color_fprintf(s->fp, header_color, "...");
        color_fprintf(s->fp, branch_color_remote, "%s", base);
 
+       if (!upstream_is_gone && !num_ours && !num_theirs) {
+               fputc(s->null_termination ? '\0' : '\n', s->fp);
+               return;
+       }
+
        color_fprintf(s->fp, header_color, " [");
-       if (!num_ours) {
+       if (upstream_is_gone) {
+               color_fprintf(s->fp, header_color, _("gone"));
+       } else if (!num_ours) {
                color_fprintf(s->fp, header_color, _("behind "));
                color_fprintf(s->fp, branch_color_remote, "%d", num_theirs);
        } else if (!num_theirs) {
index 9966c13deb678857d5fdb0c3648865fa7189686b..6c29e6f5e57f84eb7acdc3cf1ee621cc717fd5a9 100644 (file)
@@ -50,6 +50,7 @@ struct wt_status {
        enum commit_whence whence;
        int nowarn;
        int use_color;
+       int display_comment_prefix;
        int relative_paths;
        int submodule_summary;
        int show_ignored_files;
@@ -59,6 +60,7 @@ struct wt_status {
        unsigned colopts;
        int null_termination;
        int show_branch;
+       int hints;
 
        /* These are computed during processing of the individual sections */
        int commitable;
@@ -86,6 +88,7 @@ struct wt_status_state {
        char *detached_from;
        unsigned char detached_sha1[20];
        unsigned char revert_head_sha1[20];
+       unsigned char cherry_pick_head_sha1[20];
 };
 
 void wt_status_prepare(struct wt_status *s);