]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'lt/default-abbrev'
authorJunio C Hamano <gitster@pobox.com>
Wed, 23 Mar 2011 21:55:40 +0000 (14:55 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 23 Mar 2011 21:55:40 +0000 (14:55 -0700)
* lt/default-abbrev:
  Rename core.abbrevlength back to core.abbrev
  Make the default abbrev length configurable

444 files changed:
.gitignore
Documentation/CodingGuidelines
Documentation/RelNotes/1.7.4.1.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.4.2.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.5.txt [new file with mode: 0644]
Documentation/SubmittingPatches
Documentation/config.txt
Documentation/diff-generate-patch.txt
Documentation/fetch-options.txt
Documentation/git-add.txt
Documentation/git-am.txt
Documentation/git-annotate.txt
Documentation/git-apply.txt
Documentation/git-archimport.txt
Documentation/git-archive.txt
Documentation/git-bisect.txt
Documentation/git-blame.txt
Documentation/git-branch.txt
Documentation/git-bundle.txt
Documentation/git-cat-file.txt
Documentation/git-check-attr.txt
Documentation/git-checkout-index.txt
Documentation/git-checkout.txt
Documentation/git-cherry-pick.txt
Documentation/git-cherry.txt
Documentation/git-citool.txt
Documentation/git-clean.txt
Documentation/git-clone.txt
Documentation/git-commit-tree.txt
Documentation/git-commit.txt
Documentation/git-config.txt
Documentation/git-count-objects.txt
Documentation/git-cvsexportcommit.txt
Documentation/git-cvsimport.txt
Documentation/git-cvsserver.txt
Documentation/git-daemon.txt
Documentation/git-describe.txt
Documentation/git-diff-files.txt
Documentation/git-diff-index.txt
Documentation/git-diff-tree.txt
Documentation/git-diff.txt
Documentation/git-difftool.txt
Documentation/git-fast-export.txt
Documentation/git-fast-import.txt
Documentation/git-fetch-pack.txt
Documentation/git-fetch.txt
Documentation/git-filter-branch.txt
Documentation/git-fmt-merge-msg.txt
Documentation/git-for-each-ref.txt
Documentation/git-format-patch.txt
Documentation/git-fsck-objects.txt
Documentation/git-fsck.txt
Documentation/git-gc.txt
Documentation/git-get-tar-commit-id.txt
Documentation/git-grep.txt
Documentation/git-gui.txt
Documentation/git-hash-object.txt
Documentation/git-help.txt
Documentation/git-http-fetch.txt
Documentation/git-http-push.txt
Documentation/git-imap-send.txt
Documentation/git-index-pack.txt
Documentation/git-init-db.txt
Documentation/git-init.txt
Documentation/git-instaweb.txt
Documentation/git-log.txt
Documentation/git-lost-found.txt
Documentation/git-ls-files.txt
Documentation/git-ls-remote.txt
Documentation/git-ls-tree.txt
Documentation/git-mailinfo.txt
Documentation/git-mailsplit.txt
Documentation/git-merge-base.txt
Documentation/git-merge-file.txt
Documentation/git-merge-index.txt
Documentation/git-merge-one-file.txt
Documentation/git-merge-tree.txt
Documentation/git-merge.txt
Documentation/git-mergetool--lib.txt
Documentation/git-mergetool.txt
Documentation/git-mktag.txt
Documentation/git-mktree.txt
Documentation/git-mv.txt
Documentation/git-name-rev.txt
Documentation/git-pack-objects.txt
Documentation/git-pack-redundant.txt
Documentation/git-pack-refs.txt
Documentation/git-parse-remote.txt
Documentation/git-patch-id.txt
Documentation/git-peek-remote.txt
Documentation/git-prune-packed.txt
Documentation/git-prune.txt
Documentation/git-pull.txt
Documentation/git-push.txt
Documentation/git-quiltimport.txt
Documentation/git-read-tree.txt
Documentation/git-rebase.txt
Documentation/git-receive-pack.txt
Documentation/git-reflog.txt
Documentation/git-relink.txt
Documentation/git-remote-ext.txt
Documentation/git-remote-helpers.txt
Documentation/git-remote.txt
Documentation/git-repack.txt
Documentation/git-replace.txt
Documentation/git-repo-config.txt
Documentation/git-request-pull.txt
Documentation/git-rerere.txt
Documentation/git-reset.txt
Documentation/git-rev-list.txt
Documentation/git-rev-parse.txt
Documentation/git-revert.txt
Documentation/git-rm.txt
Documentation/git-send-email.txt
Documentation/git-send-pack.txt
Documentation/git-sh-setup.txt
Documentation/git-shell.txt
Documentation/git-shortlog.txt
Documentation/git-show-branch.txt
Documentation/git-show-index.txt
Documentation/git-show-ref.txt
Documentation/git-show.txt
Documentation/git-stage.txt
Documentation/git-stash.txt
Documentation/git-status.txt
Documentation/git-stripspace.txt
Documentation/git-submodule.txt
Documentation/git-svn.txt
Documentation/git-symbolic-ref.txt
Documentation/git-tag.txt
Documentation/git-tar-tree.txt
Documentation/git-unpack-file.txt
Documentation/git-unpack-objects.txt
Documentation/git-update-index.txt
Documentation/git-update-ref.txt
Documentation/git-update-server-info.txt
Documentation/git-upload-archive.txt
Documentation/git-upload-pack.txt
Documentation/git-var.txt
Documentation/git-verify-pack.txt
Documentation/git-verify-tag.txt
Documentation/git-web--browse.txt
Documentation/git-whatchanged.txt
Documentation/git-write-tree.txt
Documentation/git.txt
Documentation/gitattributes.txt
Documentation/gitcli.txt
Documentation/gitignore.txt
Documentation/gitk.txt
Documentation/gitmodules.txt
Documentation/glossary-content.txt
Documentation/howto/using-merge-subtree.txt
Documentation/merge-config.txt
Documentation/merge-options.txt
Documentation/rev-list-options.txt
Documentation/revisions.txt
Makefile
RelNotes
abspath.c
aclocal.m4
attr.c
branch.c
builtin.h
builtin/add.c
builtin/apply.c
builtin/blame.c
builtin/branch.c
builtin/checkout.c
builtin/clone.c
builtin/commit.c
builtin/config.c
builtin/describe.c
builtin/diff-files.c
builtin/diff.c
builtin/fast-export.c
builtin/fetch-pack.c
builtin/fetch.c
builtin/fmt-merge-msg.c
builtin/fsck.c
builtin/grep.c
builtin/hash-object.c
builtin/index-pack.c
builtin/init-db.c
builtin/log.c
builtin/ls-remote.c
builtin/merge-index.c
builtin/merge-recursive.c
builtin/merge-tree.c
builtin/merge.c
builtin/mktag.c
builtin/notes.c
builtin/pack-redundant.c
builtin/pack-refs.c
builtin/patch-id.c
builtin/push.c
builtin/read-tree.c
builtin/receive-pack.c
builtin/remote-ext.c
builtin/remote-fd.c
builtin/remote.c
builtin/rerere.c
builtin/reset.c
builtin/rev-list.c
builtin/revert.c
builtin/send-pack.c
builtin/tag.c
builtin/unpack-file.c
builtin/update-index.c
builtin/var.c
bundle.c
cache.h
color.c
color.h
commit.c
commit.h
compat/bswap.h
compat/mingw.c
compat/mingw.h
compat/msvc.h
config.c
configure.ac
contrib/completion/git-completion.bash
contrib/examples/git-revert.sh
contrib/fast-import/git-p4
contrib/fast-import/git-p4.txt
contrib/hooks/post-receive-email
contrib/svn-fe/svn-fe.c
contrib/svn-fe/svn-fe.txt
convert.c
daemon.c
diff-lib.c
diff-no-index.c
diff.c
diff.h
diffcore-rename.c
dir.c
dir.h
environment.c
exec_cmd.c
fast-import.c
fetch-pack.h
fsck.c
generate-cmdlist.sh
gettext.c [new file with mode: 0644]
gettext.h [new file with mode: 0644]
git-bisect.sh
git-compat-util.h
git-cvsimport.perl
git-instaweb.sh
git-mergetool--lib.sh
git-mergetool.sh
git-parse-remote.sh
git-pull.sh
git-request-pull.sh
git-stash.sh
git-submodule.sh
git-svn.perl
git.c
gitweb/INSTALL
gitweb/gitweb.perl
graph.c
hash.c
hash.h
http-push.c
http-walker.c
http.h
imap-send.c
list-objects.c
lockfile.c
log-tree.c
merge-recursive.c
merge-recursive.h
notes-merge.c
object.h
pack-check.c
parse-options.c
parse-options.h
patch-delta.c
path.c
perl/Git.pm
pkt-line.c
po/.gitignore [new file with mode: 0644]
preload-index.c
pretty.c
quote.h
read-cache.c
remote-curl.c
replace_object.c
rerere.c
rerere.h
revision.c
revision.h
run-command.c
setup.c
sha1_file.c
sha1_name.c
strbuf.c
strbuf.h
string-list.c
string-list.h
submodule.c
symlinks.c
t/README
t/gitweb-lib.sh
t/lib-terminal.sh
t/t0000-basic.sh
t/t0001-init.sh
t/t0040-parse-options.sh
t/t0070-fundamental.sh
t/t0080-vcs-svn.sh
t/t0081-line-buffer.sh [new file with mode: 0755]
t/t1007-hash-object.sh
t/t1300-repo-config.sh
t/t1510-repo-setup.sh
t/t2019-checkout-ambiguous-ref.sh [new file with mode: 0755]
t/t2020-checkout-detach.sh [new file with mode: 0755]
t/t2021-checkout-overwrite.sh [new file with mode: 0755]
t/t3032-merge-recursive-options.sh
t/t3200-branch.sh
t/t3507-cherry-pick-conflict.sh
t/t3509-cherry-pick-merge-df.sh
t/t3903-stash.sh
t/t4003-diff-rename-1.sh
t/t4004-diff-rename-symlink.sh
t/t4005-diff-rename-2.sh
t/t4008-diff-break-rewrite.sh
t/t4009-diff-rename-4.sh
t/t4010-diff-pathspec.sh
t/t4013-diff-various.sh
t/t4013/diff.diff_--cached [new file with mode: 0644]
t/t4013/diff.diff_--cached_--_file0 [new file with mode: 0644]
t/t4013/diff.log_-SF_master_--max-count=0 [new file with mode: 0644]
t/t4013/diff.log_-SF_master_--max-count=1 [new file with mode: 0644]
t/t4013/diff.log_-SF_master_--max-count=2 [new file with mode: 0644]
t/t4014-format-patch.sh
t/t4031-diff-rewrite-binary.sh
t/t4034-diff-words.sh
t/t4034/bibtex/expect [new file with mode: 0644]
t/t4034/bibtex/post [new file with mode: 0644]
t/t4034/bibtex/pre [new file with mode: 0644]
t/t4034/cpp/expect [new file with mode: 0644]
t/t4034/cpp/post [new file with mode: 0644]
t/t4034/cpp/pre [new file with mode: 0644]
t/t4034/csharp/expect [new file with mode: 0644]
t/t4034/csharp/post [new file with mode: 0644]
t/t4034/csharp/pre [new file with mode: 0644]
t/t4034/fortran/expect [new file with mode: 0644]
t/t4034/fortran/post [new file with mode: 0644]
t/t4034/fortran/pre [new file with mode: 0644]
t/t4034/html/expect [new file with mode: 0644]
t/t4034/html/post [new file with mode: 0644]
t/t4034/html/pre [new file with mode: 0644]
t/t4034/java/expect [new file with mode: 0644]
t/t4034/java/post [new file with mode: 0644]
t/t4034/java/pre [new file with mode: 0644]
t/t4034/objc/expect [new file with mode: 0644]
t/t4034/objc/post [new file with mode: 0644]
t/t4034/objc/pre [new file with mode: 0644]
t/t4034/pascal/expect [new file with mode: 0644]
t/t4034/pascal/post [new file with mode: 0644]
t/t4034/pascal/pre [new file with mode: 0644]
t/t4034/perl/expect [new file with mode: 0644]
t/t4034/perl/post [new file with mode: 0644]
t/t4034/perl/pre [new file with mode: 0644]
t/t4034/php/expect [new file with mode: 0644]
t/t4034/php/post [new file with mode: 0644]
t/t4034/php/pre [new file with mode: 0644]
t/t4034/python/expect [new file with mode: 0644]
t/t4034/python/post [new file with mode: 0644]
t/t4034/python/pre [new file with mode: 0644]
t/t4034/ruby/expect [new file with mode: 0644]
t/t4034/ruby/post [new file with mode: 0644]
t/t4034/ruby/pre [new file with mode: 0644]
t/t4034/tex/expect [new file with mode: 0644]
t/t4034/tex/post [new file with mode: 0644]
t/t4034/tex/pre [new file with mode: 0644]
t/t4040-whitespace-status.sh
t/t4120-apply-popt.sh
t/t4204-patch-id.sh
t/t5501-fetch-push-alternates.sh [new file with mode: 0755]
t/t5526-fetch-submodules.sh
t/t5601-clone.sh
t/t5701-clone-local.sh
t/t6000-rev-list-misc.sh [new file with mode: 0755]
t/t6004-rev-list-path-optim.sh
t/t6007-rev-list-cherry-pick-file.sh
t/t6035-merge-dir-to-symlink.sh
t/t6040-tracking-info.sh
t/t6110-rev-list-sparse.sh [new file with mode: 0755]
t/t7201-co.sh
t/t7406-submodule-update.sh
t/t7407-submodule-foreach.sh
t/t7500-commit.sh
t/t7505-prepare-commit-msg-hook.sh
t/t7509-commit.sh
t/t7607-merge-overwrite.sh
t/t7610-mergetool.sh
t/t7810-grep.sh
t/t8006-blame-textconv.sh
t/t9010-svn-fe.sh
t/t9130-git-svn-authors-file.sh
t/t9300-fast-import.sh
t/t9301-fast-import-notes.sh
t/t9500-gitweb-standalone-no-errors.sh
t/t9501-gitweb-standalone-http-status.sh
t/t9700/test.pl
t/t9800-git-p4.sh [new file with mode: 0755]
t/test-lib.sh
t/valgrind/default.supp
tag.c
tag.h
test-line-buffer.c
test-mktemp.c [new file with mode: 0644]
test-parse-options.c
test-path-utils.c
test-svn-fe.c
thread-utils.c
trace.c
transport-helper.c
transport.c
transport.h
tree-diff.c
tree-walk.c
tree-walk.h
unpack-trees.c
upload-pack.c
url.c
usage.c
userdiff.c
utf8.c
utf8.h
vcs-svn/fast_export.c
vcs-svn/fast_export.h
vcs-svn/line_buffer.c
vcs-svn/line_buffer.h
vcs-svn/line_buffer.txt
vcs-svn/repo_tree.c
vcs-svn/repo_tree.h
vcs-svn/string_pool.c
vcs-svn/svndump.c
vcs-svn/svndump.h
wrapper.c
wt-status.c
wt-status.h

index 3dd6ef7d259d8fe2811f68525b5309e97c79f4cc..c460c66766ab590239e4ae9107bb55b9fd30fac6 100644 (file)
 /test-index-version
 /test-line-buffer
 /test-match-trees
+/test-mktemp
 /test-obj-pool
 /test-parse-options
 /test-path-utils
index ba2006d892ec09d606f8846588c7727396b1ee28..fe1c1e5bc26e683540cb9fe5f43320192be9185d 100644 (file)
@@ -152,7 +152,7 @@ Writing Documentation:
  when writing or modifying command usage strings and synopsis sections
  in the manual pages:
 
- Placeholders are enclosed in angle brackets:
+ Placeholders are spelled in lowercase and enclosed in angle brackets:
    <file>
    --sort=<key>
    --abbrev[=<n>]
diff --git a/Documentation/RelNotes/1.7.4.1.txt b/Documentation/RelNotes/1.7.4.1.txt
new file mode 100644 (file)
index 0000000..79923a6
--- /dev/null
@@ -0,0 +1,27 @@
+Git v1.7.4.1 Release Notes
+==========================
+
+Fixes since v1.7.4
+------------------
+
+ * On Windows platform, the codepath to spawn a new child process forgot
+   to first flush the output buffer.
+
+ * "git bundle" did not use OFS_DELTA encoding, making its output a few
+   per-cent larger than necessarily.
+
+ * The option to tell "git clone" to recurse into the submodules was
+   misspelled with an underscore "--recurse_submodules".
+
+ * "git diff --cached HEAD" before the first commit does what an end user
+   would expect (namely, show what would be committed without further "git
+   add").
+
+ * "git fast-import" didn't accept the command to ask for "notes" feature
+   to be present in its input stream, even though it was capable of the
+   feature.
+
+ * "git fsck" gave up scanning loose object files in directories with
+   garbage files.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.4.2.txt b/Documentation/RelNotes/1.7.4.2.txt
new file mode 100644 (file)
index 0000000..991dae4
--- /dev/null
@@ -0,0 +1,51 @@
+Git v1.7.4.2 Release Notes
+==========================
+
+Fixes since v1.7.4.1
+--------------------
+
+ * Many documentation updates to match "git cmd -h" output and the
+   git-cmd manual page.
+
+ * We used to keep one file descriptor open for each and every packfile
+   that we have a mmap window on it (read: "in use"), even when for very
+   tiny packfiles.  We now close the file descriptor early when the entire
+   packfile fits inside one mmap window.
+
+ * "git clone /no/such/path" did not fail correctly.
+
+ * "git commit" did not correctly error out when the user asked to use a
+   non existent file as the commit message template.
+
+ * "git diff --stat -B" ran on binary files counted the changes in lines,
+   which was nonsensical.
+
+ * "git diff -M" opportunistically detected copies, which was not
+   necessarily a good thing, especially when it is internally run by
+   recursive merge.
+
+ * "git difftool" didn't tell (g)vimdiff that the files it is reading are
+   to be opened read-only.
+
+ * "git merge" didn't pay attention to prepare-commit-msg hook, even
+   though if a merge is conflicted and manually resolved, the subsequent
+   "git commit" would have triggered the hook, which was inconsistent.
+
+ * "git patch-id" (and commands like "format-patch --ignore-in-upstream"
+   that use it as their internal logic) handled changes to files that end
+   with incomplete lines incorrectly.
+
+ * The official value to tell "git push" to push the current branch back
+   to update the upstream branch it forked from is now called "upstream".
+   The old name "tracking" is and will be supported.
+
+ * "git submodule update" used to honor the --merge/--rebase option (or
+   corresponding configuration variables) even for a newly cloned
+   subproject, which made no sense (so/submodule-no-update-first-time).
+
+ * gitweb's "highlight" interface mishandled tabs.
+
+ * gitweb had a few forward-incompatible syntactic constructs and
+   also used incorrect variable when showing the file mode in a diff.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.5.txt b/Documentation/RelNotes/1.7.5.txt
new file mode 100644 (file)
index 0000000..24f5d8c
--- /dev/null
@@ -0,0 +1,127 @@
+Git v1.7.5 Release Notes (draft)
+========================
+
+Updates since v1.7.4
+--------------------
+
+ * Various MinGW portability fixes.
+
+ * Various git-p4 enhancements (in contrib).
+
+ * Various vcs-svn enhancements.
+
+ * Update to more modern HP-UX port.
+
+ * The codebase is getting prepared for i18n/l10n; no translated/translatable
+   strings in the code yet.
+
+ * The bash completion script can now complete symmetric difference
+   for "git diff" command, e.g. "git diff ...bra<TAB>".
+
+ * "git apply -v" reports offset lines when the patch does not apply at
+   the exact location recorded in the diff output.
+
+ * "git branch --track" (and "git checkout --track --branch") used to
+   allow setting up a random non-branch that does not make sense to follow
+   as the "upstream".  The command correctly diagnoses it as an error.
+
+ * "git config" used to be also known as "git repo-config", but the old
+   name is now officially deprecated.
+
+ * "git checkout --detach <commit>" is a more user friendly synonym for
+   "git checkout <commit>^0".
+
+ * "git checkout" performed on detached HEAD gives a warning and
+   advice when the commit being left behind will become unreachable from
+   any branch or tag.
+
+ * "git cherry-pick" and "git revert" can be told to use a custom merge
+   strategy, similar to "git rebase".
+
+ * "git cherry-pick" remembers which commit failed to apply when it is
+   stopped by conflicts, making it unnecessary to use "commit -c $commit"
+   to conclude it.
+
+ * "git cvsimport" bails out immediately when the cvs server cannot be
+   reached, without spewing unnecessary error messages that complain about
+   the server response it never got.
+
+ * "git fetch" vs "git upload-pack" transfer learned 'no-done'
+   protocol extension to save one round-trip after the content
+   negotiation is done. This saves one HTTP RPC, reducing the overall
+   latency for a trivial fetch.
+
+ * "git grep -f <filename>" learned to treat "-" as "read from the
+   standard input stream".
+
+ * "git grep --no-index" did not honor pathspecs correctly, returning
+   paths outside the specified area.
+
+ * "git log" type commands now understand globbing pathspecs.  You
+   can say "git log -- '*.txt'" for example.
+
+ * "git log" family of commands learned --cherry and --cherry-mark
+   options that can be used to view two diverged branches while omitting
+   or highlighting equivalent changes that appear on both sides of a
+   symmetric difference (e.g. "log --cherry A...B").
+
+ * "git mergetool" learned how to drive "beyond compare 3" as well.
+
+ * "git rerere forget" without pathspec used to forget all the saved
+   conflicts that relate to the current merge; it now requires you to
+   give it pathspecs.
+
+ * "git rev-list --objects $revs -- $pathspec" now limits the objects listed
+   in its output properly with the pathspec, in preparation for narrow
+   clones.
+
+ * "git push" with no parameters gives better advice messages when
+   "tracking" is used as the push.default semantics or there is no remote
+   configured yet.
+
+ * "git rerere" learned a new subcommand "remaining" that is similar to
+   "status" and lists the paths that had conflicts which are known to
+   rerere, but excludes the paths that have already been marked as
+   resolved in the index from its output.  "git mergetool" has been
+   updated to use this facility.
+
+ * A possible value to the "push.default" configuration variable,
+   'tracking', gained a synonym that more naturally describes what it
+   does, 'upstream'.
+
+Also contains various documentation updates.
+
+
+Fixes since v1.7.4
+------------------
+
+All of the fixes in the v1.7.4.X maintenance series are included in this
+release, unless otherwise noted.
+
+ * "git apply" used to confuse lines updated by previous hunks as lines
+   that existed before when applying a hunk, contributing misapplication
+   of patches with offsets.
+
+ * "git checkout $other_branch" silently removed untracked symbolic links
+   in the working tree that are in the way in order to check out paths
+   under it from the named branch (js/checkout-untracked-symlink).
+
+ * "git fetch" from a client that is mostly following the remote
+   needlessly told all of its refs to the server for both sides to
+   compute the set of objects that need to be transferred efficiently,
+   instead of stopping when the server heard enough. In a project with
+   many tags, this turns out to be extremely wasteful, especially over
+   the smart HTTP transport (sp/maint-{upload,fetch}-pack-stop-early~1).
+
+ * "git fetch" run from a repository that uses the same repository as
+   its alternate object store as the repository it is fetching from
+   did not tell the server that it already has access to objects
+   reachable from the refs in their common alternate object store,
+   causing it to fetch unnecessary objects (jc/maint-fetch-alt).
+
+---
+exec >/var/tmp/1
+O=v1.7.4.1-352-gcdc3466
+O=v1.7.4.1-414-gaeb2aaa
+echo O=$(git describe 'master')
+git shortlog --no-merges ^maint ^$O master
index 72741ebda12de8fbf786f12531d70ab465eecf42..c3b0816ed7e5f4d5989de85c3c3ad3f7eb829591 100644 (file)
@@ -10,10 +10,18 @@ Checklist (and a short version for the impatient):
          description (50 characters is the soft limit, see DISCUSSION
          in git-commit(1)), and should skip the full stop
        - the body should provide a meaningful commit message, which:
-               - uses the imperative, present tense: "change",
-                 not "changed" or "changes".
-               - includes motivation for the change, and contrasts
-                 its implementation with previous behaviour
+         . explains the problem the change tries to solve, iow, what
+           is wrong with the current code without the change.
+         . justifies the way the change solves the problem, iow, why
+           the result with the change is better.
+         . alternate solutions considered but discarded, if any.
+       - describe changes in imperative mood, e.g. "make xyzzy do frotz"
+         instead of "[This patch] makes xyzzy do frotz" or "[I] changed
+         xyzzy to do frotz", as if you are giving orders to the codebase
+         to change its behaviour.
+       - try to make sure your explanation can be understood without
+         external resources. Instead of giving a URL to a mailing list
+         archive, summarize the relevant points of the discussion.
        - add a "Signed-off-by: Your Name <you@example.com>" line to the
          commit message (or just use the option "-s" when committing)
          to confirm that you agree to the Developer's Certificate of Origin
@@ -90,7 +98,10 @@ your commit head.  Instead, always make a commit with complete
 commit message and generate a series of patches from your
 repository.  It is a good discipline.
 
-Describe the technical detail of the change(s).
+Give an explanation for the change(s) that is detailed enough so
+that people can judge if it is good thing to do, without reading
+the actual patch text to determine how well the code does what
+the explanation promises to do.
 
 If your description starts to get too long, that's a sign that you
 probably need to split up your commit to finer grained pieces.
@@ -99,9 +110,8 @@ help reviewers check the patch, and future maintainers understand
 the code, are the most beautiful patches.  Descriptions that summarise
 the point in the subject well, and describe the motivation for the
 change, the approach taken by the change, and if relevant how this
-differs substantially from the prior version, can be found on Usenet
-archives back into the late 80's.  Consider it like good Netiquette,
-but for code.
+differs substantially from the prior version, are all good things
+to have.
 
 Oh, another thing.  I am picky about whitespaces.  Make sure your
 changes do not trigger errors with the sample pre-commit hook shipped
index dacbcdeb793f7803bef887c20bd1eae4bdc857a6..8ea55d46add1da6d1e810cb126a7ecc5ce456650 100644 (file)
@@ -376,15 +376,6 @@ core.warnAmbiguousRefs::
        If true, git will warn you if the ref name you passed it is ambiguous
        and might match multiple refs in the .git/refs/ tree. True by default.
 
-core.abbrevguard::
-       Even though git makes sure that it uses enough hexdigits to show
-       an abbreviated object name unambiguously, as more objects are
-       added to the repository over time, a short name that used to be
-       unique will stop being unique.  Git uses this many extra hexdigits
-       that are more than necessary to make the object name currently
-       unique, in the hope that its output will stay unique a bit longer.
-       Defaults to 0.
-
 core.compression::
        An integer -1..9, indicating a default compression level.
        -1 is the zlib default. 0 means no compression,
@@ -1597,7 +1588,8 @@ push.default::
 * `matching` - push all matching branches.
   All branches having the same name in both ends are considered to be
   matching. This is the default.
-* `tracking` - push the current branch to its upstream branch.
+* `upstream` - push the current branch to its upstream branch.
+* `tracking` - deprecated synonym for `upstream`.
 * `current` - push the current branch to a branch of the same name.
 
 rebase.stat::
index 3ac2beac6229955dc2534c428238c3d5ff57d25d..c57460c03dd1512e1e3644d3321e87d38316befe 100644 (file)
@@ -74,10 +74,13 @@ separate lines indicate the old and the new mode.
 combined diff format
 --------------------
 
-"git-diff-tree", "git-diff-files" and "git-diff" can take '-c' or
-'--cc' option to produce 'combined diff'.  For showing a merge commit
-with "git log -p", this is the default format; you can force showing
-full diff with the '-m' option.
+Any diff-generating command can take the `-c` or `--cc` option to
+produce a 'combined diff' when showing a merge. This is the default
+format when showing merges with linkgit:git-diff[1] or
+linkgit:git-show[1]. Note also that you can give the `-m' option to any
+of these commands to force generation of diffs with individual parents
+of a merge.
+
 A 'combined diff' format looks like this:
 
 ------------
index 695696da1b6e78639014388e1d4ac8bf09a0e12d..f37276e5add75583fd363af2cd0b7ba051771a97 100644 (file)
@@ -64,13 +64,11 @@ ifndef::git-pull[]
        downloaded. The default behavior for a remote may be
        specified with the remote.<name>.tagopt setting. See
        linkgit:git-config[1].
-endif::git-pull[]
 
 --[no-]recurse-submodules::
        This option controls if new commits of all populated submodules should
        be fetched too (see linkgit:git-config[1] and linkgit:gitmodules[5]).
 
-ifndef::git-pull[]
 --submodule-prefix=<path>::
        Prepend <path> to paths printed in informative messages
        such as "Fetching submodule foo".  This option is used
index a03448f9231f78340fc492bffa009b96648ee6ac..7eebbefe7b6f665a8f6a5003eb37d7bcb3c196bd 100644 (file)
@@ -378,14 +378,6 @@ linkgit:git-mv[1]
 linkgit:git-commit[1]
 linkgit:git-update-index[1]
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 51297d09ecdd3468ecd87a4f7aa6fac2b8ef6224..6b1b5af64e2daec1ecc8ee832f58f5186d740a79 100644 (file)
@@ -173,9 +173,9 @@ aborts in the middle.  You can recover from this in one of two ways:
   the index file to bring it into a state that the patch should
   have produced.  Then run the command with the '--resolved' option.
 
-The command refuses to process new mailboxes while the `.git/rebase-apply`
-directory exists, so if you decide to start over from scratch,
-run `rm -f -r .git/rebase-apply` before running the command with mailbox
+The command refuses to process new mailboxes until the current
+operation is finished, so if you decide to start over from scratch,
+run `git am --abort` before running the command with mailbox
 names.
 
 Before any patches are applied, ORIG_HEAD is set to the tip of the
@@ -189,15 +189,6 @@ SEE ALSO
 --------
 linkgit:git-apply[1].
 
-
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
-Documentation
---------------
-Documentation by Petr Baudis, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 0590eec0566cf9f318ddd1ac27d10bb989b2c52f..9eb75c37dae574f4f9d4699b795f53e94e6fa0dd 100644 (file)
@@ -27,10 +27,6 @@ SEE ALSO
 --------
 linkgit:git-blame[1]
 
-AUTHOR
-------
-Written by Ryan Anderson <ryan@michonline.com>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 881652f4904c102104cfe0a0b1de07dbfc32da3f..afd2c9ae59e9145f377d5c702df27bf861c9b2f5 100644 (file)
@@ -22,7 +22,7 @@ DESCRIPTION
 -----------
 Reads the supplied diff output (i.e. "a patch") and applies it to files.
 With the `--index` option the patch is also applied to the index, and
-with the `--cache` option the patch is only applied to the index.
+with the `--cached` option the patch is only applied to the index.
 Without these options, the command applies the patch only to files,
 and does not require them to be in a git repository.
 
@@ -246,20 +246,10 @@ If `--index` is not specified, then the submodule commits in the patch
 are ignored and only the absence or presence of the corresponding
 subdirectory is checked and (if possible) updated.
 
-
 SEE ALSO
 --------
 linkgit:git-am[1].
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 2411ce5bfe05a14ed45c1546c3d1a6d92b39d8eb..f4504ba9bfd7285f2e117d3f54cab37801cc5b25 100644 (file)
@@ -107,14 +107,6 @@ OPTIONS
        Archive/branch identifier in a format that `tla log` understands.
 
 
-Author
-------
-Written by Martin Langhoff <martin@laptop.org>.
-
-Documentation
---------------
-Documentation by Junio C Hamano, Martin Langhoff and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index bf5037ab2a5042a20e9cb603f0831bb186ac3b74..f2b8684596576cd515e617ea68f06a479348b522 100644 (file)
@@ -153,14 +153,6 @@ SEE ALSO
 --------
 linkgit:gitattributes[5]
 
-Author
-------
-Written by Franck Bui-Huu and Rene Scharfe.
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index c39d957c3a3a432f5e685d44066c145f03b96365..7b7bafba0c514755f9eec423b5aed19db640c091 100644 (file)
@@ -241,7 +241,12 @@ exit(3) manual page), as the value is chopped with "& 0377".
 
 The special exit code 125 should be used when the current source code
 cannot be tested. If the script exits with this code, the current
-revision will be skipped (see `git bisect skip` above).
+revision will be skipped (see `git bisect skip` above). 125 was chosen
+as the highest sensible value to use for this purpose, because 126 and 127
+are used by POSIX shells to signal specific error status (127 is for
+command not found, 126 is for command found but not executable---these
+details do not matter, as they are normal errors in the script, as far as
+"bisect run" is concerned).
 
 You may often find that during a bisect session you want to have
 temporary modifications (e.g. s/#define DEBUG 0/#define DEBUG 1/ in a
@@ -274,61 +279,68 @@ $ git bisect start HEAD origin --    # HEAD is bad, origin is good
 $ git bisect run make test           # "make test" builds and tests
 ------------
 
-* Automatically bisect a broken test suite:
+* Automatically bisect a broken test case:
 +
 ------------
 $ cat ~/test.sh
 #!/bin/sh
-make || exit 125                   # this skips broken builds
-make test                          # "make test" runs the test suite
-$ git bisect start v1.3 v1.1 --    # v1.3 is bad, v1.1 is good
+make || exit 125                     # this skips broken builds
+~/check_test_case.sh                 # does the test case pass?
+$ git bisect start HEAD HEAD~10 --   # culprit is among the last 10
 $ git bisect run ~/test.sh
 ------------
 +
 Here we use a "test.sh" custom script. In this script, if "make"
 fails, we skip the current commit.
+"check_test_case.sh" should "exit 0" if the test case passes,
+and "exit 1" otherwise.
 +
-It is safer to use a custom script outside the repository to prevent
-interactions between the bisect, make and test processes and the
-script.
-+
-"make test" should "exit 0", if the test suite passes, and
-"exit 1" otherwise.
+It is safer if both "test.sh" and "check_test_case.sh" are
+outside the repository to prevent interactions between the bisect,
+make and test processes and the scripts.
 
-* Automatically bisect a broken test case:
+* Automatically bisect with temporary modifications (hot-fix):
 +
 ------------
 $ cat ~/test.sh
 #!/bin/sh
-make || exit 125                     # this skips broken builds
-~/check_test_case.sh                 # does the test case passes ?
-$ git bisect start HEAD HEAD~10 --   # culprit is among the last 10
-$ git bisect run ~/test.sh
+
+# tweak the working tree by merging the hot-fix branch
+# and then attempt a build
+if     git merge --no-commit hot-fix &&
+       make
+then
+       # run project specific test and report its status
+       ~/check_test_case.sh
+       status=$?
+else
+       # tell the caller this is untestable
+       status=125
+fi
+
+# undo the tweak to allow clean flipping to the next commit
+git reset --hard
+
+# return control
+exit $status
 ------------
 +
-Here "check_test_case.sh" should "exit 0" if the test case passes,
-and "exit 1" otherwise.
-+
-It is safer if both "test.sh" and "check_test_case.sh" scripts are
-outside the repository to prevent interactions between the bisect,
-make and test processes and the scripts.
+This applies modifications from a hot-fix branch before each test run,
+e.g. in case your build or test environment changed so that older
+revisions may need a fix which newer ones have already. (Make sure the
+hot-fix branch is based off a commit which is contained in all revisions
+which you are bisecting, so that the merge does not pull in too much, or
+use `git cherry-pick` instead of `git merge`.)
 
-* Automatically bisect a broken test suite:
+* Automatically bisect a broken test case:
 +
 ------------
 $ git bisect start HEAD HEAD~10 --   # culprit is among the last 10
 $ git bisect run sh -c "make || exit 125; ~/check_test_case.sh"
 ------------
 +
-Does the same as the previous example, but on a single line.
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
--------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
+This shows that you can do without a run script if you write the test
+on a single line.
 
 SEE ALSO
 --------
index c71671b4f99e0be3670fc6d7e4872927a86ed02e..c4d1ff86c90d22ffea3fff173ee6b76d88013dab 100644 (file)
@@ -198,10 +198,6 @@ SEE ALSO
 --------
 linkgit:git-annotate[1]
 
-AUTHOR
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 9106d38e406003cd53fd690ca66ee8e98630e4e3..c50f1898272f6b2a9a1c1cd236d3b27621d4fdb9 100644 (file)
@@ -232,14 +232,6 @@ linkgit:git-remote[1],
 link:user-manual.html#what-is-a-branch[``Understanding history: What is
 a branch?''] in the Git User's Manual.
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org> and Junio C Hamano <gitster@pobox.com>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 299007b206cb5d810d19eed9b7831c3ea6368043..92b01ec25d147831afaa0ffa43e11549af69e18c 100644 (file)
@@ -201,10 +201,6 @@ You can also see what references it offers:
 $ git ls-remote mybundle
 ----------------
 
-Author
-------
-Written by Mark Levedahl <mdl123@verizon.net>
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 544ba7ba218550ac1b09d9c95dc6f60ac604f7e8..2fb95bbd19f26317a542abfdb78d3b2be72f577b 100644 (file)
@@ -100,14 +100,6 @@ for each object specified on stdin that does not exist in the repository:
 <object> SP missing LF
 ------------
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 50824e3a2d7d00370d7311088349da84ee23b728..30eca6cee62ad7b9ccfc9d71209a17287c65d48c 100644 (file)
@@ -86,15 +86,6 @@ SEE ALSO
 --------
 linkgit:gitattributes[5].
 
-
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
-Documentation
---------------
-Documentation by James Bowes.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 0c0a9c14bc8e78ada9fb9b7174fcb90698e497a0..4d33e7be0f5599cc3bb74a45cb0d20fcde1631e8 100644 (file)
@@ -172,18 +172,6 @@ $ git checkout-index --prefix=.merged- Makefile
 This will check out the currently cached copy of `Makefile`
 into the file `.merged-Makefile`.
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-
-Documentation
---------------
-Documentation by David Greaves,
-Junio C Hamano and the git-list <git@vger.kernel.org>.
-
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 880763d391d18364485edc2e1e3dfc6f52243973..1063f69023f97357c747cf73f8a4bcc9d9a59c4b 100644 (file)
@@ -9,6 +9,7 @@ SYNOPSIS
 --------
 [verse]
 'git checkout' [-q] [-f] [-m] [<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' --patch [<tree-ish>] [--] [<paths>...]
@@ -22,9 +23,10 @@ branch.
 
 'git checkout' [<branch>]::
 'git checkout' -b|-B <new_branch> [<start point>]::
+'git checkout' [--detach] [<commit>]::
 
        This form switches branches by updating the index, working
-       tree, and HEAD to reflect the specified branch.
+       tree, and HEAD to reflect the specified branch or commit.
 +
 If `-b` is given, a new branch is created as if linkgit:git-branch[1]
 were called and then checked out; in this case you can
@@ -115,6 +117,13 @@ explicitly give a name with '-b' in such a case.
        Create the new branch's reflog; see linkgit:git-branch[1] for
        details.
 
+--detach::
+       Rather than checking out a branch to work on it, check out a
+       commit for inspection and discardable experiments.
+       This is the default behavior of "git checkout <commit>" when
+       <commit> is not a branch name.  See the "DETACHED HEAD" section
+       below for details.
+
 --orphan::
        Create a new 'orphan' branch, named <new_branch>, started from
        <start_point> and switch to it.  The first commit made on this
@@ -204,42 +213,140 @@ leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
 
 
 
-Detached HEAD
+DETACHED HEAD
 -------------
+HEAD normally refers to a named branch (e.g. 'master'). Meanwhile, each
+branch refers to a specific commit. Let's look at a repo with three
+commits, one of them tagged, and with branch 'master' checked out:
+
+------------
+          HEAD (refers to branch 'master')
+           |
+           v
+a---b---c  branch 'master' (refers to commit 'c')
+    ^
+    |
+  tag 'v2.0' (refers to commit 'b')
+------------
 
-It is sometimes useful to be able to 'checkout' a commit that is
-not at the tip of one of your branches.  The most obvious
-example is to check out the commit at a tagged official release
-point, like this:
+When a commit is created in this state, the branch is updated to refer to
+the new commit. Specifically, 'git commit' creates a new commit 'd', whose
+parent is commit 'c', and then updates branch 'master' to refer to new
+commit 'd'. HEAD still refers to branch 'master' and so indirectly now refers
+to commit 'd':
 
 ------------
-$ git checkout v2.6.18
+$ edit; git add; git commit
+
+              HEAD (refers to branch 'master')
+               |
+               v
+a---b---c---d  branch 'master' (refers to commit 'd')
+    ^
+    |
+  tag 'v2.0' (refers to commit 'b')
 ------------
 
-Earlier versions of git did not allow this and asked you to
-create a temporary branch using the `-b` option, but starting from
-version 1.5.0, the above command 'detaches' your HEAD from the
-current branch and directly points at the commit named by the tag
-(`v2.6.18` in the example above).
+It is sometimes useful to be able to checkout a commit that is not at
+the tip of any named branch, or even to create a new commit that is not
+referenced by a named branch. Let's look at what happens when we
+checkout commit 'b' (here we show two ways this may be done):
 
-You can use all git commands while in this state.  You can use
-`git reset --hard $othercommit` to further move around, for
-example.  You can make changes and create a new commit on top of
-a detached HEAD.  You can even create a merge by using `git
-merge $othercommit`.
+------------
+$ git checkout v2.0  # or
+$ git checkout master^^
+
+   HEAD (refers to commit 'b')
+    |
+    v
+a---b---c---d  branch 'master' (refers to commit 'd')
+    ^
+    |
+  tag 'v2.0' (refers to commit 'b')
+------------
 
-The state you are in while your HEAD is detached is not recorded
-by any branch (which is natural --- you are not on any branch).
-What this means is that you can discard your temporary commits
-and merges by switching back to an existing branch (e.g. `git
-checkout master`), and a later `git prune` or `git gc` would
-garbage-collect them.  If you did this by mistake, you can ask
-the reflog for HEAD where you were, e.g.
+Notice that regardless of which checkout command we use, HEAD now refers
+directly to commit 'b'. This is known as being in detached HEAD state.
+It means simply that HEAD refers to a specific commit, as opposed to
+referring to a named branch. Let's see what happens when we create a commit:
 
 ------------
-$ git log -g -2 HEAD
+$ edit; git add; git commit
+
+     HEAD (refers to commit 'e')
+      |
+      v
+      e
+     /
+a---b---c---d  branch 'master' (refers to commit 'd')
+    ^
+    |
+  tag 'v2.0' (refers to commit 'b')
+------------
+
+There is now a new commit 'e', but it is referenced only by HEAD. We can
+of course add yet another commit in this state:
+
+------------
+$ edit; git add; git commit
+
+        HEAD (refers to commit 'f')
+         |
+         v
+      e---f
+     /
+a---b---c---d  branch 'master' (refers to commit 'd')
+    ^
+    |
+  tag 'v2.0' (refers to commit 'b')
+------------
+
+In fact, we can perform all the normal git operations. But, let's look
+at what happens when we then checkout master:
+
+------------
+$ git checkout master
+
+              HEAD (refers to branch 'master')
+      e---f     |
+     /          v
+a---b---c---d  branch 'master' (refers to commit 'd')
+    ^
+    |
+  tag 'v2.0' (refers to commit 'b')
 ------------
 
+It is important to realize that at this point nothing refers to commit
+'f'. Eventually commit 'f' (and by extension commit 'e') will be deleted
+by the routine git garbage collection process, unless we create a reference
+before that happens. If we have not yet moved away from commit 'f',
+any of these will create a reference to it:
+
+------------
+$ git checkout -b foo   <1>
+$ git branch foo        <2>
+$ git tag foo           <3>
+------------
+
+<1> creates a new branch 'foo', which refers to commit 'f', and then
+updates HEAD to refer to branch 'foo'. In other words, we'll no longer
+be in detached HEAD state after this command.
+
+<2> similarly creates a new branch 'foo', which refers to commit 'f',
+but leaves HEAD detached.
+
+<3> creates a new tag 'foo', which refers to commit 'f',
+leaving HEAD detached.
+
+If we have moved away from commit 'f', then we must first recover its object
+name (typically by using git reflog), and then we can create a reference to
+it. For example, to see the last two commits to which HEAD referred, we
+can use either of these commands:
+
+------------
+$ git reflog -2 HEAD # or
+$ git log -g -2 HEAD
+------------
 
 EXAMPLES
 --------
@@ -315,15 +422,6 @@ $ edit frotz
 $ git add frotz
 ------------
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 73008705ebe304c8d2a2d089e9328be369c50fc6..01db83039fc36aa4bc08eab730db48ec513ec583 100644 (file)
@@ -16,6 +16,25 @@ Given one or more existing commits, apply the change each one
 introduces, recording a new commit for each.  This requires your
 working tree to be clean (no modifications from the HEAD commit).
 
+When it is not obvious how to apply a change, the following
+happens:
+
+1. The current branch and `HEAD` pointer stay at the last commit
+   successfully made.
+2. The `CHERRY_PICK_HEAD` ref is set to point at the commit that
+   introduced the change that is difficult to apply.
+3. Paths in which the change applied cleanly are updated both
+   in the index file and in your working tree.
+4. For conflicting paths, the index file records up to three
+   versions, as described in the "TRUE MERGE" section of
+   linkgit:git-merge[1].  The working tree files will include
+   a description of the conflict bracketed by the usual
+   conflict markers `<<<<<<<` and `>>>>>>>`.
+5. No other modifications are made.
+
+See linkgit:git-merge[1] for some hints on resolving such
+conflicts.
+
 OPTIONS
 -------
 <commit>...::
@@ -79,6 +98,16 @@ effect to your index in a row.
        cherry-pick'ed commit, then a fast forward to this commit will
        be performed.
 
+--strategy=<strategy>::
+       Use the given merge strategy.  Should only be used once.
+       See the MERGE STRATEGIES section in linkgit:git-merge[1]
+       for details.
+
+-X<option>::
+--strategy-option=<option>::
+       Pass the merge strategy-specific option through to the
+       merge strategy.  See linkgit:git-merge[1] for details.
+
 EXAMPLES
 --------
 git cherry-pick master::
@@ -120,13 +149,27 @@ git rev-list --reverse master \-- README | git cherry-pick -n --stdin::
        so the result can be inspected and made into a single new
        commit if suitable.
 
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
+The following sequence attempts to backport a patch, bails out because
+the code the patch applies to has changed too much, and then tries
+again, this time exercising more care about matching up context lines.
+
+------------
+$ git cherry-pick topic^             <1>
+$ git diff                           <2>
+$ git reset --merge ORIG_HEAD        <3>
+$ git cherry-pick -Xpatience topic^  <4>
+------------
+<1> apply the change that would be shown by `git show topic^`.
+In this example, the patch does not apply cleanly, so
+information about the conflict is written to the index and
+working tree and no new commit results.
+<2> summarize changes to be reconciled
+<3> cancel the cherry-pick.  In other words, return to the
+pre-cherry-pick state, preserving any local modifications you had in
+the working tree.
+<4> try to apply the change introduced by `topic^` again,
+spending extra time to avoid mistakes based on incorrectly matching
+context lines.
 
 SEE ALSO
 --------
index fed115acd01a63801a647ae870357d4c2d59ea44..79448c505bd66f370ab0d79fd9f6a31af84752be 100644 (file)
@@ -63,14 +63,6 @@ SEE ALSO
 --------
 linkgit:git-patch-id[1]
 
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index fb2753c97eb186c63ba16f9b7714c2e3a5b82a64..6e5c8126f595b95f70df2b02c0779cb06527bfa7 100644 (file)
@@ -19,14 +19,6 @@ to the less interactive 'git commit' program.
 'git citool' is actually a standard alias for `git gui citool`.
 See linkgit:git-gui[1] for more details.
 
-Author
-------
-Written by Shawn O. Pearce <spearce@spearce.org>.
-
-Documentation
---------------
-Documentation by Shawn O. Pearce <spearce@spearce.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 60e38e6e275f5cf90a1ccba36dd3930cafa1b630..974e04ef1abaf4a3018b83b0323a46cbaa5339d4 100644 (file)
@@ -61,12 +61,6 @@ OPTIONS
        Remove only files ignored by git.  This may be useful to rebuild
        everything from scratch, but keep manually created files.
 
-
-Author
-------
-Written by Pavel Roskin <proski@gnu.org>
-
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 42e7021215563f146a66d14e1b642d4dbe55bfaf..8577480074d84fe213cc6fd16486a1fa92c3e08a 100644 (file)
@@ -236,17 +236,6 @@ $ git clone --bare -l -s /pub/scm/.../torvalds/linux-2.6.git \
     /pub/scm/.../me/subsys-2.6.git
 ------------
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 5dcf4278fc497e4d72093069bdcd18b4ecff0949..f524d76019960512ba65a0110a542fedf9a54ebb 100644 (file)
@@ -93,15 +93,6 @@ SEE ALSO
 --------
 linkgit:git-write-tree[1]
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index b586c0f442afd33c2875af26b83bb261de7361b0..d0534b8c05c5780a7f9debc664dd21af6739a3ec 100644 (file)
@@ -84,9 +84,10 @@ OPTIONS
        linkgit:git-rebase[1] for details.
 
 --reset-author::
-       When used with -C/-c/--amend options, declare that the
-       authorship of the resulting commit now belongs of the committer.
-       This also renews the author timestamp.
+       When used with -C/-c/--amend options, or when committing after a
+       a conflicting cherry-pick, declare that the authorship of the
+       resulting commit now belongs of the committer. This also renews
+       the author timestamp.
 
 --short::
        When doing a dry-run, give the output in the short-format. See
@@ -214,10 +215,11 @@ FROM UPSTREAM REBASE" section in linkgit:git-rebase[1].)
 
 -u[<mode>]::
 --untracked-files[=<mode>]::
-       Show untracked files (Default: 'all').
+       Show untracked files.
 +
-The mode parameter is optional, and is used to specify
-the handling of untracked files.
+The mode parameter is optional (defaults to 'all'), and is used to
+specify the handling of untracked files; when -u is not used, the
+default is 'normal', i.e. show untracked files and directories.
 +
 The possible options are:
 +
@@ -225,9 +227,8 @@ The possible options are:
        - 'normal' - Shows untracked files and directories
        - 'all'    - Also shows individual files in untracked directories.
 +
-See linkgit:git-config[1] for configuration variable
-used to change the default for when the option is not
-specified.
+The default can be changed using the status.showUntrackedFiles
+configuration variable documented in linkgit:git-config[1].
 
 -v::
 --verbose::
@@ -396,12 +397,6 @@ linkgit:git-mv[1],
 linkgit:git-merge[1],
 linkgit:git-commit-tree[1]
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org> and
-Junio C Hamano <gitster@pobox.com>
-
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 543dd64a468a8e96daf7c97d9c52264ce426db65..8804de327fd5973ae5d36bff18cfcac3e738763d 100644 (file)
@@ -336,15 +336,6 @@ echo "${WS}your whitespace color or blue reverse${RESET}"
 
 include::config.txt[]
 
-
-Author
-------
-Written by Johannes Schindelin <Johannes.Schindelin@gmx.de>
-
-Documentation
---------------
-Documentation by Johannes Schindelin, Petr Baudis and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 6bc1c21e6283284e2eae16d7ec4cb8183d8e0851..a73933a931161ba81d6bf8dfaa9f2fe4287e0331 100644 (file)
@@ -25,15 +25,6 @@ OPTIONS
        and number of objects that can be removed by running
        `git prune-packed`.
 
-
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index d25661eb215c8bd2002933a48dd6ad5ea360459a..ad93a3e84e732291bbd1e4de196ddb8ce23eea32 100644 (file)
@@ -112,14 +112,6 @@ $ cd ~/project_cvs_checkout
 $ git cherry cvshead myhead | sed -n 's/^+ //p' | xargs -l1 git cvsexportcommit -c -p -v
 ------------
 
-Author
-------
-Written by Martin Langhoff <martin@laptop.org> and others.
-
-Documentation
---------------
-Documentation by Martin Langhoff <martin@laptop.org> and others.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 608cd63fc359d591e2aafbb8bd2fbae9b868b68b..6695ab3b4b93aa7c5829f89ceff936de48e9bc78 100644 (file)
@@ -217,15 +217,6 @@ more stable in practice:
 * cvs2git (part of cvs2svn), `http://cvs2svn.tigris.org`
 * parsecvs, `http://cgit.freedesktop.org/~keithp/parsecvs`
 
-Author
-------
-Written by Matthias Urlichs <smurf@smurf.noris.de>, with help from
-various participants of the git-list <git@vger.kernel.org>.
-
-Documentation
---------------
-Documentation by Matthias Urlichs <smurf@smurf.noris.de>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 70cbb2cae7b60a5c6514d0990da91ed5b23e0827..88d814af0e050eb3b31f5763cbf12f03a5f6cbc3 100644 (file)
@@ -391,22 +391,6 @@ Dependencies
 ------------
 'git-cvsserver' depends on DBD::SQLite.
 
-Copyright and Authors
----------------------
-
-This program is copyright The Open University UK - 2006.
-
-Authors:
-
-- Martyn Smith    <martyn@catalyst.net.nz>
-- Martin Langhoff <martin@laptop.org>
-
-with ideas and patches from participants of the git-list <git@vger.kernel.org>.
-
-Documentation
---------------
-Documentation by Martyn Smith <martyn@catalyst.net.nz>, Martin Langhoff <martin@laptop.org>, and Matthias Urlichs <smurf@smurf.noris.de>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index d15cb6a845645d7fe76e7782ce580b3678bd25e4..ebd13be72e58cf0d0a66ddd0105117747ac900be 100644 (file)
@@ -279,17 +279,6 @@ that connected to it, if the IP address is available. REMOTE_ADDR will
 be available in the environment of hooks called when
 services are performed.
 
-
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>, YOSHIFUJI Hideaki
-<yoshfuji@linux-ipv6.org> and the git-list <git@vger.kernel.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 02e015ad9c41e760b3ab37d2c5a9e4ef9ef0c4f5..039cce2e98367fdbff6f7c0ea68f8f4f77b8a107 100644 (file)
@@ -156,17 +156,6 @@ 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.
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>, but somewhat
-butchered by Junio C Hamano <gitster@pobox.com>.  Later significantly
-updated by Shawn Pearce <spearce@spearce.org>.
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 9cd8ccef37f131d7913926ef9b5b7b49fe6d3463..8d481948bd9b29393c8884abfef9d0a76c922c2d 100644 (file)
@@ -46,15 +46,6 @@ omit diff output for unmerged entries and just show "Unmerged".
 
 include::diff-format.txt[]
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 162cb741b3052560351d2dd3f53c56ece5e51e95..6d184864022cef90e284113a627103db99327052 100644 (file)
@@ -116,15 +116,6 @@ tell which file is in which state, since the "has been updated" ones
 show a valid sha1, and the "not in sync with the index" ones will
 always have the special all-zero sha1.
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index a7e37b875fdf4bd25ce9adcb3296e2f2066f7130..4e5f127efa634dd4ea68bb73508c59bd1cad32e5 100644 (file)
@@ -162,15 +162,6 @@ in case you care).
 
 include::diff-format.txt[]
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index f6ac847507a635759323565be44b088b479d8bf0..f8d0819113c52ac7c6388ec27eb96083a8c86d4a 100644 (file)
@@ -38,6 +38,8 @@ directories. This behavior can be forced by --no-index.
        commit relative to the named <commit>.  Typically you
        would want comparison with the latest commit, so if you
        do not give <commit>, it defaults to HEAD.
+       If HEAD does not exist (e.g. unborned branches) and
+       <commit> is not given, it shows all staged changes.
        --staged is a synonym of --cached.
 
 'git diff' [--options] <commit> [--] [<path>...]::
@@ -172,14 +174,6 @@ linkgit:gitdiffcore[7],
 linkgit:git-format-patch[1],
 linkgit:git-apply[1]
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index db87f1d42382e32d7e3ee94e5c3d0a032b7430e2..590f410abf0b902160eca0e92888191a2e2a0b89 100644 (file)
@@ -31,8 +31,8 @@ OPTIONS
 --tool=<tool>::
        Use the diff tool specified by <tool>.
        Valid merge tools are:
-       kdiff3, kompare, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff,
-       ecmerge, diffuse, opendiff, p4merge and araxis.
+       araxis, bc3, diffuse, emerge, ecmerge, gvimdiff, kdiff3,
+       kompare, meld, opendiff, p4merge, tkdiff, vimdiff and xxdiff.
 +
 If a diff tool is not specified, 'git difftool'
 will use the configuration variable `diff.tool`.  If the
@@ -109,15 +109,6 @@ linkgit:git-mergetool[1]::
 linkgit:git-config[1]::
         Get and set repository or global options
 
-
-AUTHOR
-------
-Written by David Aguilar <davvid@gmail.com>.
-
-Documentation
---------------
-Documentation by David Aguilar and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index e05b686b1e4784290e40993469a2c5fab9b4ce5d..781bd6edc3cce9d1488bf793231d08119e142948 100644 (file)
@@ -135,15 +135,6 @@ Since 'git fast-import' cannot tag trees, you will not be
 able to export the linux-2.6.git repository completely, as it contains
 a tag referencing a tree instead of a commit.
 
-
-Author
-------
-Written by Johannes E. Schindelin <johannes.schindelin@gmx.de>.
-
-Documentation
---------------
-Documentation by Johannes E. Schindelin <johannes.schindelin@gmx.de>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 4415e636352ea88f34a798b6c29dc5e34d60d868..2c2ea12c5c4e19907674609c228997062d305983 100644 (file)
@@ -78,6 +78,10 @@ OPTIONS
        set of marks.  If a mark is defined to different values,
        the last file wins.
 
+--import-marks-if-exists=<file>::
+       Like --import-marks but instead of erroring out, silently
+       skips the file if it does not exist.
+
 --relative-marks::
        After specifying --relative-marks= the paths specified
        with --import-marks= and --export-marks= are relative
@@ -192,7 +196,8 @@ especially when a higher level language such as Perl, Python or
 Ruby is being used.
 
 fast-import is very strict about its input.  Where we say SP below we mean
-*exactly* one space.  Likewise LF means one (and only one) linefeed.
+*exactly* one space.  Likewise LF means one (and only one) linefeed
+and HT one (and only one) horizontal tab.
 Supplying additional whitespace characters will cause unexpected
 results, such as branch names or file names with leading or trailing
 spaces in their name, or early termination of fast-import when it encounters
@@ -330,6 +335,11 @@ and control the current import process.  More detailed discussion
        format to the file descriptor set with `--cat-blob-fd` or
        `stdout` if unspecified.
 
+`ls`::
+       Causes fast-import to print a line describing a directory
+       entry in 'ls-tree' format to the file descriptor set with
+       `--cat-blob-fd` or `stdout` if unspecified.
+
 `feature`::
        Require that fast-import supports the specified feature, or
        abort if it does not.
@@ -915,6 +925,55 @@ This command can be used anywhere in the stream that comments are
 accepted.  In particular, the `cat-blob` command can be used in the
 middle of a commit but not in the middle of a `data` command.
 
+`ls`
+~~~~
+Prints information about the object at a path to a file descriptor
+previously arranged with the `--cat-blob-fd` argument.  This allows
+printing a blob from the active commit (with `cat-blob`) or copying a
+blob or tree from a previous commit for use in the current one (with
+`filemodify`).
+
+The `ls` command can be used anywhere in the stream that comments are
+accepted, including the middle of a commit.
+
+Reading from the active commit::
+       This form can only be used in the middle of a `commit`.
+       The path names a directory entry within fast-import's
+       active commit.  The path must be quoted in this case.
++
+....
+       'ls' SP <path> LF
+....
+
+Reading from a named tree::
+       The `<dataref>` can be a mark reference (`:<idnum>`) or the
+       full 40-byte SHA-1 of a Git tag, commit, or tree object,
+       preexisting or waiting to be written.
+       The path is relative to the top level of the tree
+       named by `<dataref>`.
++
+....
+       'ls' SP <dataref> SP <path> LF
+....
+
+See `filemodify` above for a detailed description of `<path>`.
+
+Output uses the same format as `git ls-tree <tree> {litdd} <path>`:
+
+====
+       <mode> SP ('blob' | 'tree' | 'commit') SP <dataref> HT <path> LF
+====
+
+The <dataref> represents the blob, tree, or commit object at <path>
+and can be used in later 'cat-blob', 'filemodify', or 'ls' commands.
+
+If there is no file or subtree at that path, 'git fast-import' will
+instead report
+
+====
+       missing SP <path> LF
+====
+
 `feature`
 ~~~~~~~~~
 Require that fast-import supports the specified feature, or abort if
@@ -942,12 +1001,21 @@ import-marks::
        any "feature import-marks" command in the stream.
 
 cat-blob::
-       Ignored.  Versions of fast-import not supporting the
-       "cat-blob" command will exit with a message indicating so.
+ls::
+       Require that the backend support the 'cat-blob' or 'ls' command.
+       Versions of fast-import not supporting the specified command
+       will exit with a message indicating so.
        This lets the import error out early with a clear message,
        rather than wasting time on the early part of an import
        before the unsupported command is detected.
 
+notes::
+       Require that the backend support the 'notemodify' (N)
+       subcommand to the 'commit' command.
+       Versions of fast-import not supporting notes will exit
+       with a message indicating so.
+
+
 `option`
 ~~~~~~~~
 Processes the specified option so that git fast-import behaves in a
@@ -1282,14 +1350,6 @@ operator can use this facility to peek at the objects and refs from an
 import in progress, at the cost of some added running time and worse
 compression.
 
-Author
-------
-Written by Shawn O. Pearce <spearce@spearce.org>.
-
-Documentation
---------------
-Documentation by Shawn O. Pearce <spearce@spearce.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 4a8487c1547abc156c8fad9e7cafe4d3c5a535f6..48d4bf6d68fd51d9374f896ac839351936580e31 100644 (file)
@@ -90,15 +90,6 @@ OPTIONS
        $GIT_DIR (e.g. "HEAD", "refs/heads/master").  When
        unspecified, update from all heads the remote side has.
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index c76e313923f6a6655ad69209070e8333ca360678..7146f6ba0b3d531f788693cf78590565a0645144 100644 (file)
@@ -80,16 +80,6 @@ SEE ALSO
 --------
 linkgit:git-pull[1]
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org> and
-Junio C Hamano <gitster@pobox.com>
-
-Documentation
--------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 796e7489ff7ee573a65647f4de33df932bd1bea1..03c76c717ac6c41edfaaed47fa9798344e5e8f94 100644 (file)
@@ -405,16 +405,6 @@ warned.
   (or if your git-gc is not new enough to support arguments to
   `\--prune`, use `git repack -ad; git prune` instead).
 
-
-Author
-------
-Written by Petr "Pasky" Baudis <pasky@suse.cz>,
-and the git list <git@vger.kernel.org>
-
-Documentation
---------------
-Documentation by Petr Baudis and the git list.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 75adf7a502e18aa11e7a8424acf217b4bf6be64c..32aff954a2b2f95a61b39b8d08fb0482724400bb 100644 (file)
@@ -67,15 +67,6 @@ SEE ALSO
 --------
 linkgit:git-merge[1]
 
-
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
-Documentation
---------------
-Documentation by Petr Baudis, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index fac1cf55e51ff289167270de4f248dad959741c6..152e695c8178fee9daa478cdf67eae58a2f1af00 100644 (file)
@@ -123,7 +123,7 @@ EXAMPLES
 --------
 
 An example directly producing formatted text.  Show the most recent
-3 tagged commits::
+3 tagged commits:
 
 ------------
 #!/bin/sh
@@ -140,7 +140,7 @@ Ref: %(*refname)
 
 
 A simple example showing the use of shell eval on the output,
-demonstrating the use of --shell.  List the prefixes of all heads::
+demonstrating the use of --shell.  List the prefixes of all heads:
 ------------
 #!/bin/sh
 
@@ -154,7 +154,7 @@ done
 
 
 A bit more elaborate report on tags, demonstrating that the format
-may be an entire script::
+may be an entire script:
 ------------
 #!/bin/sh
 
@@ -204,3 +204,15 @@ eval=`git for-each-ref --shell --format="$fmt" \
        refs/tags`
 eval "$eval"
 ------------
+
+Author
+------
+Written by Junio C Hamano <gitster@pobox.com>.
+
+Documentation
+-------------
+Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the linkgit:git[1] suite
index 9dcafc6d4442b6db66df642e92336537395b9919..a5525e9aa87e8c2c724542bc9e54dfa7e34548fd 100644 (file)
@@ -278,15 +278,6 @@ SEE ALSO
 --------
 linkgit:git-am[1], linkgit:git-send-email[1]
 
-
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 965a8279c1b17df6fbf82f4fbcadbd254049a7d5..90ebb8a59401ddd16622533cc998bbb218137e34 100644 (file)
@@ -15,3 +15,7 @@ DESCRIPTION
 
 This is a synonym for linkgit:git-fsck[1].  Please refer to the
 documentation of that command.
+
+GIT
+---
+Part of the linkgit:git[1] suite
index 86f9b2bf91f604cbfd175a4e241fc14fcb5828d5..c9ede794b03460ec2911b6ceddc781ab08fb8ded 100644 (file)
@@ -140,14 +140,6 @@ GIT_INDEX_FILE::
 GIT_ALTERNATE_OBJECT_DIRECTORIES::
        used to specify additional object database roots (usually unset)
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 26632414b2646ba80a17fa861d422a9c8c957810..4966cb57846412b097bbc8ba15d09005f4019340 100644 (file)
@@ -151,10 +151,6 @@ linkgit:git-reflog[1]
 linkgit:git-repack[1]
 linkgit:git-rerere[1]
 
-Author
-------
-Written by Shawn O. Pearce <spearce@spearce.org>
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 790af9573b02d643aa6dae117f8b50f7cb565b9b..8035736c9682d5615c98dc83eaff6cf389d6c463 100644 (file)
@@ -22,15 +22,6 @@ return code of 1.  This can happen if <tarfile> had not been created
 using 'git archive' or if the first parameter of 'git archive' had been
 a tree ID instead of a commit ID or tag.
 
-
-Author
-------
-Written by Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index dab0a78fa890d0c0cd193d89b7f4ac9ed19fb001..d4d425ea30292d69edd6e89a78e25dbe6346ef40 100644 (file)
@@ -203,16 +203,6 @@ git grep --all-match -e NODE -e Unexpected::
        Looks for a line that has `NODE` or `Unexpected` in
        files that have lines that match both.
 
-Author
-------
-Originally written by Linus Torvalds <torvalds@osdl.org>, later
-revamped by Junio C Hamano.
-
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 2563710b56bf441125bda6766365eb2a2b5eb46a..32a833e0ae522f034b9b7c9115c486aa68658b2c 100644 (file)
@@ -121,14 +121,6 @@ or
 
 or browsed online at http://repo.or.cz/w/git-gui.git/[].
 
-Author
-------
-Written by Shawn O. Pearce <spearce@spearce.org>.
-
-Documentation
---------------
-Documentation by Shawn O. Pearce <spearce@spearce.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 51edeecbe5b546c6fbbbe117f39b51f352cb6bc8..4b0a502e8ef92ac989cce308f87e1f269a8a69be 100644 (file)
@@ -53,14 +53,6 @@ OPTIONS
        conversion. If the file is read from standard input then this
        is always implied, unless the --path option is given.
 
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index eccd0ffd384bf90f1846bf4cfeb7670dbd64cb6e..42aa2b0c012aaa559162517ee8913ba8bbe72212 100644 (file)
@@ -171,17 +171,6 @@ $ git config --global web.browser firefox
 as they are probably more user specific than repository specific.
 See linkgit:git-config[1] for more information about this.
 
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com> and the git-list
-<git@vger.kernel.org>.
-
-Documentation
--------------
-Initial documentation was part of the linkgit:git[1] man page.
-Christian Couder <chriscool@tuxfamily.org> extracted and rewrote it a
-little. Maintenance is done by the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index d91cb7ff85b8c05a39cd18757bc66a16662c5150..fefa75219822331f7c7bc426a1224978a5da6795 100644 (file)
@@ -43,14 +43,6 @@ commit-id::
        Verify that everything reachable from target is fetched.  Used after
        an earlier fetch is interrupted.
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index ddf7a18dc42ef4d5f8ad44aed89ee5b17bb0e9a6..82ae34b9b80d8f3fd8605d5c06cc37c7a203f758 100644 (file)
@@ -91,15 +91,6 @@ With '--force', the fast-forward check is disabled for all refs.
 Optionally, a <ref> parameter can be prefixed with a plus '+' sign
 to disable the fast-forward check only on that ref.
 
-
-Author
-------
-Written by Nick Hengeveld <nickh@reactrix.com>
-
-Documentation
---------------
-Documentation by Nick Hengeveld
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 57aba42e6654e3d32617c3c7b17d18e8dd85852b..d3013d6a29f2696e05e3c77b0d6f0159d0a98a76 100644 (file)
@@ -124,14 +124,6 @@ Thunderbird in particular is known to be problematic.  Thunderbird
 users may wish to visit this web page for more information:
   http://kb.mozillazine.org/Plain_text_e-mail_-_Thunderbird#Completely_plain_email
 
-Author
-------
-Derived from isync 1.0.1 by Mike McCormack.
-
-Documentation
---------------
-Documentation by Mike McCormack
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index c2bb81042c80dbf93b7a651c47fc177358132f97..909687fed4269d8ad2e02b90d5a1f56fbcfde40e 100644 (file)
@@ -85,15 +85,6 @@ new .keep file was successfully created. This is useful to remove a
 .keep file used as a lock to prevent the race with 'git repack'
 mentioned above.
 
-
-Author
-------
-Written by Sergey Vlasov <vsu@altlinux.ru>
-
-Documentation
--------------
-Documentation by Sergey Vlasov
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index eba3cb4998b2732a22551aaf962ae1a742d221de..2c4c716f33f9dd3f0b876a013e22ac115ac3c936 100644 (file)
@@ -16,3 +16,7 @@ DESCRIPTION
 
 This is a synonym for linkgit:git-init[1].  Please refer to the
 documentation of that command.
+
+GIT
+---
+Part of the linkgit:git[1] suite
index 00d4a124c918e7548628140646f698b9e37ab87a..593192555e3b407536c81e4cd7b1bcc0dbe8f519 100644 (file)
@@ -134,15 +134,6 @@ $ git add .     <2>
 <1> prepare /path/to/my/codebase/.git directory
 <2> add all existing file to the index
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 7477ce8fa8e5185cfbd74a31b8d5accd18216a1b..08f85ba046598070432e9d9cd45052ae20484402 100644 (file)
@@ -84,14 +84,6 @@ If the configuration variable 'instaweb.browser' is not set,
 'web.browser' will be used instead if it is defined. See
 linkgit:git-web{litdd}browse[1] for more information about this.
 
-Author
-------
-Written by Eric Wong <normalperson@yhbt.net>
-
-Documentation
---------------
-Documentation by Eric Wong <normalperson@yhbt.net>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index ff41784c60b04a276931fc90ab54a22a67024a1e..2c84028838d566d424082efc71516f565b0ebbd2 100644 (file)
@@ -25,6 +25,7 @@ OPTIONS
 
 -<n>::
        Limits the number of commits to show.
+       Note that this is a commit limiting option, see below.
 
 <since>..<until>::
        Show only commits between the named two commits.  When
@@ -72,16 +73,16 @@ produced by --stat etc.
        to be prefixed with "\-- " to separate them from options or
        refnames.
 
+include::rev-list-options.txt[]
+
+include::pretty-formats.txt[]
+
 Common diff options
-~~~~~~~~~~~~~~~~~~~
+-------------------
 
 :git-log: 1
 include::diff-options.txt[]
 
-include::rev-list-options.txt[]
-
-include::pretty-formats.txt[]
-
 include::diff-generate-patch.txt[]
 
 Examples
@@ -181,14 +182,6 @@ This setting can be disabled by the `--no-standard-notes` option,
 overridden by the 'GIT_NOTES_DISPLAY_REF' environment variable,
 and supplemented by the `--show-notes` option.
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 602b8d5d4de8f7649cb88e6622108c012f484933..adf7e1c0557b3dab145403d73687f5e125ae73f4 100644 (file)
@@ -67,15 +67,6 @@ $ git rev-parse not-lost-anymore
 1ef2b196d909eed523d4f3c9bf54b78cdd6843c6
 ------------
 
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 86abd1345178d4c5d2362509fc075de80d2fc7e3..4b28292811ce019fc94259849f8c5ad6d514b686 100644 (file)
@@ -209,15 +209,6 @@ SEE ALSO
 --------
 linkgit:git-read-tree[1], linkgit:gitignore[5]
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano, Josh Triplett, and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index abe7bf9ff9eb9a3ddb1924938de071291520797a..c3df8c0ebe48af7192f7d593c13af69825b6560f 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 --------
 [verse]
 'git ls-remote' [--heads] [--tags]  [-u <exec> | --upload-pack <exec>]
-             <repository> <refs>...
+             <repository> [<refs>...]
 
 DESCRIPTION
 -----------
@@ -67,10 +67,6 @@ EXAMPLES
        c5db5456ae3b0873fc659c19fafdde22313cc441        refs/tags/v0.99.2
        7ceca275d047c90c0c7d5afb13ab97efdf51bd6e        refs/tags/v0.99.3
 
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 76ed625e7b2fe503d3fb2262371ecd4de006411f..16e87fd6dd548d462715d394df0586bd9cb5d3ec 100644 (file)
@@ -95,18 +95,6 @@ Object size identified by <object> is given in bytes, and right-justified
 with minimum width of 7 characters.  Object size is given only for blobs
 (file) entries; for other entries `-` character is used in place of size.
 
-
-Author
-------
-Written by Petr Baudis <pasky@suse.cz>
-Completely rewritten from scratch by Junio C Hamano <gitster@pobox.com>,
-another major rewrite by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list
-<git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 3ea5aad56c5e1cec7fc2ca01ba9b5ea6badebe2f..ed45662cc9bb0ef93c6748d02e3791ac915830f9 100644 (file)
@@ -80,17 +80,6 @@ This can enabled by default with the configuration option mailinfo.scissors.
 <patch>::
        The patch extracted from e-mail.
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org> and
-Junio C Hamano <gitster@pobox.com>
-
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 71912a19a4dcda5f2b76d1c06b4c9ef5051265e3..9b2049d674a5d0b71a9454b2ce4afbfa59e2db34 100644 (file)
@@ -46,16 +46,6 @@ OPTIONS
 --keep-cr::
        Do not remove `\r` from lines ending with `\r\n`.
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-and Junio C Hamano <gitster@pobox.com>
-
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index eedef1bb1a14591d23b1fe6e93da1e3c2be2786b..ba36ec04f4b9fa4733b6e0a4c7e41aa3e43327a0 100644 (file)
@@ -102,14 +102,6 @@ both '1' and '2' are merge-bases of A and B.  Neither one is better than
 the other (both are 'best' merge bases).  When the `--all` option is not given,
 it is unspecified which best one is output.
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 See also
 --------
 linkgit:git-rev-list[1],
index f334d694e0160df91d197293e5b76cc0bfaac187..635c66956e90452c58938f2d48e84454983f22e6 100644 (file)
@@ -86,17 +86,6 @@ git merge-file -L a -L b -L c tmp/a123 tmp/b234 tmp/c345::
        merges tmp/a123 and tmp/c345 with the base tmp/b234, but uses labels
        `a` and `c` instead of `tmp/a123` and `tmp/c345`.
 
-
-Author
-------
-Written by Johannes Schindelin <johannes.schindelin@gmx.de>
-
-
-Documentation
---------------
-Documentation by Johannes Schindelin and the git-list <git@vger.kernel.org>,
-with parts copied from the original documentation of RCS 'merge'.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 921b38f18374c20d1f94c0907a629425acb38aa4..6ce54673b0c239a04503ce9da231826c61470bd1 100644 (file)
@@ -73,15 +73,6 @@ merge once anything has returned an error (i.e., `cat` returned an error
 for the AA file, because it didn't exist in the original, and thus
 'git merge-index' didn't even try to merge the MM thing).
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-One-shot merge by Petr Baudis <pasky@ucw.cz>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index a163cfca6993b61b3f3d198bd0980bd1fed37e52..ee059def79f85e770b23b34bce1dfc293434aa8b 100644 (file)
@@ -15,15 +15,6 @@ DESCRIPTION
 This is the standard helper program to use with 'git merge-index'
 to resolve a merge after the trivial merge done with 'git read-tree -m'.
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>,
-Junio C Hamano <gitster@pobox.com> and Petr Baudis <pasky@suse.cz>.
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index f869a7f00fa812bed068f5b60bd970d4dcac0655..3bfa7b422026181f675a7398d41e1153fdfbd837 100644 (file)
@@ -23,14 +23,6 @@ merge results outside of the index, and stuff the results back into the
 index.  For this reason, the output from the command omits
 entries that match the <branch1> tree.
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index c1efaaa5c52cd93e90a1a7427125e470f771146a..fb4c05b83f2c5b27598938416ea092da77e5c81d 100644 (file)
@@ -312,15 +312,6 @@ linkgit:git-diff[1], linkgit:git-ls-files[1],
 linkgit:git-add[1], linkgit:git-rm[1],
 linkgit:git-mergetool[1]
 
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index d8df55362ce653516006b02df2950c325f1176b7..63ededec1d7099bb2156461895f32dcf008dedcc 100644 (file)
@@ -41,14 +41,6 @@ run_merge_tool::
        '$MERGED', '$LOCAL', '$REMOTE', and '$BASE' must be defined
        for use by the merge tool.
 
-Author
-------
-Written by David Aguilar <davvid@gmail.com>
-
-Documentation
---------------
-Documentation by David Aguilar and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 1f75a848ba36728eeaa67e5cbbc209075393193b..8c79ae8d2a610bf4f1dea1a840bfc52e85d90fd9 100644 (file)
@@ -26,8 +26,8 @@ OPTIONS
 --tool=<tool>::
        Use the merge resolution program specified by <tool>.
        Valid merge tools are:
-       kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge,
-       diffuse, tortoisemerge, opendiff, p4merge and araxis.
+       araxis, bc3, diffuse, ecmerge, emerge, gvimdiff, kdiff3,
+       meld, opendiff, p4merge, tkdiff, tortoisemerge, vimdiff and xxdiff.
 +
 If a merge resolution program is not specified, 'git mergetool'
 will use the configuration variable `merge.tool`.  If the
@@ -82,14 +82,6 @@ Setting the `mergetool.keepBackup` configuration variable to `false`
 causes `git mergetool` to automatically remove the backup as files
 are successfully merged.
 
-Author
-------
-Written by Theodore Y Ts'o <tytso@mit.edu>
-
-Documentation
---------------
-Documentation by Theodore Y Ts'o.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 8bcc11443dce7322ac5b0fa70e07b2465f762615..037ab1045d91b730e5cae9073226bd09ebe67b9a 100644 (file)
@@ -32,15 +32,6 @@ exists, is separated by a blank line from the header.  The
 message part may contain a signature that git itself doesn't
 care about, but that can be verified with gpg.
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 81e3326772d94464708cc2037715e1e62eae5f11..afe21be64dfa9ea2540f9c4fc24d97413643879f 100644 (file)
@@ -34,14 +34,6 @@ OPTIONS
        optional.  Note - if the '-z' option is used, lines are terminated
        with NUL.
 
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index bdcb58526ec2e838949e079891a420802df477db..db0e030d69f92a1f52cd7c98de99504e850ab2db 100644 (file)
@@ -39,17 +39,6 @@ OPTIONS
 --dry-run::
        Do nothing; only show what would happen
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-Rewritten by Ryan Anderson <ryan@michonline.com>
-Move functionality added by Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 2108237c36cead52b14cd9a593c1398ea717a231..ad1d1468c9936d206701d379003177e7457c884e 100644 (file)
@@ -70,15 +70,6 @@ Another nice thing you can do is:
 % git log | git name-rev --stdin
 ------------
 
-
-Author
-------
-Written by Johannes Schindelin <Johannes.Schindelin@gmx.de>
-
-Documentation
---------------
-Documentation by Johannes Schindelin.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 65eff66afe5990efc4af4f141809f355b7111bd3..a51071e5247f3a6c525b93384ec0ffc1a12eb8d2 100644 (file)
@@ -219,15 +219,6 @@ self-contained. Use `git index-pack --fix-thin`
        With this option, parents that are hidden by grafts are packed
        nevertheless.
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
--------------
-Documentation by Junio C Hamano
-
 SEE ALSO
 --------
 linkgit:git-rev-list[1]
index d0607879db7ffc125e3a3aad2046b5e77730dcd6..db9f0f70554d997fab9d8441f78c10e523dda178 100644 (file)
@@ -38,14 +38,6 @@ OPTIONS
 --verbose::
        Outputs some statistics to stderr. Has a small performance penalty.
 
-Author
-------
-Written by Lukas Sandström <lukass@etek.chalmers.se>
-
-Documentation
---------------
-Documentation by Lukas Sandström <lukass@etek.chalmers.se>
-
 SEE ALSO
 --------
 linkgit:git-pack-objects[1]
index 1ee99c208ce4893d2fa2367544b22ed0c8b18044..54b92534ceb7895dadf1bec22782af3d09f1ef78 100644 (file)
@@ -56,11 +56,6 @@ a repository with many branches of historical interests.
 The command usually removes loose refs under `$GIT_DIR/refs`
 hierarchy after packing them.  This option tells it not to.
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 39d9daa7e00b97ddcca8f3d25d7376234c57c246..02217f6ba2007bb7bc55c577b77773dfcce93225 100644 (file)
@@ -17,14 +17,6 @@ routines to parse files under $GIT_DIR/remotes/ and
 $GIT_DIR/branches/ and configuration variables that are related
 to fetching, pulling and pushing.
 
-Author
-------
-Written by Junio C Hamano.
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 4dae1390a5c663867b93e1dce6cd4d2bf59e84ab..50e26f43c1cd9fde593760d1557ac57b3695ae5c 100644 (file)
@@ -29,14 +29,6 @@ OPTIONS
 <patch>::
        The diff to create the ID of.
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 87dacd797f6e36d47024bc0d2ebc82bb0b5bb387..a34d62f0daa3ada5c5287008b05d989eb52cc8f0 100644 (file)
@@ -37,14 +37,6 @@ OPTIONS
        The repository to sync from.
 
 
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
-Documentation
---------------
-Documentation by Junio C Hamano.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index abfc6b6ead534311d8a29696c497ecf94ce4fd1a..9e6202cdffd01fc685a78d1bd2c56128a8b8b73a 100644 (file)
@@ -36,14 +36,6 @@ OPTIONS
 --quiet::
        Squelch the progress indicator.
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Ryan Anderson <ryan@michonline.com>
-
 SEE ALSO
 --------
 linkgit:git-pack-objects[1]
index 4d673a56864ca88de0e98f54a6de469e99ea0f44..f616a739efdab16a58c33e9c2671e8afbaf13b98 100644 (file)
@@ -78,14 +78,6 @@ linkgit:git-fsck[1],
 linkgit:git-gc[1],
 linkgit:git-reflog[1]
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 30466917dad52eefd76de95aead3fdc12ad8425d..c2a7f103ee5bf4495d39b3034752be564b119766 100644 (file)
@@ -84,6 +84,15 @@ must be given before the options meant for 'git fetch'.
 --verbose::
        Pass --verbose to git-fetch and git-merge.
 
+--[no-]recurse-submodules::
+       This option controls if new commits of all populated submodules should
+       be fetched too (see linkgit:git-config[1] and linkgit:gitmodules[5]).
+       That might be necessary to get the data needed for merging submodule
+       commits, a feature git learned in 1.7.3. Notice that the result of a
+       merge will not be checked out in the submodule, "git submodule update"
+       has to be called afterwards to bring the work tree up to date with the
+       merge result.
+
 Options related to merging
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -215,18 +224,6 @@ SEE ALSO
 --------
 linkgit:git-fetch[1], linkgit:git-merge[1], linkgit:git-config[1]
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-and Junio C Hamano <gitster@pobox.com>
-
-Documentation
---------------
-Documentation by Jon Loeliger,
-David Greaves,
-Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index e11660a2e651b385251bef4f45dc36f212fa58bf..88acfcd4cc8e0eeafc809df0d72b37daded6f8a6 100644 (file)
@@ -406,16 +406,6 @@ Commits A and B would no longer belong to a branch with a symbolic name,
 and so would be unreachable.  As such, these commits would be removed by
 a `git gc` command on the origin repository.
 
-
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>, later rewritten in C
-by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 579e8d2f3ba54e393a60a8b4d8a4ad6a95cb79f1..7f112f3dcd87490dcf50fc74e45cace5736c599f 100644 (file)
@@ -49,14 +49,6 @@ The default for the patch directory is patches
 or the value of the $QUILT_PATCHES environment
 variable.
 
-Author
-------
-Written by Eric Biederman <ebiederm@lnxi.com>
-
-Documentation
---------------
-Documentation by Eric Biederman <ebiederm@lnxi.com>
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 634423a69ee6a4f2e9c7dd3941fd5160fbf6c99f..26fdadc642a3534c4005488cb9ca2b2a47a495a1 100644 (file)
@@ -421,15 +421,6 @@ SEE ALSO
 linkgit:git-write-tree[1]; linkgit:git-ls-files[1];
 linkgit:gitignore[5]
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 96680c84561c434c4cf3a00cfe958b21f18a3d8d..620d50e71f1a04f587079180ff2d987521d38786 100644 (file)
@@ -66,8 +66,9 @@ would be:
     D---E---F---G master
 ------------
 
-The latter form is just a short-hand of `git checkout topic`
-followed by `git rebase master`.
+*NOTE:* The latter form is just a short-hand of `git checkout topic`
+followed by `git rebase master`. When rebase exits `topic` will
+remain the checked-out branch.
 
 If the upstream branch already contains a change you have made (e.g.,
 because you mailed a patch which was applied upstream), then that commit
@@ -658,7 +659,6 @@ The ripple effect of a "hard case" recovery is especially bad:
 'everyone' downstream from 'topic' will now have to perform a "hard
 case" recovery too!
 
-
 BUGS
 ----
 The todo list presented by `--preserve-merges --interactive` does not
@@ -681,15 +681,6 @@ by moving the "pick 4" line will result in the following history:
 1 --- 2 --- 4 --- 5
 ------------
 
-Authors
-------
-Written by Junio C Hamano <gitster@pobox.com> and
-Johannes E. Schindelin <johannes.schindelin@gmx.de>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 2790eebaff3b9dd9a56358cc470396f36eb87085..f34e0ae1bd4bf9f3d0fa5de1e8b0eba47637f7a6 100644 (file)
@@ -151,15 +151,6 @@ SEE ALSO
 --------
 linkgit:git-send-pack[1]
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index e50bd9b68d80e9be997de80252dec5afbb7452b4..09057bf90cbea3a360cf65c212c358d9c848f11a 100644 (file)
@@ -90,14 +90,6 @@ them.
 --verbose::
        Print extra information on screen.
 
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 8fc809f82b2fae71f5cf6315dec707b649931382..98933764870fa73d693c636e713fd1f08eb8244d 100644 (file)
@@ -24,14 +24,6 @@ OPTIONS
 <dir>::
        Directories containing a .git/objects/ subdirectory.
 
-Author
-------
-Written by Ryan Anderson <ryan@michonline.com>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 2d65cfefd5d2aeaafcbc0bb6e6705f8379b2f826..68263a6a538b3d4659ca9dc0afd2253170143fb6 100644 (file)
@@ -7,17 +7,17 @@ git-remote-ext - Bridge smart transport to external command.
 
 SYNOPSIS
 --------
-git remote add nick "ext::<command>[ <arguments>...]"
+git remote add <nick> "ext::<command>[ <arguments>...]"
 
 DESCRIPTION
 -----------
-This remote helper uses the specified 'program' to connect
+This remote helper uses the specified '<command>' to connect
 to a remote git server.
 
-Data written to stdin of this specified 'program' is assumed
+Data written to stdin of the specified '<command>' is assumed
 to be sent to a git:// server, git-upload-pack, git-receive-pack
 or git-upload-archive (depending on situation), and data read
-from stdout of this program is assumed to be received from
+from stdout of <command> is assumed to be received from
 the same service.
 
 Command and arguments are separated by an unescaped space.
@@ -40,7 +40,7 @@ The following sequences have a special meaning:
        git wants to invoke.
 
 '%G' (must be the first characters in an argument)::
-       This argument will not be passed to 'program'. Instead, it
+       This argument will not be passed to '<command>'. Instead, it
        will cause the helper to start by sending git:// service requests to
        the remote side with the service field set to an appropriate value and
        the repository field set to rest of the argument. Default is not to send
@@ -50,7 +50,7 @@ This is useful if remote side is git:// server accessed over
 some tunnel.
 
 '%V' (must be first characters in argument)::
-       This argument will not be passed to 'program'. Instead it sets
+       This argument will not be passed to '<command>'. Instead it sets
        the vhost field in the git:// service request (to rest of the argument).
        Default is not to send vhost in such request (if sent).
 
@@ -76,7 +76,7 @@ EXAMPLES:
 ---------
 This remote helper is transparently used by git when
 you use commands such as "git fetch <URL>", "git clone <URL>",
-, "git push <URL>" or "git remote add nick <URL>", where <URL>
+, "git push <URL>" or "git remote add <nick> <URL>", where <URL>
 begins with `ext::`.  Examples:
 
 "ext::ssh -i /home/foo/.ssh/somekey user&#64;host.example %S 'foo/repo'"::
index 3a23477ce72763b562258a25c3777dd57ac1a962..87cd11f2c47b66387d31c38f648c02f4c2734955 100644 (file)
@@ -201,12 +201,12 @@ REF LIST ATTRIBUTES
 
 OPTIONS
 -------
-'option verbosity' <N>::
+'option verbosity' <n>::
        Changes the verbosity of messages displayed by the helper.
-       A value of 0 for N means that processes operate
+       A value of 0 for <n> means that processes operate
        quietly, and the helper produces only error output.
        1 is the default level of verbosity, and higher values
-       of N correspond to the number of -v flags passed on the
+       of <n> correspond to the number of -v flags passed on the
        command line.
 
 'option progress' \{'true'|'false'\}::
@@ -239,10 +239,6 @@ SEE ALSO
 --------
 linkgit:git-remote[1]
 
-Documentation
--------------
-Documentation by Daniel Barkalow and Ilari Liusvaara
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index c258ea48dbb8889a48f3075ab171ebddfd7fda3b..37bd3e538894206b7b79022a58c72e9a75263513 100644 (file)
@@ -214,16 +214,6 @@ linkgit:git-fetch[1]
 linkgit:git-branch[1]
 linkgit:git-config[1]
 
-Author
-------
-Written by Junio Hamano
-
-
-Documentation
---------------
-Documentation by J. Bruce Fields and the git-list <git@vger.kernel.org>.
-
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 27f7865b061cc96398f7aa052d162723e1f9255e..0decee240bfbad5c924de36e1867edca9975f39c 100644 (file)
@@ -123,15 +123,6 @@ need to set the configuration variable `repack.UseDeltaBaseOffset` to
 is unaffected by this option as the conversion is performed on the fly
 as needed in that case.
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Ryan Anderson <ryan@michonline.com>
-
 SEE ALSO
 --------
 linkgit:git-pack-objects[1]
index fde209258234edd221dea2f5b096c78f1978eeb4..17df525275493f5bdcdd912ad56581ffa8a97fa2 100644 (file)
@@ -80,17 +80,6 @@ linkgit:git-tag[1]
 linkgit:git-branch[1]
 linkgit:git[1]
 
-Author
-------
-Written by Christian Couder <chriscool@tuxfamily.org> and Junio C
-Hamano <gitster@pobox.com>, based on 'git tag' by Kristian Hogsberg
-<krh@redhat.com> and Carlos Rica <jasampler@gmail.com>.
-
-Documentation
---------------
-Documentation by Christian Couder <chriscool@tuxfamily.org> and the
-git-list <git@vger.kernel.org>, based on 'git tag' documentation.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index e5bdb5533e61687874ad36d30534b2ac9e58d7cb..a0d1fa6594cc4fed65c7ce68a4957e5e611cfa78 100644 (file)
@@ -16,3 +16,7 @@ DESCRIPTION
 
 This is a synonym for linkgit:git-config[1].  Please refer to the
 documentation of that command.
+
+GIT
+---
+Part of the linkgit:git[1] suite
index 400f61f6e24947525e51b7e5d808378819945205..3521d8e3c88c97f85ab95d82d416256d0debc94c 100644 (file)
@@ -29,14 +29,6 @@ OPTIONS
 <end>::
        Commit to end at; defaults to HEAD.
 
-Author
-------
-Written by Ryan Anderson <ryan@michonline.com> and Junio C Hamano <gitster@pobox.com>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index db99d4786e06df1cd2c9352c877c45efcbfb10cc..52db1d80cfe068f39ae5996a88e95bbfcf095a36 100644 (file)
@@ -7,7 +7,7 @@ git-rerere - Reuse recorded resolution of conflicted merges
 
 SYNOPSIS
 --------
-'git rerere' ['clear'|'forget' [<pathspec>]|'diff'|'status'|'gc']
+'git rerere' ['clear'|'forget' <pathspec>|'diff'|'status'|'gc']
 
 DESCRIPTION
 -----------
@@ -43,7 +43,7 @@ will automatically invoke this command.
 'forget' <pathspec>::
 
 This resets the conflict resolutions which rerere has recorded for the current
-conflict in <pathspec>.  The <pathspec> is optional.
+conflict in <pathspec>.
 
 'diff'::
 
@@ -205,11 +205,6 @@ would conflict the same way as the test merge you resolved earlier.
 'git rerere' will be run by 'git rebase' to help you resolve this
 conflict.
 
-
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 927ecee2f26cdf0bd30457d5016b654c01a23a14..8481f9db746b70c10a2f20a97a8ef4a68cb56d75 100644 (file)
@@ -397,15 +397,6 @@ entries:
 
 X means any state and U means an unmerged index.
 
-
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com> and Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 8e1e32908c31ddb8cb07046a25bcdb6dd38d74f5..b08dfbc3c455a19b3257e7e921c2a1a7436ddf3e 100644 (file)
@@ -31,6 +31,9 @@ SYNOPSIS
             [ \--parents ]
             [ \--timestamp ]
             [ \--left-right ]
+            [ \--left-only ]
+            [ \--right-only ]
+            [ \--cherry-mark ]
             [ \--cherry-pick ]
             [ \--encoding[=<encoding>] ]
             [ \--(author|committer|grep)=<pattern> ]
@@ -105,16 +108,6 @@ include::rev-list-options.txt[]
 
 include::pretty-formats.txt[]
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano, Jonas Fonseca
-and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index ff23cb0219d602803a83da273195fcc4ca71b5f5..02c44c999f361cd7c40a504ae4ccdc2d8b1a18fe 100644 (file)
@@ -308,16 +308,6 @@ $ git rev-parse --default master --verify $REV
 +
 but if $REV is empty, the commit object name from master will be printed.
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org> .
-Junio C Hamano <gitster@pobox.com> and Pierre Habouzit <madcoder@debian.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 752fc88e768e4b8e1afddad4bdd7833cf20978c7..ac10cfbb14aba460973019d712ee90e8804de34d 100644 (file)
@@ -80,6 +80,16 @@ effect to your index in a row.
 --signoff::
        Add Signed-off-by line at the end of the commit message.
 
+--strategy=<strategy>::
+       Use the given merge strategy.  Should only be used once.
+       See the MERGE STRATEGIES section in linkgit:git-merge[1]
+       for details.
+
+-X<option>::
+--strategy-option=<option>::
+       Pass the merge strategy-specific option through to the
+       merge strategy.  See linkgit:git-merge[1] for details.
+
 EXAMPLES
 --------
 git revert HEAD~3::
@@ -95,14 +105,6 @@ git revert -n master{tilde}5..master{tilde}2::
        changes. The revert only modifies the working tree and the
        index.
 
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 SEE ALSO
 --------
 linkgit:git-cherry-pick[1]
index 0adbe8b1f8e6e992a1f991fbdba4deffbd6e15b0..8c0554f9716c0d3ca7570a8f893f48189ea0c6f8 100644 (file)
@@ -153,14 +153,6 @@ SEE ALSO
 --------
 linkgit:git-add[1]
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 7ec9dabe6815f2b8ff03048043e1cfd81cd19fcc..ee14f74fd3af8dd6cfd9e52002993355d63b97c8 100644 (file)
@@ -348,7 +348,6 @@ sendemail.confirm::
        one of 'always', 'never', 'cc', 'compose', or 'auto'. See '--confirm'
        in the previous section for the meaning of these values.
 
-
 Use gmail as the smtp server
 ----------------------------
 
@@ -363,20 +362,6 @@ Add the following section to the config file:
 Note: the following perl modules are required
       Net::SMTP::SSL, MIME::Base64 and Authen::SASL
 
-
-Author
-------
-Written by Ryan Anderson <ryan@michonline.com>
-
-git-send-email is originally based upon
-send_lots_of_email.pl by Greg Kroah-Hartman.
-
-
-Documentation
---------------
-Documentation by Ryan Anderson
-
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index deaa7d9654f5938fabad3e1eae29ae7c7803d2ec..17f8f5552646cc063fdcc3674c0b133ed070aec9 100644 (file)
@@ -114,15 +114,6 @@ With '--force', the fast-forward check is disabled for all refs.
 Optionally, a <ref> parameter can be prefixed with a plus '+' sign
 to disable the fast-forward check only on that ref.
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 3da241304b0d2fdaa376bca740beb024a36b2cb6..053df505bc3aaa5e74c3a9266858eef0de1c2bd2 100644 (file)
@@ -66,15 +66,6 @@ get_author_ident_from_commit::
        outputs code for use with eval to set the GIT_AUTHOR_NAME,
        GIT_AUTHOR_EMAIL and GIT_AUTHOR_DATE variables for a given commit.
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 6403126a029bf43acaa219296353f7ab1f2040a0..d7d4b92894d143daaf1f0e27fa4bdbcf35aba10d 100644 (file)
@@ -28,14 +28,6 @@ read and execute permissions to the directory in order to execute the
 programs in it. The programs are executed with a cwd of $HOME, and
 <argument> is parsed as a command-line string.
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Petr Baudis and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 5cc3baf48dcbf86e976d5d4407831a6d0ceb108f..ff3755b4c72a52595be805e92a9f3b62d1477af2 100644 (file)
@@ -68,15 +68,6 @@ spelled differently.
 
 include::mailmap.txt[]
 
-
-Author
-------
-Written by Jeff Garzik <jgarzik@pobox.com>
-
-Documentation
---------------
-Documentation by Junio C Hamano.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 3b0c88271a80ad9dfc989dcb44247479f09431bf..ee4559b6f20d6cfe399c2b7e1b8dd9a1e2aafc7a 100644 (file)
@@ -200,17 +200,6 @@ shows 10 reflog entries going back from the tip as of 1 hour ago.
 Without `--list`, the output also shows how these tips are
 topologically related with each other.
 
-
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
-
-Documentation
---------------
-Documentation by Junio C Hamano.
-
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 8382fbe0ec5e59545e265317bdff38bfa098e0ed..c4d99f10281599ae52f95da455372e8ed759cfe7 100644 (file)
@@ -20,15 +20,6 @@ The information it outputs is subset of what you can get from
 'git verify-pack -v'; this command only shows the packfile
 offset and SHA1 of each object.
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index be0ec189af45e1006134e5607bb76a7b6ad20699..3c4589529960e013df364c68e4480caa09b744c6 100644 (file)
@@ -177,11 +177,6 @@ linkgit:git-ls-remote[1],
 linkgit:git-update-ref[1],
 linkgit:gitrepository-layout[5]
 
-AUTHORS
--------
-Written by Linus Torvalds <torvalds@osdl.org>.
-Man page by Jonas Fonseca <fonseca@diku.dk>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index f0a8a1aff3694cf00587d8670a8fe9962fe98af3..7f075e84f54e3abc5c16b7cae57af831bd2b5bd7 100644 (file)
@@ -72,17 +72,6 @@ Discussion
 
 include::i18n.txt[]
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org> and
-Junio C Hamano <gitster@pobox.com>.  Significantly enhanced by
-Johannes Schindelin <Johannes.Schindelin@gmx.de>.
-
-
-Documentation
--------------
-Documentation by David Greaves, Petr Baudis and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 7f251a58656e9fe30fc9f74a02d6a48adc01b860..ba3fe0d7f59b1ae4c9ae9e3d32675d2e281ccf13 100644 (file)
@@ -17,3 +17,7 @@ DESCRIPTION
 
 This is a synonym for linkgit:git-add[1].  Please refer to the
 documentation of that command.
+
+GIT
+---
+Part of the linkgit:git[1] suite
index 8728f7a5142284d036594628cbb99da677c16651..79abc38e50a9a82243085383401b2d93468efaf3 100644 (file)
@@ -257,10 +257,6 @@ linkgit:git-commit[1],
 linkgit:git-reflog[1],
 linkgit:git-reset[1]
 
-AUTHOR
-------
-Written by Nanako Shiraishi <nanako3@bluebottle.com>
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index dae190a5f21d3835024ce263bf4bd9b08048cfa6..00b699fef71b45c78e298fa48609b553a32fd175 100644 (file)
@@ -38,20 +38,20 @@ OPTIONS
 
 -u[<mode>]::
 --untracked-files[=<mode>]::
-       Show untracked files (Default: 'all').
+       Show untracked files.
 +
-The mode parameter is optional, and is used to specify
-the handling of untracked files. The possible options are:
+The mode parameter is optional (defaults to 'all'), and is used to
+specify the handling of untracked files; when -u is not used, the
+default is 'normal', i.e. show untracked files and directories.
++
+The possible options are:
 +
---
        - 'no'     - Show no untracked files
        - 'normal' - Shows untracked files and directories
        - 'all'    - Also shows individual files in untracked directories.
---
 +
-See linkgit:git-config[1] for configuration variable
-used to change the default for when the option is not
-specified.
+The default can be changed using the status.showUntrackedFiles
+configuration variable documented in linkgit:git-config[1].
 
 --ignore-submodules[=<when>]::
        Ignore changes to submodules when looking for changes. <when> can be
@@ -174,14 +174,6 @@ SEE ALSO
 --------
 linkgit:gitignore[5]
 
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>.
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 7508c0e42d2cd50ac522fc80a3a866411b7b51c5..10509cc450d47de35387a547cb79e30177f6304c 100644 (file)
@@ -23,14 +23,6 @@ OPTIONS
 <stream>::
        Byte stream to act on.
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 1ed331c599d4b492b0dec112332bb83db5506d74..3a5aa01435e5fa1b19cd666e6cb357c85fd4df90 100644 (file)
@@ -257,11 +257,6 @@ This file should be formatted in the same way as `$GIT_DIR/config`. The key
 to each submodule url is "submodule.$name.url".  See linkgit:gitmodules[5]
 for details.
 
-
-AUTHOR
-------
-Written by Lars Hjemli <hjemli@gmail.com>
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 0ade2ce54efee3cd2241fc7e3009909eef5cf8bb..ea8fafd18a7e5f79a017f0f6ea0bbfdbf947461b 100644 (file)
@@ -66,7 +66,7 @@ COMMANDS
        Set the 'rewriteRoot' option in the [svn-remote] config.
 --rewrite-uuid=<UUID>;;
        Set the 'rewriteUUID' option in the [svn-remote] config.
---username=<USER>;;
+--username=<user>;;
        For transports that SVN handles authentication for (http,
        https, and plain svn), specify the username.  For other
        transports (eg svn+ssh://), you must include the username in
@@ -443,8 +443,8 @@ OPTIONS
        Only used with the 'init' command.
        These are passed directly to 'git init'.
 
--r <ARG>::
---revision <ARG>::
+-r <arg>::
+--revision <arg>::
           Used with the 'fetch' command.
 +
 This allows revision ranges for partial/cauterized history
@@ -878,10 +878,6 @@ SEE ALSO
 --------
 linkgit:git-rebase[1]
 
-Author
-------
-Written by Eric Wong <normalperson@yhbt.net>.
-
-Documentation
--------------
-Written by Eric Wong <normalperson@yhbt.net>.
+GIT
+---
+Part of the linkgit:git[1] suite
index 33a15362949bed9e23debb7ac50db35585ed23ce..d7795ed65777c18e648ba1b23b1b63330b78c9ce 100644 (file)
@@ -53,10 +53,6 @@ and symbolic refs are used by default.
 symbolic ref were printed correctly, with status 1 if the requested
 name is not a symbolic ref, or 128 if another error occurs.
 
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 8b169e364a32afe7d2ff3fa8ae54121ed44e3788..61263fa3290598680207c93d23d44ac3cd1f34e1 100644 (file)
@@ -18,21 +18,22 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-Adds a tag reference in `.git/refs/tags/`.
+Add a tag reference in `.git/refs/tags/`, unless `-d/-l/-v` is given
+to delete, list or verify tags.
 
-Unless `-f` is given, the tag must not yet exist in
+Unless `-f` is given, the tag to be created must not yet exist in the
 `.git/refs/tags/` directory.
 
 If one of `-a`, `-s`, or `-u <key-id>` is passed, the command
-creates a 'tag' object, and requires the tag message.  Unless
+creates a 'tag' object, and requires a tag message.  Unless
 `-m <msg>` or `-F <file>` is given, an editor is started for the user to type
 in the tag message.
 
 If `-m <msg>` or `-F <file>` is given and `-a`, `-s`, and `-u <key-id>`
 are absent, `-a` is implied.
 
-Otherwise just the SHA1 object name of the commit object is
-written (i.e. a lightweight tag).
+Otherwise just a tag reference for the SHA1 object name of the commit object is
+created (i.e. a lightweight tag).
 
 A GnuPG signed tag object will be created when `-s` or `-u
 <key-id>` is used.  When `-u <key-id>` is not used, the
@@ -261,15 +262,6 @@ SEE ALSO
 --------
 linkgit:git-check-ref-format[1].
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>,
-Junio C Hamano <gitster@pobox.com> and Chris Wright <chrisw@osdl.org>.
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 3c786bd283ce839ca9339f0a8ac7412a1f985d3a..5f1575425743118ffb13567472ae81be56698566 100644 (file)
@@ -76,14 +76,6 @@ git tar-tree HEAD:Documentation/ git-docs > git-1.4.0-docs.tar::
        Put everything in the current head's Documentation/ directory
        into 'git-1.4.0-docs.tar', with the prefix 'git-docs/'.
 
-Author
-------
-Written by Rene Scharfe.
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 995db9feadf68df6f22de745d90790a145128e44..c49d727f7463446c4182807cbd9077db5e34007f 100644 (file)
@@ -22,14 +22,6 @@ OPTIONS
 <blob>::
        Must be a blob id
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 36d1038056101a459a33e32b6729d75e03f127ce..dd7799095b4dd26a1625015f3fe0fcbd89dd0e70 100644 (file)
@@ -43,15 +43,6 @@ OPTIONS
 --strict::
        Don't write objects with broken content or links.
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
--------------
-Documentation by Junio C Hamano
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 1ca56c85aa66b96dc1774b77ba1e117d93847033..d3931294d174e5c06adb81e428e31e00fbfa3b5e 100644 (file)
@@ -365,15 +365,6 @@ SEE ALSO
 linkgit:git-config[1],
 linkgit:git-add[1]
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 9639f705afafab6fcf0cd21ad2693627ab42f66d..e25a65a80fafb7143957247e2fd85d64a701ddf5 100644 (file)
@@ -84,10 +84,6 @@ An update will fail (without changing <ref>) if the current user is
 unable to create a new log file, append to the existing log file
 or does not have committer information available.
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 035cc3018f22a9e2669c94f10475624d02f4098a..775024da3ed6ed50e8aa587dc31eb79f00030e84 100644 (file)
@@ -38,15 +38,6 @@ what they are for:
 
 * info/refs
 
-
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
-Documentation
---------------
-Documentation by Junio C Hamano.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index f5f2b3908b2a1550f44ad6615d9335d40e264112..acbf634f85c72d70bbb7dd7653aded63d67dcbf6 100644 (file)
@@ -24,14 +24,6 @@ OPTIONS
 <directory>::
        The repository to get a tar archive from.
 
-Author
-------
-Written by Franck Bui-Huu.
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 71ca4ef442e08acad27b4d7873a7f153dc4c79dc..4c0ca9ded25a27c11636ef9af5f7c1f2e6970c12 100644 (file)
@@ -33,14 +33,6 @@ OPTIONS
 <directory>::
        The repository to sync from.
 
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by Junio C Hamano.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 458f3e2755fcc6431757af6178942ef756f6a5bd..6498f7cb69be3d3fcece285a714679ac7f4f6454 100644 (file)
@@ -65,14 +65,6 @@ linkgit:git-commit-tree[1]
 linkgit:git-tag[1]
 linkgit:git-config[1]
 
-Author
-------
-Written by Eric Biederman <ebiederm@xmission.com>
-
-Documentation
---------------
-Documentation by Eric Biederman and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 916a38aa99020efe281907670932517a66d075e1..7c2428d5692ce7e3961821c865c9539c30dca113 100644 (file)
@@ -8,7 +8,7 @@ git-verify-pack - Validate packed git archive files
 
 SYNOPSIS
 --------
-'git verify-pack' [-v|--verbose] [--] <pack>.idx ...
+'git verify-pack' [-v|--verbose] [-s|--stat-only] [--] <pack>.idx ...
 
 
 DESCRIPTION
@@ -47,14 +47,6 @@ for objects that are not deltified in the pack, and
 
 for objects that are deltified.
 
-Author
-------
-Written by Junio C Hamano <gitster@pobox.com>
-
-Documentation
---------------
-Documentation by Junio C Hamano
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 711219749cac76ff1363ce5f27e28da9a7ecba57..8c9a71865b45120700c21a52d1e06aad45f3221f 100644 (file)
@@ -22,14 +22,6 @@ OPTIONS
 <tag>...::
        SHA1 identifiers of git tag objects.
 
-Author
-------
-Written by Jan Harkes <jaharkes@cs.cmu.edu> and Eric W. Biederman <ebiederm@xmission.com>
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index c0416e5e1a5243ef228173a3a45bb47bf1f3a840..69d92fa00ef91dff0346925ba1c50857132e9c03 100644 (file)
@@ -116,16 +116,6 @@ $ git config --global web.browser firefox
 as they are probably more user specific than repository specific.
 See linkgit:git-config[1] for more information about this.
 
-Author
-------
-Written by Christian Couder <chriscool@tuxfamily.org> and the git-list
-<git@vger.kernel.org>, based on 'git mergetool' by Theodore Y. Ts'o.
-
-Documentation
--------------
-Documentation by Christian Couder <chriscool@tuxfamily.org> and the
-git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index ea753cdafce66c33a0a0e8d9a52d75c974194ad5..31f3663ae7fe2cc97d6e61b85181a02424323fb2 100644 (file)
@@ -63,17 +63,6 @@ git whatchanged --since="2 weeks ago" \-- gitk::
        The "--" is necessary to avoid confusion with the *branch* named
        'gitk'
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org> and
-Junio C Hamano <gitster@pobox.com>
-
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index bfceacacb34262b73507a87fa23995d1183a3edc..e8c94c1352a8f1a889225ee063b4c59799cbb7e6 100644 (file)
@@ -36,15 +36,6 @@ OPTIONS
        `<prefix>`.  This can be used to write the tree object
        for a subproject that is in the named subdirectory.
 
-
-Author
-------
-Written by Linus Torvalds <torvalds@osdl.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index e968ed4aa09705d98530add23135e76141ec75c2..5e57f6995a1039112c704565b380cedf9ff5b721 100644 (file)
@@ -44,9 +44,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.7.4/git.html[documentation for release 1.7.4]
+* link:v1.7.4.1/git.html[documentation for release 1.7.4.1]
 
 * release notes for
+  link:RelNotes/1.7.4.1.txt[1.7.4.1],
   link:RelNotes/1.7.4.txt[1.7.4].
 
 * link:v1.7.3.5/git.html[documentation for release 1.7.3.5]
@@ -744,16 +745,12 @@ unmerged version of a file when a merge is in progress.
 
 Authors
 -------
-* git's founding father is Linus Torvalds <torvalds@osdl.org>.
-* The current git nurse is Junio C Hamano <gitster@pobox.com>.
-* The git potty was written by Andreas Ericsson <ae@op5.se>.
-* General upbringing is handled by the git-list <git@vger.kernel.org>.
-
-Documentation
---------------
-The documentation for git suite was started by David Greaves
-<david@dgreaves.com>, and later enhanced greatly by the
-contributors on the git-list <git@vger.kernel.org>.
+Git was started by Linus Torvalds, and is currently maintained by Junio
+C Hamano. Numerous contributions have come from the git mailing list
+<git@vger.kernel.org>. For a more complete list of contributors, see
+http://git-scm.com/about. If you have a clone of git.git itself, the
+output of linkgit:git-shortlog[1] and linkgit:git-blame[1] can show you
+the authors for specific parts of the project.
 
 Reporting Bugs
 --------------
index 7e7e12168eb69d43f6d7eea9cde2176e06fe73d5..15aebc60623d97053aa14f3e6463d12eb8f60f26 100644 (file)
@@ -632,7 +632,7 @@ Performing a three-way merge
 `merge`
 ^^^^^^^
 
-The attribute `merge` affects how three versions of a file is
+The attribute `merge` affects how three versions of a file are
 merged when a file-level merge is necessary during `git merge`,
 and other commands such as `git revert` and `git cherry-pick`.
 
@@ -646,15 +646,15 @@ Unset::
 
        Take the version from the current branch as the
        tentative merge result, and declare that the merge has
-       conflicts.  This is suitable for binary files that does
+       conflicts.  This is suitable for binary files that do
        not have a well-defined merge semantics.
 
 Unspecified::
 
        By default, this uses the same built-in 3-way merge
-       driver as is the case the `merge` attribute is set.
-       However, `merge.default` configuration variable can name
-       different merge driver to be used for paths to which the
+       driver as is the case when the `merge` attribute is set.
+       However, the `merge.default` configuration variable can name
+       different merge driver to be used with paths for which the
        `merge` attribute is unspecified.
 
 String::
index 6928724a05f304c430e8d7f60cc35d22e4873bca..f734f97b8e1b64f2d3bfc926e92e9226ba716289 100644 (file)
@@ -169,10 +169,6 @@ See also http://marc.info/?l=git&m=116563135620359 and
 http://marc.info/?l=git&m=119150393620273 for further
 information.
 
-Documentation
--------------
-Documentation by Pierre Habouzit and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 8416f3445a5e5d3b583733136d4211b8d0bd4084..2e7328b8306f4e949e22456b33d495226c1f014b 100644 (file)
@@ -156,11 +156,6 @@ SEE ALSO
 linkgit:git-rm[1], linkgit:git-update-index[1],
 linkgit:gitrepository-layout[5]
 
-Documentation
--------------
-Documentation by David Greaves, Junio C Hamano, Josh Triplett,
-Frank Lichtenheld, and the git-list <git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index e21bac4f3f16a6d0c0b1ff6d3062e8464e182e7f..e10ac58cae4f0a825f391a5fa1eab8114aa27a18 100644 (file)
@@ -113,15 +113,6 @@ SEE ALSO
        A minimal repository browser and git tool output highlighter written
        in C using Ncurses.
 
-Author
-------
-Written by Paul Mackerras <paulus@samba.org>.
-
-Documentation
---------------
-Documentation by Junio C Hamano, Jonas Fonseca, and the git-list
-<git@vger.kernel.org>.
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index 68977943e7bba092f5e55e6ad1b9ede83f4c2b67..15a218655970de61781e1b2793576a05b0fac7b2 100644 (file)
@@ -90,10 +90,6 @@ SEE ALSO
 --------
 linkgit:git-submodule[1] linkgit:git-config[1]
 
-DOCUMENTATION
--------------
-Documentation by Lars Hjemli <hjemli@gmail.com>
-
 GIT
 ---
 Part of the linkgit:git[1] suite
index f04b48ef0d482f03f186d749768da246aabcd1db..33716a31d0c60093c14f894ef07a87bee73fafc9 100644 (file)
@@ -273,6 +273,29 @@ This commit is referred to as a "merge commit", or sometimes just a
        <<def_pack,pack>>, to assist in efficiently accessing the contents of a
        pack.
 
+[[def_pathspec]]pathspec::
+       Pattern used to specify paths.
++
+Pathspecs are used on the command line of "git ls-files", "git
+ls-tree", "git grep", "git checkout", and many other commands to
+limit the scope of operations to some subset of the tree or
+worktree.  See the documentation of each command for whether
+paths are relative to the current directory or toplevel.  The
+pathspec syntax is as follows:
+
+* any path matches itself
+* the pathspec up to the last slash represents a
+  directory prefix.  The scope of that pathspec is
+  limited to that subtree.
+* the rest of the pathspec is a pattern for the remainder
+  of the pathname.  Paths relative to the directory
+  prefix will be matched against that pattern using fnmatch(3);
+  in particular, '*' and '?' _can_ match directory separators.
++
+For example, Documentation/*.jpg will match all .jpg files
+in the Documentation subtree,
+including Documentation/chapter_1/figure_1.jpg.
+
 [[def_parent]]parent::
        A <<def_commit_object,commit object>> contains a (possibly empty) list
        of the logical predecessor(s) in the line of development, i.e. its
index 0953a50b693307976977c81a4c0b611fd5dfb490..2933056120bf0a0d6249c6951ab1e964ae40674b 100644 (file)
@@ -71,5 +71,5 @@ Additional tips
   relevant parts of your tree.
 
 - Please note that if the other project merges from you, then it will
-  connects its history to yours, which can be something they don't want
+  connect its history to yours, which can be something they don't want
   to.
index 1e5c22c5e5c19dab5d5c35ec2401870237830a5d..33bf74c334ead9ee5e44d81d15d544b0625f2894 100644 (file)
@@ -33,10 +33,10 @@ merge.stat::
 
 merge.tool::
        Controls which merge resolution program is used by
-       linkgit:git-mergetool[1].  Valid built-in values are: "kdiff3",
-       "tkdiff", "meld", "xxdiff", "emerge", "vimdiff", "gvimdiff",
-       "diffuse", "ecmerge", "tortoisemerge", "p4merge", "araxis" and
-       "opendiff".  Any other value is treated is custom merge tool
+       linkgit:git-mergetool[1].  Valid built-in values are: "araxis",
+       "bc3", "diffuse", "ecmerge", "emerge", "gvimdiff", "kdiff3", "meld",
+       "opendiff", "p4merge", "tkdiff", "tortoisemerge", "vimdiff"
+       and "xxdiff".  Any other value is treated is custom merge tool
        and there must be a corresponding mergetool.<tool>.cmd option.
 
 merge.verbosity::
index e33e0f8e110879a0cd6fe81d97ee6044290e5cfa..b613d4ed083d080797f7da90fc92212f98611d07 100644 (file)
@@ -75,9 +75,17 @@ option can be used to override --squash.
 ifndef::git-pull[]
 -q::
 --quiet::
-       Operate quietly.
+       Operate quietly. Implies --no-progress.
 
 -v::
 --verbose::
        Be verbose.
+
+--progress::
+--no-progress::
+       Turn progress on/off explicitly. If neither is specified,
+       progress is shown if standard error is connected to a terminal.
+       Note that not all merge strategies may support progress
+       reporting.
+
 endif::git-pull[]
index 44a2ef1de15bdce5d67a151a1cb6150031e57c7e..5c6850f0486dbea0c515e2323bc6455d89897628 100644 (file)
-Commit Formatting
-~~~~~~~~~~~~~~~~~
-
-ifdef::git-rev-list[]
-Using these options, linkgit:git-rev-list[1] will act similar to the
-more specialized family of commit log tools: linkgit:git-log[1],
-linkgit:git-show[1], and linkgit:git-whatchanged[1]
-endif::git-rev-list[]
-
-include::pretty-options.txt[]
-
---relative-date::
-
-       Synonym for `--date=relative`.
-
---date=(relative|local|default|iso|rfc|short|raw)::
-
-       Only takes effect for dates shown in human-readable format, such
-       as when using "--pretty". `log.date` config variable sets a default
-       value for log command's --date option.
-+
-`--date=relative` shows dates relative to the current time,
-e.g. "2 hours ago".
-+
-`--date=local` shows timestamps in user's local timezone.
-+
-`--date=iso` (or `--date=iso8601`) shows timestamps in ISO 8601 format.
-+
-`--date=rfc` (or `--date=rfc2822`) shows timestamps in RFC 2822
-format, often found in E-mail messages.
-+
-`--date=short` shows only date but not time, in `YYYY-MM-DD` format.
-+
-`--date=raw` shows the date in the internal raw git format `%s %z` format.
-+
-`--date=default` shows timestamps in the original timezone
-(either committer's or author's).
-
-ifdef::git-rev-list[]
---header::
-
-       Print the contents of the commit in raw-format; each record is
-       separated with a NUL character.
-endif::git-rev-list[]
-
---parents::
-
-       Print also the parents of the commit (in the form "commit parent...").
-       Also enables parent rewriting, see 'History Simplification' below.
-
---children::
-
-       Print also the children of the commit (in the form "commit child...").
-       Also enables parent rewriting, see 'History Simplification' below.
-
-ifdef::git-rev-list[]
---timestamp::
-       Print the raw commit timestamp.
-endif::git-rev-list[]
-
---left-right::
-
-       Mark which side of a symmetric diff a commit is reachable from.
-       Commits from the left side are prefixed with `<` and those from
-       the right with `>`.  If combined with `--boundary`, those
-       commits are prefixed with `-`.
-+
-For example, if you have this topology:
-+
------------------------------------------------------------------------
-             y---b---b  branch B
-            / \ /
-           /   .
-          /   / \
-         o---x---a---a  branch A
------------------------------------------------------------------------
-+
-you would get an output like this:
-+
------------------------------------------------------------------------
-       $ git rev-list --left-right --boundary --pretty=oneline A...B
-
-       >bbbbbbb... 3rd on b
-       >bbbbbbb... 2nd on b
-       <aaaaaaa... 3rd on a
-       <aaaaaaa... 2nd on a
-       -yyyyyyy... 1st on b
-       -xxxxxxx... 1st on a
------------------------------------------------------------------------
-
---graph::
-
-       Draw a text-based graphical representation of the commit history
-       on the left hand side of the output.  This may cause extra lines
-       to be printed in between commits, in order for the graph history
-       to be drawn properly.
-+
-This enables parent rewriting, see 'History Simplification' below.
-+
-This implies the '--topo-order' option by default, but the
-'--date-order' option may also be specified.
-
-ifdef::git-rev-list[]
---count::
-       Print a number stating how many commits would have been
-       listed, and suppress all other output.  When used together
-       with '--left-right', instead print the counts for left and
-       right commits, separated by a tab.
-endif::git-rev-list[]
-
-
-ifndef::git-rev-list[]
-Diff Formatting
-~~~~~~~~~~~~~~~
-
-Below are listed options that control the formatting of diff output.
-Some of them are specific to linkgit:git-rev-list[1], however other diff
-options may be given. See linkgit:git-diff-files[1] for more options.
-
--c::
-
-       With this option, diff output for a merge commit
-       shows the differences from each of the parents to the merge result
-       simultaneously instead of showing pairwise diff between a parent
-       and the result one at a time. Furthermore, it lists only files
-       which were modified from all parents.
-
---cc::
-
-       This flag implies the '-c' options and further compresses the
-       patch output by omitting uninteresting hunks whose contents in
-       the parents have only two variants and the merge result picks
-       one of them without modification.
-
--m::
-
-       This flag makes the merge commits show the full diff like
-       regular commits; for each merge parent, a separate log entry
-       and diff is generated. An exception is that only diff against
-       the first parent is shown when '--first-parent' option is given;
-       in that case, the output represents the changes the merge
-       brought _into_ the then-current branch.
-
--r::
-
-       Show recursive diffs.
-
--t::
-
-       Show the tree objects in the diff output. This implies '-r'.
-
--s::
-       Suppress diff output.
-endif::git-rev-list[]
-
 Commit Limiting
 ~~~~~~~~~~~~~~~
 
 Besides specifying a range of commits that should be listed using the
 special notations explained in the description, additional commit
-limiting may be applied.
+limiting may be applied. Note that they are applied before commit
+ordering and formatting options, such as '--reverse'.
 
 --
 
 -n 'number'::
 --max-count=<number>::
 
-       Limit the number of commits output.
+       Limit the number of commits to output.
 
 --skip=<number>::
 
@@ -305,6 +151,11 @@ ifdef::git-rev-list[]
        to /dev/null as the output does not have to be formatted.
 endif::git-rev-list[]
 
+--cherry-mark::
+
+       Like `--cherry-pick` (see below) but mark equivalent commits
+       with `=` rather than omitting them, and inequivalent ones with `+`.
+
 --cherry-pick::
 
        Omit any commit that introduces the same change as
@@ -319,6 +170,27 @@ from the other branch (for example, "3rd on b" may be cherry-picked
 from branch A).  With this option, such pairs of commits are
 excluded from the output.
 
+--left-only::
+--right-only::
+
+       List only commits on the respective side of a symmetric range,
+       i.e. only those which would be marked `<` resp. `>` by
+       `--left-right`.
++
+For example, `--cherry-pick --right-only A...B` omits those
+commits from `B` which are in `A` or are patch-equivalent to a commit in
+`A`. In other words, this lists the `{plus}` commits from `git cherry A B`.
+More precisely, `--cherry-pick --right-only --no-merges` gives the exact
+list.
+
+--cherry::
+
+       A synonym for `--right-only --cherry-mark --no-merges`; useful to
+       limit the output to the commits on our side and mark those that
+       have been applied to the other side of a forked history with
+       `git log --cherry upstream...mybranch`, similar to
+       `git cherry upstream mybranch`.
+
 -g::
 --walk-reflogs::
 
@@ -735,3 +607,158 @@ These options are mostly targeted for packing of git repositories.
 --do-walk::
 
        Overrides a previous --no-walk.
+
+Commit Formatting
+~~~~~~~~~~~~~~~~~
+
+ifdef::git-rev-list[]
+Using these options, linkgit:git-rev-list[1] will act similar to the
+more specialized family of commit log tools: linkgit:git-log[1],
+linkgit:git-show[1], and linkgit:git-whatchanged[1]
+endif::git-rev-list[]
+
+include::pretty-options.txt[]
+
+--relative-date::
+
+       Synonym for `--date=relative`.
+
+--date=(relative|local|default|iso|rfc|short|raw)::
+
+       Only takes effect for dates shown in human-readable format, such
+       as when using "--pretty". `log.date` config variable sets a default
+       value for log command's --date option.
++
+`--date=relative` shows dates relative to the current time,
+e.g. "2 hours ago".
++
+`--date=local` shows timestamps in user's local timezone.
++
+`--date=iso` (or `--date=iso8601`) shows timestamps in ISO 8601 format.
++
+`--date=rfc` (or `--date=rfc2822`) shows timestamps in RFC 2822
+format, often found in E-mail messages.
++
+`--date=short` shows only date but not time, in `YYYY-MM-DD` format.
++
+`--date=raw` shows the date in the internal raw git format `%s %z` format.
++
+`--date=default` shows timestamps in the original timezone
+(either committer's or author's).
+
+ifdef::git-rev-list[]
+--header::
+
+       Print the contents of the commit in raw-format; each record is
+       separated with a NUL character.
+endif::git-rev-list[]
+
+--parents::
+
+       Print also the parents of the commit (in the form "commit parent...").
+       Also enables parent rewriting, see 'History Simplification' below.
+
+--children::
+
+       Print also the children of the commit (in the form "commit child...").
+       Also enables parent rewriting, see 'History Simplification' below.
+
+ifdef::git-rev-list[]
+--timestamp::
+       Print the raw commit timestamp.
+endif::git-rev-list[]
+
+--left-right::
+
+       Mark which side of a symmetric diff a commit is reachable from.
+       Commits from the left side are prefixed with `<` and those from
+       the right with `>`.  If combined with `--boundary`, those
+       commits are prefixed with `-`.
++
+For example, if you have this topology:
++
+-----------------------------------------------------------------------
+            y---b---b  branch B
+           / \ /
+          /   .
+         /   / \
+        o---x---a---a  branch A
+-----------------------------------------------------------------------
++
+you would get an output like this:
++
+-----------------------------------------------------------------------
+       $ git rev-list --left-right --boundary --pretty=oneline A...B
+
+       >bbbbbbb... 3rd on b
+       >bbbbbbb... 2nd on b
+       <aaaaaaa... 3rd on a
+       <aaaaaaa... 2nd on a
+       -yyyyyyy... 1st on b
+       -xxxxxxx... 1st on a
+-----------------------------------------------------------------------
+
+--graph::
+
+       Draw a text-based graphical representation of the commit history
+       on the left hand side of the output.  This may cause extra lines
+       to be printed in between commits, in order for the graph history
+       to be drawn properly.
++
+This enables parent rewriting, see 'History Simplification' below.
++
+This implies the '--topo-order' option by default, but the
+'--date-order' option may also be specified.
+
+ifdef::git-rev-list[]
+--count::
+       Print a number stating how many commits would have been
+       listed, and suppress all other output.  When used together
+       with '--left-right', instead print the counts for left and
+       right commits, separated by a tab.
+endif::git-rev-list[]
+
+
+ifndef::git-rev-list[]
+Diff Formatting
+~~~~~~~~~~~~~~~
+
+Below are listed options that control the formatting of diff output.
+Some of them are specific to linkgit:git-rev-list[1], however other diff
+options may be given. See linkgit:git-diff-files[1] for more options.
+
+-c::
+
+       With this option, diff output for a merge commit
+       shows the differences from each of the parents to the merge result
+       simultaneously instead of showing pairwise diff between a parent
+       and the result one at a time. Furthermore, it lists only files
+       which were modified from all parents.
+
+--cc::
+
+       This flag implies the '-c' options and further compresses the
+       patch output by omitting uninteresting hunks whose contents in
+       the parents have only two variants and the merge result picks
+       one of them without modification.
+
+-m::
+
+       This flag makes the merge commits show the full diff like
+       regular commits; for each merge parent, a separate log entry
+       and diff is generated. An exception is that only diff against
+       the first parent is shown when '--first-parent' option is given;
+       in that case, the output represents the changes the merge
+       brought _into_ the then-current branch.
+
+-r::
+
+       Show recursive diffs.
+
+-t::
+
+       Show the tree objects in the diff output. This implies '-r'.
+
+-s::
+       Suppress diff output.
+endif::git-rev-list[]
index 9e92734bc1b308c47e5f5726c704a3ddffa5beb9..04fceee2535d91b9cec9157e5219a81fc63a5dce 100644 (file)
@@ -25,7 +25,8 @@ blobs contained in a commit.
   first match in the following rules:
 
   . if `$GIT_DIR/<name>` exists, that is what you mean (this is usually
-    useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD` and `MERGE_HEAD`);
+    useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD`, `MERGE_HEAD`
+    and `CHERRY_PICK_HEAD`);
 
   . otherwise, `refs/<name>` if exists;
 
@@ -46,6 +47,8 @@ you can change the tip of the branch back to the state before you ran
 them easily.
 MERGE_HEAD records the commit(s) you are merging into your branch
 when you run 'git merge'.
+CHERRY_PICK_HEAD records the commit you are cherry-picking
+when you run 'git cherry-pick'.
 +
 Note that any of the `refs/*` cases above may come either from
 the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file.
index 775ee838c332c7311df34a98448fc3723c6bd95e..654d8ac7e14a2118b1fd2014fb13a6b5d4c50c64 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -216,6 +216,11 @@ all::
 #
 # Define NO_REGEX if you have no or inferior regex support in your C library.
 #
+# Define GETTEXT_POISON if you are debugging the choice of strings marked
+# for translation.  In a GETTEXT_POISON build, you can turn all strings marked
+# for translation into gibberish by setting the GIT_GETTEXT_POISON variable
+# (to any value) in your environment.
+#
 # Define JSMIN to point to JavaScript minifier that functions as
 # a filter to have gitweb.js minified.
 #
@@ -316,6 +321,7 @@ INSTALL = install
 RPMBUILD = rpmbuild
 TCL_PATH = tclsh
 TCLTK_PATH = wish
+XGETTEXT = xgettext
 PTHREAD_LIBS = -lpthread
 PTHREAD_CFLAGS =
 GCOV = gcov
@@ -435,6 +441,7 @@ TEST_PROGRAMS_NEED_X += test-subprocess
 TEST_PROGRAMS_NEED_X += test-svn-fe
 TEST_PROGRAMS_NEED_X += test-treap
 TEST_PROGRAMS_NEED_X += test-index-version
+TEST_PROGRAMS_NEED_X += test-mktemp
 
 TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
 
@@ -514,6 +521,7 @@ LIB_H += diff.h
 LIB_H += dir.h
 LIB_H += exec_cmd.h
 LIB_H += fsck.h
+LIB_H += gettext.h
 LIB_H += git-compat-util.h
 LIB_H += graph.h
 LIB_H += grep.h
@@ -1041,6 +1049,7 @@ ifeq ($(uname_S),HP-UX)
        NO_UNSETENV = YesPlease
        NO_HSTRERROR = YesPlease
        NO_SYS_SELECT_H = YesPlease
+       NO_FNMATCH_CASEFOLD = YesPlease
        SNPRINTF_RETURNS_BOGUS = YesPlease
        NO_NSEC = YesPlease
        ifeq ($(uname_R),B.11.00)
@@ -1368,6 +1377,10 @@ endif
 ifdef NO_SYMLINK_HEAD
        BASIC_CFLAGS += -DNO_SYMLINK_HEAD
 endif
+ifdef GETTEXT_POISON
+       LIB_OBJS += gettext.o
+       BASIC_CFLAGS += -DGETTEXT_POISON
+endif
 ifdef NO_STRCASESTR
        COMPAT_CFLAGS += -DNO_STRCASESTR
        COMPAT_OBJS += compat/strcasestr.o
@@ -1579,6 +1592,7 @@ ifndef V
        QUIET_BUILT_IN = @echo '   ' BUILTIN $@;
        QUIET_GEN      = @echo '   ' GEN $@;
        QUIET_LNCP     = @echo '   ' LN/CP $@;
+       QUIET_XGETTEXT = @echo '   ' XGETTEXT $@;
        QUIET_GCOV     = @echo '   ' GCOV $@;
        QUIET_SUBDIR0  = +@subdir=
        QUIET_SUBDIR1  = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \
@@ -2046,6 +2060,20 @@ info:
 pdf:
        $(MAKE) -C Documentation pdf
 
+XGETTEXT_FLAGS = \
+       --force-po \
+       --add-comments \
+       --msgid-bugs-address="Git Mailing List <git@vger.kernel.org>" \
+       --from-code=UTF-8
+XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --keyword=_ --keyword=N_ --language=C
+LOCALIZED_C := $(C_OBJ:o=c)
+
+po/git.pot: $(LOCALIZED_C)
+       $(QUIET_XGETTEXT)$(XGETTEXT) -o$@+ $(XGETTEXT_FLAGS_C) $(LOCALIZED_C) && \
+       mv $@+ $@
+
+pot: po/git.pot
+
 $(ETAGS_TARGET): FORCE
        $(RM) $(ETAGS_TARGET)
        $(FIND) . -name '*.[hcS]' -print | xargs etags -a -o $(ETAGS_TARGET)
@@ -2087,6 +2115,7 @@ endif
 ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT
        @echo GIT_TEST_CMP_USE_COPIED_CONTEXT=YesPlease >>$@
 endif
+       @echo GETTEXT_POISON=\''$(subst ','\'',$(subst ','\'',$(GETTEXT_POISON)))'\' >>$@
 
 ### Detect Tck/Tk interpreter path changes
 ifndef NO_TCLTK
@@ -2312,6 +2341,7 @@ dist-doc:
 
 distclean: clean
        $(RM) configure
+       $(RM) po/git.pot
 
 clean:
        $(RM) *.o block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o xdiff/*.o vcs-svn/*.o \
index b942e499449d97aeb50c73ca2bdc1c6e6d528743..540b756d2f64d8c8ebf927a707b9b2cc0a4c6151 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.7.4.txt
\ No newline at end of file
+Documentation/RelNotes/1.7.5.txt
\ No newline at end of file
index 91ca00f05f7d648fa801a36b78c749f9d691ba43..3005aedde68b48297aacd2082797b2e2f249b094 100644 (file)
--- a/abspath.c
+++ b/abspath.c
@@ -14,7 +14,14 @@ int is_directory(const char *path)
 /* We allow "recursive" symbolic links. Only within reason, though. */
 #define MAXDEPTH 5
 
-const char *make_absolute_path(const char *path)
+/*
+ * Use this to get the real path, i.e. resolve links. If you want an
+ * absolute path but don't mind links, use absolute_path.
+ *
+ * If path is our buffer, then return path, as it's already what the
+ * user wants.
+ */
+const char *real_path(const char *path)
 {
        static char bufs[2][PATH_MAX + 1], *buf = bufs[0], *next_buf = bufs[1];
        char cwd[1024] = "";
@@ -24,6 +31,10 @@ const char *make_absolute_path(const char *path)
        char *last_elem = NULL;
        struct stat st;
 
+       /* We've already done it */
+       if (path == buf || path == next_buf)
+               return path;
+
        if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
                die ("Too long path: %.*s", 60, path);
 
@@ -100,7 +111,14 @@ static const char *get_pwd_cwd(void)
        return cwd;
 }
 
-const char *make_nonrelative_path(const char *path)
+/*
+ * Use this to get an absolute path from a relative one. If you want
+ * to resolve links, you should use real_path.
+ *
+ * If the path is already absolute, then return path. As the user is
+ * never meant to free the return value, we're safe.
+ */
+const char *absolute_path(const char *path)
 {
        static char buf[PATH_MAX + 1];
 
index d399de2671bff39ee34b55017c179242010d643f..f11bc7ed7df2f6b058f947bfe850abb33590bfa7 100644 (file)
@@ -13,7 +13,7 @@ AC_DEFUN([TYPE_SOCKLEN_T],
          git_cv_socklen_t_equiv=
          for arg2 in "struct sockaddr" void; do
             for t in int size_t unsigned long "unsigned long"; do
-               AC_TRY_COMPILE([
+               AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
                   #include <sys/types.h>
                   #include <sys/socket.h>
 
@@ -21,7 +21,7 @@ AC_DEFUN([TYPE_SOCKLEN_T],
                ],[
                   $t len;
                   getpeername(0,0,&len);
-               ],[
+               ])],[
                   git_cv_socklen_t_equiv="$t"
                   break 2
                ])
diff --git a/attr.c b/attr.c
index 6aff6951d38d7f672aeb9851eca88c6e5a26b950..0e28ba871f9ba0da129610019cd0d0246f3a15f0 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -478,11 +478,6 @@ int git_attr_system(void)
        return !git_env_bool("GIT_ATTR_NOSYSTEM", 0);
 }
 
-int git_attr_global(void)
-{
-       return !git_env_bool("GIT_ATTR_NOGLOBAL", 0);
-}
-
 static int git_attr_config(const char *var, const char *value, void *dummy)
 {
        if (!strcmp(var, "core.attributesfile"))
@@ -511,7 +506,7 @@ static void bootstrap_attr_stack(void)
                }
 
                git_config(git_attr_config, NULL);
-               if (git_attr_global() && attributes_file) {
+               if (attributes_file) {
                        elem = read_attr_from_file(attributes_file, 1);
                        if (elem) {
                                elem->origin = NULL;
index 93dc866f8c09a2da2308c4fd677178b043f2d4d5..c0c865a4b1b0fca038f32b77f2239d7987438ff5 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -175,9 +175,14 @@ void create_branch(const char *head,
                        die("Cannot setup tracking information; starting point is not a branch.");
                break;
        case 1:
-               /* Unique completion -- good, only if it is a real ref */
-               if (explicit_tracking && !strcmp(real_ref, "HEAD"))
-                       die("Cannot setup tracking information; starting point is not a branch.");
+               /* Unique completion -- good, only if it is a real branch */
+               if (prefixcmp(real_ref, "refs/heads/") &&
+                   prefixcmp(real_ref, "refs/remotes/")) {
+                       if (explicit_tracking)
+                               die("Cannot setup tracking information; starting point is not a branch.");
+                       else
+                               real_ref = NULL;
+               }
                break;
        default:
                die("Ambiguous object name: '%s'.", start_name);
@@ -217,6 +222,7 @@ void create_branch(const char *head,
 
 void remove_branch_state(void)
 {
+       unlink(git_path("CHERRY_PICK_HEAD"));
        unlink(git_path("MERGE_HEAD"));
        unlink(git_path("MERGE_RR"));
        unlink(git_path("MERGE_MSG"));
index 904e067a88f242b42f16b715d2b67b45a101e468..0e9da9083491eb3c18464b730f481cf74ee82430 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -57,6 +57,7 @@ extern int cmd_clone(int argc, const char **argv, const char *prefix);
 extern int cmd_clean(int argc, const char **argv, const char *prefix);
 extern int cmd_commit(int argc, const char **argv, const char *prefix);
 extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
+extern int cmd_config(int argc, const char **argv, const char *prefix);
 extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
 extern int cmd_describe(int argc, const char **argv, const char *prefix);
 extern int cmd_diff_files(int argc, const char **argv, const char *prefix);
@@ -110,7 +111,7 @@ extern int cmd_reflog(int argc, const char **argv, const char *prefix);
 extern int cmd_remote(int argc, const char **argv, const char *prefix);
 extern int cmd_remote_ext(int argc, const char **argv, const char *prefix);
 extern int cmd_remote_fd(int argc, const char **argv, const char *prefix);
-extern int cmd_config(int argc, const char **argv, const char *prefix);
+extern int cmd_repo_config(int argc, const char **argv, const char *prefix);
 extern int cmd_rerere(int argc, const char **argv, const char *prefix);
 extern int cmd_reset(int argc, const char **argv, const char *prefix);
 extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
index 12b964e642b91863776f161a7b2aab2ec216efcb..e127d5a68b5c28497a3e640760e4c597fbaa59d5 100644 (file)
@@ -21,8 +21,7 @@ static const char * const builtin_add_usage[] = {
 static int patch_interactive, add_interactive, edit_interactive;
 static int take_worktree_changes;
 
-struct update_callback_data
-{
+struct update_callback_data {
        int flags;
        int add_errors;
 };
@@ -86,7 +85,7 @@ int add_files_to_cache(const char *prefix, const char **pathspec, int flags)
        struct rev_info rev;
        init_revisions(&rev, prefix);
        setup_revisions(0, NULL, &rev, NULL);
-       rev.prune_data = pathspec;
+       init_pathspec(&rev.prune_data, pathspec);
        rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
        rev.diffopt.format_callback = update_callback;
        data.flags = flags;
@@ -317,12 +316,12 @@ static struct option builtin_add_options[] = {
        OPT__VERBOSE(&verbose, "be verbose"),
        OPT_GROUP(""),
        OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
-       OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
+       OPT_BOOLEAN('p', "patch", &patch_interactive, "select hunks interactively"),
        OPT_BOOLEAN('e', "edit", &edit_interactive, "edit current diff and apply"),
        OPT__FORCE(&ignored_too, "allow adding otherwise ignored files"),
        OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
        OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"),
-       OPT_BOOLEAN('A', "all", &addremove, "add all, noticing removal of tracked files"),
+       OPT_BOOLEAN('A', "all", &addremove, "add changes from all tracked and untracked files"),
        OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
        OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, "just skip files which cannot be added because of errors"),
        OPT_BOOLEAN( 0 , "ignore-missing", &ignore_missing, "check if - even missing - files are ignored in dry run"),
index 14951daedffa9e8a8a913eee5e8423220e86e291..36e150768ba88e427e6257900d7ec4c67c8303c1 100644 (file)
@@ -204,6 +204,7 @@ struct line {
        unsigned hash : 24;
        unsigned flag : 8;
 #define LINE_COMMON     1
+#define LINE_PATCHED   2
 };
 
 /*
@@ -2085,7 +2086,8 @@ static int match_fragment(struct image *img,
 
        /* Quick hash check */
        for (i = 0; i < preimage_limit; i++)
-               if (preimage->line[i].hash != img->line[try_lno + i].hash)
+               if ((img->line[try_lno + i].flag & LINE_PATCHED) ||
+                   (preimage->line[i].hash != img->line[try_lno + i].hash))
                        return 0;
 
        if (preimage_limit == preimage->nr) {
@@ -2428,11 +2430,15 @@ static void update_image(struct image *img,
        memcpy(img->line + applied_pos,
               postimage->line,
               postimage->nr * sizeof(*img->line));
+       for (i = 0; i < postimage->nr; i++)
+               img->line[applied_pos + i].flag |= LINE_PATCHED;
+
        img->nr = nr;
 }
 
 static int apply_one_fragment(struct image *img, struct fragment *frag,
-                             int inaccurate_eof, unsigned ws_rule)
+                             int inaccurate_eof, unsigned ws_rule,
+                             int nth_fragment)
 {
        int match_beginning, match_end;
        const char *patch = frag->patch;
@@ -2638,6 +2644,15 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
                                apply = 0;
                }
 
+               if (apply_verbosely && applied_pos != pos) {
+                       int offset = applied_pos - pos;
+                       if (apply_in_reverse)
+                               offset = 0 - offset;
+                       fprintf(stderr,
+                               "Hunk #%d succeeded at %d (offset %d lines).\n",
+                               nth_fragment, applied_pos + 1, offset);
+               }
+
                /*
                 * Warn if it was necessary to reduce the number
                 * of context lines.
@@ -2785,12 +2800,14 @@ static int apply_fragments(struct image *img, struct patch *patch)
        const char *name = patch->old_name ? patch->old_name : patch->new_name;
        unsigned ws_rule = patch->ws_rule;
        unsigned inaccurate_eof = patch->inaccurate_eof;
+       int nth = 0;
 
        if (patch->is_binary)
                return apply_binary(img, patch);
 
        while (frag) {
-               if (apply_one_fragment(img, frag, inaccurate_eof, ws_rule)) {
+               nth++;
+               if (apply_one_fragment(img, frag, inaccurate_eof, ws_rule, nth)) {
                        error("patch failed: %s:%ld", name, frag->oldpos);
                        if (!apply_with_reject)
                                return -1;
index aa30ec52692558b0d8ed3dc3b6d671185682026e..f6b03f750a0b69ef835caa0a2e4988f9a08abb85 100644 (file)
@@ -1312,8 +1312,7 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
 /*
  * Information on commits, used for output.
  */
-struct commit_info
-{
+struct commit_info {
        const char *author;
        const char *author_mail;
        unsigned long author_time;
index 9e546e4a83d07dd6dd4d4b0cb7d23a02c82747fb..b9ba011f7b3f37a9448afae909d743249c3d8e1f 100644 (file)
@@ -134,7 +134,7 @@ static int branch_merged(int kind, const char *name,
            in_merge_bases(rev, &head_rev, 1) != merged) {
                if (merged)
                        warning("deleting branch '%s' that has been merged to\n"
-                               "         '%s', but it is not yet merged to HEAD.",
+                               "         '%s', but not yet been merged to HEAD.",
                                name, reference_name);
                else
                        warning("not deleting branch '%s' that is not yet merged to\n"
@@ -390,6 +390,30 @@ static int matches_merge_filter(struct commit *commit)
        return (is_merged == (merge_filter == SHOW_MERGED));
 }
 
+static void add_verbose_info(struct strbuf *out, struct ref_item *item,
+                            int verbose, int abbrev)
+{
+       struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;
+       const char *sub = " **** invalid ref ****";
+       struct commit *commit = item->commit;
+
+       if (commit && !parse_commit(commit)) {
+               struct pretty_print_context ctx = {0};
+               pretty_print_commit(CMIT_FMT_ONELINE, commit,
+                                   &subject, &ctx);
+               sub = subject.buf;
+       }
+
+       if (item->kind == REF_LOCAL_BRANCH)
+               fill_tracking_info(&stat, item->name, verbose > 1);
+
+       strbuf_addf(out, " %s %s%s",
+               find_unique_abbrev(item->commit->object.sha1, abbrev),
+               stat.buf, sub);
+       strbuf_release(&stat);
+       strbuf_release(&subject);
+}
+
 static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
                           int abbrev, int current, char *prefix)
 {
@@ -430,27 +454,9 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
 
        if (item->dest)
                strbuf_addf(&out, " -> %s", item->dest);
-       else if (verbose) {
-               struct strbuf subject = STRBUF_INIT, stat = STRBUF_INIT;
-               const char *sub = " **** invalid ref ****";
-
-               commit = item->commit;
-               if (commit && !parse_commit(commit)) {
-                       struct pretty_print_context ctx = {0};
-                       pretty_print_commit(CMIT_FMT_ONELINE, commit,
-                                           &subject, &ctx);
-                       sub = subject.buf;
-               }
-
-               if (item->kind == REF_LOCAL_BRANCH)
-                       fill_tracking_info(&stat, item->name, verbose > 1);
-
-               strbuf_addf(&out, " %s %s%s",
-                       find_unique_abbrev(item->commit->object.sha1, abbrev),
-                       stat.buf, sub);
-               strbuf_release(&stat);
-               strbuf_release(&subject);
-       }
+       else if (verbose)
+               /* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
+               add_verbose_info(&out, item, verbose, abbrev);
        printf("%s\n", out.buf);
        strbuf_release(&name);
        strbuf_release(&out);
index 757f9a08ddbaf102726a781b06d7294a4638984e..2bf02f2841a84a2a86de08e53328dbbb87ff3587 100644 (file)
@@ -30,6 +30,7 @@ struct checkout_opts {
        int quiet;
        int merge;
        int force;
+       int force_detach;
        int writeout_stage;
        int writeout_error;
 
@@ -297,7 +298,7 @@ static void show_local_changes(struct object *head, struct diff_options *opts)
        run_diff_index(&rev, 0);
 }
 
-static void describe_detached_head(char *msg, struct commit *commit)
+static void describe_detached_head(const char *msg, struct commit *commit)
 {
        struct strbuf sb = STRBUF_INIT;
        struct pretty_print_context ctx = {0};
@@ -404,7 +405,7 @@ static int merge_working_tree(struct checkout_opts *opts,
                topts.dir->exclude_per_dir = ".gitignore";
                tree = parse_tree_indirect(old->commit ?
                                           old->commit->object.sha1 :
-                                          (unsigned char *)EMPTY_TREE_SHA1_BIN);
+                                          EMPTY_TREE_SHA1_BIN);
                init_tree_desc(&trees[0], tree->buffer, tree->size);
                tree = parse_tree_indirect(new->commit->object.sha1);
                init_tree_desc(&trees[1], tree->buffer, tree->size);
@@ -541,7 +542,17 @@ static void update_refs_for_switch(struct checkout_opts *opts,
        strbuf_addf(&msg, "checkout: moving from %s to %s",
                    old_desc ? old_desc : "(invalid)", new->name);
 
-       if (new->path) {
+       if (!strcmp(new->name, "HEAD") && !new->path && !opts->force_detach) {
+               /* Nothing to do. */
+       } else if (opts->force_detach || !new->path) {  /* No longer on any branch. */
+               update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
+                          REF_NODEREF, DIE_ON_ERR);
+               if (!opts->quiet) {
+                       if (old->path && advice_detached_head)
+                               detach_advice(old->path, new->name);
+                       describe_detached_head("HEAD is now at", new->commit);
+               }
+       } else if (new->path) { /* Switch branches. */
                create_symref("HEAD", new->path, msg.buf);
                if (!opts->quiet) {
                        if (old->path && !strcmp(new->path, old->path))
@@ -563,21 +574,108 @@ static void update_refs_for_switch(struct checkout_opts *opts,
                        if (!file_exists(ref_file) && file_exists(log_file))
                                remove_path(log_file);
                }
-       } else if (strcmp(new->name, "HEAD")) {
-               update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
-                          REF_NODEREF, DIE_ON_ERR);
-               if (!opts->quiet) {
-                       if (old->path && advice_detached_head)
-                               detach_advice(old->path, new->name);
-                       describe_detached_head("HEAD is now at", new->commit);
-               }
        }
        remove_branch_state();
        strbuf_release(&msg);
-       if (!opts->quiet && (new->path || !strcmp(new->name, "HEAD")))
+       if (!opts->quiet &&
+           (new->path || (!opts->force_detach && !strcmp(new->name, "HEAD"))))
                report_tracking(new);
 }
 
+struct rev_list_args {
+       int argc;
+       int alloc;
+       const char **argv;
+};
+
+static void add_one_rev_list_arg(struct rev_list_args *args, const char *s)
+{
+       ALLOC_GROW(args->argv, args->argc + 1, args->alloc);
+       args->argv[args->argc++] = s;
+}
+
+static int add_one_ref_to_rev_list_arg(const char *refname,
+                                      const unsigned char *sha1,
+                                      int flags,
+                                      void *cb_data)
+{
+       add_one_rev_list_arg(cb_data, refname);
+       return 0;
+}
+
+
+static void describe_one_orphan(struct strbuf *sb, struct commit *commit)
+{
+       struct pretty_print_context ctx = { 0 };
+
+       parse_commit(commit);
+       strbuf_addstr(sb, " - ");
+       pretty_print_commit(CMIT_FMT_ONELINE, commit, sb, &ctx);
+       strbuf_addch(sb, '\n');
+}
+
+#define ORPHAN_CUTOFF 4
+static void suggest_reattach(struct commit *commit, struct rev_info *revs)
+{
+       struct commit *c, *last = NULL;
+       struct strbuf sb = STRBUF_INIT;
+       int lost = 0;
+       while ((c = get_revision(revs)) != NULL) {
+               if (lost < ORPHAN_CUTOFF)
+                       describe_one_orphan(&sb, c);
+               last = c;
+               lost++;
+       }
+       if (ORPHAN_CUTOFF < lost) {
+               int more = lost - ORPHAN_CUTOFF;
+               if (more == 1)
+                       describe_one_orphan(&sb, last);
+               else
+                       strbuf_addf(&sb, " ... and %d more.\n", more);
+       }
+
+       fprintf(stderr,
+               "Warning: you are leaving %d commit%s behind, "
+               "not connected to\n"
+               "any of your branches:\n\n"
+               "%s\n"
+               "If you want to keep them by creating a new branch, "
+               "this may be a good time\nto do so with:\n\n"
+               " git branch new_branch_name %s\n\n",
+               lost, ((1 < lost) ? "s" : ""),
+               sb.buf,
+               sha1_to_hex(commit->object.sha1));
+       strbuf_release(&sb);
+}
+
+/*
+ * We are about to leave commit that was at the tip of a detached
+ * HEAD.  If it is not reachable from any ref, this is the last chance
+ * for the user to do so without resorting to reflog.
+ */
+static void orphaned_commit_warning(struct commit *commit)
+{
+       struct rev_list_args args = { 0, 0, NULL };
+       struct rev_info revs;
+
+       add_one_rev_list_arg(&args, "(internal)");
+       add_one_rev_list_arg(&args, sha1_to_hex(commit->object.sha1));
+       add_one_rev_list_arg(&args, "--not");
+       for_each_ref(add_one_ref_to_rev_list_arg, &args);
+       add_one_rev_list_arg(&args, "--");
+       add_one_rev_list_arg(&args, NULL);
+
+       init_revisions(&revs, NULL);
+       if (setup_revisions(args.argc - 1, args.argv, &revs, NULL) != 1)
+               die("internal error: only -- alone should have been left");
+       if (prepare_revision_walk(&revs))
+               die("internal error in revision walk");
+       if (!(commit->object.flags & UNINTERESTING))
+               suggest_reattach(commit, &revs);
+       else
+               describe_detached_head("Previous HEAD position was", commit);
+}
+
 static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
 {
        int ret = 0;
@@ -605,13 +703,8 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)
        if (ret)
                return ret;
 
-       /*
-        * If we were on a detached HEAD, but have now moved to
-        * a new commit, we want to mention the old commit once more
-        * to remind the user that it might be lost.
-        */
        if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
-               describe_detached_head("Previous HEAD position was", old.commit);
+               orphaned_commit_warning(old.commit);
 
        update_refs_for_switch(opts, &old, new);
 
@@ -675,11 +768,123 @@ static const char *unique_tracking_name(const char *name)
        return NULL;
 }
 
+static int parse_branchname_arg(int argc, const char **argv,
+                               int dwim_new_local_branch_ok,
+                               struct branch_info *new,
+                               struct tree **source_tree,
+                               unsigned char rev[20],
+                               const char **new_branch)
+{
+       int argcount = 0;
+       unsigned char branch_rev[20];
+       const char *arg;
+       int has_dash_dash;
+
+       /*
+        * case 1: git checkout <ref> -- [<paths>]
+        *
+        *   <ref> must be a valid tree, everything after the '--' must be
+        *   a path.
+        *
+        * case 2: git checkout -- [<paths>]
+        *
+        *   everything after the '--' must be paths.
+        *
+        * case 3: git checkout <something> [<paths>]
+        *
+        *   With no paths, if <something> is a commit, that is to
+        *   switch to the branch or detach HEAD at it.  As a special case,
+        *   if <something> is A...B (missing A or B means HEAD but you can
+        *   omit at most one side), and if there is a unique merge base
+        *   between A and B, A...B names that merge base.
+        *
+        *   With no paths, if <something> is _not_ a commit, no -t nor -b
+        *   was given, and there is a tracking branch whose name is
+        *   <something> in one and only one remote, then this is a short-hand
+        *   to fork local <something> from that remote-tracking branch.
+        *
+        *   Otherwise <something> shall not be ambiguous.
+        *   - If it's *only* a reference, treat it like case (1).
+        *   - If it's only a path, treat it like case (2).
+        *   - else: fail.
+        *
+        */
+       if (!argc)
+               return 0;
+
+       if (!strcmp(argv[0], "--"))     /* case (2) */
+               return 1;
+
+       arg = argv[0];
+       has_dash_dash = (argc > 1) && !strcmp(argv[1], "--");
+
+       if (!strcmp(arg, "-"))
+               arg = "@{-1}";
+
+       if (get_sha1_mb(arg, rev)) {
+               if (has_dash_dash)          /* case (1) */
+                       die("invalid reference: %s", arg);
+               if (dwim_new_local_branch_ok &&
+                   !check_filename(NULL, arg) &&
+                   argc == 1) {
+                       const char *remote = unique_tracking_name(arg);
+                       if (!remote || get_sha1(remote, rev))
+                               return argcount;
+                       *new_branch = arg;
+                       arg = remote;
+                       /* DWIMmed to create local branch */
+               } else {
+                       return argcount;
+               }
+       }
+
+       /* we can't end up being in (2) anymore, eat the argument */
+       argcount++;
+       argv++;
+       argc--;
+
+       new->name = arg;
+       setup_branch_path(new);
+
+       if (check_ref_format(new->path) == CHECK_REF_FORMAT_OK &&
+           resolve_ref(new->path, branch_rev, 1, NULL))
+               hashcpy(rev, branch_rev);
+       else
+               new->path = NULL; /* not an existing branch */
+
+       new->commit = lookup_commit_reference_gently(rev, 1);
+       if (!new->commit) {
+               /* not a commit */
+               *source_tree = parse_tree_indirect(rev);
+       } else {
+               parse_commit(new->commit);
+               *source_tree = new->commit->tree;
+       }
+
+       if (!*source_tree)                   /* case (1): want a tree */
+               die("reference is not a tree: %s", arg);
+       if (!has_dash_dash) {/* case (3 -> 1) */
+               /*
+                * Do not complain the most common case
+                *      git checkout branch
+                * even if there happen to be a file called 'branch';
+                * it would be extremely annoying.
+                */
+               if (argc)
+                       verify_non_filename(NULL, arg);
+       } else {
+               argcount++;
+               argv++;
+               argc--;
+       }
+
+       return argcount;
+}
+
 int cmd_checkout(int argc, const char **argv, const char *prefix)
 {
        struct checkout_opts opts;
        unsigned char rev[20];
-       const char *arg;
        struct branch_info new;
        struct tree *source_tree = NULL;
        char *conflict_style = NULL;
@@ -692,6 +897,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                OPT_STRING('B', NULL, &opts.new_branch_force, "branch",
                           "create/reset and checkout a branch"),
                OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "create reflog for new branch"),
+               OPT_BOOLEAN(0, "detach", &opts.force_detach, "detach the HEAD at named commit"),
                OPT_SET_INT('t', "track",  &opts.track, "set upstream info for new branch",
                        BRANCH_TRACK_EXPLICIT),
                OPT_STRING(0, "orphan", &opts.new_orphan_branch, "new branch", "new unparented branch"),
@@ -709,7 +915,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                  PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
                OPT_END(),
        };
-       int has_dash_dash;
 
        memset(&opts, 0, sizeof(opts));
        memset(&new, 0, sizeof(new));
@@ -731,9 +936,15 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                opts.new_branch = opts.new_branch_force;
 
        if (patch_mode && (opts.track > 0 || opts.new_branch
-                          || opts.new_branch_log || opts.merge || opts.force))
+                          || opts.new_branch_log || opts.merge || opts.force
+                          || opts.force_detach))
                die ("--patch is incompatible with all other options");
 
+       if (opts.force_detach && (opts.new_branch || opts.new_orphan_branch))
+               die("--detach cannot be used with -b/-B/--orphan");
+       if (opts.force_detach && 0 < opts.track)
+               die("--detach cannot be used with -t");
+
        /* --track without -b should DWIM */
        if (0 < opts.track && !opts.new_branch) {
                const char *argv0 = argv[0];
@@ -766,105 +977,30 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                die("git checkout: -f and -m are incompatible");
 
        /*
-        * case 1: git checkout <ref> -- [<paths>]
-        *
-        *   <ref> must be a valid tree, everything after the '--' must be
-        *   a path.
-        *
-        * case 2: git checkout -- [<paths>]
-        *
-        *   everything after the '--' must be paths.
-        *
-        * case 3: git checkout <something> [<paths>]
-        *
-        *   With no paths, if <something> is a commit, that is to
-        *   switch to the branch or detach HEAD at it.  As a special case,
-        *   if <something> is A...B (missing A or B means HEAD but you can
-        *   omit at most one side), and if there is a unique merge base
-        *   between A and B, A...B names that merge base.
+        * Extract branch name from command line arguments, so
+        * all that is left is pathspecs.
         *
-        *   With no paths, if <something> is _not_ a commit, no -t nor -b
-        *   was given, and there is a remote-tracking branch whose name is
-        *   <something> in one and only one remote, then this is a short-hand
-        *   to fork local <something> from that remote-tracking branch.
+        * Handle
         *
-        *   Otherwise <something> shall not be ambiguous.
-        *   - If it's *only* a reference, treat it like case (1).
-        *   - If it's only a path, treat it like case (2).
-        *   - else: fail.
+        *  1) git checkout <tree> -- [<paths>]
+        *  2) git checkout -- [<paths>]
+        *  3) git checkout <something> [<paths>]
         *
+        * including "last branch" syntax and DWIM-ery for names of
+        * remote branches, erroring out for invalid or ambiguous cases.
         */
        if (argc) {
-               if (!strcmp(argv[0], "--")) {       /* case (2) */
-                       argv++;
-                       argc--;
-                       goto no_reference;
-               }
-
-               arg = argv[0];
-               has_dash_dash = (argc > 1) && !strcmp(argv[1], "--");
-
-               if (!strcmp(arg, "-"))
-                       arg = "@{-1}";
-
-               if (get_sha1_mb(arg, rev)) {
-                       if (has_dash_dash)          /* case (1) */
-                               die("invalid reference: %s", arg);
-                       if (!patch_mode &&
-                           dwim_new_local_branch &&
-                           opts.track == BRANCH_TRACK_UNSPECIFIED &&
-                           !opts.new_branch &&
-                           !check_filename(NULL, arg) &&
-                           argc == 1) {
-                               const char *remote = unique_tracking_name(arg);
-                               if (!remote || get_sha1(remote, rev))
-                                       goto no_reference;
-                               opts.new_branch = arg;
-                               arg = remote;
-                               /* DWIMmed to create local branch */
-                       }
-                       else
-                               goto no_reference;
-               }
-
-               /* we can't end up being in (2) anymore, eat the argument */
-               argv++;
-               argc--;
-
-               new.name = arg;
-               if ((new.commit = lookup_commit_reference_gently(rev, 1))) {
-                       setup_branch_path(&new);
-
-                       if ((check_ref_format(new.path) == CHECK_REF_FORMAT_OK) &&
-                           resolve_ref(new.path, rev, 1, NULL))
-                               ;
-                       else
-                               new.path = NULL;
-                       parse_commit(new.commit);
-                       source_tree = new.commit->tree;
-               } else
-                       source_tree = parse_tree_indirect(rev);
-
-               if (!source_tree)                   /* case (1): want a tree */
-                       die("reference is not a tree: %s", arg);
-               if (!has_dash_dash) {/* case (3 -> 1) */
-                       /*
-                        * Do not complain the most common case
-                        *      git checkout branch
-                        * even if there happen to be a file called 'branch';
-                        * it would be extremely annoying.
-                        */
-                       if (argc)
-                               verify_non_filename(NULL, arg);
-               }
-               else {
-                       argv++;
-                       argc--;
-               }
+               int dwim_ok =
+                       !patch_mode &&
+                       dwim_new_local_branch &&
+                       opts.track == BRANCH_TRACK_UNSPECIFIED &&
+                       !opts.new_branch;
+               int n = parse_branchname_arg(argc, argv, dwim_ok,
+                               &new, &source_tree, rev, &opts.new_branch);
+               argv += n;
+               argc -= n;
        }
 
-no_reference:
-
        if (opts.track == BRANCH_TRACK_UNSPECIFIED)
                opts.track = git_branch_track;
 
@@ -886,6 +1022,9 @@ no_reference:
                        }
                }
 
+               if (opts.force_detach)
+                       die("git checkout: --detach does not take a path argument");
+
                if (1 < !!opts.writeout_stage + !!opts.force + !!opts.merge)
                        die("git checkout: --ours/--theirs, --force and --merge are incompatible when\nchecking out of the index.");
 
index 61e0989b5ab8fffb16ec28e64c38b4fa236cb3ed..c6e10bb9e916a21ad5c71018d6380ad85540dc65 100644 (file)
@@ -8,7 +8,7 @@
  * Clone a repository into a different directory that does not yet exist.
  */
 
-#include "cache.h"
+#include "builtin.h"
 #include "parse-options.h"
 #include "fetch-pack.h"
 #include "refs.h"
@@ -66,10 +66,10 @@ static struct option builtin_clone_options[] = {
                    "setup as shared repository"),
        OPT_BOOLEAN(0, "recursive", &option_recursive,
                    "initialize submodules in the clone"),
-       OPT_BOOLEAN(0, "recurse_submodules", &option_recursive,
+       OPT_BOOLEAN(0, "recurse-submodules", &option_recursive,
                    "initialize submodules in the clone"),
-       OPT_STRING(0, "template", &option_template, "path",
-                  "path the template repository"),
+       OPT_STRING(0, "template", &option_template, "template-directory",
+                  "directory from which templates will be used"),
        OPT_STRING(0, "reference", &option_reference, "repo",
                   "reference repository"),
        OPT_STRING('o', "origin", &option_origin, "branch",
@@ -100,7 +100,7 @@ static char *get_repo_path(const char *repo, int *is_bundle)
                path = mkpath("%s%s", repo, suffix[i]);
                if (is_directory(path)) {
                        *is_bundle = 0;
-                       return xstrdup(make_nonrelative_path(path));
+                       return xstrdup(absolute_path(path));
                }
        }
 
@@ -109,7 +109,7 @@ static char *get_repo_path(const char *repo, int *is_bundle)
                path = mkpath("%s%s", repo, bundle_suffix[i]);
                if (!stat(path, &st) && S_ISREG(st.st_mode)) {
                        *is_bundle = 1;
-                       return xstrdup(make_nonrelative_path(path));
+                       return xstrdup(absolute_path(path));
                }
        }
 
@@ -203,7 +203,7 @@ static void setup_reference(const char *repo)
        struct transport *transport;
        const struct ref *extra;
 
-       ref_git = make_absolute_path(option_reference);
+       ref_git = real_path(option_reference);
 
        if (is_directory(mkpath("%s/.git/objects", ref_git)))
                ref_git = mkpath("%s/.git", ref_git);
@@ -383,6 +383,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
        junk_pid = getpid();
 
+       packet_trace_identity("clone");
        argc = parse_options(argc, argv, prefix, builtin_clone_options,
                             builtin_clone_usage, 0);
 
@@ -411,9 +412,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
        path = get_repo_path(repo_name, &is_bundle);
        if (path)
-               repo = xstrdup(make_nonrelative_path(repo_name));
+               repo = xstrdup(absolute_path(repo_name));
        else if (!strchr(repo_name, ':'))
-               repo = xstrdup(make_absolute_path(repo_name));
+               die("repository '%s' does not exist", repo_name);
        else
                repo = repo_name;
        is_local = path && !is_bundle;
@@ -466,7 +467,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
        if (safe_create_leading_directories_const(git_dir) < 0)
                die("could not create leading directories of '%s'", git_dir);
-       set_git_dir(make_absolute_path(git_dir));
+       set_git_dir(real_path(git_dir));
 
        if (0 <= option_verbosity)
                printf("Cloning into %s%s...\n",
index 03cff5af631fec975442c528b1ffba264b879c8e..3979b823ef4227aac641be48c47581c56423b9d7 100644 (file)
@@ -54,9 +54,17 @@ static const char empty_amend_advice[] =
 "it empty. You can repeat your command with --allow-empty, or you can\n"
 "remove the commit entirely with \"git reset HEAD^\".\n";
 
+static const char empty_cherry_pick_advice[] =
+"The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
+"If you wish to commit it anyway, use:\n"
+"\n"
+"    git commit --allow-empty\n"
+"\n"
+"Otherwise, please use 'git reset'\n";
+
 static unsigned char head_sha1[20];
 
-static char *use_message_buffer;
+static const char *use_message_buffer;
 static const char commit_editmsg[] = "COMMIT_EDITMSG";
 static struct lock_file index_lock; /* real index */
 static struct lock_file false_lock; /* used only for partial commits */
@@ -68,6 +76,11 @@ static enum {
 
 static const char *logfile, *force_author;
 static const char *template_file;
+/*
+ * The _message variables are commit names from which to take
+ * the commit message and/or authorship.
+ */
+static const char *author_message, *author_message_buffer;
 static char *edit_message, *use_message;
 static char *fixup_message, *squash_message;
 static int all, edit_flag, also, interactive, only, amend, signoff;
@@ -88,7 +101,8 @@ static enum {
 } cleanup_mode;
 static char *cleanup_arg;
 
-static int use_editor = 1, initial_commit, in_merge, include_status = 1;
+static enum commit_whence whence;
+static int use_editor = 1, initial_commit, include_status = 1;
 static int show_ignored_in_status;
 static const char *only_include_assumed;
 static struct strbuf message;
@@ -118,14 +132,14 @@ static struct option builtin_commit_options[] = {
        OPT__VERBOSE(&verbose, "show diff in commit message template"),
 
        OPT_GROUP("Commit message options"),
-       OPT_FILENAME('F', "file", &logfile, "read log from file"),
-       OPT_STRING(0, "author", &force_author, "AUTHOR", "override author for commit"),
-       OPT_STRING(0, "date", &force_date, "DATE", "override date for commit"),
-       OPT_CALLBACK('m', "message", &message, "MESSAGE", "specify commit message", opt_parse_m),
-       OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit"),
-       OPT_STRING('C', "reuse-message", &use_message, "COMMIT", "reuse message from specified commit"),
-       OPT_STRING(0, "fixup", &fixup_message, "COMMIT", "use autosquash formatted message to fixup specified commit"),
-       OPT_STRING(0, "squash", &squash_message, "COMMIT", "use autosquash formatted message to squash specified commit"),
+       OPT_FILENAME('F', "file", &logfile, "read message from file"),
+       OPT_STRING(0, "author", &force_author, "author", "override author for commit"),
+       OPT_STRING(0, "date", &force_date, "date", "override date for commit"),
+       OPT_CALLBACK('m', "message", &message, "message", "commit message", opt_parse_m),
+       OPT_STRING('c', "reedit-message", &edit_message, "commit", "reuse and edit message from specified commit"),
+       OPT_STRING('C', "reuse-message", &use_message, "commit", "reuse message from specified commit"),
+       OPT_STRING(0, "fixup", &fixup_message, "commit", "use autosquash formatted message to fixup specified commit"),
+       OPT_STRING(0, "squash", &squash_message, "commit", "use autosquash formatted message to squash specified commit"),
        OPT_BOOLEAN(0, "reset-author", &renew_authorship, "the commit is authored by me now (used with -C-c/--amend)"),
        OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by:"),
        OPT_FILENAME('t', "template", &template_file, "use specified template file"),
@@ -145,12 +159,12 @@ static struct option builtin_commit_options[] = {
                    STATUS_FORMAT_SHORT),
        OPT_BOOLEAN(0, "branch", &status_show_branch, "show branch information"),
        OPT_SET_INT(0, "porcelain", &status_format,
-                   "show porcelain output format", STATUS_FORMAT_PORCELAIN),
+                   "machine-readable output", STATUS_FORMAT_PORCELAIN),
        OPT_BOOLEAN('z', "null", &null_termination,
                    "terminate entries with NUL"),
        OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
        OPT_BOOLEAN(0, "no-post-rewrite", &no_post_rewrite, "bypass post-rewrite hook"),
-       { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
+       { OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, "mode", "show untracked files, optional modes: all, normal, no. (Default: all)", PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
        /* end commit contents options */
 
        { OPTION_BOOLEAN, 0, "allow-empty", &allow_empty, NULL,
@@ -163,6 +177,36 @@ static struct option builtin_commit_options[] = {
        OPT_END()
 };
 
+static void determine_whence(struct wt_status *s)
+{
+       if (file_exists(git_path("MERGE_HEAD")))
+               whence = FROM_MERGE;
+       else if (file_exists(git_path("CHERRY_PICK_HEAD")))
+               whence = FROM_CHERRY_PICK;
+       else
+               whence = FROM_COMMIT;
+       if (s)
+               s->whence = whence;
+}
+
+static const char *whence_s(void)
+{
+       char *s = "";
+
+       switch (whence) {
+       case FROM_COMMIT:
+               break;
+       case FROM_MERGE:
+               s = "merge";
+               break;
+       case FROM_CHERRY_PICK:
+               s = "cherry-pick";
+               break;
+       }
+
+       return s;
+}
+
 static void rollback_index_files(void)
 {
        switch (commit_style) {
@@ -378,8 +422,8 @@ static char *prepare_index(int argc, const char **argv, const char *prefix, int
         */
        commit_style = COMMIT_PARTIAL;
 
-       if (in_merge)
-               die("cannot do a partial commit during a merge.");
+       if (whence != FROM_COMMIT)
+               die("cannot do a partial commit during a %s.", whence_s());
 
        memset(&partial, 0, sizeof(partial));
        partial.strdup_strings = 1;
@@ -469,18 +513,18 @@ static void determine_author_info(struct strbuf *author_ident)
        email = getenv("GIT_AUTHOR_EMAIL");
        date = getenv("GIT_AUTHOR_DATE");
 
-       if (use_message && !renew_authorship) {
+       if (author_message) {
                const char *a, *lb, *rb, *eol;
 
-               a = strstr(use_message_buffer, "\nauthor ");
+               a = strstr(author_message_buffer, "\nauthor ");
                if (!a)
-                       die("invalid commit: %s", use_message);
+                       die("invalid commit: %s", author_message);
 
                lb = strchrnul(a + strlen("\nauthor "), '<');
                rb = strchrnul(lb, '>');
                eol = strchrnul(rb, '\n');
                if (!*lb || !*rb || !*eol)
-                       die("invalid commit: %s", use_message);
+                       die("invalid commit: %s", author_message);
 
                if (lb == a + strlen("\nauthor "))
                        /* \nauthor <foo@example.com> */
@@ -568,7 +612,6 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
        int commitable, saved_color_setting;
        struct strbuf sb = STRBUF_INIT;
        char *buffer;
-       FILE *fp;
        const char *hook_arg1 = NULL;
        const char *hook_arg2 = NULL;
        int ident_shown = 0;
@@ -634,18 +677,22 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0)
                        die_errno("could not read SQUASH_MSG");
                hook_arg1 = "squash";
-       } else if (template_file && !stat(template_file, &statbuf)) {
+       } else if (template_file) {
                if (strbuf_read_file(&sb, template_file, 0) < 0)
                        die_errno("could not read '%s'", template_file);
                hook_arg1 = "template";
        }
 
        /*
-        * This final case does not modify the template message,
-        * it just sets the argument to the prepare-commit-msg hook.
+        * The remaining cases don't modify the template message, but
+        * just set the argument(s) to the prepare-commit-msg hook.
         */
-       else if (in_merge)
+       else if (whence == FROM_MERGE)
                hook_arg1 = "merge";
+       else if (whence == FROM_CHERRY_PICK) {
+               hook_arg1 = "commit";
+               hook_arg2 = "CHERRY_PICK_HEAD";
+       }
 
        if (squash_message) {
                /*
@@ -657,8 +704,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                hook_arg2 = "";
        }
 
-       fp = fopen(git_path(commit_editmsg), "w");
-       if (fp == NULL)
+       s->fp = fopen(git_path(commit_editmsg), "w");
+       if (s->fp == NULL)
                die_errno("could not open '%s'", git_path(commit_editmsg));
 
        if (cleanup_mode != CLEANUP_NONE)
@@ -682,7 +729,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                strbuf_release(&sob);
        }
 
-       if (fwrite(sb.buf, 1, sb.len, fp) < sb.len)
+       if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
                die_errno("could not write commit template");
 
        strbuf_release(&sb);
@@ -694,55 +741,59 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
        strbuf_addstr(&committer_ident, git_committer_info(0));
        if (use_editor && include_status) {
                char *ai_tmp, *ci_tmp;
-               if (in_merge)
-                       fprintf(fp,
-                               "#\n"
-                               "# It looks like you may be committing a MERGE.\n"
-                               "# If this is not correct, please remove the file\n"
-                               "#      %s\n"
-                               "# and try again.\n"
-                               "#\n",
-                               git_path("MERGE_HEAD"));
-
-               fprintf(fp,
-                       "\n"
-                       "# Please enter the commit message for your changes.");
+               if (whence != FROM_COMMIT)
+                       status_printf_ln(s, GIT_COLOR_NORMAL,
+                               "\n"
+                               "It looks like you may be committing a %s.\n"
+                               "If this is not correct, please remove the file\n"
+                               "       %s\n"
+                               "and try again.\n"
+                               "",
+                               whence_s(),
+                               git_path(whence == FROM_MERGE
+                                        ? "MERGE_HEAD"
+                                        : "CHERRY_PICK_HEAD"));
+
+               fprintf(s->fp, "\n");
+               status_printf(s, GIT_COLOR_NORMAL,
+                       "Please enter the commit message for your changes.");
                if (cleanup_mode == CLEANUP_ALL)
-                       fprintf(fp,
+                       status_printf_more(s, GIT_COLOR_NORMAL,
                                " Lines starting\n"
-                               "with '#' will be ignored, and an empty"
+                               "with '#' will be ignored, and an empty"
                                " message aborts the commit.\n");
                else /* CLEANUP_SPACE, that is. */
-                       fprintf(fp,
+                       status_printf_more(s, GIT_COLOR_NORMAL,
                                " Lines starting\n"
-                               "with '#' will be kept; you may remove them"
+                               "with '#' will be kept; you may remove them"
                                " yourself if you want to.\n"
-                               "An empty message aborts the commit.\n");
+                               "An empty message aborts the commit.\n");
                if (only_include_assumed)
-                       fprintf(fp, "# %s\n", only_include_assumed);
+                       status_printf_ln(s, GIT_COLOR_NORMAL,
+                                       "%s", only_include_assumed);
 
                ai_tmp = cut_ident_timestamp_part(author_ident->buf);
                ci_tmp = cut_ident_timestamp_part(committer_ident.buf);
                if (strcmp(author_ident->buf, committer_ident.buf))
-                       fprintf(fp,
+                       status_printf_ln(s, GIT_COLOR_NORMAL,
                                "%s"
-                               "# Author:    %s\n",
-                               ident_shown++ ? "" : "#\n",
+                               "Author:    %s",
+                               ident_shown++ ? "" : "\n",
                                author_ident->buf);
 
                if (!user_ident_sufficiently_given())
-                       fprintf(fp,
+                       status_printf_ln(s, GIT_COLOR_NORMAL,
                                "%s"
-                               "# Committer: %s\n",
-                               ident_shown++ ? "" : "#\n",
+                               "Committer: %s",
+                               ident_shown++ ? "" : "\n",
                                committer_ident.buf);
 
                if (ident_shown)
-                       fprintf(fp, "#\n");
+                       status_printf_ln(s, GIT_COLOR_NORMAL, "");
 
                saved_color_setting = s->use_color;
                s->use_color = 0;
-               commitable = run_status(fp, index_file, prefix, 1, s);
+               commitable = run_status(s->fp, index_file, prefix, 1, s);
                s->use_color = saved_color_setting;
 
                *ai_tmp = ' ';
@@ -764,13 +815,20 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
        }
        strbuf_release(&committer_ident);
 
-       fclose(fp);
+       fclose(s->fp);
 
-       if (!commitable && !in_merge && !allow_empty &&
+       /*
+        * Reject an attempt to record a non-merge empty commit without
+        * explicit --allow-empty. In the cherry-pick case, it may be
+        * empty due to conflict resolution, which the user should okay.
+        */
+       if (!commitable && whence != FROM_MERGE && !allow_empty &&
            !(amend && is_a_merge(head_sha1))) {
                run_status(stdout, index_file, prefix, 0, s);
                if (amend)
                        fputs(empty_amend_advice, stderr);
+               else if (whence == FROM_CHERRY_PICK)
+                       fputs(empty_cherry_pick_advice, stderr);
                return 0;
        }
 
@@ -898,6 +956,28 @@ static void handle_untracked_files_arg(struct wt_status *s)
                die("Invalid untracked files mode '%s'", untracked_files_arg);
 }
 
+static const char *read_commit_message(const char *name)
+{
+       const char *out_enc, *out;
+       struct commit *commit;
+
+       commit = lookup_commit_reference_by_name(name);
+       if (!commit)
+               die("could not lookup commit %s", name);
+       out_enc = get_commit_output_encoding();
+       out = logmsg_reencode(commit, out_enc);
+
+       /*
+        * If we failed to reencode the buffer, just copy it
+        * byte for byte so the user can try to fix it up.
+        * This also handles the case where input and output
+        * encodings are identical.
+        */
+       if (out == NULL)
+               out = xstrdup(commit->buffer);
+       return out;
+}
+
 static int parse_and_validate_options(int argc, const char *argv[],
                                      const char * const usage[],
                                      const char *prefix,
@@ -927,8 +1007,8 @@ static int parse_and_validate_options(int argc, const char *argv[],
        /* Sanity check options */
        if (amend && initial_commit)
                die("You have nothing to amend.");
-       if (amend && in_merge)
-               die("You are in the middle of a merge -- cannot amend.");
+       if (amend && whence != FROM_COMMIT)
+               die("You are in the middle of a %s -- cannot amend.", whence_s());
        if (fixup_message && squash_message)
                die("Options --squash and --fixup cannot be used together");
        if (use_message)
@@ -947,26 +1027,18 @@ static int parse_and_validate_options(int argc, const char *argv[],
                use_message = edit_message;
        if (amend && !use_message && !fixup_message)
                use_message = "HEAD";
-       if (!use_message && renew_authorship)
+       if (!use_message && whence != FROM_CHERRY_PICK && renew_authorship)
                die("--reset-author can be used only with -C, -c or --amend.");
        if (use_message) {
-               const char *out_enc;
-               struct commit *commit;
-
-               commit = lookup_commit_reference_by_name(use_message);
-               if (!commit)
-                       die("could not lookup commit %s", use_message);
-               out_enc = get_commit_output_encoding();
-               use_message_buffer = logmsg_reencode(commit, out_enc);
-
-               /*
-                * If we failed to reencode the buffer, just copy it
-                * byte for byte so the user can try to fix it up.
-                * This also handles the case where input and output
-                * encodings are identical.
-                */
-               if (use_message_buffer == NULL)
-                       use_message_buffer = xstrdup(commit->buffer);
+               use_message_buffer = read_commit_message(use_message);
+               if (!renew_authorship) {
+                       author_message = use_message;
+                       author_message_buffer = use_message_buffer;
+               }
+       }
+       if (whence == FROM_CHERRY_PICK && !renew_authorship) {
+               author_message = "CHERRY_PICK_HEAD";
+               author_message_buffer = read_commit_message(author_message);
        }
 
        if (!!also + !!only + !!all + !!interactive > 1)
@@ -1092,7 +1164,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
                OPT_BOOLEAN('b', "branch", &status_show_branch,
                            "show branch information"),
                OPT_SET_INT(0, "porcelain", &status_format,
-                           "show porcelain output format",
+                           "machine-readable output",
                            STATUS_FORMAT_PORCELAIN),
                OPT_BOOLEAN('z', "null", &null_termination,
                            "terminate entries with NUL"),
@@ -1117,7 +1189,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
        wt_status_prepare(&s);
        gitmodules_config();
        git_config(git_status_config, &s);
-       in_merge = file_exists(git_path("MERGE_HEAD"));
+       determine_whence(&s);
        argc = parse_options(argc, argv, prefix,
                             builtin_status_options,
                             builtin_status_usage, 0);
@@ -1140,7 +1212,6 @@ int cmd_status(int argc, const char **argv, const char *prefix)
        }
 
        s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;
-       s.in_merge = in_merge;
        s.ignore_submodule_arg = ignore_submodule_arg;
        wt_status_collect(&s);
 
@@ -1215,7 +1286,6 @@ static void print_summary(const char *prefix, const unsigned char *sha1)
        get_commit_format(format.buf, &rev);
        rev.always_show_header = 0;
        rev.diffopt.detect_rename = 1;
-       rev.diffopt.rename_limit = 100;
        rev.diffopt.break_opt = 0;
        diff_setup_done(&rev.diffopt);
 
@@ -1302,8 +1372,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 
        wt_status_prepare(&s);
        git_config(git_commit_config, &s);
-       in_merge = file_exists(git_path("MERGE_HEAD"));
-       s.in_merge = in_merge;
+       determine_whence(&s);
 
        if (s.use_color == -1)
                s.use_color = git_use_color_default;
@@ -1340,7 +1409,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 
                for (c = commit->parents; c; c = c->next)
                        pptr = &commit_list_insert(c->item, pptr)->next;
-       } else if (in_merge) {
+       } else if (whence == FROM_MERGE) {
                struct strbuf m = STRBUF_INIT;
                FILE *fp;
 
@@ -1369,7 +1438,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                        parents = reduce_heads(parents);
        } else {
                if (!reflog_msg)
-                       reflog_msg = "commit";
+                       reflog_msg = (whence == FROM_CHERRY_PICK)
+                                       ? "commit (cherry-pick)"
+                                       : "commit";
                pptr = &commit_list_insert(lookup_commit(head_sha1), pptr)->next;
        }
 
@@ -1424,6 +1495,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                die("cannot update HEAD ref");
        }
 
+       unlink(git_path("CHERRY_PICK_HEAD"));
        unlink(git_path("MERGE_HEAD"));
        unlink(git_path("MERGE_MSG"));
        unlink(git_path("MERGE_MODE"));
index ca4a0db4a79241d7ded005483b4693967eea636f..3e3c52849773348a568241f678b3e3ee2e8d123a 100644 (file)
@@ -52,7 +52,7 @@ static struct option builtin_config_options[] = {
        OPT_BOOLEAN(0, "global", &use_global_config, "use global config file"),
        OPT_BOOLEAN(0, "system", &use_system_config, "use system config file"),
        OPT_BOOLEAN(0, "local", &use_local_config, "use repository config file"),
-       OPT_STRING('f', "file", &given_config_file, "FILE", "use given config file"),
+       OPT_STRING('f', "file", &given_config_file, "file", "use given config file"),
        OPT_GROUP("Action"),
        OPT_BIT(0, "get", &actions, "get value: name [value-regex]", ACTION_GET),
        OPT_BIT(0, "get-all", &actions, "get all values: key [value-regex]", ACTION_GET_ALL),
@@ -153,7 +153,6 @@ static int show_config(const char *key_, const char *value_, void *cb)
 static int get_value(const char *key_, const char *regex_)
 {
        int ret = -1;
-       char *tl;
        char *global = NULL, *repo_config = NULL;
        const char *system_wide = NULL, *local;
 
@@ -161,24 +160,38 @@ static int get_value(const char *key_, const char *regex_)
        if (!local) {
                const char *home = getenv("HOME");
                local = repo_config = git_pathdup("config");
-               if (git_config_global() && home)
+               if (home)
                        global = xstrdup(mkpath("%s/.gitconfig", home));
                if (git_config_system())
                        system_wide = git_etc_gitconfig();
        }
 
-       key = xstrdup(key_);
-       for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl)
-               *tl = tolower(*tl);
-       for (tl=key; *tl && *tl != '.'; ++tl)
-               *tl = tolower(*tl);
-
        if (use_key_regexp) {
+               char *tl;
+
+               /*
+                * NEEDSWORK: this naive pattern lowercasing obviously does not
+                * work for more complex patterns like "^[^.]*Foo.*bar".
+                * Perhaps we should deprecate this altogether someday.
+                */
+
+               key = xstrdup(key_);
+               for (tl = key + strlen(key) - 1;
+                    tl >= key && *tl != '.';
+                    tl--)
+                       *tl = tolower(*tl);
+               for (tl = key; *tl && *tl != '.'; tl++)
+                       *tl = tolower(*tl);
+
                key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
                if (regcomp(key_regexp, key, REG_EXTENDED)) {
                        fprintf(stderr, "Invalid key pattern: %s\n", key_);
+                       free(key);
                        goto free_strings;
                }
+       } else {
+               if (git_config_parse_key(key_, &key, NULL))
+                       goto free_strings;
        }
 
        if (regex_) {
@@ -500,3 +513,9 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 
        return 0;
 }
+
+int cmd_repo_config(int argc, const char **argv, const char *prefix)
+{
+       fprintf(stderr, "WARNING: git repo-config is deprecated in favor of git config.\n");
+       return cmd_config(argc, argv, prefix);
+}
index 95915960d46a2e6b6f222da07b99bcaa428dde42..4afd1504a666d670ec71bdbd61b09bc0530ed04b 100644 (file)
@@ -63,7 +63,7 @@ static inline struct commit_name *find_commit_name(const unsigned char *peeled)
        return n;
 }
 
-static int set_util(void *chain)
+static int set_util(void *chain, void *data)
 {
        struct commit_name *n;
        for (n = chain; n; n = n->next) {
@@ -289,7 +289,7 @@ static void describe(const char *arg, int last_one)
                fprintf(stderr, "searching to describe %s\n", arg);
 
        if (!have_util) {
-               for_each_hash(&names, set_util);
+               for_each_hash(&names, set_util, NULL);
                have_util = 1;
        }
 
index 951c7c8994704543fc1784c87a17a1aa47ede257..46085f862f937b005493319cea25b93bcb10c999 100644 (file)
@@ -61,7 +61,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
            (rev.diffopt.output_format & DIFF_FORMAT_PATCH))
                rev.combine_merges = rev.dense_combined_merges = 1;
 
-       if (read_cache_preload(rev.diffopt.paths) < 0) {
+       if (read_cache_preload(rev.diffopt.pathspec.raw) < 0) {
                perror("read_cache_preload");
                return -1;
        }
index 945e7583a8294f0612682f3228687498e5c61822..4c9deb28ec15d0c2adae795cc2c177b24256e585 100644 (file)
@@ -135,7 +135,7 @@ static int builtin_diff_index(struct rev_info *revs,
            revs->max_count != -1 || revs->min_age != -1 ||
            revs->max_age != -1)
                usage(builtin_diff_usage);
-       if (read_cache_preload(revs->diffopt.paths) < 0) {
+       if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {
                perror("read_cache_preload");
                return -1;
        }
@@ -237,7 +237,7 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv
                revs->combine_merges = revs->dense_combined_merges = 1;
 
        setup_work_tree();
-       if (read_cache_preload(revs->diffopt.paths) < 0) {
+       if (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {
                perror("read_cache_preload");
                return -1;
        }
@@ -330,8 +330,11 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
                        else if (!strcmp(arg, "--cached") ||
                                 !strcmp(arg, "--staged")) {
                                add_head_to_pending(&rev);
-                               if (!rev.pending.nr)
-                                       die("No HEAD commit to compare with (yet)");
+                               if (!rev.pending.nr) {
+                                       struct tree *tree;
+                                       tree = lookup_tree((const unsigned char*)EMPTY_TREE_SHA1_BIN);
+                                       add_pending_object(&rev, &tree->object, "HEAD");
+                               }
                                break;
                        }
                }
@@ -371,14 +374,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
                }
                die("unhandled object '%s' given.", name);
        }
-       if (rev.prune_data) {
-               const char **pathspec = rev.prune_data;
-               while (*pathspec) {
-                       if (!path)
-                               path = *pathspec;
-                       paths++;
-                       pathspec++;
-               }
+       if (rev.prune_data.nr) {
+               if (!path)
+                       path = rev.prune_data.items[0].match;
+               paths += rev.prune_data.nr;
        }
 
        /*
index c8fd46b872780b27b09ad70316fa164d855f3220..daf19451ba7df541d1314c880679749232ccce35 100644 (file)
@@ -619,9 +619,9 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
                OPT_CALLBACK(0, "tag-of-filtered-object", &tag_of_filtered_mode, "mode",
                             "select handling of tags that tag filtered objects",
                             parse_opt_tag_of_filtered_mode),
-               OPT_STRING(0, "export-marks", &export_filename, "FILE",
+               OPT_STRING(0, "export-marks", &export_filename, "file",
                             "Dump marks to this file"),
-               OPT_STRING(0, "import-marks", &import_filename, "FILE",
+               OPT_STRING(0, "import-marks", &import_filename, "file",
                             "Import marks from this file"),
                OPT_BOOLEAN(0, "fake-missing-tagger", &fake_missing_tagger,
                             "Fake a tagger when tags lack one"),
@@ -651,7 +651,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
        if (import_filename)
                import_marks(import_filename);
 
-       if (import_filename && revs.prune_data)
+       if (import_filename && revs.prune_data.nr)
                full_tree = 1;
 
        get_tags_and_duplicates(&revs.pending, &extra_refs);
index b9994139345834a58b08a5ce57cf59c124e21760..0ef9a119405160ddacfb7a80a119ff749bb3a4f8 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
 #include "refs.h"
 #include "pkt-line.h"
 #include "commit.h"
@@ -9,11 +9,13 @@
 #include "fetch-pack.h"
 #include "remote.h"
 #include "run-command.h"
+#include "transport.h"
 
 static int transfer_unpack_limit = -1;
 static int fetch_unpack_limit = -1;
 static int unpack_limit = 100;
 static int prefer_ofs_delta = 1;
+static int no_done = 0;
 static struct fetch_pack_args args = {
        /* .uploadpack = */ "git-upload-pack",
 };
@@ -217,6 +219,16 @@ static void send_request(int fd, struct strbuf *buf)
                safe_write(fd, buf->buf, buf->len);
 }
 
+static void insert_one_alternate_ref(const struct ref *ref, void *unused)
+{
+       rev_list_insert_ref(NULL, ref->old_sha1, 0, NULL);
+}
+
+static void insert_alternate_refs(void)
+{
+       foreach_alt_odb(refs_from_alternate_cb, insert_one_alternate_ref);
+}
+
 static int find_common(int fd[2], unsigned char *result_sha1,
                       struct ref *refs)
 {
@@ -225,6 +237,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
        const unsigned char *sha1;
        unsigned in_vain = 0;
        int got_continue = 0;
+       int got_ready = 0;
        struct strbuf req_buf = STRBUF_INIT;
        size_t state_len = 0;
 
@@ -235,6 +248,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
        marked = 1;
 
        for_each_ref(rev_list_insert_ref, NULL);
+       insert_alternate_refs();
 
        fetching = 0;
        for ( ; refs ; refs = refs->next) {
@@ -262,6 +276,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
                        struct strbuf c = STRBUF_INIT;
                        if (multi_ack == 2)     strbuf_addstr(&c, " multi_ack_detailed");
                        if (multi_ack == 1)     strbuf_addstr(&c, " multi_ack");
+                       if (no_done)            strbuf_addstr(&c, " no-done");
                        if (use_sideband == 2)  strbuf_addstr(&c, " side-band-64k");
                        if (use_sideband == 1)  strbuf_addstr(&c, " side-band");
                        if (args.use_thin_pack) strbuf_addstr(&c, " thin-pack");
@@ -379,6 +394,10 @@ static int find_common(int fd[2], unsigned char *result_sha1,
                                        retval = 0;
                                        in_vain = 0;
                                        got_continue = 1;
+                                       if (ack == ACK_ready) {
+                                               rev_list = NULL;
+                                               got_ready = 1;
+                                       }
                                        break;
                                        }
                                }
@@ -392,8 +411,10 @@ static int find_common(int fd[2], unsigned char *result_sha1,
                }
        }
 done:
-       packet_buf_write(&req_buf, "done\n");
-       send_request(fd[1], &req_buf);
+       if (!got_ready || !no_done) {
+               packet_buf_write(&req_buf, "done\n");
+               send_request(fd[1], &req_buf);
+       }
        if (args.verbose)
                fprintf(stderr, "done\n");
        if (retval != 0) {
@@ -696,6 +717,11 @@ static struct ref *do_fetch_pack(int fd[2],
                if (args.verbose)
                        fprintf(stderr, "Server supports multi_ack_detailed\n");
                multi_ack = 2;
+               if (server_supports("no-done")) {
+                       if (args.verbose)
+                               fprintf(stderr, "Server supports no-done\n");
+                       no_done = 1;
+               }
        }
        else if (server_supports("multi_ack")) {
                if (args.verbose)
@@ -804,6 +830,8 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
        char **pack_lockfile_ptr = NULL;
        struct child_process *conn;
 
+       packet_trace_identity("fetch-pack");
+
        nr_heads = 0;
        heads = NULL;
        for (i = 1; i < argc; i++) {
index 357f3cdbbfd601e2ce3f1261a4d6b30c1257cda4..1b6d4be00207576f612b8d2cf1f5979656a63da7 100644 (file)
@@ -49,7 +49,7 @@ static struct option builtin_fetch_options[] = {
                    "fetch from all remotes"),
        OPT_BOOLEAN('a', "append", &append,
                    "append to .git/FETCH_HEAD instead of overwriting"),
-       OPT_STRING(0, "upload-pack", &upload_pack, "PATH",
+       OPT_STRING(0, "upload-pack", &upload_pack, "path",
                   "path to upload pack on remote end"),
        OPT__FORCE(&force, "force overwrite of local branch"),
        OPT_BOOLEAN('m', "multiple", &multiple,
@@ -69,9 +69,9 @@ static struct option builtin_fetch_options[] = {
        OPT_BOOLEAN('u', "update-head-ok", &update_head_ok,
                    "allow updating of HEAD ref"),
        OPT_BOOLEAN(0, "progress", &progress, "force progress reporting"),
-       OPT_STRING(0, "depth", &depth, "DEPTH",
+       OPT_STRING(0, "depth", &depth, "depth",
                   "deepen history of shallow clone"),
-       { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, "DIR",
+       { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, "dir",
                   "prepend this to submodule path output", PARSE_OPT_HIDDEN },
        OPT_END()
 };
@@ -906,6 +906,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        struct remote *remote;
        int result = 0;
 
+       packet_trace_identity("fetch");
+
        /* Record the command line for the reflog */
        strbuf_addstr(&default_rla, "fetch");
        for (i = 1; i < argc; i++)
index 5189b16c9e59c20b449435c413c34da9f7bf9baa..75816329d6153c35e0763b35f70cfaf165f2a4b8 100644 (file)
@@ -31,7 +31,7 @@ struct src_data {
        int head_status;
 };
 
-void init_src_data(struct src_data *data)
+static void init_src_data(struct src_data *data)
 {
        data->branch.strdup_strings = 1;
        data->tag.strdup_strings = 1;
index 6d5ebca7a9bc9333ea8e493057ecce1b4814c252..795aba087fe9c6ce0e644526d662a561b7f13f31 100644 (file)
@@ -74,7 +74,13 @@ static int mark_object(struct object *obj, int type, void *data)
 {
        struct object *parent = data;
 
+       /*
+        * The only case data is NULL or type is OBJ_ANY is when
+        * mark_object_reachable() calls us.  All the callers of
+        * that function has non-NULL obj hence ...
+        */
        if (!obj) {
+               /* ... these references to parent->fld are safe here */
                printf("broken link from %7s %s\n",
                           typename(parent->type), sha1_to_hex(parent->sha1));
                printf("broken link from %7s %s\n",
@@ -84,6 +90,7 @@ static int mark_object(struct object *obj, int type, void *data)
        }
 
        if (type != OBJ_ANY && obj->type != type)
+               /* ... and the reference to parent is safe here */
                objerror(parent, "wrong object type in link");
 
        if (obj->flags & REACHABLE)
@@ -109,7 +116,7 @@ static void mark_object_reachable(struct object *obj)
        mark_object(obj, OBJ_ANY, NULL);
 }
 
-static int traverse_one_object(struct object *obj, struct object *parent)
+static int traverse_one_object(struct object *obj)
 {
        int result;
        struct tree *tree = NULL;
@@ -138,7 +145,7 @@ static int traverse_reachable(void)
                entry = pending.objects + --pending.nr;
                obj = entry->item;
                parent = (struct object *) entry->name;
-               result |= traverse_one_object(obj, parent);
+               result |= traverse_one_object(obj);
        }
        return !!result;
 }
@@ -385,10 +392,20 @@ static void add_sha1_list(unsigned char *sha1, unsigned long ino)
        sha1_list.nr = ++nr;
 }
 
+static inline int is_loose_object_file(struct dirent *de,
+                                      char *name, unsigned char *sha1)
+{
+       if (strlen(de->d_name) != 38)
+               return 0;
+       memcpy(name + 2, de->d_name, 39);
+       return !get_sha1_hex(name, sha1);
+}
+
 static void fsck_dir(int i, char *path)
 {
        DIR *dir = opendir(path);
        struct dirent *de;
+       char name[100];
 
        if (!dir)
                return;
@@ -396,17 +413,13 @@ static void fsck_dir(int i, char *path)
        if (verbose)
                fprintf(stderr, "Checking directory %s\n", path);
 
+       sprintf(name, "%02x", i);
        while ((de = readdir(dir)) != NULL) {
-               char name[100];
                unsigned char sha1[20];
 
                if (is_dot_or_dotdot(de->d_name))
                        continue;
-               if (strlen(de->d_name) == 38) {
-                       sprintf(name, "%02x", i);
-                       memcpy(name+2, de->d_name, 39);
-                       if (get_sha1_hex(name, sha1) < 0)
-                               break;
+               if (is_loose_object_file(de, name, sha1)) {
                        add_sha1_list(sha1, DIRENT_SORT_HINT(de));
                        continue;
                }
@@ -556,8 +569,8 @@ static int fsck_cache_tree(struct cache_tree *it)
                              sha1_to_hex(it->sha1));
                        return 1;
                }
-               mark_object_reachable(obj);
                obj->used = 1;
+               mark_object_reachable(obj);
                if (obj->type != OBJ_TREE)
                        err |= objerror(obj, "non-tree in cache-tree");
        }
index fdf7131efd25618250f382dff178ca38f9b42c77..0bf8c0116a6a4c178a2c368f17d4103e91486624 100644 (file)
@@ -40,8 +40,7 @@ enum work_type {WORK_SHA1, WORK_FILE};
  * threads. The producer adds struct work_items to 'todo' and the
  * consumers pick work items from the same array.
  */
-struct work_item
-{
+struct work_item {
        enum work_type type;
        char *name;
 
@@ -329,106 +328,6 @@ static int grep_config(const char *var, const char *value, void *cb)
        return 0;
 }
 
-/*
- * Return non-zero if max_depth is negative or path has no more then max_depth
- * slashes.
- */
-static int accept_subdir(const char *path, int max_depth)
-{
-       if (max_depth < 0)
-               return 1;
-
-       while ((path = strchr(path, '/')) != NULL) {
-               max_depth--;
-               if (max_depth < 0)
-                       return 0;
-               path++;
-       }
-       return 1;
-}
-
-/*
- * Return non-zero if name is a subdirectory of match and is not too deep.
- */
-static int is_subdir(const char *name, int namelen,
-               const char *match, int matchlen, int max_depth)
-{
-       if (matchlen > namelen || strncmp(name, match, matchlen))
-               return 0;
-
-       if (name[matchlen] == '\0') /* exact match */
-               return 1;
-
-       if (!matchlen || match[matchlen-1] == '/' || name[matchlen] == '/')
-               return accept_subdir(name + matchlen + 1, max_depth);
-
-       return 0;
-}
-
-/*
- * git grep pathspecs are somewhat different from diff-tree pathspecs;
- * pathname wildcards are allowed.
- */
-static int pathspec_matches(const char **paths, const char *name, int max_depth)
-{
-       int namelen, i;
-       if (!paths || !*paths)
-               return accept_subdir(name, max_depth);
-       namelen = strlen(name);
-       for (i = 0; paths[i]; i++) {
-               const char *match = paths[i];
-               int matchlen = strlen(match);
-               const char *cp, *meta;
-
-               if (is_subdir(name, namelen, match, matchlen, max_depth))
-                       return 1;
-               if (!fnmatch(match, name, 0))
-                       return 1;
-               if (name[namelen-1] != '/')
-                       continue;
-
-               /* We are being asked if the directory ("name") is worth
-                * descending into.
-                *
-                * Find the longest leading directory name that does
-                * not have metacharacter in the pathspec; the name
-                * we are looking at must overlap with that directory.
-                */
-               for (cp = match, meta = NULL; cp - match < matchlen; cp++) {
-                       char ch = *cp;
-                       if (ch == '*' || ch == '[' || ch == '?') {
-                               meta = cp;
-                               break;
-                       }
-               }
-               if (!meta)
-                       meta = cp; /* fully literal */
-
-               if (namelen <= meta - match) {
-                       /* Looking at "Documentation/" and
-                        * the pattern says "Documentation/howto/", or
-                        * "Documentation/diff*.txt".  The name we
-                        * have should match prefix.
-                        */
-                       if (!memcmp(match, name, namelen))
-                               return 1;
-                       continue;
-               }
-
-               if (meta - match < namelen) {
-                       /* Looking at "Documentation/howto/" and
-                        * the pattern says "Documentation/h*";
-                        * match up to "Do.../h"; this avoids descending
-                        * into "Documentation/technical/".
-                        */
-                       if (!memcmp(match, name, meta - match))
-                               return 1;
-                       continue;
-               }
-       }
-       return 0;
-}
-
 static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
 {
        void *data;
@@ -581,7 +480,7 @@ static void run_pager(struct grep_opt *opt, const char *prefix)
        free(argv);
 }
 
-static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
+static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int cached)
 {
        int hit = 0;
        int nr;
@@ -591,7 +490,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
                struct cache_entry *ce = active_cache[nr];
                if (!S_ISREG(ce->ce_mode))
                        continue;
-               if (!pathspec_matches(paths, ce->name, opt->max_depth))
+               if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
                        continue;
                /*
                 * If CE_VALID is on, we assume worktree file and its cache entry
@@ -618,44 +517,29 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
        return hit;
 }
 
-static int grep_tree(struct grep_opt *opt, const char **paths,
-                    struct tree_desc *tree,
-                    const char *tree_name, const char *base)
+static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
+                    struct tree_desc *tree, struct strbuf *base, int tn_len)
 {
-       int len;
-       int hit = 0;
+       int hit = 0, matched = 0;
        struct name_entry entry;
-       char *down;
-       int tn_len = strlen(tree_name);
-       struct strbuf pathbuf;
-
-       strbuf_init(&pathbuf, PATH_MAX + tn_len);
-
-       if (tn_len) {
-               strbuf_add(&pathbuf, tree_name, tn_len);
-               strbuf_addch(&pathbuf, ':');
-               tn_len = pathbuf.len;
-       }
-       strbuf_addstr(&pathbuf, base);
-       len = pathbuf.len;
+       int old_baselen = base->len;
 
        while (tree_entry(tree, &entry)) {
                int te_len = tree_entry_len(entry.path, entry.sha1);
-               pathbuf.len = len;
-               strbuf_add(&pathbuf, entry.path, te_len);
-
-               if (S_ISDIR(entry.mode))
-                       /* Match "abc/" against pathspec to
-                        * decide if we want to descend into "abc"
-                        * directory.
-                        */
-                       strbuf_addch(&pathbuf, '/');
-
-               down = pathbuf.buf + tn_len;
-               if (!pathspec_matches(paths, down, opt->max_depth))
-                       ;
-               else if (S_ISREG(entry.mode))
-                       hit |= grep_sha1(opt, entry.sha1, pathbuf.buf, tn_len);
+
+               if (matched != 2) {
+                       matched = tree_entry_interesting(&entry, base, tn_len, pathspec);
+                       if (matched == -1)
+                               break; /* no more matches */
+                       if (!matched)
+                               continue;
+               }
+
+               strbuf_add(base, entry.path, te_len);
+
+               if (S_ISREG(entry.mode)) {
+                       hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len);
+               }
                else if (S_ISDIR(entry.mode)) {
                        enum object_type type;
                        struct tree_desc sub;
@@ -666,18 +550,21 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
                        if (!data)
                                die("unable to read tree (%s)",
                                    sha1_to_hex(entry.sha1));
+
+                       strbuf_addch(base, '/');
                        init_tree_desc(&sub, data, size);
-                       hit |= grep_tree(opt, paths, &sub, tree_name, down);
+                       hit |= grep_tree(opt, pathspec, &sub, base, tn_len);
                        free(data);
                }
+               strbuf_setlen(base, old_baselen);
+
                if (hit && opt->status_only)
                        break;
        }
-       strbuf_release(&pathbuf);
        return hit;
 }
 
-static int grep_object(struct grep_opt *opt, const char **paths,
+static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
                       struct object *obj, const char *name)
 {
        if (obj->type == OBJ_BLOB)
@@ -686,20 +573,30 @@ static int grep_object(struct grep_opt *opt, const char **paths,
                struct tree_desc tree;
                void *data;
                unsigned long size;
-               int hit;
+               struct strbuf base;
+               int hit, len;
+
                data = read_object_with_reference(obj->sha1, tree_type,
                                                  &size, NULL);
                if (!data)
                        die("unable to read tree (%s)", sha1_to_hex(obj->sha1));
+
+               len = name ? strlen(name) : 0;
+               strbuf_init(&base, PATH_MAX + len + 1);
+               if (len) {
+                       strbuf_add(&base, name, len);
+                       strbuf_addch(&base, ':');
+               }
                init_tree_desc(&tree, data, size);
-               hit = grep_tree(opt, paths, &tree, name, "");
+               hit = grep_tree(opt, pathspec, &tree, &base, base.len);
+               strbuf_release(&base);
                free(data);
                return hit;
        }
        die("unable to grep from object of type %s", typename(obj->type));
 }
 
-static int grep_objects(struct grep_opt *opt, const char **paths,
+static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
                        const struct object_array *list)
 {
        unsigned int i;
@@ -709,7 +606,7 @@ static int grep_objects(struct grep_opt *opt, const char **paths,
        for (i = 0; i < nr; i++) {
                struct object *real_obj;
                real_obj = deref_tag(list->objects[i].item, NULL, 0);
-               if (grep_object(opt, paths, real_obj, list->objects[i].name)) {
+               if (grep_object(opt, pathspec, real_obj, list->objects[i].name)) {
                        hit = 1;
                        if (opt->status_only)
                                break;
@@ -718,7 +615,7 @@ static int grep_objects(struct grep_opt *opt, const char **paths,
        return hit;
 }
 
-static int grep_directory(struct grep_opt *opt, const char **paths)
+static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec)
 {
        struct dir_struct dir;
        int i, hit = 0;
@@ -726,8 +623,12 @@ static int grep_directory(struct grep_opt *opt, const char **paths)
        memset(&dir, 0, sizeof(dir));
        setup_standard_excludes(&dir);
 
-       fill_directory(&dir, paths);
+       fill_directory(&dir, pathspec->raw);
        for (i = 0; i < dir.nr; i++) {
+               const char *name = dir.entries[i]->name;
+               int namelen = strlen(name);
+               if (!match_pathspec_depth(pathspec, name, namelen, 0, NULL))
+                       continue;
                hit |= grep_file(opt, dir.entries[i]->name);
                if (hit && opt->status_only)
                        break;
@@ -758,11 +659,12 @@ static int context_callback(const struct option *opt, const char *arg,
 static int file_callback(const struct option *opt, const char *arg, int unset)
 {
        struct grep_opt *grep_opt = opt->value;
+       int from_stdin = !strcmp(arg, "-");
        FILE *patterns;
        int lno = 0;
        struct strbuf sb = STRBUF_INIT;
 
-       patterns = fopen(arg, "r");
+       patterns = from_stdin ? stdin : fopen(arg, "r");
        if (!patterns)
                die_errno("cannot open '%s'", arg);
        while (strbuf_getline(&sb, patterns, '\n') == 0) {
@@ -776,7 +678,8 @@ static int file_callback(const struct option *opt, const char *arg, int unset)
                s = strbuf_detach(&sb, &len);
                append_grep_pat(grep_opt, s, len, arg, ++lno, GREP_PATTERN);
        }
-       fclose(patterns);
+       if (!from_stdin)
+               fclose(patterns);
        strbuf_release(&sb);
        return 0;
 }
@@ -832,6 +735,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        struct grep_opt opt;
        struct object_array list = OBJECT_ARRAY_INIT;
        const char **paths = NULL;
+       struct pathspec pathspec;
        struct string_list path_list = STRING_LIST_INIT_NODUP;
        int i;
        int dummy;
@@ -1059,6 +963,9 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                paths[0] = prefix;
                paths[1] = NULL;
        }
+       init_pathspec(&pathspec, paths);
+       pathspec.max_depth = opt.max_depth;
+       pathspec.recursive = 1;
 
        if (show_in_pager && (cached || list.nr))
                die("--open-files-in-pager only works on the worktree");
@@ -1089,16 +996,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                        die("--cached cannot be used with --no-index.");
                if (list.nr)
                        die("--no-index cannot be used with revs.");
-               hit = grep_directory(&opt, paths);
+               hit = grep_directory(&opt, &pathspec);
        } else if (!list.nr) {
                if (!cached)
                        setup_work_tree();
 
-               hit = grep_cache(&opt, paths, cached);
+               hit = grep_cache(&opt, &pathspec, cached);
        } else {
                if (cached)
                        die("both --cached and trees are given.");
-               hit = grep_objects(&opt, paths, &list);
+               hit = grep_objects(&opt, &pathspec, &list);
        }
 
        if (use_threads)
index 080af1a01b8155680faf6c04101217b60ae7b919..b96f46acf52d23f68c1ec164be8264396dea22db 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) Linus Torvalds, 2005
  * Copyright (C) Junio C Hamano, 2005
  */
-#include "cache.h"
+#include "builtin.h"
 #include "blob.h"
 #include "quote.h"
 #include "parse-options.h"
@@ -15,7 +15,7 @@ static void hash_fd(int fd, const char *type, int write_object, const char *path
        struct stat st;
        unsigned char sha1[20];
        if (fstat(fd, &st) < 0 ||
-           index_fd(sha1, fd, &st, write_object, type_from_string(type), path))
+           index_fd(sha1, fd, &st, write_object, type_from_string(type), path, 1))
                die(write_object
                    ? "Unable to add %s to database"
                    : "Unable to hash %s", path);
index 8dc5c0b5410d4bb57607bab690126f22d954dd7a..5a67c8181e5273ab0e79b8cb704dadc87cde1a37 100644 (file)
@@ -13,8 +13,7 @@
 static const char index_pack_usage[] =
 "git index-pack [-v] [-o <index-file>] [ --keep | --keep=<msg> ] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
 
-struct object_entry
-{
+struct object_entry {
        struct pack_idx_entry idx;
        unsigned long size;
        unsigned int hdr_size;
@@ -44,8 +43,7 @@ struct base_data {
 #define FLAG_LINK (1u<<20)
 #define FLAG_CHECKED (1u<<21)
 
-struct delta_entry
-{
+struct delta_entry {
        union delta_base base;
        int obj_no;
 };
@@ -209,7 +207,7 @@ static void parse_pack_header(void)
 static NORETURN void bad_object(unsigned long offset, const char *format,
                       ...) __attribute__((format (printf, 2, 3)));
 
-static void bad_object(unsigned long offset, const char *format, ...)
+static NORETURN void bad_object(unsigned long offset, const char *format, ...)
 {
        va_list params;
        char buf[1024];
index e3af9eaa877089639d6ba4f47d7155a0c1ee106e..8f5cfd712243975dacd08cb51c69c2e174e470b1 100644 (file)
@@ -419,7 +419,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
        unsigned int flags = 0;
        const struct option init_db_options[] = {
                OPT_STRING(0, "template", &template_dir, "template-directory",
-                               "provide the directory from which templates will be used"),
+                               "directory from which templates will be used"),
                OPT_SET_INT(0, "bare", &is_bare_repository_cfg,
                                "create a bare repository", 1),
                { OPTION_CALLBACK, 0, "shared", &init_shared_repository,
@@ -498,13 +498,11 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
                is_bare_repository_cfg = guess_repository_type(git_dir);
 
        if (!is_bare_repository_cfg) {
-               if (git_dir) {
-                       const char *git_dir_parent = strrchr(git_dir, '/');
-                       if (git_dir_parent) {
-                               char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
-                               git_work_tree_cfg = xstrdup(make_absolute_path(rel));
-                               free(rel);
-                       }
+               const char *git_dir_parent = strrchr(git_dir, '/');
+               if (git_dir_parent) {
+                       char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
+                       git_work_tree_cfg = xstrdup(real_path(rel));
+                       free(rel);
                }
                if (!git_work_tree_cfg) {
                        git_work_tree_cfg = xcalloc(PATH_MAX, 1);
@@ -512,7 +510,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
                                die_errno ("Cannot access current working directory");
                }
                if (work_tree)
-                       set_git_work_tree(make_absolute_path(work_tree));
+                       set_git_work_tree(real_path(work_tree));
                else
                        set_git_work_tree(git_work_tree_cfg);
                if (access(get_git_work_tree(), X_OK))
@@ -521,10 +519,10 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
        }
        else {
                if (work_tree)
-                       set_git_work_tree(make_absolute_path(work_tree));
+                       set_git_work_tree(real_path(work_tree));
        }
 
-       set_git_dir(make_absolute_path(git_dir));
+       set_git_dir(real_path(git_dir));
 
        return init_db(template_dir, flags);
 }
index d8c6c28d2fcc3bd0744f071da536215141dc0d0b..796e9e57460468748d1e2af975ac52a6470a379d 100644 (file)
@@ -89,7 +89,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
                rev->always_show_header = 0;
        if (DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES)) {
                rev->always_show_header = 0;
-               if (rev->diffopt.nr_paths != 1)
+               if (rev->diffopt.pathspec.nr != 1)
                        usage("git logs can only follow renames on one pathname at a time");
        }
        for (i = 1; i < argc; i++) {
@@ -263,7 +263,13 @@ static int cmd_log_walk(struct rev_info *rev)
         * retain that state information if replacing rev->diffopt in this loop
         */
        while ((commit = get_revision(rev)) != NULL) {
-               log_tree_commit(rev, commit);
+               if (!log_tree_commit(rev, commit) &&
+                   rev->max_count >= 0)
+                       /*
+                        * We decremented max_count in get_revision,
+                        * but we didn't actually show the commit.
+                        */
+                       rev->max_count++;
                if (!rev->reflog_info) {
                        /* we allow cycles in reflog ancestry */
                        free(commit->buffer);
@@ -1352,6 +1358,23 @@ static const char * const cherry_usage[] = {
        NULL
 };
 
+static void print_commit(char sign, struct commit *commit, int verbose,
+                        int abbrev)
+{
+       if (!verbose) {
+               printf("%c %s\n", sign,
+                      find_unique_abbrev(commit->object.sha1, abbrev));
+       } else {
+               struct strbuf buf = STRBUF_INIT;
+               struct pretty_print_context ctx = {0};
+               pretty_print_commit(CMIT_FMT_ONELINE, commit, &buf, &ctx);
+               printf("%c %s %s\n", sign,
+                      find_unique_abbrev(commit->object.sha1, abbrev),
+                      buf.buf);
+               strbuf_release(&buf);
+       }
+}
+
 int cmd_cherry(int argc, const char **argv, const char *prefix)
 {
        struct rev_info revs;
@@ -1436,22 +1459,7 @@ int cmd_cherry(int argc, const char **argv, const char *prefix)
                commit = list->item;
                if (has_commit_patch_id(commit, &ids))
                        sign = '-';
-
-               if (verbose) {
-                       struct strbuf buf = STRBUF_INIT;
-                       struct pretty_print_context ctx = {0};
-                       pretty_print_commit(CMIT_FMT_ONELINE, commit,
-                                           &buf, &ctx);
-                       printf("%c %s %s\n", sign,
-                              find_unique_abbrev(commit->object.sha1, abbrev),
-                              buf.buf);
-                       strbuf_release(&buf);
-               }
-               else {
-                       printf("%c %s\n", sign,
-                              find_unique_abbrev(commit->object.sha1, abbrev));
-               }
-
+               print_commit(sign, commit, verbose, abbrev);
                list = list->next;
        }
 
index 97eed4012ba23cfe7f13cf2b6c160ade54f6b2d1..1a1ff87e8f9ed7db84f106960f36888835f7057b 100644 (file)
@@ -33,6 +33,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
        int i;
        const char *dest = NULL;
        unsigned flags = 0;
+       int get_url = 0;
        int quiet = 0;
        const char *uploadpack = NULL;
        const char **pattern = NULL;
@@ -69,6 +70,10 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
                                quiet = 1;
                                continue;
                        }
+                       if (!strcmp("--get-url", arg)) {
+                               get_url = 1;
+                               continue;
+                       }
                        usage(ls_remote_usage);
                }
                dest = arg;
@@ -94,6 +99,12 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
        }
        if (!remote->url_nr)
                die("remote %s has no configured URL", dest);
+
+       if (get_url) {
+               printf("%s\n", *remote->url);
+               return 0;
+       }
+
        transport = transport_get(remote, NULL);
        if (uploadpack != NULL)
                transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);
index 2c4cf5e559b4166973f12bda567e1a6c5657a7e7..23388325879c5a52a4a8c25f254aafe23573e820 100644 (file)
@@ -1,6 +1,5 @@
-#include "cache.h"
+#include "builtin.h"
 #include "run-command.h"
-#include "exec_cmd.h"
 
 static const char *pgm;
 static int one_shot, quiet;
index c33091b3ed52bc8539ff82f039ec8c7718f3dcc2..3a64f5d0bdbcc8d7d21edb01f285cc8b41755228 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
 #include "commit.h"
 #include "tag.h"
 #include "merge-recursive.h"
index 9b25ddc9794efe489ee9ec9fd3203ffa997f03f7..19917426fba19cf60b838ff9b07d20b5e44259a5 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
 #include "tree-walk.h"
 #include "xdiff-interface.h"
 #include "blob.h"
index 42fff387e69d9b5412e8e776aed3272b78ebe758..aa3453c5e1c99c02d802bc77632ecedec4451c43 100644 (file)
@@ -58,6 +58,7 @@ static int option_renormalize;
 static int verbosity;
 static int allow_rerere_auto;
 static int abort_current_merge;
+static int show_progress = -1;
 
 static struct strategy all_strategy[] = {
        { "recursive",  DEFAULT_TWOHEAD | NO_TRIVIAL },
@@ -195,11 +196,12 @@ static struct option builtin_merge_options[] = {
        OPT_CALLBACK('X', "strategy-option", &xopts, "option=value",
                "option for selected merge strategy", option_parse_x),
        OPT_CALLBACK('m', "message", &merge_msg, "message",
-               "message to be used for the merge commit (if any)",
+               "merge commit message (for a non-fast-forward merge)",
                option_parse_message),
        OPT__VERBOSITY(&verbosity),
        OPT_BOOLEAN(0, "abort", &abort_current_merge,
                "abort the current in-progress merge"),
+       OPT_SET_INT(0, "progress", &show_progress, "force progress reporting", 1),
        OPT_END()
 };
 
@@ -582,7 +584,8 @@ static void write_tree_trivial(unsigned char *sha1)
                die("git write-tree failed to write a tree");
 }
 
-int try_merge_command(const char *strategy, struct commit_list *common,
+int try_merge_command(const char *strategy, size_t xopts_nr,
+                     const char **xopts, struct commit_list *common,
                      const char *head_arg, struct commit_list *remotes)
 {
        const char **args;
@@ -659,6 +662,8 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
                        o.subtree_shift = "";
 
                o.renormalize = option_renormalize;
+               o.show_rename_progress =
+                       show_progress == -1 ? isatty(2) : show_progress;
 
                for (x = 0; x < xopts_nr; x++)
                        if (parse_merge_opt(&o, xopts[x]))
@@ -680,7 +685,8 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
                rollback_lock_file(lock);
                return clean ? 0 : 1;
        } else {
-               return try_merge_command(strategy, common, head_arg, remoteheads);
+               return try_merge_command(strategy, xopts_nr, xopts,
+                                               common, head_arg, remoteheads);
        }
 }
 
@@ -795,6 +801,32 @@ static void add_strategies(const char *string, unsigned attr)
 
 }
 
+static void write_merge_msg(void)
+{
+       int fd = open(git_path("MERGE_MSG"), O_WRONLY | O_CREAT, 0666);
+       if (fd < 0)
+               die_errno("Could not open '%s' for writing",
+                         git_path("MERGE_MSG"));
+       if (write_in_full(fd, merge_msg.buf, merge_msg.len) != merge_msg.len)
+               die_errno("Could not write to '%s'", git_path("MERGE_MSG"));
+       close(fd);
+}
+
+static void read_merge_msg(void)
+{
+       strbuf_reset(&merge_msg);
+       if (strbuf_read_file(&merge_msg, git_path("MERGE_MSG"), 0) < 0)
+               die_errno("Could not read from '%s'", git_path("MERGE_MSG"));
+}
+
+static void run_prepare_commit_msg(void)
+{
+       write_merge_msg();
+       run_hook(get_index_file(), "prepare-commit-msg",
+                git_path("MERGE_MSG"), "merge", NULL, NULL);
+       read_merge_msg();
+}
+
 static int merge_trivial(void)
 {
        unsigned char result_tree[20], result_commit[20];
@@ -806,6 +838,7 @@ static int merge_trivial(void)
        parent->next = xmalloc(sizeof(*parent->next));
        parent->next->item = remoteheads->item;
        parent->next->next = NULL;
+       run_prepare_commit_msg();
        commit_tree(merge_msg.buf, result_tree, parent, result_commit, NULL);
        finish(result_commit, "In-index merge");
        drop_save();
@@ -835,6 +868,7 @@ static int finish_automerge(struct commit_list *common,
        }
        free_commit_list(remoteheads);
        strbuf_addch(&merge_msg, '\n');
+       run_prepare_commit_msg();
        commit_tree(merge_msg.buf, result_tree, parents, result_commit, NULL);
        strbuf_addf(&buf, "Merge made by %s.", wt_strategy);
        finish(result_commit, buf.buf);
@@ -944,6 +978,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
        argc = parse_options(argc, argv, prefix, builtin_merge_options,
                        builtin_merge_usage, 0);
 
+       if (verbosity < 0 && show_progress == -1)
+               show_progress = 0;
+
        if (abort_current_merge) {
                int nargc = 2;
                const char *nargv[] = {"reset", "--merge", NULL};
@@ -969,6 +1006,13 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                else
                        die("You have not concluded your merge (MERGE_HEAD exists).");
        }
+       if (file_exists(git_path("CHERRY_PICK_HEAD"))) {
+               if (advice_resolve_conflict)
+                       die("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
+                           "Please, commit your changes before you can merge.");
+               else
+                       die("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).");
+       }
        resolve_undo_clear();
 
        if (verbosity < 0)
@@ -1316,14 +1360,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                        die_errno("Could not write to '%s'", git_path("MERGE_HEAD"));
                close(fd);
                strbuf_addch(&merge_msg, '\n');
-               fd = open(git_path("MERGE_MSG"), O_WRONLY | O_CREAT, 0666);
-               if (fd < 0)
-                       die_errno("Could not open '%s' for writing",
-                                 git_path("MERGE_MSG"));
-               if (write_in_full(fd, merge_msg.buf, merge_msg.len) !=
-                       merge_msg.len)
-                       die_errno("Could not write to '%s'", git_path("MERGE_MSG"));
-               close(fd);
+               write_merge_msg();
                fd = open(git_path("MERGE_MODE"), O_WRONLY | O_CREAT | O_TRUNC, 0666);
                if (fd < 0)
                        die_errno("Could not open '%s' for writing",
index 1cb0f3f2a7cf580efc76957de24684630d596af9..d0ccbb22227ac9667ded5fc5687ca64b7fd66afc 100644 (file)
@@ -1,6 +1,5 @@
-#include "cache.h"
+#include "builtin.h"
 #include "tag.h"
-#include "exec_cmd.h"
 
 /*
  * A signature file has a very simple fixed format: four lines
index 4d5556e2cb5bccaf0100d9f5019e1a1c493e35e7..a0f310b72956dcb00d2a0899d39ddfb9f7811fa4 100644 (file)
@@ -423,7 +423,7 @@ void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c)
        free(c);
 }
 
-int notes_copy_from_stdin(int force, const char *rewrite_cmd)
+static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
 {
        struct strbuf buf = STRBUF_INIT;
        struct notes_rewrite_cfg *c = NULL;
@@ -537,16 +537,16 @@ static int add(int argc, const char **argv, const char *prefix)
        const unsigned char *note;
        struct msg_arg msg = { 0, 0, STRBUF_INIT };
        struct option options[] = {
-               { OPTION_CALLBACK, 'm', "message", &msg, "MSG",
+               { OPTION_CALLBACK, 'm', "message", &msg, "msg",
                        "note contents as a string", PARSE_OPT_NONEG,
                        parse_msg_arg},
-               { OPTION_CALLBACK, 'F', "file", &msg, "FILE",
+               { OPTION_CALLBACK, 'F', "file", &msg, "file",
                        "note contents in a file", PARSE_OPT_NONEG,
                        parse_file_arg},
-               { OPTION_CALLBACK, 'c', "reedit-message", &msg, "OBJECT",
+               { OPTION_CALLBACK, 'c', "reedit-message", &msg, "object",
                        "reuse and edit specified note object", PARSE_OPT_NONEG,
                        parse_reedit_arg},
-               { OPTION_CALLBACK, 'C', "reuse-message", &msg, "OBJECT",
+               { OPTION_CALLBACK, 'C', "reuse-message", &msg, "object",
                        "reuse specified note object", PARSE_OPT_NONEG,
                        parse_reuse_arg},
                OPT__FORCE(&force, "replace existing notes"),
@@ -682,16 +682,16 @@ static int append_edit(int argc, const char **argv, const char *prefix)
        const char * const *usage;
        struct msg_arg msg = { 0, 0, STRBUF_INIT };
        struct option options[] = {
-               { OPTION_CALLBACK, 'm', "message", &msg, "MSG",
+               { OPTION_CALLBACK, 'm', "message", &msg, "msg",
                        "note contents as a string", PARSE_OPT_NONEG,
                        parse_msg_arg},
-               { OPTION_CALLBACK, 'F', "file", &msg, "FILE",
+               { OPTION_CALLBACK, 'F', "file", &msg, "file",
                        "note contents in a file", PARSE_OPT_NONEG,
                        parse_file_arg},
-               { OPTION_CALLBACK, 'c', "reedit-message", &msg, "OBJECT",
+               { OPTION_CALLBACK, 'c', "reedit-message", &msg, "object",
                        "reuse and edit specified note object", PARSE_OPT_NONEG,
                        parse_reedit_arg},
-               { OPTION_CALLBACK, 'C', "reuse-message", &msg, "OBJECT",
+               { OPTION_CALLBACK, 'C', "reuse-message", &msg, "object",
                        "reuse specified note object", PARSE_OPT_NONEG,
                        parse_reuse_arg},
                OPT_END()
@@ -819,7 +819,7 @@ static int merge_commit(struct notes_merge_options *o)
        t = xcalloc(1, sizeof(struct notes_tree));
        init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
 
-       o->local_ref = resolve_ref("NOTES_MERGE_REF", sha1, 0, 0);
+       o->local_ref = resolve_ref("NOTES_MERGE_REF", sha1, 0, NULL);
        if (!o->local_ref)
                die("Failed to resolve NOTES_MERGE_REF");
 
index 41e1615a28d772d1677c172ff2f570f31de4026f..f5c6afc5dd46c8f856d0f125287724bbfdc65db7 100644 (file)
@@ -6,8 +6,7 @@
 *
 */
 
-#include "cache.h"
-#include "exec_cmd.h"
+#include "builtin.h"
 
 #define BLKSIZE 512
 
index 091860b2e370561f0811399b0d307e732e9eaac3..39a9d89fbdf322a8ef42a62e41ac36af934ff638 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
 #include "parse-options.h"
 #include "pack-refs.h"
 
index 512530022edac398f8541ee6c400c7312659e730..f821eb3f0b864c26d5e822cc7c5b0747340abee5 100644 (file)
@@ -1,5 +1,4 @@
-#include "cache.h"
-#include "exec_cmd.h"
+#include "builtin.h"
 
 static void flush_current_id(int patchlen, unsigned char *id, git_SHA_CTX *c)
 {
@@ -57,7 +56,7 @@ static int scan_hunk_header(const char *p, int *p_before, int *p_after)
        return 1;
 }
 
-int get_one_patchid(unsigned char *next_sha1, git_SHA_CTX *ctx)
+static int get_one_patchid(unsigned char *next_sha1, git_SHA_CTX *ctx)
 {
        static char line[1000];
        int patchlen = 0, found_next = 0;
@@ -73,6 +72,8 @@ int get_one_patchid(unsigned char *next_sha1, git_SHA_CTX *ctx)
                        p += 7;
                else if (!memcmp(line, "From ", 5))
                        p += 5;
+               else if (!memcmp(line, "\\ ", 2) && 12 < strlen(line))
+                       continue;
 
                if (!get_sha1_hex(p, next_sha1)) {
                        found_next = 1;
index e655eb7695faba13c4d9e8f25b9649ffec7195be..6f6a66f9862d5ee5eaf4a4ce07934832569eacf9 100644 (file)
@@ -64,23 +64,33 @@ static void set_refspecs(const char **refs, int nr)
        }
 }
 
-static void setup_push_tracking(void)
+static void setup_push_upstream(struct remote *remote)
 {
        struct strbuf refspec = STRBUF_INIT;
        struct branch *branch = branch_get(NULL);
        if (!branch)
-               die("You are not currently on a branch.");
+               die("You are not currently on a branch.\n"
+                   "To push the history leading to the current (detached HEAD)\n"
+                   "state now, use\n"
+                   "\n"
+                   "    git push %s HEAD:<name-of-remote-branch>\n",
+                   remote->name);
        if (!branch->merge_nr || !branch->merge)
-               die("The current branch %s is not tracking anything.",
+               die("The current branch %s has no upstream branch.\n"
+                   "To push the current branch and set the remote as upstream, use\n"
+                   "\n"
+                   "    git push --set-upstream %s %s\n",
+                   branch->name,
+                   remote->name,
                    branch->name);
        if (branch->merge_nr != 1)
-               die("The current branch %s is tracking multiple branches, "
+               die("The current branch %s has multiple upstream branches, "
                    "refusing to push.", branch->name);
        strbuf_addf(&refspec, "%s:%s", branch->name, branch->merge[0]->src);
        add_refspec(refspec.buf);
 }
 
-static void setup_default_push_refspecs(void)
+static void setup_default_push_refspecs(struct remote *remote)
 {
        switch (push_default) {
        default:
@@ -88,8 +98,8 @@ static void setup_default_push_refspecs(void)
                add_refspec(":");
                break;
 
-       case PUSH_DEFAULT_TRACKING:
-               setup_push_tracking();
+       case PUSH_DEFAULT_UPSTREAM:
+               setup_push_upstream(remote);
                break;
 
        case PUSH_DEFAULT_CURRENT:
@@ -147,7 +157,14 @@ static int do_push(const char *repo, int flags)
        if (!remote) {
                if (repo)
                        die("bad repository '%s'", repo);
-               die("No destination configured to push to.");
+               die("No configured push destination.\n"
+                   "Either specify the URL from the command-line or configure a remote repository using\n"
+                   "\n"
+                   "    git remote add <name> <url>\n"
+                   "\n"
+                   "and then push using the remote name\n"
+                   "\n"
+                   "    git push <name>\n");
        }
 
        if (remote->mirror)
@@ -175,7 +192,7 @@ static int do_push(const char *repo, int flags)
                        refspec = remote->push_refspec;
                        refspec_nr = remote->push_refspec_nr;
                } else if (!(flags & TRANSPORT_PUSH_MIRROR))
-                       setup_default_push_refspecs();
+                       setup_default_push_refspecs(remote);
        }
        errs = 0;
        if (remote->pushurl_nr) {
@@ -228,6 +245,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
                OPT_END()
        };
 
+       packet_trace_identity("push");
        git_config(git_default_config, NULL);
        argc = parse_options(argc, argv, prefix, options, push_usage, 0);
 
index 73c89ed15ba2fb0c470141499c3390b77cf1d81c..93c92814cf28855aee87cabf4a3b906e11a36125 100644 (file)
@@ -104,8 +104,8 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
        struct unpack_trees_options opts;
        int prefix_set = 0;
        const struct option read_tree_options[] = {
-               { OPTION_CALLBACK, 0, "index-output", NULL, "FILE",
-                 "write resulting index to <FILE>",
+               { OPTION_CALLBACK, 0, "index-output", NULL, "file",
+                 "write resulting index to <file>",
                  PARSE_OPT_NONEG, index_output_cb },
                OPT_SET_INT(0, "empty", &read_empty,
                            "only empty the index", 1),
index 760817dbd7fec0086a0a1b62e58ab4438f227b7b..27050e7c1627ed2899963fb3fdb81a7ba95d06df 100644 (file)
@@ -731,43 +731,14 @@ static int delete_only(struct command *commands)
        return 1;
 }
 
-static int add_refs_from_alternate(struct alternate_object_database *e, void *unused)
+static void add_one_alternate_ref(const struct ref *ref, void *unused)
 {
-       char *other;
-       size_t len;
-       struct remote *remote;
-       struct transport *transport;
-       const struct ref *extra;
-
-       e->name[-1] = '\0';
-       other = xstrdup(make_absolute_path(e->base));
-       e->name[-1] = '/';
-       len = strlen(other);
-
-       while (other[len-1] == '/')
-               other[--len] = '\0';
-       if (len < 8 || memcmp(other + len - 8, "/objects", 8))
-               return 0;
-       /* Is this a git repository with refs? */
-       memcpy(other + len - 8, "/refs", 6);
-       if (!is_directory(other))
-               return 0;
-       other[len - 8] = '\0';
-       remote = remote_get(other);
-       transport = transport_get(remote, other);
-       for (extra = transport_get_remote_refs(transport);
-            extra;
-            extra = extra->next) {
-               add_extra_ref(".have", extra->old_sha1, 0);
-       }
-       transport_disconnect(transport);
-       free(other);
-       return 0;
+       add_extra_ref(".have", ref->old_sha1, 0);
 }
 
 static void add_alternate_refs(void)
 {
-       foreach_alt_odb(add_refs_from_alternate, NULL);
+       foreach_alt_odb(refs_from_alternate_cb, add_one_alternate_ref);
 }
 
 int cmd_receive_pack(int argc, const char **argv, const char *prefix)
@@ -778,6 +749,8 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
        char *dir = NULL;
        struct command *commands;
 
+       packet_trace_identity("receive-pack");
+
        argv++;
        for (i = 1; i < argc; i++) {
                const char *arg = *argv++;
index ea71977c8360e1a7899bbd035cf26f93d889800b..155e609d68ae81a94128d8d6588dc54463c36ef2 100644 (file)
@@ -1,4 +1,4 @@
-#include "git-compat-util.h"
+#include "builtin.h"
 #include "transport.h"
 #include "run-command.h"
 
index 1f2467bdb756435764f9156ffefeeb510dc872d8..08d7121b6d118042a45086d2902769d282c062f8 100644 (file)
@@ -1,4 +1,4 @@
-#include "git-compat-util.h"
+#include "builtin.h"
 #include "transport.h"
 
 /*
index cb26080956077f8c9ae02c91ffdc341293a4f9f1..b71ecd228f5c27bc436602469d3090eb860a1222 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
 #include "parse-options.h"
 #include "transport.h"
 #include "remote.h"
index 642bf35587ed994948d3eeac0a189ae29e39bf11..82358855d1da90b75f94c3d424a5da5c0f97960e 100644 (file)
@@ -8,7 +8,7 @@
 #include "xdiff-interface.h"
 
 static const char * const rerere_usage[] = {
-       "git rerere [clear | status | diff | gc]",
+       "git rerere [clear | forget path... | status | remaining | diff | gc]",
        NULL,
 };
 
@@ -136,7 +136,10 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
                return rerere(flags);
 
        if (!strcmp(argv[0], "forget")) {
-               const char **pathspec = get_pathspec(prefix, argv + 1);
+               const char **pathspec;
+               if (argc < 2)
+                       warning("'git rerere forget' without paths is deprecated");
+               pathspec = get_pathspec(prefix, argv + 1);
                return rerere_forget(pathspec);
        }
 
@@ -156,7 +159,17 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
        else if (!strcmp(argv[0], "status"))
                for (i = 0; i < merge_rr.nr; i++)
                        printf("%s\n", merge_rr.items[i].string);
-       else if (!strcmp(argv[0], "diff"))
+       else if (!strcmp(argv[0], "remaining")) {
+               rerere_remaining(&merge_rr);
+               for (i = 0; i < merge_rr.nr; i++) {
+                       if (merge_rr.items[i].util != RERERE_RESOLVED)
+                               printf("%s\n", merge_rr.items[i].string);
+                       else
+                               /* prepare for later call to
+                                * string_list_clear() */
+                               merge_rr.items[i].util = NULL;
+               }
+       } else if (!strcmp(argv[0], "diff"))
                for (i = 0; i < merge_rr.nr; i++) {
                        const char *path = merge_rr.items[i].string;
                        const char *name = (const char *)merge_rr.items[i].util;
index 5de2bceeec8c1d243ed6da70464d0c4dd60d7352..eb5f98c16320cd4eded3c842ec1d019e75c5b9c3 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano
  */
-#include "cache.h"
+#include "builtin.h"
 #include "tag.h"
 #include "object.h"
 #include "commit.h"
index ba27d39f977f2807cddb6e18364837b9fd50e970..f458cb7587c7d40cf93d42d73379fac485ee3889 100644 (file)
@@ -64,18 +64,8 @@ static void show_commit(struct commit *commit, void *data)
        if (info->header_prefix)
                fputs(info->header_prefix, stdout);
 
-       if (!revs->graph) {
-               if (commit->object.flags & BOUNDARY)
-                       putchar('-');
-               else if (commit->object.flags & UNINTERESTING)
-                       putchar('^');
-               else if (revs->left_right) {
-                       if (commit->object.flags & SYMMETRIC_LEFT)
-                               putchar('<');
-                       else
-                               putchar('>');
-               }
-       }
+       if (!revs->graph)
+               fputs(get_revision_mark(revs, commit), stdout);
        if (revs->abbrev_commit && revs->abbrev)
                fputs(find_unique_abbrev(commit->object.sha1, revs->abbrev),
                      stdout);
index bb6e9e83b756b47dae449064ca7762fe3558fc0e..c57b872fe114145ec82bf33717c2a8d7f0982204 100644 (file)
@@ -3,7 +3,6 @@
 #include "object.h"
 #include "commit.h"
 #include "tag.h"
-#include "wt-status.h"
 #include "run-command.h"
 #include "exec_cmd.h"
 #include "utf8.h"
@@ -44,7 +43,11 @@ static const char **commit_argv;
 static int allow_rerere_auto;
 
 static const char *me;
+
+/* Merge strategy. */
 static const char *strategy;
+static const char **xopts;
+static size_t xopts_nr, xopts_alloc;
 
 #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
 
@@ -55,6 +58,17 @@ static const char * const *revert_or_cherry_pick_usage(void)
        return action == REVERT ? revert_usage : cherry_pick_usage;
 }
 
+static int option_parse_x(const struct option *opt,
+                         const char *arg, int unset)
+{
+       if (unset)
+               return 0;
+
+       ALLOC_GROW(xopts, xopts_nr + 1, xopts_alloc);
+       xopts[xopts_nr++] = xstrdup(arg);
+       return 0;
+}
+
 static void parse_args(int argc, const char **argv)
 {
        const char * const * usage_str = revert_or_cherry_pick_usage();
@@ -67,6 +81,8 @@ static void parse_args(int argc, const char **argv)
                OPT_INTEGER('m', "mainline", &mainline, "parent number"),
                OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
                OPT_STRING(0, "strategy", &strategy, "strategy", "merge strategy"),
+               OPT_CALLBACK('X', "strategy-option", &xopts, "option",
+                       "option for merge strategy", option_parse_x),
                OPT_END(),
                OPT_END(),
                OPT_END(),
@@ -181,54 +197,20 @@ static void add_message_to_msg(struct strbuf *msgbuf, const char *message)
        strbuf_addstr(msgbuf, p);
 }
 
-static void set_author_ident_env(const char *message)
+static void write_cherry_pick_head(void)
 {
-       const char *p = message;
-       if (!p)
-               die ("Could not read commit message of %s",
-                               sha1_to_hex(commit->object.sha1));
-       while (*p && *p != '\n') {
-               const char *eol;
-
-               for (eol = p; *eol && *eol != '\n'; eol++)
-                       ; /* do nothing */
-               if (!prefixcmp(p, "author ")) {
-                       char *line, *pend, *email, *timestamp;
-
-                       p += 7;
-                       line = xmemdupz(p, eol - p);
-                       email = strchr(line, '<');
-                       if (!email)
-                               die ("Could not extract author email from %s",
-                                       sha1_to_hex(commit->object.sha1));
-                       if (email == line)
-                               pend = line;
-                       else
-                               for (pend = email; pend != line + 1 &&
-                                               isspace(pend[-1]); pend--);
-                                       ; /* do nothing */
-                       *pend = '\0';
-                       email++;
-                       timestamp = strchr(email, '>');
-                       if (!timestamp)
-                               die ("Could not extract author time from %s",
-                                       sha1_to_hex(commit->object.sha1));
-                       *timestamp = '\0';
-                       for (timestamp++; *timestamp && isspace(*timestamp);
-                                       timestamp++)
-                               ; /* do nothing */
-                       setenv("GIT_AUTHOR_NAME", line, 1);
-                       setenv("GIT_AUTHOR_EMAIL", email, 1);
-                       setenv("GIT_AUTHOR_DATE", timestamp, 1);
-                       free(line);
-                       return;
-               }
-               p = eol;
-               if (*p == '\n')
-                       p++;
-       }
-       die ("No author information found in %s",
-                       sha1_to_hex(commit->object.sha1));
+       int fd;
+       struct strbuf buf = STRBUF_INIT;
+
+       strbuf_addf(&buf, "%s\n", sha1_to_hex(commit->object.sha1));
+
+       fd = open(git_path("CHERRY_PICK_HEAD"), O_WRONLY | O_CREAT, 0666);
+       if (fd < 0)
+               die_errno("Could not open '%s' for writing",
+                         git_path("CHERRY_PICK_HEAD"));
+       if (write_in_full(fd, buf.buf, buf.len) != buf.len || close(fd))
+               die_errno("Could not write to '%s'", git_path("CHERRY_PICK_HEAD"));
+       strbuf_release(&buf);
 }
 
 static void advise(const char *advice, ...)
@@ -246,15 +228,18 @@ static void print_advice(void)
 
        if (msg) {
                fprintf(stderr, "%s\n", msg);
+               /*
+                * A conflict has occured but the porcelain
+                * (typically rebase --interactive) wants to take care
+                * of the commit itself so remove CHERRY_PICK_HEAD
+                */
+               unlink(git_path("CHERRY_PICK_HEAD"));
                return;
        }
 
        advise("after resolving the conflicts, mark the corrected paths");
        advise("with 'git add <paths>' or 'git rm <paths>'");
-
-       if (action == CHERRY_PICK)
-               advise("and commit the result with 'git commit -c %s'",
-                      find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
+       advise("and commit the result with 'git commit'");
 }
 
 static void write_message(struct strbuf *msgbuf, const char *filename)
@@ -311,18 +296,13 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
        struct merge_options o;
        struct tree *result, *next_tree, *base_tree, *head_tree;
        int clean, index_fd;
+       const char **xopt;
        static struct lock_file index_lock;
 
        index_fd = hold_locked_index(&index_lock, 1);
 
        read_cache();
 
-       /*
-        * NEEDSWORK: cherry-picking between branches with
-        * different end-of-line normalization is a pain;
-        * plumb in an option to set o.renormalize?
-        * (or better: arbitrary -X options)
-        */
        init_merge_options(&o);
        o.ancestor = base ? base_label : "(empty tree)";
        o.branch1 = "HEAD";
@@ -332,6 +312,9 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
        next_tree = next ? next->tree : empty_tree();
        base_tree = base ? base->tree : empty_tree();
 
+       for (xopt = xopts; xopt != xopts + xopts_nr; xopt++)
+               parse_merge_opt(&o, *xopt);
+
        clean = merge_trees(&o,
                            head_tree,
                            next_tree, base_tree, &result);
@@ -482,13 +465,14 @@ static int do_pick_commit(void)
                base_label = msg.parent_label;
                next = commit;
                next_label = msg.label;
-               set_author_ident_env(msg.message);
                add_message_to_msg(&msgbuf, msg.message);
                if (no_replay) {
                        strbuf_addstr(&msgbuf, "(cherry picked from commit ");
                        strbuf_addstr(&msgbuf, sha1_to_hex(commit->object.sha1));
                        strbuf_addstr(&msgbuf, ")\n");
                }
+               if (!no_commit)
+                       write_cherry_pick_head();
        }
 
        if (!strategy || !strcmp(strategy, "recursive") || action == REVERT) {
@@ -503,7 +487,7 @@ static int do_pick_commit(void)
 
                commit_list_insert(base, &common);
                commit_list_insert(next, &remotes);
-               res = try_merge_command(strategy, common,
+               res = try_merge_command(strategy, xopts_nr, xopts, common,
                                        sha1_to_hex(head), remotes);
                free_commit_list(common);
                free_commit_list(remotes);
index 2cd1c40b70890732905ad9433e452aa9a9548533..8b0911c0d2ac5a60f8a3c7a43e7960617ded9d7a 100644 (file)
@@ -1,4 +1,4 @@
-#include "cache.h"
+#include "builtin.h"
 #include "commit.h"
 #include "refs.h"
 #include "pkt-line.h"
index aa1f87d47a3e4bdaa2ca3711c9dfc495fc2247e0..7cf48abca857f049243dfab7c95fea70d216ea93 100644 (file)
@@ -376,9 +376,9 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
                OPT_GROUP("Tag creation options"),
                OPT_BOOLEAN('a', NULL, &annotate,
                                        "annotated tag, needs a message"),
-               OPT_CALLBACK('m', NULL, &msg, "msg",
-                            "message for the tag", parse_msg_arg),
-               OPT_FILENAME('F', NULL, &msgfile, "message in a file"),
+               OPT_CALLBACK('m', NULL, &msg, "message",
+                            "tag message", parse_msg_arg),
+               OPT_FILENAME('F', NULL, &msgfile, "read message from file"),
                OPT_BOOLEAN('s', NULL, &sign, "annotated and GPG-signed tag"),
                OPT_STRING('u', NULL, &keyid, "key-id",
                                        "use another key to sign the tag"),
index 608590ada8105a2e6a8cb9d6176696b511b410f6..19200291a2632554223b1a675d5324b4682248ab 100644 (file)
@@ -1,6 +1,4 @@
-#include "cache.h"
-#include "blob.h"
-#include "exec_cmd.h"
+#include "builtin.h"
 
 static char *create_temp_file(unsigned char *sha1)
 {
index 56baf27fb7eb18d77e8793d089f2a719d4876689..d7850c6309aec0c1a4f640999fb757d7b32ba1b8 100644 (file)
@@ -546,7 +546,10 @@ static int do_reupdate(int ac, const char **av,
         */
        int pos;
        int has_head = 1;
-       const char **pathspec = get_pathspec(prefix, av + 1);
+       const char **paths = get_pathspec(prefix, av + 1);
+       struct pathspec pathspec;
+
+       init_pathspec(&pathspec, paths);
 
        if (read_ref("HEAD", head_sha1))
                /* If there is no HEAD, that means it is an initial
@@ -559,7 +562,7 @@ static int do_reupdate(int ac, const char **av,
                struct cache_entry *old = NULL;
                int save_nr;
 
-               if (ce_stage(ce) || !ce_path_match(ce, pathspec))
+               if (ce_stage(ce) || !ce_path_match(ce, &pathspec))
                        continue;
                if (has_head)
                        old = read_one_ent(NULL, head_sha1,
@@ -578,6 +581,7 @@ static int do_reupdate(int ac, const char **av,
                if (save_nr != active_nr)
                        goto redo;
        }
+       free_pathspec(&pathspec);
        return 0;
 }
 
index 0744bb83185289e26bd32b3b2ecaec717d8c75d7..99d068a5327255f36c8e415ecb8d0cf98cbbe180 100644 (file)
@@ -3,8 +3,7 @@
  *
  * Copyright (C) Eric Biederman, 2005
  */
-#include "cache.h"
-#include "exec_cmd.h"
+#include "builtin.h"
 
 static const char var_usage[] = "git var (-l | <variable>)";
 
index 65ea26bdb8c2cef671030c3a62d87d84612e8144..f48fd7d4c1c706b68e879e4dfabdd3fb8597a328 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -200,7 +200,7 @@ int create_bundle(struct bundle_header *header, const char *path,
        int bundle_fd = -1;
        int bundle_to_stdout;
        const char **argv_boundary = xmalloc((argc + 4) * sizeof(const char *));
-       const char **argv_pack = xmalloc(5 * sizeof(const char *));
+       const char **argv_pack = xmalloc(6 * sizeof(const char *));
        int i, ref_count = 0;
        char buffer[1024];
        struct rev_info revs;
@@ -346,7 +346,8 @@ int create_bundle(struct bundle_header *header, const char *path,
        argv_pack[1] = "--all-progress-implied";
        argv_pack[2] = "--stdout";
        argv_pack[3] = "--thin";
-       argv_pack[4] = NULL;
+       argv_pack[4] = "--delta-base-offset";
+       argv_pack[5] = NULL;
        memset(&rls, 0, sizeof(rls));
        rls.argv = argv_pack;
        rls.in = -1;
diff --git a/cache.h b/cache.h
index 8d73d88962f3f1be42fa4fddb69b115b6dbf0a76..f765cf5da2af379106e0e4e2d99780a268ad21fa 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -5,6 +5,7 @@
 #include "strbuf.h"
 #include "hash.h"
 #include "advice.h"
+#include "gettext.h"
 
 #include SHA1_HEADER
 #ifndef git_SHA_CTX
@@ -500,8 +501,23 @@ extern int index_name_is_other(const struct index_state *, const char *, int);
 extern int ie_match_stat(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);
 extern int ie_modified(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);
 
-extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
-extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
+struct pathspec {
+       const char **raw; /* get_pathspec() result, not freed by free_pathspec() */
+       int nr;
+       unsigned int has_wildcard:1;
+       unsigned int recursive:1;
+       int max_depth;
+       struct pathspec_item {
+               const char *match;
+               int len;
+               unsigned int has_wildcard:1;
+       } *items;
+};
+
+extern int init_pathspec(struct pathspec *, const char **);
+extern void free_pathspec(struct pathspec *);
+extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec);
+extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path, int format_check);
 extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
 extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
 
@@ -511,7 +527,7 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
 #define REFRESH_IGNORE_MISSING 0x0008  /* ignore non-existent */
 #define REFRESH_IGNORE_SUBMODULES      0x0010  /* ignore submodules */
 #define REFRESH_IN_PORCELAIN   0x0020  /* user friendly output, not "needs update" */
-extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen, char *header_msg);
+extern int refresh_index(struct index_state *, unsigned int flags, const char **pathspec, char *seen, const char *header_msg);
 
 struct lock_file {
        struct lock_file *next;
@@ -546,7 +562,6 @@ extern int assume_unchanged;
 extern int prefer_symlink_refs;
 extern int log_all_ref_updates;
 extern int warn_ambiguous_refs;
-extern int unique_abbrev_extra_length;
 extern int shared_repository;
 extern const char *apply_default_whitespace;
 extern const char *apply_default_ignorewhitespace;
@@ -572,7 +587,7 @@ extern enum safe_crlf safe_crlf;
 enum auto_crlf {
        AUTO_CRLF_FALSE = 0,
        AUTO_CRLF_TRUE = 1,
-       AUTO_CRLF_INPUT = -1,
+       AUTO_CRLF_INPUT = -1
 };
 
 extern enum auto_crlf auto_crlf;
@@ -609,7 +624,7 @@ enum rebase_setup_type {
 enum push_default_type {
        PUSH_DEFAULT_NOTHING = 0,
        PUSH_DEFAULT_MATCHING,
-       PUSH_DEFAULT_TRACKING,
+       PUSH_DEFAULT_UPSTREAM,
        PUSH_DEFAULT_CURRENT
 };
 
@@ -677,9 +692,11 @@ static inline void hashclr(unsigned char *hash)
 
 #define EMPTY_TREE_SHA1_HEX \
        "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
-#define EMPTY_TREE_SHA1_BIN \
+#define EMPTY_TREE_SHA1_BIN_LITERAL \
         "\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60" \
         "\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04"
+#define EMPTY_TREE_SHA1_BIN \
+        ((const unsigned char *) EMPTY_TREE_SHA1_BIN_LITERAL)
 
 int git_mkstemp(char *path, size_t n, const char *template);
 
@@ -716,9 +733,9 @@ static inline int is_absolute_path(const char *path)
        return path[0] == '/' || has_dos_drive_prefix(path);
 }
 int is_directory(const char *);
-const char *make_absolute_path(const char *path);
-const char *make_nonrelative_path(const char *path);
-const char *make_relative_path(const char *abs, const char *base);
+const char *real_path(const char *path);
+const char *absolute_path(const char *path);
+const char *relative_path(const char *abs, const char *base);
 int normalize_path_copy(char *dst, const char *src);
 int longest_ancestor_length(const char *path, const char *prefix_list);
 char *strip_path_suffix(const char *path, const char *suffix);
@@ -898,7 +915,8 @@ extern struct packed_git {
        time_t mtime;
        int pack_fd;
        unsigned pack_local:1,
-                pack_keep:1;
+                pack_keep:1,
+                do_not_close:1;
        unsigned char sha1[20];
        /* something like ".git/objects/pack/xxxxx.pack" */
        char pack_name[FLEX_ARRAY]; /* more */
@@ -998,13 +1016,13 @@ extern int git_config_maybe_bool(const char *, const char *);
 extern int git_config_string(const char **, const char *, const char *);
 extern int git_config_pathname(const char **, const char *, const char *);
 extern int git_config_set(const char *, const char *);
+extern int git_config_parse_key(const char *, char **, int *);
 extern int git_config_set_multivar(const char *, const char *, const char *, int);
 extern int git_config_rename_section(const char *, const char *);
 extern const char *git_etc_gitconfig(void);
 extern int check_repository_format_version(const char *var, const char *value, void *cb);
 extern int git_env_bool(const char *, int);
 extern int git_config_system(void);
-extern int git_config_global(void);
 extern int config_error_nonbool(const char *);
 extern const char *get_log_output_encoding(void);
 extern const char *get_commit_output_encoding(void);
@@ -1066,9 +1084,14 @@ extern void alloc_report(void);
 /* trace.c */
 __attribute__((format (printf, 1, 2)))
 extern void trace_printf(const char *format, ...);
+extern void trace_vprintf(const char *key, const char *format, va_list ap);
 __attribute__((format (printf, 2, 3)))
 extern void trace_argv_printf(const char **argv, const char *format, ...);
 extern void trace_repo_setup(const char *prefix);
+extern int trace_want(const char *key);
+extern void trace_strbuf(const char *key, const struct strbuf *buf);
+
+void packet_trace_identity(const char *prog);
 
 /* convert.c */
 /* returns 1 if *dst was used */
diff --git a/color.c b/color.c
index 6a5a54ec668e08ddef0d2f27359f3ebb3272243b..417cf8fb2812b09ad4f5bfa2674b35d7e11f32b9 100644 (file)
--- a/color.c
+++ b/color.c
@@ -175,6 +175,15 @@ int git_color_default_config(const char *var, const char *value, void *cb)
        return git_default_config(var, value, cb);
 }
 
+void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb)
+{
+       if (*color)
+               fprintf(fp, "%s", color);
+       fprintf(fp, "%s", sb->buf);
+       if (*color)
+               fprintf(fp, "%s", GIT_COLOR_RESET);
+}
+
 static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
                va_list args, const char *trail)
 {
diff --git a/color.h b/color.h
index 170ff4074d220e7e62264c4c63d1419f4a59d664..c0528cf08713ac8e101cfdeac2b3de193a0c5094 100644 (file)
--- a/color.h
+++ b/color.h
@@ -1,6 +1,8 @@
 #ifndef COLOR_H
 #define COLOR_H
 
+struct strbuf;
+
 /*  2 + (2 * num_attrs) + 8 + 1 + 8 + 'm' + NUL */
 /* "\033[1;2;4;5;7;38;5;2xx;48;5;2xxm\0" */
 /*
@@ -64,6 +66,7 @@ __attribute__((format (printf, 3, 4)))
 int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
 __attribute__((format (printf, 3, 4)))
 int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
+void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb);
 
 int color_is_nil(const char *color);
 
index 74d66018800d7a2a2b3a3365e87a23049690da6b..ac337c7d7dc1724fa918f9340816d3102edb10bd 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -245,10 +245,10 @@ int unregister_shallow(const unsigned char *sha1)
        return 0;
 }
 
-int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
+int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size)
 {
-       char *tail = buffer;
-       char *bufptr = buffer;
+       const char *tail = buffer;
+       const char *bufptr = buffer;
        unsigned char parent[20];
        struct commit_list **pptr;
        struct commit_graft *graft;
index eb6c5af1f6b18546b3b3f1683142b15bb0ae9e34..41985130d1473573af2cfd4ca97a579e999b0c0b 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -38,7 +38,7 @@ struct commit *lookup_commit_reference_gently(const unsigned char *sha1,
                                              int quiet);
 struct commit *lookup_commit_reference_by_name(const char *name);
 
-int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size);
+int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size);
 int parse_commit(struct commit *item);
 
 /* Find beginning and length of commit subject. */
@@ -68,8 +68,7 @@ enum cmit_fmt {
        CMIT_FMT_UNSPECIFIED
 };
 
-struct pretty_print_context
-{
+struct pretty_print_context {
        int abbrev;
        const char *subject;
        const char *after_subject;
index 54756dbb05ba99ab1679f17a50f04c3f1cede8e6..5061214f73d2d51cfd1d49b97b4e69be913928bd 100644 (file)
@@ -21,14 +21,16 @@ static inline uint32_t default_swab32(uint32_t val)
 
 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
 
-#define bswap32(x) ({ \
-       uint32_t __res; \
-       if (__builtin_constant_p(x)) { \
-               __res = default_swab32(x); \
-       } else { \
-               __asm__("bswap %0" : "=r" (__res) : "0" ((uint32_t)(x))); \
-       } \
-       __res; })
+#define bswap32 git_bswap32
+static inline uint32_t git_bswap32(uint32_t x)
+{
+       uint32_t result;
+       if (__builtin_constant_p(x))
+               result = default_swab32(x);
+       else
+               __asm__("bswap %0" : "=r" (result) : "0" (x));
+       return result;
+}
 
 #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
 
index bee605441910caeddd1e94eb7795f615a3d1348a..878b1de97c6c437857e7a29e1b9afc677610f1fe 100644 (file)
@@ -2,6 +2,9 @@
 #include "win32.h"
 #include <conio.h>
 #include "../strbuf.h"
+#include "../run-command.h"
+
+static const int delay[] = { 0, 1, 10, 20, 40 };
 
 int err_win_to_posix(DWORD winerr)
 {
@@ -116,6 +119,165 @@ int err_win_to_posix(DWORD winerr)
        return error;
 }
 
+static inline int is_file_in_use_error(DWORD errcode)
+{
+       switch (errcode) {
+       case ERROR_SHARING_VIOLATION:
+       case ERROR_ACCESS_DENIED:
+               return 1;
+       }
+
+       return 0;
+}
+
+static int read_yes_no_answer(void)
+{
+       char answer[1024];
+
+       if (fgets(answer, sizeof(answer), stdin)) {
+               size_t answer_len = strlen(answer);
+               int got_full_line = 0, c;
+
+               /* remove the newline */
+               if (answer_len >= 2 && answer[answer_len-2] == '\r') {
+                       answer[answer_len-2] = '\0';
+                       got_full_line = 1;
+               } else if (answer_len >= 1 && answer[answer_len-1] == '\n') {
+                       answer[answer_len-1] = '\0';
+                       got_full_line = 1;
+               }
+               /* flush the buffer in case we did not get the full line */
+               if (!got_full_line)
+                       while ((c = getchar()) != EOF && c != '\n')
+                               ;
+       } else
+               /* we could not read, return the
+                * default answer which is no */
+               return 0;
+
+       if (tolower(answer[0]) == 'y' && !answer[1])
+               return 1;
+       if (!strncasecmp(answer, "yes", sizeof(answer)))
+               return 1;
+       if (tolower(answer[0]) == 'n' && !answer[1])
+               return 0;
+       if (!strncasecmp(answer, "no", sizeof(answer)))
+               return 0;
+
+       /* did not find an answer we understand */
+       return -1;
+}
+
+static int ask_yes_no_if_possible(const char *format, ...)
+{
+       char question[4096];
+       const char *retry_hook[] = { NULL, NULL, NULL };
+       va_list args;
+
+       va_start(args, format);
+       vsnprintf(question, sizeof(question), format, args);
+       va_end(args);
+
+       if ((retry_hook[0] = getenv("GIT_ASK_YESNO"))) {
+               retry_hook[1] = question;
+               return !run_command_v_opt(retry_hook, 0);
+       }
+
+       if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr)))
+               return 0;
+
+       while (1) {
+               int answer;
+               fprintf(stderr, "%s (y/n) ", question);
+
+               if ((answer = read_yes_no_answer()) >= 0)
+                       return answer;
+
+               fprintf(stderr, "Sorry, I did not understand your answer. "
+                               "Please type 'y' or 'n'\n");
+       }
+}
+
+#undef unlink
+int mingw_unlink(const char *pathname)
+{
+       int ret, tries = 0;
+
+       /* read-only files cannot be removed */
+       chmod(pathname, 0666);
+       while ((ret = unlink(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+               if (!is_file_in_use_error(GetLastError()))
+                       break;
+               /*
+                * We assume that some other process had the source or
+                * destination file open at the wrong moment and retry.
+                * In order to give the other process a higher chance to
+                * complete its operation, we give up our time slice now.
+                * If we have to retry again, we do sleep a bit.
+                */
+               Sleep(delay[tries]);
+               tries++;
+       }
+       while (ret == -1 && is_file_in_use_error(GetLastError()) &&
+              ask_yes_no_if_possible("Unlink of file '%s' failed. "
+                       "Should I try again?", pathname))
+              ret = unlink(pathname);
+       return ret;
+}
+
+static int is_dir_empty(const char *path)
+{
+       struct strbuf buf = STRBUF_INIT;
+       WIN32_FIND_DATAA findbuf;
+       HANDLE handle;
+
+       strbuf_addf(&buf, "%s\\*", path);
+       handle = FindFirstFileA(buf.buf, &findbuf);
+       if (handle == INVALID_HANDLE_VALUE) {
+               strbuf_release(&buf);
+               return GetLastError() == ERROR_NO_MORE_FILES;
+       }
+
+       while (!strcmp(findbuf.cFileName, ".") ||
+                       !strcmp(findbuf.cFileName, ".."))
+               if (!FindNextFile(handle, &findbuf)) {
+                       strbuf_release(&buf);
+                       return GetLastError() == ERROR_NO_MORE_FILES;
+               }
+       FindClose(handle);
+       strbuf_release(&buf);
+       return 0;
+}
+
+#undef rmdir
+int mingw_rmdir(const char *pathname)
+{
+       int ret, tries = 0;
+
+       while ((ret = rmdir(pathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+               if (!is_file_in_use_error(GetLastError()))
+                       break;
+               if (!is_dir_empty(pathname)) {
+                       errno = ENOTEMPTY;
+                       break;
+               }
+               /*
+                * We assume that some other process had the source or
+                * destination file open at the wrong moment and retry.
+                * In order to give the other process a higher chance to
+                * complete its operation, we give up our time slice now.
+                * If we have to retry again, we do sleep a bit.
+                */
+               Sleep(delay[tries]);
+               tries++;
+       }
+       while (ret == -1 && is_file_in_use_error(GetLastError()) &&
+              ask_yes_no_if_possible("Deletion of directory '%s' failed. "
+                       "Should I try again?", pathname))
+              ret = rmdir(pathname);
+       return ret;
+}
+
 #undef open
 int mingw_open (const char *filename, int oflags, ...)
 {
@@ -1249,7 +1411,6 @@ int mingw_rename(const char *pold, const char *pnew)
 {
        DWORD attrs, gle;
        int tries = 0;
-       static const int delay[] = { 0, 1, 10, 20, 40 };
 
        /*
         * Try native rename() first to get errno right.
@@ -1291,6 +1452,11 @@ repeat:
                tries++;
                goto repeat;
        }
+       if (gle == ERROR_ACCESS_DENIED &&
+              ask_yes_no_if_possible("Rename from '%s' to '%s' failed. "
+                      "Should I try again?", pold, pnew))
+               goto repeat;
+
        errno = EACCES;
        return -1;
 }
index cafc1eb08a71dd60566a7389ed606e777cf17fc8..62eccd33911e2f332dc9d0faf097ecff6d6a7aa6 100644 (file)
@@ -119,14 +119,6 @@ static inline int mingw_mkdir(const char *path, int mode)
 }
 #define mkdir mingw_mkdir
 
-static inline int mingw_unlink(const char *pathname)
-{
-       /* read-only files cannot be removed */
-       chmod(pathname, 0666);
-       return unlink(pathname);
-}
-#define unlink mingw_unlink
-
 #define WNOHANG 1
 pid_t waitpid(pid_t pid, int *status, unsigned options);
 
@@ -174,6 +166,12 @@ int link(const char *oldpath, const char *newpath);
  * replacements of existing functions
  */
 
+int mingw_unlink(const char *pathname);
+#define unlink mingw_unlink
+
+int mingw_rmdir(const char *path);
+#define rmdir mingw_rmdir
+
 int mingw_open (const char *filename, int oflags, ...);
 #define open mingw_open
 
@@ -233,6 +231,22 @@ int mingw_getpagesize(void);
 #define getpagesize mingw_getpagesize
 #endif
 
+struct rlimit {
+       unsigned int rlim_cur;
+};
+#define RLIMIT_NOFILE 0
+
+static inline int getrlimit(int resource, struct rlimit *rlp)
+{
+       if (resource != RLIMIT_NOFILE) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       rlp->rlim_cur = 2048;
+       return 0;
+}
+
 /* Use mingw_lstat() instead of lstat()/stat() and
  * mingw_fstat() instead of fstat() on Windows.
  */
index 023aba0238c844f79f2662a4b885058acbfc91fd..a33b01c032b1ab948d87b29447ad0787c86f14f1 100644 (file)
@@ -9,7 +9,6 @@
 #define inline __inline
 #define __inline__ __inline
 #define __attribute__(x)
-#define va_copy(dst, src)     ((dst) = (src))
 #define strncasecmp  _strnicmp
 #define ftruncate    _chsize
 
index 79e6c1896e5a901a3b70cefa621524275046e7ba..0abcada9381a3e6638f94bcf41bf9ee7b96f4de8 100644 (file)
--- a/config.c
+++ b/config.c
@@ -20,8 +20,7 @@ static int zlib_compression_seen;
 
 const char *config_exclusive_filename = NULL;
 
-struct config_item
-{
+struct config_item {
        struct config_item *next;
        char *name;
        char *value;
@@ -499,13 +498,6 @@ static int git_default_core_config(const char *var, const char *value)
                return 0;
        }
 
-       if (!strcmp(var, "core.abbrevguard")) {
-               unique_abbrev_extra_length = git_config_int(var, value);
-               if (unique_abbrev_extra_length < 0)
-                       unique_abbrev_extra_length = 0;
-               return 0;
-       }
-
        if (!strcmp(var, "core.bare")) {
                is_bare_repository_cfg = git_config_bool(var, value);
                return 0;
@@ -745,8 +737,10 @@ static int git_default_push_config(const char *var, const char *value)
                        push_default = PUSH_DEFAULT_NOTHING;
                else if (!strcmp(value, "matching"))
                        push_default = PUSH_DEFAULT_MATCHING;
-               else if (!strcmp(value, "tracking"))
-                       push_default = PUSH_DEFAULT_TRACKING;
+               else if (!strcmp(value, "upstream"))
+                       push_default = PUSH_DEFAULT_UPSTREAM;
+               else if (!strcmp(value, "tracking")) /* deprecated */
+                       push_default = PUSH_DEFAULT_UPSTREAM;
                else if (!strcmp(value, "current"))
                        push_default = PUSH_DEFAULT_CURRENT;
                else {
@@ -839,11 +833,6 @@ int git_config_system(void)
        return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
 }
 
-int git_config_global(void)
-{
-       return !git_env_bool("GIT_CONFIG_NOGLOBAL", 0);
-}
-
 int git_config_from_parameters(config_fn_t fn, void *data)
 {
        static int loaded_environment;
@@ -875,7 +864,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
        }
 
        home = getenv("HOME");
-       if (git_config_global() && home) {
+       if (home) {
                char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
                if (!access(user_config, R_OK)) {
                        ret += git_config_from_file(fn, user_config, data);
@@ -1106,6 +1095,75 @@ int git_config_set(const char *key, const char *value)
        return git_config_set_multivar(key, value, NULL, 0);
 }
 
+/*
+ * Auxiliary function to sanity-check and split the key into the section
+ * identifier and variable name.
+ *
+ * Returns 0 on success, -1 when there is an invalid character in the key and
+ * -2 if there is no section name in the key.
+ *
+ * store_key - pointer to char* which will hold a copy of the key with
+ *             lowercase section and variable name
+ * baselen - pointer to int which will hold the length of the
+ *           section + subsection part, can be NULL
+ */
+int git_config_parse_key(const char *key, char **store_key, int *baselen_)
+{
+       int i, dot, baselen;
+       const char *last_dot = strrchr(key, '.');
+
+       /*
+        * Since "key" actually contains the section name and the real
+        * key name separated by a dot, we have to know where the dot is.
+        */
+
+       if (last_dot == NULL || last_dot == key) {
+               error("key does not contain a section: %s", key);
+               return -2;
+       }
+
+       if (!last_dot[1]) {
+               error("key does not contain variable name: %s", key);
+               return -2;
+       }
+
+       baselen = last_dot - key;
+       if (baselen_)
+               *baselen_ = baselen;
+
+       /*
+        * Validate the key and while at it, lower case it for matching.
+        */
+       *store_key = xmalloc(strlen(key) + 1);
+
+       dot = 0;
+       for (i = 0; key[i]; i++) {
+               unsigned char c = key[i];
+               if (c == '.')
+                       dot = 1;
+               /* Leave the extended basename untouched.. */
+               if (!dot || i > baselen) {
+                       if (!iskeychar(c) ||
+                           (i == baselen + 1 && !isalpha(c))) {
+                               error("invalid key: %s", key);
+                               goto out_free_ret_1;
+                       }
+                       c = tolower(c);
+               } else if (c == '\n') {
+                       error("invalid key (newline): %s", key);
+                       goto out_free_ret_1;
+               }
+               (*store_key)[i] = c;
+       }
+       (*store_key)[i] = 0;
+
+       return 0;
+
+out_free_ret_1:
+       free(*store_key);
+       return -1;
+}
+
 /*
  * If value==NULL, unset in (remove from) config,
  * if value_regex!=NULL, disregard key/value pairs where value does not match.
@@ -1132,59 +1190,23 @@ int git_config_set(const char *key, const char *value)
 int git_config_set_multivar(const char *key, const char *value,
        const char *value_regex, int multi_replace)
 {
-       int i, dot;
        int fd = -1, in_fd;
        int ret;
        char *config_filename;
        struct lock_file *lock = NULL;
-       const char *last_dot = strrchr(key, '.');
 
        if (config_exclusive_filename)
                config_filename = xstrdup(config_exclusive_filename);
        else
                config_filename = git_pathdup("config");
 
-       /*
-        * Since "key" actually contains the section name and the real
-        * key name separated by a dot, we have to know where the dot is.
-        */
-
-       if (last_dot == NULL) {
-               error("key does not contain a section: %s", key);
-               ret = 2;
+       /* parse-key returns negative; flip the sign to feed exit(3) */
+       ret = 0 - git_config_parse_key(key, &store.key, &store.baselen);
+       if (ret)
                goto out_free;
-       }
-       store.baselen = last_dot - key;
 
        store.multi_replace = multi_replace;
 
-       /*
-        * Validate the key and while at it, lower case it for matching.
-        */
-       store.key = xmalloc(strlen(key) + 1);
-       dot = 0;
-       for (i = 0; key[i]; i++) {
-               unsigned char c = key[i];
-               if (c == '.')
-                       dot = 1;
-               /* Leave the extended basename untouched.. */
-               if (!dot || i > store.baselen) {
-                       if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) {
-                               error("invalid key: %s", key);
-                               free(store.key);
-                               ret = 1;
-                               goto out_free;
-                       }
-                       c = tolower(c);
-               } else if (c == '\n') {
-                       error("invalid key (newline): %s", key);
-                       free(store.key);
-                       ret = 1;
-                       goto out_free;
-               }
-               store.key[i] = c;
-       }
-       store.key[i] = 0;
 
        /*
         * The lock serves a purpose in addition to locking: the new
index 5792425a4948148b5a110346f5b830063dd78914..20039c546f1cc91575771acbe6f52de6778bea89 100644 (file)
@@ -345,7 +345,7 @@ esac
 AC_CACHE_CHECK([if linker supports -R], git_cv_ld_dashr, [
    SAVE_LDFLAGS="${LDFLAGS}"
    LDFLAGS="${SAVE_LDFLAGS} -R /"
-   AC_LINK_IFELSE(AC_LANG_PROGRAM([], []), [git_cv_ld_dashr=yes], [git_cv_ld_dashr=no])
+   AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [git_cv_ld_dashr=yes], [git_cv_ld_dashr=no])
    LDFLAGS="${SAVE_LDFLAGS}"
 ])
 if test "$git_cv_ld_dashr" = "yes"; then
@@ -354,7 +354,7 @@ else
    AC_CACHE_CHECK([if linker supports -Wl,-rpath,], git_cv_ld_wl_rpath, [
       SAVE_LDFLAGS="${LDFLAGS}"
       LDFLAGS="${SAVE_LDFLAGS} -Wl,-rpath,/"
-      AC_LINK_IFELSE(AC_LANG_PROGRAM([], []), [git_cv_ld_wl_rpath=yes], [git_cv_ld_wl_rpath=no])
+      AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [git_cv_ld_wl_rpath=yes], [git_cv_ld_wl_rpath=no])
       LDFLAGS="${SAVE_LDFLAGS}"
    ])
    if test "$git_cv_ld_wl_rpath" = "yes"; then
@@ -363,7 +363,7 @@ else
       AC_CACHE_CHECK([if linker supports -rpath], git_cv_ld_rpath, [
          SAVE_LDFLAGS="${LDFLAGS}"
          LDFLAGS="${SAVE_LDFLAGS} -rpath /"
-         AC_LINK_IFELSE(AC_LANG_PROGRAM([], []), [git_cv_ld_rpath=yes], [git_cv_ld_rpath=no])
+         AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])], [git_cv_ld_rpath=yes], [git_cv_ld_rpath=no])
          LDFLAGS="${SAVE_LDFLAGS}"
       ])
       if test "$git_cv_ld_rpath" = "yes"; then
@@ -472,15 +472,9 @@ if test -z "$NO_ICONV"; then
 
 GIT_STASH_FLAGS($ICONVDIR)
 
-AC_DEFUN([ICONVTEST_SRC], [
-#include <iconv.h>
-
-int main(void)
-{
-       iconv_open("", "");
-       return 0;
-}
-])
+AC_DEFUN([ICONVTEST_SRC],
+[AC_LANG_PROGRAM([#include <iconv.h>],
+ [iconv_open("", "");])])
 
 if test -n "$ICONVDIR"; then
    lib_order="-liconv -lc"
@@ -500,7 +494,7 @@ for l in $lib_order; do
     old_LIBS="$LIBS"
     LIBS="$LIBS $l"
     AC_MSG_CHECKING([for iconv in $l])
-    AC_LINK_IFELSE(ICONVTEST_SRC,
+    AC_LINK_IFELSE([ICONVTEST_SRC],
        [AC_MSG_RESULT([yes])
        NO_ICONV=
        break],
@@ -528,18 +522,12 @@ fi
 GIT_STASH_FLAGS($ZLIB_PATH)
 
 AC_DEFUN([ZLIBTEST_SRC], [
-#include <zlib.h>
-
-int main(void)
-{
-       deflateBound(0, 0);
-       return 0;
-}
-])
+AC_LANG_PROGRAM([#include <zlib.h>],
+ [deflateBound(0, 0);])])
 AC_MSG_CHECKING([for deflateBound in -lz])
 old_LIBS="$LIBS"
 LIBS="$LIBS -lz"
-AC_LINK_IFELSE(ZLIBTEST_SRC,
+AC_LINK_IFELSE([ZLIBTEST_SRC],
        [AC_MSG_RESULT([yes])],
        [AC_MSG_RESULT([no])
        NO_DEFLATE_BOUND=yes])
@@ -631,23 +619,19 @@ AC_SUBST(NO_INTTYPES_H)
 #
 # Define OLD_ICONV if your library has an old iconv(), where the second
 # (input buffer pointer) parameter is declared with type (const char **).
-AC_DEFUN([OLDICONVTEST_SRC], [[
+AC_DEFUN([OLDICONVTEST_SRC], [
+AC_LANG_PROGRAM([[
 #include <iconv.h>
 
 extern size_t iconv(iconv_t cd,
                    char **inbuf, size_t *inbytesleft,
                    char **outbuf, size_t *outbytesleft);
-
-int main(void)
-{
-       return 0;
-}
-]])
+]], [])])
 
 GIT_STASH_FLAGS($ICONVDIR)
 
 AC_MSG_CHECKING([for old iconv()])
-AC_COMPILE_IFELSE(OLDICONVTEST_SRC,
+AC_COMPILE_IFELSE([OLDICONVTEST_SRC],
        [AC_MSG_RESULT([no])],
        [AC_MSG_RESULT([yes])
        OLD_ICONV=UnfortunatelyYes])
@@ -931,18 +915,16 @@ AC_SUBST(NO_INITGROUPS)
 #
 # Define PTHREAD_LIBS to the linker flag used for Pthread support.
 AC_DEFUN([PTHREADTEST_SRC], [
+AC_LANG_PROGRAM([[
 #include <pthread.h>
-
-int main(void)
-{
+]], [[
        pthread_mutex_t test_mutex;
        int retcode = 0;
        retcode |= pthread_mutex_init(&test_mutex,(void *)0);
        retcode |= pthread_mutex_lock(&test_mutex);
        retcode |= pthread_mutex_unlock(&test_mutex);
        return retcode;
-}
-])
+]])])
 
 dnl AC_LANG_CONFTEST([AC_LANG_PROGRAM(
 dnl   [[#include <pthread.h>]],
@@ -962,7 +944,7 @@ elif test -z "$PTHREAD_CFLAGS"; then
      old_CFLAGS="$CFLAGS"
      CFLAGS="$opt $CFLAGS"
      AC_MSG_CHECKING([Checking for POSIX Threads with '$opt'])
-     AC_LINK_IFELSE(PTHREADTEST_SRC,
+     AC_LINK_IFELSE([PTHREADTEST_SRC],
        [AC_MSG_RESULT([yes])
                NO_PTHREADS=
                PTHREAD_LIBS="$opt"
@@ -982,7 +964,7 @@ else
   old_CFLAGS="$CFLAGS"
   CFLAGS="$PTHREAD_CFLAGS $CFLAGS"
   AC_MSG_CHECKING([Checking for POSIX Threads with '$PTHREAD_CFLAGS'])
-  AC_LINK_IFELSE(PTHREADTEST_SRC,
+  AC_LINK_IFELSE([PTHREADTEST_SRC],
        [AC_MSG_RESULT([yes])
                NO_PTHREADS=
                PTHREAD_LIBS="$PTHREAD_CFLAGS"
index 893b7716cafa4811d237480a980140d308aa20dc..3b1cc83e2d120b03d0a2fc8ca36078d22b1c9c15 100755 (executable)
@@ -246,6 +246,8 @@ __git_ps1 ()
                                fi
                        elif [ -f "$g/MERGE_HEAD" ]; then
                                r="|MERGING"
+                       elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
+                               r="|CHERRY-PICKING"
                        elif [ -f "$g/BISECT_LOG" ]; then
                                r="|BISECTING"
                        fi
@@ -662,11 +664,14 @@ __git_compute_merge_strategies ()
        : ${__git_merge_strategies:=$(__git_list_merge_strategies)}
 }
 
-__git_complete_file ()
+__git_complete_revlist_file ()
 {
        local pfx ls ref cur
        _get_comp_words_by_ref -n =: cur
        case "$cur" in
+       *..?*:*)
+               return
+               ;;
        ?*:*)
                ref="${cur%%:*}"
                cur="${cur#*:}"
@@ -680,7 +685,7 @@ __git_complete_file ()
                *)
                        ls="$ref"
                        ;;
-           esac
+               esac
 
                case "$COMP_WORDBREAKS" in
                *:*) : great ;;
@@ -705,17 +710,6 @@ __git_complete_file ()
                                       s/^.*    //')" \
                        -- "$cur"))
                ;;
-       *)
-               __gitcomp "$(__git_refs)"
-               ;;
-       esac
-}
-
-__git_complete_revlist ()
-{
-       local pfx cur
-       _get_comp_words_by_ref -n =: cur
-       case "$cur" in
        *...*)
                pfx="${cur%...*}..."
                cur="${cur#*...}"
@@ -732,6 +726,17 @@ __git_complete_revlist ()
        esac
 }
 
+
+__git_complete_file ()
+{
+       __git_complete_revlist_file
+}
+
+__git_complete_revlist ()
+{
+       __git_complete_revlist_file
+}
+
 __git_complete_remote_or_refspec ()
 {
        local cur words cword
@@ -1354,11 +1359,11 @@ _git_diff ()
                return
                ;;
        esac
-       __git_complete_file
+       __git_complete_revlist_file
 }
 
 __git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff
-                       tkdiff vimdiff gvimdiff xxdiff araxis p4merge
+                       tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc3
 "
 
 _git_difftool ()
index 60a05a8b978345224c0313edb8060f5a7c2ccb54..6bf155cbdb61498bdaf84712a2dea6fb05361ce2 100755 (executable)
@@ -26,6 +26,7 @@ require_work_tree
 cd_to_toplevel
 
 no_commit=
+xopt=
 while case "$#" in 0) break ;; esac
 do
        case "$1" in
@@ -44,6 +45,16 @@ do
        -x|--i-really-want-to-expose-my-private-commit-object-name)
                replay=
                ;;
+       -X?*)
+               xopt="$xopt$(git rev-parse --sq-quote "--${1#-X}")"
+               ;;
+       --strategy-option=*)
+               xopt="$xopt$(git rev-parse --sq-quote "--${1#--strategy-option=}")"
+               ;;
+       -X|--strategy-option)
+               shift
+               xopt="$xopt$(git rev-parse --sq-quote "--$1")"
+               ;;
        -*)
                usage
                ;;
@@ -159,7 +170,7 @@ export GITHEAD_$head GITHEAD_$next
 # and $prev on top of us (when reverting), or the change between
 # $prev and $commit on top of us (when cherry-picking or replaying).
 
-git-merge-recursive $base -- $head $next &&
+eval "git merge-recursive $xopt $base -- $head $next" &&
 result=$(git-write-tree 2>/dev/null) || {
        mv -f .msg "$GIT_DIR/MERGE_MSG"
        {
index 04ce7e3b020f489d59fe103970fc989d7b351127..388151503423aeff0a99ee943f7eebf0c8fec476 100755 (executable)
@@ -333,9 +333,13 @@ def gitBranchExists(branch):
     return proc.wait() == 0;
 
 _gitConfig = {}
-def gitConfig(key):
+def gitConfig(key, args = None): # set args to "--bool", for instance
     if not _gitConfig.has_key(key):
-        _gitConfig[key] = read_pipe("git config %s" % key, ignore_error=True).strip()
+        argsFilter = ""
+        if args != None:
+            argsFilter = "%s " % args
+        cmd = "git config %s%s" % (argsFilter, key)
+        _gitConfig[key] = read_pipe(cmd, ignore_error=True).strip()
     return _gitConfig[key]
 
 def p4BranchesInGit(branchesAreInRemotes = True):
@@ -452,6 +456,19 @@ def p4ChangesForPaths(depotPaths, changeRange):
     changelist.sort()
     return changelist
 
+def p4PathStartsWith(path, prefix):
+    # This method tries to remedy a potential mixed-case issue:
+    #
+    # If UserA adds  //depot/DirA/file1
+    # and UserB adds //depot/dira/file2
+    #
+    # we may or may not have a problem. If you have core.ignorecase=true,
+    # we treat DirA and dira as the same directory
+    ignorecase = gitConfig("core.ignorecase", "--bool") == "true"
+    if ignorecase:
+        return path.lower().startswith(prefix.lower())
+    return path.startswith(prefix)
+
 class Command:
     def __init__(self):
         self.usage = "usage: %prog [options]"
@@ -543,13 +560,13 @@ class P4Submit(Command):
         self.options = [
                 optparse.make_option("--verbose", dest="verbose", action="store_true"),
                 optparse.make_option("--origin", dest="origin"),
-                optparse.make_option("-M", dest="detectRename", action="store_true"),
+                optparse.make_option("-M", dest="detectRenames", action="store_true"),
         ]
         self.description = "Submit changes from git to the perforce depot."
         self.usage += " [name of git branch to submit into perforce depot]"
         self.interactive = True
         self.origin = ""
-        self.detectRename = False
+        self.detectRenames = False
         self.verbose = False
         self.isWindows = (platform.system() == "Windows")
 
@@ -570,7 +587,7 @@ class P4Submit(Command):
                 continue
 
             if inDescriptionSection:
-                if line.startswith("Files:"):
+                if line.startswith("Files:") or line.startswith("Jobs:"):
                     inDescriptionSection = False
                 else:
                     continue
@@ -599,7 +616,7 @@ class P4Submit(Command):
                     lastTab = path.rfind("\t")
                     if lastTab != -1:
                         path = path[:lastTab]
-                        if not path.startswith(self.depotPath):
+                        if not p4PathStartsWith(path, self.depotPath):
                             continue
                 else:
                     inFilesSection = False
@@ -613,7 +630,22 @@ class P4Submit(Command):
 
     def applyCommit(self, id):
         print "Applying %s" % (read_pipe("git log --max-count=1 --pretty=oneline %s" % id))
-        diffOpts = ("", "-M")[self.detectRename]
+
+        if not self.detectRenames:
+            # If not explicitly set check the config variable
+            self.detectRenames = gitConfig("git-p4.detectRenames").lower() == "true"
+
+        if self.detectRenames:
+            diffOpts = "-M"
+        else:
+            diffOpts = ""
+
+        if gitConfig("git-p4.detectCopies").lower() == "true":
+            diffOpts += " -C"
+
+        if gitConfig("git-p4.detectCopiesHarder").lower() == "true":
+            diffOpts += " --find-copies-harder"
+
         diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (diffOpts, id, id))
         filesToAdd = set()
         filesToDelete = set()
@@ -637,11 +669,23 @@ class P4Submit(Command):
                 filesToDelete.add(path)
                 if path in filesToAdd:
                     filesToAdd.remove(path)
+            elif modifier == "C":
+                src, dest = diff['src'], diff['dst']
+                p4_system("integrate -Dt \"%s\" \"%s\"" % (src, dest))
+                if diff['src_sha1'] != diff['dst_sha1']:
+                    p4_system("edit \"%s\"" % (dest))
+                if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
+                    p4_system("edit \"%s\"" % (dest))
+                    filesToChangeExecBit[dest] = diff['dst_mode']
+                os.unlink(dest)
+                editedFiles.add(dest)
             elif modifier == "R":
                 src, dest = diff['src'], diff['dst']
                 p4_system("integrate -Dt \"%s\" \"%s\"" % (src, dest))
-                p4_system("edit \"%s\"" % (dest))
+                if diff['src_sha1'] != diff['dst_sha1']:
+                    p4_system("edit \"%s\"" % (dest))
                 if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
+                    p4_system("edit \"%s\"" % (dest))
                     filesToChangeExecBit[dest] = diff['dst_mode']
                 os.unlink(dest)
                 editedFiles.add(dest)
@@ -834,6 +878,8 @@ class P4Submit(Command):
         return True
 
 class P4Sync(Command):
+    delete_actions = ( "delete", "move/delete", "purge" )
+
     def __init__(self):
         Command.__init__(self)
         self.options = [
@@ -882,6 +928,23 @@ class P4Sync(Command):
         if gitConfig("git-p4.syncFromOrigin") == "false":
             self.syncWithOrigin = False
 
+    #
+    # P4 wildcards are not allowed in filenames.  P4 complains
+    # if you simply add them, but you can force it with "-f", in
+    # which case it translates them into %xx encoding internally.
+    # Search for and fix just these four characters.  Do % last so
+    # that fixing it does not inadvertently create new %-escapes.
+    #
+    def wildcard_decode(self, path):
+        # Cannot have * in a filename in windows; untested as to
+        # what p4 would do in such a case.
+        if not self.isWindows:
+            path = path.replace("%2A", "*")
+        path = path.replace("%23", "#") \
+                   .replace("%40", "@") \
+                   .replace("%25", "%")
+        return path
+
     def extractFilesFromCommit(self, commit):
         self.cloneExclude = [re.sub(r"\.\.\.$", "", path)
                              for path in self.cloneExclude]
@@ -891,11 +954,11 @@ class P4Sync(Command):
             path =  commit["depotFile%s" % fnum]
 
             if [p for p in self.cloneExclude
-                if path.startswith (p)]:
+                if p4PathStartsWith(path, p)]:
                 found = False
             else:
                 found = [p for p in self.depotPaths
-                         if path.startswith (p)]
+                         if p4PathStartsWith(path, p)]
             if not found:
                 fnum = fnum + 1
                 continue
@@ -910,11 +973,27 @@ class P4Sync(Command):
         return files
 
     def stripRepoPath(self, path, prefixes):
+        if self.useClientSpec:
+
+            # if using the client spec, we use the output directory
+            # specified in the client.  For example, a view
+            #   //depot/foo/branch/... //client/branch/foo/...
+            # will end up putting all foo/branch files into
+            #  branch/foo/
+            for val in self.clientSpecDirs:
+                if path.startswith(val[0]):
+                    # replace the depot path with the client path
+                    path = path.replace(val[0], val[1][1])
+                    # now strip out the client (//client/...)
+                    path = re.sub("^(//[^/]+/)", '', path)
+                    # the rest is all path
+                    return path
+
         if self.keepRepoPath:
             prefixes = [re.sub("^(//[^/]+/).*", r'\1', prefixes[0])]
 
         for p in prefixes:
-            if path.startswith(p):
+            if p4PathStartsWith(path, p):
                 path = path[len(p):]
 
         return path
@@ -925,7 +1004,7 @@ class P4Sync(Command):
         while commit.has_key("depotFile%s" % fnum):
             path =  commit["depotFile%s" % fnum]
             found = [p for p in self.depotPaths
-                     if path.startswith (p)]
+                     if p4PathStartsWith(path, p)]
             if not found:
                 fnum = fnum + 1
                 continue
@@ -960,6 +1039,7 @@ class P4Sync(Command):
            return
 
         relPath = self.stripRepoPath(file['depotFile'], self.branchPrefixes)
+        relPath = self.wildcard_decode(relPath)
         if verbose:
             sys.stderr.write("%s\n" % relPath)
 
@@ -1032,16 +1112,16 @@ class P4Sync(Command):
             includeFile = True
             for val in self.clientSpecDirs:
                 if f['path'].startswith(val[0]):
-                    if val[1] <= 0:
+                    if val[1][0] <= 0:
                         includeFile = False
                     break
 
             if includeFile:
                 filesForCommit.append(f)
-                if f['action'] not in ('delete', 'move/delete', 'purge'):
-                    filesToRead.append(f)
-                else:
+                if f['action'] in self.delete_actions:
                     filesToDelete.append(f)
+                else:
+                    filesToRead.append(f)
 
         # deleted files...
         for f in filesToDelete:
@@ -1077,10 +1157,10 @@ class P4Sync(Command):
         # create a commit.
         new_files = []
         for f in files:
-            if [p for p in branchPrefixes if f['path'].startswith(p)]:
+            if [p for p in branchPrefixes if p4PathStartsWith(f['path'], p)]:
                 new_files.append (f)
             else:
-                sys.stderr.write("Ignoring file outside of prefix: %s\n" % path)
+                sys.stderr.write("Ignoring file outside of prefix: %s\n" % f['path'])
 
         self.gitStream.write("commit %s\n" % branch)
 #        gitStream.write("mark :%s\n" % details["change"])
@@ -1127,7 +1207,7 @@ class P4Sync(Command):
 
                 cleanedFiles = {}
                 for info in files:
-                    if info["action"] in ("delete", "purge"):
+                    if info["action"] in self.delete_actions:
                         continue
                     cleanedFiles[info["depotFile"]] = info["rev"]
 
@@ -1241,7 +1321,7 @@ class P4Sync(Command):
                 source = paths[0]
                 destination = paths[1]
                 ## HACK
-                if source.startswith(self.depotPaths[0]) and destination.startswith(self.depotPaths[0]):
+                if p4PathStartsWith(source, self.depotPaths[0]) and p4PathStartsWith(destination, self.depotPaths[0]):
                     source = source[len(self.depotPaths[0]):-4]
                     destination = destination[len(self.depotPaths[0]):-4]
 
@@ -1429,7 +1509,7 @@ class P4Sync(Command):
         print "Doing initial import of %s from revision %s into %s" % (' '.join(self.depotPaths), revision, self.branch)
 
         details = { "user" : "git perforce import user", "time" : int(time.time()) }
-        details["desc"] = ("Initial import of %s from the state at revision %s"
+        details["desc"] = ("Initial import of %s from the state at revision %s\n"
                            % (' '.join(self.depotPaths), revision))
         details["change"] = revision
         newestRevision = 0
@@ -1440,9 +1520,16 @@ class P4Sync(Command):
                                            % (p, revision)
                                            for p in self.depotPaths])):
 
-            if info['code'] == 'error':
+            if 'code' in info and info['code'] == 'error':
                 sys.stderr.write("p4 returned an error: %s\n"
                                  % info['data'])
+                if info['data'].find("must refer to client") >= 0:
+                    sys.stderr.write("This particular p4 error is misleading.\n")
+                    sys.stderr.write("Perhaps the depot path was misspelled.\n");
+                    sys.stderr.write("Depot path:  %s\n" % " ".join(self.depotPaths))
+                sys.exit(1)
+            if 'p4ExitCode' in info:
+                sys.stderr.write("p4 exitcode: %s\n" % info['p4ExitCode'])
                 sys.exit(1)
 
 
@@ -1450,7 +1537,7 @@ class P4Sync(Command):
             if change > newestRevision:
                 newestRevision = change
 
-            if info["action"] in ("delete", "purge"):
+            if info["action"] in self.delete_actions:
                 # don't increase the file cnt, otherwise details["depotFile123"] will have gaps!
                 #fileCnt = fileCnt + 1
                 continue
@@ -1475,19 +1562,45 @@ class P4Sync(Command):
         for entry in specList:
             for k,v in entry.iteritems():
                 if k.startswith("View"):
+
+                    # p4 has these %%1 to %%9 arguments in specs to
+                    # reorder paths; which we can't handle (yet :)
+                    if re.match('%%\d', v) != None:
+                        print "Sorry, can't handle %%n arguments in client specs"
+                        sys.exit(1)
+
                     if v.startswith('"'):
                         start = 1
                     else:
                         start = 0
                     index = v.find("...")
+
+                    # save the "client view"; i.e the RHS of the view
+                    # line that tells the client where to put the
+                    # files for this view.
+                    cv = v[index+3:].strip() # +3 to remove previous '...'
+
+                    # if the client view doesn't end with a
+                    # ... wildcard, then we're going to mess up the
+                    # output directory, so fail gracefully.
+                    if not cv.endswith('...'):
+                        print 'Sorry, client view in "%s" needs to end with wildcard' % (k)
+                        sys.exit(1)
+                    cv=cv[:-3]
+
+                    # now save the view; +index means included, -index
+                    # means it should be filtered out.
                     v = v[start:index]
                     if v.startswith("-"):
                         v = v[1:]
-                        temp[v] = -len(v)
+                        include = -len(v)
                     else:
-                        temp[v] = len(v)
+                        include = len(v)
+
+                    temp[v] = (include, cv)
+
         self.clientSpecDirs = temp.items()
-        self.clientSpecDirs.sort( lambda x, y: abs( y[1] ) - abs( x[1] ) )
+        self.clientSpecDirs.sort( lambda x, y: abs( y[1][0] ) - abs( x[1][0] ) )
 
     def run(self, args):
         self.depotPaths = []
@@ -1667,6 +1780,10 @@ class P4Sync(Command):
 
                 changes.sort()
             else:
+                # catch "git-p4 sync" with no new branches, in a repo that
+                # does not have any existing git-p4 branches
+                if len(args) == 0 and not self.p4BranchesInGit:
+                    die("No remote p4 branches.  Perhaps you never did \"git p4 clone\" in here.");
                 if self.verbose:
                     print "Getting p4 changes for %s...%s" % (', '.join(self.depotPaths),
                                                               self.changeRange)
@@ -1747,10 +1864,13 @@ class P4Clone(P4Sync):
                                  help="where to leave result of the clone"),
             optparse.make_option("-/", dest="cloneExclude",
                                  action="append", type="string",
-                                 help="exclude depot path")
+                                 help="exclude depot path"),
+            optparse.make_option("--bare", dest="cloneBare",
+                                 action="store_true", default=False),
         ]
         self.cloneDestination = None
         self.needsGit = False
+        self.cloneBare = False
 
     # This is required for the "append" cloneExclude action
     def ensure_value(self, attr, value):
@@ -1790,11 +1910,16 @@ class P4Clone(P4Sync):
             self.cloneDestination = self.defaultDestination(args)
 
         print "Importing from %s into %s" % (', '.join(depotPaths), self.cloneDestination)
+
         if not os.path.exists(self.cloneDestination):
             os.makedirs(self.cloneDestination)
         chdir(self.cloneDestination)
-        system("git init")
-        self.gitdir = os.getcwd() + "/.git"
+
+        init_cmd = [ "git", "init" ]
+        if self.cloneBare:
+            init_cmd.append("--bare")
+        subprocess.check_call(init_cmd)
+
         if not P4Sync.run(self, depotPaths):
             return False
         if self.branch != "master":
@@ -1804,7 +1929,8 @@ class P4Clone(P4Sync):
                 masterbranch = "refs/heads/p4/master"
             if gitBranchExists(masterbranch):
                 system("git branch master %s" % masterbranch)
-                system("git checkout -f")
+                if not self.cloneBare:
+                    system("git checkout -f")
             else:
                 print "Could not detect main branch. No checkout/master branch created."
 
index 49b335921a3871d82a2c0110170a6e66d71561ee..e09da445b692db2a1cbdba7ee49456de6e2571e9 100644 (file)
@@ -191,6 +191,11 @@ git-p4.useclientspec
 
   git config [--global] git-p4.useclientspec false
 
+The P4CLIENT environment variable should be correctly set for p4 to be
+able to find the relevant client.  This client spec will be used to
+both filter the files cloned by git and set the directory layout as
+specified in the client (this implies --keep-path style semantics).
+
 Implementation Details...
 =========================
 
index f99ea9585014face001849aeeefa5f20e79bc1e2..21989fc6ab84c0503cdc9418673d9d0bf06f9d49 100755 (executable)
@@ -709,7 +709,7 @@ if [ -z "$GIT_DIR" ]; then
        exit 1
 fi
 
-projectdesc=$(sed -ne '1p' "$GIT_DIR/description")
+projectdesc=$(sed -ne '1p' "$GIT_DIR/description" 2>/dev/null)
 # Check if the description is unchanged from it's default, and shorten it to
 # a more manageable length if it is
 if expr "$projectdesc" : "Unnamed repository.*$" >/dev/null
index a2677b03e0ff8347d13a5d56f4fa2e1aba18824a..35db24f5eae600a973391915ceb61c4635941aec 100644 (file)
@@ -8,7 +8,8 @@
 
 int main(int argc, char **argv)
 {
-       svndump_init(NULL);
+       if (svndump_init(NULL))
+               return 1;
        svndump_read((argc > 1) ? argv[1] : NULL);
        svndump_deinit();
        svndump_reset();
index 35f84bd9e7577b58bc9905c8b46806bfb37963ff..cd075b96c54419fdaa25c56b24133dd080f440ca 100644 (file)
@@ -18,6 +18,9 @@ Subversion repository mirrored on the local disk. Remote Subversion
 repositories can be mirrored on local disk using the `svnsync`
 command.
 
+Note: this tool is very young.  The details of its commandline
+interface may change in backward incompatible ways.
+
 INPUT FORMAT
 ------------
 Subversion's repository dump format is documented in full in
index d5aebed48df3387e966a23b6ee460dc2244f728e..7eb51b16ed03e650f3af11383c5c43c00d7d9812 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -18,7 +18,7 @@ enum action {
        CRLF_TEXT,
        CRLF_INPUT,
        CRLF_CRLF,
-       CRLF_AUTO,
+       CRLF_AUTO
 };
 
 struct text_stat {
index 347fd0c52b4cd797f5dafffb6885324f7c7f0274..4c8346d5a1fe1325de2dd335a4e61a2dad994211 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -660,7 +660,7 @@ static void check_dead_children(void)
 static char **cld_argv;
 static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
 {
-       struct child_process cld = { 0 };
+       struct child_process cld = { NULL };
        char addrbuf[300] = "REMOTE_ADDR=", portbuf[300];
        char *env[] = { addrbuf, portbuf, NULL };
 
index 392ce2bef05746cea7922d39da67bf25d1d3d192..2870de400ed533d83c77269ee1654af212c6510c 100644 (file)
@@ -103,10 +103,11 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
                unsigned dirty_submodule = 0;
 
                if (DIFF_OPT_TST(&revs->diffopt, QUICK) &&
-                       DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))
+                   !revs->diffopt.filter &&
+                   DIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))
                        break;
 
-               if (!ce_path_match(ce, revs->prune_data))
+               if (!ce_path_match(ce, &revs->prune_data))
                        continue;
 
                if (ce_stage(ce)) {
@@ -427,7 +428,7 @@ static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o)
        if (tree == o->df_conflict_entry)
                tree = NULL;
 
-       if (ce_path_match(idx ? idx : tree, revs->prune_data))
+       if (ce_path_match(idx ? idx : tree, &revs->prune_data))
                do_oneway_diff(o, idx, tree);
 
        return 0;
@@ -501,7 +502,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
        active_nr = dst - active_cache;
 
        init_revisions(&revs, NULL);
-       revs.prune_data = opt->paths;
+       init_pathspec(&revs.prune_data, opt->pathspec.raw);
        tree = parse_tree_indirect(tree_sha1);
        if (!tree)
                die("bad tree object %s", sha1_to_hex(tree_sha1));
index ce9e783407437bb1e0efc6d5bc2392af26da5a41..3a36144687ae2f5bf7bb3afc914ddbada8d5ff93 100644 (file)
@@ -231,8 +231,9 @@ void diff_no_index(struct rev_info *revs,
 
        if (prefix) {
                int len = strlen(prefix);
+               const char *paths[3];
+               memset(paths, 0, sizeof(paths));
 
-               revs->diffopt.paths = xcalloc(2, sizeof(char *));
                for (i = 0; i < 2; i++) {
                        const char *p = argv[argc - 2 + i];
                        /*
@@ -242,12 +243,12 @@ void diff_no_index(struct rev_info *revs,
                        p = (strcmp(p, "-")
                             ? xstrdup(prefix_filename(prefix, len, p))
                             : p);
-                       revs->diffopt.paths[i] = p;
+                       paths[i] = p;
                }
+               diff_tree_setup_paths(paths, &revs->diffopt);
        }
        else
-               revs->diffopt.paths = argv + argc - 2;
-       revs->diffopt.nr_paths = 2;
+               diff_tree_setup_paths(argv + argc - 2, &revs->diffopt);
        revs->diffopt.skip_stat_unmatch = 1;
        if (!revs->diffopt.output_format)
                revs->diffopt.output_format = DIFF_FORMAT_PATCH;
@@ -259,8 +260,8 @@ void diff_no_index(struct rev_info *revs,
        if (diff_setup_done(&revs->diffopt) < 0)
                die("diff_setup_done failed");
 
-       if (queue_diff(&revs->diffopt, revs->diffopt.paths[0],
-                      revs->diffopt.paths[1]))
+       if (queue_diff(&revs->diffopt, revs->diffopt.pathspec.raw[0],
+                      revs->diffopt.pathspec.raw[1]))
                exit(1);
        diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/");
        diffcore_std(&revs->diffopt);
diff --git a/diff.c b/diff.c
index 5422c438826254f36d1e00af0e8b882690661276..9b3eb9938f8cf9f81cac2b9e79da34e1e02e727c 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -23,7 +23,7 @@
 #endif
 
 static int diff_detect_rename_default;
-static int diff_rename_limit_default = 200;
+static int diff_rename_limit_default = 400;
 static int diff_suppress_blank_empty;
 int diff_use_color_default = -1;
 static const char *diff_word_regex_cfg;
@@ -245,6 +245,15 @@ static int fill_mmfile(mmfile_t *mf, struct diff_filespec *one)
        return 0;
 }
 
+/* like fill_mmfile, but only for size, so we can avoid retrieving blob */
+static unsigned long diff_filespec_size(struct diff_filespec *one)
+{
+       if (!DIFF_FILE_VALID(one))
+               return 0;
+       diff_populate_filespec(one, 1);
+       return one->size;
+}
+
 static int count_trailing_blank(mmfile_t *mf, unsigned ws_rule)
 {
        char *ptr = mf->ptr;
@@ -606,22 +615,20 @@ static void diff_words_append(char *line, unsigned long len,
        buffer->text.ptr[buffer->text.size] = '\0';
 }
 
-struct diff_words_style_elem
-{
+struct diff_words_style_elem {
        const char *prefix;
        const char *suffix;
        const char *color; /* NULL; filled in by the setup code if
                            * color is enabled */
 };
 
-struct diff_words_style
-{
+struct diff_words_style {
        enum diff_words_type type;
        struct diff_words_style_elem new, old, ctx;
        const char *newline;
 };
 
-struct diff_words_style diff_words_styles[] = {
+static struct diff_words_style diff_words_styles[] = {
        { DIFF_WORDS_PORCELAIN, {"+", "\n"}, {"-", "\n"}, {" ", "\n"}, "~\n" },
        { DIFF_WORDS_PLAIN, {"{+", "+}"}, {"[-", "-]"}, {"", ""}, "\n" },
        { DIFF_WORDS_COLOR, {"", ""}, {"", ""}, {"", ""}, "\n" }
@@ -2079,25 +2086,28 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
                data->is_unmerged = 1;
                return;
        }
-       if (complete_rewrite) {
+
+       if (diff_filespec_is_binary(one) || diff_filespec_is_binary(two)) {
+               data->is_binary = 1;
+               data->added = diff_filespec_size(two);
+               data->deleted = diff_filespec_size(one);
+       }
+
+       else if (complete_rewrite) {
                diff_populate_filespec(one, 0);
                diff_populate_filespec(two, 0);
                data->deleted = count_lines(one->data, one->size);
                data->added = count_lines(two->data, two->size);
-               goto free_and_return;
        }
-       if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
-               die("unable to read files to diff");
 
-       if (diff_filespec_is_binary(one) || diff_filespec_is_binary(two)) {
-               data->is_binary = 1;
-               data->added = mf2.size;
-               data->deleted = mf1.size;
-       } else {
+       else {
                /* Crazy xdl interfaces.. */
                xpparam_t xpp;
                xdemitconf_t xecfg;
 
+               if (fill_mmfile(&mf1, one) < 0 || fill_mmfile(&mf2, two) < 0)
+                       die("unable to read files to diff");
+
                memset(&xpp, 0, sizeof(xpp));
                memset(&xecfg, 0, sizeof(xecfg));
                xpp.flags = o->xdl_opts;
@@ -2105,7 +2115,6 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
                              &xpp, &xecfg);
        }
 
- free_and_return:
        diff_free_filespec_data(one);
        diff_free_filespec_data(two);
 }
diff --git a/diff.h b/diff.h
index 0083d92438916a8188656df140ba70d6acc8c6f6..007a0554d4b252e83e98f5578758d51ec0c6e120 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -110,7 +110,8 @@ struct diff_options {
        int pickaxe_opts;
        int rename_score;
        int rename_limit;
-       int warn_on_too_large_rename;
+       int needed_rename_limit;
+       int show_rename_progress;
        int dirstat_percent;
        int setup;
        int abbrev;
@@ -133,9 +134,7 @@ struct diff_options {
        FILE *file;
        int close_file;
 
-       int nr_paths;
-       const char **paths;
-       int *pathlens;
+       struct pathspec pathspec;
        change_fn_t change;
        add_remove_fn_t add_remove;
        diff_format_fn_t format_callback;
index df41be56deab60d4d39a45920a1e62b05d0474f6..d40e40a3ac9c919475d6157464fa906e37b0dd80 100644 (file)
@@ -5,6 +5,7 @@
 #include "diff.h"
 #include "diffcore.h"
 #include "hash.h"
+#include "progress.h"
 
 /* Table of rename/copy destinations */
 
@@ -170,7 +171,7 @@ static int estimate_similarity(struct diff_filespec *src,
         * and the final score computation below would not have a
         * divide-by-zero issue.
         */
-       if (base_size * (MAX_SCORE-minimum_score) < delta_size * MAX_SCORE)
+       if (max_size * (MAX_SCORE-minimum_score) < delta_size * MAX_SCORE)
                return 0;
 
        if (!src->cnt_data && diff_populate_filespec(src, 0))
@@ -247,7 +248,8 @@ struct file_similarity {
 };
 
 static int find_identical_files(struct file_similarity *src,
-                               struct file_similarity *dst)
+                               struct file_similarity *dst,
+                               struct diff_options *options)
 {
        int renames = 0;
 
@@ -277,6 +279,8 @@ static int find_identical_files(struct file_similarity *src,
                        }
                        /* Give higher scores to sources that haven't been used already */
                        score = !source->rename_used;
+                       if (source->rename_used && options->detect_rename != DIFF_DETECT_COPY)
+                               continue;
                        score += basename_same(source, target);
                        if (score > best_score) {
                                best = p;
@@ -306,11 +310,12 @@ static void free_similarity_list(struct file_similarity *p)
        }
 }
 
-static int find_same_files(void *ptr)
+static int find_same_files(void *ptr, void *data)
 {
        int ret;
        struct file_similarity *p = ptr;
        struct file_similarity *src = NULL, *dst = NULL;
+       struct diff_options *options = data;
 
        /* Split the hash list up into sources and destinations */
        do {
@@ -329,7 +334,7 @@ static int find_same_files(void *ptr)
         * If we have both sources *and* destinations, see if
         * we can match them up
         */
-       ret = (src && dst) ? find_identical_files(src, dst) : 0;
+       ret = (src && dst) ? find_identical_files(src, dst, options) : 0;
 
        /* Free the hashes and return the number of renames found */
        free_similarity_list(src);
@@ -377,7 +382,7 @@ static void insert_file_table(struct hash_table *table, int src_dst, int index,
  * and then during the second round we try to match
  * cache-dirty entries as well.
  */
-static int find_exact_renames(void)
+static int find_exact_renames(struct diff_options *options)
 {
        int i;
        struct hash_table file_table;
@@ -390,7 +395,7 @@ static int find_exact_renames(void)
                insert_file_table(&file_table, 1, i, rename_dst[i].two);
 
        /* Find the renames */
-       i = for_each_hash(&file_table, find_same_files);
+       i = for_each_hash(&file_table, find_same_files, options);
 
        /* .. and free the hash data structure */
        free_hash(&file_table);
@@ -414,6 +419,27 @@ static void record_if_better(struct diff_score m[], struct diff_score *o)
                m[worst] = *o;
 }
 
+static int find_renames(struct diff_score *mx, int dst_cnt, int minimum_score, int copies)
+{
+       int count = 0, i;
+
+       for (i = 0; i < dst_cnt * NUM_CANDIDATE_PER_DST; i++) {
+               struct diff_rename_dst *dst;
+
+               if ((mx[i].dst < 0) ||
+                   (mx[i].score < minimum_score))
+                       break; /* there is no more usable pair. */
+               dst = &rename_dst[mx[i].dst];
+               if (dst->pair)
+                       continue; /* already done, either exact or fuzzy. */
+               if (!copies && rename_src[mx[i].src].one->rename_used)
+                       continue;
+               record_rename_pair(mx[i].dst, mx[i].src, mx[i].score);
+               count++;
+       }
+       return count;
+}
+
 void diffcore_rename(struct diff_options *options)
 {
        int detect_rename = options->detect_rename;
@@ -424,6 +450,7 @@ void diffcore_rename(struct diff_options *options)
        struct diff_score *mx;
        int i, j, rename_count;
        int num_create, num_src, dst_cnt;
+       struct progress *progress = NULL;
 
        if (!minimum_score)
                minimum_score = DEFAULT_RENAME_SCORE;
@@ -467,7 +494,7 @@ void diffcore_rename(struct diff_options *options)
         * We really want to cull the candidates list early
         * with cheap tests in order to avoid doing deltas.
         */
-       rename_count = find_exact_renames();
+       rename_count = find_exact_renames(options);
 
        /* Did we only want exact renames? */
        if (minimum_score == MAX_SCORE)
@@ -493,15 +520,22 @@ void diffcore_rename(struct diff_options *options)
         * but handles the potential overflow case specially (and we
         * assume at least 32-bit integers)
         */
+       options->needed_rename_limit = 0;
        if (rename_limit <= 0 || rename_limit > 32767)
                rename_limit = 32767;
        if ((num_create > rename_limit && num_src > rename_limit) ||
            (num_create * num_src > rename_limit * rename_limit)) {
-               if (options->warn_on_too_large_rename)
-                       warning("too many files (created: %d deleted: %d), skipping inexact rename detection", num_create, num_src);
+               options->needed_rename_limit =
+                       num_src > num_create ? num_src : num_create;
                goto cleanup;
        }
 
+       if (options->show_rename_progress) {
+               progress = start_progress_delay(
+                               "Performing inexact rename detection",
+                               rename_dst_nr * rename_src_nr, 50, 1);
+       }
+
        mx = xcalloc(num_create * NUM_CANDIDATE_PER_DST, sizeof(*mx));
        for (dst_cnt = i = 0; i < rename_dst_nr; i++) {
                struct diff_filespec *two = rename_dst[i].two;
@@ -531,38 +565,16 @@ void diffcore_rename(struct diff_options *options)
                        diff_free_filespec_blob(two);
                }
                dst_cnt++;
+               display_progress(progress, (i+1)*rename_src_nr);
        }
+       stop_progress(&progress);
 
        /* cost matrix sorted by most to least similar pair */
        qsort(mx, dst_cnt * NUM_CANDIDATE_PER_DST, sizeof(*mx), score_compare);
 
-       for (i = 0; i < dst_cnt * NUM_CANDIDATE_PER_DST; i++) {
-               struct diff_rename_dst *dst;
-
-               if ((mx[i].dst < 0) ||
-                   (mx[i].score < minimum_score))
-                       break; /* there is no more usable pair. */
-               dst = &rename_dst[mx[i].dst];
-               if (dst->pair)
-                       continue; /* already done, either exact or fuzzy. */
-               if (rename_src[mx[i].src].one->rename_used)
-                       continue;
-               record_rename_pair(mx[i].dst, mx[i].src, mx[i].score);
-               rename_count++;
-       }
-
-       for (i = 0; i < dst_cnt * NUM_CANDIDATE_PER_DST; i++) {
-               struct diff_rename_dst *dst;
-
-               if ((mx[i].dst < 0) ||
-                   (mx[i].score < minimum_score))
-                       break; /* there is no more usable pair. */
-               dst = &rename_dst[mx[i].dst];
-               if (dst->pair)
-                       continue; /* already done, either exact or fuzzy. */
-               record_rename_pair(mx[i].dst, mx[i].src, mx[i].score);
-               rename_count++;
-       }
+       rename_count += find_renames(mx, dst_cnt, minimum_score, 0);
+       if (detect_rename == DIFF_DETECT_COPY)
+               rename_count += find_renames(mx, dst_cnt, minimum_score, 1);
        free(mx);
 
  cleanup:
diff --git a/dir.c b/dir.c
index 570b651a17520cbb0273b9247ab0fcffc0129477..325fb56ad395c9b47dcbdea47b2833a4287198bc 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -87,6 +87,21 @@ int fill_directory(struct dir_struct *dir, const char **pathspec)
        return len;
 }
 
+int within_depth(const char *name, int namelen,
+                       int depth, int max_depth)
+{
+       const char *cp = name, *cpe = name + namelen;
+
+       while (cp < cpe) {
+               if (*cp++ != '/')
+                       continue;
+               depth++;
+               if (depth > max_depth)
+                       return 0;
+       }
+       return 1;
+}
+
 /*
  * Does 'match' match the given name?
  * A match is found if
@@ -184,6 +199,95 @@ int match_pathspec(const char **pathspec, const char *name, int namelen,
        return retval;
 }
 
+/*
+ * Does 'match' match the given name?
+ * A match is found if
+ *
+ * (1) the 'match' string is leading directory of 'name', or
+ * (2) the 'match' string is a wildcard and matches 'name', or
+ * (3) the 'match' string is exactly the same as 'name'.
+ *
+ * and the return value tells which case it was.
+ *
+ * It returns 0 when there is no match.
+ */
+static int match_pathspec_item(const struct pathspec_item *item, int prefix,
+                              const char *name, int namelen)
+{
+       /* name/namelen has prefix cut off by caller */
+       const char *match = item->match + prefix;
+       int matchlen = item->len - prefix;
+
+       /* If the match was just the prefix, we matched */
+       if (!*match)
+               return MATCHED_RECURSIVELY;
+
+       if (matchlen <= namelen && !strncmp(match, name, matchlen)) {
+               if (matchlen == namelen)
+                       return MATCHED_EXACTLY;
+
+               if (match[matchlen-1] == '/' || name[matchlen] == '/')
+                       return MATCHED_RECURSIVELY;
+       }
+
+       if (item->has_wildcard && !fnmatch(match, name, 0))
+               return MATCHED_FNMATCH;
+
+       return 0;
+}
+
+/*
+ * Given a name and a list of pathspecs, see if the name matches
+ * any of the pathspecs.  The caller is also interested in seeing
+ * all pathspec matches some names it calls this function with
+ * (otherwise the user could have mistyped the unmatched pathspec),
+ * and a mark is left in seen[] array for pathspec element that
+ * actually matched anything.
+ */
+int match_pathspec_depth(const struct pathspec *ps,
+                        const char *name, int namelen,
+                        int prefix, char *seen)
+{
+       int i, retval = 0;
+
+       if (!ps->nr) {
+               if (!ps->recursive || ps->max_depth == -1)
+                       return MATCHED_RECURSIVELY;
+
+               if (within_depth(name, namelen, 0, ps->max_depth))
+                       return MATCHED_EXACTLY;
+               else
+                       return 0;
+       }
+
+       name += prefix;
+       namelen -= prefix;
+
+       for (i = ps->nr - 1; i >= 0; i--) {
+               int how;
+               if (seen && seen[i] == MATCHED_EXACTLY)
+                       continue;
+               how = match_pathspec_item(ps->items+i, prefix, name, namelen);
+               if (ps->recursive && ps->max_depth != -1 &&
+                   how && how != MATCHED_FNMATCH) {
+                       int len = ps->items[i].len;
+                       if (name[len] == '/')
+                               len++;
+                       if (within_depth(name+len, namelen-len, 0, ps->max_depth))
+                               how = MATCHED_EXACTLY;
+                       else
+                               how = 0;
+               }
+               if (how) {
+                       if (retval < how)
+                               retval = how;
+                       if (seen && seen[i] < how)
+                               seen[i] = how;
+               }
+       }
+       return retval;
+}
+
 static int no_wildcard(const char *string)
 {
        return string[strcspn(string, "*?[{\\")] == '\0';
@@ -1024,7 +1128,7 @@ char *get_relative_cwd(char *buffer, int size, const char *dir)
                die_errno("can't find the current directory");
 
        if (!is_absolute_path(dir))
-               dir = make_absolute_path(dir);
+               dir = real_path(dir);
 
        while (*dir && *dir == *cwd) {
                dir++;
@@ -1151,3 +1255,50 @@ int remove_path(const char *name)
        return 0;
 }
 
+static int pathspec_item_cmp(const void *a_, const void *b_)
+{
+       struct pathspec_item *a, *b;
+
+       a = (struct pathspec_item *)a_;
+       b = (struct pathspec_item *)b_;
+       return strcmp(a->match, b->match);
+}
+
+int init_pathspec(struct pathspec *pathspec, const char **paths)
+{
+       const char **p = paths;
+       int i;
+
+       memset(pathspec, 0, sizeof(*pathspec));
+       if (!p)
+               return 0;
+       while (*p)
+               p++;
+       pathspec->raw = paths;
+       pathspec->nr = p - paths;
+       if (!pathspec->nr)
+               return 0;
+
+       pathspec->items = xmalloc(sizeof(struct pathspec_item)*pathspec->nr);
+       for (i = 0; i < pathspec->nr; i++) {
+               struct pathspec_item *item = pathspec->items+i;
+               const char *path = paths[i];
+
+               item->match = path;
+               item->len = strlen(path);
+               item->has_wildcard = !no_wildcard(path);
+               if (item->has_wildcard)
+                       pathspec->has_wildcard = 1;
+       }
+
+       qsort(pathspec->items, pathspec->nr,
+             sizeof(struct pathspec_item), pathspec_item_cmp);
+
+       return 0;
+}
+
+void free_pathspec(struct pathspec *pathspec)
+{
+       free(pathspec->items);
+       pathspec->items = NULL;
+}
diff --git a/dir.h b/dir.h
index 72a764ed84828e4a6336d2880f2167fbc9d3143a..aa511da77b0ec54cbdbd3786faad0c1285df7182 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -65,6 +65,10 @@ struct dir_struct {
 #define MATCHED_FNMATCH 2
 #define MATCHED_EXACTLY 3
 extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);
+extern int match_pathspec_depth(const struct pathspec *pathspec,
+                               const char *name, int namelen,
+                               int prefix, char *seen);
+extern int within_depth(const char *name, int namelen, int depth, int max_depth);
 
 extern int fill_directory(struct dir_struct *dir, const char **pathspec);
 extern int read_directory(struct dir_struct *, const char *path, int len, const char **pathspec);
index f2d90a807b7d50cc3fb6dd7a5c017d0dbc2937dc..f4549d3f7b0367b31b0fa0042fb12ff183beb081 100644 (file)
@@ -22,7 +22,6 @@ int prefer_symlink_refs;
 int is_bare_repository_cfg = -1; /* unspecified */
 int log_all_ref_updates = -1; /* unspecified */
 int warn_ambiguous_refs = 1;
-int unique_abbrev_extra_length;
 int repository_format_version;
 const char *git_commit_encoding;
 const char *git_log_output_encoding;
@@ -141,7 +140,7 @@ static int git_work_tree_initialized;
 void set_git_work_tree(const char *new_work_tree)
 {
        if (git_work_tree_initialized) {
-               new_work_tree = make_absolute_path(new_work_tree);
+               new_work_tree = real_path(new_work_tree);
                if (strcmp(new_work_tree, work_tree))
                        die("internal error: work tree has already been set\n"
                            "Current worktree: %s\nNew worktree: %s",
@@ -149,7 +148,7 @@ void set_git_work_tree(const char *new_work_tree)
                return;
        }
        git_work_tree_initialized = 1;
-       work_tree = xstrdup(make_absolute_path(new_work_tree));
+       work_tree = xstrdup(real_path(new_work_tree));
 }
 
 const char *get_git_work_tree(void)
index 38545e8bfd72c8cd4f91e0d33257b143db86bac5..171e841531de7fd5b51aa26f639104382395b854 100644 (file)
@@ -89,7 +89,7 @@ static void add_path(struct strbuf *out, const char *path)
                if (is_absolute_path(path))
                        strbuf_addstr(out, path);
                else
-                       strbuf_addstr(out, make_nonrelative_path(path));
+                       strbuf_addstr(out, absolute_path(path));
 
                strbuf_addch(out, PATH_SEP);
        }
index 60f26fe473ad6922166e952f4f7e5be2b79d45de..65d65bf8f91b7a584c7dc77f84a5dec263c3d11c 100644 (file)
@@ -24,10 +24,12 @@ Format of STDIN stream:
     commit_msg
     ('from' sp committish lf)?
     ('merge' sp committish lf)*
-    file_change*
+    (file_change | ls)*
     lf?;
   commit_msg ::= data;
 
+  ls ::= 'ls' sp '"' quoted(path) '"' lf;
+
   file_change ::= file_clr
     | file_del
     | file_rnm
@@ -132,7 +134,7 @@ Format of STDIN stream:
   ts    ::= # time since the epoch in seconds, ascii base10 notation;
   tz    ::= # GIT style timezone;
 
-     # note: comments and cat requests may appear anywhere
+     # note: comments, ls and cat requests may appear anywhere
      # in the input, except within a data command.  Any form
      # of the data command always escapes the related input
      # from comment processing.
@@ -141,7 +143,9 @@ Format of STDIN stream:
      # must be the first character on that line (an lf
      # preceded it).
      #
+
   cat_blob ::= 'cat-blob' sp (hexsha1 | idnum) lf;
+  ls_tree  ::= 'ls' sp (hexsha1 | idnum) sp path_str lf;
 
   comment ::= '#' not_lf* lf;
   not_lf  ::= # Any byte that is not ASCII newline (LF);
@@ -166,8 +170,7 @@ Format of STDIN stream:
 #define DEPTH_BITS 13
 #define MAX_DEPTH ((1<<DEPTH_BITS)-1)
 
-struct object_entry
-{
+struct object_entry {
        struct pack_idx_entry idx;
        struct object_entry *next;
        uint32_t type : TYPE_BITS,
@@ -175,16 +178,14 @@ struct object_entry
                depth : DEPTH_BITS;
 };
 
-struct object_entry_pool
-{
+struct object_entry_pool {
        struct object_entry_pool *next_pool;
        struct object_entry *next_free;
        struct object_entry *end;
        struct object_entry entries[FLEX_ARRAY]; /* more */
 };
 
-struct mark_set
-{
+struct mark_set {
        union {
                struct object_entry *marked[1024];
                struct mark_set *sets[1024];
@@ -192,57 +193,49 @@ struct mark_set
        unsigned int shift;
 };
 
-struct last_object
-{
+struct last_object {
        struct strbuf data;
        off_t offset;
        unsigned int depth;
        unsigned no_swap : 1;
 };
 
-struct mem_pool
-{
+struct mem_pool {
        struct mem_pool *next_pool;
        char *next_free;
        char *end;
        uintmax_t space[FLEX_ARRAY]; /* more */
 };
 
-struct atom_str
-{
+struct atom_str {
        struct atom_str *next_atom;
        unsigned short str_len;
        char str_dat[FLEX_ARRAY]; /* more */
 };
 
 struct tree_content;
-struct tree_entry
-{
+struct tree_entry {
        struct tree_content *tree;
        struct atom_str *name;
-       struct tree_entry_ms
-       {
+       struct tree_entry_ms {
                uint16_t mode;
                unsigned char sha1[20];
        } versions[2];
 };
 
-struct tree_content
-{
+struct tree_content {
        unsigned int entry_capacity; /* must match avail_tree_content */
        unsigned int entry_count;
        unsigned int delta_depth;
        struct tree_entry *entries[FLEX_ARRAY]; /* more */
 };
 
-struct avail_tree_content
-{
+struct avail_tree_content {
        unsigned int entry_capacity; /* must match tree_content */
        struct avail_tree_content *next_avail;
 };
 
-struct branch
-{
+struct branch {
        struct branch *table_next_branch;
        struct branch *active_next_branch;
        const char *name;
@@ -254,16 +247,14 @@ struct branch
        unsigned char sha1[20];
 };
 
-struct tag
-{
+struct tag {
        struct tag *next_tag;
        const char *name;
        unsigned int pack_id;
        unsigned char sha1[20];
 };
 
-struct hash_list
-{
+struct hash_list {
        struct hash_list *next;
        unsigned char sha1[20];
 };
@@ -274,8 +265,7 @@ typedef enum {
        WHENSPEC_NOW
 } whenspec_type;
 
-struct recent_command
-{
+struct recent_command {
        struct recent_command *prev;
        struct recent_command *next;
        char *buf;
@@ -329,6 +319,7 @@ static struct mark_set *marks;
 static const char *export_marks_file;
 static const char *import_marks_file;
 static int import_marks_file_from_stream;
+static int import_marks_file_ignore_missing;
 static int relative_marks_paths;
 
 /* Our last blob */
@@ -373,6 +364,7 @@ static int cat_blob_fd = STDOUT_FILENO;
 
 static void parse_argv(void);
 static void parse_cat_blob(void);
+static void parse_ls(struct branch *b);
 
 static void write_branch_report(FILE *rpt, struct branch *b)
 {
@@ -871,6 +863,7 @@ static void start_packfile(void)
        p = xcalloc(1, sizeof(*p) + strlen(tmpfile) + 2);
        strcpy(p->pack_name, tmpfile);
        p->pack_fd = pack_fd;
+       p->do_not_close = 1;
        pack_file = sha1fd(pack_fd, p->pack_name);
 
        hdr.hdr_signature = htonl(PACK_SIGNATURE);
@@ -1795,7 +1788,11 @@ static void read_marks(void)
 {
        char line[512];
        FILE *f = fopen(import_marks_file, "r");
-       if (!f)
+       if (f)
+               ;
+       else if (import_marks_file_ignore_missing && errno == ENOENT)
+               return; /* Marks file does not exist */
+       else
                die_errno("cannot read '%s'", import_marks_file);
        while (fgets(line, sizeof(line), f)) {
                uintmax_t mark;
@@ -2609,6 +2606,8 @@ static void parse_new_commit(void)
                        note_change_n(b, prev_fanout);
                else if (!strcmp("deleteall", command_buf.buf))
                        file_change_deleteall(b);
+               else if (!prefixcmp(command_buf.buf, "ls "))
+                       parse_ls(b);
                else {
                        unread_command_buf = 1;
                        break;
@@ -2832,6 +2831,153 @@ static void parse_cat_blob(void)
        cat_blob(oe, sha1);
 }
 
+static struct object_entry *dereference(struct object_entry *oe,
+                                       unsigned char sha1[20])
+{
+       unsigned long size;
+       char *buf = NULL;
+       if (!oe) {
+               enum object_type type = sha1_object_info(sha1, NULL);
+               if (type < 0)
+                       die("object not found: %s", sha1_to_hex(sha1));
+               /* cache it! */
+               oe = insert_object(sha1);
+               oe->type = type;
+               oe->pack_id = MAX_PACK_ID;
+               oe->idx.offset = 1;
+       }
+       switch (oe->type) {
+       case OBJ_TREE:  /* easy case. */
+               return oe;
+       case OBJ_COMMIT:
+       case OBJ_TAG:
+               break;
+       default:
+               die("Not a treeish: %s", command_buf.buf);
+       }
+
+       if (oe->pack_id != MAX_PACK_ID) {       /* in a pack being written */
+               buf = gfi_unpack_entry(oe, &size);
+       } else {
+               enum object_type unused;
+               buf = read_sha1_file(sha1, &unused, &size);
+       }
+       if (!buf)
+               die("Can't load object %s", sha1_to_hex(sha1));
+
+       /* Peel one layer. */
+       switch (oe->type) {
+       case OBJ_TAG:
+               if (size < 40 + strlen("object ") ||
+                   get_sha1_hex(buf + strlen("object "), sha1))
+                       die("Invalid SHA1 in tag: %s", command_buf.buf);
+               break;
+       case OBJ_COMMIT:
+               if (size < 40 + strlen("tree ") ||
+                   get_sha1_hex(buf + strlen("tree "), sha1))
+                       die("Invalid SHA1 in commit: %s", command_buf.buf);
+       }
+
+       free(buf);
+       return find_object(sha1);
+}
+
+static struct object_entry *parse_treeish_dataref(const char **p)
+{
+       unsigned char sha1[20];
+       struct object_entry *e;
+
+       if (**p == ':') {       /* <mark> */
+               char *endptr;
+               e = find_mark(strtoumax(*p + 1, &endptr, 10));
+               if (endptr == *p + 1)
+                       die("Invalid mark: %s", command_buf.buf);
+               if (!e)
+                       die("Unknown mark: %s", command_buf.buf);
+               *p = endptr;
+               hashcpy(sha1, e->idx.sha1);
+       } else {        /* <sha1> */
+               if (get_sha1_hex(*p, sha1))
+                       die("Invalid SHA1: %s", command_buf.buf);
+               e = find_object(sha1);
+               *p += 40;
+       }
+
+       while (!e || e->type != OBJ_TREE)
+               e = dereference(e, sha1);
+       return e;
+}
+
+static void print_ls(int mode, const unsigned char *sha1, const char *path)
+{
+       static struct strbuf line = STRBUF_INIT;
+
+       /* See show_tree(). */
+       const char *type =
+               S_ISGITLINK(mode) ? commit_type :
+               S_ISDIR(mode) ? tree_type :
+               blob_type;
+
+       if (!mode) {
+               /* missing SP path LF */
+               strbuf_reset(&line);
+               strbuf_addstr(&line, "missing ");
+               quote_c_style(path, &line, NULL, 0);
+               strbuf_addch(&line, '\n');
+       } else {
+               /* mode SP type SP object_name TAB path LF */
+               strbuf_reset(&line);
+               strbuf_addf(&line, "%06o %s %s\t",
+                               mode, type, sha1_to_hex(sha1));
+               quote_c_style(path, &line, NULL, 0);
+               strbuf_addch(&line, '\n');
+       }
+       cat_blob_write(line.buf, line.len);
+}
+
+static void parse_ls(struct branch *b)
+{
+       const char *p;
+       struct tree_entry *root = NULL;
+       struct tree_entry leaf = {NULL};
+
+       /* ls SP (<treeish> SP)? <path> */
+       p = command_buf.buf + strlen("ls ");
+       if (*p == '"') {
+               if (!b)
+                       die("Not in a commit: %s", command_buf.buf);
+               root = &b->branch_tree;
+       } else {
+               struct object_entry *e = parse_treeish_dataref(&p);
+               root = new_tree_entry();
+               hashcpy(root->versions[1].sha1, e->idx.sha1);
+               load_tree(root);
+               if (*p++ != ' ')
+                       die("Missing space after tree-ish: %s", command_buf.buf);
+       }
+       if (*p == '"') {
+               static struct strbuf uq = STRBUF_INIT;
+               const char *endp;
+               strbuf_reset(&uq);
+               if (unquote_c_style(&uq, p, &endp))
+                       die("Invalid path: %s", command_buf.buf);
+               if (*endp)
+                       die("Garbage after path in: %s", command_buf.buf);
+               p = uq.buf;
+       }
+       tree_content_get(root, p, &leaf);
+       /*
+        * A directory in preparation would have a sha1 of zero
+        * until it is saved.  Save, for simplicity.
+        */
+       if (S_ISDIR(leaf.versions[1].mode))
+               store_tree(&leaf);
+
+       print_ls(leaf.versions[1].mode, leaf.versions[1].sha1, p);
+       if (!b || root != &b->branch_tree)
+               release_tree_entry(root);
+}
+
 static void checkpoint(void)
 {
        checkpoint_requested = 0;
@@ -2867,7 +3013,8 @@ static char* make_fast_import_path(const char *path)
        return strbuf_detach(&abs_path, NULL);
 }
 
-static void option_import_marks(const char *marks, int from_stream)
+static void option_import_marks(const char *marks,
+                                       int from_stream, int ignore_missing)
 {
        if (import_marks_file) {
                if (from_stream)
@@ -2881,6 +3028,7 @@ static void option_import_marks(const char *marks, int from_stream)
        import_marks_file = make_fast_import_path(marks);
        safe_create_leading_directories_const(import_marks_file);
        import_marks_file_from_stream = from_stream;
+       import_marks_file_ignore_missing = ignore_missing;
 }
 
 static void option_date_format(const char *fmt)
@@ -2980,7 +3128,10 @@ static int parse_one_feature(const char *feature, int from_stream)
        if (!prefixcmp(feature, "date-format=")) {
                option_date_format(feature + 12);
        } else if (!prefixcmp(feature, "import-marks=")) {
-               option_import_marks(feature + 13, from_stream);
+               option_import_marks(feature + 13, from_stream, 0);
+       } else if (!prefixcmp(feature, "import-marks-if-exists=")) {
+               option_import_marks(feature + strlen("import-marks-if-exists="),
+                                       from_stream, 1);
        } else if (!prefixcmp(feature, "export-marks=")) {
                option_export_marks(feature + 13);
        } else if (!strcmp(feature, "cat-blob")) {
@@ -2991,6 +3142,8 @@ static int parse_one_feature(const char *feature, int from_stream)
                relative_marks_paths = 0;
        } else if (!prefixcmp(feature, "force")) {
                force_update = 1;
+       } else if (!strcmp(feature, "notes") || !strcmp(feature, "ls")) {
+               ; /* do nothing; we have the feature */
        } else {
                return 0;
        }
@@ -3130,6 +3283,8 @@ int main(int argc, const char **argv)
        while (read_next_command() != EOF) {
                if (!strcmp("blob", command_buf.buf))
                        parse_new_blob();
+               else if (!prefixcmp(command_buf.buf, "ls "))
+                       parse_ls(NULL);
                else if (!prefixcmp(command_buf.buf, "commit "))
                        parse_new_commit();
                else if (!prefixcmp(command_buf.buf, "tag "))
index fbe85ac05fd2d945d645365dc086460003fa7f27..0608edae3fe7b07b852b30281fea978806798c99 100644 (file)
@@ -1,8 +1,7 @@
 #ifndef FETCH_PACK_H
 #define FETCH_PACK_H
 
-struct fetch_pack_args
-{
+struct fetch_pack_args {
        const char *uploadpack;
        int unpacklimit;
        int depth;
diff --git a/fsck.c b/fsck.c
index 3d05d4a794a4158a421ce1265422d241e28a5278..6f266c1ea4b8df503c211170741fa5b490a6a02a 100644 (file)
--- a/fsck.c
+++ b/fsck.c
@@ -347,26 +347,14 @@ int fsck_object(struct object *obj, int strict, fsck_error error_func)
 int fsck_error_function(struct object *obj, int type, const char *fmt, ...)
 {
        va_list ap;
-       int len;
        struct strbuf sb = STRBUF_INIT;
 
        strbuf_addf(&sb, "object %s:", obj->sha1?sha1_to_hex(obj->sha1):"(null)");
 
        va_start(ap, fmt);
-       len = vsnprintf(sb.buf + sb.len, strbuf_avail(&sb), fmt, ap);
+       strbuf_vaddf(&sb, fmt, ap);
        va_end(ap);
 
-       if (len < 0)
-               len = 0;
-       if (len >= strbuf_avail(&sb)) {
-               strbuf_grow(&sb, len + 2);
-               va_start(ap, fmt);
-               len = vsnprintf(sb.buf + sb.len, strbuf_avail(&sb), fmt, ap);
-               va_end(ap);
-               if (len >= strbuf_avail(&sb))
-                       die("this should not happen, your snprintf is broken");
-       }
-
        error("%s", sb.buf);
        strbuf_release(&sb);
        return 1;
index 75c68d948fd3105272f893ff2f901007519f62f5..3ef4861d04ed5fed14d31b92e047a03cf5362970 100755 (executable)
@@ -1,8 +1,7 @@
 #!/bin/sh
 
 echo "/* Automatically generated by $0 */
-struct cmdname_help
-{
+struct cmdname_help {
     char name[16];
     char help[80];
 };
diff --git a/gettext.c b/gettext.c
new file mode 100644 (file)
index 0000000..ae5394a
--- /dev/null
+++ b/gettext.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2010 Ã†var Arnfjörð Bjarmason
+ */
+
+#include "git-compat-util.h"
+#include "gettext.h"
+
+int use_gettext_poison(void)
+{
+       static int poison_requested = -1;
+       if (poison_requested == -1)
+               poison_requested = getenv("GIT_GETTEXT_POISON") ? 1 : 0;
+       return poison_requested;
+}
diff --git a/gettext.h b/gettext.h
new file mode 100644 (file)
index 0000000..1b253b7
--- /dev/null
+++ b/gettext.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2010-2011 Ã†var Arnfjörð Bjarmason
+ *
+ * This is a skeleton no-op implementation of gettext for Git.
+ * You can replace it with something that uses libintl.h and wraps
+ * gettext() to try out the translations.
+ */
+
+#ifndef GETTEXT_H
+#define GETTEXT_H
+
+#if defined(_) || defined(Q_)
+#error "namespace conflict: '_' or 'Q_' is pre-defined?"
+#endif
+
+#define FORMAT_PRESERVING(n) __attribute__((format_arg(n)))
+
+#ifdef GETTEXT_POISON
+extern int use_gettext_poison(void);
+#else
+#define use_gettext_poison() 0
+#endif
+
+static inline FORMAT_PRESERVING(1) const char *_(const char *msgid)
+{
+       return use_gettext_poison() ? "# GETTEXT POISON #" : msgid;
+}
+
+static inline FORMAT_PRESERVING(1) FORMAT_PRESERVING(2)
+const char *Q_(const char *msgid, const char *plu, unsigned long n)
+{
+       if (use_gettext_poison())
+               return "# GETTEXT POISON #";
+       return n == 1 ? msgid : plu;
+}
+
+/* Mark msgid for translation but do not translate it. */
+#define N_(msgid) (msgid)
+
+#endif
index c21e33c8d133af0e9e0ae3edaffd0a5593ff4ac3..415a8d04ccc4f313eb111a3bbfbf2af2382beebd 100755 (executable)
@@ -288,10 +288,12 @@ bisect_visualize() {
 
        if test $# = 0
        then
-               case "${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" in
-               '')     set git log ;;
-               set*)   set gitk ;;
-               esac
+               if test -n "${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" &&
+                  type gitk >/dev/null 2>&1; then
+                       set gitk
+               else
+                       set git log
+               fi
        else
                case "$1" in
                git*|tig) ;;
index d6d269f138b06791ba6e8712b06036f00a73c7e3..49b50eec86828066c90b6165c35ec21cb51e85ce 100644 (file)
@@ -31,6 +31,9 @@
 #define maximum_signed_value_of_type(a) \
     (INTMAX_MAX >> (bitsizeof(intmax_t) - bitsizeof(a)))
 
+#define maximum_unsigned_value_of_type(a) \
+    (UINTMAX_MAX >> (bitsizeof(uintmax_t) - bitsizeof(a)))
+
 /*
  * Signed integer overflow is undefined in C, so here's a helper macro
  * to detect if the sum of two integers will overflow.
@@ -40,6 +43,9 @@
 #define signed_add_overflows(a, b) \
     ((b) > maximum_signed_value_of_type(a) - (a))
 
+#define unsigned_add_overflows(a, b) \
+    ((b) > maximum_unsigned_value_of_type(a) - (a))
+
 #ifdef __GNUC__
 #define TYPEOF(x) (__typeof__(x))
 #else
@@ -208,7 +214,10 @@ extern char *gitbasename(char *);
 #define is_dir_sep(c) ((c) == '/')
 #endif
 
-#ifdef __GNUC__
+#if __HP_cc >= 61000
+#define NORETURN __attribute__((noreturn))
+#define NORETURN_PTR
+#elif defined(__GNUC__)
 #define NORETURN __attribute__((__noreturn__))
 #define NORETURN_PTR __attribute__((__noreturn__))
 #elif defined(_MSC_VER)
@@ -529,6 +538,19 @@ void git_qsort(void *base, size_t nmemb, size_t size,
 #define fstat_is_reliable() 1
 #endif
 
+#ifndef va_copy
+/*
+ * Since an obvious implementation of va_list would be to make it a
+ * pointer into the stack frame, a simple assignment will work on
+ * many systems.  But let's try to be more portable.
+ */
+#ifdef __va_copy
+#define va_copy(dst, src) __va_copy(dst, src)
+#else
+#define va_copy(dst, src) ((dst) = (src))
+#endif
+#endif
+
 /*
  * Preserves errno, prints a message, but gives no warning for ENOENT.
  * Always returns the return value of unlink(2).
index 8e683e54783ab6e916bdb8ade56832ac81470648..bbf327f3e891cacdd14c0b18b51702ce14b2b6df 100755 (executable)
@@ -366,7 +366,9 @@ sub conn {
        $self->{'socketo'}->write("valid-requests\n");
        $self->{'socketo'}->flush();
 
-       chomp(my $rep=$self->readline());
+       my $rep=$self->readline();
+       die "Failed to read from server" unless defined $rep;
+       chomp($rep);
        if ($rep !~ s/^Valid-requests\s*//) {
                $rep="<unknown>" unless $rep;
                die "Expected Valid-requests from server, but got: $rep\n";
index 10fcebb119ce2af81527aa3c24a9b7c3ab3b3e7f..8bfa8a055ccd0c344d595f112b571bb3d6e21c28 100755 (executable)
@@ -558,12 +558,14 @@ my \$app = builder {
 
 # make it runnable as standalone app,
 # like it would be run via 'plackup' utility
-if (__FILE__ eq \$0) {
+if (caller) {
+       return \$app;
+} else {
        require Plack::Runner;
 
        my \$runner = Plack::Runner->new();
        \$runner->parse_options(qw(--env deployment --port $port),
-                              "$local" ? qw(--host 127.0.0.1) : ());
+                               "$local" ? qw(--host 127.0.0.1) : ());
        \$runner->run(\$app);
 }
 __END__
index 77d4aee20ee5b8b01f9a0e3d1f8dbc9f7fdf3eb9..fb3f52ba2507b4fb78db150b5c183f24bd2c57c1 100644 (file)
@@ -10,17 +10,20 @@ merge_mode() {
 
 translate_merge_tool_path () {
        case "$1" in
-       vimdiff|vimdiff2)
-               echo vim
+       araxis)
+               echo compare
                ;;
-       gvimdiff|gvimdiff2)
-               echo gvim
+       bc3)
+               echo bcompare
                ;;
        emerge)
                echo emacs
                ;;
-       araxis)
-               echo compare
+       gvimdiff|gvimdiff2)
+               echo gvim
+               ;;
+       vimdiff|vimdiff2)
+               echo vim
                ;;
        *)
                echo "$1"
@@ -46,17 +49,16 @@ check_unchanged () {
 
 valid_tool () {
        case "$1" in
-       kdiff3 | tkdiff | xxdiff | meld | opendiff | \
-       vimdiff | gvimdiff | vimdiff2 | gvimdiff2 | \
-       emerge | ecmerge | diffuse | araxis | p4merge)
+       araxis | bc3 | diffuse | ecmerge | emerge | gvimdiff | gvimdiff2 | \
+       kdiff3 | meld | opendiff | p4merge | tkdiff | vimdiff | vimdiff2 | xxdiff)
                ;; # happy
-       tortoisemerge)
-               if ! merge_mode; then
+       kompare)
+               if ! diff_mode; then
                        return 1
                fi
                ;;
-       kompare)
-               if ! diff_mode; then
+       tortoisemerge)
+               if ! merge_mode; then
                        return 1
                fi
                ;;
@@ -89,88 +91,91 @@ run_merge_tool () {
        status=0
 
        case "$1" in
-       kdiff3)
+       araxis)
                if merge_mode; then
+                       touch "$BACKUP"
                        if $base_present; then
-                               ("$merge_tool_path" --auto \
-                                       --L1 "$MERGED (Base)" \
-                                       --L2 "$MERGED (Local)" \
-                                       --L3 "$MERGED (Remote)" \
-                                       -o "$MERGED" \
-                                       "$BASE" "$LOCAL" "$REMOTE" \
-                               > /dev/null 2>&1)
+                               "$merge_tool_path" -wait -merge -3 -a1 \
+                                       "$BASE" "$LOCAL" "$REMOTE" "$MERGED" \
+                                       >/dev/null 2>&1
                        else
-                               ("$merge_tool_path" --auto \
-                                       --L1 "$MERGED (Local)" \
-                                       --L2 "$MERGED (Remote)" \
-                                       -o "$MERGED" \
-                                       "$LOCAL" "$REMOTE" \
-                               > /dev/null 2>&1)
+                               "$merge_tool_path" -wait -2 \
+                                       "$LOCAL" "$REMOTE" "$MERGED" \
+                                       >/dev/null 2>&1
                        fi
-                       status=$?
+                       check_unchanged
                else
-                       ("$merge_tool_path" --auto \
-                               --L1 "$MERGED (A)" \
-                               --L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \
-                       > /dev/null 2>&1)
+                       "$merge_tool_path" -wait -2 "$LOCAL" "$REMOTE" \
+                               >/dev/null 2>&1
                fi
                ;;
-       kompare)
-               "$merge_tool_path" "$LOCAL" "$REMOTE"
-               ;;
-       tkdiff)
+       bc3)
                if merge_mode; then
+                       touch "$BACKUP"
                        if $base_present; then
-                               "$merge_tool_path" -a "$BASE" \
-                                       -o "$MERGED" "$LOCAL" "$REMOTE"
+                               "$merge_tool_path" "$LOCAL" "$REMOTE" "$BASE" \
+                                       -mergeoutput="$MERGED"
                        else
-                               "$merge_tool_path" \
-                                       -o "$MERGED" "$LOCAL" "$REMOTE"
+                               "$merge_tool_path" "$LOCAL" "$REMOTE" \
+                                       -mergeoutput="$MERGED"
                        fi
-                       status=$?
+                       check_unchanged
                else
                        "$merge_tool_path" "$LOCAL" "$REMOTE"
                fi
                ;;
-       p4merge)
+       diffuse)
                if merge_mode; then
-                   touch "$BACKUP"
+                       touch "$BACKUP"
                        if $base_present; then
-                               "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
+                               "$merge_tool_path" \
+                                       "$LOCAL" "$MERGED" "$REMOTE" \
+                                       "$BASE" | cat
                        else
-                               "$merge_tool_path" "$LOCAL" "$LOCAL" "$REMOTE" "$MERGED"
+                               "$merge_tool_path" \
+                                       "$LOCAL" "$MERGED" "$REMOTE" | cat
                        fi
                        check_unchanged
                else
-                       "$merge_tool_path" "$LOCAL" "$REMOTE"
+                       "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
                fi
                ;;
-       meld)
+       ecmerge)
                if merge_mode; then
                        touch "$BACKUP"
-                       "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"
+                       if $base_present; then
+                               "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" \
+                                       --default --mode=merge3 --to="$MERGED"
+                       else
+                               "$merge_tool_path" "$LOCAL" "$REMOTE" \
+                                       --default --mode=merge2 --to="$MERGED"
+                       fi
                        check_unchanged
                else
-                       "$merge_tool_path" "$LOCAL" "$REMOTE"
+                       "$merge_tool_path" --default --mode=diff2 \
+                               "$LOCAL" "$REMOTE"
                fi
                ;;
-       diffuse)
+       emerge)
                if merge_mode; then
-                       touch "$BACKUP"
                        if $base_present; then
                                "$merge_tool_path" \
-                                       "$LOCAL" "$MERGED" "$REMOTE" \
-                                       "$BASE" | cat
+                                       -f emerge-files-with-ancestor-command \
+                                       "$LOCAL" "$REMOTE" "$BASE" \
+                                       "$(basename "$MERGED")"
                        else
                                "$merge_tool_path" \
-                                       "$LOCAL" "$MERGED" "$REMOTE" | cat
+                                       -f emerge-files-command \
+                                       "$LOCAL" "$REMOTE" \
+                                       "$(basename "$MERGED")"
                        fi
-                       check_unchanged
+                       status=$?
                else
-                       "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
+                       "$merge_tool_path" -f emerge-files-command \
+                               "$LOCAL" "$REMOTE"
                fi
                ;;
-       vimdiff|gvimdiff)
+       gvimdiff|vimdiff)
                if merge_mode; then
                        touch "$BACKUP"
                        if $base_present; then
@@ -182,45 +187,57 @@ run_merge_tool () {
                        fi
                        check_unchanged
                else
-                       "$merge_tool_path" -f -d -c "wincmd l" \
+                       "$merge_tool_path" -R -f -d -c "wincmd l" \
                                "$LOCAL" "$REMOTE"
                fi
                ;;
-       vimdiff2|gvimdiff2)
+       gvimdiff2|vimdiff2)
                if merge_mode; then
                        touch "$BACKUP"
                        "$merge_tool_path" -f -d -c "wincmd l" \
                                "$LOCAL" "$MERGED" "$REMOTE"
                        check_unchanged
                else
-                       "$merge_tool_path" -f -d -c "wincmd l" \
+                       "$merge_tool_path" -R -f -d -c "wincmd l" \
                                "$LOCAL" "$REMOTE"
                fi
                ;;
-       xxdiff)
+       kdiff3)
                if merge_mode; then
-                       touch "$BACKUP"
                        if $base_present; then
-                               "$merge_tool_path" -X --show-merged-pane \
-                                       -R 'Accel.SaveAsMerged: "Ctrl-S"' \
-                                       -R 'Accel.Search: "Ctrl+F"' \
-                                       -R 'Accel.SearchForward: "Ctrl-G"' \
-                                       --merged-file "$MERGED" \
-                                       "$LOCAL" "$BASE" "$REMOTE"
+                               ("$merge_tool_path" --auto \
+                                       --L1 "$MERGED (Base)" \
+                                       --L2 "$MERGED (Local)" \
+                                       --L3 "$MERGED (Remote)" \
+                                       -o "$MERGED" \
+                                       "$BASE" "$LOCAL" "$REMOTE" \
+                               > /dev/null 2>&1)
                        else
-                               "$merge_tool_path" -X $extra \
-                                       -R 'Accel.SaveAsMerged: "Ctrl-S"' \
-                                       -R 'Accel.Search: "Ctrl+F"' \
-                                       -R 'Accel.SearchForward: "Ctrl-G"' \
-                                       --merged-file "$MERGED" \
-                                       "$LOCAL" "$REMOTE"
+                               ("$merge_tool_path" --auto \
+                                       --L1 "$MERGED (Local)" \
+                                       --L2 "$MERGED (Remote)" \
+                                       -o "$MERGED" \
+                                       "$LOCAL" "$REMOTE" \
+                               > /dev/null 2>&1)
                        fi
+                       status=$?
+               else
+                       ("$merge_tool_path" --auto \
+                               --L1 "$MERGED (A)" \
+                               --L2 "$MERGED (B)" "$LOCAL" "$REMOTE" \
+                       > /dev/null 2>&1)
+               fi
+               ;;
+       kompare)
+               "$merge_tool_path" "$LOCAL" "$REMOTE"
+               ;;
+       meld)
+               if merge_mode; then
+                       touch "$BACKUP"
+                       "$merge_tool_path" "$LOCAL" "$MERGED" "$REMOTE"
                        check_unchanged
                else
-                       "$merge_tool_path" \
-                               -R 'Accel.Search: "Ctrl+F"' \
-                               -R 'Accel.SearchForward: "Ctrl-G"' \
-                               "$LOCAL" "$REMOTE"
+                       "$merge_tool_path" "$LOCAL" "$REMOTE"
                fi
                ;;
        opendiff)
@@ -239,39 +256,31 @@ run_merge_tool () {
                        "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
                fi
                ;;
-       ecmerge)
+       p4merge)
                if merge_mode; then
-                       touch "$BACKUP"
+                   touch "$BACKUP"
                        if $base_present; then
-                               "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" \
-                                       --default --mode=merge3 --to="$MERGED"
+                               "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
                        else
-                               "$merge_tool_path" "$LOCAL" "$REMOTE" \
-                                       --default --mode=merge2 --to="$MERGED"
+                               "$merge_tool_path" "$LOCAL" "$LOCAL" "$REMOTE" "$MERGED"
                        fi
                        check_unchanged
                else
-                       "$merge_tool_path" --default --mode=diff2 \
-                               "$LOCAL" "$REMOTE"
+                       "$merge_tool_path" "$LOCAL" "$REMOTE"
                fi
                ;;
-       emerge)
+       tkdiff)
                if merge_mode; then
                        if $base_present; then
-                               "$merge_tool_path" \
-                                       -f emerge-files-with-ancestor-command \
-                                       "$LOCAL" "$REMOTE" "$BASE" \
-                                       "$(basename "$MERGED")"
+                               "$merge_tool_path" -a "$BASE" \
+                                       -o "$MERGED" "$LOCAL" "$REMOTE"
                        else
                                "$merge_tool_path" \
-                                       -f emerge-files-command \
-                                       "$LOCAL" "$REMOTE" \
-                                       "$(basename "$MERGED")"
+                                       -o "$MERGED" "$LOCAL" "$REMOTE"
                        fi
                        status=$?
                else
-                       "$merge_tool_path" -f emerge-files-command \
-                               "$LOCAL" "$REMOTE"
+                       "$merge_tool_path" "$LOCAL" "$REMOTE"
                fi
                ;;
        tortoisemerge)
@@ -286,22 +295,30 @@ run_merge_tool () {
                        status=1
                fi
                ;;
-       araxis)
+       xxdiff)
                if merge_mode; then
                        touch "$BACKUP"
                        if $base_present; then
-                               "$merge_tool_path" -wait -merge -3 -a1 \
-                                       "$BASE" "$LOCAL" "$REMOTE" "$MERGED" \
-                                       >/dev/null 2>&1
+                               "$merge_tool_path" -X --show-merged-pane \
+                                       -R 'Accel.SaveAsMerged: "Ctrl-S"' \
+                                       -R 'Accel.Search: "Ctrl+F"' \
+                                       -R 'Accel.SearchForward: "Ctrl-G"' \
+                                       --merged-file "$MERGED" \
+                                       "$LOCAL" "$BASE" "$REMOTE"
                        else
-                               "$merge_tool_path" -wait -2 \
-                                       "$LOCAL" "$REMOTE" "$MERGED" \
-                                       >/dev/null 2>&1
+                               "$merge_tool_path" -X $extra \
+                                       -R 'Accel.SaveAsMerged: "Ctrl-S"' \
+                                       -R 'Accel.Search: "Ctrl+F"' \
+                                       -R 'Accel.SearchForward: "Ctrl-G"' \
+                                       --merged-file "$MERGED" \
+                                       "$LOCAL" "$REMOTE"
                        fi
                        check_unchanged
                else
-                       "$merge_tool_path" -wait -2 "$LOCAL" "$REMOTE" \
-                               >/dev/null 2>&1
+                       "$merge_tool_path" \
+                               -R 'Accel.Search: "Ctrl+F"' \
+                               -R 'Accel.SearchForward: "Ctrl-G"' \
+                               "$LOCAL" "$REMOTE"
                fi
                ;;
        *)
@@ -343,7 +360,7 @@ guess_merge_tool () {
                else
                        tools="opendiff kdiff3 tkdiff xxdiff meld $tools"
                fi
-               tools="$tools gvimdiff diffuse ecmerge p4merge araxis"
+               tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3"
        fi
        case "${VISUAL:-$EDITOR}" in
        *vim*)
index 2f8dc441c6d575323f2fad920ecdb7b20e1445e6..bacbda2bb75854235b912903c7e45fc94d38e719 100755 (executable)
@@ -269,7 +269,7 @@ rerere=false
 files_to_merge() {
     if test "$rerere" = true
     then
-       git rerere status
+       git rerere remaining
     else
        git ls-files -u | sed -e 's/^[^ ]*      //' | sort -u
     fi
index 1cc2ba6e09614fa55ad205145a3bdacfb78bf283..e7013f7ba72a64ab24b991846755b6d6c068b37a 100644 (file)
@@ -4,56 +4,6 @@
 # this would fail in that case and would issue an error message.
 GIT_DIR=$(git rev-parse -q --git-dir) || :;
 
-get_data_source () {
-       case "$1" in
-       */*)
-               echo ''
-               ;;
-       .)
-               echo self
-               ;;
-       *)
-               if test "$(git config --get "remote.$1.url")"
-               then
-                       echo config
-               elif test -f "$GIT_DIR/remotes/$1"
-               then
-                       echo remotes
-               elif test -f "$GIT_DIR/branches/$1"
-               then
-                       echo branches
-               else
-                       echo ''
-               fi ;;
-       esac
-}
-
-get_remote_url () {
-       data_source=$(get_data_source "$1")
-       case "$data_source" in
-       '')
-               echo "$1"
-               ;;
-       self)
-               echo "$1"
-               ;;
-       config)
-               git config --get "remote.$1.url"
-               ;;
-       remotes)
-               sed -ne '/^URL: */{
-                       s///p
-                       q
-               }' "$GIT_DIR/remotes/$1"
-               ;;
-       branches)
-               sed -e 's/#.*//' "$GIT_DIR/branches/$1"
-               ;;
-       *)
-               die "internal error: get-remote-url $1" ;;
-       esac
-}
-
 get_default_remote () {
        curr_branch=$(git symbolic-ref -q HEAD | sed -e 's|^refs/heads/||')
        origin=$(git config --get "branch.$curr_branch.remote")
index eb87f49062b70d707adebca4013809822123608b..63b063a7b284bac5b10a9bd6fe879e5717bee2f3 100755 (executable)
@@ -53,6 +53,8 @@ do
                verbosity="$verbosity -v" ;;
        --progress)
                progress=--progress ;;
+       --no-progress)
+               progress=--no-progress ;;
        -n|--no-stat|--no-summary)
                diffstat=--no-stat ;;
        --stat|--summary)
@@ -114,7 +116,7 @@ do
        --d|--dr|--dry|--dry-|--dry-r|--dry-ru|--dry-run)
                dry_run=--dry-run
                ;;
-       -h|--h|--he|--hel|--help)
+       -h|--h|--he|--hel|--help|--help-|--help-a|--help-al|--help-all)
                usage
                ;;
        *)
@@ -293,8 +295,8 @@ true)
        ;;
 *)
        eval="git-merge $diffstat $no_commit $squash $no_ff $ff_only"
-       eval="$eval  $log_arg $strategy_args $merge_args"
-       eval="$eval \"\$merge_name\" HEAD $merge_head $verbosity"
+       eval="$eval  $log_arg $strategy_args $merge_args $verbosity $progress"
+       eval="$eval \"\$merge_name\" HEAD $merge_head"
        ;;
 esac
 eval "exec $eval"
index 6fdea397ddec3cfa4ff37cdf672e7cced840bb60..fc080cc5e45d02e618e7224c052de1be676f4360 100755 (executable)
@@ -15,7 +15,6 @@ p    show patch text as well
 '
 
 . git-sh-setup
-. git-parse-remote
 
 GIT_PAGER=
 export GIT_PAGER
@@ -55,7 +54,7 @@ branch=$(git ls-remote "$url" \
                p
                q
        }")
-url=$(get_remote_url "$url")
+url=$(git ls-remote --get-url "$url")
 if [ -z "$branch" ]; then
        echo "warn: No branch of $url is at:" >&2
        git log --max-count=1 --pretty='tformat:warn:   %h: %s' $headrev >&2
index 7561b374d2ec90fe774e98e39a121a1a3a3cdfa9..a305fb19f11bc4ae80e585b102ecb5d982d1a0f5 100755 (executable)
@@ -12,12 +12,14 @@ USAGE="list [<options>]
 
 SUBDIRECTORY_OK=Yes
 OPTIONS_SPEC=
+START_DIR=`pwd`
 . git-sh-setup
 require_work_tree
 cd_to_toplevel
 
 TMP="$GIT_DIR/.git-stash.$$"
-trap 'rm -f "$TMP-*"' 0
+TMPindex=${GIT_INDEX_FILE-"$GIT_DIR/index"}.stash.$$
+trap 'rm -f "$TMP-"* "$TMPindex"' 0
 
 ref_stash=refs/stash
 
@@ -81,14 +83,12 @@ create_stash () {
 
                # state of the working tree
                w_tree=$( (
-                       rm -f "$TMP-index" &&
-                       cp -p ${GIT_INDEX_FILE-"$GIT_DIR/index"} "$TMP-index" &&
-                       GIT_INDEX_FILE="$TMP-index" &&
+                       git read-tree --index-output="$TMPindex" -m $i_tree &&
+                       GIT_INDEX_FILE="$TMPindex" &&
                        export GIT_INDEX_FILE &&
-                       git read-tree -m $i_tree &&
                        git diff --name-only -z HEAD | git update-index -z --add --remove --stdin &&
                        git write-tree &&
-                       rm -f "$TMP-index"
+                       rm -f "$TMPindex"
                ) ) ||
                        die "Cannot save the current worktree state"
 
@@ -394,7 +394,7 @@ apply_stash () {
                then
                        squelch='>/dev/null 2>&1'
                fi
-               eval "git status $squelch" || :
+               (cd "$START_DIR" && eval "git status $squelch") || :
        else
                # Merge conflict; keep the exit status from merge-recursive
                status=$?
index 8b9058971767dbb4d94e996876f6ba7ed178ddd6..3a13397e057edf88d2c810490ec3d7d755be2009 100755 (executable)
@@ -423,6 +423,7 @@ cmd_update()
                cmd_init "--" "$@" || return
        fi
 
+       cloned_modules=
        module_list "$@" |
        while read mode sha1 stage path
        do
@@ -442,6 +443,7 @@ cmd_update()
                if ! test -d "$path"/.git -o -f "$path"/.git
                then
                        module_clone "$path" "$url" "$reference"|| exit
+                       cloned_modules="$cloned_modules;$name"
                        subsha1=
                else
                        subsha1=$(clear_local_git_env; cd "$path" &&
@@ -469,6 +471,13 @@ cmd_update()
                                die "Unable to fetch in submodule path '$path'"
                        fi
 
+                       # Is this something we just cloned?
+                       case ";$cloned_modules;" in
+                       *";$name;"*)
+                               # then there is no local change to integrate
+                               update_module= ;;
+                       esac
+
                        case "$update_module" in
                        rebase)
                                command="git rebase"
index 177dd259cd53cde017d73db5ccbecc7ed7dfa573..a5857c1ad45b0462f168a4b3b9249ed8c3cf6e89 100755 (executable)
@@ -5734,7 +5734,7 @@ sub cmd_show_log {
        my (@k, $c, $d, $stat);
        my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/;
        while (<$log>) {
-               if (/^${esc_color}commit -?($::sha1_short)/o) {
+               if (/^${esc_color}commit (- )?($::sha1_short)/o) {
                        my $cmt = $1;
                        if ($c && cmt_showable($c) && $c->{r} != $r_last) {
                                $r_last = $c->{r};
diff --git a/git.c b/git.c
index 68334f6a3134bb76a8ffc59e4da773400c59a388..ef598c3e7053b8dd2859f4d582ce2917a804fe42 100644 (file)
--- a/git.c
+++ b/git.c
@@ -177,24 +177,24 @@ static int handle_alias(int *argcp, const char ***argv)
        alias_string = alias_lookup(alias_command);
        if (alias_string) {
                if (alias_string[0] == '!') {
+                       const char **alias_argv;
+                       int argc = *argcp, i;
+
                        commit_pager_choice();
-                       if (*argcp > 1) {
-                               struct strbuf buf;
-
-                               strbuf_init(&buf, PATH_MAX);
-                               strbuf_addstr(&buf, alias_string);
-                               sq_quote_argv(&buf, (*argv) + 1, PATH_MAX);
-                               free(alias_string);
-                               alias_string = buf.buf;
-                       }
-                       trace_printf("trace: alias to shell cmd: %s => %s\n",
-                                    alias_command, alias_string + 1);
-                       ret = system(alias_string + 1);
-                       if (ret >= 0 && WIFEXITED(ret) &&
-                           WEXITSTATUS(ret) != 127)
-                               exit(WEXITSTATUS(ret));
-                       die("Failed to run '%s' when expanding alias '%s'",
-                           alias_string + 1, alias_command);
+
+                       /* build alias_argv */
+                       alias_argv = xmalloc(sizeof(*alias_argv) * (argc + 1));
+                       alias_argv[0] = alias_string + 1;
+                       for (i = 1; i < argc; ++i)
+                               alias_argv[i] = (*argv)[i];
+                       alias_argv[argc] = NULL;
+
+                       ret = run_command_v_opt(alias_argv, RUN_USING_SHELL);
+                       if (ret >= 0)   /* normal exit */
+                               exit(ret);
+
+                       die_errno("While expanding alias '%s': '%s'",
+                           alias_command, alias_string + 1);
                }
                count = split_cmdline(alias_string, &new_argv);
                if (count < 0)
@@ -313,7 +313,6 @@ static void handle_internal_command(int argc, const char **argv)
        const char *cmd = argv[0];
        static struct cmd_struct commands[] = {
                { "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
-               { "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
                { "annotate", cmd_annotate, RUN_SETUP },
                { "apply", cmd_apply, RUN_SETUP_GENTLY },
                { "archive", cmd_archive },
@@ -322,15 +321,15 @@ static void handle_internal_command(int argc, const char **argv)
                { "branch", cmd_branch, RUN_SETUP },
                { "bundle", cmd_bundle, RUN_SETUP_GENTLY },
                { "cat-file", cmd_cat_file, RUN_SETUP },
+               { "check-attr", cmd_check_attr, RUN_SETUP },
+               { "check-ref-format", cmd_check_ref_format },
                { "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
                { "checkout-index", cmd_checkout_index,
                        RUN_SETUP | NEED_WORK_TREE},
-               { "check-ref-format", cmd_check_ref_format },
-               { "check-attr", cmd_check_attr, RUN_SETUP },
                { "cherry", cmd_cherry, RUN_SETUP },
                { "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
-               { "clone", cmd_clone },
                { "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE },
+               { "clone", cmd_clone },
                { "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
                { "commit-tree", cmd_commit_tree, RUN_SETUP },
                { "config", cmd_config, RUN_SETUP_GENTLY },
@@ -358,8 +357,8 @@ static void handle_internal_command(int argc, const char **argv)
                { "init-db", cmd_init_db },
                { "log", cmd_log, RUN_SETUP },
                { "ls-files", cmd_ls_files, RUN_SETUP },
-               { "ls-tree", cmd_ls_tree, RUN_SETUP },
                { "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
+               { "ls-tree", cmd_ls_tree, RUN_SETUP },
                { "mailinfo", cmd_mailinfo },
                { "mailsplit", cmd_mailsplit },
                { "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE },
@@ -379,6 +378,7 @@ static void handle_internal_command(int argc, const char **argv)
                { "notes", cmd_notes, RUN_SETUP },
                { "pack-objects", cmd_pack_objects, RUN_SETUP },
                { "pack-redundant", cmd_pack_redundant, RUN_SETUP },
+               { "pack-refs", cmd_pack_refs, RUN_SETUP },
                { "patch-id", cmd_patch_id },
                { "peek-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
                { "pickaxe", cmd_blame, RUN_SETUP },
@@ -392,7 +392,7 @@ static void handle_internal_command(int argc, const char **argv)
                { "remote-ext", cmd_remote_ext },
                { "remote-fd", cmd_remote_fd },
                { "replace", cmd_replace, RUN_SETUP },
-               { "repo-config", cmd_config, RUN_SETUP_GENTLY },
+               { "repo-config", cmd_repo_config, RUN_SETUP_GENTLY },
                { "rerere", cmd_rerere, RUN_SETUP },
                { "reset", cmd_reset, RUN_SETUP },
                { "rev-list", cmd_rev_list, RUN_SETUP },
@@ -401,8 +401,10 @@ static void handle_internal_command(int argc, const char **argv)
                { "rm", cmd_rm, RUN_SETUP },
                { "send-pack", cmd_send_pack, RUN_SETUP },
                { "shortlog", cmd_shortlog, RUN_SETUP_GENTLY | USE_PAGER },
-               { "show-branch", cmd_show_branch, RUN_SETUP },
                { "show", cmd_show, RUN_SETUP },
+               { "show-branch", cmd_show_branch, RUN_SETUP },
+               { "show-ref", cmd_show_ref, RUN_SETUP },
+               { "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
                { "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
                { "stripspace", cmd_stripspace },
                { "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
@@ -415,13 +417,11 @@ static void handle_internal_command(int argc, const char **argv)
                { "update-server-info", cmd_update_server_info, RUN_SETUP },
                { "upload-archive", cmd_upload_archive },
                { "var", cmd_var, RUN_SETUP_GENTLY },
+               { "verify-pack", cmd_verify_pack },
                { "verify-tag", cmd_verify_tag, RUN_SETUP },
                { "version", cmd_version },
                { "whatchanged", cmd_whatchanged, RUN_SETUP },
                { "write-tree", cmd_write_tree, RUN_SETUP },
-               { "verify-pack", cmd_verify_pack },
-               { "show-ref", cmd_show_ref, RUN_SETUP },
-               { "pack-refs", cmd_pack_refs, RUN_SETUP },
        };
        int i;
        static const char ext[] = STRIP_EXTENSION;
index 823053173c92e4097dad54945db16f42b4b5d994..4964a679b3013caa9bfa2f438dc110eaa0274b69 100644 (file)
@@ -237,6 +237,12 @@ Requirements
  - Perl modules: CGI, Encode, Fcntl, File::Find, File::Basename.
  - web server
 
+The following optional Perl modules are required for extra features
+ - Digest::MD5 - for gravatar support
+ - CGI::Fast and FCGI - for running gitweb as FastCGI script
+ - HTML::TagCloud - for fancy tag cloud in project list view
+ - HTTP::Date or Time::ParseDate - to support If-Modified-Since for feeds
+
 
 Example web server configuration
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
index 0779f12d6178c23a47f4b9a08152176d0e19a2a8..9dccfb01d6634febbb51fbadf10bed07bd97c804 100755 (executable)
@@ -3468,7 +3468,7 @@ sub run_highlighter {
        close $fd;
        open $fd, quote_command(git_cmd(), "cat-file", "blob", $hash)." | ".
                  quote_command($highlight_bin).
-                 " --fragment --syntax $syntax |"
+                 " --replace-tabs=8 --fragment --syntax $syntax |"
                or die_error(500, "Couldn't open file or run syntax highlighter");
        return $fd;
 }
@@ -3501,7 +3501,7 @@ sub print_feed_meta {
                        $href_params{'-title'} = 'log';
                }
 
-               foreach my $format qw(RSS Atom) {
+               foreach my $format (qw(RSS Atom)) {
                        my $type = lc($format);
                        my %link_attr = (
                                '-rel' => 'alternate',
@@ -3682,7 +3682,7 @@ sub git_footer_html {
                }
                $href_params{'-title'} ||= 'log';
 
-               foreach my $format qw(RSS Atom) {
+               foreach my $format (qw(RSS Atom)) {
                        $href_params{'action'} = lc($format);
                        print $cgi->a({-href => href(%href_params),
                                      -title => "$href_params{'-title'} $format feed",
@@ -4412,7 +4412,7 @@ sub git_difftree_body {
                }
                if ($diff->{'from_mode'} ne ('0' x 6)) {
                        $from_mode_oct = oct $diff->{'from_mode'};
-                       if (S_ISREG($to_mode_oct)) { # only for regular file
+                       if (S_ISREG($from_mode_oct)) { # only for regular file
                                $from_mode_str = sprintf("%04o", $from_mode_oct & 0777); # permission bits
                        }
                        $from_file_type = file_type($diff->{'from_mode'});
@@ -4906,7 +4906,6 @@ sub git_log_body {
                next if !%co;
                my $commit = $co{'id'};
                my $ref = format_ref_marker($refs, $commit);
-               my %ad = parse_date($co{'author_epoch'});
                git_print_header_div('commit',
                               "<span class=\"age\">$co{'age_string'}</span>" .
                               esc_html($co{'title'}) . $ref,
@@ -7064,7 +7063,7 @@ sub git_feed {
        if (defined($commitlist[0])) {
                %latest_commit = %{$commitlist[0]};
                my $latest_epoch = $latest_commit{'committer_epoch'};
-               %latest_date   = parse_date($latest_epoch);
+               %latest_date   = parse_date($latest_epoch, $latest_commit{'comitter_tz'});
                my $if_modified = $cgi->http('IF_MODIFIED_SINCE');
                if (defined $if_modified) {
                        my $since;
@@ -7195,7 +7194,7 @@ XML
                if (($i >= 20) && ((time - $co{'author_epoch'}) > 48*60*60)) {
                        last;
                }
-               my %cd = parse_date($co{'author_epoch'});
+               my %cd = parse_date($co{'author_epoch'}, $co{'author_tz'});
 
                # get list of changed files
                open my $fd, "-|", git_cmd(), "diff-tree", '-r', @diff_opts,
diff --git a/graph.c b/graph.c
index f1a63c2241a30cce0141b87b5e8005b1a899a8ef..ef2e24e85a41dc97cf00bb7b19985ec01b8662bf 100644 (file)
--- a/graph.c
+++ b/graph.c
@@ -798,22 +798,9 @@ static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb)
        }
 
        /*
-        * If revs->left_right is set, print '<' for commits that
-        * come from the left side, and '>' for commits from the right
-        * side.
+        * get_revision_mark() handles all other cases without assert()
         */
-       if (graph->revs && graph->revs->left_right) {
-               if (graph->commit->object.flags & SYMMETRIC_LEFT)
-                       strbuf_addch(sb, '<');
-               else
-                       strbuf_addch(sb, '>');
-               return;
-       }
-
-       /*
-        * Print '*' in all other cases
-        */
-       strbuf_addch(sb, '*');
+       strbuf_addstr(sb, get_revision_mark(graph->revs, graph->commit));
 }
 
 /*
diff --git a/hash.c b/hash.c
index 1cd4c9d5c0945994b84bb25edd6e4685cf76b5c5..749ecfe4841a6a2af6ba4fdc6c540fd3016178f1 100644 (file)
--- a/hash.c
+++ b/hash.c
@@ -81,7 +81,7 @@ void **insert_hash(unsigned int hash, void *ptr, struct hash_table *table)
        return insert_hash_entry(hash, ptr, table);
 }
 
-int for_each_hash(const struct hash_table *table, int (*fn)(void *))
+int for_each_hash(const struct hash_table *table, int (*fn)(void *, void *), void *data)
 {
        int sum = 0;
        unsigned int i;
@@ -92,7 +92,7 @@ int for_each_hash(const struct hash_table *table, int (*fn)(void *))
                void *ptr = array->ptr;
                array++;
                if (ptr) {
-                       int val = fn(ptr);
+                       int val = fn(ptr, data);
                        if (val < 0)
                                return val;
                        sum += val;
diff --git a/hash.h b/hash.h
index 69e33a47b9861df9ac12c354eae180b4f8fea857..b875ce67c49eb39a8ca8ad6a688a334985db0534 100644 (file)
--- a/hash.h
+++ b/hash.h
@@ -30,7 +30,7 @@ struct hash_table {
 
 extern void *lookup_hash(unsigned int hash, const struct hash_table *table);
 extern void **insert_hash(unsigned int hash, void *ptr, struct hash_table *table);
-extern int for_each_hash(const struct hash_table *table, int (*fn)(void *));
+extern int for_each_hash(const struct hash_table *table, int (*fn)(void *, void *), void *data);
 extern void free_hash(struct hash_table *table);
 
 static inline void init_hash(struct hash_table *table)
index ff41a0e183dd3a449f5136c6d1488a31b4a8960b..d18346c0f5c9ce73f3fe9a1efc7b1b63e7380bb8 100644 (file)
@@ -82,8 +82,7 @@ static int helper_status;
 
 static struct object_list *objects;
 
-struct repo
-{
+struct repo {
        char *url;
        char *path;
        int path_len;
@@ -108,8 +107,7 @@ enum transfer_state {
        COMPLETE
 };
 
-struct transfer_request
-{
+struct transfer_request {
        struct object *obj;
        char *url;
        char *dest;
@@ -127,8 +125,7 @@ struct transfer_request
 
 static struct transfer_request *request_queue_head;
 
-struct xml_ctx
-{
+struct xml_ctx {
        char *name;
        int len;
        char *cdata;
@@ -136,8 +133,7 @@ struct xml_ctx
        void *userData;
 };
 
-struct remote_lock
-{
+struct remote_lock {
        char *url;
        char *owner;
        char *token;
@@ -156,8 +152,7 @@ struct remote_lock
 /* Flags that remote_ls passes to callback functions */
 #define IS_DIR (1u << 0)
 
-struct remote_ls_ctx
-{
+struct remote_ls_ctx {
        char *path;
        void (*userFunc)(struct remote_ls_ctx *ls);
        void *userData;
index 18bd6504beb99ab68f360c4fa93011efae42fdfb..9bc8114c3bb2f6f87f7f61962a64c4e5b012dcf8 100644 (file)
@@ -3,8 +3,7 @@
 #include "walker.h"
 #include "http.h"
 
-struct alt_base
-{
+struct alt_base {
        char *base;
        int got_indices;
        struct packed_git *packs;
@@ -18,8 +17,7 @@ enum object_request_state {
        COMPLETE
 };
 
-struct object_request
-{
+struct object_request {
        struct walker *walker;
        unsigned char sha1[20];
        struct alt_base *repo;
diff --git a/http.h b/http.h
index 5c6e243dde3c654a3c0a705146fb15395c27fb95..e9ed3c2e8272e43208e75459ec29fd8b6548ae4d 100644 (file)
--- a/http.h
+++ b/http.h
 #define NO_CURL_IOCTL
 #endif
 
-struct slot_results
-{
+struct slot_results {
        CURLcode curl_result;
        long http_code;
 };
 
-struct active_request_slot
-{
+struct active_request_slot {
        CURL *curl;
        FILE *local;
        int in_use;
@@ -62,8 +60,7 @@ struct active_request_slot
        struct active_request_slot *next;
 };
 
-struct buffer
-{
+struct buffer {
        struct strbuf buf;
        size_t posn;
 };
@@ -149,8 +146,7 @@ extern int http_fetch_ref(const char *base, struct ref *ref);
 extern int http_get_info_packs(const char *base_url,
        struct packed_git **packs_head);
 
-struct http_pack_request
-{
+struct http_pack_request {
        char *url;
        struct packed_git *target;
        struct packed_git **lst;
@@ -166,8 +162,7 @@ extern int finish_http_pack_request(struct http_pack_request *preq);
 extern void release_http_pack_request(struct http_pack_request *preq);
 
 /* Helpers for fetching object */
-struct http_object_request
-{
+struct http_object_request {
        char *url;
        char tmpfile[PATH_MAX];
        int localfile;
index 71506a8dd3ed07fe44c487a644ce9a42b94a7578..9adf4b981953080676aa24907fead1038b920e60 100644 (file)
@@ -1069,7 +1069,7 @@ static struct store *imap_open_store(struct imap_server_conf *srvc)
 
        if (srvc->tunnel) {
                const char *argv[] = { srvc->tunnel, NULL };
-               struct child_process tunnel = {0};
+               struct child_process tunnel = {NULL};
 
                imap_info("Starting tunnel '%s'... ", srvc->tunnel);
 
index 8953548c07bb36f20798c7ca344d07960c22618c..838b6a732e4758265432cbc9c8e8fc81568a2b50 100644 (file)
@@ -61,12 +61,15 @@ static void process_tree(struct rev_info *revs,
                         struct tree *tree,
                         show_object_fn show,
                         struct name_path *path,
+                        struct strbuf *base,
                         const char *name)
 {
        struct object *obj = &tree->object;
        struct tree_desc desc;
        struct name_entry entry;
        struct name_path me;
+       int all_interesting = (revs->diffopt.pathspec.nr == 0);
+       int baselen = base->len;
 
        if (!revs->tree_objects)
                return;
@@ -82,13 +85,32 @@ static void process_tree(struct rev_info *revs,
        me.elem = name;
        me.elem_len = strlen(name);
 
+       if (!all_interesting) {
+               strbuf_addstr(base, name);
+               if (base->len)
+                       strbuf_addch(base, '/');
+       }
+
        init_tree_desc(&desc, tree->buffer, tree->size);
 
        while (tree_entry(&desc, &entry)) {
+               if (!all_interesting) {
+                       int showit = tree_entry_interesting(&entry,
+                                                           base, 0,
+                                                           &revs->diffopt.pathspec);
+
+                       if (showit < 0)
+                               break;
+                       else if (!showit)
+                               continue;
+                       else if (showit == 2)
+                               all_interesting = 1;
+               }
+
                if (S_ISDIR(entry.mode))
                        process_tree(revs,
                                     lookup_tree(entry.sha1),
-                                    show, &me, entry.path);
+                                    show, &me, base, entry.path);
                else if (S_ISGITLINK(entry.mode))
                        process_gitlink(revs, entry.sha1,
                                        show, &me, entry.path);
@@ -97,6 +119,7 @@ static void process_tree(struct rev_info *revs,
                                     lookup_blob(entry.sha1),
                                     show, &me, entry.path);
        }
+       strbuf_setlen(base, baselen);
        free(tree->buffer);
        tree->buffer = NULL;
 }
@@ -146,9 +169,16 @@ void traverse_commit_list(struct rev_info *revs,
 {
        int i;
        struct commit *commit;
+       struct strbuf base;
 
+       strbuf_init(&base, PATH_MAX);
        while ((commit = get_revision(revs)) != NULL) {
-               add_pending_tree(revs, commit->tree);
+               /*
+                * an uninteresting boundary commit may not have its tree
+                * parsed yet, but we are not going to show them anyway
+                */
+               if (commit->tree)
+                       add_pending_tree(revs, commit->tree);
                show_commit(commit, data);
        }
        for (i = 0; i < revs->pending.nr; i++) {
@@ -164,7 +194,7 @@ void traverse_commit_list(struct rev_info *revs,
                }
                if (obj->type == OBJ_TREE) {
                        process_tree(revs, (struct tree *)obj, show_object,
-                                    NULL, name);
+                                    NULL, &base, name);
                        continue;
                }
                if (obj->type == OBJ_BLOB) {
@@ -181,4 +211,5 @@ void traverse_commit_list(struct rev_info *revs,
                revs->pending.alloc = 0;
                revs->pending.objects = NULL;
        }
+       strbuf_release(&base);
 }
index b0d74cdddee2407de590cb9f725e8e24093d9d35..c6fb77b26fd88f4edf85a8920a6d72e49551deed 100644 (file)
@@ -164,10 +164,10 @@ static char *unable_to_lock_message(const char *path, int err)
                    "If no other git process is currently running, this probably means a\n"
                    "git process crashed in this repository earlier. Make sure no other git\n"
                    "process is running and remove the file manually to continue.",
-                           make_nonrelative_path(path), strerror(err));
+                           absolute_path(path), strerror(err));
        } else
                strbuf_addf(&buf, "Unable to create '%s.lock': %s",
-                           make_nonrelative_path(path), strerror(err));
+                           absolute_path(path), strerror(err));
        return strbuf_detach(&buf, NULL);
 }
 
index b46ed3baef7d9d9971a3886d700059217fbe974a..2a1e3a94c910cd74e41303d8b7aefa539817c831 100644 (file)
@@ -380,18 +380,8 @@ void show_log(struct rev_info *opt)
        if (!opt->verbose_header) {
                graph_show_commit(opt->graph);
 
-               if (!opt->graph) {
-                       if (commit->object.flags & BOUNDARY)
-                               putchar('-');
-                       else if (commit->object.flags & UNINTERESTING)
-                               putchar('^');
-                       else if (opt->left_right) {
-                               if (commit->object.flags & SYMMETRIC_LEFT)
-                                       putchar('<');
-                               else
-                                       putchar('>');
-                       }
-               }
+               if (!opt->graph)
+                       put_revision_mark(opt, commit);
                fputs(find_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);
                if (opt->print_parents)
                        show_parents(commit, abbrev_commit);
@@ -448,18 +438,8 @@ void show_log(struct rev_info *opt)
                if (opt->commit_format != CMIT_FMT_ONELINE)
                        fputs("commit ", stdout);
 
-               if (!opt->graph) {
-                       if (commit->object.flags & BOUNDARY)
-                               putchar('-');
-                       else if (commit->object.flags & UNINTERESTING)
-                               putchar('^');
-                       else if (opt->left_right) {
-                               if (commit->object.flags & SYMMETRIC_LEFT)
-                                       putchar('<');
-                               else
-                                       putchar('>');
-                       }
-               }
+               if (!opt->graph)
+                       put_revision_mark(opt, commit);
                fputs(find_unique_abbrev(commit->object.sha1, abbrev_commit),
                      stdout);
                if (opt->print_parents)
index 16c2dbeab95a0f4099e3de8badf688bb4dee8189..8e82a8b1a5ab8a2f5af00910a8febda93b9e420d 100644 (file)
 #include "dir.h"
 #include "submodule.h"
 
+static const char rename_limit_advice[] =
+"inexact rename detection was skipped because there were too many\n"
+"  files. You may want to set your merge.renamelimit variable to at least\n"
+"  %d and retry this merge.";
+
 static struct tree *shift_tree_object(struct tree *one, struct tree *two,
                                      const char *subtree_shift)
 {
@@ -83,10 +88,8 @@ struct rename_df_conflict_info {
  * Since we want to write the index eventually, we cannot reuse the index
  * for these (temporary) data.
  */
-struct stage_data
-{
-       struct
-       {
+struct stage_data {
+       struct {
                unsigned mode;
                unsigned char sha[20];
        } stages[4];
@@ -137,7 +140,6 @@ static void flush_output(struct merge_options *o)
 __attribute__((format (printf, 3, 4)))
 static void output(struct merge_options *o, int v, const char *fmt, ...)
 {
-       int len;
        va_list ap;
 
        if (!show(o, v))
@@ -148,21 +150,9 @@ static void output(struct merge_options *o, int v, const char *fmt, ...)
        strbuf_setlen(&o->obuf, o->obuf.len + o->call_depth * 2);
 
        va_start(ap, fmt);
-       len = vsnprintf(o->obuf.buf + o->obuf.len, strbuf_avail(&o->obuf), fmt, ap);
+       strbuf_vaddf(&o->obuf, fmt, ap);
        va_end(ap);
 
-       if (len < 0)
-               len = 0;
-       if (len >= strbuf_avail(&o->obuf)) {
-               strbuf_grow(&o->obuf, len + 2);
-               va_start(ap, fmt);
-               len = vsnprintf(o->obuf.buf + o->obuf.len, strbuf_avail(&o->obuf), fmt, ap);
-               va_end(ap);
-               if (len >= strbuf_avail(&o->obuf)) {
-                       die("this should not happen, your snprintf is broken");
-               }
-       }
-       strbuf_setlen(&o->obuf, o->obuf.len + len);
        strbuf_add(&o->obuf, "\n", 1);
        if (!o->buffer_output)
                flush_output(o);
@@ -403,8 +393,7 @@ static void make_room_for_directories_of_df_conflicts(struct merge_options *o,
        }
 }
 
-struct rename
-{
+struct rename {
        struct diff_filepair *pair;
        struct stage_data *src_entry;
        struct stage_data *dst_entry;
@@ -434,14 +423,16 @@ static struct string_list *get_renames(struct merge_options *o,
        opts.detect_rename = DIFF_DETECT_RENAME;
        opts.rename_limit = o->merge_rename_limit >= 0 ? o->merge_rename_limit :
                            o->diff_rename_limit >= 0 ? o->diff_rename_limit :
-                           500;
+                           1000;
        opts.rename_score = o->rename_score;
-       opts.warn_on_too_large_rename = 1;
+       opts.show_rename_progress = o->show_rename_progress;
        opts.output_format = DIFF_FORMAT_NO_OUTPUT;
        if (diff_setup_done(&opts) < 0)
                die("diff setup failed");
        diff_tree_sha1(o_tree->object.sha1, tree->object.sha1, "", &opts);
        diffcore_std(&opts);
+       if (opts.needed_rename_limit > o->needed_rename_limit)
+               o->needed_rename_limit = opts.needed_rename_limit;
        for (i = 0; i < diff_queued_diff.nr; ++i) {
                struct string_list_item *item;
                struct rename *re;
@@ -717,8 +708,7 @@ static void update_file(struct merge_options *o,
 
 /* Low level file merging, update and removal */
 
-struct merge_file_info
-{
+struct merge_file_info {
        unsigned char sha[20];
        unsigned mode;
        unsigned clean:1,
@@ -1666,6 +1656,8 @@ int merge_recursive(struct merge_options *o,
                commit_list_insert(h2, &(*result)->parents->next);
        }
        flush_output(o);
+       if (o->needed_rename_limit)
+               warning(rename_limit_advice, o->needed_rename_limit);
        return clean;
 }
 
index c8135b0ec70cc2eb92e5a6fd9353a134fda6b7bf..7e1e972b13cb8a9f2fae084f769fffede24c8dbb 100644 (file)
@@ -20,6 +20,8 @@ struct merge_options {
        int diff_rename_limit;
        int merge_rename_limit;
        int rename_score;
+       int needed_rename_limit;
+       int show_rename_progress;
        int call_depth;
        struct strbuf obuf;
        struct string_list current_file_set;
@@ -57,6 +59,8 @@ struct tree *write_tree_from_memory(struct merge_options *o);
 int parse_merge_opt(struct merge_options *out, const char *s);
 
 /* builtin/merge.c */
-int try_merge_command(const char *strategy, struct commit_list *common, const char *head_arg, struct commit_list *remotes);
+int try_merge_command(const char *strategy, size_t xopts_nr,
+               const char **xopts, struct commit_list *common,
+               const char *head_arg, struct commit_list *remotes);
 
 #endif
index 71c4d45fcd1ac49630bdb8bc7b0aec658011c21b..28046a998426e88dec9ad6ab431624bb41a81ce1 100644 (file)
@@ -359,7 +359,7 @@ static int ll_merge_in_worktree(struct notes_merge_options *o,
        read_mmblob(&remote, p->remote);
 
        status = ll_merge(&result_buf, sha1_to_hex(p->obj), &base, NULL,
-                         &local, o->local_ref, &remote, o->remote_ref, 0);
+                         &local, o->local_ref, &remote, o->remote_ref, NULL);
 
        free(base.ptr);
        free(local.ptr);
@@ -615,7 +615,7 @@ int notes_merge(struct notes_merge_options *o,
        bases = get_merge_bases(local, remote, 1);
        if (!bases) {
                base_sha1 = null_sha1;
-               base_tree_sha1 = (unsigned char *)EMPTY_TREE_SHA1_BIN;
+               base_tree_sha1 = EMPTY_TREE_SHA1_BIN;
                OUTPUT(o, 4, "No merge base found; doing history-less merge");
        } else if (!bases->next) {
                base_sha1 = bases->item->object.sha1;
index 4d1d61546f0441bd198cda3ad153b35a91444b72..b6618d92bf04d549350d83b6237770c48734686f 100644 (file)
--- a/object.h
+++ b/object.h
@@ -6,11 +6,6 @@ struct object_list {
        struct object_list *next;
 };
 
-struct object_refs {
-       unsigned count;
-       struct object *ref[FLEX_ARRAY]; /* more */
-};
-
 struct object_array {
        unsigned int nr;
        unsigned int alloc;
index 9d0cb9a114cb3e5b0a4a4a132b9289ef18d8ae21..c3bf21dbcb4b79fdc815ef80ae5c970aafd02bbf 100644 (file)
@@ -2,8 +2,7 @@
 #include "pack.h"
 #include "pack-revindex.h"
 
-struct idx_entry
-{
+struct idx_entry {
        off_t                offset;
        const unsigned char *sha1;
        unsigned int nr;
index 42b51ef14514f3c3df454e4b718718a9b58f1612..73bd28ad90986af1618d82176076133186d045de 100644 (file)
@@ -561,14 +561,14 @@ static int usage_with_options_internal(struct parse_opt_ctx_t *ctx,
        return PARSE_OPT_HELP;
 }
 
-void usage_with_options(const char * const *usagestr,
+void NORETURN usage_with_options(const char * const *usagestr,
                        const struct option *opts)
 {
        usage_with_options_internal(NULL, usagestr, opts, 0, 1);
        exit(129);
 }
 
-void usage_msg_opt(const char *msg,
+void NORETURN usage_msg_opt(const char *msg,
                   const char * const *usagestr,
                   const struct option *options)
 {
index 31ec5d24763b13b3e97c79f7a3edd6e7799bcd91..d1b12fe979b34ac9bbf2ff637934b96f3878a53d 100644 (file)
@@ -141,7 +141,7 @@ struct option {
        { OPTION_NUMBER, 0, NULL, (v), NULL, (h), \
          PARSE_OPT_NOARG | PARSE_OPT_NONEG, (f) }
 #define OPT_FILENAME(s, l, v, h)    { OPTION_FILENAME, (s), (l), (v), \
-                                      "FILE", (h) }
+                                      "file", (h) }
 #define OPT_COLOR_FLAG(s, l, v, h) \
        { OPTION_CALLBACK, (s), (l), (v), "when", (h), PARSE_OPT_OPTARG, \
                parse_opt_color_flag_cb, (intptr_t)"always" }
index d218faa02bd12b0e6a0df298a6a0e5787e46d93f..56e0a5ede22c9396fc897bf1d3444dce92d8916f 100644 (file)
@@ -48,7 +48,7 @@ void *patch_delta(const void *src_buf, unsigned long src_size,
                        if (cmd & 0x20) cp_size |= (*data++ << 8);
                        if (cmd & 0x40) cp_size |= (*data++ << 16);
                        if (cp_size == 0) cp_size = 0x10000;
-                       if (cp_off + cp_size < cp_size ||
+                       if (unsigned_add_overflows(cp_off, cp_size) ||
                            cp_off + cp_size > src_size ||
                            cp_size > size)
                                break;
diff --git a/path.c b/path.c
index 8951333cb88a6e28ef29538183ebf71e3b0913fa..4d73cc9cd26708b4cb41e86fb319b93f526cb2f2 100644 (file)
--- a/path.c
+++ b/path.c
@@ -397,7 +397,7 @@ int set_shared_perm(const char *path, int mode)
        return 0;
 }
 
-const char *make_relative_path(const char *abs, const char *base)
+const char *relative_path(const char *abs, const char *base)
 {
        static char buf[PATH_MAX + 1];
        int i = 0, j = 0;
index 205e48aa3a7b912005565ac9c296205a897a1476..a86ab709c25b5e110aa2708941cea560f82c1fa8 100644 (file)
@@ -99,7 +99,7 @@ increase notwithstanding).
 
 use Carp qw(carp croak); # but croak is bad - throw instead
 use Error qw(:try);
-use Cwd qw(abs_path);
+use Cwd qw(abs_path cwd);
 use IPC::Open2 qw(open2);
 use Fcntl qw(SEEK_SET SEEK_CUR);
 }
@@ -396,7 +396,16 @@ See C<command_close_bidi_pipe()> for details.
 
 sub command_bidi_pipe {
        my ($pid, $in, $out);
+       my ($self) = _maybe_self(@_);
+       local %ENV = %ENV;
+       my $cwd_save = undef;
+       if ($self) {
+               shift;
+               $cwd_save = cwd();
+               _setup_git_cmd_env($self);
+       }
        $pid = open2($in, $out, 'git', @_);
+       chdir($cwd_save) if $cwd_save;
        return ($pid, $in, $out, join(' ', @_));
 }
 
@@ -843,7 +852,7 @@ sub _open_hash_and_insert_object_if_needed {
 
        ($self->{hash_object_pid}, $self->{hash_object_in},
         $self->{hash_object_out}, $self->{hash_object_ctx}) =
-               command_bidi_pipe(qw(hash-object -w --stdin-paths --no-filters));
+               $self->command_bidi_pipe(qw(hash-object -w --stdin-paths --no-filters));
 }
 
 sub _close_hash_and_insert_object {
@@ -932,7 +941,7 @@ sub _open_cat_blob_if_needed {
 
        ($self->{cat_blob_pid}, $self->{cat_blob_in},
         $self->{cat_blob_out}, $self->{cat_blob_ctx}) =
-               command_bidi_pipe(qw(cat-file --batch));
+               $self->command_bidi_pipe(qw(cat-file --batch));
 }
 
 sub _close_cat_blob {
@@ -1279,6 +1288,14 @@ sub _command_common_pipe {
 # for the given repository and execute the git command.
 sub _cmd_exec {
        my ($self, @args) = @_;
+       _setup_git_cmd_env($self);
+       _execv_git_cmd(@args);
+       die qq[exec "@args" failed: $!];
+}
+
+# set up the appropriate state for git command
+sub _setup_git_cmd_env {
+       my $self = shift;
        if ($self) {
                $self->repo_path() and $ENV{'GIT_DIR'} = $self->repo_path();
                $self->repo_path() and $self->wc_path()
@@ -1286,8 +1303,6 @@ sub _cmd_exec {
                $self->wc_path() and chdir($self->wc_path());
                $self->wc_subdir() and chdir($self->wc_subdir());
        }
-       _execv_git_cmd(@args);
-       die qq[exec "@args" failed: $!];
 }
 
 # Execute the given Git command ($_[0]) with arguments ($_[1..])
index 295ba2b16c8675d8c5c5d0a5ee6e61e044ce99dd..cd1bd264139bf15cca06f900b7921f0956c6458b 100644 (file)
@@ -1,6 +1,51 @@
 #include "cache.h"
 #include "pkt-line.h"
 
+const char *packet_trace_prefix = "git";
+static const char trace_key[] = "GIT_TRACE_PACKET";
+
+void packet_trace_identity(const char *prog)
+{
+       packet_trace_prefix = xstrdup(prog);
+}
+
+static void packet_trace(const char *buf, unsigned int len, int write)
+{
+       int i;
+       struct strbuf out;
+
+       if (!trace_want(trace_key))
+               return;
+
+       /* +32 is just a guess for header + quoting */
+       strbuf_init(&out, len+32);
+
+       strbuf_addf(&out, "packet: %12s%c ",
+                   packet_trace_prefix, write ? '>' : '<');
+
+       if ((len >= 4 && !prefixcmp(buf, "PACK")) ||
+           (len >= 5 && !prefixcmp(buf+1, "PACK"))) {
+               strbuf_addstr(&out, "PACK ...");
+               unsetenv(trace_key);
+       }
+       else {
+               /* XXX we should really handle printable utf8 */
+               for (i = 0; i < len; i++) {
+                       /* suppress newlines */
+                       if (buf[i] == '\n')
+                               continue;
+                       if (buf[i] >= 0x20 && buf[i] <= 0x7e)
+                               strbuf_addch(&out, buf[i]);
+                       else
+                               strbuf_addf(&out, "\\%o", buf[i]);
+               }
+       }
+
+       strbuf_addch(&out, '\n');
+       trace_strbuf(trace_key, &out);
+       strbuf_release(&out);
+}
+
 /*
  * Write a packetized stream, where each line is preceded by
  * its length (including the header) as a 4-byte hex number.
@@ -39,11 +84,13 @@ ssize_t safe_write(int fd, const void *buf, ssize_t n)
  */
 void packet_flush(int fd)
 {
+       packet_trace("0000", 4, 1);
        safe_write(fd, "0000", 4);
 }
 
 void packet_buf_flush(struct strbuf *buf)
 {
+       packet_trace("0000", 4, 1);
        strbuf_add(buf, "0000", 4);
 }
 
@@ -62,6 +109,7 @@ static unsigned format_packet(const char *fmt, va_list args)
        buffer[1] = hex(n >> 8);
        buffer[2] = hex(n >> 4);
        buffer[3] = hex(n);
+       packet_trace(buffer+4, n-4, 1);
        return n;
 }
 
@@ -130,13 +178,16 @@ int packet_read_line(int fd, char *buffer, unsigned size)
        len = packet_length(linelen);
        if (len < 0)
                die("protocol error: bad line length character: %.4s", linelen);
-       if (!len)
+       if (!len) {
+               packet_trace("0000", 4, 0);
                return 0;
+       }
        len -= 4;
        if (len >= size)
                die("protocol error: bad line length %d", len);
        safe_read(fd, buffer, len);
        buffer[len] = 0;
+       packet_trace(buffer, len, 0);
        return len;
 }
 
@@ -153,6 +204,7 @@ int packet_get_line(struct strbuf *out,
        if (!len) {
                *src_buf += 4;
                *src_len -= 4;
+               packet_trace("0000", 4, 0);
                return 0;
        }
        if (*src_len < len)
@@ -165,5 +217,6 @@ int packet_get_line(struct strbuf *out,
        strbuf_add(out, *src_buf, len);
        *src_buf += len;
        *src_len -= len;
+       packet_trace(out->buf, out->len, 0);
        return len;
 }
diff --git a/po/.gitignore b/po/.gitignore
new file mode 100644 (file)
index 0000000..a242a86
--- /dev/null
@@ -0,0 +1 @@
+/git.pot
index e3d0bda31a98372eb9b6a8c2cd0fd65917a9dbde..49cb08df96faa90101bb25d8f96acaffc066f19b 100644 (file)
@@ -35,7 +35,9 @@ static void *preload_thread(void *_data)
        struct index_state *index = p->index;
        struct cache_entry **cep = index->cache + p->offset;
        struct cache_def cache;
+       struct pathspec pathspec;
 
+       init_pathspec(&pathspec, p->pathspec);
        memset(&cache, 0, sizeof(cache));
        nr = p->nr;
        if (nr + p->offset > index->cache_nr)
@@ -51,7 +53,7 @@ static void *preload_thread(void *_data)
                        continue;
                if (ce_uptodate(ce))
                        continue;
-               if (!ce_path_match(ce, p->pathspec))
+               if (!ce_path_match(ce, &pathspec))
                        continue;
                if (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce)))
                        continue;
@@ -61,6 +63,7 @@ static void *preload_thread(void *_data)
                        continue;
                ce_mark_uptodate(ce);
        } while (--nr > 0);
+       free_pathspec(&pathspec);
        return NULL;
 }
 
index 85499347514ec3e1d62d6caa9f53b886c556e345..e1d8a8f414bf052a59fbe78d022e611f44ed8361 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -216,36 +216,53 @@ static int is_rfc2047_special(char ch)
 static void add_rfc2047(struct strbuf *sb, const char *line, int len,
                       const char *encoding)
 {
-       int i, last;
+       static const int max_length = 78; /* per rfc2822 */
+       int i;
+       int line_len;
+
+       /* How many bytes are already used on the current line? */
+       for (i = sb->len - 1; i >= 0; i--)
+               if (sb->buf[i] == '\n')
+                       break;
+       line_len = sb->len - (i+1);
 
        for (i = 0; i < len; i++) {
                int ch = line[i];
-               if (non_ascii(ch))
+               if (non_ascii(ch) || ch == '\n')
                        goto needquote;
                if ((i + 1 < len) && (ch == '=' && line[i+1] == '?'))
                        goto needquote;
        }
-       strbuf_add(sb, line, len);
+       strbuf_add_wrapped_bytes(sb, line, len, 0, 1, max_length - line_len);
        return;
 
 needquote:
        strbuf_grow(sb, len * 3 + strlen(encoding) + 100);
        strbuf_addf(sb, "=?%s?q?", encoding);
-       for (i = last = 0; i < len; i++) {
+       line_len += strlen(encoding) + 5; /* 5 for =??q? */
+       for (i = 0; i < len; i++) {
                unsigned ch = line[i] & 0xFF;
+
+               if (line_len >= max_length - 2) {
+                       strbuf_addf(sb, "?=\n =?%s?q?", encoding);
+                       line_len = strlen(encoding) + 5 + 1; /* =??q? plus SP */
+               }
+
                /*
                 * We encode ' ' using '=20' even though rfc2047
                 * allows using '_' for readability.  Unfortunately,
                 * many programs do not understand this and just
                 * leave the underscore in place.
                 */
-               if (is_rfc2047_special(ch) || ch == ' ') {
-                       strbuf_add(sb, line + last, i - last);
+               if (is_rfc2047_special(ch) || ch == ' ' || ch == '\n') {
                        strbuf_addf(sb, "=%02X", ch);
-                       last = i + 1;
+                       line_len += 3;
+               }
+               else {
+                       strbuf_addch(sb, ch);
+                       line_len++;
                }
        }
-       strbuf_add(sb, line + last, len - last);
        strbuf_addstr(sb, "?=");
 }
 
@@ -859,11 +876,7 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
                                              c->abbrev_parent_hashes.off;
                return 1;
        case 'm':               /* left/right/bottom */
-               strbuf_addch(sb, (commit->object.flags & BOUNDARY)
-                                ? '-'
-                                : (commit->object.flags & SYMMETRIC_LEFT)
-                                ? '<'
-                                : '>');
+               strbuf_addstr(sb, get_revision_mark(NULL, commit));
                return 1;
        case 'd':
                format_decoration(sb, commit);
@@ -1106,11 +1119,10 @@ void pp_title_line(enum cmit_fmt fmt,
                   const char *encoding,
                   int need_8bit_cte)
 {
-       const char *line_separator = (fmt == CMIT_FMT_EMAIL) ? "\n " : " ";
        struct strbuf title;
 
        strbuf_init(&title, 80);
-       *msg_p = format_subject(&title, *msg_p, line_separator);
+       *msg_p = format_subject(&title, *msg_p, " ");
 
        strbuf_grow(sb, title.len + 1024);
        if (subject) {
diff --git a/quote.h b/quote.h
index 38003bff5f97a11e051b106522a8548d43d24f6c..024e21d80ceaa37ec1f893acc907a62092560d21 100644 (file)
--- a/quote.h
+++ b/quote.h
@@ -1,8 +1,7 @@
 #ifndef QUOTE_H
 #define QUOTE_H
 
-#include <stddef.h>
-#include <stdio.h>
+struct strbuf;
 
 /* Help to copy the thing properly quoted for the shell safety.
  * any single quote is replaced with '\'', any exclamation point
index 4f2e890b01b0c27ef2e49080e1fd34bf67e969c7..98d526bd48d2a0e764dd0efb4c6efe4965174c9a 100644 (file)
@@ -92,7 +92,7 @@ static int ce_compare_data(struct cache_entry *ce, struct stat *st)
 
        if (fd >= 0) {
                unsigned char sha1[20];
-               if (!index_fd(sha1, fd, st, 0, OBJ_BLOB, ce->name))
+               if (!index_fd(sha1, fd, st, 0, OBJ_BLOB, ce->name, 0))
                        match = hashcmp(sha1, ce->sha1);
                /* index_fd() closed the file descriptor already */
        }
@@ -706,30 +706,9 @@ int ce_same_name(struct cache_entry *a, struct cache_entry *b)
        return ce_namelen(b) == len && !memcmp(a->name, b->name, len);
 }
 
-int ce_path_match(const struct cache_entry *ce, const char **pathspec)
+int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec)
 {
-       const char *match, *name;
-       int len;
-
-       if (!pathspec)
-               return 1;
-
-       len = ce_namelen(ce);
-       name = ce->name;
-       while ((match = *pathspec++) != NULL) {
-               int matchlen = strlen(match);
-               if (matchlen > len)
-                       continue;
-               if (memcmp(name, match, matchlen))
-                       continue;
-               if (matchlen && name[matchlen-1] == '/')
-                       return 1;
-               if (name[matchlen] == '/' || !name[matchlen])
-                       return 1;
-               if (!matchlen)
-                       return 1;
-       }
-       return 0;
+       return match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL);
 }
 
 /*
@@ -1104,7 +1083,7 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
 }
 
 static void show_file(const char * fmt, const char * name, int in_porcelain,
-                     int * first, char *header_msg)
+                     int * first, const char *header_msg)
 {
        if (in_porcelain && *first && header_msg) {
                printf("%s\n", header_msg);
@@ -1114,7 +1093,7 @@ static void show_file(const char * fmt, const char * name, int in_porcelain,
 }
 
 int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec,
-                 char *seen, char *header_msg)
+                 char *seen, const char *header_msg)
 {
        int i;
        int has_errors = 0;
index 04d4813e4183c675b54aba942cd078d8ff632053..775d6143037aa4573c0202715fe1b1a0f99e2799 100644 (file)
@@ -356,14 +356,59 @@ static size_t rpc_in(const void *ptr, size_t eltsize,
        return size;
 }
 
+static int run_slot(struct active_request_slot *slot)
+{
+       int err = 0;
+       struct slot_results results;
+
+       slot->results = &results;
+       slot->curl_result = curl_easy_perform(slot->curl);
+       finish_active_slot(slot);
+
+       if (results.curl_result != CURLE_OK) {
+               err |= error("RPC failed; result=%d, HTTP code = %ld",
+                       results.curl_result, results.http_code);
+       }
+
+       return err;
+}
+
+static int probe_rpc(struct rpc_state *rpc)
+{
+       struct active_request_slot *slot;
+       struct curl_slist *headers = NULL;
+       struct strbuf buf = STRBUF_INIT;
+       int err;
+
+       slot = get_active_slot();
+
+       headers = curl_slist_append(headers, rpc->hdr_content_type);
+       headers = curl_slist_append(headers, rpc->hdr_accept);
+
+       curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
+       curl_easy_setopt(slot->curl, CURLOPT_POST, 1);
+       curl_easy_setopt(slot->curl, CURLOPT_URL, rpc->service_url);
+       curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "");
+       curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, "0000");
+       curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, 4);
+       curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers);
+       curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite_buffer);
+       curl_easy_setopt(slot->curl, CURLOPT_FILE, &buf);
+
+       err = run_slot(slot);
+
+       curl_slist_free_all(headers);
+       strbuf_release(&buf);
+       return err;
+}
+
 static int post_rpc(struct rpc_state *rpc)
 {
        struct active_request_slot *slot;
-       struct slot_results results;
        struct curl_slist *headers = NULL;
        int use_gzip = rpc->gzip_request;
        char *gzip_body = NULL;
-       int err = 0, large_request = 0;
+       int err, large_request = 0;
 
        /* Try to load the entire request, if we can fit it into the
         * allocated buffer space we can use HTTP/1.0 and avoid the
@@ -386,8 +431,13 @@ static int post_rpc(struct rpc_state *rpc)
                rpc->len += n;
        }
 
+       if (large_request) {
+               err = probe_rpc(rpc);
+               if (err)
+                       return err;
+       }
+
        slot = get_active_slot();
-       slot->results = &results;
 
        curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0);
        curl_easy_setopt(slot->curl, CURLOPT_POST, 1);
@@ -396,12 +446,12 @@ static int post_rpc(struct rpc_state *rpc)
 
        headers = curl_slist_append(headers, rpc->hdr_content_type);
        headers = curl_slist_append(headers, rpc->hdr_accept);
+       headers = curl_slist_append(headers, "Expect:");
 
        if (large_request) {
                /* The request body is large and the size cannot be predicted.
                 * We must use chunked encoding to send it.
                 */
-               headers = curl_slist_append(headers, "Expect: 100-continue");
                headers = curl_slist_append(headers, "Transfer-Encoding: chunked");
                rpc->initial_buffer = 1;
                curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, rpc_out);
@@ -475,13 +525,7 @@ static int post_rpc(struct rpc_state *rpc)
        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, rpc_in);
        curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc);
 
-       slot->curl_result = curl_easy_perform(slot->curl);
-       finish_active_slot(slot);
-
-       if (results.curl_result != CURLE_OK) {
-               err |= error("RPC failed; result=%d, HTTP code = %ld",
-                       results.curl_result, results.http_code);
-       }
+       err = run_slot(slot);
 
        curl_slist_free_all(headers);
        free(gzip_body);
index eb59604fd39e2beaf7d43802499c27305ac92132..7c6c7544ada4585e62341f0c0854a919f10c2277 100644 (file)
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "sha1-lookup.h"
 #include "refs.h"
+#include "commit.h"
 
 static struct replace_object {
        unsigned char sha1[2][20];
index d2608434750c336c3f3881efda8373b7c67d4b11..22996bd08b532fb8016f24391dd0e63010706385 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -7,6 +7,11 @@
 #include "ll-merge.h"
 #include "attr.h"
 
+#define RESOLVED 0
+#define PUNTED 1
+#define THREE_STAGED 2
+void *RERERE_RESOLVED = &RERERE_RESOLVED;
+
 /* if rerere_enabled == -1, fall back to detection of .git/rr-cache */
 static int rerere_enabled = -1;
 
@@ -345,21 +350,74 @@ static int handle_cache(const char *path, unsigned char *sha1, const char *outpu
        return hunk_no;
 }
 
-static int find_conflict(struct string_list *conflict)
+static int check_one_conflict(int i, int *type)
 {
-       int i;
-       if (read_cache() < 0)
-               return error("Could not read index");
-       for (i = 0; i+1 < active_nr; i++) {
+       struct cache_entry *e = active_cache[i];
+
+       if (!ce_stage(e)) {
+               *type = RESOLVED;
+               return i + 1;
+       }
+
+       *type = PUNTED;
+       if (ce_stage(e) == 1) {
+               if (active_nr <= ++i)
+                       return i + 1;
+       }
+
+       /* Only handle regular files with both stages #2 and #3 */
+       if (i + 1 < active_nr) {
                struct cache_entry *e2 = active_cache[i];
-               struct cache_entry *e3 = active_cache[i+1];
+               struct cache_entry *e3 = active_cache[i + 1];
                if (ce_stage(e2) == 2 &&
                    ce_stage(e3) == 3 &&
-                   ce_same_name(e2, e3) &&
+                   ce_same_name(e, e3) &&
                    S_ISREG(e2->ce_mode) &&
-                   S_ISREG(e3->ce_mode)) {
-                       string_list_insert(conflict, (const char *)e2->name);
-                       i++; /* skip over both #2 and #3 */
+                   S_ISREG(e3->ce_mode))
+                       *type = THREE_STAGED;
+       }
+
+       /* Skip the entries with the same name */
+       while (i < active_nr && ce_same_name(e, active_cache[i]))
+               i++;
+       return i;
+}
+
+static int find_conflict(struct string_list *conflict)
+{
+       int i;
+       if (read_cache() < 0)
+               return error("Could not read index");
+
+       for (i = 0; i < active_nr;) {
+               int conflict_type;
+               struct cache_entry *e = active_cache[i];
+               i = check_one_conflict(i, &conflict_type);
+               if (conflict_type == THREE_STAGED)
+                       string_list_insert(conflict, (const char *)e->name);
+       }
+       return 0;
+}
+
+int rerere_remaining(struct string_list *merge_rr)
+{
+       int i;
+       if (read_cache() < 0)
+               return error("Could not read index");
+
+       for (i = 0; i < active_nr;) {
+               int conflict_type;
+               struct cache_entry *e = active_cache[i];
+               i = check_one_conflict(i, &conflict_type);
+               if (conflict_type == PUNTED)
+                       string_list_insert(merge_rr, (const char *)e->name);
+               else if (conflict_type == RESOLVED) {
+                       struct string_list_item *it;
+                       it = string_list_lookup(merge_rr, (const char *)e->name);
+                       if (it != NULL) {
+                               free(it->util);
+                               it->util = RERERE_RESOLVED;
+                       }
                }
        }
        return 0;
index eaa9004dcdbb2f0dfd446e1ac68237c6dff18530..595f49f701dc1003927679085ca6eea8ad1083ae 100644 (file)
--- a/rerere.h
+++ b/rerere.h
@@ -6,11 +6,19 @@
 #define RERERE_AUTOUPDATE   01
 #define RERERE_NOAUTOUPDATE 02
 
+/*
+ * Marks paths that have been hand-resolved and added to the
+ * index. Set in the util field of such paths after calling
+ * rerere_remaining.
+ */
+extern void *RERERE_RESOLVED;
+
 extern int setup_rerere(struct string_list *, int);
 extern int rerere(int);
 extern const char *rerere_path(const char *hex, const char *file);
 extern int has_rerere_resolution(const char *hex);
 extern int rerere_forget(const char **);
+extern int rerere_remaining(struct string_list *);
 
 #define OPT_RERERE_AUTOUPDATE(v) OPT_UYN(0, "rerere-autoupdate", (v), \
        "update the index with reused conflict resolution if possible")
index 7b9eaefae4ed03e994c2122453144b3c09591b9c..e96c281d1f04f37e519e9447e18e43b86cb2363a 100644 (file)
@@ -323,7 +323,7 @@ static int rev_compare_tree(struct rev_info *revs, struct commit *parent, struct
                 * tagged commit by specifying both --simplify-by-decoration
                 * and pathspec.
                 */
-               if (!revs->prune_data)
+               if (!revs->prune_data.nr)
                        return REV_TREE_SAME;
        }
 
@@ -535,6 +535,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
        int left_count = 0, right_count = 0;
        int left_first;
        struct patch_ids ids;
+       unsigned cherry_flag;
 
        /* First count the commits on the left and on the right */
        for (p = list; p; p = p->next) {
@@ -553,11 +554,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
 
        left_first = left_count < right_count;
        init_patch_ids(&ids);
-       if (revs->diffopt.nr_paths) {
-               ids.diffopts.nr_paths = revs->diffopt.nr_paths;
-               ids.diffopts.paths = revs->diffopt.paths;
-               ids.diffopts.pathlens = revs->diffopt.pathlens;
-       }
+       ids.diffopts.pathspec = revs->diffopt.pathspec;
 
        /* Compute patch-ids for one side */
        for (p = list; p; p = p->next) {
@@ -576,6 +573,9 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
                commit->util = add_commit_patch_id(commit, &ids);
        }
 
+       /* either cherry_mark or cherry_pick are true */
+       cherry_flag = revs->cherry_mark ? PATCHSAME : SHOWN;
+
        /* Check the other side */
        for (p = list; p; p = p->next) {
                struct commit *commit = p->item;
@@ -598,7 +598,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
                if (!id)
                        continue;
                id->seen = 1;
-               commit->object.flags |= SHOWN;
+               commit->object.flags |= cherry_flag;
        }
 
        /* Now check the original side for seen ones */
@@ -610,7 +610,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
                if (!ent)
                        continue;
                if (ent->seen)
-                       commit->object.flags |= SHOWN;
+                       commit->object.flags |= cherry_flag;
                commit->util = NULL;
        }
 
@@ -733,6 +733,23 @@ static struct commit_list *collect_bottom_commits(struct commit_list *list)
        return bottom;
 }
 
+/* Assumes either left_only or right_only is set */
+static void limit_left_right(struct commit_list *list, struct rev_info *revs)
+{
+       struct commit_list *p;
+
+       for (p = list; p; p = p->next) {
+               struct commit *commit = p->item;
+
+               if (revs->right_only) {
+                       if (commit->object.flags & SYMMETRIC_LEFT)
+                               commit->object.flags |= SHOWN;
+               } else  /* revs->left_only is set */
+                       if (!(commit->object.flags & SYMMETRIC_LEFT))
+                               commit->object.flags |= SHOWN;
+       }
+}
+
 static int limit_list(struct rev_info *revs)
 {
        int slop = SLOP;
@@ -785,9 +802,12 @@ static int limit_list(struct rev_info *revs)
                show(revs, newlist);
                show_early_output = NULL;
        }
-       if (revs->cherry_pick)
+       if (revs->cherry_pick || revs->cherry_mark)
                cherry_pick_list(newlist, revs);
 
+       if (revs->left_only || revs->right_only)
+               limit_left_right(newlist, revs);
+
        if (bottom) {
                limit_to_ancestry(bottom, newlist);
                free_commit_list(bottom);
@@ -973,7 +993,7 @@ static void prepare_show_merge(struct rev_info *revs)
                struct cache_entry *ce = active_cache[i];
                if (!ce_stage(ce))
                        continue;
-               if (ce_path_match(ce, revs->prune_data)) {
+               if (ce_path_match(ce, &revs->prune_data)) {
                        prune_num++;
                        prune = xrealloc(prune, sizeof(*prune) * prune_num);
                        prune[prune_num-2] = ce->name;
@@ -983,7 +1003,8 @@ static void prepare_show_merge(struct rev_info *revs)
                       ce_same_name(ce, active_cache[i+1]))
                        i++;
        }
-       revs->prune_data = prune;
+       free_pathspec(&revs->prune_data);
+       init_pathspec(&revs->prune_data, prune);
        revs->limited = 1;
 }
 
@@ -1263,9 +1284,32 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                revs->boundary = 1;
        } else if (!strcmp(arg, "--left-right")) {
                revs->left_right = 1;
+       } else if (!strcmp(arg, "--left-only")) {
+               if (revs->right_only)
+                       die("--left-only is incompatible with --right-only"
+                           " or --cherry");
+               revs->left_only = 1;
+       } else if (!strcmp(arg, "--right-only")) {
+               if (revs->left_only)
+                       die("--right-only is incompatible with --left-only");
+               revs->right_only = 1;
+       } else if (!strcmp(arg, "--cherry")) {
+               if (revs->left_only)
+                       die("--cherry is incompatible with --left-only");
+               revs->cherry_mark = 1;
+               revs->right_only = 1;
+               revs->no_merges = 1;
+               revs->limited = 1;
        } else if (!strcmp(arg, "--count")) {
                revs->count = 1;
+       } else if (!strcmp(arg, "--cherry-mark")) {
+               if (revs->cherry_pick)
+                       die("--cherry-mark is incompatible with --cherry-pick");
+               revs->cherry_mark = 1;
+               revs->limited = 1; /* needs limit_list() */
        } else if (!strcmp(arg, "--cherry-pick")) {
+               if (revs->cherry_mark)
+                       die("--cherry-pick is incompatible with --cherry-mark");
                revs->cherry_pick = 1;
                revs->limited = 1;
        } else if (!strcmp(arg, "--objects")) {
@@ -1620,7 +1664,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
        }
 
        if (prune_data)
-               revs->prune_data = get_pathspec(revs->prefix, prune_data);
+               init_pathspec(&revs->prune_data, get_pathspec(revs->prefix, prune_data));
 
        if (revs->def == NULL)
                revs->def = opt ? opt->def : NULL;
@@ -1651,13 +1695,13 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
        if (revs->topo_order)
                revs->limited = 1;
 
-       if (revs->prune_data) {
-               diff_tree_setup_paths(revs->prune_data, &revs->pruning);
+       if (revs->prune_data.nr) {
+               diff_tree_setup_paths(revs->prune_data.raw, &revs->pruning);
                /* Can't prune commits with rename following: the paths change.. */
                if (!DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES))
                        revs->prune = 1;
                if (!revs->full_diff)
-                       diff_tree_setup_paths(revs->prune_data, &revs->diffopt);
+                       diff_tree_setup_paths(revs->prune_data.raw, &revs->diffopt);
        }
        if (revs->combine_merges)
                revs->ignore_merges = 0;
@@ -2235,3 +2279,32 @@ struct commit *get_revision(struct rev_info *revs)
                graph_update(revs->graph, c);
        return c;
 }
+
+char *get_revision_mark(const struct rev_info *revs, const struct commit *commit)
+{
+       if (commit->object.flags & BOUNDARY)
+               return "-";
+       else if (commit->object.flags & UNINTERESTING)
+               return "^";
+       else if (commit->object.flags & PATCHSAME)
+               return "=";
+       else if (!revs || revs->left_right) {
+               if (commit->object.flags & SYMMETRIC_LEFT)
+                       return "<";
+               else
+                       return ">";
+       } else if (revs->graph)
+               return "*";
+       else if (revs->cherry_mark)
+               return "+";
+       return "";
+}
+
+void put_revision_mark(const struct rev_info *revs, const struct commit *commit)
+{
+       char *mark = get_revision_mark(revs, commit);
+       if (!strlen(mark))
+               return;
+       fputs(mark, stdout);
+       putchar(' ');
+}
index 05659c64acd7fe8eb7be011cee6174e397e57baf..ae948601f94c726c3677f23517dba5c046431904 100644 (file)
@@ -14,7 +14,8 @@
 #define CHILD_SHOWN    (1u<<6)
 #define ADDED          (1u<<7) /* Parents already parsed and added? */
 #define SYMMETRIC_LEFT (1u<<8)
-#define ALL_REV_FLAGS  ((1u<<9)-1)
+#define PATCHSAME      (1u<<9)
+#define ALL_REV_FLAGS  ((1u<<10)-1)
 
 #define DECORATE_SHORT_REFS    1
 #define DECORATE_FULL_REFS     2
@@ -34,7 +35,7 @@ struct rev_info {
        /* Basic information */
        const char *prefix;
        const char *def;
-       void *prune_data;
+       struct pathspec prune_data;
        unsigned int early_output;
 
        /* Traversal flags */
@@ -59,6 +60,8 @@ struct rev_info {
                        boundary:2,
                        count:1,
                        left_right:1,
+                       left_only:1,
+                       right_only:1,
                        rewrite_parents:1,
                        print_parents:1,
                        show_source:1,
@@ -66,6 +69,7 @@ struct rev_info {
                        reverse:1,
                        reverse_output_stage:1,
                        cherry_pick:1,
+                       cherry_mark:1,
                        bisect:1,
                        ancestry_path:1,
                        first_parent_only:1;
@@ -163,6 +167,8 @@ extern int handle_revision_arg(const char *arg, struct rev_info *revs,int flags,
 
 extern int prepare_revision_walk(struct rev_info *revs);
 extern struct commit *get_revision(struct rev_info *revs);
+extern char *get_revision_mark(const struct rev_info *revs, const struct commit *commit);
+extern void put_revision_mark(const struct rev_info *revs, const struct commit *commit);
 
 extern void mark_parents_uninteresting(struct commit *commit);
 extern void mark_tree_uninteresting(struct tree *tree);
index 2a1041ef6599c84fff6a8d9faf5dea23a2af3ab0..f91e446c86be8e27f98554567143d7ce6f934bd1 100644 (file)
@@ -194,6 +194,7 @@ fail_pipe:
        }
 
        trace_argv_printf(cmd->argv, "trace: run_command:");
+       fflush(NULL);
 
 #ifndef WIN32
 {
@@ -201,7 +202,6 @@ fail_pipe:
        if (pipe(notify_pipe))
                notify_pipe[0] = notify_pipe[1] = -1;
 
-       fflush(NULL);
        cmd->pid = fork();
        if (!cmd->pid) {
                /*
diff --git a/setup.c b/setup.c
index dadc66659a4037b614b215b7f812c4df8969562b..03cd84f2fcbf9cdbc25116308a9c2c9407af8e71 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -7,10 +7,13 @@ static int inside_work_tree = -1;
 char *prefix_path(const char *prefix, int len, const char *path)
 {
        const char *orig = path;
-       char *sanitized = xmalloc(len + strlen(path) + 1);
-       if (is_absolute_path(orig))
-               strcpy(sanitized, path);
-       else {
+       char *sanitized;
+       if (is_absolute_path(orig)) {
+               const char *temp = real_path(path);
+               sanitized = xmalloc(len + strlen(temp) + 1);
+               strcpy(sanitized, temp);
+       } else {
+               sanitized = xmalloc(len + strlen(path) + 1);
                if (len)
                        memcpy(sanitized, prefix, len);
                strcpy(sanitized + len, path);
@@ -218,7 +221,7 @@ void setup_work_tree(void)
        work_tree = get_git_work_tree();
        git_dir = get_git_dir();
        if (!is_absolute_path(git_dir))
-               git_dir = make_absolute_path(git_dir);
+               git_dir = real_path(get_git_dir());
        if (!work_tree || chdir(work_tree))
                die("This operation must be run in a work tree");
 
@@ -229,7 +232,7 @@ void setup_work_tree(void)
        if (getenv(GIT_WORK_TREE_ENVIRONMENT))
                setenv(GIT_WORK_TREE_ENVIRONMENT, ".", 1);
 
-       set_git_dir(make_relative_path(git_dir, work_tree));
+       set_git_dir(relative_path(git_dir, work_tree));
        initialized = 1;
 }
 
@@ -309,7 +312,7 @@ const char *read_gitfile_gently(const char *path)
 
        if (!is_git_directory(dir))
                die("Not a git repository: %s", dir);
-       path = make_absolute_path(dir);
+       path = real_path(dir);
 
        free(buf);
        return path;
@@ -389,7 +392,7 @@ static const char *setup_explicit_git_dir(const char *gitdirenv,
 
        if (!prefixcmp(cwd, worktree) &&
            cwd[strlen(worktree)] == '/') { /* cwd inside worktree */
-               set_git_dir(make_absolute_path(gitdirenv));
+               set_git_dir(real_path(gitdirenv));
                if (chdir(worktree))
                        die_errno("Could not chdir to '%s'", worktree);
                cwd[len++] = '/';
@@ -414,7 +417,7 @@ static const char *setup_discovered_git_dir(const char *gitdir,
        /* --work-tree is set without --git-dir; use discovered one */
        if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
                if (offset != len && !is_absolute_path(gitdir))
-                       gitdir = xstrdup(make_absolute_path(gitdir));
+                       gitdir = xstrdup(real_path(gitdir));
                if (chdir(cwd))
                        die_errno("Could not come back to cwd");
                return setup_explicit_git_dir(gitdir, cwd, len, nongit_ok);
@@ -422,7 +425,7 @@ static const char *setup_discovered_git_dir(const char *gitdir,
 
        /* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
        if (is_bare_repository_cfg > 0) {
-               set_git_dir(offset == len ? gitdir : make_absolute_path(gitdir));
+               set_git_dir(offset == len ? gitdir : real_path(gitdir));
                if (chdir(cwd))
                        die_errno("Could not come back to cwd");
                return NULL;
index d86a8db69ade6fd26ebd88bbb361a7a86838f14e..b4fcca8ffdbfe48b11478709c61eb90cd64de20d 100644 (file)
@@ -13,6 +13,7 @@
 #include "commit.h"
 #include "tag.h"
 #include "tree.h"
+#include "tree-walk.h"
 #include "refs.h"
 #include "pack-revindex.h"
 #include "sha1-lookup.h"
@@ -37,6 +38,41 @@ const unsigned char null_sha1[20];
 
 static int git_open_noatime(const char *name, struct packed_git *p);
 
+/*
+ * This is meant to hold a *small* number of objects that you would
+ * want read_sha1_file() to be able to return, but yet you do not want
+ * to write them into the object store (e.g. a browse-only
+ * application).
+ */
+static struct cached_object {
+       unsigned char sha1[20];
+       enum object_type type;
+       void *buf;
+       unsigned long size;
+} *cached_objects;
+static int cached_object_nr, cached_object_alloc;
+
+static struct cached_object empty_tree = {
+       EMPTY_TREE_SHA1_BIN_LITERAL,
+       OBJ_TREE,
+       "",
+       0
+};
+
+static struct cached_object *find_cached_object(const unsigned char *sha1)
+{
+       int i;
+       struct cached_object *co = cached_objects;
+
+       for (i = 0; i < cached_object_nr; i++, co++) {
+               if (!hashcmp(co->sha1, sha1))
+                       return co;
+       }
+       if (!hashcmp(sha1, empty_tree.sha1))
+               return &empty_tree;
+       return NULL;
+}
+
 int safe_create_leading_directories(char *path)
 {
        char *pos = path + offset_1st_component(path);
@@ -382,6 +418,8 @@ static unsigned int pack_used_ctr;
 static unsigned int pack_mmap_calls;
 static unsigned int peak_pack_open_windows;
 static unsigned int pack_open_windows;
+static unsigned int pack_open_fds;
+static unsigned int pack_max_fds;
 static size_t peak_pack_mapped;
 static size_t pack_mapped;
 struct packed_git *packed_git;
@@ -559,8 +597,10 @@ static int unuse_one_window(struct packed_git *current, int keep_fd)
                        lru_l->next = lru_w->next;
                else {
                        lru_p->windows = lru_w->next;
-                       if (!lru_p->windows && lru_p->pack_fd != keep_fd) {
+                       if (!lru_p->windows && lru_p->pack_fd != -1
+                               && lru_p->pack_fd != keep_fd) {
                                close(lru_p->pack_fd);
+                               pack_open_fds--;
                                lru_p->pack_fd = -1;
                        }
                }
@@ -645,8 +685,10 @@ void free_pack_by_name(const char *pack_name)
                if (strcmp(pack_name, p->pack_name) == 0) {
                        clear_delta_base_cache();
                        close_pack_windows(p);
-                       if (p->pack_fd != -1)
+                       if (p->pack_fd != -1) {
                                close(p->pack_fd);
+                               pack_open_fds--;
+                       }
                        close_pack_index(p);
                        free(p->bad_object_sha1);
                        *pp = p->next;
@@ -672,9 +714,29 @@ static int open_packed_git_1(struct packed_git *p)
        if (!p->index_data && open_pack_index(p))
                return error("packfile %s index unavailable", p->pack_name);
 
+       if (!pack_max_fds) {
+               struct rlimit lim;
+               unsigned int max_fds;
+
+               if (getrlimit(RLIMIT_NOFILE, &lim))
+                       die_errno("cannot get RLIMIT_NOFILE");
+
+               max_fds = lim.rlim_cur;
+
+               /* Save 3 for stdin/stdout/stderr, 22 for work */
+               if (25 < max_fds)
+                       pack_max_fds = max_fds - 25;
+               else
+                       pack_max_fds = 1;
+       }
+
+       while (pack_max_fds <= pack_open_fds && unuse_one_window(NULL, -1))
+               ; /* nothing */
+
        p->pack_fd = git_open_noatime(p->pack_name, p);
        if (p->pack_fd < 0 || fstat(p->pack_fd, &st))
                return -1;
+       pack_open_fds++;
 
        /* If we created the struct before we had the pack we lack size. */
        if (!p->pack_size) {
@@ -726,6 +788,7 @@ static int open_packed_git(struct packed_git *p)
                return 0;
        if (p->pack_fd != -1) {
                close(p->pack_fd);
+               pack_open_fds--;
                p->pack_fd = -1;
        }
        return -1;
@@ -751,14 +814,13 @@ unsigned char *use_pack(struct packed_git *p,
 {
        struct pack_window *win = *w_cursor;
 
-       if (p->pack_fd == -1 && open_packed_git(p))
-               die("packfile %s cannot be accessed", p->pack_name);
-
        /* Since packfiles end in a hash of their content and it's
         * pointless to ask for an offset into the middle of that
         * hash, and the in_window function above wouldn't match
         * don't allow an offset too close to the end of the file.
         */
+       if (!p->pack_size && p->pack_fd == -1 && open_packed_git(p))
+               die("packfile %s cannot be accessed", p->pack_name);
        if (offset > (p->pack_size - 20))
                die("offset beyond end of packfile (truncated pack?)");
 
@@ -772,6 +834,10 @@ unsigned char *use_pack(struct packed_git *p,
                if (!win) {
                        size_t window_align = packed_git_window_size / 2;
                        off_t len;
+
+                       if (p->pack_fd == -1 && open_packed_git(p))
+                               die("packfile %s cannot be accessed", p->pack_name);
+
                        win = xcalloc(1, sizeof(*win));
                        win->offset = (offset / window_align) * window_align;
                        len = p->pack_size - win->offset;
@@ -789,6 +855,12 @@ unsigned char *use_pack(struct packed_git *p,
                                die("packfile %s cannot be mapped: %s",
                                        p->pack_name,
                                        strerror(errno));
+                       if (!win->offset && win->len == p->pack_size
+                               && !p->do_not_close) {
+                               close(p->pack_fd);
+                               pack_open_fds--;
+                               p->pack_fd = -1;
+                       }
                        pack_mmap_calls++;
                        pack_open_windows++;
                        if (pack_mapped > peak_pack_mapped)
@@ -883,6 +955,9 @@ struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path)
 
 void install_packed_git(struct packed_git *pack)
 {
+       if (pack->pack_fd != -1)
+               pack_open_fds++;
+
        pack->next = packed_git;
        packed_git = pack;
 }
@@ -900,8 +975,6 @@ static void prepare_packed_git_one(char *objdir, int local)
        sprintf(path, "%s/pack", objdir);
        len = strlen(path);
        dir = opendir(path);
-       while (!dir && errno == EMFILE && unuse_one_window(NULL, -1))
-               dir = opendir(path);
        if (!dir) {
                if (errno != ENOENT)
                        error("unable to open object pack directory: %s: %s",
@@ -1057,14 +1130,6 @@ static int git_open_noatime(const char *name, struct packed_git *p)
                if (fd >= 0)
                        return fd;
 
-               /* Might the failure be insufficient file descriptors? */
-               if (errno == EMFILE) {
-                       if (unuse_one_window(p, -1))
-                               continue;
-                       else
-                               return -1;
-               }
-
                /* Might the failure be due to O_NOATIME? */
                if (errno != ENOENT && sha1_file_open_flag) {
                        sha1_file_open_flag = 0;
@@ -1896,6 +1961,27 @@ off_t find_pack_entry_one(const unsigned char *sha1,
        return 0;
 }
 
+static int is_pack_valid(struct packed_git *p)
+{
+       /* An already open pack is known to be valid. */
+       if (p->pack_fd != -1)
+               return 1;
+
+       /* If the pack has one window completely covering the
+        * file size, the pack is known to be valid even if
+        * the descriptor is not currently open.
+        */
+       if (p->windows) {
+               struct pack_window *w = p->windows;
+
+               if (!w->offset && w->len == p->pack_size)
+                       return 1;
+       }
+
+       /* Force the pack to open to prove its valid. */
+       return !open_packed_git(p);
+}
+
 static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
 {
        static struct packed_git *last_found = (void *)1;
@@ -1925,7 +2011,7 @@ static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e)
                         * it may have been deleted since the index
                         * was loaded!
                         */
-                       if (p->pack_fd == -1 && open_packed_git(p)) {
+                       if (!is_pack_valid(p)) {
                                error("packfile %s cannot be accessed", p->pack_name);
                                goto next;
                        }
@@ -1985,9 +2071,17 @@ static int sha1_loose_object_info(const unsigned char *sha1, unsigned long *size
 
 int sha1_object_info(const unsigned char *sha1, unsigned long *sizep)
 {
+       struct cached_object *co;
        struct pack_entry e;
        int status;
 
+       co = find_cached_object(sha1);
+       if (co) {
+               if (sizep)
+                       *sizep = co->size;
+               return co->type;
+       }
+
        if (!find_pack_entry(sha1, &e)) {
                /* Most likely it's a loose object. */
                status = sha1_loose_object_info(sha1, sizep);
@@ -2033,41 +2127,6 @@ static void *read_packed_sha1(const unsigned char *sha1,
        return data;
 }
 
-/*
- * This is meant to hold a *small* number of objects that you would
- * want read_sha1_file() to be able to return, but yet you do not want
- * to write them into the object store (e.g. a browse-only
- * application).
- */
-static struct cached_object {
-       unsigned char sha1[20];
-       enum object_type type;
-       void *buf;
-       unsigned long size;
-} *cached_objects;
-static int cached_object_nr, cached_object_alloc;
-
-static struct cached_object empty_tree = {
-       EMPTY_TREE_SHA1_BIN,
-       OBJ_TREE,
-       "",
-       0
-};
-
-static struct cached_object *find_cached_object(const unsigned char *sha1)
-{
-       int i;
-       struct cached_object *co = cached_objects;
-
-       for (i = 0; i < cached_object_nr; i++, co++) {
-               if (!hashcmp(co->sha1, sha1))
-                       return co;
-       }
-       if (!hashcmp(sha1, empty_tree.sha1))
-               return &empty_tree;
-       return NULL;
-}
-
 int pretend_sha1_file(void *buf, unsigned long len, enum object_type type,
                      unsigned char *sha1)
 {
@@ -2351,8 +2410,6 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
 
        filename = sha1_file_name(sha1);
        fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename);
-       while (fd < 0 && errno == EMFILE && unuse_one_window(NULL, -1))
-               fd = create_tmpfile(tmpfile, sizeof(tmpfile), filename);
        if (fd < 0) {
                if (errno == EACCES)
                        return error("insufficient permission for adding an object to repository database %s\n", get_object_directory());
@@ -2471,8 +2528,37 @@ int has_sha1_file(const unsigned char *sha1)
        return has_loose_object(sha1);
 }
 
+static void check_tree(const void *buf, size_t size)
+{
+       struct tree_desc desc;
+       struct name_entry entry;
+
+       init_tree_desc(&desc, buf, size);
+       while (tree_entry(&desc, &entry))
+               /* do nothing
+                * tree_entry() will die() on malformed entries */
+               ;
+}
+
+static void check_commit(const void *buf, size_t size)
+{
+       struct commit c;
+       memset(&c, 0, sizeof(c));
+       if (parse_commit_buffer(&c, buf, size))
+               die("corrupt commit");
+}
+
+static void check_tag(const void *buf, size_t size)
+{
+       struct tag t;
+       memset(&t, 0, sizeof(t));
+       if (parse_tag_buffer(&t, buf, size))
+               die("corrupt tag");
+}
+
 static int index_mem(unsigned char *sha1, void *buf, size_t size,
-                    int write_object, enum object_type type, const char *path)
+                    int write_object, enum object_type type,
+                    const char *path, int format_check)
 {
        int ret, re_allocated = 0;
 
@@ -2490,6 +2576,14 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size,
                        re_allocated = 1;
                }
        }
+       if (format_check) {
+               if (type == OBJ_TREE)
+                       check_tree(buf, size);
+               if (type == OBJ_COMMIT)
+                       check_commit(buf, size);
+               if (type == OBJ_TAG)
+                       check_tag(buf, size);
+       }
 
        if (write_object)
                ret = write_sha1_file(buf, size, typename(type), sha1);
@@ -2503,7 +2597,7 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size,
 #define SMALL_FILE_SIZE (32*1024)
 
 int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
-            enum object_type type, const char *path)
+            enum object_type type, const char *path, int format_check)
 {
        int ret;
        size_t size = xsize_t(st->st_size);
@@ -2512,23 +2606,25 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
                struct strbuf sbuf = STRBUF_INIT;
                if (strbuf_read(&sbuf, fd, 4096) >= 0)
                        ret = index_mem(sha1, sbuf.buf, sbuf.len, write_object,
-                                       type, path);
+                                       type, path, format_check);
                else
                        ret = -1;
                strbuf_release(&sbuf);
        } else if (!size) {
-               ret = index_mem(sha1, NULL, size, write_object, type, path);
+               ret = index_mem(sha1, NULL, size, write_object, type, path,
+                               format_check);
        } else if (size <= SMALL_FILE_SIZE) {
                char *buf = xmalloc(size);
                if (size == read_in_full(fd, buf, size))
                        ret = index_mem(sha1, buf, size, write_object, type,
-                                       path);
+                                       path, format_check);
                else
                        ret = error("short read %s", strerror(errno));
                free(buf);
        } else {
                void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
-               ret = index_mem(sha1, buf, size, write_object, type, path);
+               ret = index_mem(sha1, buf, size, write_object, type, path,
+                               format_check);
                munmap(buf, size);
        }
        close(fd);
@@ -2546,7 +2642,7 @@ int index_path(unsigned char *sha1, const char *path, struct stat *st, int write
                if (fd < 0)
                        return error("open(\"%s\"): %s", path,
                                     strerror(errno));
-               if (index_fd(sha1, fd, st, write_object, OBJ_BLOB, path) < 0)
+               if (index_fd(sha1, fd, st, write_object, OBJ_BLOB, path, 0) < 0)
                        return error("%s: failed to insert into database",
                                     path);
                break;
index 709ff2eee64cf106191ad274bede82a95d00e2a3..faea58dc8c27de23e8fbaff17b39cb9e57708510 100644 (file)
@@ -208,9 +208,7 @@ const char *find_unique_abbrev(const unsigned char *sha1, int len)
                if (exists
                    ? !status
                    : status == SHORT_NAME_NOT_FOUND) {
-                       int cut_at = len + unique_abbrev_extra_length;
-                       cut_at = (cut_at < 40) ? cut_at : 40;
-                       hex[cut_at] = 0;
+                       hex[len] = 0;
                        return hex;
                }
                len++;
index 9b3c4457f229041784edfa65218aa09de7a5eff8..77444a94df3d4a0cda6403957fd13ea262d3ab24 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -63,7 +63,8 @@ void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc)
 
 void strbuf_grow(struct strbuf *sb, size_t extra)
 {
-       if (sb->len + extra + 1 <= sb->len)
+       if (unsigned_add_overflows(extra, 1) ||
+           unsigned_add_overflows(sb->len, extra + 1))
                die("you want to use way too much memory");
        if (!sb->alloc)
                sb->buf = NULL;
@@ -152,7 +153,7 @@ int strbuf_cmp(const struct strbuf *a, const struct strbuf *b)
 void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,
                                   const void *data, size_t dlen)
 {
-       if (pos + len < pos)
+       if (unsigned_add_overflows(pos, len))
                die("you want to use way too much memory");
        if (pos > sb->len)
                die("`pos' is too far after the end of the buffer");
@@ -194,24 +195,29 @@ void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
 
 void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
 {
-       int len;
        va_list ap;
+       va_start(ap, fmt);
+       strbuf_vaddf(sb, fmt, ap);
+       va_end(ap);
+}
+
+void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap)
+{
+       int len;
+       va_list cp;
 
        if (!strbuf_avail(sb))
                strbuf_grow(sb, 64);
-       va_start(ap, fmt);
-       len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
-       va_end(ap);
+       va_copy(cp, ap);
+       len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, cp);
+       va_end(cp);
        if (len < 0)
-               die("your vsnprintf is broken");
+               die("BUG: your vsnprintf is broken (returned %d)", len);
        if (len > strbuf_avail(sb)) {
                strbuf_grow(sb, len);
-               va_start(ap, fmt);
                len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
-               va_end(ap);
-               if (len > strbuf_avail(sb)) {
-                       die("this should not happen, your snprintf is broken");
-               }
+               if (len > strbuf_avail(sb))
+                       die("BUG: your vsnprintf is broken (insatiable)");
        }
        strbuf_setlen(sb, sb->len + len);
 }
index 675a91f93821421aa79de51857b22a4960da8ec1..f722331470065f448197ea461ef3af06d3623ff2 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
@@ -120,6 +120,8 @@ extern void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *
 
 __attribute__((format (printf,2,3)))
 extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
+__attribute__((format (printf,2,0)))
+extern void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);
 
 extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
 /* XXX: if read fails, any partial read is undone */
index 9b023a25841cb7a9c1faecc30c484eba0e16d6af..51681189e8380cc43ed26d35526a6dff78f1a24c 100644 (file)
@@ -153,6 +153,7 @@ struct string_list_item *string_list_append(struct string_list *list, const char
        ALLOC_GROW(list->items, list->nr + 1, list->alloc);
        list->items[list->nr].string =
                list->strdup_strings ? xstrdup(string) : (char *)string;
+       list->items[list->nr].util = NULL;
        return list->items + list->nr++;
 }
 
index 494693898b89fe2f8145b483ea7e366e9b1192c1..bda69839832d2030c15bbd86c4d8d79aa3cc4785 100644 (file)
@@ -5,8 +5,7 @@ struct string_list_item {
        char *string;
        void *util;
 };
-struct string_list
-{
+struct string_list {
        struct string_list_item *items;
        unsigned int nr, alloc;
        unsigned int strdup_strings:1;
index 6f1c10722f744f4a27f18dae4867b15ecbf57d49..0cb6d1829944b8a6d0f1a7ed1c228b61c31c7e0d 100644 (file)
@@ -9,9 +9,9 @@
 #include "refs.h"
 #include "string-list.h"
 
-struct string_list config_name_for_path;
-struct string_list config_fetch_recurse_submodules_for_name;
-struct string_list config_ignore_for_name;
+static struct string_list config_name_for_path;
+static struct string_list config_fetch_recurse_submodules_for_name;
+static struct string_list config_ignore_for_name;
 static int config_fetch_recurse_submodules;
 
 static int add_submodule_odb(const char *path)
@@ -152,17 +152,69 @@ void handle_ignore_submodules_arg(struct diff_options *diffopt,
                die("bad --ignore-submodules argument: %s", arg);
 }
 
+static int prepare_submodule_summary(struct rev_info *rev, const char *path,
+               struct commit *left, struct commit *right,
+               int *fast_forward, int *fast_backward)
+{
+       struct commit_list *merge_bases, *list;
+
+       init_revisions(rev, NULL);
+       setup_revisions(0, NULL, rev, NULL);
+       rev->left_right = 1;
+       rev->first_parent_only = 1;
+       left->object.flags |= SYMMETRIC_LEFT;
+       add_pending_object(rev, &left->object, path);
+       add_pending_object(rev, &right->object, path);
+       merge_bases = get_merge_bases(left, right, 1);
+       if (merge_bases) {
+               if (merge_bases->item == left)
+                       *fast_forward = 1;
+               else if (merge_bases->item == right)
+                       *fast_backward = 1;
+       }
+       for (list = merge_bases; list; list = list->next) {
+               list->item->object.flags |= UNINTERESTING;
+               add_pending_object(rev, &list->item->object,
+                       sha1_to_hex(list->item->object.sha1));
+       }
+       return prepare_revision_walk(rev);
+}
+
+static void print_submodule_summary(struct rev_info *rev, FILE *f,
+               const char *del, const char *add, const char *reset)
+{
+       static const char format[] = "  %m %s";
+       struct strbuf sb = STRBUF_INIT;
+       struct commit *commit;
+
+       while ((commit = get_revision(rev))) {
+               struct pretty_print_context ctx = {0};
+               ctx.date_mode = rev->date_mode;
+               strbuf_setlen(&sb, 0);
+               if (commit->object.flags & SYMMETRIC_LEFT) {
+                       if (del)
+                               strbuf_addstr(&sb, del);
+               }
+               else if (add)
+                       strbuf_addstr(&sb, add);
+               format_commit_message(commit, format, &sb, &ctx);
+               if (reset)
+                       strbuf_addstr(&sb, reset);
+               strbuf_addch(&sb, '\n');
+               fprintf(f, "%s", sb.buf);
+       }
+       strbuf_release(&sb);
+}
+
 void show_submodule_summary(FILE *f, const char *path,
                unsigned char one[20], unsigned char two[20],
                unsigned dirty_submodule,
                const char *del, const char *add, const char *reset)
 {
        struct rev_info rev;
-       struct commit *commit, *left = left, *right = right;
-       struct commit_list *merge_bases, *list;
+       struct commit *left = left, *right = right;
        const char *message = NULL;
        struct strbuf sb = STRBUF_INIT;
-       static const char *format = "  %m %s";
        int fast_forward = 0, fast_backward = 0;
 
        if (is_null_sha1(two))
@@ -175,29 +227,10 @@ void show_submodule_summary(FILE *f, const char *path,
                 !(right = lookup_commit_reference(two)))
                message = "(commits not present)";
 
-       if (!message) {
-               init_revisions(&rev, NULL);
-               setup_revisions(0, NULL, &rev, NULL);
-               rev.left_right = 1;
-               rev.first_parent_only = 1;
-               left->object.flags |= SYMMETRIC_LEFT;
-               add_pending_object(&rev, &left->object, path);
-               add_pending_object(&rev, &right->object, path);
-               merge_bases = get_merge_bases(left, right, 1);
-               if (merge_bases) {
-                       if (merge_bases->item == left)
-                               fast_forward = 1;
-                       else if (merge_bases->item == right)
-                               fast_backward = 1;
-               }
-               for (list = merge_bases; list; list = list->next) {
-                       list->item->object.flags |= UNINTERESTING;
-                       add_pending_object(&rev, &list->item->object,
-                               sha1_to_hex(list->item->object.sha1));
-               }
-               if (prepare_revision_walk(&rev))
-                       message = "(revision walker failed)";
-       }
+       if (!message &&
+           prepare_submodule_summary(&rev, path, left, right,
+                                       &fast_forward, &fast_backward))
+               message = "(revision walker failed)";
 
        if (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)
                fprintf(f, "Submodule %s contains untracked content\n", path);
@@ -221,25 +254,11 @@ void show_submodule_summary(FILE *f, const char *path,
        fwrite(sb.buf, sb.len, 1, f);
 
        if (!message) {
-               while ((commit = get_revision(&rev))) {
-                       struct pretty_print_context ctx = {0};
-                       ctx.date_mode = rev.date_mode;
-                       strbuf_setlen(&sb, 0);
-                       if (commit->object.flags & SYMMETRIC_LEFT) {
-                               if (del)
-                                       strbuf_addstr(&sb, del);
-                       }
-                       else if (add)
-                               strbuf_addstr(&sb, add);
-                       format_commit_message(commit, format, &sb, &ctx);
-                       if (reset)
-                               strbuf_addstr(&sb, reset);
-                       strbuf_addch(&sb, '\n');
-                       fprintf(f, "%s", sb.buf);
-               }
+               print_submodule_summary(&rev, f, del, add, reset);
                clear_commit_marks(left, ~0);
                clear_commit_marks(right, ~0);
        }
+
        strbuf_release(&sb);
 }
 
index 3cacebd91adc2958e81d952523bd7cfe0078078c..034943bda0e8be781f4a7568f0dbb5b1958f7e15 100644 (file)
@@ -223,7 +223,7 @@ int check_leading_path(const char *name, int len)
        int flags;
        int match_len = lstat_cache_matchlen(cache, name, len, &flags,
                           FL_SYMLINK|FL_NOENT|FL_DIR, USE_ONLY_LSTAT);
-       if (flags & (FL_SYMLINK|FL_NOENT))
+       if (flags & FL_NOENT)
                return 0;
        else if (flags & FL_DIR)
                return -1;
index 25f7d2d2e3cf70d54f5b854ad4199c831a74ae2a..ccf6a53377804153f7a516031d5bab4ef6da4016 100644 (file)
--- a/t/README
+++ b/t/README
@@ -79,6 +79,10 @@ appropriately before running "make".
 --debug::
        This may help the person who is developing a new test.
        It causes the command defined with test_debug to run.
+       The "trash" directory (used to store all temporary data
+       during testing) is not deleted even if there are no
+       failed tests so that you can inspect its contents after
+       the test finished.
 
 --immediate::
        This causes the test to immediately exit upon the first
@@ -98,6 +102,13 @@ appropriately before running "make".
        not see any output, this option implies --verbose.  For
        convenience, it also implies --tee.
 
+       Note that valgrind is run with the option --leak-check=no,
+       as the git process is short-lived and some errors are not
+       interesting. In order to run a single command under the same
+       conditions manually, you should set GIT_VALGRIND to point to
+       the 't/valgrind/' directory and use the commands under
+       't/valgrind/bin/'.
+
 --tee::
        In addition to printing the test output to the terminal,
        write it to files named 't/test-results/$TEST_NAME.out'.
@@ -328,7 +339,7 @@ Keep in mind:
 Skipping tests
 --------------
 
-If you need to skip tests you should do so be using the three-arg form
+If you need to skip tests you should do so by using the three-arg form
 of the test_* functions (see the "Test harness library" section
 below), e.g.:
 
index b9bb95feaa5088254b002c2806c2c2ae9e9d7be4..143eb1f24092df070c5ddf75340bebb319a0c746 100644 (file)
@@ -82,7 +82,12 @@ gitweb_run () {
                }
                close O;
        ' gitweb.output &&
-       if grep '^[[]' gitweb.log >/dev/null 2>&1; then false; else true; fi
+       if grep '^[[]' gitweb.log >/dev/null 2>&1; then
+               test_debug 'cat gitweb.log >&2' &&
+               false
+       else
+               true
+       fi
 
        # gitweb.log is left for debugging
        # gitweb.output is used to parse HTTP output
index c383b57ed9d995f530004923962c45ab38c7fc8b..58d911d21b894ba05e878e6efbc234071795c600 100644 (file)
@@ -1,8 +1,24 @@
 #!/bin/sh
 
-test_expect_success 'set up terminal for tests' '
-       if
-               test_have_prereq PERL &&
+test_expect_success PERL 'set up terminal for tests' '
+       # Reading from the pty master seems to get stuck _sometimes_
+       # on Mac OS X 10.5.0, using Perl 5.10.0 or 5.8.9.
+       #
+       # Reproduction recipe: run
+       #
+       #       i=0
+       #       while ./test-terminal.perl echo hi $i
+       #       do
+       #               : $((i = $i + 1))
+       #       done
+       #
+       # After 2000 iterations or so it hangs.
+       # https://rt.cpan.org/Ticket/Display.html?id=65692
+       #
+       if test "$(uname -s)" = Darwin
+       then
+               :
+       elif
                "$PERL_PATH" "$TEST_DIRECTORY"/test-terminal.perl \
                        sh -c "test -t 1 && test -t 2"
        then
index 8deec75c3a0eef961986a0bb313a918ab532f58d..f4e8f43bae5d1929718578a2a589125beb5d30c8 100755 (executable)
@@ -435,7 +435,7 @@ test_expect_success 'update-index D/F conflict' '
        test $numpath0 = 1
 '
 
-test_expect_success SYMLINKS 'absolute path works as expected' '
+test_expect_success SYMLINKS 'real path works as expected' '
        mkdir first &&
        ln -s ../.git first/.git &&
        mkdir second &&
@@ -443,14 +443,14 @@ test_expect_success SYMLINKS 'absolute path works as expected' '
        mkdir third &&
        dir="$(cd .git; pwd -P)" &&
        dir2=third/../second/other/.git &&
-       test "$dir" = "$(test-path-utils make_absolute_path $dir2)" &&
+       test "$dir" = "$(test-path-utils real_path $dir2)" &&
        file="$dir"/index &&
-       test "$file" = "$(test-path-utils make_absolute_path $dir2/index)" &&
+       test "$file" = "$(test-path-utils real_path $dir2/index)" &&
        basename=blub &&
-       test "$dir/$basename" = "$(cd .git && test-path-utils make_absolute_path "$basename")" &&
+       test "$dir/$basename" = "$(cd .git && test-path-utils real_path "$basename")" &&
        ln -s ../first/file .git/syml &&
        sym="$(cd first; pwd -P)"/file &&
-       test "$sym" = "$(test-path-utils make_absolute_path "$dir2/syml")"
+       test "$sym" = "$(test-path-utils real_path "$dir2/syml")"
 '
 
 test_expect_success 'very long name in the index handled sanely' '
index f6849932112f1bbea1dafad09150857a707b64e4..ce4ba1379ef05066cc697cdc7fdf53f8c40f58ee 100755 (executable)
@@ -47,7 +47,7 @@ test_expect_success 'plain nested in bare' '
 
 test_expect_success 'plain through aliased command, outside any git repo' '
        (
-               sane_unset GIT_DIR GIT_WORK_TREE GIT_CONFIG_NOGLOBAL &&
+               sane_unset GIT_DIR GIT_WORK_TREE &&
                HOME=$(pwd)/alias-config &&
                export HOME &&
                mkdir alias-config &&
@@ -231,7 +231,6 @@ test_expect_success 'init with init.templatedir set' '
                git config -f "$test_config"  init.templatedir "${HOME}/templatedir-source" &&
                mkdir templatedir-set &&
                cd templatedir-set &&
-               sane_unset GIT_CONFIG_NOGLOBAL &&
                sane_unset GIT_TEMPLATE_DIR &&
                NO_SET_GIT_TEMPLATE_DIR=t &&
                export NO_SET_GIT_TEMPLATE_DIR &&
@@ -243,7 +242,6 @@ test_expect_success 'init with init.templatedir set' '
 test_expect_success 'init --bare/--shared overrides system/global config' '
        (
                test_config="$HOME"/.gitconfig &&
-               sane_unset GIT_CONFIG_NOGLOBAL &&
                git config -f "$test_config" core.bare false &&
                git config -f "$test_config" core.sharedRepository 0640 &&
                mkdir init-bare-shared-override &&
@@ -258,7 +256,6 @@ test_expect_success 'init --bare/--shared overrides system/global config' '
 test_expect_success 'init honors global core.sharedRepository' '
        (
                test_config="$HOME"/.gitconfig &&
-               sane_unset GIT_CONFIG_NOGLOBAL &&
                git config -f "$test_config" core.sharedRepository 0666 &&
                mkdir shared-honor-global &&
                cd shared-honor-global &&
index 20924506af886c8d0ce28f3fcb2742214d80020f..ae266147b6db9e06abeb4dc30e4271b6c611deac 100755 (executable)
@@ -19,7 +19,7 @@ usage: test-parse-options <options>
     --set23               set integer to 23
     -t <time>             get timestamp of <time>
     -L, --length <str>    get length of <str>
-    -F, --file <FILE>     set file to <FILE>
+    -F, --file <file>     set file to <file>
 
 String options
     -s, --string <string>
index 680d7d68612b168a2642ab64e7bc6c15c316d5b4..9bee8bfd2e063c40bae2d76930370bd9e8ba8fa5 100755 (executable)
@@ -12,4 +12,17 @@ test_expect_success 'character classes (isspace, isalpha etc.)' '
        test-ctype
 '
 
+test_expect_success 'mktemp to nonexistent directory prints filename' '
+       test_must_fail test-mktemp doesnotexist/testXXXXXX 2>err &&
+       grep "doesnotexist/test" err
+'
+
+test_expect_success POSIXPERM 'mktemp to unwritable directory prints filename' '
+       mkdir cannotwrite &&
+       chmod -w cannotwrite &&
+       test_when_finished "chmod +w cannotwrite" &&
+       test_must_fail test-mktemp cannotwrite/testXXXXXX 2>err &&
+       grep "cannotwrite/test" err
+'
+
 test_done
index d3225ada681d205f43914a6b59f4bdf4f2263451..99a314b08078960b8736ce94890e805943e4f970 100755 (executable)
@@ -76,60 +76,6 @@ test_expect_success 'obj pool: high-water mark' '
        test_cmp expected actual
 '
 
-test_expect_success 'line buffer' '
-       echo HELLO >expected1 &&
-       printf "%s\n" "" HELLO >expected2 &&
-       echo >expected3 &&
-       printf "%s\n" "" Q | q_to_nul >expected4 &&
-       printf "%s\n" foo "" >expected5 &&
-       printf "%s\n" "" foo >expected6 &&
-
-       test-line-buffer <<-\EOF >actual1 &&
-       5
-       HELLO
-       EOF
-
-       test-line-buffer <<-\EOF >actual2 &&
-       0
-
-       5
-       HELLO
-       EOF
-
-       q_to_nul <<-\EOF |
-       1
-       Q
-       EOF
-       test-line-buffer >actual3 &&
-
-       q_to_nul <<-\EOF |
-       0
-
-       1
-       Q
-       EOF
-       test-line-buffer >actual4 &&
-
-       test-line-buffer <<-\EOF >actual5 &&
-       5
-       foo
-       EOF
-
-       test-line-buffer <<-\EOF >actual6 &&
-       0
-
-       5
-       foo
-       EOF
-
-       test_cmp expected1 actual1 &&
-       test_cmp expected2 actual2 &&
-       test_cmp expected3 actual3 &&
-       test_cmp expected4 actual4 &&
-       test_cmp expected5 actual5 &&
-       test_cmp expected6 actual6
-'
-
 test_expect_success 'string pool' '
        echo a does not equal b >expected.differ &&
        echo a equals a >expected.match &&
diff --git a/t/t0081-line-buffer.sh b/t/t0081-line-buffer.sh
new file mode 100755 (executable)
index 0000000..550fad0
--- /dev/null
@@ -0,0 +1,201 @@
+#!/bin/sh
+
+test_description="Test the svn importer's input handling routines.
+
+These tests exercise the line_buffer library, but their real purpose
+is to check the assumptions that library makes of the platform's input
+routines.  Processes engaged in bi-directional communication would
+hang if fread or fgets is too greedy.
+
+While at it, check that input of newlines and null bytes are handled
+correctly.
+"
+. ./test-lib.sh
+
+test -n "$GIT_REMOTE_SVN_TEST_BIG_FILES" && test_set_prereq EXPENSIVE
+
+generate_tens_of_lines () {
+       tens=$1 &&
+       line=$2 &&
+
+       i=0 &&
+       while test $i -lt "$tens"
+       do
+               for j in a b c d e f g h i j
+               do
+                       echo "$line"
+               done &&
+               : $((i = $i + 1)) ||
+               return
+       done
+}
+
+long_read_test () {
+       : each line is 10 bytes, including newline &&
+       line=abcdefghi &&
+       echo "$line" >expect &&
+
+       if ! test_declared_prereq PIPE
+       then
+               echo >&4 "long_read_test: need to declare PIPE prerequisite"
+               return 127
+       fi &&
+       tens_of_lines=$(($1 / 100 + 1)) &&
+       lines=$(($tens_of_lines * 10)) &&
+       readsize=$((($lines - 1) * 10 + 3)) &&
+       copysize=7 &&
+       rm -f input &&
+       mkfifo input &&
+       {
+               {
+                       generate_tens_of_lines $tens_of_lines "$line" &&
+                       sleep 100
+               } >input &
+       } &&
+       test-line-buffer input <<-EOF >output &&
+       read $readsize
+       copy $copysize
+       EOF
+       kill $! &&
+       test_line_count = $lines output &&
+       tail -n 1 <output >actual &&
+       test_cmp expect actual
+}
+
+test_expect_success 'setup: have pipes?' '
+      rm -f frob &&
+      if mkfifo frob
+      then
+               test_set_prereq PIPE
+      fi
+'
+
+test_expect_success 'hello world' '
+       echo HELLO >expect &&
+       test-line-buffer <<-\EOF >actual &&
+       read 6
+       HELLO
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success PIPE '0-length read, no input available' '
+       >expect &&
+       rm -f input &&
+       mkfifo input &&
+       {
+               sleep 100 >input &
+       } &&
+       test-line-buffer input <<-\EOF >actual &&
+       read 0
+       copy 0
+       EOF
+       kill $! &&
+       test_cmp expect actual
+'
+
+test_expect_success '0-length read, send along greeting' '
+       echo HELLO >expect &&
+       test-line-buffer <<-\EOF >actual &&
+       read 0
+       copy 6
+       HELLO
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success PIPE '1-byte read, no input available' '
+       printf "%s" ab >expect &&
+       rm -f input &&
+       mkfifo input &&
+       {
+               {
+                       printf "%s" a &&
+                       printf "%s" b &&
+                       sleep 100
+               } >input &
+       } &&
+       test-line-buffer input <<-\EOF >actual &&
+       read 1
+       copy 1
+       EOF
+       kill $! &&
+       test_cmp expect actual
+'
+
+test_expect_success PIPE 'long read (around 8192 bytes)' '
+       long_read_test 8192
+'
+
+test_expect_success PIPE,EXPENSIVE 'longer read (around 65536 bytes)' '
+       long_read_test 65536
+'
+
+test_expect_success 'read from file descriptor' '
+       rm -f input &&
+       echo hello >expect &&
+       echo hello >input &&
+       echo copy 6 |
+       test-line-buffer "&4" 4<input >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'buffer_read_string copes with null byte' '
+       >expect &&
+       q_to_nul <<-\EOF | test-line-buffer >actual &&
+       read 2
+       Q
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'skip, copy null byte' '
+       echo Q | q_to_nul >expect &&
+       q_to_nul <<-\EOF | test-line-buffer >actual &&
+       skip 2
+       Q
+       copy 2
+       Q
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'read null byte' '
+       echo ">QhelloQ" | q_to_nul >expect &&
+       q_to_nul <<-\EOF | test-line-buffer >actual &&
+       binary 8
+       QhelloQ
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'long reads are truncated' '
+       echo foo >expect &&
+       test-line-buffer <<-\EOF >actual &&
+       read 5
+       foo
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'long copies are truncated' '
+       printf "%s\n" "" foo >expect &&
+       test-line-buffer <<-\EOF >actual &&
+       read 1
+
+       copy 5
+       foo
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'long binary reads are truncated' '
+       echo ">foo" >expect &&
+       test-line-buffer <<-\EOF >actual &&
+       binary 5
+       foo
+       EOF
+       test_cmp expect actual
+'
+
+test_done
index dd32432d626e4f3d192c2bbe4824772025bb08b1..6d52b824b115964c5551aaf4284205b98b885ce3 100755 (executable)
@@ -188,4 +188,17 @@ for args in "-w --stdin-paths" "--stdin-paths -w"; do
        pop_repo
 done
 
+test_expect_success 'corrupt tree' '
+       echo abc >malformed-tree
+       test_must_fail git hash-object -t tree malformed-tree
+'
+
+test_expect_success 'corrupt commit' '
+       test_must_fail git hash-object -t commit --stdin </dev/null
+'
+
+test_expect_success 'corrupt tag' '
+       test_must_fail git hash-object -t tag --stdin </dev/null
+'
+
 test_done
index d0e55465ff08698376f5d9fa86357d51bd57458c..53fb8228cf18e2b58f3ea63e98a0220fa0fd39f2 100755 (executable)
@@ -876,11 +876,25 @@ test_expect_success 'check split_cmdline return' "
        "
 
 test_expect_success 'git -c "key=value" support' '
-       test "z$(git -c name=value config name)" = zvalue &&
        test "z$(git -c core.name=value config core.name)" = zvalue &&
-       test "z$(git -c CamelCase=value config camelcase)" = zvalue &&
-       test "z$(git -c flag config --bool flag)" = ztrue &&
-       test_must_fail git -c core.name=value config name
+       test "z$(git -c foo.CamelCase=value config foo.camelcase)" = zvalue &&
+       test "z$(git -c foo.flag config --bool foo.flag)" = ztrue &&
+       test_must_fail git -c name=value config core.name
+'
+
+test_expect_success 'key sanity-checking' '
+       test_must_fail git config foo=bar &&
+       test_must_fail git config foo=.bar &&
+       test_must_fail git config foo.ba=r &&
+       test_must_fail git config foo.1bar &&
+       test_must_fail git config foo."ba
+                               z".bar &&
+       test_must_fail git config . false &&
+       test_must_fail git config .foo false &&
+       test_must_fail git config foo. false &&
+       test_must_fail git config .foo. false &&
+       git config foo.bar true &&
+       git config foo."ba =z".bar false
 '
 
 test_done
index 15101d5e032fbbef4a66039342d07afbc5203ee0..ec50a9ad70450cb80074a6002c66bf2efb8e7833 100755 (executable)
@@ -57,7 +57,7 @@ test_repo () {
                        export GIT_WORK_TREE
                fi &&
                rm -f trace &&
-               GIT_TRACE="$(pwd)/trace" git symbolic-ref HEAD >/dev/null &&
+               GIT_TRACE_SETUP="$(pwd)/trace" git symbolic-ref HEAD >/dev/null &&
                grep '^setup: ' trace >result &&
                test_cmp expected result
        )
diff --git a/t/t2019-checkout-ambiguous-ref.sh b/t/t2019-checkout-ambiguous-ref.sh
new file mode 100755 (executable)
index 0000000..943541d
--- /dev/null
@@ -0,0 +1,59 @@
+#!/bin/sh
+
+test_description='checkout handling of ambiguous (branch/tag) refs'
+. ./test-lib.sh
+
+test_expect_success 'setup ambiguous refs' '
+       test_commit branch file &&
+       git branch ambiguity &&
+       git branch vagueness &&
+       test_commit tag file &&
+       git tag ambiguity &&
+       git tag vagueness HEAD:file &&
+       test_commit other file
+'
+
+test_expect_success 'checkout ambiguous ref succeeds' '
+       git checkout ambiguity >stdout 2>stderr
+'
+
+test_expect_success 'checkout produces ambiguity warning' '
+       grep "warning.*ambiguous" stderr
+'
+
+test_expect_success 'checkout chooses branch over tag' '
+       echo refs/heads/ambiguity >expect &&
+       git symbolic-ref HEAD >actual &&
+       test_cmp expect actual &&
+       echo branch >expect &&
+       test_cmp expect file
+'
+
+test_expect_success 'checkout reports switch to branch' '
+       grep "Switched to branch" stderr &&
+       ! grep "^HEAD is now at" stderr
+'
+
+test_expect_success 'checkout vague ref succeeds' '
+       git checkout vagueness >stdout 2>stderr &&
+       test_set_prereq VAGUENESS_SUCCESS
+'
+
+test_expect_success VAGUENESS_SUCCESS 'checkout produces ambiguity warning' '
+       grep "warning.*ambiguous" stderr
+'
+
+test_expect_success VAGUENESS_SUCCESS 'checkout chooses branch over tag' '
+       echo refs/heads/vagueness >expect &&
+       git symbolic-ref HEAD >actual &&
+       test_cmp expect actual &&
+       echo branch >expect &&
+       test_cmp expect file
+'
+
+test_expect_success VAGUENESS_SUCCESS 'checkout reports switch to branch' '
+       grep "Switched to branch" stderr &&
+       ! grep "^HEAD is now at" stderr
+'
+
+test_done
diff --git a/t/t2020-checkout-detach.sh b/t/t2020-checkout-detach.sh
new file mode 100755 (executable)
index 0000000..0042145
--- /dev/null
@@ -0,0 +1,95 @@
+#!/bin/sh
+
+test_description='checkout into detached HEAD state'
+. ./test-lib.sh
+
+check_detached () {
+       test_must_fail git symbolic-ref -q HEAD >/dev/null
+}
+
+check_not_detached () {
+       git symbolic-ref -q HEAD >/dev/null
+}
+
+reset () {
+       git checkout master &&
+       check_not_detached
+}
+
+test_expect_success 'setup' '
+       test_commit one &&
+       test_commit two &&
+       git branch branch &&
+       git tag tag
+'
+
+test_expect_success 'checkout branch does not detach' '
+       reset &&
+       git checkout branch &&
+       check_not_detached
+'
+
+test_expect_success 'checkout tag detaches' '
+       reset &&
+       git checkout tag &&
+       check_detached
+'
+
+test_expect_success 'checkout branch by full name detaches' '
+       reset &&
+       git checkout refs/heads/branch &&
+       check_detached
+'
+
+test_expect_success 'checkout non-ref detaches' '
+       reset &&
+       git checkout branch^ &&
+       check_detached
+'
+
+test_expect_success 'checkout ref^0 detaches' '
+       reset &&
+       git checkout branch^0 &&
+       check_detached
+'
+
+test_expect_success 'checkout --detach detaches' '
+       reset &&
+       git checkout --detach branch &&
+       check_detached
+'
+
+test_expect_success 'checkout --detach without branch name' '
+       reset &&
+       git checkout --detach &&
+       check_detached
+'
+
+test_expect_success 'checkout --detach errors out for non-commit' '
+       reset &&
+       test_must_fail git checkout --detach one^{tree} &&
+       check_not_detached
+'
+
+test_expect_success 'checkout --detach errors out for extra argument' '
+       reset &&
+       git checkout master &&
+       test_must_fail git checkout --detach tag one.t &&
+       check_not_detached
+'
+
+test_expect_success 'checkout --detached and -b are incompatible' '
+       reset &&
+       test_must_fail git checkout --detach -b newbranch tag &&
+       check_not_detached
+'
+
+test_expect_success 'checkout --detach moves HEAD' '
+       reset &&
+       git checkout one &&
+       git checkout --detach two &&
+       git diff --exit-code HEAD &&
+       git diff --exit-code two
+'
+
+test_done
diff --git a/t/t2021-checkout-overwrite.sh b/t/t2021-checkout-overwrite.sh
new file mode 100755 (executable)
index 0000000..27db2ad
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+test_description='checkout must not overwrite an untracked objects'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+
+       mkdir -p a/b/c &&
+       >a/b/c/d &&
+       git add -A &&
+       git commit -m base &&
+       git tag start
+'
+
+test_expect_success 'create a commit where dir a/b changed to file' '
+
+       git checkout -b file &&
+       rm -rf a/b &&
+       >a/b &&
+       git add -A &&
+       git commit -m "dir to file"
+'
+
+test_expect_success 'checkout commit with dir must not remove untracked a/b' '
+
+       git rm --cached a/b &&
+       git commit -m "un-track the file" &&
+       test_must_fail git checkout start &&
+       test -f a/b
+'
+
+test_expect_success SYMLINKS 'create a commit where dir a/b changed to symlink' '
+
+       rm -rf a/b &&   # cleanup if previous test failed
+       git checkout -f -b symlink start &&
+       rm -rf a/b &&
+       ln -s foo a/b &&
+       git add -A &&
+       git commit -m "dir to symlink"
+'
+
+test_expect_failure SYMLINKS 'checkout commit with dir must not remove untracked a/b' '
+
+       git rm --cached a/b &&
+       git commit -m "un-track the symlink" &&
+       test_must_fail git checkout start &&
+       test -h a/b
+'
+
+test_done
index 44f5421be45579b10c5556a958404ad2daa02002..2b17311cb0870ea210d9b5cbe167363d13641d67 100755 (executable)
@@ -110,6 +110,20 @@ test_expect_success '--ignore-space-change makes merge succeed' '
        git merge-recursive --ignore-space-change HEAD^ -- HEAD remote
 '
 
+test_expect_success 'naive cherry-pick fails' '
+       git read-tree --reset -u HEAD &&
+       test_must_fail git cherry-pick --no-commit remote &&
+       git read-tree --reset -u HEAD &&
+       test_must_fail git cherry-pick remote &&
+       test_must_fail git update-index --refresh &&
+       grep "<<<<<<" text.txt
+'
+
+test_expect_success '-Xignore-space-change makes cherry-pick succeed' '
+       git read-tree --reset -u HEAD &&
+       git cherry-pick --no-commit -Xignore-space-change remote
+'
+
 test_expect_success '--ignore-space-change: our w/s-only change wins' '
        q_to_cr <<-\EOF >expected &&
            justice and holiness and is the nurse of his age and theQ
index f308235f5dd28da2c19d91dc63803312aacd2cda..78ce09f9d788203ebea280cc94c8098c9043311f 100755 (executable)
@@ -223,6 +223,11 @@ test_expect_success \
     'branch from non-branch HEAD w/--track causes failure' \
     'test_must_fail git branch --track my10 HEAD^'
 
+test_expect_success \
+    'branch from tag w/--track causes failure' \
+    'git tag foobar &&
+     test_must_fail git branch --track my11 foobar'
+
 # Keep this test last, as it changes the current branch
 cat >expect <<EOF
 0000000000000000000000000000000000000000 $HEAD $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150200 +0000     branch: Created from master
@@ -488,6 +493,15 @@ test_expect_success 'autosetuprebase always on an untracked remote branch' '
        test "z$(git config branch.myr20.rebase)" = z
 '
 
+test_expect_success 'autosetuprebase always on detached HEAD' '
+       git config branch.autosetupmerge always &&
+       test_when_finished git checkout master &&
+       git checkout HEAD^0 &&
+       git branch my11 &&
+       test -z "$(git config branch.my11.remote)" &&
+       test -z "$(git config branch.my11.merge)"
+'
+
 test_expect_success 'detect misconfigured autosetuprebase (bad value)' '
        git config branch.autosetuprebase garbage &&
        test_must_fail git branch
index 607bf25d8ff7720407c2b15e4808c575b5f36093..95741801b0007b6ecbf22f665c4dcf3c744d5221 100755 (executable)
@@ -11,6 +11,18 @@ test_description='test cherry-pick and revert with conflicts
 
 . ./test-lib.sh
 
+test_cmp_rev () {
+       git rev-parse --verify "$1" >expect.rev &&
+       git rev-parse --verify "$2" >actual.rev &&
+       test_cmp expect.rev actual.rev
+}
+
+pristine_detach () {
+       git checkout -f "$1^0" &&
+       git read-tree -u --reset HEAD &&
+       git clean -d -f -f -q -x
+}
+
 test_expect_success setup '
 
        echo unrelated >unrelated &&
@@ -23,13 +35,7 @@ test_expect_success setup '
 '
 
 test_expect_success 'failed cherry-pick does not advance HEAD' '
-
-       git checkout -f initial^0 &&
-       git read-tree -u --reset HEAD &&
-       git clean -d -f -f -q -x &&
-
-       git update-index --refresh &&
-       git diff-index --exit-code HEAD &&
+       pristine_detach initial &&
 
        head=$(git rev-parse HEAD) &&
        test_must_fail git cherry-pick picked &&
@@ -39,33 +45,96 @@ test_expect_success 'failed cherry-pick does not advance HEAD' '
 '
 
 test_expect_success 'advice from failed cherry-pick' "
-       git checkout -f initial^0 &&
-       git read-tree -u --reset HEAD &&
-       git clean -d -f -f -q -x &&
-
-       git update-index --refresh &&
-       git diff-index --exit-code HEAD &&
+       pristine_detach initial &&
 
        picked=\$(git rev-parse --short picked) &&
        cat <<-EOF >expected &&
        error: could not apply \$picked... picked
        hint: after resolving the conflicts, mark the corrected paths
        hint: with 'git add <paths>' or 'git rm <paths>'
-       hint: and commit the result with 'git commit -c \$picked'
+       hint: and commit the result with 'git commit'
        EOF
        test_must_fail git cherry-pick picked 2>actual &&
 
        test_cmp expected actual
 "
 
-test_expect_success 'failed cherry-pick produces dirty index' '
+test_expect_success 'failed cherry-pick sets CHERRY_PICK_HEAD' '
+       pristine_detach initial &&
+       test_must_fail git cherry-pick picked &&
+       test_cmp_rev picked CHERRY_PICK_HEAD
+'
 
-       git checkout -f initial^0 &&
-       git read-tree -u --reset HEAD &&
-       git clean -d -f -f -q -x &&
+test_expect_success 'successful cherry-pick does not set CHERRY_PICK_HEAD' '
+       pristine_detach initial &&
+       git cherry-pick base &&
+       test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
+'
+
+test_expect_success 'cherry-pick --no-commit does not set CHERRY_PICK_HEAD' '
+       pristine_detach initial &&
+       git cherry-pick --no-commit base &&
+       test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
+'
+
+test_expect_success 'GIT_CHERRY_PICK_HELP suppresses CHERRY_PICK_HEAD' '
+       pristine_detach initial &&
+       (
+               GIT_CHERRY_PICK_HELP="and then do something else" &&
+               export GIT_CHERRY_PICK_HELP &&
+               test_must_fail git cherry-pick picked
+       ) &&
+       test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
+'
+
+test_expect_success 'git reset clears CHERRY_PICK_HEAD' '
+       pristine_detach initial &&
+
+       test_must_fail git cherry-pick picked &&
+       git reset &&
+
+       test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
+'
+
+test_expect_success 'failed commit does not clear CHERRY_PICK_HEAD' '
+       pristine_detach initial &&
+
+       test_must_fail git cherry-pick picked &&
+       test_must_fail git commit &&
+
+       test_cmp_rev picked CHERRY_PICK_HEAD
+'
+
+test_expect_success 'cancelled commit does not clear CHERRY_PICK_HEAD' '
+       pristine_detach initial &&
 
-       git update-index --refresh &&
-       git diff-index --exit-code HEAD &&
+       test_must_fail git cherry-pick picked &&
+       echo resolved >foo &&
+       git add foo &&
+       git update-index --refresh -q &&
+       test_must_fail git diff-index --exit-code HEAD &&
+       (
+               GIT_EDITOR=false &&
+               export GIT_EDITOR &&
+               test_must_fail git commit
+       ) &&
+
+       test_cmp_rev picked CHERRY_PICK_HEAD
+'
+
+test_expect_success 'successful commit clears CHERRY_PICK_HEAD' '
+       pristine_detach initial &&
+
+       test_must_fail git cherry-pick picked &&
+       echo resolved >foo &&
+       git add foo &&
+       git commit &&
+
+       test_must_fail git rev-parse --verify CHERRY_PICK_HEAD
+'
+
+test_expect_success 'failed cherry-pick produces dirty index' '
+       pristine_detach initial &&
 
        test_must_fail git cherry-pick picked &&
 
@@ -74,9 +143,7 @@ test_expect_success 'failed cherry-pick produces dirty index' '
 '
 
 test_expect_success 'failed cherry-pick registers participants in index' '
-
-       git read-tree -u --reset HEAD &&
-       git clean -d -f -f -q -x &&
+       pristine_detach initial &&
        {
                git checkout base -- foo &&
                git ls-files --stage foo &&
@@ -90,10 +157,7 @@ test_expect_success 'failed cherry-pick registers participants in index' '
                2 s/ 0  / 2     /
                3 s/ 0  / 3     /
        " < stages > expected &&
-       git checkout -f initial^0 &&
-
-       git update-index --refresh &&
-       git diff-index --exit-code HEAD &&
+       git read-tree -u --reset HEAD &&
 
        test_must_fail git cherry-pick picked &&
        git ls-files --stage --unmerged > actual &&
@@ -102,10 +166,7 @@ test_expect_success 'failed cherry-pick registers participants in index' '
 '
 
 test_expect_success 'failed cherry-pick describes conflict in work tree' '
-
-       git checkout -f initial^0 &&
-       git read-tree -u --reset HEAD &&
-       git clean -d -f -f -q -x &&
+       pristine_detach initial &&
        cat <<-EOF > expected &&
        <<<<<<< HEAD
        a
@@ -114,9 +175,6 @@ test_expect_success 'failed cherry-pick describes conflict in work tree' '
        >>>>>>> objid picked
        EOF
 
-       git update-index --refresh &&
-       git diff-index --exit-code HEAD &&
-
        test_must_fail git cherry-pick picked &&
 
        sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
@@ -124,11 +182,8 @@ test_expect_success 'failed cherry-pick describes conflict in work tree' '
 '
 
 test_expect_success 'diff3 -m style' '
-
+       pristine_detach initial &&
        git config merge.conflictstyle diff3 &&
-       git checkout -f initial^0 &&
-       git read-tree -u --reset HEAD &&
-       git clean -d -f -f -q -x &&
        cat <<-EOF > expected &&
        <<<<<<< HEAD
        a
@@ -139,9 +194,6 @@ test_expect_success 'diff3 -m style' '
        >>>>>>> objid picked
        EOF
 
-       git update-index --refresh &&
-       git diff-index --exit-code HEAD &&
-
        test_must_fail git cherry-pick picked &&
 
        sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
@@ -149,10 +201,8 @@ test_expect_success 'diff3 -m style' '
 '
 
 test_expect_success 'revert also handles conflicts sanely' '
-
        git config --unset merge.conflictstyle &&
-       git read-tree -u --reset HEAD &&
-       git clean -d -f -f -q -x &&
+       pristine_detach initial &&
        cat <<-EOF > expected &&
        <<<<<<< HEAD
        a
@@ -173,10 +223,7 @@ test_expect_success 'revert also handles conflicts sanely' '
                2 s/ 0  / 2     /
                3 s/ 0  / 3     /
        " < stages > expected-stages &&
-       git checkout -f initial^0 &&
-
-       git update-index --refresh &&
-       git diff-index --exit-code HEAD &&
+       git read-tree -u --reset HEAD &&
 
        head=$(git rev-parse HEAD) &&
        test_must_fail git revert picked &&
@@ -192,10 +239,8 @@ test_expect_success 'revert also handles conflicts sanely' '
 '
 
 test_expect_success 'revert conflict, diff3 -m style' '
+       pristine_detach initial &&
        git config merge.conflictstyle diff3 &&
-       git checkout -f initial^0 &&
-       git read-tree -u --reset HEAD &&
-       git clean -d -f -f -q -x &&
        cat <<-EOF > expected &&
        <<<<<<< HEAD
        a
@@ -206,9 +251,6 @@ test_expect_success 'revert conflict, diff3 -m style' '
        >>>>>>> parent of objid picked
        EOF
 
-       git update-index --refresh &&
-       git diff-index --exit-code HEAD &&
-
        test_must_fail git revert picked &&
 
        sed "s/[a-f0-9]*\.\.\./objid/" foo > actual &&
index 948ca1bce66cab317bf74984b22384f2625418c1..df921d1f33df34dd2b2631580f8d53b18270662a 100755 (executable)
@@ -3,12 +3,14 @@
 test_description='Test cherry-pick with directory/file conflicts'
 . ./test-lib.sh
 
-test_expect_success SYMLINKS 'Setup rename across paths each below D/F conflicts' '
+test_expect_success 'Initialize repository' '
        mkdir a &&
        >a/f &&
        git add a &&
-       git commit -m a &&
+       git commit -m a
+'
 
+test_expect_success SYMLINKS 'Setup rename across paths each below D/F conflicts' '
        mkdir b &&
        ln -s ../a b/a &&
        git add b &&
index 6fd560ccf10db5d016a4f1dde9e5eacca70e6f5b..f62aaf5816f6ecf4e2c4e8fe5ae60925e61ccfcd 100755 (executable)
@@ -556,4 +556,23 @@ test_expect_success 'stash branch should not drop the stash if the branch exists
        git rev-parse stash@{0} --
 '
 
+test_expect_success 'stash apply shows status same as git status (relative to current directory)' '
+       git stash clear &&
+       echo 1 >subdir/subfile1 &&
+       echo 2 >subdir/subfile2 &&
+       git add subdir/subfile1 &&
+       git commit -m subdir &&
+       (
+               cd subdir &&
+               echo x >subfile1 &&
+               echo x >../file &&
+               git status >../expect &&
+               git stash &&
+               sane_unset GIT_MERGE_VERBOSITY &&
+               git stash apply
+       ) |
+       sed -e 1,2d >actual && # drop "Saved..." and "HEAD is now..."
+       test_cmp expect actual
+'
+
 test_done
index c6130c40198ad5ed5ec8a0342341a4ec5cc49d7d..bfa88356382ab9f37e6e510516bf1fc6a3811961 100755 (executable)
@@ -29,7 +29,7 @@ test_expect_success \
 # copy-and-edit one, and rename-and-edit the other.  We do not say
 # anything about rezrov.
 
-GIT_DIFF_OPTS=--unified=0 git diff-index -M -p $tree >current
+GIT_DIFF_OPTS=--unified=0 git diff-index -C -p $tree >current
 cat >expected <<\EOF
 diff --git a/COPYING b/COPYING.1
 copy from COPYING
index 92a65f4852b8eca089fb9de617e0cdc8b55e1475..6e562c80d12f9f58353c8f6444c0d7a0737dbae4 100755 (executable)
@@ -35,7 +35,7 @@ test_expect_success SYMLINKS \
 # a new creation.
 
 test_expect_success SYMLINKS 'setup diff output' "
-    GIT_DIFF_OPTS=--unified=0 git diff-index -M -p $tree >current &&
+    GIT_DIFF_OPTS=--unified=0 git diff-index -C -p $tree >current &&
     cat >expected <<\EOF
 diff --git a/bozbar b/bozbar
 new file mode 120000
index 1ba359d478e3d3491aed5f622932382767c8f4dc..77d7f4946fb51a766399549e3c7364033d7668f0 100755 (executable)
@@ -29,7 +29,7 @@ test_expect_success \
 # and COPYING.2 are based on COPYING, and do not say anything about
 # rezrov.
 
-git diff-index -M $tree >current
+git diff-index -C $tree >current
 
 cat >expected <<\EOF
 :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 0603b3238a076dc6c8022aedc6648fa523a17178 C1234 COPYING COPYING.1
index d79d9e1e71ec38b4a82f1bf36dbbff5c3247a4d4..73b4a24f5ef676b8fa9fb3dc83183437710853c3 100755 (executable)
@@ -173,8 +173,8 @@ test_expect_success \
     'compare_diff_raw expected current'
 
 test_expect_success \
-    'run diff with -B -M' \
-    'git diff-index -B -M "$tree" >current'
+    'run diff with -B -C' \
+    'git diff-index -B -C "$tree" >current'
 
 cat >expected <<\EOF
 :100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 08bb2fb671deff4c03a4d4a0a1315dff98d5732c C095  file0   file1
index de3f17478efcaf008340a7ab81cb049f9a9e9a3a..f22c8e3dbaee8882160b6132160fcc3ccd7db057 100755 (executable)
@@ -29,7 +29,7 @@ test_expect_success \
 # and COPYING.2 are based on COPYING, and do not say anything about
 # rezrov.
 
-git diff-index -z -M $tree >current
+git diff-index -z -C $tree >current
 
 cat >expected <<\EOF
 :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 0603b3238a076dc6c8022aedc6648fa523a17178 C1234
index 94df7ae53a0ef47c0ef10ca6b3215ffdf38fa399..fbc8cd8f05f4debeb30b935c1b1db86e94e49f0e 100755 (executable)
@@ -70,4 +70,36 @@ test_expect_success 'diff-tree pathspec' '
        test_cmp expected current
 '
 
+EMPTY_TREE=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+
+test_expect_success 'diff-tree with wildcard shows dir also matches' '
+       git diff-tree --name-only $EMPTY_TREE $tree -- "f*" >result &&
+       echo file0 >expected &&
+       test_cmp expected result
+'
+
+test_expect_success 'diff-tree -r with wildcard' '
+       git diff-tree -r --name-only $EMPTY_TREE $tree -- "*file1" >result &&
+       echo path1/file1 >expected &&
+       test_cmp expected result
+'
+
+test_expect_success 'diff-tree with wildcard shows dir also matches' '
+       git diff-tree --name-only $tree $tree2 -- "path1/f*" >result &&
+       echo path1 >expected &&
+       test_cmp expected result
+'
+
+test_expect_success 'diff-tree -r with wildcard from beginning' '
+       git diff-tree -r --name-only $tree $tree2 -- "path1/*file1" >result &&
+       echo path1/file1 >expected &&
+       test_cmp expected result
+'
+
+test_expect_success 'diff-tree -r with wildcard' '
+       git diff-tree -r --name-only $tree $tree2 -- "path1/f*" >result &&
+       echo path1/file1 >expected &&
+       test_cmp expected result
+'
+
 test_done
index 9a665205884fcdb1c5888558d6edf960e335e013..5daa0f2a0c9c8cd6ed2c06e12c8fd421c178d4f0 100755 (executable)
@@ -210,6 +210,9 @@ log -m -p master
 log -SF master
 log -S F master
 log -SF -p master
+log -SF master --max-count=0
+log -SF master --max-count=1
+log -SF master --max-count=2
 log -GF master
 log -GF -p master
 log -GF -p --pickaxe-all master
@@ -290,4 +293,15 @@ test_expect_success 'log -S requires an argument' '
        test_must_fail git log -S
 '
 
+test_expect_success 'diff --cached on unborn branch' '
+       echo ref: refs/heads/unborn >.git/HEAD &&
+       git diff --cached >result &&
+       test_cmp "$TEST_DIRECTORY/t4013/diff.diff_--cached" result
+'
+
+test_expect_success 'diff --cached -- file on unborn branch' '
+       git diff --cached -- file0 >result &&
+       test_cmp "$TEST_DIRECTORY/t4013/diff.diff_--cached_--_file0" result
+'
+
 test_done
diff --git a/t/t4013/diff.diff_--cached b/t/t4013/diff.diff_--cached
new file mode 100644 (file)
index 0000000..ff16e83
--- /dev/null
@@ -0,0 +1,38 @@
+diff --git a/dir/sub b/dir/sub
+new file mode 100644
+index 0000000..992913c
+--- /dev/null
++++ b/dir/sub
+@@ -0,0 +1,8 @@
++A
++B
++C
++D
++E
++F
++1
++2
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..10a8a9f
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,9 @@
++1
++2
++3
++4
++5
++6
++A
++B
++C
+diff --git a/file1 b/file1
+new file mode 100644
+index 0000000..b1e6722
+--- /dev/null
++++ b/file1
+@@ -0,0 +1,3 @@
++A
++B
++C
diff --git a/t/t4013/diff.diff_--cached_--_file0 b/t/t4013/diff.diff_--cached_--_file0
new file mode 100644 (file)
index 0000000..b9bb858
--- /dev/null
@@ -0,0 +1,15 @@
+diff --git a/file0 b/file0
+new file mode 100644
+index 0000000..10a8a9f
+--- /dev/null
++++ b/file0
+@@ -0,0 +1,9 @@
++1
++2
++3
++4
++5
++6
++A
++B
++C
diff --git a/t/t4013/diff.log_-SF_master_--max-count=0 b/t/t4013/diff.log_-SF_master_--max-count=0
new file mode 100644 (file)
index 0000000..c1fc6c8
--- /dev/null
@@ -0,0 +1,2 @@
+$ git log -SF master --max-count=0
+$
diff --git a/t/t4013/diff.log_-SF_master_--max-count=1 b/t/t4013/diff.log_-SF_master_--max-count=1
new file mode 100644 (file)
index 0000000..c981a03
--- /dev/null
@@ -0,0 +1,7 @@
+$ git log -SF master --max-count=1
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+$
diff --git a/t/t4013/diff.log_-SF_master_--max-count=2 b/t/t4013/diff.log_-SF_master_--max-count=2
new file mode 100644 (file)
index 0000000..a6c55fd
--- /dev/null
@@ -0,0 +1,7 @@
+$ git log -SF master --max-count=2
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+$
index 027c13d52cd701ba28e3c5e29c5431acfccdad73..9c663677df0887cc09ce2c8277ec300e8de4eaaa 100755 (executable)
@@ -709,4 +709,88 @@ test_expect_success TTY 'format-patch --stdout paginates' '
        test_path_is_missing .git/pager_used
 '
 
+test_expect_success 'format-patch handles multi-line subjects' '
+       rm -rf patches/ &&
+       echo content >>file &&
+       for i in one two three; do echo $i; done >msg &&
+       git add file &&
+       git commit -F msg &&
+       git format-patch -o patches -1 &&
+       grep ^Subject: patches/0001-one.patch >actual &&
+       echo "Subject: [PATCH] one two three" >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'format-patch handles multi-line encoded subjects' '
+       rm -rf patches/ &&
+       echo content >>file &&
+       for i in en tvÃ¥ tre; do echo $i; done >msg &&
+       git add file &&
+       git commit -F msg &&
+       git format-patch -o patches -1 &&
+       grep ^Subject: patches/0001-en.patch >actual &&
+       echo "Subject: [PATCH] =?UTF-8?q?en=20tv=C3=A5=20tre?=" >expect &&
+       test_cmp expect actual
+'
+
+M8="foo bar "
+M64=$M8$M8$M8$M8$M8$M8$M8$M8
+M512=$M64$M64$M64$M64$M64$M64$M64$M64
+cat >expect <<'EOF'
+Subject: [PATCH] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
+ bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
+ foo bar foo bar foo bar foo bar
+EOF
+test_expect_success 'format-patch wraps extremely long headers (ascii)' '
+       echo content >>file &&
+       git add file &&
+       git commit -m "$M512" &&
+       git format-patch --stdout -1 >patch &&
+       sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
+       test_cmp expect subject
+'
+
+M8="föö bar "
+M64=$M8$M8$M8$M8$M8$M8$M8$M8
+M512=$M64$M64$M64$M64$M64$M64$M64$M64
+cat >expect <<'EOF'
+Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
+ =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
+EOF
+test_expect_success 'format-patch wraps extremely long headers (rfc2047)' '
+       rm -rf patches/ &&
+       echo content >>file &&
+       git add file &&
+       git commit -m "$M512" &&
+       git format-patch --stdout -1 >patch &&
+       sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
+       test_cmp expect subject
+'
+
 test_done
index 7e7b307a24606131b4880817a0056af11973f3d2..7d7470f21b66a937e7414f4fe5419f8830fd8e86 100755 (executable)
@@ -44,6 +44,13 @@ test_expect_success 'rewrite diff can show binary patch' '
        grep "GIT binary patch" diff
 '
 
+test_expect_success 'rewrite diff --stat shows binary changes' '
+       git diff -B --stat --summary >diff &&
+       grep "Bin" diff &&
+       grep "0 insertions.*0 deletions" diff &&
+       grep " rewrite file" diff
+'
+
 {
        echo "#!$SHELL_PATH"
        cat <<'EOF'
index 8096d8a337867b4afdc4b061fdc314fdd8eac185..37aeab0d5c7415a54384c90708626f6a5807acee 100755 (executable)
@@ -4,331 +4,307 @@ test_description='word diff colors'
 
 . ./test-lib.sh
 
-test_expect_success setup '
-
-       git config diff.color.old red &&
-       git config diff.color.new green &&
-       git config diff.color.func magenta
+cat >pre.simple <<-\EOF
+       h(4)
 
-'
+       a = b + c
+EOF
+cat >post.simple <<-\EOF
+       h(4),hh[44]
 
-word_diff () {
-       test_must_fail git diff --no-index "$@" pre post > output &&
-       test_decode_color <output >output.decrypted &&
-       test_cmp expect output.decrypted
-}
+       a = b + c
 
-cat > pre <<\EOF
-h(4)
+       aa = a
 
-a = b + c
+       aeff = aeff * ( aaa )
 EOF
+cat >expect.letter-runs-are-words <<-\EOF
+       <BOLD>diff --git a/pre b/post<RESET>
+       <BOLD>index 330b04f..5ed8eff 100644<RESET>
+       <BOLD>--- a/pre<RESET>
+       <BOLD>+++ b/post<RESET>
+       <CYAN>@@ -1,3 +1,7 @@<RESET>
+       h(4),<GREEN>hh<RESET>[44]
 
-cat > post <<\EOF
-h(4),hh[44]
-
-a = b + c
+       a = b + c<RESET>
 
-aa = a
+       <GREEN>aa = a<RESET>
 
-aeff = aeff * ( aaa )
+       <GREEN>aeff = aeff * ( aaa<RESET> )
 EOF
+cat >expect.non-whitespace-is-word <<-\EOF
+       <BOLD>diff --git a/pre b/post<RESET>
+       <BOLD>index 330b04f..5ed8eff 100644<RESET>
+       <BOLD>--- a/pre<RESET>
+       <BOLD>+++ b/post<RESET>
+       <CYAN>@@ -1,3 +1,7 @@<RESET>
+       h(4)<GREEN>,hh[44]<RESET>
 
-cat > expect <<\EOF
-<BOLD>diff --git a/pre b/post<RESET>
-<BOLD>index 330b04f..5ed8eff 100644<RESET>
-<BOLD>--- a/pre<RESET>
-<BOLD>+++ b/post<RESET>
-<CYAN>@@ -1,3 +1,7 @@<RESET>
-<RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET>
+       a = b + c<RESET>
 
-a = b + c<RESET>
+       <GREEN>aa = a<RESET>
 
-<GREEN>aa = a<RESET>
-
-<GREEN>aeff = aeff * ( aaa )<RESET>
+       <GREEN>aeff = aeff * ( aaa )<RESET>
 EOF
 
-test_expect_success 'word diff with runs of whitespace' '
+word_diff () {
+       test_must_fail git diff --no-index "$@" pre post >output &&
+       test_decode_color <output >output.decrypted &&
+       test_cmp expect output.decrypted
+}
 
-       word_diff --color-words
+test_language_driver () {
+       lang=$1
+       test_expect_success "diff driver '$lang'" '
+               cp "$TEST_DIRECTORY/t4034/'"$lang"'/pre" \
+                       "$TEST_DIRECTORY/t4034/'"$lang"'/post" \
+                       "$TEST_DIRECTORY/t4034/'"$lang"'/expect" . &&
+               echo "* diff='"$lang"'" >.gitattributes &&
+               word_diff --color-words
+       '
+}
 
+test_expect_success setup '
+       git config diff.color.old red &&
+       git config diff.color.new green &&
+       git config diff.color.func magenta
 '
 
-test_expect_success '--word-diff=color' '
-
-       word_diff --word-diff=color
-
+test_expect_success 'set up pre and post with runs of whitespace' '
+       cp pre.simple pre &&
+       cp post.simple post
 '
 
-test_expect_success '--color --word-diff=color' '
-
+test_expect_success 'word diff with runs of whitespace' '
+       cat >expect <<-\EOF &&
+               <BOLD>diff --git a/pre b/post<RESET>
+               <BOLD>index 330b04f..5ed8eff 100644<RESET>
+               <BOLD>--- a/pre<RESET>
+               <BOLD>+++ b/post<RESET>
+               <CYAN>@@ -1,3 +1,7 @@<RESET>
+               <RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET>
+
+               a = b + c<RESET>
+
+               <GREEN>aa = a<RESET>
+
+               <GREEN>aeff = aeff * ( aaa )<RESET>
+       EOF
+       word_diff --color-words &&
+       word_diff --word-diff=color &&
        word_diff --color --word-diff=color
-
 '
 
-sed 's/#.*$//' > expect <<EOF
-diff --git a/pre b/post
-index 330b04f..5ed8eff 100644
---- a/pre
-+++ b/post
-@@ -1,3 +1,7 @@
--h(4)
-+h(4),hh[44]
-~
- # significant space
-~
- a = b + c
-~
-~
-+aa = a
-~
-~
-+aeff = aeff * ( aaa )
-~
-EOF
-
 test_expect_success '--word-diff=porcelain' '
-
+       sed 's/#.*$//' >expect <<-\EOF &&
+               diff --git a/pre b/post
+               index 330b04f..5ed8eff 100644
+               --- a/pre
+               +++ b/post
+               @@ -1,3 +1,7 @@
+               -h(4)
+               +h(4),hh[44]
+               ~
+                # significant space
+               ~
+                a = b + c
+               ~
+               ~
+               +aa = a
+               ~
+               ~
+               +aeff = aeff * ( aaa )
+               ~
+       EOF
        word_diff --word-diff=porcelain
-
 '
 
-cat > expect <<EOF
-diff --git a/pre b/post
-index 330b04f..5ed8eff 100644
---- a/pre
-+++ b/post
-@@ -1,3 +1,7 @@
-[-h(4)-]{+h(4),hh[44]+}
-
-a = b + c
-
-{+aa = a+}
-
-{+aeff = aeff * ( aaa )+}
-EOF
-
 test_expect_success '--word-diff=plain' '
+       cat >expect <<-\EOF &&
+               diff --git a/pre b/post
+               index 330b04f..5ed8eff 100644
+               --- a/pre
+               +++ b/post
+               @@ -1,3 +1,7 @@
+               [-h(4)-]{+h(4),hh[44]+}
 
-       word_diff --word-diff=plain
-
-'
+               a = b + c
 
-test_expect_success '--word-diff=plain --no-color' '
+               {+aa = a+}
 
+               {+aeff = aeff * ( aaa )+}
+       EOF
+       word_diff --word-diff=plain &&
        word_diff --word-diff=plain --no-color
-
 '
 
-cat > expect <<EOF
-<BOLD>diff --git a/pre b/post<RESET>
-<BOLD>index 330b04f..5ed8eff 100644<RESET>
-<BOLD>--- a/pre<RESET>
-<BOLD>+++ b/post<RESET>
-<CYAN>@@ -1,3 +1,7 @@<RESET>
-<RED>[-h(4)-]<RESET><GREEN>{+h(4),hh[44]+}<RESET>
-
-a = b + c<RESET>
-
-<GREEN>{+aa = a+}<RESET>
+test_expect_success '--word-diff=plain --color' '
+       cat >expect <<-\EOF &&
+               <BOLD>diff --git a/pre b/post<RESET>
+               <BOLD>index 330b04f..5ed8eff 100644<RESET>
+               <BOLD>--- a/pre<RESET>
+               <BOLD>+++ b/post<RESET>
+               <CYAN>@@ -1,3 +1,7 @@<RESET>
+               <RED>[-h(4)-]<RESET><GREEN>{+h(4),hh[44]+}<RESET>
 
-<GREEN>{+aeff = aeff * ( aaa )+}<RESET>
-EOF
+               a = b + c<RESET>
 
-test_expect_success '--word-diff=plain --color' '
+               <GREEN>{+aa = a+}<RESET>
 
+               <GREEN>{+aeff = aeff * ( aaa )+}<RESET>
+       EOF
        word_diff --word-diff=plain --color
-
 '
 
-cat > expect <<\EOF
-<BOLD>diff --git a/pre b/post<RESET>
-<BOLD>index 330b04f..5ed8eff 100644<RESET>
-<BOLD>--- a/pre<RESET>
-<BOLD>+++ b/post<RESET>
-<CYAN>@@ -1 +1 @@<RESET>
-<RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET>
-<CYAN>@@ -3,0 +4,4 @@<RESET> <RESET><MAGENTA>a = b + c<RESET>
-
-<GREEN>aa = a<RESET>
-
-<GREEN>aeff = aeff * ( aaa )<RESET>
-EOF
-
 test_expect_success 'word diff without context' '
-
+       cat >expect <<-\EOF &&
+               <BOLD>diff --git a/pre b/post<RESET>
+               <BOLD>index 330b04f..5ed8eff 100644<RESET>
+               <BOLD>--- a/pre<RESET>
+               <BOLD>+++ b/post<RESET>
+               <CYAN>@@ -1 +1 @@<RESET>
+               <RED>h(4)<RESET><GREEN>h(4),hh[44]<RESET>
+               <CYAN>@@ -3,0 +4,4 @@<RESET> <RESET><MAGENTA>a = b + c<RESET>
+
+               <GREEN>aa = a<RESET>
+
+               <GREEN>aeff = aeff * ( aaa )<RESET>
+       EOF
        word_diff --color-words --unified=0
-
 '
 
-cat > expect <<\EOF
-<BOLD>diff --git a/pre b/post<RESET>
-<BOLD>index 330b04f..5ed8eff 100644<RESET>
-<BOLD>--- a/pre<RESET>
-<BOLD>+++ b/post<RESET>
-<CYAN>@@ -1,3 +1,7 @@<RESET>
-h(4),<GREEN>hh<RESET>[44]
-
-a = b + c<RESET>
-
-<GREEN>aa = a<RESET>
-
-<GREEN>aeff = aeff * ( aaa<RESET> )
-EOF
-cp expect expect.letter-runs-are-words
-
 test_expect_success 'word diff with a regular expression' '
-
+       cp expect.letter-runs-are-words expect &&
        word_diff --color-words="[a-z]+"
-
 '
 
-test_expect_success 'set a diff driver' '
+test_expect_success 'set up a diff driver' '
        git config diff.testdriver.wordRegex "[^[:space:]]" &&
-       cat <<EOF > .gitattributes
-pre diff=testdriver
-post diff=testdriver
-EOF
+       cat <<-\EOF >.gitattributes
+               pre diff=testdriver
+               post diff=testdriver
+       EOF
 '
 
 test_expect_success 'option overrides .gitattributes' '
-
+       cp expect.letter-runs-are-words expect &&
        word_diff --color-words="[a-z]+"
-
 '
 
-cat > expect <<\EOF
-<BOLD>diff --git a/pre b/post<RESET>
-<BOLD>index 330b04f..5ed8eff 100644<RESET>
-<BOLD>--- a/pre<RESET>
-<BOLD>+++ b/post<RESET>
-<CYAN>@@ -1,3 +1,7 @@<RESET>
-h(4)<GREEN>,hh[44]<RESET>
-
-a = b + c<RESET>
-
-<GREEN>aa = a<RESET>
-
-<GREEN>aeff = aeff * ( aaa )<RESET>
-EOF
-cp expect expect.non-whitespace-is-word
-
 test_expect_success 'use regex supplied by driver' '
-
+       cp expect.non-whitespace-is-word expect &&
        word_diff --color-words
-
 '
 
-test_expect_success 'set diff.wordRegex option' '
+test_expect_success 'set up diff.wordRegex option' '
        git config diff.wordRegex "[[:alnum:]]+"
 '
 
-cp expect.letter-runs-are-words expect
-
 test_expect_success 'command-line overrides config' '
+       cp expect.letter-runs-are-words expect &&
        word_diff --color-words="[a-z]+"
 '
 
-cat > expect <<\EOF
-<BOLD>diff --git a/pre b/post<RESET>
-<BOLD>index 330b04f..5ed8eff 100644<RESET>
-<BOLD>--- a/pre<RESET>
-<BOLD>+++ b/post<RESET>
-<CYAN>@@ -1,3 +1,7 @@<RESET>
-h(4),<GREEN>{+hh+}<RESET>[44]
-
-a = b + c<RESET>
+test_expect_success 'command-line overrides config: --word-diff-regex' '
+       cat >expect <<-\EOF &&
+               <BOLD>diff --git a/pre b/post<RESET>
+               <BOLD>index 330b04f..5ed8eff 100644<RESET>
+               <BOLD>--- a/pre<RESET>
+               <BOLD>+++ b/post<RESET>
+               <CYAN>@@ -1,3 +1,7 @@<RESET>
+               h(4),<GREEN>{+hh+}<RESET>[44]
 
-<GREEN>{+aa = a+}<RESET>
+               a = b + c<RESET>
 
-<GREEN>{+aeff = aeff * ( aaa+}<RESET> )
-EOF
+               <GREEN>{+aa = a+}<RESET>
 
-test_expect_success 'command-line overrides config: --word-diff-regex' '
+               <GREEN>{+aeff = aeff * ( aaa+}<RESET> )
+       EOF
        word_diff --color --word-diff-regex="[a-z]+"
 '
 
-cp expect.non-whitespace-is-word expect
-
 test_expect_success '.gitattributes override config' '
+       cp expect.non-whitespace-is-word expect &&
        word_diff --color-words
 '
 
-test_expect_success 'remove diff driver regex' '
-       git config --unset diff.testdriver.wordRegex
+test_expect_success 'setup: remove diff driver regex' '
+       test_might_fail git config --unset diff.testdriver.wordRegex
 '
 
-cat > expect <<\EOF
-<BOLD>diff --git a/pre b/post<RESET>
-<BOLD>index 330b04f..5ed8eff 100644<RESET>
-<BOLD>--- a/pre<RESET>
-<BOLD>+++ b/post<RESET>
-<CYAN>@@ -1,3 +1,7 @@<RESET>
-h(4),<GREEN>hh[44<RESET>]
-
-a = b + c<RESET>
+test_expect_success 'use configured regex' '
+       cat >expect <<-\EOF &&
+               <BOLD>diff --git a/pre b/post<RESET>
+               <BOLD>index 330b04f..5ed8eff 100644<RESET>
+               <BOLD>--- a/pre<RESET>
+               <BOLD>+++ b/post<RESET>
+               <CYAN>@@ -1,3 +1,7 @@<RESET>
+               h(4),<GREEN>hh[44<RESET>]
 
-<GREEN>aa = a<RESET>
+               a = b + c<RESET>
 
-<GREEN>aeff = aeff * ( aaa<RESET> )
-EOF
+               <GREEN>aa = a<RESET>
 
-test_expect_success 'use configured regex' '
+               <GREEN>aeff = aeff * ( aaa<RESET> )
+       EOF
        word_diff --color-words
 '
 
-echo 'aaa (aaa)' > pre
-echo 'aaa (aaa) aaa' > post
-
-cat > expect <<\EOF
-<BOLD>diff --git a/pre b/post<RESET>
-<BOLD>index c29453b..be22f37 100644<RESET>
-<BOLD>--- a/pre<RESET>
-<BOLD>+++ b/post<RESET>
-<CYAN>@@ -1 +1 @@<RESET>
-aaa (aaa) <GREEN>aaa<RESET>
-EOF
-
 test_expect_success 'test parsing words for newline' '
-
+       echo "aaa (aaa)" >pre &&
+       echo "aaa (aaa) aaa" >post &&
+       cat >expect <<-\EOF &&
+               <BOLD>diff --git a/pre b/post<RESET>
+               <BOLD>index c29453b..be22f37 100644<RESET>
+               <BOLD>--- a/pre<RESET>
+               <BOLD>+++ b/post<RESET>
+               <CYAN>@@ -1 +1 @@<RESET>
+               aaa (aaa) <GREEN>aaa<RESET>
+       EOF
        word_diff --color-words="a+"
-
-
 '
 
-echo '(:' > pre
-echo '(' > post
-
-cat > expect <<\EOF
-<BOLD>diff --git a/pre b/post<RESET>
-<BOLD>index 289cb9d..2d06f37 100644<RESET>
-<BOLD>--- a/pre<RESET>
-<BOLD>+++ b/post<RESET>
-<CYAN>@@ -1 +1 @@<RESET>
-(<RED>:<RESET>
-EOF
-
 test_expect_success 'test when words are only removed at the end' '
-
+       echo "(:" >pre &&
+       echo "(" >post &&
+       cat >expect <<-\EOF &&
+               <BOLD>diff --git a/pre b/post<RESET>
+               <BOLD>index 289cb9d..2d06f37 100644<RESET>
+               <BOLD>--- a/pre<RESET>
+               <BOLD>+++ b/post<RESET>
+               <CYAN>@@ -1 +1 @@<RESET>
+               (<RED>:<RESET>
+       EOF
        word_diff --color-words=.
-
 '
 
-cat > expect <<\EOF
-diff --git a/pre b/post
-index 289cb9d..2d06f37 100644
---- a/pre
-+++ b/post
-@@ -1 +1 @@
--(:
-+(
-EOF
-
 test_expect_success '--word-diff=none' '
-
+       echo "(:" >pre &&
+       echo "(" >post &&
+       cat >expect <<-\EOF &&
+               diff --git a/pre b/post
+               index 289cb9d..2d06f37 100644
+               --- a/pre
+               +++ b/post
+               @@ -1 +1 @@
+               -(:
+               +(
+       EOF
        word_diff --word-diff=plain --word-diff=none
-
 '
 
+test_language_driver bibtex
+test_language_driver cpp
+test_language_driver csharp
+test_language_driver fortran
+test_language_driver html
+test_language_driver java
+test_language_driver objc
+test_language_driver pascal
+test_language_driver perl
+test_language_driver php
+test_language_driver python
+test_language_driver ruby
+test_language_driver tex
+
 test_done
diff --git a/t/t4034/bibtex/expect b/t/t4034/bibtex/expect
new file mode 100644 (file)
index 0000000..a157774
--- /dev/null
@@ -0,0 +1,15 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 95cd55b..ddcba9b 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,9 +1,10 @@<RESET>
+@article{aldous1987uie,<RESET>
+  title={{Ultimate instability of exponential back-off protocol for acknowledgment-based transmission control of random access communication channels}},<RESET>
+  author={Aldous, <RED>D.<RESET><GREEN>David<RESET>},
+  journal={Information Theory, IEEE Transactions on},<RESET>
+  volume={<RED>33<RESET><GREEN>Bogus.<RESET>},
+  number={<RED>2<RESET><GREEN>4<RESET>},
+  pages={219--223},<RESET>
+  year=<GREEN>1987,<RESET>
+<GREEN>  note={This is in fact a rather funny read since ethernet works well in practice. The<RESET> {<RED>1987<RESET><GREEN>\em pre} reference is the right one, however.<RESET>}<RED>,<RESET>
+}<RESET>
diff --git a/t/t4034/bibtex/post b/t/t4034/bibtex/post
new file mode 100644 (file)
index 0000000..ddcba9b
--- /dev/null
@@ -0,0 +1,10 @@
+@article{aldous1987uie,
+  title={{Ultimate instability of exponential back-off protocol for acknowledgment-based transmission control of random access communication channels}},
+  author={Aldous, David},
+  journal={Information Theory, IEEE Transactions on},
+  volume={Bogus.},
+  number={4},
+  pages={219--223},
+  year=1987,
+  note={This is in fact a rather funny read since ethernet works well in practice. The {\em pre} reference is the right one, however.}
+}
diff --git a/t/t4034/bibtex/pre b/t/t4034/bibtex/pre
new file mode 100644 (file)
index 0000000..95cd55b
--- /dev/null
@@ -0,0 +1,9 @@
+@article{aldous1987uie,
+  title={{Ultimate instability of exponential back-off protocol for acknowledgment-based transmission control of random access communication channels}},
+  author={Aldous, D.},
+  journal={Information Theory, IEEE Transactions on},
+  volume={33},
+  number={2},
+  pages={219--223},
+  year={1987},
+}
diff --git a/t/t4034/cpp/expect b/t/t4034/cpp/expect
new file mode 100644 (file)
index 0000000..37d1ea2
--- /dev/null
@@ -0,0 +1,36 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 23d5c8a..7e8c026 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,19 +1,19 @@<RESET>
+Foo() : x(0<RED>&&1<RESET><GREEN>&42<RESET>) { <GREEN>bar(x);<RESET> }
+cout<<"Hello World<RED>!<RESET><GREEN>?<RESET>\n"<<endl;
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>|<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z
+<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,y
+<RED>a<RESET><GREEN>x<RESET>::<RED>b<RESET><GREEN>y<RESET>
diff --git a/t/t4034/cpp/post b/t/t4034/cpp/post
new file mode 100644 (file)
index 0000000..7e8c026
--- /dev/null
@@ -0,0 +1,19 @@
+Foo() : x(0&42) { bar(x); }
+cout<<"Hello World?\n"<<endl;
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x ~x x++ x-- x*y x&y
+x*y x/y x%y
+x+y x-y
+x<<y x>>y
+x<y x<=y x>y x>=y
+x==y x!=y
+x&y
+x^y
+x|y
+x&&y
+x||y
+x?y:z
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+x,y
+x::y
diff --git a/t/t4034/cpp/pre b/t/t4034/cpp/pre
new file mode 100644 (file)
index 0000000..23d5c8a
--- /dev/null
@@ -0,0 +1,19 @@
+Foo():x(0&&1){}
+cout<<"Hello World!\n"<<endl;
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a ~a a++ a-- a*b a&b
+a*b a/b a%b
+a+b a-b
+a<<b a>>b
+a<b a<=b a>b a>=b
+a==b a!=b
+a&b
+a^b
+a|b
+a&&b
+a||b
+a?b:z
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a,y
+a::b
diff --git a/t/t4034/csharp/expect b/t/t4034/csharp/expect
new file mode 100644 (file)
index 0000000..e5d1dd2
--- /dev/null
@@ -0,0 +1,35 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 9106d63..dd5f421 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,18 +1,18 @@<RESET>
+Foo() : x(0<RED>&&1<RESET><GREEN>&42<RESET>) { <GREEN>bar(x);<RESET> }
+cout<<"Hello World<RED>!<RESET><GREEN>?<RESET>\n"<<endl;
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>|<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z
+<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,y
diff --git a/t/t4034/csharp/post b/t/t4034/csharp/post
new file mode 100644 (file)
index 0000000..dd5f421
--- /dev/null
@@ -0,0 +1,18 @@
+Foo() : x(0&42) { bar(x); }
+cout<<"Hello World?\n"<<endl;
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x ~x x++ x-- x*y x&y
+x*y x/y x%y
+x+y x-y
+x<<y x>>y
+x<y x<=y x>y x>=y
+x==y x!=y
+x&y
+x^y
+x|y
+x&&y
+x||y
+x?y:z
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+x,y
diff --git a/t/t4034/csharp/pre b/t/t4034/csharp/pre
new file mode 100644 (file)
index 0000000..9106d63
--- /dev/null
@@ -0,0 +1,18 @@
+Foo():x(0&&1){}
+cout<<"Hello World!\n"<<endl;
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a ~a a++ a-- a*b a&b
+a*b a/b a%b
+a+b a-b
+a<<b a>>b
+a<b a<=b a>b a>=b
+a==b a!=b
+a&b
+a^b
+a|b
+a&&b
+a||b
+a?b:z
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a,y
diff --git a/t/t4034/fortran/expect b/t/t4034/fortran/expect
new file mode 100644 (file)
index 0000000..b233dbd
--- /dev/null
@@ -0,0 +1,10 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 87f0d0b..d308da2 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,5 +1,5 @@<RESET>
+print *, "Hello World<RED>!<RESET><GREEN>?<RESET>"
+
+DO10I = 1,10<RESET>
+<RED>DO10I<RESET><GREEN>DO 10 I<RESET> = 1,10
+<RED>DO10I<RESET><GREEN>DO 1 0 I<RESET> = 1,10
diff --git a/t/t4034/fortran/post b/t/t4034/fortran/post
new file mode 100644 (file)
index 0000000..d308da2
--- /dev/null
@@ -0,0 +1,5 @@
+print *, "Hello World?"
+
+DO10I = 1,10
+DO 10 I = 1,10
+DO 1 0 I = 1,10
diff --git a/t/t4034/fortran/pre b/t/t4034/fortran/pre
new file mode 100644 (file)
index 0000000..87f0d0b
--- /dev/null
@@ -0,0 +1,5 @@
+print *, "Hello World!"
+
+DO10I = 1,10
+DO10I = 1,10
+DO10I = 1,10
diff --git a/t/t4034/html/expect b/t/t4034/html/expect
new file mode 100644 (file)
index 0000000..447b49a
--- /dev/null
@@ -0,0 +1,8 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 8ca4aea..46921e5 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,3 +1,3 @@<RESET>
+<tag <GREEN>newattr="newvalue"<RESET>><GREEN>added<RESET> content</tag>
+<tag attr=<RED>"value"<RESET><GREEN>"newvalue"<RESET>><RED>content<RESET><GREEN>changed<RESET></tag>
+<<RED>tag<RESET><GREEN>newtag<RESET>>content <RED>&entity;<RESET><GREEN>&newentity;<RESET><<RED>/tag<RESET><GREEN>/newtag<RESET>>
diff --git a/t/t4034/html/post b/t/t4034/html/post
new file mode 100644 (file)
index 0000000..46921e5
--- /dev/null
@@ -0,0 +1,3 @@
+<tag newattr="newvalue">added content</tag>
+<tag attr="newvalue">changed</tag>
+<newtag>content &newentity;</newtag>
diff --git a/t/t4034/html/pre b/t/t4034/html/pre
new file mode 100644 (file)
index 0000000..8ca4aea
--- /dev/null
@@ -0,0 +1,3 @@
+<tag>content</tag>
+<tag attr="value">content</tag>
+<tag>content &entity;</tag>
diff --git a/t/t4034/java/expect b/t/t4034/java/expect
new file mode 100644 (file)
index 0000000..37d1ea2
--- /dev/null
@@ -0,0 +1,36 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 23d5c8a..7e8c026 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,19 +1,19 @@<RESET>
+Foo() : x(0<RED>&&1<RESET><GREEN>&42<RESET>) { <GREEN>bar(x);<RESET> }
+cout<<"Hello World<RED>!<RESET><GREEN>?<RESET>\n"<<endl;
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>|<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z
+<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,y
+<RED>a<RESET><GREEN>x<RESET>::<RED>b<RESET><GREEN>y<RESET>
diff --git a/t/t4034/java/post b/t/t4034/java/post
new file mode 100644 (file)
index 0000000..7e8c026
--- /dev/null
@@ -0,0 +1,19 @@
+Foo() : x(0&42) { bar(x); }
+cout<<"Hello World?\n"<<endl;
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x ~x x++ x-- x*y x&y
+x*y x/y x%y
+x+y x-y
+x<<y x>>y
+x<y x<=y x>y x>=y
+x==y x!=y
+x&y
+x^y
+x|y
+x&&y
+x||y
+x?y:z
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+x,y
+x::y
diff --git a/t/t4034/java/pre b/t/t4034/java/pre
new file mode 100644 (file)
index 0000000..23d5c8a
--- /dev/null
@@ -0,0 +1,19 @@
+Foo():x(0&&1){}
+cout<<"Hello World!\n"<<endl;
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a ~a a++ a-- a*b a&b
+a*b a/b a%b
+a+b a-b
+a<<b a>>b
+a<b a<=b a>b a>=b
+a==b a!=b
+a&b
+a^b
+a|b
+a&&b
+a||b
+a?b:z
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a,y
+a::b
diff --git a/t/t4034/objc/expect b/t/t4034/objc/expect
new file mode 100644 (file)
index 0000000..e5d1dd2
--- /dev/null
@@ -0,0 +1,35 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 9106d63..dd5f421 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,18 +1,18 @@<RESET>
+Foo() : x(0<RED>&&1<RESET><GREEN>&42<RESET>) { <GREEN>bar(x);<RESET> }
+cout<<"Hello World<RED>!<RESET><GREEN>?<RESET>\n"<<endl;
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>|<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z
+<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,y
diff --git a/t/t4034/objc/post b/t/t4034/objc/post
new file mode 100644 (file)
index 0000000..dd5f421
--- /dev/null
@@ -0,0 +1,18 @@
+Foo() : x(0&42) { bar(x); }
+cout<<"Hello World?\n"<<endl;
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x ~x x++ x-- x*y x&y
+x*y x/y x%y
+x+y x-y
+x<<y x>>y
+x<y x<=y x>y x>=y
+x==y x!=y
+x&y
+x^y
+x|y
+x&&y
+x||y
+x?y:z
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+x,y
diff --git a/t/t4034/objc/pre b/t/t4034/objc/pre
new file mode 100644 (file)
index 0000000..9106d63
--- /dev/null
@@ -0,0 +1,18 @@
+Foo():x(0&&1){}
+cout<<"Hello World!\n"<<endl;
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a ~a a++ a-- a*b a&b
+a*b a/b a%b
+a+b a-b
+a<<b a>>b
+a<b a<=b a>b a>=b
+a==b a!=b
+a&b
+a^b
+a|b
+a&&b
+a||b
+a?b:z
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a,y
diff --git a/t/t4034/pascal/expect b/t/t4034/pascal/expect
new file mode 100644 (file)
index 0000000..2ce4230
--- /dev/null
@@ -0,0 +1,35 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 077046c..8865e6b 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,18 +1,18 @@<RESET>
+writeln("Hello World<RED>!<RESET><GREEN>?<RESET>");
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>|<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z
+<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,y
+<RED>a<RESET><GREEN>x<RESET>::<RED>b<RESET><GREEN>y<RESET>
diff --git a/t/t4034/pascal/post b/t/t4034/pascal/post
new file mode 100644 (file)
index 0000000..8865e6b
--- /dev/null
@@ -0,0 +1,18 @@
+writeln("Hello World?");
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x ~x x++ x-- x*y x&y
+x*y x/y x%y
+x+y x-y
+x<<y x>>y
+x<y x<=y x>y x>=y
+x==y x!=y
+x&y
+x^y
+x|y
+x&&y
+x||y
+x?y:z
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+x,y
+x::y
diff --git a/t/t4034/pascal/pre b/t/t4034/pascal/pre
new file mode 100644 (file)
index 0000000..077046c
--- /dev/null
@@ -0,0 +1,18 @@
+writeln("Hello World!");
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a ~a a++ a-- a*b a&b
+a*b a/b a%b
+a+b a-b
+a<<b a>>b
+a<b a<=b a>b a>=b
+a==b a!=b
+a&b
+a^b
+a|b
+a&&b
+a||b
+a?b:z
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a,y
+a::b
diff --git a/t/t4034/perl/expect b/t/t4034/perl/expect
new file mode 100644 (file)
index 0000000..a1deb6b
--- /dev/null
@@ -0,0 +1,13 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index f6610d3..e8b72ef 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -4,8 +4,8 @@<RESET>
+
+package Frotz;<RESET>
+sub new {<RESET>
+       my <GREEN>(<RESET>$class<GREEN>, %opts)<RESET> = <RED>shift<RESET><GREEN>@_<RESET>;
+       return bless { <GREEN>xyzzy => "nitfol", %opts<RESET> }, $class;
+}<RESET>
+
+__END__<RESET>
diff --git a/t/t4034/perl/post b/t/t4034/perl/post
new file mode 100644 (file)
index 0000000..e8b72ef
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/perl
+
+use strict;
+
+package Frotz;
+sub new {
+       my ($class, %opts) = @_;
+       return bless { xyzzy => "nitfol", %opts }, $class;
+}
+
+__END__
+=head1 NAME
+
+frotz - Frotz
+
+=head1 SYNOPSIS
+
+  use frotz;
+
+  $nitfol = new Frotz();
+
+=cut
diff --git a/t/t4034/perl/pre b/t/t4034/perl/pre
new file mode 100644 (file)
index 0000000..f6610d3
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/perl
+
+use strict;
+
+package Frotz;
+sub new {
+       my $class = shift;
+       return bless {}, $class;
+}
+
+__END__
+=head1 NAME
+
+frotz - Frotz
+
+=head1 SYNOPSIS
+
+  use frotz;
+
+  $nitfol = new Frotz();
+
+=cut
diff --git a/t/t4034/php/expect b/t/t4034/php/expect
new file mode 100644 (file)
index 0000000..0404408
--- /dev/null
@@ -0,0 +1,35 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index cf6e06b..4420a49 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,18 +1,18 @@<RESET>
+<GREEN>(<RESET>$var<GREEN>)<RESET> $ var
+<?="Hello World<RED>!<RESET><GREEN>?<RESET>"?>
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>|<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z
+<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,y
diff --git a/t/t4034/php/post b/t/t4034/php/post
new file mode 100644 (file)
index 0000000..4420a49
--- /dev/null
@@ -0,0 +1,18 @@
+($var) $ var
+<?="Hello World?"?>
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x ~x x++ x-- x*y x&y
+x*y x/y x%y
+x+y x-y
+x<<y x>>y
+x<y x<=y x>y x>=y
+x==y x!=y
+x&y
+x^y
+x|y
+x&&y
+x||y
+x?y:z
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+x,y
diff --git a/t/t4034/php/pre b/t/t4034/php/pre
new file mode 100644 (file)
index 0000000..cf6e06b
--- /dev/null
@@ -0,0 +1,18 @@
+$var $var
+<?= "Hello World!" ?>
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a ~a a++ a-- a*b a&b
+a*b a/b a%b
+a+b a-b
+a<<b a>>b
+a<b a<=b a>b a>=b
+a==b a!=b
+a&b
+a^b
+a|b
+a&&b
+a||b
+a?b:z
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a,y
diff --git a/t/t4034/python/expect b/t/t4034/python/expect
new file mode 100644 (file)
index 0000000..8abb8a4
--- /dev/null
@@ -0,0 +1,34 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 438f776..68baf34 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,17 +1,17 @@<RESET>
+print<RED>u<RESET> "Hello World<RED>!<RESET><GREEN>?<RESET>\n"<GREEN>; print<RESET>
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>) u<RESET>'<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>|<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>||<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>?<RED>b<RESET><GREEN>y<RESET>:z
+<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,y
diff --git a/t/t4034/python/post b/t/t4034/python/post
new file mode 100644 (file)
index 0000000..68baf34
--- /dev/null
@@ -0,0 +1,17 @@
+print "Hello World?\n"; print
+(1) (-1e10) (0xabcdef) u'y'
+[x] x->y x.y
+!x ~x x++ x-- x*y x&y
+x*y x/y x%y
+x+y x-y
+x<<y x>>y
+x<y x<=y x>y x>=y
+x==y x!=y
+x&y
+x^y
+x|y
+x&&y
+x||y
+x?y:z
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+x,y
diff --git a/t/t4034/python/pre b/t/t4034/python/pre
new file mode 100644 (file)
index 0000000..438f776
--- /dev/null
@@ -0,0 +1,17 @@
+print u"Hello World!\n"
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a ~a a++ a-- a*b a&b
+a*b a/b a%b
+a+b a-b
+a<<b a>>b
+a<b a<=b a>b a>=b
+a==b a!=b
+a&b
+a^b
+a|b
+a&&b
+a||b
+a?b:z
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a,y
diff --git a/t/t4034/ruby/expect b/t/t4034/ruby/expect
new file mode 100644 (file)
index 0000000..16e1dd5
--- /dev/null
@@ -0,0 +1,34 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 30ed9a1..7678f14 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,17 +1,17 @@<RESET>
+10.downto(1) {|<RED>x<RESET><GREEN>y<RESET>| puts <RED>x<RESET><GREEN>y<RESET>}
+<GREEN>(<RESET>1<GREEN>) (<RESET>-1e10<GREEN>) (<RESET>0xabcdef<GREEN>)<RESET> '<RED>x<RESET><GREEN>y<RESET>'
+[<RED>a<RESET><GREEN>x<RESET>] <RED>a<RESET><GREEN>x<RESET>-><RED>b a<RESET><GREEN>y x<RESET>.<RED>b<RESET><GREEN>y<RESET>
+!<RED>a<RESET><GREEN>x<RESET> ~<RED>a a<RESET><GREEN>x x<RESET>++ <RED>a<RESET><GREEN>x<RESET>-- <RED>a<RESET><GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>*<RED>b a<RESET><GREEN>y x<RESET>/<RED>b a<RESET><GREEN>y x<RESET>%<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>+<RED>b a<RESET><GREEN>y x<RESET>-<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<<RED>b a<RESET><GREEN>y x<RESET>>><RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET><<RED>b a<RESET><GREEN>y x<RESET><=<RED>b a<RESET><GREEN>y x<RESET>><RED>b a<RESET><GREEN>y x<RESET>>=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>==<RED>b a<RESET><GREEN>y x<RESET>!=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>^<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>|<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>&&<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>||<RED>b<RESET>
+<RED>a?b<RESET><GREEN>y<RESET>
+<GREEN>x?y<RESET>:z
+<RED>a<RESET><GREEN>x<RESET>=<RED>b a<RESET><GREEN>y x<RESET>+=<RED>b a<RESET><GREEN>y x<RESET>-=<RED>b a<RESET><GREEN>y x<RESET>*=<RED>b a<RESET><GREEN>y x<RESET>/=<RED>b a<RESET><GREEN>y x<RESET>%=<RED>b a<RESET><GREEN>y x<RESET><<=<RED>b a<RESET><GREEN>y x<RESET>>>=<RED>b a<RESET><GREEN>y x<RESET>&=<RED>b a<RESET><GREEN>y x<RESET>^=<RED>b a<RESET><GREEN>y x<RESET>|=<RED>b<RESET>
+<RED>a<RESET><GREEN>y<RESET>
+<GREEN>x<RESET>,y
diff --git a/t/t4034/ruby/post b/t/t4034/ruby/post
new file mode 100644 (file)
index 0000000..7678f14
--- /dev/null
@@ -0,0 +1,17 @@
+10.downto(1) {|y| puts y}
+(1) (-1e10) (0xabcdef) 'y'
+[x] x->y x.y
+!x ~x x++ x-- x*y x&y
+x*y x/y x%y
+x+y x-y
+x<<y x>>y
+x<y x<=y x>y x>=y
+x==y x!=y
+x&y
+x^y
+x|y
+x&&y
+x||y
+x?y:z
+x=y x+=y x-=y x*=y x/=y x%=y x<<=y x>>=y x&=y x^=y x|=y
+x,y
diff --git a/t/t4034/ruby/pre b/t/t4034/ruby/pre
new file mode 100644 (file)
index 0000000..30ed9a1
--- /dev/null
@@ -0,0 +1,17 @@
+10.downto(1) {|x| puts x}
+1 -1e10 0xabcdef 'x'
+[a] a->b a.b
+!a ~a a++ a-- a*b a&b
+a*b a/b a%b
+a+b a-b
+a<<b a>>b
+a<b a<=b a>b a>=b
+a==b a!=b
+a&b
+a^b
+a|b
+a&&b
+a||b
+a?b:z
+a=b a+=b a-=b a*=b a/=b a%=b a<<=b a>>=b a&=b a^=b a|=b
+a,y
diff --git a/t/t4034/tex/expect b/t/t4034/tex/expect
new file mode 100644 (file)
index 0000000..604969b
--- /dev/null
@@ -0,0 +1,9 @@
+<BOLD>diff --git a/pre b/post<RESET>
+<BOLD>index 2b2dfcb..65cab61 100644<RESET>
+<BOLD>--- a/pre<RESET>
+<BOLD>+++ b/post<RESET>
+<CYAN>@@ -1,4 +1,4 @@<RESET>
+\section{Something <GREEN>new<RESET>}
+<RED>\emph<RESET><GREEN>\textbf<RESET>{Macro style}
+{<RED>\em<RESET><GREEN>\bfseries<RESET> State toggle style}
+\\[<RED>1em<RESET><GREEN>1cm<RESET>]
diff --git a/t/t4034/tex/post b/t/t4034/tex/post
new file mode 100644 (file)
index 0000000..65cab61
--- /dev/null
@@ -0,0 +1,4 @@
+\section{Something new}
+\textbf{Macro style}
+{\bfseries State toggle style}
+\\[1cm]
diff --git a/t/t4034/tex/pre b/t/t4034/tex/pre
new file mode 100644 (file)
index 0000000..2b2dfcb
--- /dev/null
@@ -0,0 +1,4 @@
+\section{Something}
+\emph{Macro style}
+{\em State toggle style}
+\\[1em]
index a30b03bcf27ba360c3761ade77ddf0ed00600470..abc49348b196cf0fec232b6f2399356e4fe324d5 100755 (executable)
@@ -60,4 +60,11 @@ test_expect_success 'diff-files -b -p --exit-code' '
        git diff-files -b -p --exit-code
 '
 
+test_expect_success 'diff-files --diff-filter --quiet' '
+       git reset --hard &&
+       rm a/d &&
+       echo x >>b/e &&
+       test_must_fail git diff-files --diff-filter=M --quiet
+'
+
 test_done
index 579c9e61054521301464bfc31351040d45966836..a33d510bf6b27a6bb2c640cfc9d11f462cbdf7a6 100755 (executable)
@@ -6,6 +6,7 @@
 test_description='git apply -p handling.'
 
 . ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-prereq-FILEMODE.sh
 
 test_expect_success setup '
        mkdir sub &&
@@ -62,8 +63,12 @@ test_expect_success 'apply (-p2) diff, mode change only' '
        old mode 100644
        new mode 100755
        EOF
-       chmod 644 file1 &&
-       git apply -p2 patch.chmod &&
+       test_chmod -x file1 &&
+       git apply --index -p2 patch.chmod &&
+       case $(git ls-files -s file1) in 100755*) : good;; *) false;; esac
+'
+
+test_expect_success FILEMODE 'file mode was changed' '
        test -x file1
 '
 
index 68e2652814c6a52265407b0fdfb70162eb634d53..d2c930de87f721a0e876351e511295ae0b094108 100755 (executable)
@@ -63,4 +63,40 @@ test_expect_success 'patch-id supports git-format-patch MIME output' '
        test_cmp patch-id_master patch-id_same
 '
 
+cat >nonl <<\EOF
+diff --git i/a w/a
+index e69de29..2e65efe 100644
+--- i/a
++++ w/a
+@@ -0,0 +1 @@
++a
+\ No newline at end of file
+diff --git i/b w/b
+index e69de29..6178079 100644
+--- i/b
++++ w/b
+@@ -0,0 +1 @@
++b
+EOF
+
+cat >withnl <<\EOF
+diff --git i/a w/a
+index e69de29..7898192 100644
+--- i/a
++++ w/a
+@@ -0,0 +1 @@
++a
+diff --git i/b w/b
+index e69de29..6178079 100644
+--- i/b
++++ w/b
+@@ -0,0 +1 @@
++b
+EOF
+
+test_expect_success 'patch-id handles no-nl-at-eof markers' '
+       cat nonl | calc_patch_id nonl &&
+       cat withnl | calc_patch_id withnl &&
+       test_cmp patch-id_nonl patch-id_withnl
+'
 test_done
diff --git a/t/t5501-fetch-push-alternates.sh b/t/t5501-fetch-push-alternates.sh
new file mode 100755 (executable)
index 0000000..b5ced84
--- /dev/null
@@ -0,0 +1,66 @@
+#!/bin/sh
+
+test_description='fetch/push involving alternates'
+. ./test-lib.sh
+
+count_objects () {
+       loose=0 inpack=0
+       eval "$(
+               git count-objects -v |
+               sed -n -e 's/^count: \(.*\)/loose=\1/p' \
+                   -e 's/^in-pack: \(.*\)/inpack=\1/p'
+       )" &&
+       echo $(( $loose + $inpack ))
+}
+
+
+test_expect_success setup '
+       (
+               git init original &&
+               cd original &&
+               i=0 &&
+               while test $i -le 100
+               do
+                       echo "$i" >count &&
+                       git add count &&
+                       git commit -m "$i" || exit
+                       i=$(($i + 1))
+               done
+       ) &&
+       (
+               git clone --reference=original "file:///$(pwd)/original" one &&
+               cd one &&
+               echo Z >count &&
+               git add count &&
+               git commit -m Z &&
+               count_objects >../one.count
+       ) &&
+       A=$(pwd)/original/.git/objects &&
+       git init receiver &&
+       echo "$A" >receiver/.git/objects/info/alternates &&
+       git init fetcher &&
+       echo "$A" >fetcher/.git/objects/info/alternates
+'
+
+test_expect_success 'pushing into a repository with the same alternate' '
+       (
+               cd one &&
+               git push ../receiver master:refs/heads/it
+       ) &&
+       (
+               cd receiver &&
+               count_objects >../receiver.count
+       ) &&
+       test_cmp one.count receiver.count
+'
+
+test_expect_success 'fetching from a repository with the same alternate' '
+       (
+               cd fetcher &&
+               git fetch ../one master:refs/heads/it &&
+               count_objects >../fetcher.count
+       ) &&
+       test_cmp one.count fetcher.count
+'
+
+test_done
index 884a5e567c308e976ce50036dc93c3932b717603..a5f458533fd071c13550a72bf251e2e10c109637 100755 (executable)
@@ -124,7 +124,7 @@ test_expect_success "--recurse-submodules overrides fetchRecurseSubmodules setti
        (
                cd downstream &&
                git fetch --recurse-submodules >../actual.out 2>../actual.err &&
-               git config -f --unset .gitmodules submodule.submodule.fetchRecurseSubmodules true &&
+               git config --unset -f .gitmodules submodule.submodule.fetchRecurseSubmodules &&
                git config --unset submodule.submodule.fetchRecurseSubmodules
        ) &&
        test_cmp expect.out actual.out &&
index 987e0c846309a8a49dbe31ce292edd55342217b3..3ca275cc671502febd8397e1828c612f575c5b89 100755 (executable)
@@ -164,7 +164,6 @@ test_expect_success 'clone a void' '
 test_expect_success 'clone respects global branch.autosetuprebase' '
        (
                test_config="$HOME/.gitconfig" &&
-               unset GIT_CONFIG_NOGLOBAL &&
                git config -f "$test_config" branch.autosetuprebase remote &&
                rm -fr dst &&
                git clone src dst &&
index 0f4d487be34d22820bcc63619e6e85b96f18c609..6972258b27f6039e05f6bd2129f9c18ca45404d4 100755 (executable)
@@ -144,4 +144,17 @@ test_expect_success 'clone empty repository, and then push should not segfault.'
        test_must_fail git push)
 '
 
+test_expect_success 'cloning non-existent directory fails' '
+       cd "$D" &&
+       rm -rf does-not-exist &&
+       test_must_fail git clone does-not-exist
+'
+
+test_expect_success 'cloning non-git directory fails' '
+       cd "$D" &&
+       rm -rf not-a-git-repo not-a-git-repo-clone &&
+       mkdir not-a-git-repo &&
+       test_must_fail git clone not-a-git-repo not-a-git-repo-clone
+'
+
 test_done
diff --git a/t/t6000-rev-list-misc.sh b/t/t6000-rev-list-misc.sh
new file mode 100755 (executable)
index 0000000..b10685a
--- /dev/null
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+test_description='miscellaneous rev-list tests'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+       echo content1 >wanted_file &&
+       echo content2 >unwanted_file &&
+       git add wanted_file unwanted_file &&
+       git commit -m one
+'
+
+test_expect_success 'rev-list --objects heeds pathspecs' '
+       git rev-list --objects HEAD -- wanted_file >output &&
+       grep wanted_file output &&
+       ! grep unwanted_file output
+'
+
+test_expect_success 'rev-list --objects with pathspecs and deeper paths' '
+       mkdir foo &&
+       >foo/file &&
+       git add foo/file &&
+       git commit -m two &&
+
+       git rev-list --objects HEAD -- foo >output &&
+       grep foo/file output &&
+
+       git rev-list --objects HEAD -- foo/file >output &&
+       grep foo/file output &&
+       ! grep unwanted_file output
+'
+
+test_expect_success 'rev-list --objects with pathspecs and copied files' '
+       git checkout --orphan junio-testcase &&
+       git rm -rf . &&
+
+       mkdir two &&
+       echo frotz >one &&
+       cp one two/three &&
+       git add one two/three &&
+       test_tick &&
+       git commit -m that &&
+
+       ONE=$(git rev-parse HEAD:one)
+       git rev-list --objects HEAD two >output &&
+       grep "$ONE two/three" output &&
+       ! grep one output
+'
+
+test_done
index 5dabf1c5e354c28cc593bd0ea8e4b0d5f0d56d67..3e8c42ee0b93cff3be39f42a411e9b32d16c5d5d 100755 (executable)
@@ -1,51 +1,96 @@
 #!/bin/sh
 
-test_description='git rev-list trivial path optimization test'
+test_description='git rev-list trivial path optimization test
+
+   d/z1
+   b0                             b1
+   o------------------------*----o master
+  /                        /
+ o---------o----o----o----o side
+ a0        c0   c1   a1   c2
+ d/f0      d/f1
+ d/z0
+
+'
 
 . ./test-lib.sh
 
 test_expect_success setup '
-echo Hello > a &&
-git add a &&
-git commit -m "Initial commit" a &&
-initial=$(git rev-parse --verify HEAD)
+       echo Hello >a &&
+       mkdir d &&
+       echo World >d/f &&
+       echo World >d/z &&
+       git add a d &&
+       test_tick &&
+       git commit -m "Initial commit" &&
+       git rev-parse --verify HEAD &&
+       git tag initial
 '
 
 test_expect_success path-optimization '
-    commit=$(echo "Unchanged tree" | git commit-tree "HEAD^{tree}" -p HEAD) &&
-    test $(git rev-list $commit | wc -l) = 2 &&
-    test $(git rev-list $commit -- . | wc -l) = 1
+       test_tick &&
+       commit=$(echo "Unchanged tree" | git commit-tree "HEAD^{tree}" -p HEAD) &&
+       test $(git rev-list $commit | wc -l) = 2 &&
+       test $(git rev-list $commit -- . | wc -l) = 1
 '
 
 test_expect_success 'further setup' '
        git checkout -b side &&
        echo Irrelevant >c &&
-       git add c &&
+       echo Irrelevant >d/f &&
+       git add c d/f &&
+       test_tick &&
        git commit -m "Side makes an irrelevant commit" &&
+       git tag side_c0 &&
        echo "More Irrelevancy" >c &&
        git add c &&
+       test_tick &&
        git commit -m "Side makes another irrelevant commit" &&
        echo Bye >a &&
        git add a &&
+       test_tick &&
        git commit -m "Side touches a" &&
-       side=$(git rev-parse --verify HEAD) &&
+       git tag side_a1 &&
        echo "Yet more Irrelevancy" >c &&
        git add c &&
+       test_tick &&
        git commit -m "Side makes yet another irrelevant commit" &&
        git checkout master &&
        echo Another >b &&
-       git add b &&
+       echo Munged >d/z &&
+       git add b d/z &&
+       test_tick &&
        git commit -m "Master touches b" &&
+       git tag master_b0 &&
        git merge side &&
        echo Touched >b &&
        git add b &&
+       test_tick &&
        git commit -m "Master touches b again"
 '
 
 test_expect_success 'path optimization 2' '
-       ( echo "$side"; echo "$initial" ) >expected &&
+       git rev-parse side_a1 initial >expected &&
        git rev-list HEAD -- a >actual &&
        test_cmp expected actual
 '
 
+test_expect_success 'pathspec with leading path' '
+       git rev-parse master^ master_b0 side_c0 initial >expected &&
+       git rev-list HEAD -- d >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'pathspec with glob (1)' '
+       git rev-parse master^ master_b0 side_c0 initial >expected &&
+       git rev-list HEAD -- "d/*" >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'pathspec with glob (2)' '
+       git rev-parse side_c0 initial >expected &&
+       git rev-list HEAD -- "d/[a-m]*" >actual &&
+       test_cmp expected actual
+'
+
 test_done
index b565638e92655c12c841c29a108516a8b13cf8d2..cacf3de6c9f31889fd8df0bc0cebbbc74e3525bd 100755 (executable)
@@ -4,13 +4,14 @@ test_description='test git rev-list --cherry-pick -- file'
 
 . ./test-lib.sh
 
-# A---B
+# A---B---D---F
 #  \
 #   \
-#    C
+#    C---E
 #
 # B changes a file foo.c, adding a line of text.  C changes foo.c as
 # well as bar.c, but the change in foo.c was identical to change B.
+# D and C change bar in the same way, E and F differently.
 
 test_expect_success setup '
        echo Hallo > foo &&
@@ -25,11 +26,26 @@ test_expect_success setup '
        test_tick &&
        git commit -m "C" &&
        git tag C &&
+       echo Dello > bar &&
+       git add bar &&
+       test_tick &&
+       git commit -m "E" &&
+       git tag E &&
        git checkout master &&
        git checkout branch foo &&
        test_tick &&
        git commit -m "B" &&
-       git tag B
+       git tag B &&
+       echo Cello > bar &&
+       git add bar &&
+       test_tick &&
+       git commit -m "D" &&
+       git tag D &&
+       echo Nello > bar &&
+       git add bar &&
+       test_tick &&
+       git commit -m "F" &&
+       git tag F
 '
 
 cat >expect <<EOF
@@ -53,8 +69,92 @@ test_expect_success '--cherry-pick foo comes up empty' '
        test -z "$(git rev-list --left-right --cherry-pick B...C -- foo)"
 '
 
+cat >expect <<EOF
+>tags/C
+EOF
+
 test_expect_success '--cherry-pick bar does not come up empty' '
-       ! test -z "$(git rev-list --left-right --cherry-pick B...C -- bar)"
+       git rev-list --left-right --cherry-pick B...C -- bar > actual &&
+       git name-rev --stdin --name-only --refs="*tags/*" \
+               < actual > actual.named &&
+       test_cmp actual.named expect
+'
+
+test_expect_success 'bar does not come up empty' '
+       git rev-list --left-right B...C -- bar > actual &&
+       git name-rev --stdin --name-only --refs="*tags/*" \
+               < actual > actual.named &&
+       test_cmp actual.named expect
+'
+
+cat >expect <<EOF
+<tags/F
+>tags/E
+EOF
+
+test_expect_success '--cherry-pick bar does not come up empty (II)' '
+       git rev-list --left-right --cherry-pick F...E -- bar > actual &&
+       git name-rev --stdin --name-only --refs="*tags/*" \
+               < actual > actual.named &&
+       test_cmp actual.named expect
+'
+
+cat >expect <<EOF
++tags/F
+=tags/D
++tags/E
+=tags/C
+EOF
+
+test_expect_success '--cherry-mark' '
+       git rev-list --cherry-mark F...E -- bar > actual &&
+       git name-rev --stdin --name-only --refs="*tags/*" \
+               < actual > actual.named &&
+       test_cmp actual.named expect
+'
+
+cat >expect <<EOF
+<tags/F
+=tags/D
+>tags/E
+=tags/C
+EOF
+
+test_expect_success '--cherry-mark --left-right' '
+       git rev-list --cherry-mark --left-right F...E -- bar > actual &&
+       git name-rev --stdin --name-only --refs="*tags/*" \
+               < actual > actual.named &&
+       test_cmp actual.named expect
+'
+
+cat >expect <<EOF
+tags/E
+EOF
+
+test_expect_success '--cherry-pick --right-only' '
+       git rev-list --cherry-pick --right-only F...E -- bar > actual &&
+       git name-rev --stdin --name-only --refs="*tags/*" \
+               < actual > actual.named &&
+       test_cmp actual.named expect
+'
+
+test_expect_success '--cherry-pick --left-only' '
+       git rev-list --cherry-pick --left-only E...F -- bar > actual &&
+       git name-rev --stdin --name-only --refs="*tags/*" \
+               < actual > actual.named &&
+       test_cmp actual.named expect
+'
+
+cat >expect <<EOF
++tags/E
+=tags/C
+EOF
+
+test_expect_success '--cherry' '
+       git rev-list --cherry F...E -- bar > actual &&
+       git name-rev --stdin --name-only --refs="*tags/*" \
+               < actual > actual.named &&
+       test_cmp actual.named expect
 '
 
 test_expect_success '--cherry-pick with independent, but identical branches' '
@@ -75,11 +175,8 @@ cat >expect <<EOF
 1      2
 EOF
 
-# Insert an extra commit to break the symmetry
 test_expect_success '--count --left-right' '
-       git checkout branch &&
-       test_commit D &&
-       git rev-list --count --left-right B...D > actual &&
+       git rev-list --count --left-right C...D > actual &&
        test_cmp expect actual
 '
 
index 92e02d5d77501b2a3ff52069931a534fc7bb24fd..2599ae50eb94051f66b4dc1de603aaf8cd1f79eb 100755 (executable)
@@ -17,13 +17,21 @@ test_expect_success SYMLINKS 'create a commit where dir a/b changed to symlink'
        git commit -m "dir to symlink"
 '
 
-test_expect_success SYMLINKS 'keep a/b-2/c/d across checkout' '
+test_expect_success SYMLINKS 'checkout does not clobber untracked symlink' '
        git checkout HEAD^0 &&
        git reset --hard master &&
        git rm --cached a/b &&
        git commit -m "untracked symlink remains" &&
-        git checkout start^0 &&
-        test -f a/b-2/c/d
+       test_must_fail git checkout start^0
+'
+
+test_expect_success SYMLINKS 'a/b-2/c/d is kept when clobbering symlink b' '
+       git checkout HEAD^0 &&
+       git reset --hard master &&
+       git rm --cached a/b &&
+       git commit -m "untracked symlink remains" &&
+       git checkout -f start^0 &&
+       test -f a/b-2/c/d
 '
 
 test_expect_success SYMLINKS 'checkout should not have deleted a/b-2/c/d' '
index 1e0447f615c55ecf98ae341553ea60f10a956ae3..cb851326425be7a552a0624a5d7483244625a7ed 100755 (executable)
@@ -74,20 +74,20 @@ test_expect_success 'status' '
        grep "have 1 and 1 different" actual
 '
 
-test_expect_success 'status when tracking lightweight tags' '
+test_expect_success 'fail to track lightweight tags' '
        git checkout master &&
        git tag light &&
-       git branch --track lighttrack light >actual &&
-       grep "set up to track" actual &&
-       git checkout lighttrack
+       test_must_fail git branch --track lighttrack light >actual &&
+       test_must_fail grep "set up to track" actual &&
+       test_must_fail git checkout lighttrack
 '
 
-test_expect_success 'status when tracking annotated tags' '
+test_expect_success 'fail to track annotated tags' '
        git checkout master &&
        git tag -m heavy heavy &&
-       git branch --track heavytrack heavy >actual &&
-       grep "set up to track" actual &&
-       git checkout heavytrack
+       test_must_fail git branch --track heavytrack heavy >actual &&
+       test_must_fail grep "set up to track" actual &&
+       test_must_fail git checkout heavytrack
 '
 
 test_expect_success 'setup tracking with branch --set-upstream on existing branch' '
diff --git a/t/t6110-rev-list-sparse.sh b/t/t6110-rev-list-sparse.sh
new file mode 100755 (executable)
index 0000000..656ac7f
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+test_description='operations that cull histories in unusual ways'
+. ./test-lib.sh
+
+test_expect_success setup '
+       test_commit A &&
+       test_commit B &&
+       test_commit C &&
+       git checkout -b side HEAD^ &&
+       test_commit D &&
+       test_commit E &&
+       git merge master
+'
+
+test_expect_success 'rev-list --first-parent --boundary' '
+       git rev-list --first-parent --boundary HEAD^..
+'
+
+test_done
index 1337fa5a2209d489c43f0a34c95a89053d3fd8bf..0c002ab6951752bbf1d466ff5d0a4668835ca57c 100755 (executable)
@@ -408,6 +408,15 @@ test_expect_success 'checkout w/--track from non-branch HEAD fails' '
     test "z$(git rev-parse master^0)" = "z$(git rev-parse HEAD)"
 '
 
+test_expect_success 'checkout w/--track from tag fails' '
+    git checkout master^0 &&
+    test_must_fail git symbolic-ref HEAD &&
+    test_must_fail git checkout --track -b track frotz &&
+    test_must_fail git rev-parse --verify track &&
+    test_must_fail git symbolic-ref HEAD &&
+    test "z$(git rev-parse master^0)" = "z$(git rev-parse HEAD)"
+'
+
 test_expect_success 'detach a symbolic link HEAD' '
     git checkout master &&
     git config --bool core.prefersymlinkrefs yes &&
@@ -423,7 +432,6 @@ test_expect_success 'detach a symbolic link HEAD' '
 test_expect_success \
     'checkout with --track fakes a sensible -b <name>' '
     git update-ref refs/remotes/origin/koala/bear renamer &&
-    git update-ref refs/new/koala/bear renamer &&
 
     git checkout --track origin/koala/bear &&
     test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
@@ -439,12 +447,6 @@ test_expect_success \
 
     git checkout --track remotes/origin/koala/bear &&
     test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
-    test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)" &&
-
-    git checkout master && git branch -D koala/bear &&
-
-    git checkout --track refs/new/koala/bear &&
-    test "refs/heads/koala/bear" = "$(git symbolic-ref HEAD)" &&
     test "$(git rev-parse HEAD)" = "$(git rev-parse renamer)"
 '
 
index bfb4975e940e29edf3b06e5c074b8e963cfbbdcf..fa9d23aa31302f53cc1c39473492cf545ca5ae87 100755 (executable)
@@ -203,4 +203,56 @@ test_expect_success 'submodule init picks up merge' '
        )
 '
 
+test_expect_success 'submodule update --merge  - ignores --merge  for new submodules' '
+       (cd super &&
+        rm -rf submodule &&
+        git submodule update submodule &&
+        git status -s submodule >expect &&
+        rm -rf submodule &&
+        git submodule update --merge submodule &&
+        git status -s submodule >actual &&
+        test_cmp expect actual
+       )
+'
+
+test_expect_success 'submodule update --rebase - ignores --rebase for new submodules' '
+       (cd super &&
+        rm -rf submodule &&
+        git submodule update submodule &&
+        git status -s submodule >expect &&
+        rm -rf submodule &&
+        git submodule update --rebase submodule &&
+        git status -s submodule >actual &&
+        test_cmp expect actual
+       )
+'
+
+test_expect_success 'submodule update ignores update=merge config for new submodules' '
+       (cd super &&
+        rm -rf submodule &&
+        git submodule update submodule &&
+        git status -s submodule >expect &&
+        rm -rf submodule &&
+        git config submodule.submodule.update merge &&
+        git submodule update submodule &&
+        git status -s submodule >actual &&
+        git config --unset submodule.submodule.update &&
+        test_cmp expect actual
+       )
+'
+
+test_expect_success 'submodule update ignores update=rebase config for new submodules' '
+       (cd super &&
+        rm -rf submodule &&
+        git submodule update submodule &&
+        git status -s submodule >expect &&
+        rm -rf submodule &&
+        git config submodule.submodule.update rebase &&
+        git submodule update submodule &&
+        git status -s submodule >actual &&
+        git config --unset submodule.submodule.update &&
+        test_cmp expect actual
+       )
+'
+
 test_done
index d8ad25036f325ecdcc71257614e19b5e6ab2cdc5..e5be13c271c92ce7c51601ee1eaf966d849d8ae4 100755 (executable)
@@ -238,6 +238,10 @@ test_expect_success 'ensure "status --cached --recursive" preserves the --cached
                ) &&
                git submodule status --cached --recursive -- nested1 > ../actual
        ) &&
+       if test_have_prereq MINGW
+       then
+               dos2unix actual
+       fi &&
        test_cmp expect actual
 '
 
index 162527c2114955df2c55db9bf37db59d05fe75f8..5976f598fc7bf48120865eca3ceef74a151e717a 100755 (executable)
@@ -10,7 +10,12 @@ Tests for selected commit options.'
 . ./test-lib.sh
 
 commit_msg_is () {
-       test "`git log --pretty=format:%s%b -1`" = "$1"
+       expect=commit_msg_is.expect
+       actual=commit_msg_is.actual
+
+       printf "%s" "$(git log --pretty=format:%s%b -1)" >$expect &&
+       printf "%s" "$1" >$actual &&
+       test_cmp $expect $actual
 }
 
 # A sanity check to see if commit is working at all.
@@ -23,13 +28,21 @@ test_expect_success 'a basic commit in an empty tree should succeed' '
 test_expect_success 'nonexistent template file should return error' '
        echo changes >> foo &&
        git add foo &&
-       test_must_fail git commit --template "$PWD"/notexist
+       (
+               GIT_EDITOR="echo hello >\"\$1\"" &&
+               export GIT_EDITOR &&
+               test_must_fail git commit --template "$PWD"/notexist
+       )
 '
 
 test_expect_success 'nonexistent template file in config should return error' '
        git config commit.template "$PWD"/notexist &&
-       test_must_fail git commit &&
-       git config --unset commit.template
+       test_when_finished "git config --unset commit.template" &&
+       (
+               GIT_EDITOR="echo hello >\"\$1\"" &&
+               export GIT_EDITOR &&
+               test_must_fail git commit
+       )
 '
 
 # From now on we'll use a template file that exists.
index ff189624d48fb9f68997395d121d4e7056511245..5b4b694f1801f5c2284346f882cb496df9e7d74e 100755 (executable)
@@ -132,6 +132,18 @@ test_expect_success 'with hook (-c)' '
 
 '
 
+test_expect_success 'with hook (merge)' '
+
+       head=`git rev-parse HEAD` &&
+       git checkout -b other HEAD@{1} &&
+       echo "more" >> file &&
+       git add file &&
+       git commit -m other &&
+       git checkout - &&
+       git merge other &&
+       test "`git log -1 --pretty=format:%s`" = merge
+'
+
 cat > "$HOOK" <<'EOF'
 #!/bin/sh
 exit 1
index 77b69200297e222319b5701c62312bee27b62ce9..b61fd3c3c4c949785a595dac0fdcc48f4f7faf93 100755 (executable)
@@ -157,4 +157,33 @@ test_expect_success '--reset-author should be rejected without -c/-C/--amend' '
        test_must_fail git commit -a --reset-author -m done
 '
 
+test_expect_success 'commit respects CHERRY_PICK_HEAD and MERGE_MSG' '
+       echo "cherry-pick 1a" >>foo &&
+       test_tick &&
+       git commit -am "cherry-pick 1" --author="Cherry <cherry@pick.er>" &&
+       git tag cherry-pick-head &&
+       git rev-parse cherry-pick-head >.git/CHERRY_PICK_HEAD &&
+       echo "This is a MERGE_MSG" >.git/MERGE_MSG &&
+       echo "cherry-pick 1b" >>foo &&
+       test_tick &&
+       git commit -a &&
+       author_header cherry-pick-head >expect &&
+       author_header HEAD >actual &&
+       test_cmp expect actual &&
+
+       echo "This is a MERGE_MSG" >expect &&
+       message_body HEAD >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '--reset-author with CHERRY_PICK_HEAD' '
+       git rev-parse cherry-pick-head >.git/CHERRY_PICK_HEAD &&
+       echo "cherry-pick 2" >>foo &&
+       test_tick &&
+       git commit -am "cherry-pick 2" --reset-author &&
+       echo "author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE" >expect &&
+       author_header HEAD >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 4d5ce4e682c1ea69034c3f7789a8ac0c89b12466..5f731a1177267e76f19dbe1605a4d0f2e8e749bd 100755 (executable)
@@ -156,4 +156,20 @@ test_expect_success 'will not overwrite untracked file on unborn branch' '
        test_cmp important c0.c
 '
 
+test_expect_success 'set up unborn branch and content' '
+       git symbolic-ref HEAD refs/heads/unborn &&
+       rm -f .git/index &&
+       echo foo > tracked-file &&
+       git add tracked-file &&
+       echo bar > untracked-file
+'
+
+test_expect_failure 'will not clobber WT/index when merging into unborn' '
+       git merge master &&
+       grep foo tracked-file &&
+       git show :tracked-file >expect &&
+       grep foo expect &&
+       grep bar untracked-file
+'
+
 test_done
index d78bdec330cd8b9505aa92ff2e81e0f716b9a741..dc838c93bcb00a80ad56c4d1233009fe9220b90e 100755 (executable)
@@ -16,23 +16,33 @@ Testing basic merge tool invocation'
 test_expect_success 'setup' '
     git config rerere.enabled true &&
     echo master >file1 &&
+    echo master file11 >file11 &&
+    echo master file12 >file12 &&
+    echo master file13 >file13 &&
+    echo master file14 >file14 &&
     mkdir subdir &&
     echo master sub >subdir/file3 &&
-    git add file1 subdir/file3 &&
-    git commit -m "added file1" &&
+    git add file1 file1[1-4] subdir/file3 &&
+    git commit -m "add initial versions" &&
 
     git checkout -b branch1 master &&
     echo branch1 change >file1 &&
     echo branch1 newfile >file2 &&
+    echo branch1 change file11 >file11 &&
+    echo branch1 change file13 >file13 &&
     echo branch1 sub >subdir/file3 &&
-    git add file1 file2 subdir/file3 &&
+    git add file1 file11 file13 file2 subdir/file3 &&
+    git rm file12 &&
     git commit -m "branch1 changes" &&
 
     git checkout master &&
     echo master updated >file1 &&
     echo master new >file2 &&
+    echo master updated file12 >file12 &&
+    echo master updated file14 >file14 &&
     echo master new sub >subdir/file3 &&
-    git add file1 file2 subdir/file3 &&
+    git add file1 file12 file14 file2 subdir/file3 &&
+    git rm file11 &&
     git commit -m "master updates" &&
 
     git config merge.tool mytool &&
@@ -46,6 +56,8 @@ test_expect_success 'custom mergetool' '
     ( yes "" | git mergetool file1 >/dev/null 2>&1 ) &&
     ( yes "" | git mergetool file2 >/dev/null 2>&1 ) &&
     ( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) &&
+    ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) &&
+    ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) &&
     test "$(cat file1)" = "master updated" &&
     test "$(cat file2)" = "master new" &&
     test "$(cat subdir/file3)" = "master new sub" &&
@@ -59,6 +71,8 @@ test_expect_success 'mergetool crlf' '
     ( yes "" | git mergetool file1 >/dev/null 2>&1 ) &&
     ( yes "" | git mergetool file2 >/dev/null 2>&1 ) &&
     ( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) &&
+    ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) &&
+    ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) &&
     test "$(printf x | cat file1 -)" = "$(printf "master updated\r\nx")" &&
     test "$(printf x | cat file2 -)" = "$(printf "master new\r\nx")" &&
     test "$(printf x | cat subdir/file3 -)" = "$(printf "master new sub\r\nx")" &&
@@ -82,6 +96,8 @@ test_expect_success 'mergetool on file in parent dir' '
        cd subdir &&
        ( yes "" | git mergetool ../file1 >/dev/null 2>&1 ) &&
        ( yes "" | git mergetool ../file2 >/dev/null 2>&1 ) &&
+       ( yes "d" | git mergetool ../file11 >/dev/null 2>&1 ) &&
+       ( yes "d" | git mergetool ../file12 >/dev/null 2>&1 ) &&
        test "$(cat ../file1)" = "master updated" &&
        test "$(cat ../file2)" = "master new" &&
        git commit -m "branch1 resolved with mergetool - subdir"
@@ -92,6 +108,8 @@ test_expect_success 'mergetool skips autoresolved' '
     git checkout -b test4 branch1 &&
     test_must_fail git merge master &&
     test -n "$(git ls-files -u)" &&
+    ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) &&
+    ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) &&
     output="$(git mergetool --no-prompt)" &&
     test "$output" = "No files need merging" &&
     git reset --hard
@@ -102,13 +120,23 @@ test_expect_success 'mergetool merges all from subdir' '
        cd subdir &&
        git config rerere.enabled false &&
        test_must_fail git merge master &&
-       git mergetool --no-prompt &&
+       ( yes "d" "d" | git mergetool --no-prompt ) &&
        test "$(cat ../file1)" = "master updated" &&
        test "$(cat ../file2)" = "master new" &&
        test "$(cat file3)" = "master new sub" &&
-       git add ../file1 ../file2 file3 &&
        git commit -m "branch2 resolved by mergetool from subdir"
     )
 '
 
+test_expect_success 'mergetool skips resolved paths when rerere is active' '
+    git config rerere.enabled true &&
+    rm -rf .git/rr-cache &&
+    git checkout -b test5 branch1
+    test_must_fail git merge master >/dev/null 2>&1 &&
+    ( yes "d" "d" | git mergetool --no-prompt >/dev/null 2>&1 ) &&
+    output="$(yes "n" | git mergetool --no-prompt)" &&
+    test "$output" = "No files need merging" &&
+    git reset --hard
+'
+
 test_done
index c8777589ca1c89825b570cfc05405a39df39aaba..dbc6cd8a775a43efbd8fdf433958ccd090b6e3ab 100755 (executable)
@@ -182,6 +182,24 @@ do
                test_cmp expected actual
        '
 
+       test_expect_success "grep --max-depth 0 -- . t $L" '
+               {
+                       echo ${HC}t/v:1:vvv
+                       echo ${HC}v:1:vvv
+               } >expected &&
+               git grep --max-depth 0 -n -e vvv $H -- . t >actual &&
+               test_cmp expected actual
+       '
+
+       test_expect_success "grep --max-depth 0 -- t . $L" '
+               {
+                       echo ${HC}t/v:1:vvv
+                       echo ${HC}v:1:vvv
+               } >expected &&
+               git grep --max-depth 0 -n -e vvv $H -- t . >actual &&
+               test_cmp expected actual
+       '
+
 done
 
 cat >expected <<EOF
@@ -285,6 +303,11 @@ test_expect_success 'grep -f, ignore empty lines' '
        test_cmp expected actual
 '
 
+test_expect_success 'grep -f, ignore empty lines, read patterns from stdin' '
+       git grep -f - <patterns >actual &&
+       test_cmp expected actual
+'
+
 cat >expected <<EOF
 y:y yy
 --
index ea64cd8d0f02a3a08dca7742a29331c85e7da384..32ec82ad678d56bbf27f525fc8588b3391d9117d 100755 (executable)
@@ -25,7 +25,8 @@ test_expect_success 'setup ' '
        echo "bin: test 1 version 2" >one.bin &&
        echo "bin: test number 2 version 2" >>two.bin &&
        if test_have_prereq SYMLINKS; then
-               ln -sf two.bin symlink.bin
+               rm symlink.bin &&
+               ln -s two.bin symlink.bin
        fi &&
        GIT_AUTHOR_NAME=Number2 git commit -a -m Second --date="2010-01-01 20:00:00"
 '
index 88a9751dd3c73a39a15ec3d18d3dddb7790706bb..5a6a4b9b7a6e6abbb9570ddceaac68baf5c2690b 100755 (executable)
@@ -9,6 +9,30 @@ reinit_git () {
        git init
 }
 
+properties () {
+       while test "$#" -ne 0
+       do
+               property="$1" &&
+               value="$2" &&
+               printf "%s\n" "K ${#property}" &&
+               printf "%s\n" "$property" &&
+               printf "%s\n" "V ${#value}" &&
+               printf "%s\n" "$value" &&
+               shift 2 ||
+               return 1
+       done
+}
+
+text_no_props () {
+       text="$1
+" &&
+       printf "%s\n" "Prop-content-length: 10" &&
+       printf "%s\n" "Text-content-length: ${#text}" &&
+       printf "%s\n" "Content-length: $((${#text} + 10))" &&
+       printf "%s\n" "" "PROPS-END" &&
+       printf "%s\n" "$text"
+}
+
 >empty
 
 test_expect_success 'empty dump' '
@@ -18,13 +42,686 @@ test_expect_success 'empty dump' '
        git fast-import <stream
 '
 
-test_expect_success 'v3 dumps not supported' '
+test_expect_success 'v4 dumps not supported' '
        reinit_git &&
-       echo "SVN-fs-dump-format-version: 3" >input &&
-       test_must_fail test-svn-fe input >stream &&
+       echo "SVN-fs-dump-format-version: 4" >v4.dump &&
+       test_must_fail test-svn-fe v4.dump >stream &&
        test_cmp empty stream
 '
 
+test_expect_failure 'empty revision' '
+       reinit_git &&
+       printf "rev <nobody, nobody@local>: %s\n" "" "" >expect &&
+       cat >emptyrev.dump <<-\EOF &&
+       SVN-fs-dump-format-version: 3
+
+       Revision-number: 1
+       Prop-content-length: 0
+       Content-length: 0
+
+       Revision-number: 2
+       Prop-content-length: 0
+       Content-length: 0
+
+       EOF
+       test-svn-fe emptyrev.dump >stream &&
+       git fast-import <stream &&
+       git log -p --format="rev <%an, %ae>: %s" HEAD >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'empty properties' '
+       reinit_git &&
+       printf "rev <nobody, nobody@local>: %s\n" "" "" >expect &&
+       cat >emptyprop.dump <<-\EOF &&
+       SVN-fs-dump-format-version: 3
+
+       Revision-number: 1
+       Prop-content-length: 10
+       Content-length: 10
+
+       PROPS-END
+
+       Revision-number: 2
+       Prop-content-length: 10
+       Content-length: 10
+
+       PROPS-END
+       EOF
+       test-svn-fe emptyprop.dump >stream &&
+       git fast-import <stream &&
+       git log -p --format="rev <%an, %ae>: %s" HEAD >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'author name and commit message' '
+       reinit_git &&
+       echo "<author@example.com, author@example.com@local>" >expect.author &&
+       cat >message <<-\EOF &&
+       A concise summary of the change
+
+       A detailed description of the change, why it is needed, what
+       was broken and why applying this is the best course of action.
+
+       * file.c
+           Details pertaining to an individual file.
+       EOF
+       {
+               properties \
+                       svn:author author@example.com \
+                       svn:log "$(cat message)" &&
+               echo PROPS-END
+       } >props &&
+       {
+               echo "SVN-fs-dump-format-version: 3" &&
+               echo &&
+               echo "Revision-number: 1" &&
+               echo Prop-content-length: $(wc -c <props) &&
+               echo Content-length: $(wc -c <props) &&
+               echo &&
+               cat props
+       } >log.dump &&
+       test-svn-fe log.dump >stream &&
+       git fast-import <stream &&
+       git log -p --format="%B" HEAD >actual.log &&
+       git log --format="<%an, %ae>" >actual.author &&
+       test_cmp message actual.log &&
+       test_cmp expect.author actual.author
+'
+
+test_expect_success 'unsupported properties are ignored' '
+       reinit_git &&
+       echo author >expect &&
+       cat >extraprop.dump <<-\EOF &&
+       SVN-fs-dump-format-version: 3
+
+       Revision-number: 1
+       Prop-content-length: 56
+       Content-length: 56
+
+       K 8
+       nonsense
+       V 1
+       y
+       K 10
+       svn:author
+       V 6
+       author
+       PROPS-END
+       EOF
+       test-svn-fe extraprop.dump >stream &&
+       git fast-import <stream &&
+       git log -p --format=%an HEAD >actual &&
+       test_cmp expect actual
+'
+
+test_expect_failure 'timestamp and empty file' '
+       echo author@example.com >expect.author &&
+       echo 1999-01-01 >expect.date &&
+       echo file >expect.files &&
+       reinit_git &&
+       {
+               properties \
+                       svn:author author@example.com \
+                       svn:date "1999-01-01T00:01:002.000000Z" \
+                       svn:log "add empty file" &&
+               echo PROPS-END
+       } >props &&
+       {
+               cat <<-EOF &&
+               SVN-fs-dump-format-version: 3
+
+               Revision-number: 1
+               EOF
+               echo Prop-content-length: $(wc -c <props) &&
+               echo Content-length: $(wc -c <props) &&
+               echo &&
+               cat props &&
+               cat <<-\EOF
+
+               Node-path: empty-file
+               Node-kind: file
+               Node-action: add
+               Content-length: 0
+
+               EOF
+       } >emptyfile.dump &&
+       test-svn-fe emptyfile.dump >stream &&
+       git fast-import <stream &&
+       git log --format=%an HEAD >actual.author &&
+       git log --date=short --format=%ad HEAD >actual.date &&
+       git ls-tree -r --name-only HEAD >actual.files &&
+       test_cmp expect.author actual.author &&
+       test_cmp expect.date actual.date &&
+       test_cmp expect.files actual.files &&
+       git checkout HEAD empty-file &&
+       test_cmp empty file
+'
+
+test_expect_success 'directory with files' '
+       reinit_git &&
+       printf "%s\n" directory/file1 directory/file2 >expect.files &&
+       echo hi >hi &&
+       echo hello >hello &&
+       {
+               properties \
+                       svn:author author@example.com \
+                       svn:date "1999-02-01T00:01:002.000000Z" \
+                       svn:log "add directory with some files in it" &&
+               echo PROPS-END
+       } >props &&
+       {
+               cat <<-EOF &&
+               SVN-fs-dump-format-version: 3
+
+               Revision-number: 1
+               EOF
+               echo Prop-content-length: $(wc -c <props) &&
+               echo Content-length: $(wc -c <props) &&
+               echo &&
+               cat props &&
+               cat <<-\EOF &&
+
+               Node-path: directory
+               Node-kind: dir
+               Node-action: add
+               Prop-content-length: 10
+               Content-length: 10
+
+               PROPS-END
+
+               Node-path: directory/file1
+               Node-kind: file
+               Node-action: add
+               EOF
+               text_no_props hello &&
+               cat <<-\EOF &&
+               Node-path: directory/file2
+               Node-kind: file
+               Node-action: add
+               EOF
+               text_no_props hi
+       } >directory.dump &&
+       test-svn-fe directory.dump >stream &&
+       git fast-import <stream &&
+
+       git ls-tree -r --name-only HEAD >actual.files &&
+       git checkout HEAD directory &&
+       test_cmp expect.files actual.files &&
+       test_cmp hello directory/file1 &&
+       test_cmp hi directory/file2
+'
+
+test_expect_success 'node without action' '
+       cat >inaction.dump <<-\EOF &&
+       SVN-fs-dump-format-version: 3
+
+       Revision-number: 1
+       Prop-content-length: 10
+       Content-length: 10
+
+       PROPS-END
+
+       Node-path: directory
+       Node-kind: dir
+       Prop-content-length: 10
+       Content-length: 10
+
+       PROPS-END
+       EOF
+       test_must_fail test-svn-fe inaction.dump
+'
+
+test_expect_success 'action: add node without text' '
+       cat >textless.dump <<-\EOF &&
+       SVN-fs-dump-format-version: 3
+
+       Revision-number: 1
+       Prop-content-length: 10
+       Content-length: 10
+
+       PROPS-END
+
+       Node-path: textless
+       Node-kind: file
+       Node-action: add
+       Prop-content-length: 10
+       Content-length: 10
+
+       PROPS-END
+       EOF
+       test_must_fail test-svn-fe textless.dump
+'
+
+test_expect_failure 'change file mode but keep old content' '
+       reinit_git &&
+       cat >expect <<-\EOF &&
+       OBJID
+       :120000 100644 OBJID OBJID T    greeting
+       OBJID
+       :100644 120000 OBJID OBJID T    greeting
+       OBJID
+       :000000 100644 OBJID OBJID A    greeting
+       EOF
+       echo "link hello" >expect.blob &&
+       echo hello >hello &&
+       cat >filemode.dump <<-\EOF &&
+       SVN-fs-dump-format-version: 3
+
+       Revision-number: 1
+       Prop-content-length: 10
+       Content-length: 10
+
+       PROPS-END
+
+       Node-path: greeting
+       Node-kind: file
+       Node-action: add
+       Prop-content-length: 10
+       Text-content-length: 11
+       Content-length: 21
+
+       PROPS-END
+       link hello
+
+       Revision-number: 2
+       Prop-content-length: 10
+       Content-length: 10
+
+       PROPS-END
+
+       Node-path: greeting
+       Node-kind: file
+       Node-action: change
+       Prop-content-length: 33
+       Content-length: 33
+
+       K 11
+       svn:special
+       V 1
+       *
+       PROPS-END
+
+       Revision-number: 3
+       Prop-content-length: 10
+       Content-length: 10
+
+       PROPS-END
+
+       Node-path: greeting
+       Node-kind: file
+       Node-action: change
+       Prop-content-length: 10
+       Content-length: 10
+
+       PROPS-END
+       EOF
+       test-svn-fe filemode.dump >stream &&
+       git fast-import <stream &&
+       {
+               git rev-list HEAD |
+               git diff-tree --root --stdin |
+               sed "s/$_x40/OBJID/g"
+       } >actual &&
+       git show HEAD:greeting >actual.blob &&
+       git show HEAD^:greeting >actual.target &&
+       test_cmp expect actual &&
+       test_cmp expect.blob actual.blob &&
+       test_cmp hello actual.target
+'
+
+test_expect_success 'change file mode and reiterate content' '
+       reinit_git &&
+       cat >expect <<-\EOF &&
+       OBJID
+       :120000 100644 OBJID OBJID T    greeting
+       OBJID
+       :100644 120000 OBJID OBJID T    greeting
+       OBJID
+       :000000 100644 OBJID OBJID A    greeting
+       EOF
+       echo "link hello" >expect.blob &&
+       echo hello >hello &&
+       cat >filemode.dump <<-\EOF &&
+       SVN-fs-dump-format-version: 3
+
+       Revision-number: 1
+       Prop-content-length: 10
+       Content-length: 10
+
+       PROPS-END
+
+       Node-path: greeting
+       Node-kind: file
+       Node-action: add
+       Prop-content-length: 10
+       Text-content-length: 11
+       Content-length: 21
+
+       PROPS-END
+       link hello
+
+       Revision-number: 2
+       Prop-content-length: 10
+       Content-length: 10
+
+       PROPS-END
+
+       Node-path: greeting
+       Node-kind: file
+       Node-action: change
+       Prop-content-length: 33
+       Text-content-length: 11
+       Content-length: 44
+
+       K 11
+       svn:special
+       V 1
+       *
+       PROPS-END
+       link hello
+
+       Revision-number: 3
+       Prop-content-length: 10
+       Content-length: 10
+
+       PROPS-END
+
+       Node-path: greeting
+       Node-kind: file
+       Node-action: change
+       Prop-content-length: 10
+       Text-content-length: 11
+       Content-length: 21
+
+       PROPS-END
+       link hello
+       EOF
+       test-svn-fe filemode.dump >stream &&
+       git fast-import <stream &&
+       {
+               git rev-list HEAD |
+               git diff-tree --root --stdin |
+               sed "s/$_x40/OBJID/g"
+       } >actual &&
+       git show HEAD:greeting >actual.blob &&
+       git show HEAD^:greeting >actual.target &&
+       test_cmp expect actual &&
+       test_cmp expect.blob actual.blob &&
+       test_cmp hello actual.target
+'
+
+test_expect_success 'deltas not supported' '
+       {
+               # (old) h + (inline) ello + (old) \n
+               printf "SVNQ%b%b%s" "Q\003\006\005\004" "\001Q\0204\001\002" "ello" |
+               q_to_nul
+       } >delta &&
+       {
+               properties \
+                       svn:author author@example.com \
+                       svn:date "1999-01-05T00:01:002.000000Z" \
+                       svn:log "add greeting" &&
+               echo PROPS-END
+       } >props &&
+       {
+               properties \
+                       svn:author author@example.com \
+                       svn:date "1999-01-06T00:01:002.000000Z" \
+                       svn:log "change it" &&
+               echo PROPS-END
+       } >props2 &&
+       {
+               echo SVN-fs-dump-format-version: 3 &&
+               echo &&
+               echo Revision-number: 1 &&
+               echo Prop-content-length: $(wc -c <props) &&
+               echo Content-length: $(wc -c <props) &&
+               echo &&
+               cat props &&
+               cat <<-\EOF &&
+
+               Node-path: hello
+               Node-kind: file
+               Node-action: add
+               Prop-content-length: 10
+               Text-content-length: 3
+               Content-length: 13
+
+               PROPS-END
+               hi
+
+               EOF
+               echo Revision-number: 2 &&
+               echo Prop-content-length: $(wc -c <props2) &&
+               echo Content-length: $(wc -c <props2) &&
+               echo &&
+               cat props2 &&
+               cat <<-\EOF &&
+
+               Node-path: hello
+               Node-kind: file
+               Node-action: change
+               Text-delta: true
+               Prop-content-length: 10
+               EOF
+               echo Text-content-length: $(wc -c <delta) &&
+               echo Content-length: $((10 + $(wc -c <delta))) &&
+               echo &&
+               echo PROPS-END &&
+               cat delta
+       } >delta.dump &&
+       test_must_fail test-svn-fe delta.dump
+'
+
+test_expect_success 'property deltas supported' '
+       reinit_git &&
+       cat >expect <<-\EOF &&
+       OBJID
+       :100755 100644 OBJID OBJID M    script.sh
+       EOF
+       {
+               properties \
+                       svn:author author@example.com \
+                       svn:date "1999-03-06T00:01:002.000000Z" \
+                       svn:log "make an executable, or chmod -x it" &&
+               echo PROPS-END
+       } >revprops &&
+       {
+               echo SVN-fs-dump-format-version: 3 &&
+               echo &&
+               echo Revision-number: 1 &&
+               echo Prop-content-length: $(wc -c <revprops) &&
+               echo Content-length: $(wc -c <revprops) &&
+               echo &&
+               cat revprops &&
+               echo &&
+               cat <<-\EOF &&
+               Node-path: script.sh
+               Node-kind: file
+               Node-action: add
+               Text-content-length: 0
+               Prop-content-length: 39
+               Content-length: 39
+
+               K 14
+               svn:executable
+               V 4
+               true
+               PROPS-END
+
+               EOF
+               echo Revision-number: 2 &&
+               echo Prop-content-length: $(wc -c <revprops) &&
+               echo Content-length: $(wc -c <revprops) &&
+               echo &&
+               cat revprops &&
+               echo &&
+               cat <<-\EOF
+               Node-path: script.sh
+               Node-kind: file
+               Node-action: change
+               Prop-delta: true
+               Prop-content-length: 30
+               Content-length: 30
+
+               D 14
+               svn:executable
+               PROPS-END
+               EOF
+       } >propdelta.dump &&
+       test-svn-fe propdelta.dump >stream &&
+       git fast-import <stream &&
+       {
+               git rev-list HEAD |
+               git diff-tree --stdin |
+               sed "s/$_x40/OBJID/g"
+       } >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'properties on /' '
+       reinit_git &&
+       cat <<-\EOF >expect &&
+       OBJID
+       OBJID
+       :000000 100644 OBJID OBJID A    greeting
+       EOF
+       sed -e "s/X$//" <<-\EOF >changeroot.dump &&
+       SVN-fs-dump-format-version: 3
+
+       Revision-number: 1
+       Prop-content-length: 10
+       Content-length: 10
+
+       PROPS-END
+
+       Node-path: greeting
+       Node-kind: file
+       Node-action: add
+       Text-content-length: 0
+       Prop-content-length: 10
+       Content-length: 10
+
+       PROPS-END
+
+       Revision-number: 2
+       Prop-content-length: 10
+       Content-length: 10
+
+       PROPS-END
+
+       Node-path: X
+       Node-kind: dir
+       Node-action: change
+       Prop-delta: true
+       Prop-content-length: 43
+       Content-length: 43
+
+       K 10
+       svn:ignore
+       V 11
+       build-area
+
+       PROPS-END
+       EOF
+       test-svn-fe changeroot.dump >stream &&
+       git fast-import <stream &&
+       {
+               git rev-list HEAD |
+               git diff-tree --root --always --stdin |
+               sed "s/$_x40/OBJID/g"
+       } >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'deltas for typechange' '
+       reinit_git &&
+       cat >expect <<-\EOF &&
+       OBJID
+       :120000 100644 OBJID OBJID T    test-file
+       OBJID
+       :100755 120000 OBJID OBJID T    test-file
+       OBJID
+       :000000 100755 OBJID OBJID A    test-file
+       EOF
+       cat >deleteprop.dump <<-\EOF &&
+       SVN-fs-dump-format-version: 3
+
+       Revision-number: 1
+       Prop-content-length: 10
+       Content-length: 10
+
+       PROPS-END
+
+       Node-path: test-file
+       Node-kind: file
+       Node-action: add
+       Prop-delta: true
+       Prop-content-length: 35
+       Text-content-length: 17
+       Content-length: 52
+
+       K 14
+       svn:executable
+       V 0
+
+       PROPS-END
+       link testing 123
+
+       Revision-number: 2
+       Prop-content-length: 10
+       Content-length: 10
+
+       PROPS-END
+
+       Node-path: test-file
+       Node-kind: file
+       Node-action: change
+       Prop-delta: true
+       Prop-content-length: 53
+       Text-content-length: 17
+       Content-length: 70
+
+       K 11
+       svn:special
+       V 1
+       *
+       D 14
+       svn:executable
+       PROPS-END
+       link testing 231
+
+       Revision-number: 3
+       Prop-content-length: 10
+       Content-length: 10
+
+       PROPS-END
+
+       Node-path: test-file
+       Node-kind: file
+       Node-action: change
+       Prop-delta: true
+       Prop-content-length: 27
+       Text-content-length: 17
+       Content-length: 44
+
+       D 11
+       svn:special
+       PROPS-END
+       link testing 321
+       EOF
+       test-svn-fe deleteprop.dump >stream &&
+       git fast-import <stream &&
+       {
+               git rev-list HEAD |
+               git diff-tree --root --stdin |
+               sed "s/$_x40/OBJID/g"
+       } >actual &&
+       test_cmp expect actual
+'
+
+
 test_expect_success 'set up svn repo' '
        svnconf=$PWD/svnconf &&
        mkdir -p "$svnconf" &&
index ec0a10661409d24c77bf2061bd8a554bfb565d74..b324c491c52eb0fa39d713cc5f227d134c1adb01 100755 (executable)
@@ -96,7 +96,6 @@ test_expect_success 'fresh clone with svn.authors-file in config' '
                rm -r "$GIT_DIR" &&
                test x = x"$(git config svn.authorsfile)" &&
                test_config="$HOME"/.gitconfig &&
-               unset GIT_CONFIG_NOGLOBAL &&
                unset GIT_DIR &&
                unset GIT_CONFIG &&
                git config --global \
index 986bc14d58c30201e75f3d95d9b8245e997b99e9..6b1ba6c858562b7c085951fb1d69d4d2371e866c 100755 (executable)
@@ -42,6 +42,14 @@ echo "$@"'
 
 >empty
 
+test_expect_success 'setup: have pipes?' '
+       rm -f frob &&
+       if mkfifo frob
+       then
+               test_set_prereq PIPE
+       fi
+'
+
 ###
 ### series A
 ###
@@ -898,6 +906,77 @@ test_expect_success \
         git diff-tree -C --find-copies-harder -r N4^ N4 >actual &&
         compare_diff_raw expect actual'
 
+test_expect_success PIPE 'N: read and copy directory' '
+       cat >expect <<-\EOF
+       :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100   file2/newf      file3/newf
+       :100644 100644 7123f7f44e39be127c5eb701e5968176ee9d78b1 7123f7f44e39be127c5eb701e5968176ee9d78b1 C100   file2/oldf      file3/oldf
+       EOF
+       git update-ref -d refs/heads/N4 &&
+       rm -f backflow &&
+       mkfifo backflow &&
+       (
+               exec <backflow &&
+               cat <<-EOF &&
+               commit refs/heads/N4
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               copy by tree hash, part 2
+               COMMIT
+
+               from refs/heads/branch^0
+               ls "file2"
+               EOF
+               read mode type tree filename &&
+               echo "M 040000 $tree file3"
+       ) |
+       git fast-import --cat-blob-fd=3 3>backflow &&
+       git diff-tree -C --find-copies-harder -r N4^ N4 >actual &&
+       compare_diff_raw expect actual
+'
+
+test_expect_success PIPE 'N: empty directory reads as missing' '
+       cat <<-\EOF >expect &&
+       OBJNAME
+       :000000 100644 OBJNAME OBJNAME A        unrelated
+       EOF
+       echo "missing src" >expect.response &&
+       git update-ref -d refs/heads/read-empty &&
+       rm -f backflow &&
+       mkfifo backflow &&
+       (
+               exec <backflow &&
+               cat <<-EOF &&
+               commit refs/heads/read-empty
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               read "empty" (missing) directory
+               COMMIT
+
+               M 100644 inline src/greeting
+               data <<BLOB
+               hello
+               BLOB
+               C src/greeting dst1/non-greeting
+               C src/greeting unrelated
+               # leave behind "empty" src directory
+               D src/greeting
+               ls "src"
+               EOF
+               read -r line &&
+               printf "%s\n" "$line" >response &&
+               cat <<-\EOF
+               D dst1
+               D dst2
+               EOF
+       ) |
+       git fast-import --cat-blob-fd=3 3>backflow &&
+       test_cmp expect.response response &&
+       git rev-list read-empty |
+       git diff-tree -r --root --stdin |
+       sed "s/$_x40/OBJNAME/g" >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success \
        'N: copy root directory by tree hash' \
        'cat >expect <<-\EOF &&
@@ -1748,6 +1827,61 @@ test_expect_success \
     'cat input | git fast-import --export-marks=other.marks &&
     grep :1 other.marks'
 
+test_expect_success 'R: catch typo in marks file name' '
+       test_must_fail git fast-import --import-marks=nonexistent.marks </dev/null &&
+       echo "feature import-marks=nonexistent.marks" |
+       test_must_fail git fast-import
+'
+
+test_expect_success 'R: import and output marks can be the same file' '
+       rm -f io.marks &&
+       blob=$(echo hi | git hash-object --stdin) &&
+       cat >expect <<-EOF &&
+       :1 $blob
+       :2 $blob
+       EOF
+       git fast-import --export-marks=io.marks <<-\EOF &&
+       blob
+       mark :1
+       data 3
+       hi
+
+       EOF
+       git fast-import --import-marks=io.marks --export-marks=io.marks <<-\EOF &&
+       blob
+       mark :2
+       data 3
+       hi
+
+       EOF
+       test_cmp expect io.marks
+'
+
+test_expect_success 'R: --import-marks=foo --output-marks=foo to create foo fails' '
+       rm -f io.marks &&
+       test_must_fail git fast-import --import-marks=io.marks --export-marks=io.marks <<-\EOF
+       blob
+       mark :1
+       data 3
+       hi
+
+       EOF
+'
+
+test_expect_success 'R: --import-marks-if-exists' '
+       rm -f io.marks &&
+       blob=$(echo hi | git hash-object --stdin) &&
+       echo ":1 $blob" >expect &&
+       git fast-import --import-marks-if-exists=io.marks --export-marks=io.marks <<-\EOF &&
+       blob
+       mark :1
+       data 3
+       hi
+
+       EOF
+       test_cmp expect io.marks
+'
+
 cat >input << EOF
 feature import-marks=marks.out
 feature export-marks=marks.new
@@ -1806,6 +1940,11 @@ test_expect_success 'R: feature no-relative-marks should be honoured' '
     test_cmp marks.new non-relative.out
 '
 
+test_expect_success 'R: feature ls supported' '
+       echo "feature ls" |
+       git fast-import
+'
+
 test_expect_success 'R: feature cat-blob supported' '
        echo "feature cat-blob" |
        git fast-import
@@ -1931,14 +2070,6 @@ test_expect_success 'R: print two blobs to stdout' '
        test_cmp expect actual
 '
 
-test_expect_success 'setup: have pipes?' '
-       rm -f frob &&
-       if mkfifo frob
-       then
-               test_set_prereq PIPE
-       fi
-'
-
 test_expect_success PIPE 'R: copy using cat-file' '
        expect_id=$(git hash-object big) &&
        expect_len=$(wc -c <big) &&
index 7cf8cd8a2fed2191b31082c92a95598a3e06513d..463254c72734beaf74948b6c424367ef4fea9d1a 100755 (executable)
@@ -120,6 +120,7 @@ test_expect_success 'add notes with simple M command' '
 
 test_tick
 cat >input <<INPUT_END
+feature notes
 commit refs/notes/test
 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
 data <<COMMIT
index 21cd286bb7abf33c944a8758ce8d702e83ca2022..afac5b56a87f3dcc6467b8ad260e1b59d041eb03 100755 (executable)
@@ -18,42 +18,34 @@ or warnings to log.'
 test_expect_success \
        'no commits: projects_list (implicit)' \
        'gitweb_run'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'no commits: projects_index' \
        'gitweb_run "a=project_index"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'no commits: .git summary (implicit)' \
        'gitweb_run "p=.git"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'no commits: .git commit (implicit HEAD)' \
        'gitweb_run "p=.git;a=commit"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'no commits: .git commitdiff (implicit HEAD)' \
        'gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'no commits: .git tree (implicit HEAD)' \
        'gitweb_run "p=.git;a=tree"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'no commits: .git heads' \
        'gitweb_run "p=.git;a=heads"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'no commits: .git tags' \
        'gitweb_run "p=.git;a=tags"'
-test_debug 'cat gitweb.log'
 
 
 # ----------------------------------------------------------------------
@@ -69,52 +61,42 @@ test_expect_success \
 test_expect_success \
        'projects_list (implicit)' \
        'gitweb_run'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'projects_index' \
        'gitweb_run "a=project_index"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        '.git summary (implicit)' \
        'gitweb_run "p=.git"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        '.git commit (implicit HEAD)' \
        'gitweb_run "p=.git;a=commit"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        '.git commitdiff (implicit HEAD, root commit)' \
        'gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        '.git commitdiff_plain (implicit HEAD, root commit)' \
        'gitweb_run "p=.git;a=commitdiff_plain"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        '.git commit (HEAD)' \
        'gitweb_run "p=.git;a=commit;h=HEAD"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        '.git tree (implicit HEAD)' \
        'gitweb_run "p=.git;a=tree"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        '.git blob (file)' \
        'gitweb_run "p=.git;a=blob;f=file"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        '.git blob_plain (file)' \
        'gitweb_run "p=.git;a=blob_plain;f=file"'
-test_debug 'cat gitweb.log'
 
 # ----------------------------------------------------------------------
 # nonexistent objects
@@ -122,37 +104,30 @@ test_debug 'cat gitweb.log'
 test_expect_success \
        '.git commit (non-existent)' \
        'gitweb_run "p=.git;a=commit;h=non-existent"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        '.git commitdiff (non-existent)' \
        'gitweb_run "p=.git;a=commitdiff;h=non-existent"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        '.git commitdiff (non-existent vs HEAD)' \
        'gitweb_run "p=.git;a=commitdiff;hp=non-existent;h=HEAD"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        '.git tree (0000000000000000000000000000000000000000)' \
        'gitweb_run "p=.git;a=tree;h=0000000000000000000000000000000000000000"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        '.git tag (0000000000000000000000000000000000000000)' \
        'gitweb_run "p=.git;a=tag;h=0000000000000000000000000000000000000000"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        '.git blob (non-existent)' \
        'gitweb_run "p=.git;a=blob;f=non-existent"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        '.git blob_plain (non-existent)' \
        'gitweb_run "p=.git;a=blob_plain;f=non-existent"'
-test_debug 'cat gitweb.log'
 
 
 # ----------------------------------------------------------------------
@@ -161,7 +136,6 @@ test_debug 'cat gitweb.log'
 test_expect_success \
        'commitdiff(0): root' \
        'gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'commitdiff(0): file added' \
@@ -169,21 +143,18 @@ test_expect_success \
         git add new_file &&
         git commit -a -m "File added." &&
         gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'commitdiff(0): mode change' \
        'test_chmod +x new_file &&
         git commit -a -m "Mode changed." &&
         gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'commitdiff(0): file renamed' \
        'git mv new_file renamed_file &&
         git commit -a -m "File renamed." &&
         gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
 
 test_expect_success SYMLINKS \
        'commitdiff(0): file to symlink' \
@@ -191,7 +162,6 @@ test_expect_success SYMLINKS \
         ln -s file renamed_file &&
         git commit -a -m "File to symlink." &&
         gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'commitdiff(0): file deleted' \
@@ -199,7 +169,6 @@ test_expect_success \
         rm -f renamed_file &&
         git commit -a -m "File removed." &&
         gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'commitdiff(0): file copied / new file' \
@@ -207,7 +176,6 @@ test_expect_success \
         git add file2 &&
         git commit -a -m "File copied." &&
         gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'commitdiff(0): mode change and modified' \
@@ -215,7 +183,6 @@ test_expect_success \
         test_chmod +x file2 &&
         git commit -a -m "Mode change and modification." &&
         gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'commitdiff(0): renamed and modified' \
@@ -233,7 +200,6 @@ EOF
         echo "Propter nomen suum." >> file3 &&
         git commit -a -m "File rename and modification." &&
         gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'commitdiff(0): renamed, mode change and modified' \
@@ -242,7 +208,6 @@ test_expect_success \
         test_chmod +x file2 &&
         git commit -a -m "File rename, mode change and modification." &&
         gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
 
 # ----------------------------------------------------------------------
 # commitdiff testing (taken from t4114-apply-typechange.sh)
@@ -279,42 +244,34 @@ test_expect_success SYMLINKS 'setup typechange commits' '
 test_expect_success \
        'commitdiff(2): file renamed from foo to foo/baz' \
        'gitweb_run "p=.git;a=commitdiff;hp=initial;h=foo-baz-renamed-from-foo"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'commitdiff(2): file renamed from foo/baz to foo' \
        'gitweb_run "p=.git;a=commitdiff;hp=foo-baz-renamed-from-foo;h=initial"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'commitdiff(2): directory becomes file' \
        'gitweb_run "p=.git;a=commitdiff;hp=foo-becomes-a-directory;h=initial"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'commitdiff(2): file becomes directory' \
        'gitweb_run "p=.git;a=commitdiff;hp=initial;h=foo-becomes-a-directory"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'commitdiff(2): file becomes symlink' \
        'gitweb_run "p=.git;a=commitdiff;hp=initial;h=foo-symlinked-to-bar"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'commitdiff(2): symlink becomes file' \
        'gitweb_run "p=.git;a=commitdiff;hp=foo-symlinked-to-bar;h=foo-back-to-file"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'commitdiff(2): symlink becomes directory' \
        'gitweb_run "p=.git;a=commitdiff;hp=foo-symlinked-to-bar;h=foo-becomes-a-directory"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'commitdiff(2): directory becomes symlink' \
        'gitweb_run "p=.git;a=commitdiff;hp=foo-becomes-a-directory;h=foo-symlinked-to-bar"'
-test_debug 'cat gitweb.log'
 
 # ----------------------------------------------------------------------
 # commit, commitdiff: merge, large
@@ -330,12 +287,10 @@ test_expect_success \
 test_expect_success \
        'commit(0): merge commit' \
        'gitweb_run "p=.git;a=commit"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'commitdiff(0): merge commit' \
        'gitweb_run "p=.git;a=commitdiff"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'Prepare large commit' \
@@ -371,12 +326,10 @@ test_expect_success \
 test_expect_success \
        'commit(1): large commit' \
        'gitweb_run "p=.git;a=commit;h=b"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'commitdiff(1): large commit' \
        'gitweb_run "p=.git;a=commitdiff;h=b"'
-test_debug 'cat gitweb.log'
 
 # ----------------------------------------------------------------------
 # tags testing
@@ -394,17 +347,14 @@ test_expect_success \
         git tag lightweight/tag-tree HEAD^{tree} &&
         git tag lightweight/tag-blob HEAD:file &&
         gitweb_run "p=.git;a=tags"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'tag: Tag to commit object' \
        'gitweb_run "p=.git;a=tag;h=tag-commit"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'tag: on lightweight tag (invalid)' \
        'gitweb_run "p=.git;a=tag;h=lightweight/tag-commit"'
-test_debug 'cat gitweb.log'
 
 # ----------------------------------------------------------------------
 # logs
@@ -412,22 +362,18 @@ test_debug 'cat gitweb.log'
 test_expect_success \
        'logs: log (implicit HEAD)' \
        'gitweb_run "p=.git;a=log"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'logs: shortlog (implicit HEAD)' \
        'gitweb_run "p=.git;a=shortlog"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'logs: history (implicit HEAD, file)' \
        'gitweb_run "p=.git;a=history;f=file"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'logs: history (implicit HEAD, non-existent file)' \
        'gitweb_run "p=.git;a=history;f=non-existent"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'logs: history (implicit HEAD, deleted file)' \
@@ -438,55 +384,45 @@ test_expect_success \
         git rm deleted_file &&
         git commit -m "Delete file" &&
         gitweb_run "p=.git;a=history;f=deleted_file"'
-test_debug 'cat gitweb.log'
 
 # ----------------------------------------------------------------------
 # path_info links
 test_expect_success \
        'path_info: project' \
        'gitweb_run "" "/.git"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'path_info: project/branch' \
        'gitweb_run "" "/.git/b"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'path_info: project/branch:file' \
        'gitweb_run "" "/.git/master:file"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'path_info: project/branch:dir/' \
        'gitweb_run "" "/.git/master:foo/"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'path_info: project/branch:file (non-existent)' \
        'gitweb_run "" "/.git/master:non-existent"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'path_info: project/branch:dir/ (non-existent)' \
        'gitweb_run "" "/.git/master:non-existent/"'
-test_debug 'cat gitweb.log'
 
 
 test_expect_success \
        'path_info: project/branch:/file' \
        'gitweb_run "" "/.git/master:/file"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'path_info: project/:/file (implicit HEAD)' \
        'gitweb_run "" "/.git/:/file"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'path_info: project/:/ (implicit HEAD, top tree)' \
        'gitweb_run "" "/.git/:/"'
-test_debug 'cat gitweb.log'
 
 
 # ----------------------------------------------------------------------
@@ -495,17 +431,14 @@ test_debug 'cat gitweb.log'
 test_expect_success \
        'feeds: OPML' \
        'gitweb_run "a=opml"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'feed: RSS' \
        'gitweb_run "p=.git;a=rss"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'feed: Atom' \
        'gitweb_run "p=.git;a=atom"'
-test_debug 'cat gitweb.log'
 
 # ----------------------------------------------------------------------
 # encoding/decoding
@@ -513,27 +446,28 @@ test_debug 'cat gitweb.log'
 test_expect_success \
        'encode(commit): utf8' \
        '. "$TEST_DIRECTORY"/t3901-utf8.txt &&
+        test_when_finished "GIT_AUTHOR_NAME=\"A U Thor\"" &&
+        test_when_finished "GIT_COMMITTER_NAME=\"C O Mitter\"" &&
         echo "UTF-8" >> file &&
         git add file &&
         git commit -F "$TEST_DIRECTORY"/t3900/1-UTF-8.txt &&
         gitweb_run "p=.git;a=commit"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'encode(commit): iso-8859-1' \
        '. "$TEST_DIRECTORY"/t3901-8859-1.txt &&
+        test_when_finished "GIT_AUTHOR_NAME=\"A U Thor\"" &&
+        test_when_finished "GIT_COMMITTER_NAME=\"C O Mitter\"" &&
         echo "ISO-8859-1" >> file &&
         git add file &&
         git config i18n.commitencoding ISO-8859-1 &&
+        test_when_finished "git config --unset i18n.commitencoding" &&
         git commit -F "$TEST_DIRECTORY"/t3900/ISO8859-1.txt &&
-        git config --unset i18n.commitencoding &&
         gitweb_run "p=.git;a=commit"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'encode(log): utf-8 and iso-8859-1' \
        'gitweb_run "p=.git;a=log"'
-test_debug 'cat gitweb.log'
 
 # ----------------------------------------------------------------------
 # extra options
@@ -541,27 +475,22 @@ test_debug 'cat gitweb.log'
 test_expect_success \
        'opt: log --no-merges' \
        'gitweb_run "p=.git;a=log;opt=--no-merges"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'opt: atom --no-merges' \
        'gitweb_run "p=.git;a=log;opt=--no-merges"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'opt: "file" history --no-merges' \
        'gitweb_run "p=.git;a=history;f=file;opt=--no-merges"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'opt: log --no-such-option (invalid option)' \
        'gitweb_run "p=.git;a=log;opt=--no-such-option"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'opt: tree --no-merges (invalid option for action)' \
        'gitweb_run "p=.git;a=tree;opt=--no-merges"'
-test_debug 'cat gitweb.log'
 
 # ----------------------------------------------------------------------
 # testing config_to_multi / cloneurl
@@ -569,14 +498,12 @@ test_debug 'cat gitweb.log'
 test_expect_success \
        'URL: no project URLs, no base URL' \
        'gitweb_run "p=.git;a=summary"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'URL: project URLs via gitweb.url' \
        'git config --add gitweb.url git://example.com/git/trash.git &&
         git config --add gitweb.url http://example.com/git/trash.git &&
         gitweb_run "p=.git;a=summary"'
-test_debug 'cat gitweb.log'
 
 cat >.git/cloneurl <<\EOF
 git://example.com/git/trash.git
@@ -586,7 +513,6 @@ EOF
 test_expect_success \
        'URL: project URLs via cloneurl file' \
        'gitweb_run "p=.git;a=summary"'
-test_debug 'cat gitweb.log'
 
 # ----------------------------------------------------------------------
 # gitweb config and repo config
@@ -604,12 +530,10 @@ EOF
 test_expect_success \
        'config override: projects list (implicit)' \
        'gitweb_run'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'config override: tree view, features not overridden in repo config' \
        'gitweb_run "p=.git;a=tree"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'config override: tree view, features disabled in repo config' \
@@ -617,14 +541,12 @@ test_expect_success \
         git config gitweb.snapshot none &&
         git config gitweb.avatar gravatar &&
         gitweb_run "p=.git;a=tree"'
-test_debug 'cat gitweb.log'
 
 test_expect_success \
        'config override: tree view, features enabled in repo config (1)' \
        'git config gitweb.blame yes &&
         git config gitweb.snapshot "zip,tgz, tbz2" &&
         gitweb_run "p=.git;a=tree"'
-test_debug 'cat gitweb.log'
 
 cat >.git/config <<\EOF
 # testing noval and alternate separator
@@ -635,7 +557,6 @@ EOF
 test_expect_success \
        'config override: tree view, features enabled in repo config (2)' \
        'gitweb_run "p=.git;a=tree"'
-test_debug 'cat gitweb.log'
 
 # ----------------------------------------------------------------------
 # non-ASCII in README.html
@@ -645,7 +566,6 @@ test_expect_success \
        'echo "<b>UTF-8 example:</b><br />" > .git/README.html &&
         cat "$TEST_DIRECTORY"/t3900/1-UTF-8.txt >> .git/README.html &&
         gitweb_run "p=.git;a=summary"'
-test_debug 'cat gitweb.log'
 
 # ----------------------------------------------------------------------
 # syntax highlighting
@@ -666,7 +586,6 @@ test_expect_success HIGHLIGHT \
        'syntax highlighting (no highlight, unknown syntax)' \
        'git config gitweb.highlight yes &&
         gitweb_run "p=.git;a=blob;f=file"'
-test_debug 'cat gitweb.log'
 
 test_expect_success HIGHLIGHT \
        'syntax highlighting (highlighted, shell script)' \
@@ -675,6 +594,5 @@ test_expect_success HIGHLIGHT \
         git add test.sh &&
         git commit -m "Add test.sh" &&
         gitweb_run "p=.git;a=blob;f=test.sh"'
-test_debug 'cat gitweb.log'
 
 test_done
index 18825aff89f5699afaabc34df0fd7baab5863747..26102ee9b0c36a87ba17a75b0ca644cc42e2c1c4 100755 (executable)
@@ -126,7 +126,6 @@ test_expect_success 'load checking: load too high (default action)' '
        grep "Status: 503 Service Unavailable" gitweb.headers &&
        grep "503 - The load average on the server is too high" gitweb.body
 '
-test_debug 'cat gitweb.log' # just in case
 test_debug 'cat gitweb.headers'
 
 # turn off load checking
index c15ca2d6479a814d7649a38a671a554b6ed8b68f..13ba96e21a9295805aed40c89ecd5178db6bfae4 100755 (executable)
@@ -113,6 +113,16 @@ like($last_commit, qr/^[0-9a-fA-F]{40}$/, 'rev-parse returned hash');
 my $dir_commit = $r2->command_oneline('log', '-n1', '--pretty=format:%H', '.');
 isnt($last_commit, $dir_commit, 'log . does not show last commit');
 
+# commands outside working tree
+chdir($abs_repo_dir . '/..');
+my $r3 = Git->repository(Directory => $abs_repo_dir);
+my $tmpfile3 = "$abs_repo_dir/file3.tmp";
+open TEMPFILE3, "+>$tmpfile3" or die "Can't open $tmpfile3: $!";
+is($r3->cat_blob($file1hash, \*TEMPFILE3), 15, "cat_blob(outside): size");
+close TEMPFILE3;
+unlink $tmpfile3;
+chdir($abs_repo_dir);
+
 printf "1..%d\n", Test::More->builder->current_test;
 
 my $is_passing = eval { Test::More->is_passing };
diff --git a/t/t9800-git-p4.sh b/t/t9800-git-p4.sh
new file mode 100755 (executable)
index 0000000..a523473
--- /dev/null
@@ -0,0 +1,139 @@
+#!/bin/sh
+
+test_description='git-p4 tests'
+
+. ./test-lib.sh
+
+( p4 -h && p4d -h ) >/dev/null 2>&1 || {
+       skip_all='skipping git-p4 tests; no p4 or p4d'
+       test_done
+}
+
+GITP4=$GIT_BUILD_DIR/contrib/fast-import/git-p4
+P4DPORT=10669
+
+db="$TRASH_DIRECTORY/db"
+cli="$TRASH_DIRECTORY/cli"
+git="$TRASH_DIRECTORY/git"
+
+test_debug 'echo p4d -q -d -r "$db" -p $P4DPORT'
+test_expect_success setup '
+       mkdir -p "$db" &&
+       p4d -q -d -r "$db" -p $P4DPORT &&
+       mkdir -p "$cli" &&
+       mkdir -p "$git" &&
+       export P4PORT=localhost:$P4DPORT
+'
+
+test_expect_success 'add p4 files' '
+       cd "$cli" &&
+       p4 client -i <<-EOF &&
+       Client: client
+       Description: client
+       Root: $cli
+       View: //depot/... //client/...
+       EOF
+       export P4CLIENT=client &&
+       echo file1 >file1 &&
+       p4 add file1 &&
+       p4 submit -d "file1" &&
+       echo file2 >file2 &&
+       p4 add file2 &&
+       p4 submit -d "file2" &&
+       cd "$TRASH_DIRECTORY"
+'
+
+test_expect_success 'basic git-p4 clone' '
+       "$GITP4" clone --dest="$git" //depot &&
+       cd "$git" &&
+       git log --oneline >lines &&
+       test_line_count = 1 lines &&
+       cd .. &&
+       rm -rf "$git" && mkdir "$git"
+'
+
+test_expect_success 'git-p4 clone @all' '
+       "$GITP4" clone --dest="$git" //depot@all &&
+       cd "$git" &&
+       git log --oneline >lines &&
+       test_line_count = 2 lines &&
+       cd .. &&
+       rm -rf "$git" && mkdir "$git"
+'
+
+test_expect_success 'git-p4 sync uninitialized repo' '
+       test_create_repo "$git" &&
+       cd "$git" &&
+       test_must_fail "$GITP4" sync &&
+       rm -rf "$git" && mkdir "$git"
+'
+
+#
+# Create a git repo by hand.  Add a commit so that HEAD is valid.
+# Test imports a new p4 repository into a new git branch.
+#
+test_expect_success 'git-p4 sync new branch' '
+       test_create_repo "$git" &&
+       cd "$git" &&
+       test_commit head &&
+       "$GITP4" sync --branch=refs/remotes/p4/depot //depot@all &&
+       git log --oneline p4/depot >lines &&
+       cat lines &&
+       test_line_count = 2 lines &&
+       cd .. &&
+       rm -rf "$git" && mkdir "$git"
+'
+
+test_expect_success 'exit when p4 fails to produce marshaled output' '
+       badp4dir="$TRASH_DIRECTORY/badp4dir" &&
+       mkdir -p "$badp4dir" &&
+       cat >"$badp4dir"/p4 <<-EOF &&
+       #!$SHELL_PATH
+       exit 1
+       EOF
+       chmod 755 "$badp4dir"/p4 &&
+       PATH="$badp4dir:$PATH" "$GITP4" clone --dest="$git" //depot >errs 2>&1 ; retval=$? &&
+       test $retval -eq 1 &&
+       test_must_fail grep -q Traceback errs
+'
+
+test_expect_success 'add p4 files with wildcards in the names' '
+       cd "$cli" &&
+       echo file-wild-hash >file-wild#hash &&
+       echo file-wild-star >file-wild\*star &&
+       echo file-wild-at >file-wild@at &&
+       echo file-wild-percent >file-wild%percent &&
+       p4 add -f file-wild* &&
+       p4 submit -d "file wildcards" &&
+       cd "$TRASH_DIRECTORY"
+'
+
+test_expect_success 'wildcard files git-p4 clone' '
+       "$GITP4" clone --dest="$git" //depot &&
+       cd "$git" &&
+       test -f file-wild#hash &&
+       test -f file-wild\*star &&
+       test -f file-wild@at &&
+       test -f file-wild%percent &&
+       cd "$TRASH_DIRECTORY" &&
+       rm -rf "$git" && mkdir "$git"
+'
+
+test_expect_success 'clone bare' '
+       "$GITP4" clone --dest="$git" --bare //depot &&
+       cd "$git" &&
+       test ! -d .git &&
+       bare=`git config --get core.bare` &&
+       test "$bare" = true &&
+       cd "$TRASH_DIRECTORY" &&
+       rm -rf "$git" && mkdir "$git"
+'
+
+test_expect_success 'shutdown' '
+       pid=`pgrep -f p4d` &&
+       test -n "$pid" &&
+       test_debug "ps wl `echo $pid`" &&
+       kill $pid
+'
+
+test_done
index 0fdc541a7cd7d6b694c4f4a3fd06b6cf21dc7380..7cc9a52cbf78358e545f27cd5b7f69ac2030ecbf 100644 (file)
@@ -43,36 +43,16 @@ TERM=dumb
 export LANG LC_ALL PAGER TERM TZ
 EDITOR=:
 unset VISUAL
-unset GIT_EDITOR
-unset AUTHOR_DATE
-unset AUTHOR_EMAIL
-unset AUTHOR_NAME
-unset COMMIT_AUTHOR_EMAIL
-unset COMMIT_AUTHOR_NAME
 unset EMAIL
-unset GIT_ALTERNATE_OBJECT_DIRECTORIES
-unset GIT_AUTHOR_DATE
+unset $(perl -e '
+       my @env = keys %ENV;
+       my @vars = grep(/^GIT_/ && !/^GIT_(TRACE|DEBUG|USE_LOOKUP)/, @env);
+       print join("\n", @vars);
+')
 GIT_AUTHOR_EMAIL=author@example.com
 GIT_AUTHOR_NAME='A U Thor'
-unset GIT_COMMITTER_DATE
 GIT_COMMITTER_EMAIL=committer@example.com
 GIT_COMMITTER_NAME='C O Mitter'
-unset GIT_DIFF_OPTS
-unset GIT_DIR
-unset GIT_WORK_TREE
-unset GIT_EXTERNAL_DIFF
-unset GIT_INDEX_FILE
-unset GIT_OBJECT_DIRECTORY
-unset GIT_CEILING_DIRECTORIES
-unset SHA1_FILE_DIRECTORIES
-unset SHA1_FILE_DIRECTORY
-unset GIT_NOTES_REF
-unset GIT_NOTES_DISPLAY_REF
-unset GIT_NOTES_REWRITE_REF
-unset GIT_NOTES_REWRITE_MODE
-unset GIT_REFLOG_ACTION
-unset GIT_CHERRY_PICK_HELP
-unset GIT_QUIET
 GIT_MERGE_VERBOSITY=5
 export GIT_MERGE_VERBOSITY
 export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
@@ -954,8 +934,8 @@ fi
 GIT_TEMPLATE_DIR="$GIT_BUILD_DIR"/templates/blt
 unset GIT_CONFIG
 GIT_CONFIG_NOSYSTEM=1
-GIT_CONFIG_NOGLOBAL=1
-export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOBAL
+GIT_ATTR_NOSYSTEM=1
+export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_ATTR_NOSYSTEM
 
 . "$GIT_BUILD_DIR"/GIT-BUILD-OPTIONS
 
@@ -1079,6 +1059,15 @@ esac
 test -z "$NO_PERL" && test_set_prereq PERL
 test -z "$NO_PYTHON" && test_set_prereq PYTHON
 
+# Can we rely on git's output in the C locale?
+if test -n "$GETTEXT_POISON"
+then
+       GIT_GETTEXT_POISON=YesPlease
+       export GIT_GETTEXT_POISON
+else
+       test_set_prereq C_LOCALE_OUTPUT
+fi
+
 # test whether the filesystem supports symbolic links
 ln -s x y 2>/dev/null && test -h y 2>/dev/null && test_set_prereq SYMLINKS
 rm -f y
index 9e013fa3b25b82a10b71ceabfa664c796c4d7a3f..0a6724fcc45eed89d612b0e641fd3fe6d4231fcb 100644 (file)
@@ -43,3 +43,9 @@
        fun:write_buffer
        fun:write_loose_object
 }
+
+{
+       ignore-sse-strlen-invalid-read-size
+       Memcheck:Addr4
+       fun:copy_ref
+}
diff --git a/tag.c b/tag.c
index f789744ccaf5d5fb6f63ba0911a869492affc162..7d38cc0f4de1c16b5b52725ba7a6a361650a6b41 100644 (file)
--- a/tag.c
+++ b/tag.c
@@ -56,7 +56,7 @@ static unsigned long parse_tag_date(const char *buf, const char *tail)
        return strtoul(dateptr, NULL, 10);
 }
 
-int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
+int parse_tag_buffer(struct tag *item, const void *data, unsigned long size)
 {
        unsigned char sha1[20];
        char type[20];
@@ -97,7 +97,9 @@ int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
                item->tagged = NULL;
        }
 
-       if (prefixcmp(bufptr, "tag "))
+       if (bufptr + 4 < tail && !prefixcmp(bufptr, "tag "))
+               ;               /* good */
+       else
                return -1;
        bufptr += 4;
        nl = memchr(bufptr, '\n', tail - bufptr);
@@ -106,7 +108,7 @@ int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
        item->tag = xmemdupz(bufptr, nl - bufptr);
        bufptr = nl + 1;
 
-       if (!prefixcmp(bufptr, "tagger "))
+       if (bufptr + 7 < tail && !prefixcmp(bufptr, "tagger "))
                item->date = parse_tag_date(bufptr, tail);
        else
                item->date = 0;
diff --git a/tag.h b/tag.h
index 85223700396f5ddb00c046a1a9fdb63c92aae40e..5ee88e6550cafa78b7e4acaa1285d5805974a037 100644 (file)
--- a/tag.h
+++ b/tag.h
@@ -13,7 +13,7 @@ struct tag {
 };
 
 extern struct tag *lookup_tag(const unsigned char *sha1);
-extern int parse_tag_buffer(struct tag *item, void *data, unsigned long size);
+extern int parse_tag_buffer(struct tag *item, const void *data, unsigned long size);
 extern int parse_tag(struct tag *item);
 extern struct object *deref_tag(struct object *, const char *, int);
 extern size_t parse_signature(const char *buf, unsigned long size);
index c11bf7f96708c90c992423fc27b2eba73d0c34a0..25b20b93fd4a1113629c99bd5a53dfee965119c1 100644 (file)
@@ -1,14 +1,9 @@
 /*
  * test-line-buffer.c: code to exercise the svn importer's input helper
- *
- * Input format:
- *     number NL
- *     (number bytes) NL
- *     number NL
- *     ...
  */
 
 #include "git-compat-util.h"
+#include "strbuf.h"
 #include "vcs-svn/line_buffer.h"
 
 static uint32_t strtouint32(const char *s)
@@ -20,27 +15,84 @@ static uint32_t strtouint32(const char *s)
        return (uint32_t) n;
 }
 
+static void handle_command(const char *command, const char *arg, struct line_buffer *buf)
+{
+       switch (*command) {
+       case 'b':
+               if (!prefixcmp(command, "binary ")) {
+                       struct strbuf sb = STRBUF_INIT;
+                       strbuf_addch(&sb, '>');
+                       buffer_read_binary(buf, &sb, strtouint32(arg));
+                       fwrite(sb.buf, 1, sb.len, stdout);
+                       strbuf_release(&sb);
+                       return;
+               }
+       case 'c':
+               if (!prefixcmp(command, "copy ")) {
+                       buffer_copy_bytes(buf, strtouint32(arg));
+                       return;
+               }
+       case 'r':
+               if (!prefixcmp(command, "read ")) {
+                       const char *s = buffer_read_string(buf, strtouint32(arg));
+                       fputs(s, stdout);
+                       return;
+               }
+       case 's':
+               if (!prefixcmp(command, "skip ")) {
+                       buffer_skip_bytes(buf, strtouint32(arg));
+                       return;
+               }
+       default:
+               die("unrecognized command: %s", command);
+       }
+}
+
+static void handle_line(const char *line, struct line_buffer *stdin_buf)
+{
+       const char *arg = strchr(line, ' ');
+       if (!arg)
+               die("no argument in line: %s", line);
+       handle_command(line, arg + 1, stdin_buf);
+}
+
 int main(int argc, char *argv[])
 {
+       struct line_buffer stdin_buf = LINE_BUFFER_INIT;
+       struct line_buffer file_buf = LINE_BUFFER_INIT;
+       struct line_buffer *input = &stdin_buf;
+       const char *filename;
        char *s;
 
-       if (argc != 1)
-               usage("test-line-buffer < input.txt");
-       if (buffer_init(NULL))
+       if (argc == 1)
+               filename = NULL;
+       else if (argc == 2)
+               filename = argv[1];
+       else
+               usage("test-line-buffer [file | &fd] < script");
+
+       if (buffer_init(&stdin_buf, NULL))
                die_errno("open error");
-       while ((s = buffer_read_line())) {
-               s = buffer_read_string(strtouint32(s));
-               fputs(s, stdout);
-               fputc('\n', stdout);
-               buffer_skip_bytes(1);
-               if (!(s = buffer_read_line()))
-                       break;
-               buffer_copy_bytes(strtouint32(s) + 1);
+       if (filename) {
+               if (*filename == '&') {
+                       if (buffer_fdinit(&file_buf, strtouint32(filename + 1)))
+                               die_errno("error opening fd %s", filename + 1);
+               } else {
+                       if (buffer_init(&file_buf, filename))
+                               die_errno("error opening %s", filename);
+               }
+               input = &file_buf;
        }
-       if (buffer_deinit())
+
+       while ((s = buffer_read_line(&stdin_buf)))
+               handle_line(s, input);
+
+       if (filename && buffer_deinit(&file_buf))
+               die("error reading from %s", filename);
+       if (buffer_deinit(&stdin_buf))
                die("input error");
        if (ferror(stdout))
                die("output error");
-       buffer_reset();
+       buffer_reset(&stdin_buf);
        return 0;
 }
diff --git a/test-mktemp.c b/test-mktemp.c
new file mode 100644 (file)
index 0000000..c8c5421
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * test-mktemp.c: code to exercise the creation of temporary files
+ */
+#include "git-compat-util.h"
+
+int main(int argc, char *argv[])
+{
+       if (argc != 2)
+               usage("Expected 1 parameter defining the temporary file template");
+
+       xmkstemp(xstrdup(argv[1]));
+
+       return 0;
+}
index 0828592162cc7c61f0d025ba4d83fc29bc4c2067..4e3710b9a8fc868642e1e0e8f4af37eeb1ce0ce4 100644 (file)
@@ -46,7 +46,7 @@ int main(int argc, const char **argv)
                OPT_DATE('t', NULL, &timestamp, "get timestamp of <time>"),
                OPT_CALLBACK('L', "length", &integer, "str",
                        "get length of <str>", length_callback),
-               OPT_FILENAME('F', "file", &file, "set file to <FILE>"),
+               OPT_FILENAME('F', "file", &file, "set file to <file>"),
                OPT_GROUP("String options"),
                OPT_STRING('s', "string", &string, "string", "get a string"),
                OPT_STRING(0, "string2", &string, "str", "get another string"),
index d261398d6c50aeefa7450b99caae23ee5cdff0d0..e7671593df6bf014f3a9d8bd5173d1edcfd6545b 100644 (file)
@@ -11,9 +11,9 @@ int main(int argc, char **argv)
                return 0;
        }
 
-       if (argc >= 2 && !strcmp(argv[1], "make_absolute_path")) {
+       if (argc >= 2 && !strcmp(argv[1], "real_path")) {
                while (argc > 2) {
-                       puts(make_absolute_path(argv[2]));
+                       puts(real_path(argv[2]));
                        argc--;
                        argv++;
                }
index 77cf78abcfd18532b1b75e5ad5efa21b27f1a28c..b42ba789b176160285844e49cb834d60170d9a54 100644 (file)
@@ -9,7 +9,8 @@ int main(int argc, char *argv[])
 {
        if (argc != 2)
                usage("test-svn-fe <file>");
-       svndump_init(argv[1]);
+       if (svndump_init(argv[1]))
+               return 1;
        svndump_read(NULL);
        svndump_deinit();
        svndump_reset();
index 589f838f82b568195232ea81346d0049261b86b1..7f4b76a95899cc28aa1d42598d1649f126980ed9 100644 (file)
@@ -1,5 +1,5 @@
 #include "cache.h"
-#include <pthread.h>
+#include "thread-utils.h"
 
 #if defined(hpux) || defined(__hpux) || defined(_hpux)
 #  include <sys/pstat.h>
diff --git a/trace.c b/trace.c
index 35d388dce44a4a8e3d6053dfd6abcb652771818a..d95341693fa9b27caed38ffe1308838bedb49f83 100644 (file)
--- a/trace.c
+++ b/trace.c
 #include "cache.h"
 #include "quote.h"
 
-/* Get a trace file descriptor from GIT_TRACE env variable. */
-static int get_trace_fd(int *need_close)
+/* Get a trace file descriptor from "key" env variable. */
+static int get_trace_fd(const char *key, int *need_close)
 {
-       char *trace = getenv("GIT_TRACE");
+       char *trace = getenv(key);
 
        if (!trace || !strcmp(trace, "") ||
            !strcmp(trace, "0") || !strcasecmp(trace, "false"))
@@ -50,10 +50,10 @@ static int get_trace_fd(int *need_close)
                return fd;
        }
 
-       fprintf(stderr, "What does '%s' for GIT_TRACE mean?\n", trace);
+       fprintf(stderr, "What does '%s' for %s mean?\n", trace, key);
        fprintf(stderr, "If you want to trace into a file, "
-               "then please set GIT_TRACE to an absolute pathname "
-               "(starting with /).\n");
+               "then please set %s to an absolute pathname "
+               "(starting with /).\n", key);
        fprintf(stderr, "Defaulting to tracing on stderr...\n");
 
        return STDERR_FILENO;
@@ -62,33 +62,44 @@ static int get_trace_fd(int *need_close)
 static const char err_msg[] = "Could not trace into fd given by "
        "GIT_TRACE environment variable";
 
-void trace_printf(const char *fmt, ...)
+void trace_vprintf(const char *key, const char *fmt, va_list ap)
 {
-       struct strbuf buf;
-       va_list ap;
-       int fd, len, need_close = 0;
+       struct strbuf buf = STRBUF_INIT;
 
-       fd = get_trace_fd(&need_close);
-       if (!fd)
+       if (!trace_want(key))
                return;
 
        set_try_to_free_routine(NULL);  /* is never reset */
-       strbuf_init(&buf, 64);
+       strbuf_vaddf(&buf, fmt, ap);
+       trace_strbuf(key, &buf);
+       strbuf_release(&buf);
+}
+
+static void trace_printf_key(const char *key, const char *fmt, ...)
+{
+       va_list ap;
        va_start(ap, fmt);
-       len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap);
+       trace_vprintf(key, fmt, ap);
        va_end(ap);
-       if (len >= strbuf_avail(&buf)) {
-               strbuf_grow(&buf, len - strbuf_avail(&buf) + 128);
-               va_start(ap, fmt);
-               len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap);
-               va_end(ap);
-               if (len >= strbuf_avail(&buf))
-                       die("broken vsnprintf");
-       }
-       strbuf_setlen(&buf, len);
+}
 
-       write_or_whine_pipe(fd, buf.buf, buf.len, err_msg);
-       strbuf_release(&buf);
+void trace_printf(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       trace_vprintf("GIT_TRACE", fmt, ap);
+       va_end(ap);
+}
+
+void trace_strbuf(const char *key, const struct strbuf *buf)
+{
+       int fd, need_close = 0;
+
+       fd = get_trace_fd(key, &need_close);
+       if (!fd)
+               return;
+
+       write_or_whine_pipe(fd, buf->buf, buf->len, err_msg);
 
        if (need_close)
                close(fd);
@@ -96,28 +107,18 @@ void trace_printf(const char *fmt, ...)
 
 void trace_argv_printf(const char **argv, const char *fmt, ...)
 {
-       struct strbuf buf;
+       struct strbuf buf = STRBUF_INIT;
        va_list ap;
-       int fd, len, need_close = 0;
+       int fd, need_close = 0;
 
-       fd = get_trace_fd(&need_close);
+       fd = get_trace_fd("GIT_TRACE", &need_close);
        if (!fd)
                return;
 
        set_try_to_free_routine(NULL);  /* is never reset */
-       strbuf_init(&buf, 64);
        va_start(ap, fmt);
-       len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap);
+       strbuf_vaddf(&buf, fmt, ap);
        va_end(ap);
-       if (len >= strbuf_avail(&buf)) {
-               strbuf_grow(&buf, len - strbuf_avail(&buf) + 128);
-               va_start(ap, fmt);
-               len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap);
-               va_end(ap);
-               if (len >= strbuf_avail(&buf))
-                       die("broken vsnprintf");
-       }
-       strbuf_setlen(&buf, len);
 
        sq_quote_argv(&buf, argv, 0);
        strbuf_addch(&buf, '\n');
@@ -154,12 +155,11 @@ static const char *quote_crnl(const char *path)
 /* FIXME: move prefix to startup_info struct and get rid of this arg */
 void trace_repo_setup(const char *prefix)
 {
+       static const char *key = "GIT_TRACE_SETUP";
        const char *git_work_tree;
        char cwd[PATH_MAX];
-       char *trace = getenv("GIT_TRACE");
 
-       if (!trace || !strcmp(trace, "") ||
-           !strcmp(trace, "0") || !strcasecmp(trace, "false"))
+       if (!trace_want(key))
                return;
 
        if (!getcwd(cwd, PATH_MAX))
@@ -171,8 +171,18 @@ void trace_repo_setup(const char *prefix)
        if (!prefix)
                prefix = "(null)";
 
-       trace_printf("setup: git_dir: %s\n", quote_crnl(get_git_dir()));
-       trace_printf("setup: worktree: %s\n", quote_crnl(git_work_tree));
-       trace_printf("setup: cwd: %s\n", quote_crnl(cwd));
-       trace_printf("setup: prefix: %s\n", quote_crnl(prefix));
+       trace_printf_key(key, "setup: git_dir: %s\n", quote_crnl(get_git_dir()));
+       trace_printf_key(key, "setup: worktree: %s\n", quote_crnl(git_work_tree));
+       trace_printf_key(key, "setup: cwd: %s\n", quote_crnl(cwd));
+       trace_printf_key(key, "setup: prefix: %s\n", quote_crnl(prefix));
+}
+
+int trace_want(const char *key)
+{
+       const char *trace = getenv(key);
+
+       if (!trace || !strcmp(trace, "") ||
+           !strcmp(trace, "0") || !strcasecmp(trace, "false"))
+               return 0;
+       return 1;
 }
index 4e4754c32bd53f28f9335c2a4529f5804f3086f2..5846b55875f6e568711b2f90726bb6608aaf4e73 100644 (file)
@@ -12,8 +12,7 @@
 
 static int debug;
 
-struct helper_data
-{
+struct helper_data {
        const char *name;
        struct child_process *helper;
        FILE *out;
@@ -77,7 +76,7 @@ static void write_constant(int fd, const char *str)
                die_errno("Full write to remote helper failed");
 }
 
-const char *remove_ext_force(const char *url)
+static const char *remove_ext_force(const char *url)
 {
        if (url) {
                const char *colon = strchr(url, ':');
@@ -973,7 +972,7 @@ static int udt_do_read(struct unidirectional_transfer *t)
  */
 static int udt_do_write(struct unidirectional_transfer *t)
 {
-       size_t bytes;
+       ssize_t bytes;
 
        if (t->bufuse == 0)
                return 0;       /* Nothing to write. */
index 00786606117feea4b33b7e632b8ff8a3c26de4e4..a02f79aae3d91ea4109d21a9ed9ca2d962125375 100644 (file)
@@ -192,7 +192,7 @@ static const char *rsync_url(const char *url)
 static struct ref *get_refs_via_rsync(struct transport *transport, int for_push)
 {
        struct strbuf buf = STRBUF_INIT, temp_dir = STRBUF_INIT;
-       struct ref dummy = {0}, *tail = &dummy;
+       struct ref dummy = {NULL}, *tail = &dummy;
        struct child_process rsync;
        const char *args[5];
        int temp_dir_len;
@@ -1189,3 +1189,37 @@ char *transport_anonymize_url(const char *url)
 literal_copy:
        return xstrdup(url);
 }
+
+int refs_from_alternate_cb(struct alternate_object_database *e, void *cb)
+{
+       char *other;
+       size_t len;
+       struct remote *remote;
+       struct transport *transport;
+       const struct ref *extra;
+       alternate_ref_fn *ref_fn = cb;
+
+       e->name[-1] = '\0';
+       other = xstrdup(real_path(e->base));
+       e->name[-1] = '/';
+       len = strlen(other);
+
+       while (other[len-1] == '/')
+               other[--len] = '\0';
+       if (len < 8 || memcmp(other + len - 8, "/objects", 8))
+               return 0;
+       /* Is this a git repository with refs? */
+       memcpy(other + len - 8, "/refs", 6);
+       if (!is_directory(other))
+               return 0;
+       other[len - 8] = '\0';
+       remote = remote_get(other);
+       transport = transport_get(remote, other);
+       for (extra = transport_get_remote_refs(transport);
+            extra;
+            extra = extra->next)
+               ref_fn(extra, NULL);
+       transport_disconnect(transport);
+       free(other);
+       return 0;
+}
index e803c0e7baf3785fac35fca64072e05e4f668a26..efb19688692b5f1be4fc085cc36d737ace2df417 100644 (file)
@@ -166,4 +166,7 @@ int transport_refs_pushed(struct ref *ref);
 void transport_print_push_status(const char *dest, struct ref *refs,
                  int verbose, int porcelain, int *nonfastforward);
 
+typedef void alternate_ref_fn(const struct ref *, void *);
+extern int refs_from_alternate_cb(struct alternate_object_database *e, void *cb);
+
 #endif
index 12c9a88884ec3bb70a1744e44235c578a44e08e6..3954281f509bbed9a9b095ed92d24b67275fed82 100644 (file)
@@ -6,34 +6,18 @@
 #include "diffcore.h"
 #include "tree.h"
 
-static char *malloc_base(const char *base, int baselen, const char *path, int pathlen)
-{
-       char *newbase = xmalloc(baselen + pathlen + 2);
-       memcpy(newbase, base, baselen);
-       memcpy(newbase + baselen, path, pathlen);
-       memcpy(newbase + baselen + pathlen, "/", 2);
-       return newbase;
-}
+static void show_entry(struct diff_options *opt, const char *prefix,
+                      struct tree_desc *desc, struct strbuf *base);
 
-static char *malloc_fullname(const char *base, int baselen, const char *path, int pathlen)
-{
-       char *fullname = xmalloc(baselen + pathlen + 1);
-       memcpy(fullname, base, baselen);
-       memcpy(fullname + baselen, path, pathlen);
-       fullname[baselen + pathlen] = 0;
-       return fullname;
-}
-
-static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc,
-                      const char *base, int baselen);
-
-static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, int baselen, struct diff_options *opt)
+static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2,
+                             struct strbuf *base, struct diff_options *opt)
 {
        unsigned mode1, mode2;
        const char *path1, *path2;
        const unsigned char *sha1, *sha2;
        int cmp, pathlen1, pathlen2;
-       char *fullname;
+       int old_baselen = base->len;
+       int retval = 0;
 
        sha1 = tree_entry_extract(t1, &path1, &mode1);
        sha2 = tree_entry_extract(t2, &path2, &mode2);
@@ -42,11 +26,11 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const
        pathlen2 = tree_entry_len(path2, sha2);
        cmp = base_name_compare(path1, pathlen1, mode1, path2, pathlen2, mode2);
        if (cmp < 0) {
-               show_entry(opt, "-", t1, base, baselen);
+               show_entry(opt, "-", t1, base);
                return -1;
        }
        if (cmp > 0) {
-               show_entry(opt, "+", t2, base, baselen);
+               show_entry(opt, "+", t2, base);
                return 1;
        }
        if (!DIFF_OPT_TST(opt, FIND_COPIES_HARDER) && !hashcmp(sha1, sha2) && mode1 == mode2)
@@ -57,149 +41,29 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const
         * file, we need to consider it a remove and an add.
         */
        if (S_ISDIR(mode1) != S_ISDIR(mode2)) {
-               show_entry(opt, "-", t1, base, baselen);
-               show_entry(opt, "+", t2, base, baselen);
+               show_entry(opt, "-", t1, base);
+               show_entry(opt, "+", t2, base);
                return 0;
        }
 
+       strbuf_add(base, path1, pathlen1);
        if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode1)) {
-               int retval;
-               char *newbase = malloc_base(base, baselen, path1, pathlen1);
                if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) {
-                       newbase[baselen + pathlen1] = 0;
                        opt->change(opt, mode1, mode2,
-                                   sha1, sha2, newbase, 0, 0);
-                       newbase[baselen + pathlen1] = '/';
+                                   sha1, sha2, base->buf, 0, 0);
                }
-               retval = diff_tree_sha1(sha1, sha2, newbase, opt);
-               free(newbase);
-               return retval;
+               strbuf_addch(base, '/');
+               retval = diff_tree_sha1(sha1, sha2, base->buf, opt);
+       } else {
+               opt->change(opt, mode1, mode2, sha1, sha2, base->buf, 0, 0);
        }
-
-       fullname = malloc_fullname(base, baselen, path1, pathlen1);
-       opt->change(opt, mode1, mode2, sha1, sha2, fullname, 0, 0);
-       free(fullname);
+       strbuf_setlen(base, old_baselen);
        return 0;
 }
 
-/*
- * Is a tree entry interesting given the pathspec we have?
- *
- * Pre-condition: baselen == 0 || base[baselen-1] == '/'
- *
- * Return:
- *  - 2 for "yes, and all subsequent entries will be"
- *  - 1 for yes
- *  - zero for no
- *  - negative for "no, and no subsequent entries will be either"
- */
-static int tree_entry_interesting(struct tree_desc *desc, const char *base, int baselen, struct diff_options *opt)
-{
-       const char *path;
-       const unsigned char *sha1;
-       unsigned mode;
-       int i;
-       int pathlen;
-       int never_interesting = -1;
-
-       if (!opt->nr_paths)
-               return 2;
-
-       sha1 = tree_entry_extract(desc, &path, &mode);
-
-       pathlen = tree_entry_len(path, sha1);
-
-       for (i = 0; i < opt->nr_paths; i++) {
-               const char *match = opt->paths[i];
-               int matchlen = opt->pathlens[i];
-               int m = -1; /* signals that we haven't called strncmp() */
-
-               if (baselen >= matchlen) {
-                       /* If it doesn't match, move along... */
-                       if (strncmp(base, match, matchlen))
-                               continue;
-
-                       /*
-                        * If the base is a subdirectory of a path which
-                        * was specified, all of them are interesting.
-                        */
-                       if (!matchlen ||
-                           base[matchlen] == '/' ||
-                           match[matchlen - 1] == '/')
-                               return 2;
-
-                       /* Just a random prefix match */
-                       continue;
-               }
-
-               /* Does the base match? */
-               if (strncmp(base, match, baselen))
-                       continue;
-
-               match += baselen;
-               matchlen -= baselen;
-
-               if (never_interesting) {
-                       /*
-                        * We have not seen any match that sorts later
-                        * than the current path.
-                        */
-
-                       /*
-                        * Does match sort strictly earlier than path
-                        * with their common parts?
-                        */
-                       m = strncmp(match, path,
-                                   (matchlen < pathlen) ? matchlen : pathlen);
-                       if (m < 0)
-                               continue;
-
-                       /*
-                        * If we come here even once, that means there is at
-                        * least one pathspec that would sort equal to or
-                        * later than the path we are currently looking at.
-                        * In other words, if we have never reached this point
-                        * after iterating all pathspecs, it means all
-                        * pathspecs are either outside of base, or inside the
-                        * base but sorts strictly earlier than the current
-                        * one.  In either case, they will never match the
-                        * subsequent entries.  In such a case, we initialized
-                        * the variable to -1 and that is what will be
-                        * returned, allowing the caller to terminate early.
-                        */
-                       never_interesting = 0;
-               }
-
-               if (pathlen > matchlen)
-                       continue;
-
-               if (matchlen > pathlen) {
-                       if (match[pathlen] != '/')
-                               continue;
-                       if (!S_ISDIR(mode))
-                               continue;
-               }
-
-               if (m == -1)
-                       /*
-                        * we cheated and did not do strncmp(), so we do
-                        * that here.
-                        */
-                       m = strncmp(match, path, pathlen);
-
-               /*
-                * If common part matched earlier then it is a hit,
-                * because we rejected the case where path is not a
-                * leading directory and is shorter than match.
-                */
-               if (!m)
-                       return 1;
-       }
-       return never_interesting; /* No matches */
-}
-
 /* A whole sub-tree went away or appeared */
-static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base, int baselen)
+static void show_tree(struct diff_options *opt, const char *prefix,
+                     struct tree_desc *desc, struct strbuf *base)
 {
        int all_interesting = 0;
        while (desc->size) {
@@ -208,31 +72,32 @@ static void show_tree(struct diff_options *opt, const char *prefix, struct tree_
                if (all_interesting)
                        show = 1;
                else {
-                       show = tree_entry_interesting(desc, base, baselen,
-                                                     opt);
+                       show = tree_entry_interesting(&desc->entry, base, 0,
+                                                     &opt->pathspec);
                        if (show == 2)
                                all_interesting = 1;
                }
                if (show < 0)
                        break;
                if (show)
-                       show_entry(opt, prefix, desc, base, baselen);
+                       show_entry(opt, prefix, desc, base);
                update_tree_entry(desc);
        }
 }
 
 /* A file entry went away or appeared */
-static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc,
-                      const char *base, int baselen)
+static void show_entry(struct diff_options *opt, const char *prefix,
+                      struct tree_desc *desc, struct strbuf *base)
 {
        unsigned mode;
        const char *path;
        const unsigned char *sha1 = tree_entry_extract(desc, &path, &mode);
        int pathlen = tree_entry_len(path, sha1);
+       int old_baselen = base->len;
 
+       strbuf_add(base, path, pathlen);
        if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode)) {
                enum object_type type;
-               char *newbase = malloc_base(base, baselen, path, pathlen);
                struct tree_desc inner;
                void *tree;
                unsigned long size;
@@ -241,28 +106,25 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree
                if (!tree || type != OBJ_TREE)
                        die("corrupt tree sha %s", sha1_to_hex(sha1));
 
-               if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) {
-                       newbase[baselen + pathlen] = 0;
-                       opt->add_remove(opt, *prefix, mode, sha1, newbase, 0);
-                       newbase[baselen + pathlen] = '/';
-               }
+               if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE))
+                       opt->add_remove(opt, *prefix, mode, sha1, base->buf, 0);
 
-               init_tree_desc(&inner, tree, size);
-               show_tree(opt, prefix, &inner, newbase, baselen + 1 + pathlen);
+               strbuf_addch(base, '/');
 
+               init_tree_desc(&inner, tree, size);
+               show_tree(opt, prefix, &inner, base);
                free(tree);
-               free(newbase);
-       } else {
-               char *fullname = malloc_fullname(base, baselen, path, pathlen);
-               opt->add_remove(opt, prefix[0], mode, sha1, fullname, 0);
-               free(fullname);
-       }
+       } else
+               opt->add_remove(opt, prefix[0], mode, sha1, base->buf, 0);
+
+       strbuf_setlen(base, old_baselen);
 }
 
-static void skip_uninteresting(struct tree_desc *t, const char *base, int baselen, struct diff_options *opt, int *all_interesting)
+static void skip_uninteresting(struct tree_desc *t, struct strbuf *base,
+                              struct diff_options *opt, int *all_interesting)
 {
        while (t->size) {
-               int show = tree_entry_interesting(t, base, baselen, opt);
+               int show = tree_entry_interesting(&t->entry, base, 0, &opt->pathspec);
                if (show == 2)
                        *all_interesting = 1;
                if (!show) {
@@ -276,37 +138,44 @@ static void skip_uninteresting(struct tree_desc *t, const char *base, int basele
        }
 }
 
-int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)
+int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
+             const char *base_str, struct diff_options *opt)
 {
-       int baselen = strlen(base);
+       struct strbuf base;
+       int baselen = strlen(base_str);
        int all_t1_interesting = 0;
        int all_t2_interesting = 0;
 
+       /* Enable recursion indefinitely */
+       opt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE);
+       opt->pathspec.max_depth = -1;
+
+       strbuf_init(&base, PATH_MAX);
+       strbuf_add(&base, base_str, baselen);
+
        for (;;) {
                if (DIFF_OPT_TST(opt, QUICK) &&
                    DIFF_OPT_TST(opt, HAS_CHANGES))
                        break;
-               if (opt->nr_paths) {
+               if (opt->pathspec.nr) {
                        if (!all_t1_interesting)
-                               skip_uninteresting(t1, base, baselen, opt,
-                                                  &all_t1_interesting);
+                               skip_uninteresting(t1, &base, opt, &all_t1_interesting);
                        if (!all_t2_interesting)
-                               skip_uninteresting(t2, base, baselen, opt,
-                                                  &all_t2_interesting);
+                               skip_uninteresting(t2, &base, opt, &all_t2_interesting);
                }
                if (!t1->size) {
                        if (!t2->size)
                                break;
-                       show_entry(opt, "+", t2, base, baselen);
+                       show_entry(opt, "+", t2, &base);
                        update_tree_entry(t2);
                        continue;
                }
                if (!t2->size) {
-                       show_entry(opt, "-", t1, base, baselen);
+                       show_entry(opt, "-", t1, &base);
                        update_tree_entry(t1);
                        continue;
                }
-               switch (compare_tree_entry(t1, t2, base, baselen, opt)) {
+               switch (compare_tree_entry(t1, t2, &base, opt)) {
                case -1:
                        update_tree_entry(t1);
                        continue;
@@ -319,6 +188,8 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru
                }
                die("git diff-tree: internal error");
        }
+
+       strbuf_release(&base);
        return 0;
 }
 
@@ -349,7 +220,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
        DIFF_OPT_SET(&diff_opts, RECURSIVE);
        DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER);
        diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
-       diff_opts.single_follow = opt->paths[0];
+       diff_opts.single_follow = opt->pathspec.raw[0];
        diff_opts.break_opt = opt->break_opt;
        paths[0] = NULL;
        diff_tree_setup_paths(paths, &diff_opts);
@@ -369,15 +240,16 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
                 * diff_queued_diff, we will also use that as the path in
                 * the future!
                 */
-               if ((p->status == 'R' || p->status == 'C') && !strcmp(p->two->path, opt->paths[0])) {
+               if ((p->status == 'R' || p->status == 'C') &&
+                   !strcmp(p->two->path, opt->pathspec.raw[0])) {
                        /* Switch the file-pairs around */
                        q->queue[i] = choice;
                        choice = p;
 
                        /* Update the path we use from now on.. */
                        diff_tree_release_paths(opt);
-                       opt->paths[0] = xstrdup(p->one->path);
-                       diff_tree_setup_paths(opt->paths, opt);
+                       opt->pathspec.raw[0] = xstrdup(p->one->path);
+                       diff_tree_setup_paths(opt->pathspec.raw, opt);
 
                        /*
                         * The caller expects us to return a set of vanilla
@@ -452,36 +324,12 @@ int diff_root_tree_sha1(const unsigned char *new, const char *base, struct diff_
        return retval;
 }
 
-static int count_paths(const char **paths)
-{
-       int i = 0;
-       while (*paths++)
-               i++;
-       return i;
-}
-
 void diff_tree_release_paths(struct diff_options *opt)
 {
-       free(opt->pathlens);
+       free_pathspec(&opt->pathspec);
 }
 
 void diff_tree_setup_paths(const char **p, struct diff_options *opt)
 {
-       opt->nr_paths = 0;
-       opt->pathlens = NULL;
-       opt->paths = NULL;
-
-       if (p) {
-               int i;
-
-               opt->paths = p;
-               opt->nr_paths = count_paths(p);
-               if (opt->nr_paths == 0) {
-                       opt->pathlens = NULL;
-                       return;
-               }
-               opt->pathlens = xmalloc(opt->nr_paths * sizeof(int));
-               for (i=0; i < opt->nr_paths; i++)
-                       opt->pathlens[i] = strlen(p[i]);
-       }
+       init_pathspec(&opt->pathspec, p);
 }
index a9bbf4e2354df5ce6b010873b419731343a12c7d..322becc3b4ad50b8e87fae8f6d5d38f7edc51f01 100644 (file)
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "tree-walk.h"
 #include "unpack-trees.h"
+#include "dir.h"
 #include "tree.h"
 
 static const char *get_mode(const char *str, unsigned int *modep)
@@ -455,3 +456,186 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch
        free(tree);
        return retval;
 }
+
+static int match_entry(const struct name_entry *entry, int pathlen,
+                      const char *match, int matchlen,
+                      int *never_interesting)
+{
+       int m = -1; /* signals that we haven't called strncmp() */
+
+       if (*never_interesting) {
+               /*
+                * We have not seen any match that sorts later
+                * than the current path.
+                */
+
+               /*
+                * Does match sort strictly earlier than path
+                * with their common parts?
+                */
+               m = strncmp(match, entry->path,
+                           (matchlen < pathlen) ? matchlen : pathlen);
+               if (m < 0)
+                       return 0;
+
+               /*
+                * If we come here even once, that means there is at
+                * least one pathspec that would sort equal to or
+                * later than the path we are currently looking at.
+                * In other words, if we have never reached this point
+                * after iterating all pathspecs, it means all
+                * pathspecs are either outside of base, or inside the
+                * base but sorts strictly earlier than the current
+                * one.  In either case, they will never match the
+                * subsequent entries.  In such a case, we initialized
+                * the variable to -1 and that is what will be
+                * returned, allowing the caller to terminate early.
+                */
+               *never_interesting = 0;
+       }
+
+       if (pathlen > matchlen)
+               return 0;
+
+       if (matchlen > pathlen) {
+               if (match[pathlen] != '/')
+                       return 0;
+               if (!S_ISDIR(entry->mode))
+                       return 0;
+       }
+
+       if (m == -1)
+               /*
+                * we cheated and did not do strncmp(), so we do
+                * that here.
+                */
+               m = strncmp(match, entry->path, pathlen);
+
+       /*
+        * If common part matched earlier then it is a hit,
+        * because we rejected the case where path is not a
+        * leading directory and is shorter than match.
+        */
+       if (!m)
+               return 1;
+
+       return 0;
+}
+
+static int match_dir_prefix(const char *base, int baselen,
+                           const char *match, int matchlen)
+{
+       if (strncmp(base, match, matchlen))
+               return 0;
+
+       /*
+        * If the base is a subdirectory of a path which
+        * was specified, all of them are interesting.
+        */
+       if (!matchlen ||
+           base[matchlen] == '/' ||
+           match[matchlen - 1] == '/')
+               return 1;
+
+       /* Just a random prefix match */
+       return 0;
+}
+
+/*
+ * Is a tree entry interesting given the pathspec we have?
+ *
+ * Pre-condition: either baselen == base_offset (i.e. empty path)
+ * or base[baselen-1] == '/' (i.e. with trailing slash).
+ *
+ * Return:
+ *  - 2 for "yes, and all subsequent entries will be"
+ *  - 1 for yes
+ *  - zero for no
+ *  - negative for "no, and no subsequent entries will be either"
+ */
+int tree_entry_interesting(const struct name_entry *entry,
+                          struct strbuf *base, int base_offset,
+                          const struct pathspec *ps)
+{
+       int i;
+       int pathlen, baselen = base->len - base_offset;
+       int never_interesting = ps->has_wildcard ? 0 : -1;
+
+       if (!ps->nr) {
+               if (!ps->recursive || ps->max_depth == -1)
+                       return 2;
+               return !!within_depth(base->buf + base_offset, baselen,
+                                     !!S_ISDIR(entry->mode),
+                                     ps->max_depth);
+       }
+
+       pathlen = tree_entry_len(entry->path, entry->sha1);
+
+       for (i = ps->nr - 1; i >= 0; i--) {
+               const struct pathspec_item *item = ps->items+i;
+               const char *match = item->match;
+               const char *base_str = base->buf + base_offset;
+               int matchlen = item->len;
+
+               if (baselen >= matchlen) {
+                       /* If it doesn't match, move along... */
+                       if (!match_dir_prefix(base_str, baselen, match, matchlen))
+                               goto match_wildcards;
+
+                       if (!ps->recursive || ps->max_depth == -1)
+                               return 2;
+
+                       return !!within_depth(base_str + matchlen + 1,
+                                             baselen - matchlen - 1,
+                                             !!S_ISDIR(entry->mode),
+                                             ps->max_depth);
+               }
+
+               /* Does the base match? */
+               if (!strncmp(base_str, match, baselen)) {
+                       if (match_entry(entry, pathlen,
+                                       match + baselen, matchlen - baselen,
+                                       &never_interesting))
+                               return 1;
+
+                       if (ps->items[i].has_wildcard) {
+                               if (!fnmatch(match + baselen, entry->path, 0))
+                                       return 1;
+
+                               /*
+                                * Match all directories. We'll try to
+                                * match files later on.
+                                */
+                               if (ps->recursive && S_ISDIR(entry->mode))
+                                       return 1;
+                       }
+
+                       continue;
+               }
+
+match_wildcards:
+               if (!ps->items[i].has_wildcard)
+                       continue;
+
+               /*
+                * Concatenate base and entry->path into one and do
+                * fnmatch() on it.
+                */
+
+               strbuf_add(base, entry->path, pathlen);
+
+               if (!fnmatch(match, base->buf + base_offset, 0)) {
+                       strbuf_setlen(base, base_offset + baselen);
+                       return 1;
+               }
+               strbuf_setlen(base, base_offset + baselen);
+
+               /*
+                * Match all directories. We'll try to match files
+                * later on.
+                */
+               if (ps->recursive && S_ISDIR(entry->mode))
+                       return 1;
+       }
+       return never_interesting; /* No matches */
+}
index 7e3e0b5ad16710c06464726ac04d2b1c48af3708..39524b7dba6a1d0b63c4cd2b42db59a27a030b21 100644 (file)
@@ -60,4 +60,6 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru
        return info->pathlen + tree_entry_len(n->path, n->sha1);
 }
 
+extern int tree_entry_interesting(const struct name_entry *, struct strbuf *, int, const struct pathspec *ps);
+
 #endif
index 1ca41b1a6986559a7c5ddc3983d751d75a0d23ff..500ebcfd545772fb17e5fb14bba42bf4be468b75 100644 (file)
@@ -16,7 +16,7 @@
  * situation better.  See how "git checkout" and "git merge" replaces
  * them using setup_unpack_trees_porcelain(), for example.
  */
-const char *unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = {
+static const char *unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = {
        /* ERROR_WOULD_OVERWRITE */
        "Entry '%s' would be overwritten by merge. Cannot merge.",
 
@@ -381,7 +381,7 @@ static void add_same_unmerged(struct cache_entry *ce,
 static int unpack_index_entry(struct cache_entry *ce,
                              struct unpack_trees_options *o)
 {
-       struct cache_entry *src[5] = { NULL };
+       struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, };
        int ret;
 
        src[0] = ce;
@@ -427,7 +427,10 @@ static int switch_cache_bottom(struct traverse_info *info)
        return ret;
 }
 
-static int traverse_trees_recursive(int n, unsigned long dirmask, unsigned long df_conflicts, struct name_entry *names, struct traverse_info *info)
+static int traverse_trees_recursive(int n, unsigned long dirmask,
+                                   unsigned long df_conflicts,
+                                   struct name_entry *names,
+                                   struct traverse_info *info)
 {
        int i, ret, bottom;
        struct tree_desc t[MAX_UNPACK_TREES];
@@ -1105,6 +1108,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 
                }
                if (o->result.cache_nr && empty_worktree) {
+                       /* dubious---why should this fail??? */
                        ret = unpack_failed(o, "Sparse checkout leaves no entry on working directory");
                        goto done;
                }
@@ -1374,16 +1378,22 @@ static int verify_absent_1(struct cache_entry *ce,
                char path[PATH_MAX + 1];
                memcpy(path, ce->name, len);
                path[len] = 0;
-               lstat(path, &st);
+               if (lstat(path, &st))
+                       return error("cannot stat '%s': %s", path,
+                                       strerror(errno));
 
                return check_ok_to_remove(path, len, DT_UNKNOWN, NULL, &st,
                                error_type, o);
-       } else if (!lstat(ce->name, &st))
+       } else if (lstat(ce->name, &st)) {
+               if (errno != ENOENT)
+                       return error("cannot stat '%s': %s", ce->name,
+                                    strerror(errno));
+               return 0;
+       } else {
                return check_ok_to_remove(ce->name, ce_namelen(ce),
-                               ce_to_dtype(ce), ce, &st,
-                               error_type, o);
-
-       return 0;
+                                         ce_to_dtype(ce), ce, &st,
+                                         error_type, o);
+       }
 }
 
 static int verify_absent(struct cache_entry *ce,
index b40a43f27d0e16f0305153f984741938b3a6ab89..72aa661f8dabb7203001a7d9295dcf6c10ca75ee 100644 (file)
@@ -27,6 +27,7 @@ static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=<
 static unsigned long oldest_have;
 
 static int multi_ack, nr_our_refs;
+static int no_done;
 static int use_thin_pack, use_ofs_delta, use_include_tag;
 static int no_progress, daemon_mode;
 static int shallow_nr;
@@ -429,6 +430,9 @@ static int get_common_commits(void)
        static char line[1000];
        unsigned char sha1[20];
        char last_hex[41];
+       int got_common = 0;
+       int got_other = 0;
+       int sent_ready = 0;
 
        save_commit_buffer = 0;
 
@@ -437,25 +441,40 @@ static int get_common_commits(void)
                reset_timeout();
 
                if (!len) {
+                       if (multi_ack == 2 && got_common
+                           && !got_other && ok_to_give_up()) {
+                               sent_ready = 1;
+                               packet_write(1, "ACK %s ready\n", last_hex);
+                       }
                        if (have_obj.nr == 0 || multi_ack)
                                packet_write(1, "NAK\n");
+
+                       if (no_done && sent_ready) {
+                               packet_write(1, "ACK %s\n", last_hex);
+                               return 0;
+                       }
                        if (stateless_rpc)
                                exit(0);
+                       got_common = 0;
+                       got_other = 0;
                        continue;
                }
                strip(line, len);
                if (!prefixcmp(line, "have ")) {
                        switch (got_sha1(line+5, sha1)) {
                        case -1: /* they have what we do not */
+                               got_other = 1;
                                if (multi_ack && ok_to_give_up()) {
                                        const char *hex = sha1_to_hex(sha1);
-                                       if (multi_ack == 2)
+                                       if (multi_ack == 2) {
+                                               sent_ready = 1;
                                                packet_write(1, "ACK %s ready\n", hex);
-                                       else
+                                       else
                                                packet_write(1, "ACK %s continue\n", hex);
                                }
                                break;
                        default:
+                               got_common = 1;
                                memcpy(last_hex, sha1_to_hex(sha1), 41);
                                if (multi_ack == 2)
                                        packet_write(1, "ACK %s common\n", last_hex);
@@ -526,6 +545,8 @@ static void receive_needs(void)
                        multi_ack = 2;
                else if (strstr(line+45, "multi_ack"))
                        multi_ack = 1;
+               if (strstr(line+45, "no-done"))
+                       no_done = 1;
                if (strstr(line+45, "thin-pack"))
                        use_thin_pack = 1;
                if (strstr(line+45, "ofs-delta"))
@@ -619,7 +640,7 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
 {
        static const char *capabilities = "multi_ack thin-pack side-band"
                " side-band-64k ofs-delta shallow no-progress"
-               " include-tag multi_ack_detailed";
+               " include-tag multi_ack_detailed no-done";
        struct object *o = parse_object(sha1);
 
        if (!o)
@@ -682,6 +703,7 @@ int main(int argc, char **argv)
        int i;
        int strict = 0;
 
+       packet_trace_identity("upload-pack");
        git_extract_argv0_path(argv[0]);
        read_replace_refs = 0;
 
diff --git a/url.c b/url.c
index 6a5495960f03ded65f0f5f8b8bd5c7cd98c0b05e..3e06fd34c46a00b41f4843ea87a151314ce0789c 100644 (file)
--- a/url.c
+++ b/url.c
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "url.h"
 
 int is_urlschemechar(int first_flag, int ch)
 {
diff --git a/usage.c b/usage.c
index ec4cf53b6bf16f7f9b3528a430891d6c68ef64cc..b5e67e3d0d4a46a69d72371f4c6a0002e40a0bf1 100644 (file)
--- a/usage.c
+++ b/usage.c
@@ -46,7 +46,7 @@ void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list param
        die_routine = routine;
 }
 
-void usagef(const char *err, ...)
+void NORETURN usagef(const char *err, ...)
 {
        va_list params;
 
@@ -55,12 +55,12 @@ void usagef(const char *err, ...)
        va_end(params);
 }
 
-void usage(const char *err)
+void NORETURN usage(const char *err)
 {
        usagef("%s", err);
 }
 
-void die(const char *err, ...)
+void NORETURN die(const char *err, ...)
 {
        va_list params;
 
@@ -69,7 +69,7 @@ void die(const char *err, ...)
        va_end(params);
 }
 
-void die_errno(const char *fmt, ...)
+void NORETURN die_errno(const char *fmt, ...)
 {
        va_list params;
        char fmt_with_err[1024];
index 9ebf231ea5ee2e7fd1f71c9557a6537d29428d8d..1ff47977d549992ada8c1236187d4516b648ee7d 100644 (file)
@@ -8,9 +8,11 @@ static int ndrivers;
 static int drivers_alloc;
 
 #define PATTERNS(name, pattern, word_regex)                    \
-       { name, NULL, -1, { pattern, REG_EXTENDED }, word_regex }
+       { name, NULL, -1, { pattern, REG_EXTENDED },            \
+         word_regex "|[^[:space:]]|[\xc0-\xff][\x80-\xbf]+" }
 #define IPATTERN(name, pattern, word_regex)                    \
-       { name, NULL, -1, { pattern, REG_EXTENDED | REG_ICASE }, word_regex }
+       { name, NULL, -1, { pattern, REG_EXTENDED | REG_ICASE }, \
+         word_regex "|[^[:space:]]|[\xc0-\xff][\x80-\xbf]+" }
 static struct userdiff_driver builtin_drivers[] = {
 IPATTERN("fortran",
         "!^([C*]|[ \t]*!)\n"
@@ -24,10 +26,9 @@ IPATTERN("fortran",
          * Don't worry about format statements without leading digits since
          * they would have been matched above as a variable anyway. */
         "|[-+]?[0-9.]+([AaIiDdEeFfLlTtXx][Ss]?[-+]?[0-9.]*)?(_[a-zA-Z0-9][a-zA-Z0-9_]*)?"
-        "|//|\\*\\*|::|[/<>=]="
-        "|[^[:space:]]|[\x80-\xff]+"),
+        "|//|\\*\\*|::|[/<>=]="),
 PATTERNS("html", "^[ \t]*(<[Hh][1-6][ \t].*>.*)$",
-        "[^<>= \t]+|[^[:space:]]|[\x80-\xff]+"),
+        "[^<>= \t]+"),
 PATTERNS("java",
         "!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n"
         "^[ \t]*(([A-Za-z_][A-Za-z_0-9]*[ \t]+)+[A-Za-z_][A-Za-z_0-9]*[ \t]*\\([^;]*)$",
@@ -35,8 +36,7 @@ PATTERNS("java",
         "[a-zA-Z_][a-zA-Z0-9_]*"
         "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
         "|[-+*/<>%&^|=!]="
-        "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"
-        "|[^[:space:]]|[\x80-\xff]+"),
+        "|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
 PATTERNS("objc",
         /* Negate C statements that can look like functions */
         "!^[ \t]*(do|for|if|else|return|switch|while)\n"
@@ -49,8 +49,7 @@ PATTERNS("objc",
         /* -- */
         "[a-zA-Z_][a-zA-Z0-9_]*"
         "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
-        "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"
-        "|[^[:space:]]|[\x80-\xff]+"),
+        "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"),
 PATTERNS("pascal",
         "^(((class[ \t]+)?(procedure|function)|constructor|destructor|interface|"
                "implementation|initialization|finalization)[ \t]*.*)$"
@@ -59,8 +58,7 @@ PATTERNS("pascal",
         /* -- */
         "[a-zA-Z_][a-zA-Z0-9_]*"
         "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+"
-        "|<>|<=|>=|:=|\\.\\."
-        "|[^[:space:]]|[\x80-\xff]+"),
+        "|<>|<=|>=|:=|\\.\\."),
 PATTERNS("perl",
         "^[ \t]*package .*;\n"
         "^[ \t]*sub .* \\{\n"
@@ -76,33 +74,29 @@ PATTERNS("perl",
         "|&&|\\|\\||//|\\+\\+|--|\\*\\*|\\.\\.\\.?"
         "|[-+*/%.^&<>=!|]="
         "|=~|!~"
-        "|<<|<>|<=>|>>"
-        "|[^[:space:]]"),
+        "|<<|<>|<=>|>>"),
 PATTERNS("php",
         "^[\t ]*(((public|protected|private|static)[\t ]+)*function.*)$\n"
         "^[\t ]*(class.*)$",
         /* -- */
         "[a-zA-Z_][a-zA-Z0-9_]*"
         "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+"
-        "|[-+*/<>%&^|=!.]=|--|\\+\\+|<<=?|>>=?|===|&&|\\|\\||::|->"
-        "|[^[:space:]]|[\x80-\xff]+"),
+        "|[-+*/<>%&^|=!.]=|--|\\+\\+|<<=?|>>=?|===|&&|\\|\\||::|->"),
 PATTERNS("python", "^[ \t]*((class|def)[ \t].*)$",
         /* -- */
         "[a-zA-Z_][a-zA-Z0-9_]*"
         "|[-+0-9.e]+[jJlL]?|0[xX]?[0-9a-fA-F]+[lL]?"
-        "|[-+*/<>%&^|=!]=|//=?|<<=?|>>=?|\\*\\*=?"
-        "|[^[:space:]]|[\x80-\xff]+"),
+        "|[-+*/<>%&^|=!]=|//=?|<<=?|>>=?|\\*\\*=?"),
         /* -- */
 PATTERNS("ruby", "^[ \t]*((class|module|def)[ \t].*)$",
         /* -- */
         "(@|@@|\\$)?[a-zA-Z_][a-zA-Z0-9_]*"
         "|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+|\\?(\\\\C-)?(\\\\M-)?."
-        "|//=?|[-+*/<>%&^|=!]=|<<=?|>>=?|===|\\.{1,3}|::|[!=]~"
-        "|[^[:space:]]|[\x80-\xff]+"),
+        "|//=?|[-+*/<>%&^|=!]=|<<=?|>>=?|===|\\.{1,3}|::|[!=]~"),
 PATTERNS("bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$",
         "[={}\"]|[^={}\" \t]+"),
 PATTERNS("tex", "^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
-        "\\\\[a-zA-Z@]+|\\\\.|[a-zA-Z0-9\x80-\xff]+|[^[:space:]]"),
+        "\\\\[a-zA-Z@]+|\\\\.|[a-zA-Z0-9\x80-\xff]+"),
 PATTERNS("cpp",
         /* Jump targets or access declarations */
         "!^[ \t]*[A-Za-z_][A-Za-z_0-9]*:.*$\n"
@@ -113,8 +107,7 @@ PATTERNS("cpp",
         /* -- */
         "[a-zA-Z_][a-zA-Z0-9_]*"
         "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
-        "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"
-        "|[^[:space:]]|[\x80-\xff]+"),
+        "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"),
 PATTERNS("csharp",
         /* Keywords */
         "!^[ \t]*(do|while|for|if|else|instanceof|new|return|switch|case|throw|catch|using)\n"
@@ -129,8 +122,7 @@ PATTERNS("csharp",
         /* -- */
         "[a-zA-Z_][a-zA-Z0-9_]*"
         "|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
-        "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"
-        "|[^[:space:]]|[\x80-\xff]+"),
+        "|[-+*/<>%&^|=!]=|--|\\+\\+|<<=?|>>=?|&&|\\|\\||::|->"),
 { "default", NULL, -1, { NULL, 0 } },
 };
 #undef PATTERNS
diff --git a/utf8.c b/utf8.c
index 84cfc72e6db144880febad0a4ffa64800919fb6d..8acbc660d31a3552a4451749353139e0dcd371bd 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -405,6 +405,15 @@ new_line:
        }
 }
 
+int strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
+                            int indent, int indent2, int width)
+{
+       char *tmp = xstrndup(data, len);
+       int r = strbuf_add_wrapped_text(buf, tmp, indent, indent2, width);
+       free(tmp);
+       return r;
+}
+
 int is_encoding_utf8(const char *name)
 {
        if (!name)
diff --git a/utf8.h b/utf8.h
index ebc4d2fa85113c971ab4c4eaa52537a688a03745..81f2c82fabcf63e3bb02c15beb4a0409afd9ab7b 100644 (file)
--- a/utf8.h
+++ b/utf8.h
@@ -10,6 +10,8 @@ int is_encoding_utf8(const char *name);
 
 int strbuf_add_wrapped_text(struct strbuf *buf,
                const char *text, int indent, int indent2, int width);
+int strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
+                            int indent, int indent2, int width);
 
 #ifndef NO_ICONV
 char *reencode_string(const char *in, const char *out_encoding, const char *in_encoding);
index 6cfa256a3702332205faab546a405f6810cc16bd..a4d4d9993dac74f0e751009f30588aef62d3a573 100644 (file)
@@ -31,24 +31,24 @@ void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode,
 }
 
 static char gitsvnline[MAX_GITSVN_LINE_LEN];
-void fast_export_commit(uint32_t revision, uint32_t author, char *log,
-                       uint32_t uuid, uint32_t url,
+void fast_export_commit(uint32_t revision, const char *author, char *log,
+                       const char *uuid, const char *url,
                        unsigned long timestamp)
 {
        if (!log)
                log = "";
-       if (~uuid && ~url) {
+       if (*uuid && *url) {
                snprintf(gitsvnline, MAX_GITSVN_LINE_LEN,
                                "\n\ngit-svn-id: %s@%"PRIu32" %s\n",
-                                pool_fetch(url), revision, pool_fetch(uuid));
+                                url, revision, uuid);
        } else {
                *gitsvnline = '\0';
        }
        printf("commit refs/heads/master\n");
        printf("committer %s <%s@%s> %ld +0000\n",
-                  ~author ? pool_fetch(author) : "nobody",
-                  ~author ? pool_fetch(author) : "nobody",
-                  ~uuid ? pool_fetch(uuid) : "local", timestamp);
+                  *author ? author : "nobody",
+                  *author ? author : "nobody",
+                  *uuid ? uuid : "local", timestamp);
        printf("data %"PRIu32"\n%s%s\n",
                   (uint32_t) (strlen(log) + strlen(gitsvnline)),
                   log, gitsvnline);
@@ -63,14 +63,23 @@ void fast_export_commit(uint32_t revision, uint32_t author, char *log,
        printf("progress Imported commit %"PRIu32".\n\n", revision);
 }
 
-void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len)
+static void die_short_read(struct line_buffer *input)
+{
+       if (buffer_ferror(input))
+               die_errno("error reading dump file");
+       die("invalid dump: unexpected end of file");
+}
+
+void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len, struct line_buffer *input)
 {
        if (mode == REPO_MODE_LNK) {
                /* svn symlink blobs start with "link " */
-               buffer_skip_bytes(5);
                len -= 5;
+               if (buffer_skip_bytes(input, 5) != 5)
+                       die_short_read(input);
        }
        printf("blob\nmark :%"PRIu32"\ndata %"PRIu32"\n", mark, len);
-       buffer_copy_bytes(len);
+       if (buffer_copy_bytes(input, len) != len)
+               die_short_read(input);
        fputc('\n', stdout);
 }
index 2aaaea53d57bcc6a5280765dd39edf7fc5569c19..05cf97f3a7854e3ddf7060b361278ca82adc844b 100644 (file)
@@ -1,11 +1,15 @@
 #ifndef FAST_EXPORT_H_
 #define FAST_EXPORT_H_
 
+#include "line_buffer.h"
+
 void fast_export_delete(uint32_t depth, uint32_t *path);
 void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode,
                        uint32_t mark);
-void fast_export_commit(uint32_t revision, uint32_t author, char *log,
-                       uint32_t uuid, uint32_t url, unsigned long timestamp);
-void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len);
+void fast_export_commit(uint32_t revision, const char *author, char *log,
+                       const char *uuid, const char *url,
+                       unsigned long timestamp);
+void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len,
+                     struct line_buffer *input);
 
 #endif
index 1543567093fad603e09ba61b2fc47ec232b4cae2..33e733a04c2b694a7dce80c8404edd464fe1a6b7 100644 (file)
@@ -5,47 +5,81 @@
 
 #include "git-compat-util.h"
 #include "line_buffer.h"
-#include "obj_pool.h"
+#include "strbuf.h"
 
-#define LINE_BUFFER_LEN 10000
 #define COPY_BUFFER_LEN 4096
 
-/* Create memory pool for char sequence of known length */
-obj_pool_gen(blob, char, 4096)
+int buffer_init(struct line_buffer *buf, const char *filename)
+{
+       buf->infile = filename ? fopen(filename, "r") : stdin;
+       if (!buf->infile)
+               return -1;
+       return 0;
+}
 
-static char line_buffer[LINE_BUFFER_LEN];
-static char byte_buffer[COPY_BUFFER_LEN];
-static FILE *infile;
+int buffer_fdinit(struct line_buffer *buf, int fd)
+{
+       buf->infile = fdopen(fd, "r");
+       if (!buf->infile)
+               return -1;
+       return 0;
+}
 
-int buffer_init(const char *filename)
+int buffer_tmpfile_init(struct line_buffer *buf)
 {
-       infile = filename ? fopen(filename, "r") : stdin;
-       if (!infile)
+       buf->infile = tmpfile();
+       if (!buf->infile)
                return -1;
        return 0;
 }
 
-int buffer_deinit(void)
+int buffer_deinit(struct line_buffer *buf)
 {
        int err;
-       if (infile == stdin)
-               return ferror(infile);
-       err = ferror(infile);
-       err |= fclose(infile);
+       if (buf->infile == stdin)
+               return ferror(buf->infile);
+       err = ferror(buf->infile);
+       err |= fclose(buf->infile);
        return err;
 }
 
+FILE *buffer_tmpfile_rewind(struct line_buffer *buf)
+{
+       rewind(buf->infile);
+       return buf->infile;
+}
+
+long buffer_tmpfile_prepare_to_read(struct line_buffer *buf)
+{
+       long pos = ftell(buf->infile);
+       if (pos < 0)
+               return error("ftell error: %s", strerror(errno));
+       if (fseek(buf->infile, 0, SEEK_SET))
+               return error("seek error: %s", strerror(errno));
+       return pos;
+}
+
+int buffer_ferror(struct line_buffer *buf)
+{
+       return ferror(buf->infile);
+}
+
+int buffer_read_char(struct line_buffer *buf)
+{
+       return fgetc(buf->infile);
+}
+
 /* Read a line without trailing newline. */
-char *buffer_read_line(void)
+char *buffer_read_line(struct line_buffer *buf)
 {
        char *end;
-       if (!fgets(line_buffer, sizeof(line_buffer), infile))
+       if (!fgets(buf->line_buffer, sizeof(buf->line_buffer), buf->infile))
                /* Error or data exhausted. */
                return NULL;
-       end = line_buffer + strlen(line_buffer);
+       end = buf->line_buffer + strlen(buf->line_buffer);
        if (end[-1] == '\n')
                end[-1] = '\0';
-       else if (feof(infile))
+       else if (feof(buf->infile))
                ; /* No newline at end of file.  That's fine. */
        else
                /*
@@ -54,44 +88,51 @@ char *buffer_read_line(void)
                 * but for now let's return an error.
                 */
                return NULL;
-       return line_buffer;
+       return buf->line_buffer;
+}
+
+char *buffer_read_string(struct line_buffer *buf, uint32_t len)
+{
+       strbuf_reset(&buf->blob_buffer);
+       strbuf_fread(&buf->blob_buffer, len, buf->infile);
+       return ferror(buf->infile) ? NULL : buf->blob_buffer.buf;
 }
 
-char *buffer_read_string(uint32_t len)
+void buffer_read_binary(struct line_buffer *buf,
+                               struct strbuf *sb, uint32_t size)
 {
-       char *s;
-       blob_free(blob_pool.size);
-       s = blob_pointer(blob_alloc(len + 1));
-       s[fread(s, 1, len, infile)] = '\0';
-       return ferror(infile) ? NULL : s;
+       strbuf_fread(sb, size, buf->infile);
 }
 
-void buffer_copy_bytes(uint32_t len)
+off_t buffer_copy_bytes(struct line_buffer *buf, off_t nbytes)
 {
-       uint32_t in;
-       while (len > 0 && !feof(infile) && !ferror(infile)) {
-               in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
-               in = fread(byte_buffer, 1, in, infile);
-               len -= in;
+       char byte_buffer[COPY_BUFFER_LEN];
+       off_t done = 0;
+       while (done < nbytes && !feof(buf->infile) && !ferror(buf->infile)) {
+               off_t len = nbytes - done;
+               size_t in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
+               in = fread(byte_buffer, 1, in, buf->infile);
+               done += in;
                fwrite(byte_buffer, 1, in, stdout);
-               if (ferror(stdout)) {
-                       buffer_skip_bytes(len);
-                       return;
-               }
+               if (ferror(stdout))
+                       return done + buffer_skip_bytes(buf, nbytes - done);
        }
+       return done;
 }
 
-void buffer_skip_bytes(uint32_t len)
+off_t buffer_skip_bytes(struct line_buffer *buf, off_t nbytes)
 {
-       uint32_t in;
-       while (len > 0 && !feof(infile) && !ferror(infile)) {
-               in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
-               in = fread(byte_buffer, 1, in, infile);
-               len -= in;
+       char byte_buffer[COPY_BUFFER_LEN];
+       off_t done = 0;
+       while (done < nbytes && !feof(buf->infile) && !ferror(buf->infile)) {
+               off_t len = nbytes - done;
+               size_t in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
+               done += fread(byte_buffer, 1, in, buf->infile);
        }
+       return done;
 }
 
-void buffer_reset(void)
+void buffer_reset(struct line_buffer *buf)
 {
-       blob_reset();
+       strbuf_release(&buf->blob_buffer);
 }
index 9c78ae11a1e0774611b61a5407fab6cabfec226a..f5c468afa45f1f567dc5cc2b3e2e748b79fe5cb0 100644 (file)
@@ -1,12 +1,33 @@
 #ifndef LINE_BUFFER_H_
 #define LINE_BUFFER_H_
 
-int buffer_init(const char *filename);
-int buffer_deinit(void);
-char *buffer_read_line(void);
-char *buffer_read_string(uint32_t len);
-void buffer_copy_bytes(uint32_t len);
-void buffer_skip_bytes(uint32_t len);
-void buffer_reset(void);
+#include "strbuf.h"
+
+#define LINE_BUFFER_LEN 10000
+
+struct line_buffer {
+       char line_buffer[LINE_BUFFER_LEN];
+       struct strbuf blob_buffer;
+       FILE *infile;
+};
+#define LINE_BUFFER_INIT {"", STRBUF_INIT, NULL}
+
+int buffer_init(struct line_buffer *buf, const char *filename);
+int buffer_fdinit(struct line_buffer *buf, int fd);
+int buffer_deinit(struct line_buffer *buf);
+void buffer_reset(struct line_buffer *buf);
+
+int buffer_tmpfile_init(struct line_buffer *buf);
+FILE *buffer_tmpfile_rewind(struct line_buffer *buf);  /* prepare to write. */
+long buffer_tmpfile_prepare_to_read(struct line_buffer *buf);
+
+int buffer_ferror(struct line_buffer *buf);
+char *buffer_read_line(struct line_buffer *buf);
+char *buffer_read_string(struct line_buffer *buf, uint32_t len);
+int buffer_read_char(struct line_buffer *buf);
+void buffer_read_binary(struct line_buffer *buf, struct strbuf *sb, uint32_t len);
+/* Returns number of bytes read (not necessarily written). */
+off_t buffer_copy_bytes(struct line_buffer *buf, off_t len);
+off_t buffer_skip_bytes(struct line_buffer *buf, off_t len);
 
 #endif
index 8906fb1f505e125ea58fd7a15c4f13bb0dc78f27..4ef0755cf53e4ee220f1906be7c0cd54ff3265ab 100644 (file)
@@ -14,22 +14,46 @@ Calling sequence
 
 The calling program:
 
+ - initializes a `struct line_buffer` to LINE_BUFFER_INIT
  - specifies a file to read with `buffer_init`
  - processes input with `buffer_read_line`, `buffer_read_string`,
    `buffer_skip_bytes`, and `buffer_copy_bytes`
  - closes the file with `buffer_deinit`, perhaps to start over and
    read another file.
 
-Before exiting, the caller can use `buffer_reset` to deallocate
-resources for the benefit of profiling tools.
+When finished, the caller can use `buffer_reset` to deallocate
+resources.
+
+Using temporary files
+---------------------
+
+Temporary files provide a place to store data that should not outlive
+the calling program.  A program
+
+ - initializes a `struct line_buffer` to LINE_BUFFER_INIT
+ - requests a temporary file with `buffer_tmpfile_init`
+ - acquires an output handle by calling `buffer_tmpfile_rewind`
+ - uses standard I/O functions like `fprintf` and `fwrite` to fill
+   the temporary file
+ - declares writing is over with `buffer_tmpfile_prepare_to_read`
+ - can re-read what was written with `buffer_read_line`,
+   `buffer_read_string`, and so on
+ - can reuse the temporary file by calling `buffer_tmpfile_rewind`
+   again
+ - removes the temporary file with `buffer_deinit`, perhaps to
+   reuse the line_buffer for some other file.
+
+When finished, the calling program can use `buffer_reset` to deallocate
+resources.
 
 Functions
 ---------
 
-`buffer_init`::
-       Open the named file for input.  If filename is NULL,
-       start reading from stdin.  On failure, returns -1 (with
-       errno indicating the nature of the failure).
+`buffer_init`, `buffer_fdinit`::
+       Open the named file or file descriptor for input.
+       buffer_init(buf, NULL) prepares to read from stdin.
+       On failure, returns -1 (with errno indicating the nature
+       of the failure).
 
 `buffer_deinit`::
        Stop reading from the current file (closing it unless
@@ -52,7 +76,8 @@ Functions
 
 `buffer_skip_bytes`::
        Discards `len` bytes from the input stream (stopping early
-       if necessary because of an error or eof).
+       if necessary because of an error or eof).  Return value is
+       the number of bytes successfully read.
 
 `buffer_reset`::
        Deallocates non-static buffers.
index e3d1fa35444dd693ab8723a030b9fc6265cad8bc..632dbd87360b0a4a0c2fa2d401a775e9939bab35 100644 (file)
@@ -38,7 +38,7 @@ static uint32_t mark;
 static int repo_dirent_name_cmp(const void *a, const void *b);
 
 /* Treap for directory entries */
-trp_gen(static, dent_, struct repo_dirent, children, dent, repo_dirent_name_cmp);
+trp_gen(static, dent_, struct repo_dirent, children, dent, repo_dirent_name_cmp)
 
 uint32_t next_blob_mark(void)
 {
@@ -87,7 +87,8 @@ static struct repo_dir *repo_clone_dir(struct repo_dir *orig_dir)
        return dir_pointer(new_o);
 }
 
-static struct repo_dirent *repo_read_dirent(uint32_t revision, uint32_t *path)
+static struct repo_dirent *repo_read_dirent(uint32_t revision,
+                                           const uint32_t *path)
 {
        uint32_t name = 0;
        struct repo_dirent *key = dent_pointer(dent_alloc(1));
@@ -105,7 +106,7 @@ static struct repo_dirent *repo_read_dirent(uint32_t revision, uint32_t *path)
        return dent;
 }
 
-static void repo_write_dirent(uint32_t *path, uint32_t mode,
+static void repo_write_dirent(const uint32_t *path, uint32_t mode,
                              uint32_t content_offset, uint32_t del)
 {
        uint32_t name, revision, dir_o = ~0, parent_dir_o = ~0;
@@ -157,42 +158,37 @@ static void repo_write_dirent(uint32_t *path, uint32_t mode,
                dent_remove(&dir_pointer(parent_dir_o)->entries, dent);
 }
 
-uint32_t repo_copy(uint32_t revision, uint32_t *src, uint32_t *dst)
+uint32_t repo_read_path(const uint32_t *path)
 {
-       uint32_t mode = 0, content_offset = 0;
-       struct repo_dirent *src_dent;
-       src_dent = repo_read_dirent(revision, src);
-       if (src_dent != NULL) {
-               mode = src_dent->mode;
-               content_offset = src_dent->content_offset;
-               repo_write_dirent(dst, mode, content_offset, 0);
-       }
-       return mode;
+       uint32_t content_offset = 0;
+       struct repo_dirent *dent = repo_read_dirent(active_commit, path);
+       if (dent != NULL)
+               content_offset = dent->content_offset;
+       return content_offset;
 }
 
-void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark)
+uint32_t repo_read_mode(const uint32_t *path)
 {
-       repo_write_dirent(path, mode, blob_mark, 0);
+       struct repo_dirent *dent = repo_read_dirent(active_commit, path);
+       if (dent == NULL)
+               die("invalid dump: path to be modified is missing");
+       return dent->mode;
 }
 
-uint32_t repo_replace(uint32_t *path, uint32_t blob_mark)
+void repo_copy(uint32_t revision, const uint32_t *src, const uint32_t *dst)
 {
-       uint32_t mode = 0;
+       uint32_t mode = 0, content_offset = 0;
        struct repo_dirent *src_dent;
-       src_dent = repo_read_dirent(active_commit, path);
+       src_dent = repo_read_dirent(revision, src);
        if (src_dent != NULL) {
                mode = src_dent->mode;
-               repo_write_dirent(path, mode, blob_mark, 0);
+               content_offset = src_dent->content_offset;
+               repo_write_dirent(dst, mode, content_offset, 0);
        }
-       return mode;
 }
 
-void repo_modify(uint32_t *path, uint32_t mode, uint32_t blob_mark)
+void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark)
 {
-       struct repo_dirent *src_dent;
-       src_dent = repo_read_dirent(active_commit, path);
-       if (src_dent != NULL && blob_mark == 0)
-               blob_mark = src_dent->content_offset;
        repo_write_dirent(path, mode, blob_mark, 0);
 }
 
@@ -282,8 +278,8 @@ void repo_diff(uint32_t r1, uint32_t r2)
                    repo_commit_root_dir(commit_pointer(r2)));
 }
 
-void repo_commit(uint32_t revision, uint32_t author, char *log, uint32_t uuid,
-                uint32_t url, unsigned long timestamp)
+void repo_commit(uint32_t revision, const char *author, char *log,
+                const char *uuid, const char *url, unsigned long timestamp)
 {
        fast_export_commit(revision, author, log, uuid, url, timestamp);
        dent_commit();
index 5476175922740eaba663533a58deedfa981de659..a1b0e87651b7576cd4e1842261d745664331793a 100644 (file)
 #define REPO_MAX_PATH_DEPTH 1000
 
 uint32_t next_blob_mark(void);
-uint32_t repo_copy(uint32_t revision, uint32_t *src, uint32_t *dst);
+void repo_copy(uint32_t revision, const uint32_t *src, const uint32_t *dst);
 void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark);
-uint32_t repo_replace(uint32_t *path, uint32_t blob_mark);
-void repo_modify(uint32_t *path, uint32_t mode, uint32_t blob_mark);
+uint32_t repo_read_path(const uint32_t *path);
+uint32_t repo_read_mode(const uint32_t *path);
 void repo_delete(uint32_t *path);
-void repo_commit(uint32_t revision, uint32_t author, char *log, uint32_t uuid,
-                uint32_t url, long unsigned timestamp);
+void repo_commit(uint32_t revision, const char *author,
+               char *log, const char *uuid, const char *url,
+               long unsigned timestamp);
 void repo_diff(uint32_t r1, uint32_t r2);
 void repo_init(void);
 void repo_reset(void);
index f5b1da836e01bd17254b50ab3c88bae01eee200d..8af8d54d6ef41a2e84e500bd0d1a5523e59f8a32 100644 (file)
@@ -30,7 +30,7 @@ static int node_cmp(struct node *a, struct node *b)
 }
 
 /* Build a Treap from the node structure (a trp_node w/ offset) */
-trp_gen(static, tree_, struct node, children, node, node_cmp);
+trp_gen(static, tree_, struct node, children, node, node_cmp)
 
 const char *pool_fetch(uint32_t entry)
 {
index 2ad2c307dd6e8f4bddf5cbd9c588973a085bf870..ea5b128e4f205cd95694839ca9eb9b072333fa99 100644 (file)
 #include "repo_tree.h"
 #include "fast_export.h"
 #include "line_buffer.h"
-#include "obj_pool.h"
 #include "string_pool.h"
+#include "strbuf.h"
+
+/*
+ * Compare start of string to literal of equal length;
+ * must be guarded by length test.
+ */
+#define constcmp(s, ref) memcmp(s, ref, sizeof(ref) - 1)
 
 #define NODEACT_REPLACE 4
 #define NODEACT_DELETE 3
 #define LENGTH_UNKNOWN (~0)
 #define DATE_RFC2822_LEN 31
 
-/* Create memory pool for log messages */
-obj_pool_gen(log, char, 4096)
-
-static char* log_copy(uint32_t length, char *log)
-{
-       char *buffer;
-       log_free(log_pool.size);
-       buffer = log_pointer(log_alloc(length));
-       strncpy(buffer, log, length);
-       return buffer;
-}
+static struct line_buffer input = LINE_BUFFER_INIT;
 
 static struct {
-       uint32_t action, propLength, textLength, srcRev, srcMode, mark, type;
+       uint32_t action, propLength, textLength, srcRev, type;
        uint32_t src[REPO_MAX_PATH_DEPTH], dst[REPO_MAX_PATH_DEPTH];
+       uint32_t text_delta, prop_delta;
 } node_ctx;
 
 static struct {
-       uint32_t revision, author;
+       uint32_t revision;
        unsigned long timestamp;
-       char *log;
+       struct strbuf log, author;
 } rev_ctx;
 
 static struct {
-       uint32_t version, uuid, url;
+       uint32_t version;
+       struct strbuf uuid, url;
 } dump_ctx;
 
-static struct {
-       uint32_t svn_log, svn_author, svn_date, svn_executable, svn_special, uuid,
-               revision_number, node_path, node_kind, node_action,
-               node_copyfrom_path, node_copyfrom_rev, text_content_length,
-               prop_content_length, content_length, svn_fs_dump_format_version;
-} keys;
-
 static void reset_node_ctx(char *fname)
 {
        node_ctx.type = 0;
@@ -69,126 +60,226 @@ static void reset_node_ctx(char *fname)
        node_ctx.textLength = LENGTH_UNKNOWN;
        node_ctx.src[0] = ~0;
        node_ctx.srcRev = 0;
-       node_ctx.srcMode = 0;
        pool_tok_seq(REPO_MAX_PATH_DEPTH, node_ctx.dst, "/", fname);
-       node_ctx.mark = 0;
+       node_ctx.text_delta = 0;
+       node_ctx.prop_delta = 0;
 }
 
 static void reset_rev_ctx(uint32_t revision)
 {
        rev_ctx.revision = revision;
        rev_ctx.timestamp = 0;
-       rev_ctx.log = NULL;
-       rev_ctx.author = ~0;
+       strbuf_reset(&rev_ctx.log);
+       strbuf_reset(&rev_ctx.author);
 }
 
-static void reset_dump_ctx(uint32_t url)
+static void reset_dump_ctx(const char *url)
 {
-       dump_ctx.url = url;
+       strbuf_reset(&dump_ctx.url);
+       if (url)
+               strbuf_addstr(&dump_ctx.url, url);
        dump_ctx.version = 1;
-       dump_ctx.uuid = ~0;
+       strbuf_reset(&dump_ctx.uuid);
+}
+
+static void handle_property(const struct strbuf *key_buf,
+                               const char *val, uint32_t len,
+                               uint32_t *type_set)
+{
+       const char *key = key_buf->buf;
+       size_t keylen = key_buf->len;
+
+       switch (keylen + 1) {
+       case sizeof("svn:log"):
+               if (constcmp(key, "svn:log"))
+                       break;
+               if (!val)
+                       die("invalid dump: unsets svn:log");
+               strbuf_reset(&rev_ctx.log);
+               strbuf_add(&rev_ctx.log, val, len);
+               break;
+       case sizeof("svn:author"):
+               if (constcmp(key, "svn:author"))
+                       break;
+               strbuf_reset(&rev_ctx.author);
+               if (val)
+                       strbuf_add(&rev_ctx.author, val, len);
+               break;
+       case sizeof("svn:date"):
+               if (constcmp(key, "svn:date"))
+                       break;
+               if (!val)
+                       die("invalid dump: unsets svn:date");
+               if (parse_date_basic(val, &rev_ctx.timestamp, NULL))
+                       warning("invalid timestamp: %s", val);
+               break;
+       case sizeof("svn:executable"):
+       case sizeof("svn:special"):
+               if (keylen == strlen("svn:executable") &&
+                   constcmp(key, "svn:executable"))
+                       break;
+               if (keylen == strlen("svn:special") &&
+                   constcmp(key, "svn:special"))
+                       break;
+               if (*type_set) {
+                       if (!val)
+                               return;
+                       die("invalid dump: sets type twice");
+               }
+               if (!val) {
+                       node_ctx.type = REPO_MODE_BLB;
+                       return;
+               }
+               *type_set = 1;
+               node_ctx.type = keylen == strlen("svn:executable") ?
+                               REPO_MODE_EXE :
+                               REPO_MODE_LNK;
+       }
 }
 
-static void init_keys(void)
+static void die_short_read(void)
 {
-       keys.svn_log = pool_intern("svn:log");
-       keys.svn_author = pool_intern("svn:author");
-       keys.svn_date = pool_intern("svn:date");
-       keys.svn_executable = pool_intern("svn:executable");
-       keys.svn_special = pool_intern("svn:special");
-       keys.uuid = pool_intern("UUID");
-       keys.revision_number = pool_intern("Revision-number");
-       keys.node_path = pool_intern("Node-path");
-       keys.node_kind = pool_intern("Node-kind");
-       keys.node_action = pool_intern("Node-action");
-       keys.node_copyfrom_path = pool_intern("Node-copyfrom-path");
-       keys.node_copyfrom_rev = pool_intern("Node-copyfrom-rev");
-       keys.text_content_length = pool_intern("Text-content-length");
-       keys.prop_content_length = pool_intern("Prop-content-length");
-       keys.content_length = pool_intern("Content-length");
-       keys.svn_fs_dump_format_version = pool_intern("SVN-fs-dump-format-version");
+       if (buffer_ferror(&input))
+               die_errno("error reading dump file");
+       die("invalid dump: unexpected end of file");
 }
 
 static void read_props(void)
 {
-       uint32_t len;
-       uint32_t key = ~0;
-       char *val = NULL;
-       char *t;
-       while ((t = buffer_read_line()) && strcmp(t, "PROPS-END")) {
-               if (!strncmp(t, "K ", 2)) {
-                       len = atoi(&t[2]);
-                       key = pool_intern(buffer_read_string(len));
-                       buffer_read_line();
-               } else if (!strncmp(t, "V ", 2)) {
-                       len = atoi(&t[2]);
-                       val = buffer_read_string(len);
-                       if (key == keys.svn_log) {
-                               /* Value length excludes terminating nul. */
-                               rev_ctx.log = log_copy(len + 1, val);
-                       } else if (key == keys.svn_author) {
-                               rev_ctx.author = pool_intern(val);
-                       } else if (key == keys.svn_date) {
-                               if (parse_date_basic(val, &rev_ctx.timestamp, NULL))
-                                       fprintf(stderr, "Invalid timestamp: %s\n", val);
-                       } else if (key == keys.svn_executable) {
-                               node_ctx.type = REPO_MODE_EXE;
-                       } else if (key == keys.svn_special) {
-                               node_ctx.type = REPO_MODE_LNK;
-                       }
-                       key = ~0;
-                       buffer_read_line();
+       static struct strbuf key = STRBUF_INIT;
+       const char *t;
+       /*
+        * NEEDSWORK: to support simple mode changes like
+        *      K 11
+        *      svn:special
+        *      V 1
+        *      *
+        *      D 14
+        *      svn:executable
+        * we keep track of whether a mode has been set and reset to
+        * plain file only if not.  We should be keeping track of the
+        * symlink and executable bits separately instead.
+        */
+       uint32_t type_set = 0;
+       while ((t = buffer_read_line(&input)) && strcmp(t, "PROPS-END")) {
+               uint32_t len;
+               const char *val;
+               const char type = t[0];
+               int ch;
+
+               if (!type || t[1] != ' ')
+                       die("invalid property line: %s\n", t);
+               len = atoi(&t[2]);
+               val = buffer_read_string(&input, len);
+               if (!val || strlen(val) != len)
+                       die_short_read();
+
+               /* Discard trailing newline. */
+               ch = buffer_read_char(&input);
+               if (ch == EOF)
+                       die_short_read();
+               if (ch != '\n')
+                       die("invalid dump: expected newline after %s", val);
+
+               switch (type) {
+               case 'K':
+               case 'D':
+                       strbuf_reset(&key);
+                       if (val)
+                               strbuf_add(&key, val, len);
+                       if (type == 'K')
+                               continue;
+                       assert(type == 'D');
+                       val = NULL;
+                       len = 0;
+                       /* fall through */
+               case 'V':
+                       handle_property(&key, val, len, &type_set);
+                       strbuf_reset(&key);
+                       continue;
+               default:
+                       die("invalid property line: %s\n", t);
                }
        }
 }
 
 static void handle_node(void)
 {
-       if (node_ctx.propLength != LENGTH_UNKNOWN && node_ctx.propLength)
-               read_props();
-
-       if (node_ctx.srcRev)
-               node_ctx.srcMode = repo_copy(node_ctx.srcRev, node_ctx.src, node_ctx.dst);
-
-       if (node_ctx.textLength != LENGTH_UNKNOWN &&
-           node_ctx.type != REPO_MODE_DIR)
-               node_ctx.mark = next_blob_mark();
+       uint32_t mark = 0;
+       const uint32_t type = node_ctx.type;
+       const int have_props = node_ctx.propLength != LENGTH_UNKNOWN;
+       const int have_text = node_ctx.textLength != LENGTH_UNKNOWN;
 
+       if (node_ctx.text_delta)
+               die("text deltas not supported");
+       if (have_text)
+               mark = next_blob_mark();
        if (node_ctx.action == NODEACT_DELETE) {
+               if (have_text || have_props || node_ctx.srcRev)
+                       die("invalid dump: deletion node has "
+                               "copyfrom info, text, or properties");
+               return repo_delete(node_ctx.dst);
+       }
+       if (node_ctx.action == NODEACT_REPLACE) {
                repo_delete(node_ctx.dst);
-       } else if (node_ctx.action == NODEACT_CHANGE ||
-                          node_ctx.action == NODEACT_REPLACE) {
-               if (node_ctx.action == NODEACT_REPLACE &&
-                   node_ctx.type == REPO_MODE_DIR)
-                       repo_replace(node_ctx.dst, node_ctx.mark);
-               else if (node_ctx.propLength != LENGTH_UNKNOWN)
-                       repo_modify(node_ctx.dst, node_ctx.type, node_ctx.mark);
-               else if (node_ctx.textLength != LENGTH_UNKNOWN)
-                       node_ctx.srcMode = repo_replace(node_ctx.dst, node_ctx.mark);
+               node_ctx.action = NODEACT_ADD;
+       }
+       if (node_ctx.srcRev) {
+               repo_copy(node_ctx.srcRev, node_ctx.src, node_ctx.dst);
+               if (node_ctx.action == NODEACT_ADD)
+                       node_ctx.action = NODEACT_CHANGE;
+       }
+       if (have_text && type == REPO_MODE_DIR)
+               die("invalid dump: directories cannot have text attached");
+
+       /*
+        * Decide on the new content (mark) and mode (node_ctx.type).
+        */
+       if (node_ctx.action == NODEACT_CHANGE && !~*node_ctx.dst) {
+               if (type != REPO_MODE_DIR)
+                       die("invalid dump: root of tree is not a regular file");
+       } else if (node_ctx.action == NODEACT_CHANGE) {
+               uint32_t mode;
+               if (!have_text)
+                       mark = repo_read_path(node_ctx.dst);
+               mode = repo_read_mode(node_ctx.dst);
+               if (mode == REPO_MODE_DIR && type != REPO_MODE_DIR)
+                       die("invalid dump: cannot modify a directory into a file");
+               if (mode != REPO_MODE_DIR && type == REPO_MODE_DIR)
+                       die("invalid dump: cannot modify a file into a directory");
+               node_ctx.type = mode;
        } else if (node_ctx.action == NODEACT_ADD) {
-               if (node_ctx.srcRev && node_ctx.propLength != LENGTH_UNKNOWN)
-                       repo_modify(node_ctx.dst, node_ctx.type, node_ctx.mark);
-               else if (node_ctx.srcRev && node_ctx.textLength != LENGTH_UNKNOWN)
-                       node_ctx.srcMode = repo_replace(node_ctx.dst, node_ctx.mark);
-               else if ((node_ctx.type == REPO_MODE_DIR && !node_ctx.srcRev) ||
-                        node_ctx.textLength != LENGTH_UNKNOWN)
-                       repo_add(node_ctx.dst, node_ctx.type, node_ctx.mark);
+               if (!have_text && type != REPO_MODE_DIR)
+                       die("invalid dump: adds node without text");
+       } else {
+               die("invalid dump: Node-path block lacks Node-action");
        }
 
-       if (node_ctx.propLength == LENGTH_UNKNOWN && node_ctx.srcMode)
-               node_ctx.type = node_ctx.srcMode;
+       /*
+        * Adjust mode to reflect properties.
+        */
+       if (have_props) {
+               if (!node_ctx.prop_delta)
+                       node_ctx.type = type;
+               if (node_ctx.propLength)
+                       read_props();
+       }
 
-       if (node_ctx.mark)
-               fast_export_blob(node_ctx.type, node_ctx.mark, node_ctx.textLength);
-       else if (node_ctx.textLength != LENGTH_UNKNOWN)
-               buffer_skip_bytes(node_ctx.textLength);
+       /*
+        * Save the result.
+        */
+       repo_add(node_ctx.dst, node_ctx.type, mark);
+       if (have_text)
+               fast_export_blob(node_ctx.type, mark,
+                                node_ctx.textLength, &input);
 }
 
 static void handle_revision(void)
 {
        if (rev_ctx.revision)
-               repo_commit(rev_ctx.revision, rev_ctx.author, rev_ctx.log,
-                       dump_ctx.uuid, dump_ctx.url, rev_ctx.timestamp);
+               repo_commit(rev_ctx.revision, rev_ctx.author.buf,
+                       rev_ctx.log.buf, dump_ctx.uuid.buf, dump_ctx.url.buf,
+                       rev_ctx.timestamp);
 }
 
 void svndump_read(const char *url)
@@ -197,44 +288,65 @@ void svndump_read(const char *url)
        char *t;
        uint32_t active_ctx = DUMP_CTX;
        uint32_t len;
-       uint32_t key;
 
-       reset_dump_ctx(pool_intern(url));
-       while ((t = buffer_read_line())) {
-               val = strstr(t, ": ");
+       reset_dump_ctx(url);
+       while ((t = buffer_read_line(&input))) {
+               val = strchr(t, ':');
                if (!val)
                        continue;
-               *val++ = '\0';
-               *val++ = '\0';
-               key = pool_intern(t);
+               val++;
+               if (*val != ' ')
+                       continue;
+               val++;
 
-               if (key == keys.svn_fs_dump_format_version) {
+               /* strlen(key) + 1 */
+               switch (val - t - 1) {
+               case sizeof("SVN-fs-dump-format-version"):
+                       if (constcmp(t, "SVN-fs-dump-format-version"))
+                               continue;
                        dump_ctx.version = atoi(val);
-                       if (dump_ctx.version > 2)
-                               die("expected svn dump format version <= 2, found %"PRIu32,
+                       if (dump_ctx.version > 3)
+                               die("expected svn dump format version <= 3, found %"PRIu32,
                                    dump_ctx.version);
-               } else if (key == keys.uuid) {
-                       dump_ctx.uuid = pool_intern(val);
-               } else if (key == keys.revision_number) {
+                       break;
+               case sizeof("UUID"):
+                       if (constcmp(t, "UUID"))
+                               continue;
+                       strbuf_reset(&dump_ctx.uuid);
+                       strbuf_addstr(&dump_ctx.uuid, val);
+                       break;
+               case sizeof("Revision-number"):
+                       if (constcmp(t, "Revision-number"))
+                               continue;
                        if (active_ctx == NODE_CTX)
                                handle_node();
                        if (active_ctx != DUMP_CTX)
                                handle_revision();
                        active_ctx = REV_CTX;
                        reset_rev_ctx(atoi(val));
-               } else if (key == keys.node_path) {
-                       if (active_ctx == NODE_CTX)
-                               handle_node();
-                       active_ctx = NODE_CTX;
-                       reset_node_ctx(val);
-               } else if (key == keys.node_kind) {
+                       break;
+               case sizeof("Node-path"):
+                       if (prefixcmp(t, "Node-"))
+                               continue;
+                       if (!constcmp(t + strlen("Node-"), "path")) {
+                               if (active_ctx == NODE_CTX)
+                                       handle_node();
+                               active_ctx = NODE_CTX;
+                               reset_node_ctx(val);
+                               break;
+                       }
+                       if (constcmp(t + strlen("Node-"), "kind"))
+                               continue;
                        if (!strcmp(val, "dir"))
                                node_ctx.type = REPO_MODE_DIR;
                        else if (!strcmp(val, "file"))
                                node_ctx.type = REPO_MODE_BLB;
                        else
                                fprintf(stderr, "Unknown node-kind: %s\n", val);
-               } else if (key == keys.node_action) {
+                       break;
+               case sizeof("Node-action"):
+                       if (constcmp(t, "Node-action"))
+                               continue;
                        if (!strcmp(val, "delete")) {
                                node_ctx.action = NODEACT_DELETE;
                        } else if (!strcmp(val, "add")) {
@@ -247,17 +359,44 @@ void svndump_read(const char *url)
                                fprintf(stderr, "Unknown node-action: %s\n", val);
                                node_ctx.action = NODEACT_UNKNOWN;
                        }
-               } else if (key == keys.node_copyfrom_path) {
+                       break;
+               case sizeof("Node-copyfrom-path"):
+                       if (constcmp(t, "Node-copyfrom-path"))
+                               continue;
                        pool_tok_seq(REPO_MAX_PATH_DEPTH, node_ctx.src, "/", val);
-               } else if (key == keys.node_copyfrom_rev) {
+                       break;
+               case sizeof("Node-copyfrom-rev"):
+                       if (constcmp(t, "Node-copyfrom-rev"))
+                               continue;
                        node_ctx.srcRev = atoi(val);
-               } else if (key == keys.text_content_length) {
-                       node_ctx.textLength = atoi(val);
-               } else if (key == keys.prop_content_length) {
+                       break;
+               case sizeof("Text-content-length"):
+                       if (!constcmp(t, "Text-content-length")) {
+                               node_ctx.textLength = atoi(val);
+                               break;
+                       }
+                       if (constcmp(t, "Prop-content-length"))
+                               continue;
                        node_ctx.propLength = atoi(val);
-               } else if (key == keys.content_length) {
+                       break;
+               case sizeof("Text-delta"):
+                       if (!constcmp(t, "Text-delta")) {
+                               node_ctx.text_delta = !strcmp(val, "true");
+                               break;
+                       }
+                       if (constcmp(t, "Prop-delta"))
+                               continue;
+                       node_ctx.prop_delta = !strcmp(val, "true");
+                       break;
+               case sizeof("Content-length"):
+                       if (constcmp(t, "Content-length"))
+                               continue;
                        len = atoi(val);
-                       buffer_read_line();
+                       t = buffer_read_line(&input);
+                       if (!t)
+                               die_short_read();
+                       if (*t)
+                               die("invalid dump: expected blank line after content length header");
                        if (active_ctx == REV_CTX) {
                                read_props();
                        } else if (active_ctx == NODE_CTX) {
@@ -265,34 +404,42 @@ void svndump_read(const char *url)
                                active_ctx = REV_CTX;
                        } else {
                                fprintf(stderr, "Unexpected content length header: %"PRIu32"\n", len);
-                               buffer_skip_bytes(len);
+                               if (buffer_skip_bytes(&input, len) != len)
+                                       die_short_read();
                        }
                }
        }
+       if (buffer_ferror(&input))
+               die_short_read();
        if (active_ctx == NODE_CTX)
                handle_node();
        if (active_ctx != DUMP_CTX)
                handle_revision();
 }
 
-void svndump_init(const char *filename)
+int svndump_init(const char *filename)
 {
-       buffer_init(filename);
+       if (buffer_init(&input, filename))
+               return error("cannot open %s: %s", filename, strerror(errno));
        repo_init();
-       reset_dump_ctx(~0);
+       strbuf_init(&dump_ctx.uuid, 4096);
+       strbuf_init(&dump_ctx.url, 4096);
+       strbuf_init(&rev_ctx.log, 4096);
+       strbuf_init(&rev_ctx.author, 4096);
+       reset_dump_ctx(NULL);
        reset_rev_ctx(0);
        reset_node_ctx(NULL);
-       init_keys();
+       return 0;
 }
 
 void svndump_deinit(void)
 {
-       log_reset();
        repo_reset();
-       reset_dump_ctx(~0);
+       reset_dump_ctx(NULL);
        reset_rev_ctx(0);
        reset_node_ctx(NULL);
-       if (buffer_deinit())
+       strbuf_release(&rev_ctx.log);
+       if (buffer_deinit(&input))
                fprintf(stderr, "Input error\n");
        if (ferror(stdout))
                fprintf(stderr, "Output error\n");
@@ -300,10 +447,10 @@ void svndump_deinit(void)
 
 void svndump_reset(void)
 {
-       log_reset();
-       buffer_reset();
+       buffer_reset(&input);
        repo_reset();
-       reset_dump_ctx(~0);
-       reset_rev_ctx(0);
-       reset_node_ctx(NULL);
+       strbuf_release(&dump_ctx.uuid);
+       strbuf_release(&dump_ctx.url);
+       strbuf_release(&rev_ctx.log);
+       strbuf_release(&rev_ctx.author);
 }
index 93c412f14a4ca48b9de18325c09d69f051d97647..df9ceb0e8d473b65fc22ac142d3856dc4f9980e0 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef SVNDUMP_H_
 #define SVNDUMP_H_
 
-void svndump_init(const char *filename);
+int svndump_init(const char *filename);
 void svndump_read(const char *url);
 void svndump_deinit(void);
 void svndump_reset(void);
index 8d7dd31c4ba5439652d11e5ada06e0d52bc04e4f..28290002b9f6434d716a39612f3afc9958c292af 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -53,7 +53,7 @@ void *xmalloc(size_t size)
 void *xmallocz(size_t size)
 {
        void *ret;
-       if (size + 1 < size)
+       if (unsigned_add_overflows(size, 1))
                die("Data too large to fit into virtual memory space.");
        ret = xmalloc(size + 1);
        ((char*)ret)[size] = 0;
@@ -198,10 +198,22 @@ FILE *xfdopen(int fd, const char *mode)
 int xmkstemp(char *template)
 {
        int fd;
+       char origtemplate[PATH_MAX];
+       strlcpy(origtemplate, template, sizeof(origtemplate));
 
        fd = mkstemp(template);
-       if (fd < 0)
-               die_errno("Unable to create temporary file");
+       if (fd < 0) {
+               int saved_errno = errno;
+               const char *nonrelative_template;
+
+               if (!template[0])
+                       template = origtemplate;
+
+               nonrelative_template = absolute_path(template);
+               errno = saved_errno;
+               die_errno("Unable to create temporary file '%s'",
+                       nonrelative_template);
+       }
        return fd;
 }
 
@@ -321,10 +333,22 @@ int gitmkstemps(char *pattern, int suffix_len)
 int xmkstemp_mode(char *template, int mode)
 {
        int fd;
+       char origtemplate[PATH_MAX];
+       strlcpy(origtemplate, template, sizeof(origtemplate));
 
        fd = git_mkstemp_mode(template, mode);
-       if (fd < 0)
-               die_errno("Unable to create temporary file");
+       if (fd < 0) {
+               int saved_errno = errno;
+               const char *nonrelative_template;
+
+               if (!template[0])
+                       template = origtemplate;
+
+               nonrelative_template = absolute_path(template);
+               errno = saved_errno;
+               die_errno("Unable to create temporary file '%s'",
+                       nonrelative_template);
+       }
        return fd;
 }
 
index 123582b6cbdff90f4665fbf8db2c92d701680e4d..53558d7e5f517479af478e375076718189c2d2d5 100644 (file)
@@ -32,6 +32,80 @@ static const char *color(int slot, struct wt_status *s)
        return c;
 }
 
+static void status_vprintf(struct wt_status *s, int at_bol, const char *color,
+               const char *fmt, va_list ap, const char *trail)
+{
+       struct strbuf sb = STRBUF_INIT;
+       struct strbuf linebuf = STRBUF_INIT;
+       const char *line, *eol;
+
+       strbuf_vaddf(&sb, fmt, ap);
+       if (!sb.len) {
+               strbuf_addch(&sb, '#');
+               if (!trail)
+                       strbuf_addch(&sb, ' ');
+               color_print_strbuf(s->fp, color, &sb);
+               if (trail)
+                       fprintf(s->fp, "%s", trail);
+               strbuf_release(&sb);
+               return;
+       }
+       for (line = sb.buf; *line; line = eol + 1) {
+               eol = strchr(line, '\n');
+
+               strbuf_reset(&linebuf);
+               if (at_bol) {
+                       strbuf_addch(&linebuf, '#');
+                       if (*line != '\n' && *line != '\t')
+                               strbuf_addch(&linebuf, ' ');
+               }
+               if (eol)
+                       strbuf_add(&linebuf, line, eol - line);
+               else
+                       strbuf_addstr(&linebuf, line);
+               color_print_strbuf(s->fp, color, &linebuf);
+               if (eol)
+                       fprintf(s->fp, "\n");
+               else
+                       break;
+               at_bol = 1;
+       }
+       if (trail)
+               fprintf(s->fp, "%s", trail);
+       strbuf_release(&linebuf);
+       strbuf_release(&sb);
+}
+
+void status_printf_ln(struct wt_status *s, const char *color,
+                       const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       status_vprintf(s, 1, color, fmt, ap, "\n");
+       va_end(ap);
+}
+
+void status_printf(struct wt_status *s, const char *color,
+                       const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       status_vprintf(s, 1, color, fmt, ap, NULL);
+       va_end(ap);
+}
+
+void status_printf_more(struct wt_status *s, const char *color,
+                       const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       status_vprintf(s, 0, color, fmt, ap, NULL);
+       va_end(ap);
+}
+
 void wt_status_prepare(struct wt_status *s)
 {
        unsigned char sha1[20];
@@ -57,33 +131,33 @@ static void wt_status_print_unmerged_header(struct wt_status *s)
 {
        const char *c = color(WT_STATUS_HEADER, s);
 
-       color_fprintf_ln(s->fp, c, "# Unmerged paths:");
+       status_printf_ln(s, c, "Unmerged paths:");
        if (!advice_status_hints)
                return;
-       if (s->in_merge)
+       if (s->whence != FROM_COMMIT)
                ;
        else if (!s->is_initial)
-               color_fprintf_ln(s->fp, c, "#   (use \"git reset %s <file>...\" to unstage)", s->reference);
+               status_printf_ln(s, c, "  (use \"git reset %s <file>...\" to unstage)", s->reference);
        else
-               color_fprintf_ln(s->fp, c, "#   (use \"git rm --cached <file>...\" to unstage)");
-       color_fprintf_ln(s->fp, c, "#   (use \"git add/rm <file>...\" as appropriate to mark resolution)");
-       color_fprintf_ln(s->fp, c, "#");
+               status_printf_ln(s, c, "  (use \"git rm --cached <file>...\" to unstage)");
+       status_printf_ln(s, c, "  (use \"git add/rm <file>...\" as appropriate to mark resolution)");
+       status_printf_ln(s, c, "");
 }
 
 static void wt_status_print_cached_header(struct wt_status *s)
 {
        const char *c = color(WT_STATUS_HEADER, s);
 
-       color_fprintf_ln(s->fp, c, "# Changes to be committed:");
+       status_printf_ln(s, c, "Changes to be committed:");
        if (!advice_status_hints)
                return;
-       if (s->in_merge)
+       if (s->whence != FROM_COMMIT)
                ; /* NEEDSWORK: use "git reset --unresolve"??? */
        else if (!s->is_initial)
-               color_fprintf_ln(s->fp, c, "#   (use \"git reset %s <file>...\" to unstage)", s->reference);
+               status_printf_ln(s, c, "  (use \"git reset %s <file>...\" to unstage)", s->reference);
        else
-               color_fprintf_ln(s->fp, c, "#   (use \"git rm --cached <file>...\" to unstage)");
-       color_fprintf_ln(s->fp, c, "#");
+               status_printf_ln(s, c, "  (use \"git rm --cached <file>...\" to unstage)");
+       status_printf_ln(s, c, "");
 }
 
 static void wt_status_print_dirty_header(struct wt_status *s,
@@ -92,17 +166,17 @@ static void wt_status_print_dirty_header(struct wt_status *s,
 {
        const char *c = color(WT_STATUS_HEADER, s);
 
-       color_fprintf_ln(s->fp, c, "# Changes not staged for commit:");
+       status_printf_ln(s, c, "Changes not staged for commit:");
        if (!advice_status_hints)
                return;
        if (!has_deleted)
-               color_fprintf_ln(s->fp, c, "#   (use \"git add <file>...\" to update what will be committed)");
+               status_printf_ln(s, c, "  (use \"git add <file>...\" to update what will be committed)");
        else
-               color_fprintf_ln(s->fp, c, "#   (use \"git add/rm <file>...\" to update what will be committed)");
-       color_fprintf_ln(s->fp, c, "#   (use \"git checkout -- <file>...\" to discard changes in working directory)");
+               status_printf_ln(s, c, "  (use \"git add/rm <file>...\" to update what will be committed)");
+       status_printf_ln(s, c, "  (use \"git checkout -- <file>...\" to discard changes in working directory)");
        if (has_dirty_submodules)
-               color_fprintf_ln(s->fp, c, "#   (commit or discard the untracked or modified content in submodules)");
-       color_fprintf_ln(s->fp, c, "#");
+               status_printf_ln(s, c, "  (commit or discard the untracked or modified content in submodules)");
+       status_printf_ln(s, c, "");
 }
 
 static void wt_status_print_other_header(struct wt_status *s,
@@ -110,16 +184,16 @@ static void wt_status_print_other_header(struct wt_status *s,
                                         const char *how)
 {
        const char *c = color(WT_STATUS_HEADER, s);
-       color_fprintf_ln(s->fp, c, "# %s files:", what);
+       status_printf_ln(s, c, "%s files:", what);
        if (!advice_status_hints)
                return;
-       color_fprintf_ln(s->fp, c, "#   (use \"git %s <file>...\" to include in what will be committed)", how);
-       color_fprintf_ln(s->fp, c, "#");
+       status_printf_ln(s, c, "  (use \"git %s <file>...\" to include in what will be committed)", how);
+       status_printf_ln(s, c, "");
 }
 
 static void wt_status_print_trailer(struct wt_status *s)
 {
-       color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
+       status_printf_ln(s, color(WT_STATUS_HEADER, s), "");
 }
 
 #define quote_path quote_path_relative
@@ -133,7 +207,7 @@ static void wt_status_print_unmerged_data(struct wt_status *s,
        const char *one, *how = "bug";
 
        one = quote_path(it->string, -1, &onebuf, s->prefix);
-       color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t");
+       status_printf(s, color(WT_STATUS_HEADER, s), "\t");
        switch (d->stagemask) {
        case 1: how = "both deleted:"; break;
        case 2: how = "added by us:"; break;
@@ -143,7 +217,7 @@ static void wt_status_print_unmerged_data(struct wt_status *s,
        case 6: how = "both added:"; break;
        case 7: how = "both modified:"; break;
        }
-       color_fprintf(s->fp, c, "%-20s%s\n", how, one);
+       status_printf_more(s, c, "%-20s%s\n", how, one);
        strbuf_release(&onebuf);
 }
 
@@ -186,40 +260,40 @@ static void wt_status_print_change_data(struct wt_status *s,
        one = quote_path(one_name, -1, &onebuf, s->prefix);
        two = quote_path(two_name, -1, &twobuf, s->prefix);
 
-       color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t");
+       status_printf(s, color(WT_STATUS_HEADER, s), "\t");
        switch (status) {
        case DIFF_STATUS_ADDED:
-               color_fprintf(s->fp, c, "new file:   %s", one);
+               status_printf_more(s, c, "new file:   %s", one);
                break;
        case DIFF_STATUS_COPIED:
-               color_fprintf(s->fp, c, "copied:     %s -> %s", one, two);
+               status_printf_more(s, c, "copied:     %s -> %s", one, two);
                break;
        case DIFF_STATUS_DELETED:
-               color_fprintf(s->fp, c, "deleted:    %s", one);
+               status_printf_more(s, c, "deleted:    %s", one);
                break;
        case DIFF_STATUS_MODIFIED:
-               color_fprintf(s->fp, c, "modified:   %s", one);
+               status_printf_more(s, c, "modified:   %s", one);
                break;
        case DIFF_STATUS_RENAMED:
-               color_fprintf(s->fp, c, "renamed:    %s -> %s", one, two);
+               status_printf_more(s, c, "renamed:    %s -> %s", one, two);
                break;
        case DIFF_STATUS_TYPE_CHANGED:
-               color_fprintf(s->fp, c, "typechange: %s", one);
+               status_printf_more(s, c, "typechange: %s", one);
                break;
        case DIFF_STATUS_UNKNOWN:
-               color_fprintf(s->fp, c, "unknown:    %s", one);
+               status_printf_more(s, c, "unknown:    %s", one);
                break;
        case DIFF_STATUS_UNMERGED:
-               color_fprintf(s->fp, c, "unmerged:   %s", one);
+               status_printf_more(s, c, "unmerged:   %s", one);
                break;
        default:
                die("bug: unhandled diff status %c", status);
        }
        if (extra.len) {
-               color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "%s", extra.buf);
+               status_printf_more(s, color(WT_STATUS_HEADER, s), "%s", extra.buf);
                strbuf_release(&extra);
        }
-       fprintf(s->fp, "\n");
+       status_printf_more(s, GIT_COLOR_NORMAL, "\n");
        strbuf_release(&onebuf);
        strbuf_release(&twobuf);
 }
@@ -323,7 +397,7 @@ static void wt_status_collect_changes_worktree(struct wt_status *s)
     }
        rev.diffopt.format_callback = wt_status_collect_changed_cb;
        rev.diffopt.format_callback_data = s;
-       rev.prune_data = s->pathspec;
+       init_pathspec(&rev.prune_data, s->pathspec);
        run_diff_files(&rev, 0);
 }
 
@@ -348,20 +422,22 @@ static void wt_status_collect_changes_index(struct wt_status *s)
        rev.diffopt.detect_rename = 1;
        rev.diffopt.rename_limit = 200;
        rev.diffopt.break_opt = 0;
-       rev.prune_data = s->pathspec;
+       init_pathspec(&rev.prune_data, s->pathspec);
        run_diff_index(&rev, 1);
 }
 
 static void wt_status_collect_changes_initial(struct wt_status *s)
 {
+       struct pathspec pathspec;
        int i;
 
+       init_pathspec(&pathspec, s->pathspec);
        for (i = 0; i < active_nr; i++) {
                struct string_list_item *it;
                struct wt_status_change_data *d;
                struct cache_entry *ce = active_cache[i];
 
-               if (!ce_path_match(ce, s->pathspec))
+               if (!ce_path_match(ce, &pathspec))
                        continue;
                it = string_list_insert(&s->change, ce->name);
                d = it->util;
@@ -376,6 +452,7 @@ static void wt_status_collect_changes_initial(struct wt_status *s)
                else
                        d->index_status = DIFF_STATUS_ADDED;
        }
+       free_pathspec(&pathspec);
 }
 
 static void wt_status_collect_untracked(struct wt_status *s)
@@ -573,9 +650,9 @@ static void wt_status_print_other(struct wt_status *s,
        for (i = 0; i < l->nr; i++) {
                struct string_list_item *it;
                it = &(l->items[i]);
-               color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "#\t");
-               color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED, s), "%s",
-                                quote_path(it->string, strlen(it->string),
+               status_printf(s, color(WT_STATUS_HEADER, s), "\t");
+               status_printf_more(s, color(WT_STATUS_UNTRACKED, s),
+                       "%s\n", quote_path(it->string, strlen(it->string),
                                            &buf, s->prefix));
        }
        strbuf_release(&buf);
@@ -642,17 +719,17 @@ void wt_status_print(struct wt_status *s)
                        branch_status_color = color(WT_STATUS_NOBRANCH, s);
                        on_what = "Not currently on any branch.";
                }
-               color_fprintf(s->fp, color(WT_STATUS_HEADER, s), "# ");
-               color_fprintf(s->fp, branch_status_color, "%s", on_what);
-               color_fprintf_ln(s->fp, branch_color, "%s", branch_name);
+               status_printf(s, color(WT_STATUS_HEADER, s), "");
+               status_printf_more(s, branch_status_color, "%s", on_what);
+               status_printf_more(s, branch_color, "%s\n", branch_name);
                if (!s->is_initial)
                        wt_status_print_tracking(s);
        }
 
        if (s->is_initial) {
-               color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
-               color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "# Initial commit");
-               color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
+               status_printf_ln(s, color(WT_STATUS_HEADER, s), "");
+               status_printf_ln(s, color(WT_STATUS_HEADER, s), "Initial commit");
+               status_printf_ln(s, color(WT_STATUS_HEADER, s), "");
        }
 
        wt_status_print_updated(s);
@@ -669,7 +746,7 @@ void wt_status_print(struct wt_status *s)
                if (s->show_ignored_files)
                        wt_status_print_other(s, &s->ignored, "Ignored", "add -f");
        } else if (s->commitable)
-               fprintf(s->fp, "# Untracked files not listed%s\n",
+               status_printf_ln(s, GIT_COLOR_NORMAL, "Untracked files not listed%s",
                        advice_status_hints
                        ? " (use -u option to show untracked files)" : "");
 
@@ -677,7 +754,7 @@ void wt_status_print(struct wt_status *s)
                wt_status_print_verbose(s);
        if (!s->commitable) {
                if (s->amend)
-                       fprintf(s->fp, "# No changes\n");
+                       status_printf_ln(s, GIT_COLOR_NORMAL, "No changes");
                else if (s->nowarn)
                        ; /* nothing */
                else if (s->workdir_dirty)
index 20b17cf4393b8f9acce93320fb97998ad7cd609b..682b4c8f7da2c58f741a958f6488a48fd7b483b4 100644 (file)
@@ -24,6 +24,13 @@ enum untracked_status_type {
        SHOW_ALL_UNTRACKED_FILES
 };
 
+/* from where does this commit originate */
+enum commit_whence {
+       FROM_COMMIT,     /* normal */
+       FROM_MERGE,      /* commit came from merge */
+       FROM_CHERRY_PICK /* commit came from cherry-pick */
+};
+
 struct wt_status_change_data {
        int worktree_status;
        int index_status;
@@ -40,7 +47,7 @@ struct wt_status {
        const char **pathspec;
        int verbose;
        int amend;
-       int in_merge;
+       enum commit_whence whence;
        int nowarn;
        int use_color;
        int relative_paths;
@@ -68,4 +75,11 @@ void wt_status_collect(struct wt_status *s);
 void wt_shortstatus_print(struct wt_status *s, int null_termination, int show_branch);
 void wt_porcelain_print(struct wt_status *s, int null_termination);
 
+void status_printf_ln(struct wt_status *s, const char *color, const char *fmt, ...)
+       ;
+void status_printf(struct wt_status *s, const char *color, const char *fmt, ...)
+       ;
+void status_printf_more(struct wt_status *s, const char *color, const char *fmt, ...)
+       __attribute__((format(printf, 3, 4)));
+
 #endif /* STATUS_H */