Merge branch 'hv/mingw-fs-funnies'
authorJunio C Hamano <gitster@pobox.com>
Mon, 28 Feb 2011 05:17:37 +0000 (21:17 -0800)
committerJunio C Hamano <gitster@pobox.com>
Mon, 28 Feb 2011 05:17:37 +0000 (21:17 -0800)
* hv/mingw-fs-funnies:
mingw_rmdir: set errno=ENOTEMPTY when appropriate
mingw: add fallback for rmdir in case directory is in use
mingw: make failures to unlink or move raise a question
mingw: work around irregular failures of unlink on windows
mingw: move unlink wrapper to mingw.c

255 files changed:
.gitignore
Documentation/CodingGuidelines
Documentation/RelNotes/1.6.4.5.txt [new file with mode: 0644]
Documentation/RelNotes/1.6.5.9.txt [new file with mode: 0644]
Documentation/RelNotes/1.6.6.3.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.0.9.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.1.4.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.2.5.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.3.4.txt
Documentation/RelNotes/1.7.3.5.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.4.1.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.4.txt
Documentation/config.txt
Documentation/diff-options.txt
Documentation/fetch-options.txt
Documentation/git-add.txt
Documentation/git-archive.txt
Documentation/git-bundle.txt
Documentation/git-cherry-pick.txt
Documentation/git-commit.txt
Documentation/git-diff.txt
Documentation/git-difftool.txt
Documentation/git-fast-import.txt
Documentation/git-fmt-merge-msg.txt
Documentation/git-fsck.txt
Documentation/git-gc.txt
Documentation/git-pull.txt
Documentation/git-read-tree.txt
Documentation/git-remote-ext.txt
Documentation/git-remote-fd.txt
Documentation/git-reset.txt
Documentation/git-rev-parse.txt
Documentation/git-revert.txt
Documentation/git-status.txt
Documentation/git-svn.txt
Documentation/git-tag.txt
Documentation/git.txt
Documentation/gitattributes.txt
Documentation/githooks.txt
Documentation/gitmodules.txt
Documentation/glossary-content.txt
Documentation/howto/using-merge-subtree.txt
Documentation/merge-config.txt
Documentation/revisions.txt
Documentation/technical/api-sigchain.txt
GIT-VERSION-GEN
Makefile
aclocal.m4
builtin.h
builtin/add.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/fsck.c
builtin/grep.c
builtin/init-db.c
builtin/log.c
builtin/merge.c
builtin/remote-ext.c
builtin/revert.c
builtin/rm.c
builtin/show-branch.c
builtin/tag.c
builtin/update-index.c
bundle.c
cache.h
color.c
color.h
commit.c
commit.h
compat/mingw.h
compat/vcbuild/include/unistd.h
compat/win32/sys/poll.c
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.txt
convert.c
daemon.c
diff-lib.c
diff-no-index.c
diff.c
diff.h
dir.c
dir.h
environment.c
exec_cmd.c
fast-import.c
git-am.sh
git-compat-util.h
git-cvsimport.perl
git-difftool--helper.sh
git-difftool.perl
git-pull.sh
git-rebase--interactive.sh
git-rebase.sh
git-submodule.sh
git.c
gitk-git/gitk [changed mode: 0644->0755]
gitk-git/po/pt_br.po [new file with mode: 0644]
gitk-git/po/sv.po
gitweb/INSTALL
gitweb/gitweb.perl
ident.c
list-objects.c
ll-merge.c
merge-recursive.h
notes-merge.c
patch-delta.c
preload-index.c
quote.h
read-cache.c
revision.c
revision.h
run-command.c
setup.c
sha1_file.c
sha1_name.c
strbuf.c
string-list.c
submodule.c
submodule.h
t/Makefile
t/README
t/gitweb-lib.sh
t/lib-git-svn.sh
t/t0000-basic.sh
t/t0001-init.sh
t/t0021-conversion.sh
t/t0050-filesystem.sh
t/t0070-fundamental.sh
t/t1011-read-tree-sparse-checkout.sh
t/t1020-subdirectory.sh
t/t1501-worktree.sh
t/t1506-rev-parse-diagnosis.sh
t/t1510-repo-setup.sh [new file with mode: 0755]
t/t1511-rev-parse-caret.sh [new file with mode: 0755]
t/t2107-update-index-basic.sh
t/t3032-merge-recursive-options.sh
t/t3301-notes.sh
t/t3404-rebase-interactive.sh
t/t3419-rebase-patch-id.sh
t/t3509-cherry-pick-merge-df.sh
t/t3600-rm.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/t4018-diff-funcname.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/t4120-apply-popt.sh
t/t4151-am-abort.sh
t/t5407-post-rewrite-hook.sh
t/t5526-fetch-submodules.sh [new file with mode: 0755]
t/t6000-rev-list-misc.sh [new file with mode: 0755]
t/t6004-rev-list-path-optim.sh
t/t6038-merge-text-auto.sh
t/t7400-submodule-basic.sh
t/t7407-submodule-foreach.sh
t/t7500-commit.sh
t/t7501-commit.sh
t/t7508-status.sh
t/t7607-merge-overwrite.sh
t/t7609-merge-abort.sh [deleted file]
t/t7611-merge-abort.sh [new file with mode: 0755]
t/t7810-grep.sh
t/t8003-blame-corner-cases.sh [new file with mode: 0755]
t/t8003-blame.sh [deleted file]
t/t8004-blame-with-conflicts.sh [new file with mode: 0755]
t/t8004-blame.sh [deleted file]
t/t8006-blame-textconv.sh
t/t9001-send-email.sh
t/t9010-svn-fe.sh
t/t9119-git-svn-info.sh
t/t9142-git-svn-shallow-clone.sh
t/t9157-git-svn-fetch-merge.sh
t/t9158-git-svn-mergeinfo.sh [changed mode: 0644->0755]
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/t9600-cvsimport.sh
t/test-lib.sh
tag.c
tag.h
test-mktemp.c [new file with mode: 0644]
test-subprocess.c [new file with mode: 0644]
test-treap.c
trace.c
tree-diff.c
tree-walk.c
tree-walk.h
unpack-trees.c
upload-pack.c
userdiff.c
vcs-svn/repo_tree.c
vcs-svn/svndump.c
vcs-svn/trp.h
vcs-svn/trp.txt
walker.c
wrapper.c
wt-status.c
wt-status.h
xdiff-interface.c
index 87b833c9d8940a61ff77ec6bd35241b3f85decb5..c460c66766ab590239e4ae9107bb55b9fd30fac6 100644 (file)
 /test-index-version
 /test-line-buffer
 /test-match-trees
+/test-mktemp
 /test-obj-pool
 /test-parse-options
 /test-path-utils
 /test-sha1
 /test-sigchain
 /test-string-pool
+/test-subprocess
 /test-svn-fe
 /test-treap
 /common-cmds.h
index 1b1c45df5ce3ef30e588555bbd5ab404c2b7397c..ba2006d892ec09d606f8846588c7727396b1ee28 100644 (file)
@@ -157,7 +157,7 @@ Writing Documentation:
    --sort=<key>
    --abbrev[=<n>]
 
- Possibility of multiple occurences is indicated by three dots:
+ Possibility of multiple occurrences is indicated by three dots:
    <file>...
    (One or more of <file>.)
 
diff --git a/Documentation/RelNotes/1.6.4.5.txt b/Documentation/RelNotes/1.6.4.5.txt
new file mode 100644 (file)
index 0000000..eb6307d
--- /dev/null
@@ -0,0 +1,20 @@
+Git v1.6.4.5 Release Notes
+==========================
+
+Fixes since v1.6.4.4
+--------------------
+
+ * Simplified base85 implementation.
+
+ * An overlong line after ".gitdir: " in a git file caused out of bounds
+   access to an array on the stack.
+
+ * "git count-objects" did not handle packs larger than 4G.
+
+ * "git rev-parse --parseopt --stop-at-non-option" did not stop at non option
+   when --keep-dashdash was in effect.
+
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
+
+Other minor fixes and documentation updates are included.
diff --git a/Documentation/RelNotes/1.6.5.9.txt b/Documentation/RelNotes/1.6.5.9.txt
new file mode 100644 (file)
index 0000000..bb469dd
--- /dev/null
@@ -0,0 +1,18 @@
+Git v1.6.5.9 Release Notes
+==========================
+
+Fixes since v1.6.5.8
+--------------------
+
+ * An overlong line after ".gitdir: " in a git file caused out of bounds
+   access to an array on the stack.
+
+ * "git blame -L $start,$end" segfaulted when too large $start was given.
+
+ * "git rev-parse --parseopt --stop-at-non-option" did not stop at non option
+   when --keep-dashdash was in effect.
+
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
+
+Other minor fixes and documentation updates are included.
diff --git a/Documentation/RelNotes/1.6.6.3.txt b/Documentation/RelNotes/1.6.6.3.txt
new file mode 100644 (file)
index 0000000..11483ac
--- /dev/null
@@ -0,0 +1,23 @@
+Git v1.6.6.3 Release Notes
+==========================
+
+Fixes since v1.6.6.2
+--------------------
+
+ * An overlong line after ".gitdir: " in a git file caused out of bounds
+   access to an array on the stack.
+
+ * "git bisect $path" did not correctly diagnose an error when given a
+   non-existent path.
+
+ * "git blame -L $start,$end" segfaulted when too large $start was given.
+
+ * "git imap-send" did not write draft box with CRLF line endings per RFC.
+
+ * "git rev-parse --parseopt --stop-at-non-option" did not stop at non option
+   when --keep-dashdash was in effect.
+
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
+
+Other minor fixes and documentation updates are included.
diff --git a/Documentation/RelNotes/1.7.0.9.txt b/Documentation/RelNotes/1.7.0.9.txt
new file mode 100644 (file)
index 0000000..bfb3166
--- /dev/null
@@ -0,0 +1,8 @@
+Git v1.7.0.9 Release Notes
+==========================
+
+Fixes since v1.7.0.8
+--------------------
+
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
diff --git a/Documentation/RelNotes/1.7.1.4.txt b/Documentation/RelNotes/1.7.1.4.txt
new file mode 100644 (file)
index 0000000..7c734b4
--- /dev/null
@@ -0,0 +1,8 @@
+Git v1.7.1.4 Release Notes
+==========================
+
+Fixes since v1.7.1.3
+--------------------
+
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
diff --git a/Documentation/RelNotes/1.7.2.5.txt b/Documentation/RelNotes/1.7.2.5.txt
new file mode 100644 (file)
index 0000000..bf976c4
--- /dev/null
@@ -0,0 +1,8 @@
+Git v1.7.2.5 Release Notes
+==========================
+
+Fixes since v1.7.2.4
+--------------------
+
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
index 925178f6089fbeff38add340563d803bc65a7365..e57f7c176db85e3bd40862fd091ecab835c601f5 100644 (file)
@@ -14,6 +14,11 @@ Fixes since v1.7.3.3
    colon between the hours and minutes part (e.g. "-08:00" instead of
    "-0800").
 
+ * "git checkout" removed an untracked file "foo" from the working
+   tree when switching to a branch that contains a tracked path
+   "foo/bar".  Prevent this, just like the case where the conflicting
+   path were "foo" (c752e7f..7980872d).
+
  * "git cherry-pick" or "git revert" refused to work when a path that
    would be modified by the operation was stat-dirty without a real
    difference in the contents of the file.
@@ -21,12 +26,20 @@ Fixes since v1.7.3.3
  * "git diff --check" reported an incorrect line number for added
    blank lines at the end of file.
 
+ * "git imap-send" failed to build under NO_OPENSSL.
+
  * Setting log.decorate configuration variable to "0" or "1" to mean
    "false" or "true" did not work.
 
+ * "git push" over dumb HTTP protocol did not work against WebDAV
+   servers that did not terminate a collection name with a slash.
+
  * "git tag -v" did not work with GPG signatures in rfc1991 mode.
 
  * The post-receive-email sample hook was accidentally broken in 1.7.3.3
    update.
 
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
+
 Other minor fixes and documentation updates are also included.
diff --git a/Documentation/RelNotes/1.7.3.5.txt b/Documentation/RelNotes/1.7.3.5.txt
new file mode 100644 (file)
index 0000000..40f3ba5
--- /dev/null
@@ -0,0 +1,34 @@
+Git 1.7.3.5 Release Notes
+=========================
+
+ * The xfuncname pattern used by "git diff" and "git grep" to show the
+   last notable line in context were broken for python and ruby for a long
+   time.
+
+ * "git merge" into an unborn branch removed an untracked file "foo" from
+   the working tree when merged branch had "foo" (this fix was already in
+   1.7.3.3 but was omitted from the release notes by mistake).
+
+ * "git status -s" did not quote unprintable characters in paths as
+   documented.
+
+ * "git am --abort" used to always reset to the commit at the beginning of
+   the last "am" invocation that has stopped, losing any unrelated commits
+   that may have been made since then.  Now it refrains from doing so and
+   instead issues a warning.
+
+ * "git blame" incorrectly reused bogusly cached result of textconv
+   filter for files from the working tree.
+
+ * "git commit" used to abort after the user edited the log message
+   when the committer information was not correctly set up.  It now
+   aborts before starting the editor.
+
+ * "git commit --date=invalid" used to silently ignore the incorrectly
+   specified date; it is now diagnosed as an error.
+
+ * "git rebase --skip" to skip the last commit in a series used to fail
+   to run post-rewrite hook and to copy notes from old commits that have
+   successfully been rebased so far.  Now it do (backmerge ef88ad2).
+
+ * "gitweb" tried to show a wrong feed logo when none was specified.
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.
index 6084f7ddf6d4c977b5ac29043186c73920ca947d..d5bca731b589dde2b8a1edad2977e9376e0ec433 100644 (file)
@@ -1,5 +1,5 @@
-Git v1.7.4 Release Notes (draft)
-================================
+Git v1.7.4 Release Notes
+========================
 
 Updates since v1.7.3
 --------------------
@@ -8,15 +8,14 @@ Updates since v1.7.3
    docbook-xsl >= 1.73. If you have older versions, you can set
    ASCIIDOC7 and ASCIIDOC_ROFF, respectively.
 
- * The option parsers of various commands that create new branch (or
+ * The option parsers of various commands that create new branches (or
    rename existing ones to a new name) were too loose and users were
-   allowed to call a branch with a name that begins with a dash by
-   creative abuse of their command line options, which only lead to
-   burn themselves.  The name of a branch cannot begin with a dash
-   now.
+   allowed to give a branch a name that begins with a dash by creative
+   abuse of their command line options, which only led to burning
+   themselves.  The name of a branch cannot begin with a dash now.
 
  * System-wide fallback default attributes can be stored in
-   /etc/gitattributes; core.attributesfile configuration variable can
+   /etc/gitattributes; the core.attributesfile configuration variable can
    be used to customize the path to this file.
 
  * The thread structure generated by "git send-email" has changed
@@ -26,22 +25,53 @@ Updates since v1.7.3
    cover letter of the previous series; this has been changed to make
    the patches in the new series replies to the new cover letter.
 
- * Bash completion script in contrib/ has been adjusted to be also
-   usable by zsh.
+ * The Bash completion script in contrib/ has been adjusted to be usable with
+   Bash 4 (options with '=value' didn't complete).  It has been also made
+   usable with zsh.
 
- * "git blame" learned --show-email option to display the e-mail
+ * Different pagers can be chosen depending on which subcommand is
+   being run under the pager, using the "pager.<subcommand>" variable.
+
+ * The hardcoded tab-width of 8 that is used in whitespace breakage checks is now
+   configurable via the attributes mechanism.
+
+ * Support of case insensitive filesystems (i.e. "core.ignorecase") has
+   been improved.  For example, the gitignore mechanism didn't pay attention
+   to case insensitivity.
+
+ * The <tree>:<path> syntax for naming a blob in a tree, and the :<path>
+   syntax for naming a blob in the index (e.g. "master:Makefile",
+   ":hello.c") have been extended.  You can start <path> with "./" to
+   implicitly have the (sub)directory you are in prefixed to the
+   lookup.  Similarly, ":../Makefile" from a subdirectory would mean
+   "the Makefile of the parent directory in the index".
+
+ * "git blame" learned the --show-email option to display the e-mail
    addresses instead of the names of authors.
 
- * "git daemon" can be built in MinGW environment.
+ * "git commit" learned the --fixup and --squash options to help later invocation
+   of interactive rebase.
+
+ * Command line options to "git cvsimport" whose names are in capital
+   letters (-A, -M, -R and -S) can now be specified as the default in
+   the .git/config file by their longer names (cvsimport.authorsFile,
+   cvsimport.mergeRegex, cvsimport.trackRevisions, cvsimport.ignorePaths).
+
+ * "git daemon" can be built in the MinGW environment.
 
  * "git daemon" can take more than one --listen option to listen to
    multiple addresses.
 
- * "git diff" and "git grep" learned how functions and subroutines
-   in Fortran look like.
+ * "git describe --exact-match" was optimized not to read commit
+   objects unnecessarily.
+
+ * "git diff" and "git grep" learned what functions and subroutines
+   in Fortran, Pascal and Perl look like.
+
+ * "git fetch" learned the "--recurse-submodules" option.
 
- * "git mergetool" tells vim/gvim to show three-way diff by default
-   (use vimdiff2/gvimdiff2 as the tool name for old behaviour).
+ * "git mergetool" tells vim/gvim to show three-way diff by default
+   (use vimdiff2/gvimdiff2 as the tool name for old behavior).
 
  * "git log -G<pattern>" limits the output to commits whose change has
    added or deleted lines that match the given pattern.
@@ -51,8 +81,8 @@ Updates since v1.7.3
    use the new --empty option to be more explicit instead.
 
  * "git repack -f" does not spend cycles to recompress objects in the
-   non-delta representation anymore (use -F if you really mean it when
-   e.g. you changed the compression level).
+   non-delta representation anymore (use -F if you really mean it
+   e.g. after you changed the core.compression variable setting).
 
  * "git merge --log" used to limit the resulting merge log to 20
    entries; this is now customizable by giving e.g. "--log=47".
@@ -61,30 +91,44 @@ Updates since v1.7.3
    directory in one branch while a new file is created in place of that
    directory in the other branch.
 
- * "git rebase --autosquash" can use SHA-1 object names to name which
-   commit to fix up (e.g. "fixup! e83c5163").
+ * "git merge" learned the "--abort" option, synonymous to
+   "git reset --merge" when a merge is in progress.
 
- * The default "recursive" merge strategy learned --rename-threshold
+ * "git notes" learned the "merge" subcommand to merge notes refs.
+   In addition to the default manual conflict resolution, there are
+   also several notes merge strategies for automatically resolving
+   notes merge conflicts.
+
+ * "git rebase --autosquash" can use SHA-1 object names to name the
+   commit which is to be fixed up (e.g. "fixup! e83c5163").
+
+ * The default "recursive" merge strategy learned the --rename-threshold
    option to influence the rename detection, similar to the -M option
-   of "git diff".  E.g. "git merge -Xrename-threshold=50% ..." to use
-   this.
+   of "git diff".  From the "git merge" frontend, the "-X<strategy option>"
+   interface, e.g. "git merge -Xrename-threshold=50% ...", can be used
+   to trigger this.
 
  * The "recursive" strategy also learned to ignore various whitespace
    changes; the most notable is -Xignore-space-at-eol.
 
  * "git send-email" learned "--to-cmd", similar to "--cc-cmd", to read
-   recipient list from a command output.
+   the recipient list from a command output.
 
  * "git send-email" learned to read and use "To:" from its input files.
 
  * you can extend "git shell", which is often used on boxes that allow
-   git-only login over ssh as login shell, with custom set of
+   git-only login over ssh as login shell, with custom set of
    commands.
 
+ * The current branch name in "git status" output can be colored differently
+   from the generic header color by setting the "color.status.branch" variable.
+
  * "git submodule sync" updates metainformation for all submodules,
    not just the ones that have been checked out.
 
- * gitweb can use custom 'highlight' command with its configuration file.
+ * gitweb can use a custom 'highlight' command with its configuration file.
+
+ * other gitweb updates.
 
 
 Also contains various documentation updates.
@@ -93,31 +137,20 @@ Also contains various documentation updates.
 Fixes since v1.7.3
 ------------------
 
-All of the fixes in v1.7.3.X maintenance series are included in this
+All of the fixes in the v1.7.3.X maintenance series are included in this
 release, unless otherwise noted.
 
- * "git checkout" removed an untracked file "foo" from the working
-    tree when switching to a branch that contains a tracked path
-    "foo/bar".  Prevent this, just like the case where the conflicting
-    path were "foo" (c752e7f..7980872d).
-
  * "git log --author=me --author=her" did not find commits written by
    me or by her; instead it looked for commits written by me and by
    her, which is impossible.
 
- * "git merge" into an unborn branch removed an untracked file "foo"
-   from the working tree when merged branch had "foo" (2caf20c..172b642).
-
  * "git push --progress" shows progress indicators now.
 
+ * "git rebase -i" showed a confusing error message when given a
+   branch name that does not exist.
+
  * "git repack" places its temporary packs under $GIT_OBJECT_DIRECTORY/pack
    instead of $GIT_OBJECT_DIRECTORY/ to avoid cross directory renames.
 
  * "git submodule update --recursive --other-flags" passes flags down
    to its subinvocations.
-
----
-exec >/var/tmp/1
-O=v1.7.3.2-450-g5b9c331
-echo O=$(git describe master)
-git shortlog --no-merges ^maint ^$O master
index 3f01bd929f4cffe71eb8de1366ef6065cbf711fc..c5e183516a104e6efb7ed597fb4498d75560ab68 100644 (file)
@@ -317,24 +317,26 @@ false), while all other repositories are assumed to be bare (bare
 = true).
 
 core.worktree::
-       Set the path to the root of the work tree.
+       Set the path to the root of the working tree.
        This can be overridden by the GIT_WORK_TREE environment
-       variable and the '--work-tree' command line option. It can be
-       an absolute path or a relative path to the .git directory,
-       either specified by --git-dir or GIT_DIR, or automatically
-       discovered.
-       If --git-dir or GIT_DIR are specified but none of
+       variable and the '--work-tree' command line option.
+       The value can an absolute path or relative to the path to
+       the .git directory, which is either specified by --git-dir
+       or GIT_DIR, or automatically discovered.
+       If --git-dir or GIT_DIR is specified but none of
        --work-tree, GIT_WORK_TREE and core.worktree is specified,
-       the current working directory is regarded as the root of the
-       work tree.
+       the current working directory is regarded as the top level
+       of your working tree.
 +
 Note that this variable is honored even when set in a configuration
-file in a ".git" subdirectory of a directory, and its value differs
+file in a ".git" subdirectory of a directory and its value differs
 from the latter directory (e.g. "/path/to/.git/config" has
 core.worktree set to "/different/path"), which is most likely a
-misconfiguration.  Running git commands in "/path/to" directory will
+misconfiguration.  Running git commands in the "/path/to" directory will
 still use "/different/path" as the root of the work tree and can cause
-great confusion to the users.
+confusion unless you know what you are doing (e.g. you are creating a
+read-only snapshot of the same index to a location different from the
+repository's usual working tree).
 
 core.logAllRefUpdates::
        Enable the reflog. Updates to a ref <ref> is logged to the file
@@ -790,7 +792,8 @@ color.status.<slot>::
        one of `header` (the header text of the status message),
        `added` or `updated` (files which are added but not committed),
        `changed` (files which are changed but not added in the index),
-       `untracked` (files which are not tracked by git), or
+       `untracked` (files which are not tracked by git),
+       `branch` (the current branch), or
        `nobranch` (the color the 'no branch' warning is shown in, defaulting
        to red). The values of these variables may be specified as in
        color.branch.<slot>.
@@ -896,6 +899,11 @@ diff.wordRegex::
        sequences that match the regular expression are "words", all other
        characters are *ignorable* whitespace.
 
+fetch.recurseSubmodules::
+       A boolean value which changes the behavior for fetch and pull, the
+       default is to not recursively fetch populated submodules unless
+       configured otherwise.
+
 fetch.unpackLimit::
        If the number of objects fetched over the git native
        transfer is below this
@@ -990,7 +998,7 @@ gc.packrefs::
        Running `git pack-refs` in a repository renders it
        unclonable by Git versions prior to 1.5.1.2 over dumb
        transports such as HTTP.  This variable determines whether
-       'git gc' runs `git pack-refs`. This can be set to `nobare`
+       'git gc' runs `git pack-refs`. This can be set to `notbare`
        to enable it within all non-bare repos or it can be set to a
        boolean value.  The default is `true`.
 
@@ -1810,6 +1818,13 @@ submodule.<name>.update::
        URL and other values found in the `.gitmodules` file.  See
        linkgit:git-submodule[1] and linkgit:gitmodules[5] for details.
 
+submodule.<name>.fetchRecurseSubmodules::
+       This option can be used to enable/disable recursive fetching of this
+       submodule. It can be overridden by using the --[no-]recurse-submodules
+       command line option to "git fetch" and "git pull".
+       This setting will override that from in the linkgit:gitmodules[5]
+       file.
+
 submodule.<name>.ignore::
        Defines under what circumstances "git status" and the diff family show
        a submodule as modified. When set to "all", it will never be considered
index f3e95389aa5914cc05145625a5dd48bafbf086ba..c93124be79809e36d9a29fd69ce77cd7f22413e1 100644 (file)
@@ -230,7 +230,7 @@ eligible for being picked up as a possible source of a rename to
 another file.
 
 -M[<n>]::
---detect-renames[=<n>]::
+--find-renames[=<n>]::
 ifndef::git-log[]
        Detect renames.
 endif::git-log[]
@@ -246,7 +246,7 @@ endif::git-log[]
        hasn't changed.
 
 -C[<n>]::
---detect-copies[=<n>]::
+--find-copies[=<n>]::
        Detect copies as well as renames.  See also `--find-copies-harder`.
        If `n` is specified, it has the same meaning as for `-M<n>`.
 
index 678675ccdf06dbe0e97d80bb3fbc8985155d2fc0..f37276e5add75583fd363af2cd0b7ba051771a97 100644 (file)
@@ -64,6 +64,15 @@ ifndef::git-pull[]
        downloaded. The default behavior for a remote may be
        specified with the remote.<name>.tagopt setting. See
        linkgit:git-config[1].
+
+--[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]).
+
+--submodule-prefix=<path>::
+       Prepend <path> to paths printed in informative messages
+       such as "Fetching submodule foo".  This option is used
+       internally when recursing over submodules.
 endif::git-pull[]
 
 -u::
index 54aaaeb41b969be4c79a2a8072bc6daca469ca8d..a03448f9231f78340fc492bffa009b96648ee6ac 100644 (file)
@@ -333,7 +333,7 @@ likely to introduce confusing changes to the index.
 There are also more complex operations that can be performed. But beware
 that because the patch is applied only to the index and not the working
 tree, the working tree will appear to "undo" the change in the index.
-For example, introducing a new line into the index that is in neither
+For example, introducing a new line into the index that is in neither
 the HEAD nor the working tree will stage the new line for commit, but
 the line will appear to be reverted in the working tree.
 
index 4163a1bcb1643e7f05b6a79034ac9f63135d6ac9..bf5037ab2a5042a20e9cb603f0831bb186ac3b74 100644 (file)
@@ -116,7 +116,7 @@ Note that attributes are by default taken from the `.gitattributes` files
 in the tree that is being archived.  If you want to tweak the way the
 output is generated after the fact (e.g. you committed without adding an
 appropriate export-ignore in its `.gitattributes`), adjust the checked out
-`.gitattributes` file as necessary and use `--work-tree-attributes`
+`.gitattributes` file as necessary and use `--worktree-attributes`
 option.  Alternatively you can keep necessary attributes that should apply
 while archiving any tree in your `$GIT_DIR/info/attributes` file.
 
index 6266a3a6020db72c8629ad521dfedccc9d790a03..299007b206cb5d810d19eed9b7831c3ea6368043 100644 (file)
@@ -59,7 +59,7 @@ unbundle <file>::
 
 <git-rev-list-args>::
        A list of arguments, acceptable to 'git rev-parse' and
-       'git rev-list' (and containg a named ref, see SPECIFYING REFERENCES
+       'git rev-list' (and containing a named ref, see SPECIFYING REFERENCES
        below), that specifies the specific objects and references
        to transport.  For example, `master{tilde}10..master` causes the
        current master reference to be packaged along with all objects
index 73008705ebe304c8d2a2d089e9328be369c50fc6..749d68a72bf720d82260fe175be0824f7ad069eb 100644 (file)
@@ -79,6 +79,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,6 +130,28 @@ 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.
 
+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.
+
 Author
 ------
 Written by Junio C Hamano <gitster@pobox.com>
index b586c0f442afd33c2875af26b83bb261de7361b0..8f89f6f08c57335ea6606dd1eaddde98477e9c9e 100644 (file)
@@ -214,10 +214,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 +226,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::
index f6ac847507a635759323565be44b088b479d8bf0..49105102dbf899c62833572fdda51cefaed53476 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>...]::
index 6fffbc7bf89d01b14505c03993de9d97d37e9404..db87f1d42382e32d7e3ee94e5c3d0a032b7430e2 100644 (file)
@@ -56,14 +56,16 @@ the configured command line will be invoked with the following
 variables available: `$LOCAL` is set to the name of the temporary
 file containing the contents of the diff pre-image and `$REMOTE`
 is set to the name of the temporary file containing the contents
-of the diff post-image.  `$BASE` is provided for compatibility
-with custom merge tool commands and has the same value as `$LOCAL`.
+of the diff post-image.  `$MERGED` is the name of the file which is
+being compared. `$BASE` is provided for compatibility
+with custom merge tool commands and has the same value as `$MERGED`.
 
 -x <command>::
 --extcmd=<command>::
        Specify a custom command for viewing diffs.
        'git-difftool' ignores the configured defaults and runs
        `$command $LOCAL $REMOTE` when this option is specified.
+       Additionally, `$BASE` is set in the environment.
 
 -g::
 --gui::
index 5d0c245e38ff751d8c40a6eb6d5b17b80930d526..c3a2766b206609bb5f313db3ff37a1ebb40f8261 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
@@ -92,6 +96,11 @@ OPTIONS
        --(no-)-relative-marks= with the --(import|export)-marks=
        options.
 
+--cat-blob-fd=<fd>::
+       Specify the file descriptor that will be written to
+       when the `cat-blob` command is encountered in the stream.
+       The default behaviour is to write to `stdout`.
+
 --export-pack-edges=<file>::
        After creating a packfile, print a line of data to
        <file> listing the filename of the packfile and the last
@@ -320,6 +329,11 @@ and control the current import process.  More detailed discussion
        standard output.  This command is optional and is not needed
        to perform an import.
 
+`cat-blob`::
+       Causes fast-import to print a blob in 'cat-file --batch'
+       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.
@@ -524,9 +538,6 @@ start with double quote (`"`).
 If an `LF` or double quote must be encoded into `<path>` shell-style
 quoting should be used, e.g. `"path/with\n and \" in it"`.
 
-Additionally, in `040000` mode, `<path>` may also be an empty string
-(`""`) to specify the root of the tree.
-
 The value of `<path>` must be in canonical form. That is it must not:
 
 * contain an empty directory component (e.g. `foo//bar` is invalid),
@@ -535,6 +546,8 @@ The value of `<path>` must be in canonical form. That is it must not:
 * contain the special component `.` or `..` (e.g. `foo/./bar` and
   `foo/../bar` are invalid).
 
+The root of the tree can be represented by an empty string as `<path>`.
+
 It is recommended that `<path>` always be encoded using UTF-8.
 
 `filedelete`
@@ -879,34 +892,72 @@ Placing a `progress` command immediately after a `checkpoint` will
 inform the reader when the `checkpoint` has been completed and it
 can safely access the refs that fast-import updated.
 
+`cat-blob`
+~~~~~~~~~~
+Causes fast-import to print a blob to a file descriptor previously
+arranged with the `--cat-blob-fd` argument.  The command otherwise
+has no impact on the current import; its main purpose is to
+retrieve blobs that may be in fast-import's memory but not
+accessible from the target repository.
+
+....
+       'cat-blob' SP <dataref> LF
+....
+
+The `<dataref>` can be either a mark reference (`:<idnum>`)
+set previously or a full 40-byte SHA-1 of a Git blob, preexisting or
+ready to be written.
+
+Output uses the same format as `git cat-file --batch`:
+
+====
+       <sha1> SP 'blob' SP <size> LF
+       <contents> LF
+====
+
+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.
+
 `feature`
 ~~~~~~~~~
 Require that fast-import supports the specified feature, or abort if
 it does not.
 
 ....
-       'feature' SP <feature> LF
+       'feature' SP <feature> ('=' <argument>)? LF
 ....
 
-The <feature> part of the command may be any string matching
-^[a-zA-Z][a-zA-Z-]*$ and should be understood by fast-import.
-
-Feature work identical as their option counterparts with the
-exception of the import-marks feature, see below.
-
-The following features are currently supported:
+The <feature> part of the command may be any one of the following:
+
+date-format::
+export-marks::
+relative-marks::
+no-relative-marks::
+force::
+       Act as though the corresponding command-line option with
+       a leading '--' was passed on the command line
+       (see OPTIONS, above).
+
+import-marks::
+       Like --import-marks except in two respects: first, only one
+       "feature import-marks" command is allowed per stream;
+       second, an --import-marks= command-line option overrides
+       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.
+       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.
 
-* date-format
-* import-marks
-* export-marks
-* relative-marks
-* no-relative-marks
-* force
-
-The import-marks behaves differently from when it is specified as
-commandline option in that only one "feature import-marks" is allowed
-per stream. Also, any --import-marks= specified on the commandline
-will override those from the stream (if any).
 
 `option`
 ~~~~~~~~
@@ -933,6 +984,7 @@ not be passed as option:
 * date-format
 * import-marks
 * export-marks
+* cat-blob-fd
 * force
 
 Crash Reports
@@ -1233,6 +1285,13 @@ and lazy loading of subtrees, allows fast-import to efficiently import
 projects with 2,000+ branches and 45,114+ files in a very limited
 memory footprint (less than 2.7 MiB per active branch).
 
+Signals
+-------
+Sending *SIGUSR1* to the 'git fast-import' process ends the current
+packfile early, simulating a `checkpoint` command.  The impatient
+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
 ------
index 40dba8c0a9f308064f67d8f38ce8a22b2a42a77c..75adf7a502e18aa11e7a8424acf217b4bf6be64c 100644 (file)
@@ -57,7 +57,7 @@ merge.log::
        In addition to branch names, populate the log message with at
        most the specified number of one-line descriptions from the
        actual commits that are being merged.  Defaults to false, and
-       true is a synoym for 20.
+       true is a synonym for 20.
 
 merge.summary::
        Synonym to `merge.log`; this is deprecated and will be removed in
index 3ad48a633663ec22af16b4737c42fd7e7664e4d2..86f9b2bf91f604cbfd175a4e241fc14fcb5828d5 100644 (file)
@@ -123,9 +123,6 @@ dangling <type> <object>::
        The <type> object <object>, is present in the database but never
        'directly' used. A dangling commit could be a root node.
 
-warning: git-fsck: tree <tree> has full pathnames in it::
-       And it shouldn't...
-
 sha1 mismatch <object>::
        The database has an object who's sha1 doesn't match the
        database value.
index 801aede6094e40b5bfb1f4c5d09393e7011f500e..26632414b2646ba80a17fa861d422a9c8c957810 100644 (file)
@@ -107,7 +107,7 @@ how long records of conflicted merge you have not resolved are
 kept.  This defaults to 15 days.
 
 The optional configuration variable 'gc.packrefs' determines if
-'git gc' runs 'git pack-refs'. This can be set to "nobare" to enable
+'git gc' runs 'git pack-refs'. This can be set to "notbare" to enable
 it within all non-bare repos or it can be set to a boolean value.
 This defaults to true.
 
index 30466917dad52eefd76de95aead3fdc12ad8425d..b33e6be872508778faa59f478229cd6e16bddad7 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
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
index e88e9c2d55d19844ca56bc2d5b7b683e329b6fb8..634423a69ee6a4f2e9c7dd3941fd5160fbf6c99f 100644 (file)
@@ -416,13 +416,6 @@ turn `core.sparseCheckout` on in order to have sparse checkout
 support.
 
 
-BUGS
-----
-In order to match a directory with $GIT_DIR/info/sparse-checkout,
-trailing slash must be used. The form without trailing slash, while
-works with .gitignore, does not work with sparse checkout.
-
-
 SEE ALSO
 --------
 linkgit:git-write-tree[1]; linkgit:git-ls-files[1];
index f4fbf672094ed11acb5ca551b5cc411a86f3f1ba..2d65cfefd5d2aeaafcbc0bb6e6705f8379b2f826 100644 (file)
@@ -15,12 +15,12 @@ This remote helper uses the specified 'program' to connect
 to a remote git server.
 
 Data written to stdin of this specified 'program' is assumed
-to be sent to git:// server, git-upload-pack, git-receive-pack
+to be sent to 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
 the same service.
 
-Command and arguments are separated by unescaped space.
+Command and arguments are separated by an unescaped space.
 
 The following sequences have a special meaning:
 
@@ -39,19 +39,19 @@ The following sequences have a special meaning:
        git-upload-pack, or git-upload-archive) of the service
        git wants to invoke.
 
-'%G' (must be first characters in argument)::
+'%G' (must be the first characters in an argument)::
        This argument will not be passed to 'program'. Instead, it
-       will cause helper to start by sending git:// service request to
-       remote side with service field set to approiate value and
-       repository field set to rest of the argument. Default is not to send
-       such request.
+       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
+       such request.
 +
 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
-       the vhost field in git:// service request (to rest of the argument).
+       the vhost field in the git:// service request (to rest of the argument).
        Default is not to send vhost in such request (if sent).
 
 ENVIRONMENT VARIABLES:
index abc49441be7a86e25a2b09d98f7de2ddcf0b0bb2..4aecd4d1878e0af6c3e6c87a63df1375606ff65a 100644 (file)
@@ -11,20 +11,20 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-This helper uses specified file descriptors to connect to remote git server.
+This helper uses specified file descriptors to connect to remote git server.
 This is not meant for end users but for programs and scripts calling git
 fetch, push or archive.
 
-If only <infd> is given, it is assumed to be bidirectional socket connected
+If only <infd> is given, it is assumed to be bidirectional socket connected
 to remote git server (git-upload-pack, git-receive-pack or
 git-upload-achive). If both <infd> and <outfd> are given, they are assumed
-to be pipes connected to remote git server (<infd> being the inbound pipe
+to be pipes connected to remote git server (<infd> being the inbound pipe
 and <outfd> being the outbound pipe.
 
 It is assumed that any handshaking procedures have already been completed
 (such as sending service request for git://) before this helper is started.
 
-<anything> can be any string. It is ignored. It is meant for provoding
+<anything> can be any string. It is ignored. It is meant for providing
 information to user in the URL in case that URL is displayed in some
 context.
 
index fd72976371cee0fcd25e3419138eb13382dc6ab8..927ecee2f26cdf0bd30457d5016b654c01a23a14 100644 (file)
@@ -76,15 +76,10 @@ In other words, --merge does something like a 'git read-tree -u -m <commit>',
 but carries forward unmerged index entries.
 
 --keep::
-       Resets the index, updates files in the working tree that are
-       different between <commit> and HEAD, but keeps those
-       which are different between HEAD and the working tree (i.e.
-       which have local changes).
+       Resets index entries and updates files in the working tree that are
+       different between <commit> and HEAD.
        If a file that is different between <commit> and HEAD has local changes,
        reset is aborted.
-+
-In other words, --keep does a 2-way merge between <commit> and HEAD followed by
-'git reset --mixed <commit>'.
 --
 
 If you want to undo a commit other than the latest on a branch,
index 4a27643c1ea0e908a0a54b84f668d5a80f6d7100..ff23cb0219d602803a83da273195fcc4ca71b5f5 100644 (file)
@@ -136,7 +136,12 @@ appending `/{asterisk}`.
        directory (typically a sequence of "../", or an empty string).
 
 --git-dir::
-       Show `$GIT_DIR` if defined else show the path to the .git directory.
+       Show `$GIT_DIR` if defined. Otherwise show the path to
+       the .git directory, relative to the current directory.
++
+If `$GIT_DIR` is not defined and the current directory
+is not detected to lie in a git repository or work tree
+print a message to stderr and exit with nonzero status.
 
 --is-inside-git-dir::
        When the current working directory is below the repository
index 752fc88e768e4b8e1afddad4bdd7833cf20978c7..45be851750c2ce81500765f6dfbd23578c68abda 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::
index dae190a5f21d3835024ce263bf4bd9b08048cfa6..5102a23f8ee30fcff2a6e67d098495329a2fca1d 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
index 139d314ba54c4e7897ffcf257a1fd847eb7939fa..0ade2ce54efee3cd2241fc7e3009909eef5cf8bb 100644 (file)
@@ -613,7 +613,7 @@ old references to SVN revision numbers in existing documentation, bug
 reports and archives.  If you plan to eventually migrate from SVN to git
 and are certain about dropping SVN history, consider
 linkgit:git-filter-branch[1] instead.  filter-branch also allows
-reformating of metadata for ease-of-reading and rewriting authorship
+reformatting of metadata for ease-of-reading and rewriting authorship
 info for non-"svn.authorsFile" users.
 
 svn.useSvmProps::
@@ -729,8 +729,11 @@ have each person clone that repository with 'git clone':
        cd project
        git init
        git remote add origin server:/pub/project
-       git config --add remote.origin.fetch '+refs/remotes/*:refs/remotes/*'
+       git config --replace-all remote.origin.fetch '+refs/remotes/*:refs/remotes/*'
        git fetch
+# Prevent fetch/pull from remote git server in the future,
+# we only want to use git svn for future updates
+       git config --remove-section remote.origin
 # Create a local branch from one of the branches just fetched
        git checkout -b master FETCH_HEAD
 # Initialize 'git svn' locally (be sure to use the same URL and -T/-b/-t options as were used on server)
index 8b169e364a32afe7d2ff3fa8ae54121ed44e3788..65f76c544086458ec84322c73319d8b071288a0b 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
index 821608308174817861012f64439c8e8b60a1e134..0c32d45248c99e9e4b51f168ba03c829ad96423f 100644 (file)
@@ -44,34 +44,45 @@ 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.3.3/git.html[documentation for release 1.7.3.3]
+* 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]
+
+* release notes for
+  link:RelNotes/1.7.3.5.txt[1.7.3.5],
+  link:RelNotes/1.7.3.4.txt[1.7.3.4],
   link:RelNotes/1.7.3.3.txt[1.7.3.3],
   link:RelNotes/1.7.3.2.txt[1.7.3.2],
   link:RelNotes/1.7.3.1.txt[1.7.3.1],
   link:RelNotes/1.7.3.txt[1.7.3].
 
-* link:v1.7.2.4/git.html[documentation for release 1.7.2.4]
+* link:v1.7.2.5/git.html[documentation for release 1.7.2.5]
 
 * release notes for
+  link:RelNotes/1.7.2.5.txt[1.7.2.5],
   link:RelNotes/1.7.2.4.txt[1.7.2.4],
   link:RelNotes/1.7.2.3.txt[1.7.2.3],
   link:RelNotes/1.7.2.2.txt[1.7.2.2],
   link:RelNotes/1.7.2.1.txt[1.7.2.1],
   link:RelNotes/1.7.2.txt[1.7.2].
 
-* link:v1.7.1.3/git.html[documentation for release 1.7.1.3]
+* link:v1.7.1.4/git.html[documentation for release 1.7.1.4]
 
 * release notes for
+  link:RelNotes/1.7.1.4.txt[1.7.1.4],
   link:RelNotes/1.7.1.3.txt[1.7.1.3],
   link:RelNotes/1.7.1.2.txt[1.7.1.2],
   link:RelNotes/1.7.1.1.txt[1.7.1.1],
   link:RelNotes/1.7.1.txt[1.7.1].
 
-* link:v1.7.0.8/git.html[documentation for release 1.7.0.8]
+* link:v1.7.0.9/git.html[documentation for release 1.7.0.9]
 
 * release notes for
+  link:RelNotes/1.7.0.9.txt[1.7.0.9],
   link:RelNotes/1.7.0.8.txt[1.7.0.8],
   link:RelNotes/1.7.0.7.txt[1.7.0.7],
   link:RelNotes/1.7.0.6.txt[1.7.0.6],
@@ -82,16 +93,18 @@ Documentation for older releases are available here:
   link:RelNotes/1.7.0.1.txt[1.7.0.1],
   link:RelNotes/1.7.0.txt[1.7.0].
 
-* link:v1.6.6.2/git.html[documentation for release 1.6.6.2]
+* link:v1.6.6.3/git.html[documentation for release 1.6.6.3]
 
 * release notes for
+  link:RelNotes/1.6.6.3.txt[1.6.6.3],
   link:RelNotes/1.6.6.2.txt[1.6.6.2],
   link:RelNotes/1.6.6.1.txt[1.6.6.1],
   link:RelNotes/1.6.6.txt[1.6.6].
 
-* link:v1.6.5.8/git.html[documentation for release 1.6.5.8]
+* link:v1.6.5.9/git.html[documentation for release 1.6.5.9]
 
 * release notes for
+  link:RelNotes/1.6.5.9.txt[1.6.5.9],
   link:RelNotes/1.6.5.8.txt[1.6.5.8],
   link:RelNotes/1.6.5.7.txt[1.6.5.7],
   link:RelNotes/1.6.5.6.txt[1.6.5.6],
@@ -102,9 +115,10 @@ Documentation for older releases are available here:
   link:RelNotes/1.6.5.1.txt[1.6.5.1],
   link:RelNotes/1.6.5.txt[1.6.5].
 
-* link:v1.6.4.4/git.html[documentation for release 1.6.4.4]
+* link:v1.6.4.5/git.html[documentation for release 1.6.4.5]
 
 * release notes for
+  link:RelNotes/1.6.4.5.txt[1.6.4.5],
   link:RelNotes/1.6.4.4.txt[1.6.4.4],
   link:RelNotes/1.6.4.3.txt[1.6.4.3],
   link:RelNotes/1.6.4.2.txt[1.6.4.2],
@@ -283,17 +297,12 @@ help ...`.
        path or relative path to current working directory.
 
 --work-tree=<path>::
-       Set the path to the working tree.  The value will not be
-       used in combination with repositories found automatically in
-       a .git directory (i.e. $GIT_DIR is not set).
+       Set the path to the working tree. It can be an absolute path
+       or a path relative to the current working directory.
        This can also be controlled by setting the GIT_WORK_TREE
        environment variable and the core.worktree configuration
-       variable. It can be an absolute path or relative path to
-       the directory specified by --git-dir or GIT_DIR.
-       Note: If --git-dir or GIT_DIR are specified but none of
-       --work-tree, GIT_WORK_TREE and core.worktree is specified,
-       the current working directory is regarded as the top directory
-       of your working tree.
+       variable (see core.worktree in linkgit:git-config[1] for a
+       more detailed discussion).
 
 --bare::
        Treat the repository as a bare repository.  If GIT_DIR
index 5a7f9364299cb4ed34a7dc35688c9bddcd35ff3d..7e7e12168eb69d43f6d7eea9cde2176e06fe73d5 100644 (file)
@@ -335,6 +335,16 @@ input that is already correctly indented.  In this case, the lack of a
 smudge filter means that the clean filter _must_ accept its own output
 without modifying it.
 
+Sequence "%f" on the filter command line is replaced with the name of
+the file the filter is working on.  A filter might use this in keyword
+substitution.  For example:
+
+------------------------
+[filter "p4"]
+       clean = git-p4-filter --clean %f
+       smudge = git-p4-filter --smudge %f
+------------------------
+
 
 Interaction between checkin/checkout attributes
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -494,6 +504,8 @@ patterns are available:
 
 - `pascal` suitable for source code in the Pascal/Delphi language.
 
+- `perl` suitable for source code in the Perl language.
+
 - `php` suitable for source code in the PHP language.
 
 - `python` suitable for source code in the Python language.
@@ -581,6 +593,39 @@ and now produces better output), you can remove the cache
 manually with `git update-ref -d refs/notes/textconv/jpg` (where
 "jpg" is the name of the diff driver, as in the example above).
 
+Marking files as binary
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Git usually guesses correctly whether a blob contains text or binary
+data by examining the beginning of the contents. However, sometimes you
+may want to override its decision, either because a blob contains binary
+data later in the file, or because the content, while technically
+composed of text characters, is opaque to a human reader. For example,
+many postscript files contain only ascii characters, but produce noisy
+and meaningless diffs.
+
+The simplest way to mark a file as binary is to unset the diff
+attribute in the `.gitattributes` file:
+
+------------------------
+*.ps -diff
+------------------------
+
+This will cause git to generate `Binary files differ` (or a binary
+patch, if binary patches are enabled) instead of a regular diff.
+
+However, one may also want to specify other diff driver attributes. For
+example, you might want to use `textconv` to convert postscript files to
+an ascii representation for human viewing, but otherwise treat them as
+binary files. You cannot specify both `-diff` and `diff=ps` attributes.
+The solution is to use the `diff.*.binary` config option:
+
+------------------------
+[diff "ps"]
+  textconv = ps2ascii
+  binary = true
+------------------------
+
 Performing a three-way merge
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
index 7183aa9abbc35018dc50a7c0e5254cc72115af23..28edefa202fb0d1065f161f59787ceae39439eb3 100644 (file)
@@ -350,10 +350,6 @@ rebase::
 The commits are guaranteed to be listed in the order that they were
 processed by rebase.
 
-There is no default 'post-rewrite' hook, but see the
-`post-receive-copy-notes` script in `contrib/hooks` for an example
-that copies your git-notes to the rewritten commits.
-
 
 GIT
 ---
index bcffd95ada574a8fb3c6e62e539e736a17170414..68977943e7bba092f5e55e6ad1b9ede83f4c2b67 100644 (file)
@@ -44,6 +44,14 @@ submodule.<name>.update::
        This config option is overridden if 'git submodule update' is given
        the '--merge' or '--rebase' options.
 
+submodule.<name>.fetchRecurseSubmodules::
+       This option can be used to enable/disable recursive fetching of this
+       submodule. If this option is also present in the submodules entry in
+       .git/config of the superproject, the setting there will override the
+       one found in .gitmodules.
+       Both settings can be overridden on the command line by using the
+       "--[no-]recurse-submodules" option to "git fetch" and "git pull"..
+
 submodule.<name>.ignore::
        Defines under what circumstances "git status" and the diff family show
        a submodule as modified. When set to "all", it will never be considered
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 92772e7c4eb8921d3b2763fe1b533c380bd2b92b..1e5c22c5e5c19dab5d5c35ec2401870237830a5d 100644 (file)
@@ -10,7 +10,7 @@ merge.log::
        In addition to branch names, populate the log message with at
        most the specified number of one-line descriptions from the
        actual commits that are being merged.  Defaults to false, and
-       true is a synoym for 20.
+       true is a synonym for 20.
 
 merge.renameLimit::
        The number of files to consider when performing rename detection
index 3d4b79c480e2c84150bee96392ee2dd2a4b7d3ea..9e92734bc1b308c47e5f5726c704a3ddffa5beb9 100644 (file)
@@ -106,6 +106,12 @@ the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file.
   and dereference the tag recursively until a non-tag object is
   found.
 
+* A suffix '{caret}' to a revision parameter followed by a brace
+  pair that contains a text led by a slash (e.g. `HEAD^{/fix nasty bug}`):
+  this is the same as `:/fix nasty bug` syntax below except that
+  it returns the youngest matching commit which is reachable from
+  the ref before '{caret}'.
+
 * A colon, followed by a slash, followed by a text (e.g. `:/fix nasty bug`): this names
   a commit whose commit message matches the specified regular expression.
   This name returns the youngest matching commit which is
@@ -121,6 +127,10 @@ the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file.
   ':path' (with an empty part before the colon, e.g. `:README`)
   is a special case of the syntax described next: content
   recorded in the index at the given path.
+  A path starting with './' or '../' is relative to current working directory.
+  The given path will be converted to be relative to working tree's root directory.
+  This is most useful to address a blob or tree from a commit or tree that has
+  the same tree structure with the working tree.
 
 * A colon, optionally followed by a stage number (0 to 3) and a
   colon, followed by a path (e.g. `:0:README`); this names a blob object in the
index 535cdff164f1f1cdf829f18fa192783efb9f0086..9e1189ef01dff889447c1bf92802c9792f267b9b 100644 (file)
@@ -32,7 +32,7 @@ and installation code should look something like:
   }
 ------------------------------------------
 
-Handlers are given the typdef of sigchain_fun. This is the same type
+Handlers are given the typedef of sigchain_fun. This is the same type
 that is given to signal() or sigaction(). It is perfectly reasonable to
 push SIG_DFL or SIG_IGN onto the stack.
 
index d441d88d6fbd6d98bb617e5cf5d2bd7704f86a45..92fe7a59dbf81b0a055280f9351811641ce7044a 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.3.GIT
+DEF_VER=v1.7.4
 
 LF='
 '
index 5103dd4666a5bc2447c80421314aca8c5ffa7b13..ade79232f4c3c080fa7d35c4b55870c416e49da6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -431,9 +431,11 @@ TEST_PROGRAMS_NEED_X += test-run-command
 TEST_PROGRAMS_NEED_X += test-sha1
 TEST_PROGRAMS_NEED_X += test-sigchain
 TEST_PROGRAMS_NEED_X += test-string-pool
+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))
 
@@ -1003,6 +1005,7 @@ ifeq ($(uname_S),IRIX)
        # issue, comment out the NO_MMAP statement.
        NO_MMAP = YesPlease
        NO_REGEX = YesPlease
+       NO_FNMATCH_CASEFOLD = YesPlease
        SNPRINTF_RETURNS_BOGUS = YesPlease
        SHELL_PATH = /usr/gnu/bin/bash
        NEEDS_LIBGEN = YesPlease
@@ -1022,6 +1025,7 @@ ifeq ($(uname_S),IRIX64)
        # issue, comment out the NO_MMAP statement.
        NO_MMAP = YesPlease
        NO_REGEX = YesPlease
+       NO_FNMATCH_CASEFOLD = YesPlease
        SNPRINTF_RETURNS_BOGUS = YesPlease
        SHELL_PATH=/usr/gnu/bin/bash
        NEEDS_LIBGEN = YesPlease
@@ -1102,7 +1106,7 @@ ifeq ($(uname_S),Windows)
                compat/win32/sys/poll.o compat/win32/dirent.o
        COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -DHAVE_ALLOCA_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
        BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE -NODEFAULTLIB:MSVCRT.lib
-       EXTLIBS = advapi32.lib shell32.lib wininet.lib ws2_32.lib
+       EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib
        PTHREAD_LIBS =
        lib =
 ifndef DEBUG
@@ -1303,11 +1307,15 @@ else
        BLK_SHA1 = 1
        OPENSSL_LIBSSL =
 endif
+ifdef NO_OPENSSL
+       LIB_4_CRYPTO =
+else
 ifdef NEEDS_SSL_WITH_CRYPTO
        LIB_4_CRYPTO = $(OPENSSL_LINK) -lcrypto -lssl
 else
        LIB_4_CRYPTO = $(OPENSSL_LINK) -lcrypto
 endif
+endif
 ifdef NEEDS_LIBICONV
        ifdef ICONVDIR
                BASIC_CFLAGS += -I$(ICONVDIR)/include
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
                ])
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..f7a17e43f6816622ab4ff836a169221289756505 100644 (file)
@@ -86,7 +86,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 +317,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 0cad20bb5a8bd0054761861aada7f1077260dbd5..fe8f2fcd524cd690c8601d9370079f9d9ea21df3 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"
@@ -313,12 +313,7 @@ static int append_ref(const char *refname, const unsigned char *sha1, int flags,
                                           (struct object *)commit, refname);
        }
 
-       /* Resize buffer */
-       if (ref_list->index >= ref_list->alloc) {
-               ref_list->alloc = alloc_nr(ref_list->alloc);
-               ref_list->list = xrealloc(ref_list->list,
-                               ref_list->alloc * sizeof(struct ref_item));
-       }
+       ALLOC_GROW(ref_list->list, ref_list->index + 1, ref_list->alloc);
 
        /* Record the new item */
        newitem = &(ref_list->list[ref_list->index++]);
index 757f9a08ddbaf102726a781b06d7294a4638984e..bef324e4717fbe73da852c49c664e02d70955fc9 100644 (file)
@@ -297,7 +297,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 +404,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);
index 61e0989b5ab8fffb16ec28e64c38b4fa236cb3ed..60d9a64280b0318b1248b229d2ff99b27eb0e5c6 100644 (file)
@@ -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",
index c045c9ef8cf19b5458c279cd46250c839285a4a4..d7f55e3d46e215f94c94f1f40b5cc1ec6907701e 100644 (file)
@@ -45,9 +45,9 @@ static const char implicit_ident_advice[] =
 "    git config --global user.name \"Your Name\"\n"
 "    git config --global user.email you@example.com\n"
 "\n"
-"If the identity used for this commit is wrong, you can fix it with:\n"
+"After doing this, you may fix the identity used for this commit with:\n"
 "\n"
-"    git commit --amend --author='Your Name <you@example.com>'\n";
+"    git commit --amend --reset-author\n";
 
 static const char empty_amend_advice[] =
 "You asked to amend the most recent commit, but doing so would make\n"
@@ -70,7 +70,6 @@ static const char *logfile, *force_author;
 static const char *template_file;
 static char *edit_message, *use_message;
 static char *fixup_message, *squash_message;
-static char *author_name, *author_email, *author_date;
 static int all, edit_flag, also, interactive, only, amend, signoff;
 static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
 static int no_post_rewrite, allow_empty_message;
@@ -119,10 +118,10 @@ 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_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", "specify commit message", opt_parse_m),
+       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"),
@@ -146,12 +145,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,
@@ -462,7 +461,7 @@ static int is_a_merge(const unsigned char *sha1)
 
 static const char sign_off_header[] = "Signed-off-by: ";
 
-static void determine_author_info(void)
+static void determine_author_info(struct strbuf *author_ident)
 {
        char *name, *email, *date;
 
@@ -506,10 +505,8 @@ static void determine_author_info(void)
 
        if (force_date)
                date = force_date;
-
-       author_name = name;
-       author_email = email;
-       author_date = date;
+       strbuf_addstr(author_ident, fmt_ident(name, email, date,
+                                             IDENT_ERROR_ON_NO_NAME));
 }
 
 static int ends_rfc2822_footer(struct strbuf *sb)
@@ -553,10 +550,21 @@ static int ends_rfc2822_footer(struct strbuf *sb)
        return 1;
 }
 
+static char *cut_ident_timestamp_part(char *string)
+{
+       char *ket = strrchr(string, '>');
+       if (!ket || ket[1] != ' ')
+               die("Malformed ident string: '%s'", string);
+       *++ket = '\0';
+       return ket;
+}
+
 static int prepare_to_commit(const char *index_file, const char *prefix,
-                            struct wt_status *s)
+                            struct wt_status *s,
+                            struct strbuf *author_ident)
 {
        struct stat statbuf;
+       struct strbuf committer_ident = STRBUF_INIT;
        int commitable, saved_color_setting;
        struct strbuf sb = STRBUF_INIT;
        char *buffer;
@@ -679,14 +687,13 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
 
        strbuf_release(&sb);
 
-       determine_author_info();
+       /* This checks and barfs if author is badly specified */
+       determine_author_info(author_ident);
 
        /* This checks if committer ident is explicitly given */
-       git_committer_info(0);
+       strbuf_addstr(&committer_ident, git_committer_info(0));
        if (use_editor && include_status) {
-               char *author_ident;
-               const char *committer_ident;
-
+               char *ai_tmp, *ci_tmp;
                if (in_merge)
                        fprintf(fp,
                                "#\n"
@@ -714,23 +721,21 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                if (only_include_assumed)
                        fprintf(fp, "# %s\n", only_include_assumed);
 
-               author_ident = xstrdup(fmt_name(author_name, author_email));
-               committer_ident = fmt_name(getenv("GIT_COMMITTER_NAME"),
-                                          getenv("GIT_COMMITTER_EMAIL"));
-               if (strcmp(author_ident, committer_ident))
+               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,
                                "%s"
                                "# Author:    %s\n",
                                ident_shown++ ? "" : "#\n",
-                               author_ident);
-               free(author_ident);
+                               author_ident->buf);
 
                if (!user_ident_sufficiently_given())
                        fprintf(fp,
                                "%s"
                                "# Committer: %s\n",
                                ident_shown++ ? "" : "#\n",
-                               committer_ident);
+                               committer_ident.buf);
 
                if (ident_shown)
                        fprintf(fp, "#\n");
@@ -739,6 +744,9 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                s->use_color = 0;
                commitable = run_status(fp, index_file, prefix, 1, s);
                s->use_color = saved_color_setting;
+
+               *ai_tmp = ' ';
+               *ci_tmp = ' ';
        } else {
                unsigned char sha1[20];
                const char *parent = "HEAD";
@@ -754,6 +762,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                else
                        commitable = index_differs_from(parent, 0);
        }
+       strbuf_release(&committer_ident);
 
        fclose(fp);
 
@@ -1011,6 +1020,8 @@ static int parse_status_slot(const char *var, int offset)
 {
        if (!strcasecmp(var+offset, "header"))
                return WT_STATUS_HEADER;
+       if (!strcasecmp(var+offset, "branch"))
+               return WT_STATUS_ONBRANCH;
        if (!strcasecmp(var+offset, "updated")
                || !strcasecmp(var+offset, "added"))
                return WT_STATUS_UPDATED;
@@ -1081,7 +1092,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"),
@@ -1276,6 +1287,7 @@ static int run_rewrite_hook(const unsigned char *oldsha1,
 int cmd_commit(int argc, const char **argv, const char *prefix)
 {
        struct strbuf sb = STRBUF_INIT;
+       struct strbuf author_ident = STRBUF_INIT;
        const char *index_file, *reflog_msg;
        char *nl, *p;
        unsigned char commit_sha1[20];
@@ -1306,7 +1318,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
 
        /* Set up everything for writing the commit object.  This includes
           running hooks, writing the trees, and interacting with the user.  */
-       if (!prepare_to_commit(index_file, prefix, &s)) {
+       if (!prepare_to_commit(index_file, prefix, &s, &author_ident)) {
                rollback_index_files();
                return 1;
        }
@@ -1385,11 +1397,11 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        }
 
        if (commit_tree(sb.buf, active_cache_tree->sha1, parents, commit_sha1,
-                       fmt_ident(author_name, author_email, author_date,
-                               IDENT_ERROR_ON_NO_NAME))) {
+                       author_ident.buf)) {
                rollback_index_files();
                die("failed to write commit object");
        }
+       strbuf_release(&author_ident);
 
        ref_lock = lock_any_ref_for_update("HEAD",
                                           initial_commit ? NULL : head_sha1,
index ca4a0db4a79241d7ded005483b4693967eea636f..dad86fecfe8cd3b4ac5d4e1b39b74eb0f904db6b 100644 (file)
@@ -500,3 +500,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 43caff2ffe185df6ab224b93b4fd9ce3d82de2d0..342129fdbdc534bdf9277de710f8e7b7ba11c5c4 100644 (file)
@@ -6,6 +6,7 @@
 #include "exec_cmd.h"
 #include "parse-options.h"
 #include "diff.h"
+#include "hash.h"
 
 #define SEEN           (1u<<0)
 #define MAX_TAGS       (FLAG_BITS - 1)
@@ -22,7 +23,8 @@ static int tags;      /* Allow lightweight tags */
 static int longformat;
 static int abbrev = DEFAULT_ABBREV;
 static int max_candidates = 10;
-static int found_names;
+static struct hash_table names;
+static int have_util;
 static const char *pattern;
 static int always;
 static const char *dirty;
@@ -34,16 +36,44 @@ static const char *diff_index_args[] = {
 
 
 struct commit_name {
+       struct commit_name *next;
+       unsigned char peeled[20];
        struct tag *tag;
        unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
        unsigned name_checked:1;
        unsigned char sha1[20];
-       char path[FLEX_ARRAY]; /* more */
+       const char *path;
 };
 static const char *prio_names[] = {
        "head", "lightweight", "annotated",
 };
 
+static inline unsigned int hash_sha1(const unsigned char *sha1)
+{
+       unsigned int hash;
+       memcpy(&hash, sha1, sizeof(hash));
+       return hash;
+}
+
+static inline struct commit_name *find_commit_name(const unsigned char *peeled)
+{
+       struct commit_name *n = lookup_hash(hash_sha1(peeled), &names);
+       while (n && !!hashcmp(peeled, n->peeled))
+               n = n->next;
+       return n;
+}
+
+static int set_util(void *chain)
+{
+       struct commit_name *n;
+       for (n = chain; n; n = n->next) {
+               struct commit *c = lookup_commit_reference_gently(n->peeled, 1);
+               if (c)
+                       c->util = n;
+       }
+       return 0;
+}
+
 static int replace_name(struct commit_name *e,
                               int prio,
                               const unsigned char *sha1,
@@ -78,31 +108,36 @@ static int replace_name(struct commit_name *e,
 }
 
 static void add_to_known_names(const char *path,
-                              struct commit *commit,
+                              const unsigned char *peeled,
                               int prio,
                               const unsigned char *sha1)
 {
-       struct commit_name *e = commit->util;
+       struct commit_name *e = find_commit_name(peeled);
        struct tag *tag = NULL;
        if (replace_name(e, prio, sha1, &tag)) {
-               size_t len = strlen(path)+1;
-               free(e);
-               e = xmalloc(sizeof(struct commit_name) + len);
+               if (!e) {
+                       void **pos;
+                       e = xmalloc(sizeof(struct commit_name));
+                       hashcpy(e->peeled, peeled);
+                       pos = insert_hash(hash_sha1(peeled), e, &names);
+                       if (pos) {
+                               e->next = *pos;
+                               *pos = e;
+                       } else {
+                               e->next = NULL;
+                       }
+               }
                e->tag = tag;
                e->prio = prio;
                e->name_checked = 0;
                hashcpy(e->sha1, sha1);
-               memcpy(e->path, path, len);
-               commit->util = e;
+               e->path = path;
        }
-       found_names = 1;
 }
 
 static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 {
        int might_be_tag = !prefixcmp(path, "refs/tags/");
-       struct commit *commit;
-       struct object *object;
        unsigned char peeled[20];
        int is_tag, prio;
 
@@ -110,16 +145,10 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
                return 0;
 
        if (!peel_ref(path, peeled) && !is_null_sha1(peeled)) {
-               commit = lookup_commit_reference_gently(peeled, 1);
-               if (!commit)
-                       return 0;
-               is_tag = !!hashcmp(sha1, commit->object.sha1);
+               is_tag = !!hashcmp(sha1, peeled);
        } else {
-               commit = lookup_commit_reference_gently(sha1, 1);
-               object = parse_object(sha1);
-               if (!commit || !object)
-                       return 0;
-               is_tag = object->type == OBJ_TAG;
+               hashcpy(peeled, sha1);
+               is_tag = 0;
        }
 
        /* If --all, then any refs are used.
@@ -142,7 +171,7 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
                if (!prio)
                        return 0;
        }
-       add_to_known_names(all ? path + 5 : path + 10, commit, prio, sha1);
+       add_to_known_names(all ? path + 5 : path + 10, peeled, prio, sha1);
        return 0;
 }
 
@@ -189,7 +218,7 @@ static unsigned long finish_depth_computation(
                        struct commit *p = parents->item;
                        parse_commit(p);
                        if (!(p->object.flags & SEEN))
-                               insert_by_date(p, list);
+                               commit_list_insert_by_date(p, list);
                        p->object.flags |= c->object.flags;
                        parents = parents->next;
                }
@@ -240,7 +269,7 @@ static void describe(const char *arg, int last_one)
        if (!cmit)
                die("%s is not a valid '%s' object", arg, commit_type);
 
-       n = cmit->util;
+       n = find_commit_name(cmit->object.sha1);
        if (n && (tags || all || n->prio == 2)) {
                /*
                 * Exact match to an existing ref.
@@ -259,6 +288,11 @@ static void describe(const char *arg, int last_one)
        if (debug)
                fprintf(stderr, "searching to describe %s\n", arg);
 
+       if (!have_util) {
+               for_each_hash(&names, set_util);
+               have_util = 1;
+       }
+
        list = NULL;
        cmit->object.flags = SEEN;
        commit_list_insert(cmit, &list);
@@ -300,7 +334,7 @@ static void describe(const char *arg, int last_one)
                        struct commit *p = parents->item;
                        parse_commit(p);
                        if (!(p->object.flags & SEEN))
-                               insert_by_date(p, &list);
+                               commit_list_insert_by_date(p, &list);
                        p->object.flags |= c->object.flags;
                        parents = parents->next;
                }
@@ -328,7 +362,7 @@ static void describe(const char *arg, int last_one)
        qsort(all_matches, match_cnt, sizeof(all_matches[0]), compare_pt);
 
        if (gave_up_on) {
-               insert_by_date(gave_up_on, &list);
+               commit_list_insert_by_date(gave_up_on, &list);
                seen_commits--;
        }
        seen_commits += finish_depth_computation(&list, &all_matches[0]);
@@ -418,8 +452,9 @@ int cmd_describe(int argc, const char **argv, const char *prefix)
                return cmd_name_rev(i + argc, args, prefix);
        }
 
-       for_each_ref(get_name, NULL);
-       if (!found_names && !always)
+       init_hash(&names);
+       for_each_rawref(get_name, NULL);
+       if (!names.nr && !always)
                die("No names found, cannot describe anything.");
 
        if (argc == 0) {
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..ba57457cc54812ba935c5259277e12d72463f63f 100644 (file)
@@ -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 dbd8b7bcc8b5ddea9bec3a0c774346007cb0d31c..b9994139345834a58b08a5ce57cf59c124e21760 100644 (file)
@@ -47,7 +47,7 @@ static void rev_list_push(struct commit *commit, int mark)
                        if (parse_commit(commit))
                                return;
 
-               insert_by_date(commit, &rev_list);
+               commit_list_insert_by_date(commit, &rev_list);
 
                if (!(commit->object.flags & COMMON))
                        non_common_revs++;
@@ -436,7 +436,7 @@ static int mark_complete(const char *path, const unsigned char *sha1, int flag,
        if (o && o->type == OBJ_COMMIT) {
                struct commit *commit = (struct commit *)o;
                commit->object.flags |= COMPLETE;
-               insert_by_date(commit, &complete);
+               commit_list_insert_by_date(commit, &complete);
        }
        return 0;
 }
index 6bcce55c0cdb6686e0585bf11107559ba61a5700..357f3cdbbfd601e2ce3f1261a4d6b30c1257cda4 100644 (file)
@@ -12,6 +12,7 @@
 #include "parse-options.h"
 #include "sigchain.h"
 #include "transport.h"
+#include "submodule.h"
 
 static const char * const builtin_fetch_usage[] = {
        "git fetch [<options>] [<repository> [<refspec>...]]",
@@ -27,13 +28,20 @@ enum {
        TAGS_SET = 2
 };
 
+enum {
+       RECURSE_SUBMODULES_OFF = 0,
+       RECURSE_SUBMODULES_DEFAULT = 1,
+       RECURSE_SUBMODULES_ON = 2
+};
+
 static int all, append, dry_run, force, keep, multiple, prune, update_head_ok, verbosity;
-static int progress;
+static int progress, recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
 static int tags = TAGS_DEFAULT;
 static const char *depth;
 static const char *upload_pack;
 static struct strbuf default_rla = STRBUF_INIT;
 static struct transport *transport;
+static const char *submodule_prefix = "";
 
 static struct option builtin_fetch_options[] = {
        OPT__VERBOSITY(&verbosity),
@@ -52,6 +60,9 @@ static struct option builtin_fetch_options[] = {
                    "do not fetch all tags (--no-tags)", TAGS_UNSET),
        OPT_BOOLEAN('p', "prune", &prune,
                    "prune remote-tracking branches no longer on remote"),
+       OPT_SET_INT(0, "recurse-submodules", &recurse_submodules,
+                   "control recursive fetching of submodules",
+                   RECURSE_SUBMODULES_ON),
        OPT_BOOLEAN(0, "dry-run", &dry_run,
                    "dry run"),
        OPT_BOOLEAN('k', "keep", &keep, "keep downloaded pack"),
@@ -60,6 +71,8 @@ static struct option builtin_fetch_options[] = {
        OPT_BOOLEAN(0, "progress", &progress, "force progress reporting"),
        OPT_STRING(0, "depth", &depth, "DEPTH",
                   "deepen history of shallow clone"),
+       { OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, "DIR",
+                  "prepend this to submodule path output", PARSE_OPT_HIDDEN },
        OPT_END()
 };
 
@@ -783,28 +796,36 @@ static int add_remote_or_group(const char *name, struct string_list *list)
        return 1;
 }
 
-static int fetch_multiple(struct string_list *list)
+static void add_options_to_argv(int *argc, const char **argv)
 {
-       int i, result = 0;
-       const char *argv[11] = { "fetch", "--append" };
-       int argc = 2;
-
        if (dry_run)
-               argv[argc++] = "--dry-run";
+               argv[(*argc)++] = "--dry-run";
        if (prune)
-               argv[argc++] = "--prune";
+               argv[(*argc)++] = "--prune";
        if (update_head_ok)
-               argv[argc++] = "--update-head-ok";
+               argv[(*argc)++] = "--update-head-ok";
        if (force)
-               argv[argc++] = "--force";
+               argv[(*argc)++] = "--force";
        if (keep)
-               argv[argc++] = "--keep";
+               argv[(*argc)++] = "--keep";
+       if (recurse_submodules == RECURSE_SUBMODULES_ON)
+               argv[(*argc)++] = "--recurse-submodules";
        if (verbosity >= 2)
-               argv[argc++] = "-v";
+               argv[(*argc)++] = "-v";
        if (verbosity >= 1)
-               argv[argc++] = "-v";
+               argv[(*argc)++] = "-v";
        else if (verbosity < 0)
-               argv[argc++] = "-q";
+               argv[(*argc)++] = "-q";
+
+}
+
+static int fetch_multiple(struct string_list *list)
+{
+       int i, result = 0;
+       const char *argv[12] = { "fetch", "--append" };
+       int argc = 2;
+
+       add_options_to_argv(&argc, argv);
 
        if (!append && !dry_run) {
                int errcode = truncate_fetch_head();
@@ -925,6 +946,21 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
                }
        }
 
+       if (!result && (recurse_submodules != RECURSE_SUBMODULES_OFF)) {
+               const char *options[10];
+               int num_options = 0;
+               /* Set recursion as default when we already are recursing */
+               if (submodule_prefix[0])
+                       set_config_fetch_recurse_submodules(1);
+               gitmodules_config();
+               git_config(submodule_config, NULL);
+               add_options_to_argv(&num_options, options);
+               result = fetch_populated_submodules(num_options, options,
+                                                   submodule_prefix,
+                                                   recurse_submodules == RECURSE_SUBMODULES_ON,
+                                                   verbosity < 0);
+       }
+
        /* All names were strdup()ed or strndup()ed */
        list.strdup_strings = 1;
        string_list_clear(&list, 0);
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..c3af8760cc778b4eb835d4fb543f45aa333b214c 100644 (file)
@@ -329,106 +329,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 +481,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 +491,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 +518,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 +551,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 +574,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 +607,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 +616,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,7 +624,7 @@ 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++) {
                hit |= grep_file(opt, dir.entries[i]->name);
                if (hit && opt->status_only)
@@ -832,6 +730,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 +958,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 +991,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 9d4886c71675f2bc50671ea284875ebae9a34735..4f5348eec670faaa62b24fff30b477ddd42acbc6 100644 (file)
@@ -414,11 +414,12 @@ static const char *const init_db_usage[] = {
 int cmd_init_db(int argc, const char **argv, const char *prefix)
 {
        const char *git_dir;
+       const char *work_tree;
        const char *template_dir = NULL;
        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,
@@ -480,8 +481,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
         * without --bare.  Catch the error early.
         */
        git_dir = getenv(GIT_DIR_ENVIRONMENT);
-       if ((!git_dir || is_bare_repository_cfg == 1)
-           && getenv(GIT_WORK_TREE_ENVIRONMENT))
+       work_tree = getenv(GIT_WORK_TREE_ENVIRONMENT);
+       if ((!git_dir || is_bare_repository_cfg == 1) && work_tree)
                die("%s (or --work-tree=<directory>) not allowed without "
                    "specifying %s (or --git-dir=<directory>)",
                    GIT_WORK_TREE_ENVIRONMENT,
@@ -510,10 +511,18 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
                        if (!getcwd(git_work_tree_cfg, PATH_MAX))
                                die_errno ("Cannot access current working directory");
                }
+               if (work_tree)
+                       set_git_work_tree(make_absolute_path(work_tree));
+               else
+                       set_git_work_tree(git_work_tree_cfg);
                if (access(get_git_work_tree(), X_OK))
                        die_errno ("Cannot access work tree '%s'",
                                   get_git_work_tree());
        }
+       else {
+               if (work_tree)
+                       set_git_work_tree(make_absolute_path(work_tree));
+       }
 
        set_git_dir(make_absolute_path(git_dir));
 
index d8c6c28d2fcc3bd0744f071da536215141dc0d0b..f5ed690c435423662808fe0ff7f1e256374586db 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++) {
index 42fff387e69d9b5412e8e776aed3272b78ebe758..8c58c3cc4a7cfe5eae9675f627254f61c14f7be2 100644 (file)
@@ -194,8 +194,8 @@ static struct option builtin_merge_options[] = {
                "merge strategy to use", option_parse_strategy),
        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)",
+       OPT_CALLBACK('m', "message", &merge_msg, "MESSAGE",
+               "merge commit message (for a non-fast-forward merge)",
                option_parse_message),
        OPT__VERBOSITY(&verbosity),
        OPT_BOOLEAN(0, "abort", &abort_current_merge,
@@ -582,7 +582,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;
@@ -680,7 +681,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);
        }
 }
 
index 1f773171cbdde76cc105e37928cc5f2ecb2ed93f..ea71977c8360e1a7899bbd035cf26f93d889800b 100644 (file)
@@ -212,16 +212,16 @@ static int command_loop(const char *child)
        char buffer[MAXCOMMAND];
 
        while (1) {
-               size_t length;
+               size_t i;
                if (!fgets(buffer, MAXCOMMAND - 1, stdin)) {
                        if (ferror(stdin))
                                die("Comammand input error");
                        exit(0);
                }
                /* Strip end of line characters. */
-               length = strlen(buffer);
-               while (isspace((unsigned char)buffer[length - 1]))
-                       buffer[--length] = 0;
+               i = strlen(buffer);
+               while (i > 0 && isspace(buffer[i - 1]))
+                       buffer[--i] = 0;
 
                if (!strcmp(buffer, "capabilities")) {
                        printf("*connect\n\n");
index bb6e9e83b756b47dae449064ca7762fe3558fc0e..dc1b702edc6b4bd95ebf41c12bf1da6fe9d6850d 100644 (file)
@@ -44,7 +44,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 +59,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 +82,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(),
@@ -311,18 +328,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 +344,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);
@@ -503,7 +518,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 c7b7bb37a2378aaeeddbbdfacd0f0a62337ec152..ff491d77612ffb3c906c5e1ffa232f4410e4b661 100644 (file)
@@ -20,15 +20,6 @@ static struct {
        const char **name;
 } list;
 
-static void add_list(const char *name)
-{
-       if (list.nr >= list.alloc) {
-               list.alloc = alloc_nr(list.alloc);
-               list.name = xrealloc(list.name, list.alloc * sizeof(const char *));
-       }
-       list.name[list.nr++] = name;
-}
-
 static int check_local_mod(unsigned char *head, int index_only)
 {
        /*
@@ -182,7 +173,8 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
                struct cache_entry *ce = active_cache[i];
                if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen))
                        continue;
-               add_list(ce->name);
+               ALLOC_GROW(list.name, list.nr + 1, list.alloc);
+               list.name[list.nr++] = ce->name;
        }
 
        if (pathspec) {
index 8663ccaa99299447a42da64f9f2c77f772996902..da695815e26c281cbacfbf865dfa72da44df9f19 100644 (file)
@@ -243,7 +243,7 @@ static void join_revs(struct commit_list **list_p,
                        if (mark_seen(p, seen_p) && !still_interesting)
                                extra--;
                        p->object.flags |= flags;
-                       insert_by_date(p, list_p);
+                       commit_list_insert_by_date(p, list_p);
                }
        }
 
@@ -859,7 +859,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                 */
                commit->object.flags |= flag;
                if (commit->object.flags == flag)
-                       insert_by_date(commit, &list);
+                       commit_list_insert_by_date(commit, &list);
                rev[num_rev] = commit;
        }
        for (i = 0; i < num_rev; i++)
@@ -868,7 +868,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
        if (0 <= extra)
                join_revs(&list, &seen, num_rev, extra);
 
-       sort_by_date(&seen);
+       commit_list_sort_by_date(&seen);
 
        if (merge_base)
                return show_merge_base(seen, num_rev);
index aa1f87d47a3e4bdaa2ca3711c9dfc495fc2247e0..246a2bc72bf9e89454a27265f6dbcd904698feab 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 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 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 194f784808a4ead9b61f406d2ffe60fe864831bf..677994a23a71d17ccaff7c5e461e96ec501742b8 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -170,26 +170,26 @@ struct cache_entry {
  *
  * In-memory only flags
  */
-#define CE_UPDATE    (0x10000)
-#define CE_REMOVE    (0x20000)
-#define CE_UPTODATE  (0x40000)
-#define CE_ADDED     (0x80000)
+#define CE_UPDATE            (1 << 16)
+#define CE_REMOVE            (1 << 17)
+#define CE_UPTODATE          (1 << 18)
+#define CE_ADDED             (1 << 19)
 
-#define CE_HASHED    (0x100000)
-#define CE_UNHASHED  (0x200000)
-#define CE_CONFLICTED (0x800000)
+#define CE_HASHED            (1 << 20)
+#define CE_UNHASHED          (1 << 21)
+#define CE_WT_REMOVE         (1 << 22) /* remove in work directory */
+#define CE_CONFLICTED        (1 << 23)
 
-#define CE_WT_REMOVE (0x400000) /* remove in work directory */
-
-#define CE_UNPACKED  (0x1000000)
+#define CE_UNPACKED          (1 << 24)
+#define CE_NEW_SKIP_WORKTREE (1 << 25)
 
 /*
  * Extended on-disk flags
  */
-#define CE_INTENT_TO_ADD 0x20000000
-#define CE_SKIP_WORKTREE 0x40000000
+#define CE_INTENT_TO_ADD     (1 << 29)
+#define CE_SKIP_WORKTREE     (1 << 30)
 /* CE_EXTENDED2 is for future extension */
-#define CE_EXTENDED2 0x80000000
+#define CE_EXTENDED2         (1 << 31)
 
 #define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD | CE_SKIP_WORKTREE)
 
@@ -428,7 +428,7 @@ extern const char **get_pathspec(const char *prefix, const char **pathspec);
 extern void setup_work_tree(void);
 extern const char *setup_git_directory_gently(int *);
 extern const char *setup_git_directory(void);
-extern const char *prefix_path(const char *prefix, int len, const char *path);
+extern char *prefix_path(const char *prefix, int len, const char *path);
 extern const char *prefix_filename(const char *prefix, int len, const char *path);
 extern int check_filename(const char *prefix, const char *name);
 extern void verify_filename(const char *prefix, const char *name);
@@ -500,7 +500,22 @@ 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);
+struct pathspec {
+       const char **raw; /* get_pathspec() result, not freed by free_pathspec() */
+       int nr;
+       int has_wildcard:1;
+       int recursive:1;
+       int max_depth;
+       struct pathspec_item {
+               const char *match;
+               int len;
+               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);
 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 +526,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;
@@ -676,9 +691,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);
 
@@ -987,6 +1004,7 @@ extern int git_config_parse_parameter(const char *text);
 extern int git_config_parse_environment(void);
 extern int git_config_from_parameters(config_fn_t fn, void *data);
 extern int git_config(config_fn_t fn, void *);
+extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
 extern int git_parse_ulong(const char *, unsigned long *);
 extern int git_config_int(const char *, const char *);
 extern unsigned long git_config_ulong(const char *, const char *);
@@ -1066,6 +1084,7 @@ __attribute__((format (printf, 1, 2)))
 extern void trace_printf(const char *format, ...);
 __attribute__((format (printf, 2, 3)))
 extern void trace_argv_printf(const char **argv, const char *format, ...);
+extern void trace_repo_setup(const char *prefix);
 
 /* convert.c */
 /* returns 1 if *dst was used */
diff --git a/color.c b/color.c
index 1b00554dd50d2960b4e66f229b0d2d0da8eb8c28..6a5a54ec668e08ddef0d2f27359f3ebb3272243b 100644 (file)
--- a/color.c
+++ b/color.c
@@ -211,3 +211,8 @@ int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
        va_end(args);
        return r;
 }
+
+int color_is_nil(const char *c)
+{
+       return !strcmp(c, "NIL");
+}
diff --git a/color.h b/color.h
index 03ca0647485e8044d4131f2c61c37b4e9408cd2a..170ff4074d220e7e62264c4c63d1419f4a59d664 100644 (file)
--- a/color.h
+++ b/color.h
@@ -43,6 +43,9 @@
 #define GIT_COLOR_BG_MAGENTA   "\033[45m"
 #define GIT_COLOR_BG_CYAN      "\033[46m"
 
+/* A special value meaning "no color selected" */
+#define GIT_COLOR_NIL "NIL"
+
 /*
  * This variable stores the value of color.ui
  */
@@ -62,4 +65,6 @@ 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, ...);
 
+int color_is_nil(const char *color);
+
 #endif /* COLOR_H */
index b21335ee4c775d82901fb6b7dc785d63244f2bdd..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;
@@ -374,7 +374,7 @@ void free_commit_list(struct commit_list *list)
        }
 }
 
-struct commit_list * insert_by_date(struct commit *item, struct commit_list **list)
+struct commit_list * commit_list_insert_by_date(struct commit *item, struct commit_list **list)
 {
        struct commit_list **pp = list;
        struct commit_list *p;
@@ -388,11 +388,11 @@ struct commit_list * insert_by_date(struct commit *item, struct commit_list **li
 }
 
 
-void sort_by_date(struct commit_list **list)
+void commit_list_sort_by_date(struct commit_list **list)
 {
        struct commit_list *ret = NULL;
        while (*list) {
-               insert_by_date((*list)->item, &ret);
+               commit_list_insert_by_date((*list)->item, &ret);
                *list = (*list)->next;
        }
        *list = ret;
@@ -412,7 +412,7 @@ struct commit *pop_most_recent_commit(struct commit_list **list,
                struct commit *commit = parents->item;
                if (!parse_commit(commit) && !(commit->object.flags & mark)) {
                        commit->object.flags |= mark;
-                       insert_by_date(commit, list);
+                       commit_list_insert_by_date(commit, list);
                }
                parents = parents->next;
        }
@@ -501,7 +501,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
 
        /* process the list in topological order */
        if (!lifo)
-               sort_by_date(&work);
+               commit_list_sort_by_date(&work);
 
        pptr = list;
        *list = NULL;
@@ -527,7 +527,7 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
                         */
                        if (--parent->indegree == 1) {
                                if (!lifo)
-                                       insert_by_date(parent, &work);
+                                       commit_list_insert_by_date(parent, &work);
                                else
                                        commit_list_insert(parent, &work);
                        }
@@ -587,10 +587,10 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
        }
 
        one->object.flags |= PARENT1;
-       insert_by_date(one, &list);
+       commit_list_insert_by_date(one, &list);
        for (i = 0; i < n; i++) {
                twos[i]->object.flags |= PARENT2;
-               insert_by_date(twos[i], &list);
+               commit_list_insert_by_date(twos[i], &list);
        }
 
        while (interesting(list)) {
@@ -608,7 +608,7 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
                if (flags == (PARENT1 | PARENT2)) {
                        if (!(commit->object.flags & RESULT)) {
                                commit->object.flags |= RESULT;
-                               insert_by_date(commit, &result);
+                               commit_list_insert_by_date(commit, &result);
                        }
                        /* Mark parents of a found merge stale */
                        flags |= STALE;
@@ -622,7 +622,7 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
                        if (parse_commit(p))
                                return NULL;
                        p->object.flags |= flags;
-                       insert_by_date(p, &list);
+                       commit_list_insert_by_date(p, &list);
                }
        }
 
@@ -632,7 +632,7 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
        while (list) {
                struct commit_list *next = list->next;
                if (!(list->item->object.flags & STALE))
-                       insert_by_date(list->item, &result);
+                       commit_list_insert_by_date(list->item, &result);
                free(list);
                list = next;
        }
@@ -725,7 +725,7 @@ struct commit_list *get_merge_bases_many(struct commit *one,
        result = NULL;
        for (i = 0; i < cnt; i++) {
                if (rslt[i])
-                       insert_by_date(rslt[i], &result);
+                       commit_list_insert_by_date(rslt[i], &result);
        }
        free(rslt);
        return result;
index 3bfb31b5e0faad6ea04fde9e2f932f54d2e6c235..659c87c3ee90c23064f617e3bcf3ace12e32ea04 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -38,21 +38,21 @@ 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. */
 int find_commit_subject(const char *commit_buffer, const char **subject);
 
-struct commit_list * commit_list_insert(struct commit *item, struct commit_list **list_p);
+struct commit_list *commit_list_insert(struct commit *item,
+                                       struct commit_list **list);
 unsigned commit_list_count(const struct commit_list *l);
-struct commit_list * insert_by_date(struct commit *item, struct commit_list **list);
+struct commit_list *commit_list_insert_by_date(struct commit *item,
+                                   struct commit_list **list);
+void commit_list_sort_by_date(struct commit_list **list);
 
 void free_commit_list(struct commit_list *list);
 
-void sort_by_date(struct commit_list **list);
-
 /* Commit formats */
 enum cmit_fmt {
        CMIT_FMT_RAW,
index 8b159c44476efd7c7830d87cc5a5ec3dea6818c0..fe6ba340437b67237afd8cfdb4cf2a20074d27f7 100644 (file)
@@ -14,12 +14,6 @@ typedef int socklen_t;
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
 #define S_ISSOCK(x) 0
 
-#ifndef _STAT_H_
-#define S_IRUSR 0
-#define S_IWUSR 0
-#define S_IXUSR 0
-#define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
-#endif
 #define S_IRGRP 0
 #define S_IWGRP 0
 #define S_IXGRP 0
index 2a4f276869c507c49c3f1d066fa648c6ea78890d..b14fcf94da405c6f3267437e59936d598168e00f 100644 (file)
@@ -45,6 +45,10 @@ typedef unsigned long long uintmax_t;
 
 typedef int64_t off64_t;
 
+#define INTMAX_MIN  _I64_MIN
+#define INTMAX_MAX  _I64_MAX
+#define UINTMAX_MAX _UI64_MAX
+
 #define STDOUT_FILENO 1
 #define STDERR_FILENO 2
 
index 7e74ebe59a5ea2e31a9100659805ada0f5d8e278..708a6c9bec5c04cd95861b77475e54445c0d24fc 100644 (file)
@@ -34,6 +34,9 @@
 
 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
 # define WIN32_NATIVE
+# if defined (_MSC_VER)
+#  define _WIN32_WINNT 0x0502
+# endif
 # include <winsock2.h>
 # include <windows.h>
 # include <io.h>
index 32c0b2c41e01a754060e73bbf20a7f0e9c43bb10..625e0518767712583f917762634c2fc852c4d2eb 100644 (file)
--- a/config.c
+++ b/config.c
@@ -429,13 +429,11 @@ static int git_config_maybe_bool_text(const char *name, const char *value)
 
 int git_config_maybe_bool(const char *name, const char *value)
 {
-       int v = git_config_maybe_bool_text(name, value);
+       long v = git_config_maybe_bool_text(name, value);
        if (0 <= v)
                return v;
-       if (!strcmp(value, "0"))
-               return 0;
-       if (!strcmp(value, "1"))
-               return 1;
+       if (git_parse_long(value, &v))
+               return !!v;
        return -1;
 }
 
@@ -854,10 +852,9 @@ int git_config_from_parameters(config_fn_t fn, void *data)
        return 0;
 }
 
-int git_config(config_fn_t fn, void *data)
+int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 {
        int ret = 0, found = 0;
-       char *repo_config = NULL;
        const char *home = NULL;
 
        /* Setting $GIT_CONFIG makes git read _only_ the given config file. */
@@ -879,12 +876,10 @@ int git_config(config_fn_t fn, void *data)
                free(user_config);
        }
 
-       repo_config = git_pathdup("config");
-       if (!access(repo_config, R_OK)) {
+       if (repo_config && !access(repo_config, R_OK)) {
                ret += git_config_from_file(fn, repo_config, data);
                found += 1;
        }
-       free(repo_config);
 
        ret += git_config_from_parameters(fn, data);
        if (config_parameters)
@@ -893,6 +888,18 @@ int git_config(config_fn_t fn, void *data)
        return ret == 0 ? found : ret;
 }
 
+int git_config(config_fn_t fn, void *data)
+{
+       char *repo_config = NULL;
+       int ret;
+
+       repo_config = git_pathdup("config");
+       ret = git_config_early(fn, data, repo_config);
+       if (repo_config)
+               free(repo_config);
+       return ret;
+}
+
 /*
  * Find all the stuff for git_config_set() below.
  */
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 604fa794cc4d2dd657f054f42e3001bee13b8202..893b7716cafa4811d237480a980140d308aa20dc 100755 (executable)
@@ -327,11 +327,168 @@ __gitcomp_1 ()
        done
 }
 
+# The following function is based on code from:
+#
+#   bash_completion - programmable completion functions for bash 3.2+
+#
+#   Copyright © 2006-2008, Ian Macdonald <ian@caliban.org>
+#             © 2009-2010, Bash Completion Maintainers
+#                     <bash-completion-devel@lists.alioth.debian.org>
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2, or (at your option)
+#   any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+#   The latest version of this software can be obtained here:
+#
+#   http://bash-completion.alioth.debian.org/
+#
+#   RELEASE: 2.x
+
+# This function can be used to access a tokenized list of words
+# on the command line:
+#
+#      __git_reassemble_comp_words_by_ref '=:'
+#      if test "${words_[cword_-1]}" = -w
+#      then
+#              ...
+#      fi
+#
+# The argument should be a collection of characters from the list of
+# word completion separators (COMP_WORDBREAKS) to treat as ordinary
+# characters.
+#
+# This is roughly equivalent to going back in time and setting
+# COMP_WORDBREAKS to exclude those characters.  The intent is to
+# make option types like --date=<type> and <rev>:<path> easy to
+# recognize by treating each shell word as a single token.
+#
+# It is best not to set COMP_WORDBREAKS directly because the value is
+# shared with other completion scripts.  By the time the completion
+# function gets called, COMP_WORDS has already been populated so local
+# changes to COMP_WORDBREAKS have no effect.
+#
+# Output: words_, cword_, cur_.
+
+__git_reassemble_comp_words_by_ref()
+{
+       local exclude i j first
+       # Which word separators to exclude?
+       exclude="${1//[^$COMP_WORDBREAKS]}"
+       cword_=$COMP_CWORD
+       if [ -z "$exclude" ]; then
+               words_=("${COMP_WORDS[@]}")
+               return
+       fi
+       # List of word completion separators has shrunk;
+       # re-assemble words to complete.
+       for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do
+               # Append each nonempty word consisting of just
+               # word separator characters to the current word.
+               first=t
+               while
+                       [ $i -gt 0 ] &&
+                       [ -n "${COMP_WORDS[$i]}" ] &&
+                       # word consists of excluded word separators
+                       [ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ]
+               do
+                       # Attach to the previous token,
+                       # unless the previous token is the command name.
+                       if [ $j -ge 2 ] && [ -n "$first" ]; then
+                               ((j--))
+                       fi
+                       first=
+                       words_[$j]=${words_[j]}${COMP_WORDS[i]}
+                       if [ $i = $COMP_CWORD ]; then
+                               cword_=$j
+                       fi
+                       if (($i < ${#COMP_WORDS[@]} - 1)); then
+                               ((i++))
+                       else
+                               # Done.
+                               return
+                       fi
+               done
+               words_[$j]=${words_[j]}${COMP_WORDS[i]}
+               if [ $i = $COMP_CWORD ]; then
+                       cword_=$j
+               fi
+       done
+}
+
+if ! type _get_comp_words_by_ref >/dev/null 2>&1; then
+if [[ -z ${ZSH_VERSION:+set} ]]; then
+_get_comp_words_by_ref ()
+{
+       local exclude cur_ words_ cword_
+       if [ "$1" = "-n" ]; then
+               exclude=$2
+               shift 2
+       fi
+       __git_reassemble_comp_words_by_ref "$exclude"
+       cur_=${words_[cword_]}
+       while [ $# -gt 0 ]; do
+               case "$1" in
+               cur)
+                       cur=$cur_
+                       ;;
+               prev)
+                       prev=${words_[$cword_-1]}
+                       ;;
+               words)
+                       words=("${words_[@]}")
+                       ;;
+               cword)
+                       cword=$cword_
+                       ;;
+               esac
+               shift
+       done
+}
+else
+_get_comp_words_by_ref ()
+{
+       while [ $# -gt 0 ]; do
+               case "$1" in
+               cur)
+                       cur=${COMP_WORDS[COMP_CWORD]}
+                       ;;
+               prev)
+                       prev=${COMP_WORDS[COMP_CWORD-1]}
+                       ;;
+               words)
+                       words=("${COMP_WORDS[@]}")
+                       ;;
+               cword)
+                       cword=$COMP_CWORD
+                       ;;
+               -n)
+                       # assume COMP_WORDBREAKS is already set sanely
+                       shift
+                       ;;
+               esac
+               shift
+       done
+}
+fi
+fi
+
 # __gitcomp accepts 1, 2, 3, or 4 arguments
 # generates completion reply with compgen
 __gitcomp ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        if [ $# -gt 2 ]; then
                cur="$3"
        fi
@@ -392,7 +549,8 @@ __git_tags ()
 __git_refs ()
 {
        local i is_hash=y dir="$(__gitdir "${1-}")" track="${2-}"
-       local cur="${COMP_WORDS[COMP_CWORD]}" format refs
+       local cur format refs
+       _get_comp_words_by_ref -n =: cur
        if [ -d "$dir" ]; then
                case "$cur" in
                refs|refs/*)
@@ -506,7 +664,8 @@ __git_compute_merge_strategies ()
 
 __git_complete_file ()
 {
-       local pfx ls ref cur="${COMP_WORDS[COMP_CWORD]}"
+       local pfx ls ref cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        ?*:*)
                ref="${cur%%:*}"
@@ -554,7 +713,8 @@ __git_complete_file ()
 
 __git_complete_revlist ()
 {
-       local pfx cur="${COMP_WORDS[COMP_CWORD]}"
+       local pfx cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        *...*)
                pfx="${cur%...*}..."
@@ -574,11 +734,12 @@ __git_complete_revlist ()
 
 __git_complete_remote_or_refspec ()
 {
-       local cmd="${COMP_WORDS[1]}"
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur words cword
+       _get_comp_words_by_ref -n =: cur words cword
+       local cmd="${words[1]}"
        local i c=2 remote="" pfx="" lhs=1 no_complete_refspec=0
-       while [ $c -lt $COMP_CWORD ]; do
-               i="${COMP_WORDS[c]}"
+       while [ $c -lt $cword ]; do
+               i="${words[c]}"
                case "$i" in
                --mirror) [ "$cmd" = "push" ] && no_complete_refspec=1 ;;
                --all)
@@ -646,13 +807,14 @@ __git_complete_remote_or_refspec ()
 
 __git_complete_strategy ()
 {
+       local cur prev
+       _get_comp_words_by_ref -n =: cur prev
        __git_compute_merge_strategies
-       case "${COMP_WORDS[COMP_CWORD-1]}" in
+       case "$prev" in
        -s|--strategy)
                __gitcomp "$__git_merge_strategies"
                return 0
        esac
-       local cur="${COMP_WORDS[COMP_CWORD]}"
        case "$cur" in
        --strategy=*)
                __gitcomp "$__git_merge_strategies" "" "${cur##--strategy=}"
@@ -735,7 +897,6 @@ __git_list_porcelain_commands ()
                quiltimport)      : import;;
                read-tree)        : plumbing;;
                receive-pack)     : plumbing;;
-               reflog)           : plumbing;;
                remote-*)         : transport;;
                repo-config)      : deprecated;;
                rerere)           : plumbing;;
@@ -825,10 +986,10 @@ __git_aliased_command ()
 # __git_find_on_cmdline requires 1 argument
 __git_find_on_cmdline ()
 {
-       local word subcommand c=1
-
-       while [ $c -lt $COMP_CWORD ]; do
-               word="${COMP_WORDS[c]}"
+       local word subcommand c=1 words cword
+       _get_comp_words_by_ref -n =: words cword
+       while [ $c -lt $cword ]; do
+               word="${words[c]}"
                for subcommand in $1; do
                        if [ "$subcommand" = "$word" ]; then
                                echo "$subcommand"
@@ -841,9 +1002,10 @@ __git_find_on_cmdline ()
 
 __git_has_doubledash ()
 {
-       local c=1
-       while [ $c -lt $COMP_CWORD ]; do
-               if [ "--" = "${COMP_WORDS[c]}" ]; then
+       local c=1 words cword
+       _get_comp_words_by_ref -n =: words cword
+       while [ $c -lt $cword ]; do
+               if [ "--" = "${words[c]}" ]; then
                        return 0
                fi
                c=$((++c))
@@ -855,7 +1017,8 @@ __git_whitespacelist="nowarn warn error error-all fix"
 
 _git_am ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)"
+       local cur dir="$(__gitdir)"
+       _get_comp_words_by_ref -n =: cur
        if [ -d "$dir"/rebase-apply ]; then
                __gitcomp "--skip --continue --resolved --abort"
                return
@@ -879,7 +1042,8 @@ _git_am ()
 
 _git_apply ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --whitespace=*)
                __gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}"
@@ -902,7 +1066,8 @@ _git_add ()
 {
        __git_has_doubledash && return
 
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "
@@ -916,7 +1081,8 @@ _git_add ()
 
 _git_archive ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --format=*)
                __gitcomp "$(git archive --list)" "" "${cur##--format=}"
@@ -964,10 +1130,11 @@ _git_bisect ()
 
 _git_branch ()
 {
-       local i c=1 only_local_ref="n" has_r="n"
+       local i c=1 only_local_ref="n" has_r="n" cur words cword
 
-       while [ $c -lt $COMP_CWORD ]; do
-               i="${COMP_WORDS[c]}"
+       _get_comp_words_by_ref -n =: cur words cword
+       while [ $c -lt $cword ]; do
+               i="${words[c]}"
                case "$i" in
                -d|-m)  only_local_ref="y" ;;
                -r)     has_r="y" ;;
@@ -975,7 +1142,7 @@ _git_branch ()
                c=$((++c))
        done
 
-       case "${COMP_WORDS[COMP_CWORD]}" in
+       case "$cur" in
        --*)
                __gitcomp "
                        --color --no-color --verbose --abbrev= --no-abbrev
@@ -995,8 +1162,10 @@ _git_branch ()
 
 _git_bundle ()
 {
-       local cmd="${COMP_WORDS[2]}"
-       case "$COMP_CWORD" in
+       local words cword
+       _get_comp_words_by_ref -n =: words cword
+       local cmd="${words[2]}"
+       case "$cword" in
        2)
                __gitcomp "create list-heads verify unbundle"
                ;;
@@ -1017,7 +1186,8 @@ _git_checkout ()
 {
        __git_has_doubledash && return
 
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --conflict=*)
                __gitcomp "diff3 merge" "" "${cur##--conflict=}"
@@ -1047,7 +1217,8 @@ _git_cherry ()
 
 _git_cherry_pick ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--edit --no-commit"
@@ -1062,7 +1233,8 @@ _git_clean ()
 {
        __git_has_doubledash && return
 
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--dry-run --quiet"
@@ -1074,7 +1246,8 @@ _git_clean ()
 
 _git_clone ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "
@@ -1101,7 +1274,8 @@ _git_commit ()
 {
        __git_has_doubledash && return
 
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --cleanup=*)
                __gitcomp "default strip verbatim whitespace
@@ -1136,7 +1310,8 @@ _git_commit ()
 
 _git_describe ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "
@@ -1168,7 +1343,8 @@ _git_diff ()
 {
        __git_has_doubledash && return
 
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
@@ -1189,7 +1365,8 @@ _git_difftool ()
 {
        __git_has_doubledash && return
 
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --tool=*)
                __gitcomp "$__git_mergetools_common kompare" "" "${cur##--tool=}"
@@ -1214,7 +1391,8 @@ __git_fetch_options="
 
 _git_fetch ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "$__git_fetch_options"
@@ -1226,7 +1404,8 @@ _git_fetch ()
 
 _git_format_patch ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --thread=*)
                __gitcomp "
@@ -1258,7 +1437,8 @@ _git_format_patch ()
 
 _git_fsck ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "
@@ -1273,7 +1453,8 @@ _git_fsck ()
 
 _git_gc ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--prune --aggressive"
@@ -1292,7 +1473,8 @@ _git_grep ()
 {
        __git_has_doubledash && return
 
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "
@@ -1315,7 +1497,8 @@ _git_grep ()
 
 _git_help ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--all --info --man --web"
@@ -1333,7 +1516,8 @@ _git_help ()
 
 _git_init ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --shared=*)
                __gitcomp "
@@ -1353,7 +1537,8 @@ _git_ls_files ()
 {
        __git_has_doubledash && return
 
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--cached --deleted --modified --others --ignored
@@ -1407,12 +1592,13 @@ _git_log ()
 {
        __git_has_doubledash && return
 
-       local cur="${COMP_WORDS[COMP_CWORD]}"
        local g="$(git rev-parse --git-dir 2>/dev/null)"
        local merge=""
        if [ -f "$g/MERGE_HEAD" ]; then
                merge="--merge"
        fi
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --pretty=*)
                __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
@@ -1466,7 +1652,8 @@ _git_merge ()
 {
        __git_complete_strategy && return
 
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "$__git_merge_options"
@@ -1477,7 +1664,8 @@ _git_merge ()
 
 _git_mergetool ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --tool=*)
                __gitcomp "$__git_mergetools_common tortoisemerge" "" "${cur##--tool=}"
@@ -1498,7 +1686,8 @@ _git_merge_base ()
 
 _git_mv ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--dry-run"
@@ -1517,14 +1706,15 @@ _git_notes ()
 {
        local subcommands='add append copy edit list prune remove show'
        local subcommand="$(__git_find_on_cmdline "$subcommands")"
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur words cword
+       _get_comp_words_by_ref -n =: cur words cword
 
        case "$subcommand,$cur" in
        ,--*)
                __gitcomp '--ref'
                ;;
        ,*)
-               case "${COMP_WORDS[COMP_CWORD-1]}" in
+               case "${words[cword-1]}" in
                --ref)
                        __gitcomp "$(__git_refs)"
                        ;;
@@ -1552,7 +1742,7 @@ _git_notes ()
        prune,*)
                ;;
        *)
-               case "${COMP_WORDS[COMP_CWORD-1]}" in
+               case "${words[cword-1]}" in
                -m|-F)
                        ;;
                *)
@@ -1567,7 +1757,8 @@ _git_pull ()
 {
        __git_complete_strategy && return
 
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "
@@ -1583,8 +1774,9 @@ _git_pull ()
 
 _git_push ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
-       case "${COMP_WORDS[COMP_CWORD-1]}" in
+       local cur prev
+       _get_comp_words_by_ref -n =: cur prev
+       case "$prev" in
        --repo)
                __gitcomp "$(__git_remotes)"
                return
@@ -1607,7 +1799,9 @@ _git_push ()
 
 _git_rebase ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)"
+       local dir="$(__gitdir)"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        if [ -d "$dir"/rebase-apply ] || [ -d "$dir"/rebase-merge ]; then
                __gitcomp "--continue --skip --abort"
                return
@@ -1632,12 +1826,25 @@ _git_rebase ()
        __gitcomp "$(__git_refs)"
 }
 
+_git_reflog ()
+{
+       local subcommands="show delete expire"
+       local subcommand="$(__git_find_on_cmdline "$subcommands")"
+
+       if [ -z "$subcommand" ]; then
+               __gitcomp "$subcommands"
+       else
+               __gitcomp "$(__git_refs)"
+       fi
+}
+
 __git_send_email_confirm_options="always never auto cc compose"
 __git_send_email_suppresscc_options="author self cc bodycc sob cccmd body all"
 
 _git_send_email ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --confirm=*)
                __gitcomp "
@@ -1679,9 +1886,11 @@ _git_stage ()
 
 __git_config_get_set_variables ()
 {
-       local prevword word config_file= c=$COMP_CWORD
+       local words cword
+       _get_comp_words_by_ref -n =: words cword
+       local prevword word config_file= c=$cword
        while [ $c -gt 1 ]; do
-               word="${COMP_WORDS[c]}"
+               word="${words[c]}"
                case "$word" in
                --global|--system|--file=*)
                        config_file="$word"
@@ -1709,9 +1918,9 @@ __git_config_get_set_variables ()
 
 _git_config ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
-       local prv="${COMP_WORDS[COMP_CWORD-1]}"
-       case "$prv" in
+       local cur prev
+       _get_comp_words_by_ref -n =: cur prev
+       case "$prev" in
        branch.*.remote)
                __gitcomp "$(__git_remotes)"
                return
@@ -1721,13 +1930,13 @@ _git_config ()
                return
                ;;
        remote.*.fetch)
-               local remote="${prv#remote.}"
+               local remote="${prev#remote.}"
                remote="${remote%.fetch}"
                __gitcomp "$(__git_refs_remotes "$remote")"
                return
                ;;
        remote.*.push)
-               local remote="${prv#remote.}"
+               local remote="${prev#remote.}"
                remote="${remote%.push}"
                __gitcomp "$(git --git-dir="$(__gitdir)" \
                        for-each-ref --format='%(refname):%(refname)' \
@@ -1864,30 +2073,50 @@ _git_config ()
                ;;
        esac
        __gitcomp "
-               add.ignore-errors
+               add.ignoreErrors
+               advice.commitBeforeMerge
+               advice.detachedHead
+               advice.implicitIdentity
+               advice.pushNonFastForward
+               advice.resolveConflict
+               advice.statusHints
                alias.
+               am.keepcr
                apply.ignorewhitespace
                apply.whitespace
                branch.autosetupmerge
                branch.autosetuprebase
+               browser.
                clean.requireForce
                color.branch
                color.branch.current
                color.branch.local
                color.branch.plain
                color.branch.remote
+               color.decorate.HEAD
+               color.decorate.branch
+               color.decorate.remoteBranch
+               color.decorate.stash
+               color.decorate.tag
                color.diff
                color.diff.commit
                color.diff.frag
+               color.diff.func
                color.diff.meta
                color.diff.new
                color.diff.old
                color.diff.plain
                color.diff.whitespace
                color.grep
-               color.grep.external
+               color.grep.context
+               color.grep.filename
+               color.grep.function
+               color.grep.linenumber
                color.grep.match
+               color.grep.selected
+               color.grep.separator
                color.interactive
+               color.interactive.error
                color.interactive.header
                color.interactive.help
                color.interactive.prompt
@@ -1901,21 +2130,29 @@ _git_config ()
                color.status.untracked
                color.status.updated
                color.ui
+               commit.status
                commit.template
+               core.abbrevguard
+               core.askpass
+               core.attributesfile
                core.autocrlf
                core.bare
+               core.bigFileThreshold
                core.compression
                core.createObject
                core.deltaBaseCacheLimit
                core.editor
+               core.eol
                core.excludesfile
                core.fileMode
                core.fsyncobjectfiles
                core.gitProxy
                core.ignoreCygwinFSTricks
                core.ignoreStat
+               core.ignorecase
                core.logAllRefUpdates
                core.loosecompression
+               core.notesRef
                core.packedGitLimit
                core.packedGitWindowSize
                core.pager
@@ -1925,6 +2162,7 @@ _git_config ()
                core.repositoryFormatVersion
                core.safecrlf
                core.sharedRepository
+               core.sparseCheckout
                core.symlinks
                core.trustctime
                core.warnAmbiguousRefs
@@ -1932,15 +2170,17 @@ _git_config ()
                core.worktree
                diff.autorefreshindex
                diff.external
+               diff.ignoreSubmodules
                diff.mnemonicprefix
+               diff.noprefix
                diff.renameLimit
-               diff.renameLimit.
                diff.renames
                diff.suppressBlankEmpty
                diff.tool
                diff.wordRegex
                difftool.
                difftool.prompt
+               fetch.recurseSubmodules
                fetch.unpackLimit
                format.attach
                format.cc
@@ -1952,6 +2192,8 @@ _git_config ()
                format.subjectprefix
                format.suffix
                format.thread
+               format.to
+               gc.
                gc.aggressiveWindow
                gc.auto
                gc.autopacklimit
@@ -1989,15 +2231,20 @@ _git_config ()
                http.lowSpeedLimit
                http.lowSpeedTime
                http.maxRequests
+               http.minSessions
                http.noEPSV
+               http.postBuffer
                http.proxy
                http.sslCAInfo
                http.sslCAPath
                http.sslCert
+               http.sslCertPasswordProtected
                http.sslKey
                http.sslVerify
+               http.useragent
                i18n.commitEncoding
                i18n.logOutputEncoding
+               imap.authMethod
                imap.folder
                imap.host
                imap.pass
@@ -2006,6 +2253,7 @@ _git_config ()
                imap.sslverify
                imap.tunnel
                imap.user
+               init.templatedir
                instaweb.browser
                instaweb.httpd
                instaweb.local
@@ -2013,19 +2261,29 @@ _git_config ()
                instaweb.port
                interactive.singlekey
                log.date
+               log.decorate
                log.showroot
                mailmap.file
                man.
                man.viewer
+               merge.
                merge.conflictstyle
                merge.log
                merge.renameLimit
+               merge.renormalize
                merge.stat
                merge.tool
                merge.verbosity
                mergetool.
                mergetool.keepBackup
+               mergetool.keepTemporaries
                mergetool.prompt
+               notes.displayRef
+               notes.rewrite.
+               notes.rewrite.amend
+               notes.rewrite.rebase
+               notes.rewriteMode
+               notes.rewriteRef
                pack.compression
                pack.deltaCacheLimit
                pack.deltaCacheSize
@@ -2036,31 +2294,42 @@ _git_config ()
                pack.window
                pack.windowMemory
                pager.
+               pretty.
                pull.octopus
                pull.twohead
                push.default
+               rebase.autosquash
                rebase.stat
+               receive.autogc
                receive.denyCurrentBranch
+               receive.denyDeleteCurrent
                receive.denyDeletes
                receive.denyNonFastForwards
                receive.fsckObjects
                receive.unpackLimit
+               receive.updateserverinfo
+               remotes.
                repack.usedeltabaseoffset
                rerere.autoupdate
                rerere.enabled
+               sendemail.
                sendemail.aliasesfile
-               sendemail.aliasesfiletype
+               sendemail.aliasfiletype
                sendemail.bcc
                sendemail.cc
                sendemail.cccmd
                sendemail.chainreplyto
                sendemail.confirm
                sendemail.envelopesender
+               sendemail.from
+               sendemail.identity
                sendemail.multiedit
                sendemail.signedoffbycc
+               sendemail.smtpdomain
                sendemail.smtpencryption
                sendemail.smtppass
                sendemail.smtpserver
+               sendemail.smtpserveroption
                sendemail.smtpserverport
                sendemail.smtpuser
                sendemail.suppresscc
@@ -2071,6 +2340,8 @@ _git_config ()
                showbranch.default
                status.relativePaths
                status.showUntrackedFiles
+               status.submodulesummary
+               submodule.
                tar.umask
                transfer.unpackLimit
                url.
@@ -2118,7 +2389,8 @@ _git_reset ()
 {
        __git_has_doubledash && return
 
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--merge --mixed --hard --soft --patch"
@@ -2130,7 +2402,8 @@ _git_reset ()
 
 _git_revert ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--edit --mainline --no-edit --no-commit --signoff"
@@ -2144,7 +2417,8 @@ _git_rm ()
 {
        __git_has_doubledash && return
 
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "--cached --dry-run --ignore-unmatch --quiet"
@@ -2158,7 +2432,8 @@ _git_shortlog ()
 {
        __git_has_doubledash && return
 
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "
@@ -2176,7 +2451,8 @@ _git_show ()
 {
        __git_has_doubledash && return
 
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --pretty=*)
                __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
@@ -2200,7 +2476,8 @@ _git_show ()
 
 _git_show_branch ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "
@@ -2217,7 +2494,8 @@ _git_show_branch ()
 
 _git_stash ()
 {
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
+       _get_comp_words_by_ref -n =: cur
        local save_opts='--keep-index --no-keep-index --quiet --patch'
        local subcommands='save list show apply clear drop pop create branch'
        local subcommand="$(__git_find_on_cmdline "$subcommands")"
@@ -2262,7 +2540,8 @@ _git_submodule ()
 
        local subcommands="add status init update summary foreach sync"
        if [ -z "$(__git_find_on_cmdline "$subcommands")" ]; then
-               local cur="${COMP_WORDS[COMP_CWORD]}"
+               local cur
+               _get_comp_words_by_ref -n =: cur
                case "$cur" in
                --*)
                        __gitcomp "--quiet --cached"
@@ -2306,7 +2585,8 @@ _git_svn ()
                        --edit --rmdir --find-copies-harder --copy-similarity=
                        "
 
-               local cur="${COMP_WORDS[COMP_CWORD]}"
+               local cur
+               _get_comp_words_by_ref -n =: cur
                case "$subcommand,$cur" in
                fetch,--*)
                        __gitcomp "--revision= --fetch-all $fc_opts"
@@ -2378,8 +2658,10 @@ _git_svn ()
 _git_tag ()
 {
        local i c=1 f=0
-       while [ $c -lt $COMP_CWORD ]; do
-               i="${COMP_WORDS[c]}"
+       local words cword prev
+       _get_comp_words_by_ref -n =: words cword prev
+       while [ $c -lt $cword ]; do
+               i="${words[c]}"
                case "$i" in
                -d|-v)
                        __gitcomp "$(__git_tags)"
@@ -2392,7 +2674,7 @@ _git_tag ()
                c=$((++c))
        done
 
-       case "${COMP_WORDS[COMP_CWORD-1]}" in
+       case "$prev" in
        -m|-F)
                COMPREPLY=()
                ;;
@@ -2423,8 +2705,10 @@ _git ()
                setopt KSH_TYPESET
        fi
 
-       while [ $c -lt $COMP_CWORD ]; do
-               i="${COMP_WORDS[c]}"
+       local cur words cword
+       _get_comp_words_by_ref -n =: cur words cword
+       while [ $c -lt $cword ]; do
+               i="${words[c]}"
                case "$i" in
                --git-dir=*) __git_dir="${i#--git-dir=}" ;;
                --bare)      __git_dir="." ;;
@@ -2436,7 +2720,7 @@ _git ()
        done
 
        if [ -z "$command" ]; then
-               case "${COMP_WORDS[COMP_CWORD]}" in
+               case "$cur" in
                --*)   __gitcomp "
                        --paginate
                        --no-pager
@@ -2474,12 +2758,13 @@ _gitk ()
 
        __git_has_doubledash && return
 
-       local cur="${COMP_WORDS[COMP_CWORD]}"
+       local cur
        local g="$(__gitdir)"
        local merge=""
        if [ -f "$g/MERGE_HEAD" ]; then
                merge="--merge"
        fi
+       _get_comp_words_by_ref -n =: cur
        case "$cur" in
        --*)
                __gitcomp "
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..a92beb6292b49aebb12bfbb4535a94f148b88a3d 100755 (executable)
@@ -910,6 +910,22 @@ 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])]
 
@@ -1032,7 +1048,7 @@ 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
 
@@ -1475,19 +1491,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 = []
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 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 01de9a84c21b31a0120065a32a386f27321cdf7b..d5aebed48df3387e966a23b6ee460dc2244f728e 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "attr.h"
 #include "run-command.h"
+#include "quote.h"
 
 /*
  * convert.c - convert a file when checking it out and checking it in.
@@ -318,6 +319,7 @@ struct filter_params {
        const char *src;
        unsigned long size;
        const char *cmd;
+       const char *path;
 };
 
 static int filter_buffer(int in, int out, void *data)
@@ -330,7 +332,23 @@ static int filter_buffer(int in, int out, void *data)
        int write_err, status;
        const char *argv[] = { NULL, NULL };
 
-       argv[0] = params->cmd;
+       /* apply % substitution to cmd */
+       struct strbuf cmd = STRBUF_INIT;
+       struct strbuf path = STRBUF_INIT;
+       struct strbuf_expand_dict_entry dict[] = {
+               { "f", NULL, },
+               { NULL, NULL, },
+       };
+
+       /* quote the path to preserve spaces, etc. */
+       sq_quote_buf(&path, params->path);
+       dict[0].value = path.buf;
+
+       /* expand all %f with the quoted path */
+       strbuf_expand(&cmd, params->cmd, strbuf_expand_dict_cb, &dict);
+       strbuf_release(&path);
+
+       argv[0] = cmd.buf;
 
        memset(&child_process, 0, sizeof(child_process));
        child_process.argv = argv;
@@ -350,6 +368,8 @@ static int filter_buffer(int in, int out, void *data)
        status = finish_command(&child_process);
        if (status)
                error("external filter %s failed %d", params->cmd, status);
+
+       strbuf_release(&cmd);
        return (write_err || status);
 }
 
@@ -377,6 +397,7 @@ static int apply_filter(const char *path, const char *src, size_t len,
        params.src = src;
        params.size = len;
        params.cmd = cmd;
+       params.path = path;
 
        fflush(NULL);
        if (start_async(&async))
index d2a4e023e895d57db798be76450b77afb2ac49be..347fd0c52b4cd797f5dafffb6885324f7c7f0274 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -1226,9 +1226,10 @@ int main(int argc, char **argv)
 
        /* prepare argv for serving-processes */
        cld_argv = xmalloc(sizeof (char *) * (argc + 2));
-       for (i = 0; i < argc; ++i)
-               cld_argv[i] = argv[i];
-       cld_argv[argc] = "--serve";
+       cld_argv[0] = argv[0];  /* git-daemon */
+       cld_argv[1] = "--serve";
+       for (i = 1; i < argc; ++i)
+               cld_argv[i+1] = argv[i];
        cld_argv[argc+1] = NULL;
 
        return serve(&listen_addr, listen_port, cred);
index 392ce2bef05746cea7922d39da67bf25d1d3d192..1e22992cb10420b9dd6def16f80efc5f196ffbbb 100644 (file)
@@ -106,7 +106,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
                        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 +427,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 +501,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 6991ed4e17343a3104d3fd518b5d85d0913e9259..5422c438826254f36d1e00af0e8b882690661276 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -3154,14 +3154,14 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                if ((options->break_opt = diff_scoreopt_parse(arg)) == -1)
                        return error("invalid argument to -B: %s", arg+2);
        }
-       else if (!prefixcmp(arg, "-M") || !prefixcmp(arg, "--detect-renames=") ||
-                !strcmp(arg, "--detect-renames")) {
+       else if (!prefixcmp(arg, "-M") || !prefixcmp(arg, "--find-renames=") ||
+                !strcmp(arg, "--find-renames")) {
                if ((options->rename_score = diff_scoreopt_parse(arg)) == -1)
                        return error("invalid argument to -M: %s", arg+2);
                options->detect_rename = DIFF_DETECT_RENAME;
        }
-       else if (!prefixcmp(arg, "-C") || !prefixcmp(arg, "--detect-copies=") ||
-                !strcmp(arg, "--detect-copies")) {
+       else if (!prefixcmp(arg, "-C") || !prefixcmp(arg, "--find-copies=") ||
+                !strcmp(arg, "--find-copies")) {
                if (options->detect_rename == DIFF_DETECT_COPY)
                        DIFF_OPT_SET(options, FIND_COPIES_HARDER);
                if ((options->rename_score = diff_scoreopt_parse(arg)) == -1)
@@ -3384,12 +3384,12 @@ static int diff_scoreopt_parse(const char *opt)
                        opt += strlen("break-rewrites");
                        if (*opt == 0 || *opt++ == '=')
                                cmd = 'B';
-               } else if (!prefixcmp(opt, "detect-copies")) {
-                       opt += strlen("detect-copies");
+               } else if (!prefixcmp(opt, "find-copies")) {
+                       opt += strlen("find-copies");
                        if (*opt == 0 || *opt++ == '=')
                                cmd = 'C';
-               } else if (!prefixcmp(opt, "detect-renames")) {
-                       opt += strlen("detect-renames");
+               } else if (!prefixcmp(opt, "find-renames")) {
+                       opt += strlen("find-renames");
                        if (*opt == 0 || *opt++ == '=')
                                cmd = 'M';
                }
@@ -4412,7 +4412,7 @@ size_t fill_textconv(struct userdiff_driver *driver,
                return df->size;
        }
 
-       if (driver->textconv_cache) {
+       if (driver->textconv_cache && df->sha1_valid) {
                *outbuf = notes_cache_get(driver->textconv_cache, df->sha1,
                                          &size);
                if (*outbuf)
@@ -4423,7 +4423,7 @@ size_t fill_textconv(struct userdiff_driver *driver,
        if (!*outbuf)
                die("unable to read files to diff");
 
-       if (driver->textconv_cache) {
+       if (driver->textconv_cache && df->sha1_valid) {
                /* ignore errors, as we might be in a readonly repository */
                notes_cache_put(driver->textconv_cache, df->sha1, *outbuf,
                                size);
diff --git a/diff.h b/diff.h
index 0083d92438916a8188656df140ba70d6acc8c6f6..310bd6b2832ce7f874aff735bb19b4813f117d4d 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -133,9 +133,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;
diff --git a/dir.c b/dir.c
index 852e60f2a8d4784bf73d044f89fe822538121286..168dad615230d77d7719101b76b50b4f6fe02777 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';
@@ -253,6 +357,18 @@ static void *read_skip_worktree_file_from_index(const char *path, size_t *size)
        return data;
 }
 
+void free_excludes(struct exclude_list *el)
+{
+       int i;
+
+       for (i = 0; i < el->nr; i++)
+               free(el->excludes[i]);
+       free(el->excludes);
+
+       el->nr = 0;
+       el->excludes = NULL;
+}
+
 int add_excludes_from_file_to_list(const char *fname,
                                   const char *base,
                                   int baselen,
@@ -389,13 +505,6 @@ int excluded_from_list(const char *pathname,
                        int to_exclude = x->to_exclude;
 
                        if (x->flags & EXC_FLAG_MUSTBEDIR) {
-                               if (!dtype) {
-                                       if (!prefixcmp(pathname, exclude) &&
-                                           pathname[x->patternlen] == '/')
-                                               return to_exclude;
-                                       else
-                                               continue;
-                               }
                                if (*dtype == DT_UNKNOWN)
                                        *dtype = get_dtype(NULL, pathname, pathlen);
                                if (*dtype != DT_DIR)
@@ -1033,6 +1142,12 @@ char *get_relative_cwd(char *buffer, int size, const char *dir)
        case '/':
                return cwd + 1;
        default:
+               /*
+                * dir can end with a path separator when it's root
+                * directory. Return proper prefix in that case.
+                */
+               if (dir[-1] == '/')
+                       return cwd;
                return NULL;
        }
 }
@@ -1140,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 b3e2104b9f231fbed88f98df12ad48d0d9992130..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);
@@ -78,6 +82,7 @@ extern int add_excludes_from_file_to_list(const char *fname, const char *base, i
 extern void add_excludes_from_file(struct dir_struct *, const char *fname);
 extern void add_exclude(const char *string, const char *base,
                        int baselen, struct exclude_list *which);
+extern void free_excludes(struct exclude_list *el);
 extern int file_exists(const char *);
 
 extern char *get_relative_cwd(char *buffer, int size, const char *dir);
index c79f2a9b561de77e27abd7ee26831e2a58beb259..9564475f429312a467a020106f7443112367d5da 100644 (file)
@@ -139,30 +139,20 @@ static int git_work_tree_initialized;
  */
 void set_git_work_tree(const char *new_work_tree)
 {
-       if (is_bare_repository_cfg >= 0)
-               die("cannot set work tree after initialization");
+       if (git_work_tree_initialized) {
+               new_work_tree = make_absolute_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",
+                           work_tree, new_work_tree);
+               return;
+       }
        git_work_tree_initialized = 1;
-       free(work_tree);
        work_tree = xstrdup(make_absolute_path(new_work_tree));
-       is_bare_repository_cfg = 0;
 }
 
 const char *get_git_work_tree(void)
 {
-       if (!git_work_tree_initialized) {
-               work_tree = getenv(GIT_WORK_TREE_ENVIRONMENT);
-               /* core.bare = true overrides implicit and config work tree */
-               if (!work_tree && is_bare_repository_cfg < 1) {
-                       work_tree = git_work_tree_cfg;
-                       /* make_absolute_path also normalizes the path */
-                       if (work_tree && !is_absolute_path(work_tree))
-                               work_tree = xstrdup(make_absolute_path(git_path("%s", work_tree)));
-               } else if (work_tree)
-                       work_tree = xstrdup(make_absolute_path(work_tree));
-               git_work_tree_initialized = 1;
-               if (work_tree)
-                       is_bare_repository_cfg = 0;
-       }
        return work_tree;
 }
 
index bf225706ee377b89035eb21f76f9957cfaf6363b..38545e8bfd72c8cd4f91e0d33257b143db86bac5 100644 (file)
@@ -3,7 +3,6 @@
 #include "quote.h"
 #define MAX_ARGS       32
 
-extern char **environ;
 static const char *argv_exec_path;
 static const char *argv0_path;
 
index 534c68db6fe4d0c34c38e632bd2c442966cf8663..3886a1b46415ddbf66e5c2be401ad7fd2c012363 100644 (file)
@@ -132,14 +132,17 @@ Format of STDIN stream:
   ts    ::= # time since the epoch in seconds, ascii base10 notation;
   tz    ::= # GIT style timezone;
 
-     # note: comments 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.
+     # note: comments 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.
      #
      # In case it is not clear, the '#' that starts the comment
      # must be the first character on that line (an lf
      # preceded it).
      #
+  cat_blob ::= 'cat-blob' sp (hexsha1 | idnum) lf;
+
   comment ::= '#' not_lf* lf;
   not_lf  ::= # Any byte that is not ASCII newline (LF);
 */
@@ -326,6 +329,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 */
@@ -362,7 +366,14 @@ static uintmax_t next_mark;
 static struct strbuf new_data = STRBUF_INIT;
 static int seen_data_command;
 
+/* Signal handling */
+static volatile sig_atomic_t checkpoint_requested;
+
+/* Where to write output of cat-blob commands */
+static int cat_blob_fd = STDOUT_FILENO;
+
 static void parse_argv(void);
+static void parse_cat_blob(void);
 
 static void write_branch_report(FILE *rpt, struct branch *b)
 {
@@ -501,6 +512,32 @@ static NORETURN void die_nicely(const char *err, va_list params)
        exit(128);
 }
 
+#ifndef SIGUSR1        /* Windows, for example */
+
+static void set_checkpoint_signal(void)
+{
+}
+
+#else
+
+static void checkpoint_signal(int signo)
+{
+       checkpoint_requested = 1;
+}
+
+static void set_checkpoint_signal(void)
+{
+       struct sigaction sa;
+
+       memset(&sa, 0, sizeof(sa));
+       sa.sa_handler = checkpoint_signal;
+       sigemptyset(&sa.sa_mask);
+       sa.sa_flags = SA_RESTART;
+       sigaction(SIGUSR1, &sa, NULL);
+}
+
+#endif
+
 static void alloc_objects(unsigned int cnt)
 {
        struct object_entry_pool *b;
@@ -540,22 +577,17 @@ static struct object_entry *insert_object(unsigned char *sha1)
 {
        unsigned int h = sha1[0] << 8 | sha1[1];
        struct object_entry *e = object_table[h];
-       struct object_entry *p = NULL;
 
        while (e) {
                if (!hashcmp(sha1, e->idx.sha1))
                        return e;
-               p = e;
                e = e->next;
        }
 
        e = new_object(sha1);
-       e->next = NULL;
+       e->next = object_table[h];
        e->idx.offset = 0;
-       if (p)
-               p->next = e;
-       else
-               object_table[h] = e;
+       object_table[h] = e;
        return e;
 }
 
@@ -1764,7 +1796,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;
@@ -1805,7 +1841,7 @@ static int read_next_command(void)
                return EOF;
        }
 
-       do {
+       for (;;) {
                if (unread_command_buf) {
                        unread_command_buf = 0;
                } else {
@@ -1838,9 +1874,14 @@ static int read_next_command(void)
                        rc->prev->next = rc;
                        cmd_tail = rc;
                }
-       } while (command_buf.buf[0] == '#');
-
-       return 0;
+               if (!prefixcmp(command_buf.buf, "cat-blob ")) {
+                       parse_cat_blob();
+                       continue;
+               }
+               if (command_buf.buf[0] == '#')
+                       continue;
+               return 0;
+       }
 }
 
 static void skip_optional_lf(void)
@@ -2195,6 +2236,12 @@ static void file_change_m(struct branch *b)
                p = uq.buf;
        }
 
+       /* Git does not track empty, non-toplevel directories. */
+       if (S_ISDIR(mode) && !memcmp(sha1, EMPTY_TREE_SHA1_BIN, 20) && *p) {
+               tree_content_remove(&b->branch_tree, p, NULL);
+               return;
+       }
+
        if (S_ISGITLINK(mode)) {
                if (inline_data)
                        die("Git links cannot be specified 'inline': %s",
@@ -2715,14 +2762,95 @@ static void parse_reset_branch(void)
                unread_command_buf = 1;
 }
 
-static void parse_checkpoint(void)
+static void cat_blob_write(const char *buf, unsigned long size)
+{
+       if (write_in_full(cat_blob_fd, buf, size) != size)
+               die_errno("Write to frontend failed");
+}
+
+static void cat_blob(struct object_entry *oe, unsigned char sha1[20])
 {
+       struct strbuf line = STRBUF_INIT;
+       unsigned long size;
+       enum object_type type = 0;
+       char *buf;
+
+       if (!oe || oe->pack_id == MAX_PACK_ID) {
+               buf = read_sha1_file(sha1, &type, &size);
+       } else {
+               type = oe->type;
+               buf = gfi_unpack_entry(oe, &size);
+       }
+
+       /*
+        * Output based on batch_one_object() from cat-file.c.
+        */
+       if (type <= 0) {
+               strbuf_reset(&line);
+               strbuf_addf(&line, "%s missing\n", sha1_to_hex(sha1));
+               cat_blob_write(line.buf, line.len);
+               strbuf_release(&line);
+               free(buf);
+               return;
+       }
+       if (!buf)
+               die("Can't read object %s", sha1_to_hex(sha1));
+       if (type != OBJ_BLOB)
+               die("Object %s is a %s but a blob was expected.",
+                   sha1_to_hex(sha1), typename(type));
+       strbuf_reset(&line);
+       strbuf_addf(&line, "%s %s %lu\n", sha1_to_hex(sha1),
+                                               typename(type), size);
+       cat_blob_write(line.buf, line.len);
+       strbuf_release(&line);
+       cat_blob_write(buf, size);
+       cat_blob_write("\n", 1);
+       free(buf);
+}
+
+static void parse_cat_blob(void)
+{
+       const char *p;
+       struct object_entry *oe = oe;
+       unsigned char sha1[20];
+
+       /* cat-blob SP <object> LF */
+       p = command_buf.buf + strlen("cat-blob ");
+       if (*p == ':') {
+               char *x;
+               oe = find_mark(strtoumax(p + 1, &x, 10));
+               if (x == p + 1)
+                       die("Invalid mark: %s", command_buf.buf);
+               if (!oe)
+                       die("Unknown mark: %s", command_buf.buf);
+               if (*x)
+                       die("Garbage after mark: %s", command_buf.buf);
+               hashcpy(sha1, oe->idx.sha1);
+       } else {
+               if (get_sha1_hex(p, sha1))
+                       die("Invalid SHA1: %s", command_buf.buf);
+               if (p[40])
+                       die("Garbage after SHA1: %s", command_buf.buf);
+               oe = find_object(sha1);
+       }
+
+       cat_blob(oe, sha1);
+}
+
+static void checkpoint(void)
+{
+       checkpoint_requested = 0;
        if (object_count) {
                cycle_packfile();
                dump_branches();
                dump_tags();
                dump_marks();
        }
+}
+
+static void parse_checkpoint(void)
+{
+       checkpoint_requested = 1;
        skip_optional_lf();
 }
 
@@ -2744,7 +2872,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)
@@ -2758,6 +2887,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)
@@ -2772,16 +2902,25 @@ static void option_date_format(const char *fmt)
                die("unknown --date-format argument %s", fmt);
 }
 
+static unsigned long ulong_arg(const char *option, const char *arg)
+{
+       char *endptr;
+       unsigned long rv = strtoul(arg, &endptr, 0);
+       if (strchr(arg, '-') || endptr == arg || *endptr)
+               die("%s: argument must be a non-negative integer", option);
+       return rv;
+}
+
 static void option_depth(const char *depth)
 {
-       max_depth = strtoul(depth, NULL, 0);
+       max_depth = ulong_arg("--depth", depth);
        if (max_depth > MAX_DEPTH)
                die("--depth cannot exceed %u", MAX_DEPTH);
 }
 
 static void option_active_branches(const char *branches)
 {
-       max_active_branches = strtoul(branches, NULL, 0);
+       max_active_branches = ulong_arg("--active-branches", branches);
 }
 
 static void option_export_marks(const char *marks)
@@ -2790,6 +2929,14 @@ static void option_export_marks(const char *marks)
        safe_create_leading_directories_const(export_marks_file);
 }
 
+static void option_cat_blob_fd(const char *fd)
+{
+       unsigned long n = ulong_arg("--cat-blob-fd", fd);
+       if (n > (unsigned long) INT_MAX)
+               die("--cat-blob-fd cannot exceed %d", INT_MAX);
+       cat_blob_fd = (int) n;
+}
+
 static void option_export_pack_edges(const char *edges)
 {
        if (pack_edges)
@@ -2840,15 +2987,22 @@ 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")) {
+               ; /* Don't die - this feature is supported */
        } else if (!prefixcmp(feature, "relative-marks")) {
                relative_marks_paths = 1;
        } else if (!prefixcmp(feature, "no-relative-marks")) {
                relative_marks_paths = 0;
        } else if (!prefixcmp(feature, "force")) {
                force_update = 1;
+       } else if (!strcmp(feature, "notes")) {
+               ; /* do nothing; we have the feature */
        } else {
                return 0;
        }
@@ -2937,6 +3091,11 @@ static void parse_argv(void)
                if (parse_one_feature(a + 2, 0))
                        continue;
 
+               if (!prefixcmp(a + 2, "cat-blob-fd=")) {
+                       option_cat_blob_fd(a + 2 + strlen("cat-blob-fd="));
+                       continue;
+               }
+
                die("unknown option %s", a);
        }
        if (i != global_argc)
@@ -2979,6 +3138,7 @@ int main(int argc, const char **argv)
        prepare_packed_git();
        start_packfile();
        set_die_routine(die_nicely);
+       set_checkpoint_signal();
        while (read_next_command() != EOF) {
                if (!strcmp("blob", command_buf.buf))
                        parse_new_blob();
@@ -3000,6 +3160,9 @@ int main(int argc, const char **argv)
                        /* ignore non-git options*/;
                else
                        die("Unsupported command: %s", command_buf.buf);
+
+               if (checkpoint_requested)
+                       checkpoint();
        }
 
        /* argv hasn't been parsed yet, do so */
index df09b42840b7675e135605f9108894ce93e6d477..6cdd5910db50c96df3d149fba172750cb10c09cb 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -68,9 +68,31 @@ sq () {
 
 stop_here () {
     echo "$1" >"$dotest/next"
+    git rev-parse --verify -q HEAD >"$dotest/abort-safety"
     exit 1
 }
 
+safe_to_abort () {
+       if test -f "$dotest/dirtyindex"
+       then
+               return 1
+       fi
+
+       if ! test -s "$dotest/abort-safety"
+       then
+               return 0
+       fi
+
+       abort_safety=$(cat "$dotest/abort-safety")
+       if test "z$(git rev-parse --verify -q HEAD)" = "z$abort_safety"
+       then
+               return 0
+       fi
+       echo >&2 "You seem to have moved HEAD since the last 'am' failure."
+       echo >&2 "Not rewinding to ORIG_HEAD"
+       return 1
+}
+
 stop_here_user_resolve () {
     if [ -n "$resolvemsg" ]; then
            printf '%s\n' "$resolvemsg"
@@ -419,10 +441,11 @@ then
                        exec git rebase --abort
                fi
                git rerere clear
-               test -f "$dotest/dirtyindex" || {
+               if safe_to_abort
+               then
                        git read-tree --reset -u HEAD ORIG_HEAD
                        git reset ORIG_HEAD
-               }
+               fi
                rm -fr "$dotest"
                exit ;;
        esac
@@ -554,13 +577,6 @@ then
        resume=
 fi
 
-if test "$this" -gt "$last"
-then
-       say Nothing to do.
-       rm -fr "$dotest"
-       exit
-fi
-
 while test "$this" -le "$last"
 do
        msgnum=`printf "%0${prec}d" $this`
index d6d269f138b06791ba6e8712b06036f00a73c7e3..9c23622ed5ee9b60d40921ae74dd1149e1d68b8c 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
index d27abfe7f32ef47ee8b613293110147ca3006575..8e683e54783ab6e916bdb8ade56832ac81470648 100755 (executable)
@@ -90,23 +90,40 @@ ($)
 }
 
 # convert getopts specs for use by git config
+my %longmap = (
+       'A:' => 'authors-file',
+       'M:' => 'merge-regex',
+       'P:' => undef,
+       'R' => 'track-revisions',
+       'S:' => 'ignore-paths',
+);
+
 sub read_repo_config {
-    # Split the string between characters, unless there is a ':'
-    # So "abc:de" becomes ["a", "b", "c:", "d", "e"]
+       # Split the string between characters, unless there is a ':'
+       # So "abc:de" becomes ["a", "b", "c:", "d", "e"]
        my @opts = split(/ *(?!:)/, shift);
        foreach my $o (@opts) {
                my $key = $o;
                $key =~ s/://g;
                my $arg = 'git config';
                $arg .= ' --bool' if ($o !~ /:$/);
-
-        chomp(my $tmp = `$arg --get cvsimport.$key`);
+               my $ckey = $key;
+
+               if (exists $longmap{$o}) {
+                       # An uppercase option like -R cannot be
+                       # expressed in the configuration, as the
+                       # variable names are downcased.
+                       $ckey = $longmap{$o};
+                       next if (! defined $ckey);
+                       $ckey =~ s/-//g;
+               }
+               chomp(my $tmp = `$arg --get cvsimport.$ckey`);
                if ($tmp && !($arg =~ /--bool/ && $tmp eq 'false')) {
-            no strict 'refs';
-            my $opt_name = "opt_" . $key;
-            if (!$$opt_name) {
-                $$opt_name = $tmp;
-            }
+                       no strict 'refs';
+                       my $opt_name = "opt_" . $key;
+                       if (!$$opt_name) {
+                               $$opt_name = $tmp;
+                       }
                }
        }
 }
index 524f5ea8ab14bb44e5a8e6393e40c0ec5c1ddaa2..0594bf7ca54c6b91d5f96dd86d8962e93459d004 100755 (executable)
@@ -49,6 +49,7 @@ launch_merge_tool () {
        fi
 
        if use_ext_cmd; then
+               export BASE
                eval $GIT_DIFFTOOL_EXTCMD '"$LOCAL"' '"$REMOTE"'
        else
                run_merge_tool "$merge_tool"
index e95e4ad973f21dd104950dc6ebb28485844b36f4..ced1615e216018bc20303cd91eaea05c69cb6b11 100755 (executable)
@@ -52,6 +52,7 @@ sub generate_command
        my @command = (exe('git'), 'diff');
        my $skip_next = 0;
        my $idx = -1;
+       my $prompt = '';
        for my $arg (@ARGV) {
                $idx++;
                if ($skip_next) {
@@ -89,13 +90,11 @@ sub generate_command
                        next;
                }
                if ($arg eq '-y' || $arg eq '--no-prompt') {
-                       $ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true';
-                       delete $ENV{GIT_DIFFTOOL_PROMPT};
+                       $prompt = 'no';
                        next;
                }
                if ($arg eq '--prompt') {
-                       $ENV{GIT_DIFFTOOL_PROMPT} = 'true';
-                       delete $ENV{GIT_DIFFTOOL_NO_PROMPT};
+                       $prompt = 'yes';
                        next;
                }
                if ($arg eq '-h' || $arg eq '--help') {
@@ -103,6 +102,11 @@ sub generate_command
                }
                push @command, $arg;
        }
+       if ($prompt eq 'yes') {
+               $ENV{GIT_DIFFTOOL_PROMPT} = 'true';
+       } elsif ($prompt eq 'no') {
+               $ENV{GIT_DIFFTOOL_NO_PROMPT} = 'true';
+       }
        return @command
 }
 
index 20a3bbea07c259ec1f19353b2888fde20e8b67da..f6b7b8404896c15487044bcfaa64f758faeeef06 100755 (executable)
@@ -38,7 +38,7 @@ test -z "$(git ls-files -u)" || die_conflict
 test -f "$GIT_DIR/MERGE_HEAD" && die_merge
 
 strategy_args= diffstat= no_commit= squash= no_ff= ff_only=
-log_arg= verbosity= progress=
+log_arg= verbosity= progress= recurse_submodules=
 merge_args=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
@@ -105,10 +105,16 @@ do
        --no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
                rebase=false
                ;;
+       --recurse-submodules)
+               recurse_submodules=--recurse-submodules
+               ;;
+       --no-recurse-submodules)
+               recurse_submodules=--no-recurse-submodules
+               ;;
        --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
                ;;
        *)
@@ -217,7 +223,7 @@ test true = "$rebase" && {
        done
 }
 orig_head=$(git rev-parse -q --verify HEAD)
-git fetch $verbosity $progress $dry_run --update-head-ok "$@" || exit 1
+git fetch $verbosity $progress $dry_run $recurse_submodules --update-head-ok "$@" || exit 1
 test -z "$dry_run" || exit 0
 
 curr_head=$(git rev-parse -q --verify HEAD)
index a5ffd9a31eea0f361774d77867c83f444847279b..5873ba4bc3b2a94cd7754ae572072fd745dc059d 100755 (executable)
@@ -894,7 +894,7 @@ first and then run 'git rebase --continue' again."
 
                if test ! -z "$1"
                then
-                       output git checkout "$1" ||
+                       output git checkout "$1" -- ||
                                die "Could not checkout $1"
                fi
 
@@ -1021,7 +1021,7 @@ first and then run 'git rebase --continue' again."
 #  e, edit = use commit, but stop for amending
 #  s, squash = use commit, but meld into previous commit
 #  f, fixup = like "squash", but discard this commit's log message
-#  x <cmd>, exec <cmd> = Run a shell command <cmd>, and stop if it fails
+#  x, exec = run command (the rest of the line) using shell
 #
 # If you remove a line here THAT COMMIT WILL BE LOST.
 # However, if you remove everything, the rebase will be aborted.
index d8e190302668ca352fd58cd052a677347a29cdcd..cbb0ea90ed410d5af68ce814b7fd93a90829f3ee 100755 (executable)
@@ -482,6 +482,7 @@ case "$#" in
        then
                head_name="detached HEAD"
        else
+               echo >&2 "fatal: no such branch: $1"
                usage
        fi
        ;;
@@ -513,7 +514,7 @@ then
        if test -z "$force_rebase"
        then
                # Lazily switch to the target branch if needed...
-               test -z "$switch_to" || git checkout "$switch_to"
+               test -z "$switch_to" || git checkout "$switch_to" --
                say "Current branch $branch_name is up to date."
                exit 0
        else
index 33bc41f069d9807285db6630132e14f8c518ce47..8b9058971767dbb4d94e996876f6ba7ed178ddd6 100755 (executable)
@@ -37,12 +37,24 @@ resolve_relative_url ()
                die "remote ($remote) does not have a url defined in .git/config"
        url="$1"
        remoteurl=${remoteurl%/}
+       sep=/
        while test -n "$url"
        do
                case "$url" in
                ../*)
                        url="${url#../}"
-                       remoteurl="${remoteurl%/*}"
+                       case "$remoteurl" in
+                       */*)
+                               remoteurl="${remoteurl%/*}"
+                               ;;
+                       *:*)
+                               remoteurl="${remoteurl%:*}"
+                               sep=:
+                               ;;
+                       *)
+                               die "cannot strip one component off url '$remoteurl'"
+                               ;;
+                       esac
                        ;;
                ./*)
                        url="${url#./}"
@@ -51,7 +63,7 @@ resolve_relative_url ()
                        break;;
                esac
        done
-       echo "$remoteurl/${url%/}"
+       echo "$remoteurl$sep${url%/}"
 }
 
 #
@@ -93,20 +105,6 @@ module_clone()
        url=$2
        reference="$3"
 
-       # If there already is a directory at the submodule path,
-       # expect it to be empty (since that is the default checkout
-       # action) and try to remove it.
-       # Note: if $path is a symlink to a directory the test will
-       # succeed but the rmdir will fail. We might want to fix this.
-       if test -d "$path"
-       then
-               rmdir "$path" 2>/dev/null ||
-               die "Directory '$path' exists, but is neither empty nor a git repository"
-       fi
-
-       test -e "$path" &&
-       die "A file already exist at path '$path'"
-
        if test -n "$reference"
        then
                git-clone "$reference" -n "$url" "$path"
@@ -241,7 +239,7 @@ cmd_add()
                        # ash fails to wordsplit ${branch:+-b "$branch"...}
                        case "$branch" in
                        '') git checkout -f -q ;;
-                       ?*) git checkout -f -q -b "$branch" "origin/$branch" ;;
+                       ?*) git checkout -f -q -B "$branch" "origin/$branch" ;;
                        esac
                ) || die "Unable to checkout submodule '$path'"
        fi
diff --git a/git.c b/git.c
index d532576cdff244fcd3945ef4fcc580e1bf0b04ae..65ed68ffc13c5e1d893a5e0d84da795d9f8f698f 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)
@@ -275,6 +275,10 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
                        use_pager = check_pager_config(p->cmd);
                if (use_pager == -1 && p->option & USE_PAGER)
                        use_pager = 1;
+
+               if ((p->option & (RUN_SETUP | RUN_SETUP_GENTLY)) &&
+                   startup_info->have_repository) /* get_git_dir() may set up repo, avoid that */
+                       trace_repo_setup(prefix);
        }
        commit_pager_choice();
 
@@ -388,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 },
old mode 100644 (file)
new mode 100755 (executable)
index 1b0e09a..e82c6bf
@@ -131,6 +131,7 @@ proc unmerged_files {files} {
 
 proc parseviewargs {n arglist} {
     global vdatemode vmergeonly vflags vdflags vrevs vfiltered vorigargs env
+    global worddiff git_version
 
     set vdatemode($n) 0
     set vmergeonly($n) 0
@@ -168,7 +169,7 @@ proc parseviewargs {n arglist} {
                lappend diffargs $arg
            }
            "--raw" - "--patch-with-raw" - "--patch-with-stat" -
-           "--name-only" - "--name-status" - "--color" - "--color-words" -
+           "--name-only" - "--name-status" - "--color" -
            "--log-size" - "--pretty=*" - "--decorate" - "--abbrev-commit" -
            "--cc" - "-z" - "--header" - "--parents" - "--boundary" -
            "--no-color" - "-g" - "--walk-reflogs" - "--no-walk" -
@@ -177,6 +178,18 @@ proc parseviewargs {n arglist} {
                # These cause our parsing of git log's output to fail, or else
                # they're options we want to set ourselves, so ignore them.
            }
+           "--color-words*" - "--word-diff=color" {
+               # These trigger a word diff in the console interface,
+               # so help the user by enabling our own support
+               if {[package vcompare $git_version "1.7.2"] >= 0} {
+                   set worddiff [mc "Color words"]
+               }
+           }
+           "--word-diff*" {
+               if {[package vcompare $git_version "1.7.2"] >= 0} {
+                   set worddiff [mc "Markup words"]
+               }
+           }
            "--stat=*" - "--numstat" - "--shortstat" - "--summary" -
            "--check" - "--exit-code" - "--quiet" - "--topo-order" -
            "--full-history" - "--dense" - "--sparse" -
@@ -313,6 +326,7 @@ proc start_rev_list {view} {
     global viewactive viewinstances vmergeonly
     global mainheadid viewmainheadid viewmainheadid_orig
     global vcanopt vflags vrevs vorigargs
+    global show_notes
 
     set startmsecs [clock clicks -milliseconds]
     set commitidx($view) 0
@@ -361,8 +375,8 @@ proc start_rev_list {view} {
     }
 
     if {[catch {
-       set fd [open [concat | git log --no-color -z --pretty=raw --parents \
-                        --boundary $args "--" $files] r]
+       set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \
+                       --parents --boundary $args "--" $files] r]
     } err]} {
        error_popup "[mc "Error executing git log:"] $err"
        return 0
@@ -456,6 +470,7 @@ proc updatecommits {} {
     global mainheadid viewmainheadid viewmainheadid_orig pending_select
     global isworktree
     global varcid vposids vnegids vflags vrevs
+    global show_notes
 
     set isworktree [expr {[exec git rev-parse --is-inside-work-tree] == "true"}]
     rereadrefs
@@ -508,8 +523,8 @@ proc updatecommits {} {
        set args $vorigargs($view)
     }
     if {[catch {
-       set fd [open [concat | git log --no-color -z --pretty=raw --parents \
-                         --boundary $args "--" $vfilelimit($view)] r]
+       set fd [open [concat | git log --no-color -z --pretty=raw $show_notes \
+                       --parents --boundary $args "--" $vfilelimit($view)] r]
     } err]} {
        error_popup "[mc "Error executing git log:"] $err"
        return
@@ -1970,6 +1985,8 @@ proc makewindow {} {
     global fprogitem fprogcoord lastprogupdate progupdatepending
     global rprogitem rprogcoord rownumsel numcommits
     global have_tk85 use_ttk NS
+    global git_version
+    global worddiff
 
     # The "mc" arguments here are purely so that xgettext
     # sees the following string as needing to be translated
@@ -2243,6 +2260,15 @@ proc makewindow {} {
     ${NS}::checkbutton .bleft.mid.ignspace -text [mc "Ignore space change"] \
        -command changeignorespace -variable ignorespace
     pack .bleft.mid.ignspace -side left -padx 5
+
+    set worddiff [mc "Line diff"]
+    if {[package vcompare $git_version "1.7.2"] >= 0} {
+       makedroplist .bleft.mid.worddiff worddiff [mc "Line diff"] \
+           [mc "Markup words"] [mc "Color words"]
+       trace add variable worddiff write changeworddiff
+       pack .bleft.mid.worddiff -side left -padx 5
+    }
+
     set ctext .bleft.bottom.ctext
     text $ctext -background $bgcolor -foreground $fgcolor \
        -state disabled -font textfont \
@@ -2451,6 +2477,7 @@ proc makewindow {} {
     global ctxbut
     bind $cflist $ctxbut {pop_flist_menu %W %X %Y %x %y}
     bind $ctext $ctxbut {pop_diff_menu %W %X %Y %x %y}
+    bind $ctext <Button-1> {focus %W}
 
     set maincursor [. cget -cursor]
     set textcursor [$ctext cget -cursor]
@@ -7301,6 +7328,7 @@ proc getblobline {bf id} {
                            [lindex [split $commentend .] 0]}]
            mark_ctext_line $lnum
        }
+       $ctext config -state disabled
        return 0
     }
     $ctext config -state disabled
@@ -7502,11 +7530,16 @@ proc changeignorespace {} {
     reselectline
 }
 
+proc changeworddiff {name ix op} {
+    reselectline
+}
+
 proc getblobdiffs {ids} {
     global blobdifffd diffids env
     global diffinhdr treediffs
     global diffcontext
     global ignorespace
+    global worddiff
     global limitdiffs vfilelimit curview
     global diffencoding targetline diffnparents
     global git_version currdiffsubmod
@@ -7523,6 +7556,9 @@ proc getblobdiffs {ids} {
     if {$ignorespace} {
        append cmd " -w"
     }
+    if {$worddiff ne [mc "Line diff"]} {
+       append cmd " --word-diff=porcelain"
+    }
     if {$limitdiffs && $vfilelimit($curview) ne {}} {
        set cmd [concat $cmd -- $vfilelimit($curview)]
     }
@@ -7608,6 +7644,7 @@ proc getblobdiffline {bdf ids} {
     global ctext_file_names ctext_file_lines
     global diffinhdr treediffs mergemax diffnparents
     global diffencoding jump_to_here targetline diffline currdiffsubmod
+    global worddiff
 
     set nr 0
     $ctext conf -state normal
@@ -7747,15 +7784,28 @@ proc getblobdiffline {bdf ids} {
            # parse the prefix - one ' ', '-' or '+' for each parent
            set prefix [string range $line 0 [expr {$diffnparents - 1}]]
            set tag [expr {$diffnparents > 1? "m": "d"}]
+           set dowords [expr {$worddiff ne [mc "Line diff"] && $diffnparents == 1}]
+           set words_pre_markup ""
+           set words_post_markup ""
            if {[string trim $prefix " -+"] eq {}} {
                # prefix only has " ", "-" and "+" in it: normal diff line
                set num [string first "-" $prefix]
+               if {$dowords} {
+                   set line [string range $line 1 end]
+               }
                if {$num >= 0} {
                    # removed line, first parent with line is $num
                    if {$num >= $mergemax} {
                        set num "max"
                    }
-                   $ctext insert end "$line\n" $tag$num
+                   if {$dowords && $worddiff eq [mc "Markup words"]} {
+                       $ctext insert end "\[-$line-\]" $tag$num
+                   } else {
+                       $ctext insert end "$line" $tag$num
+                   }
+                   if {!$dowords} {
+                       $ctext insert end "\n" $tag$num
+                   }
                } else {
                    set tags {}
                    if {[string first "+" $prefix] >= 0} {
@@ -7770,6 +7820,8 @@ proc getblobdiffline {bdf ids} {
                                lappend tags m$num
                            }
                        }
+                       set words_pre_markup "{+"
+                       set words_post_markup "+}"
                    }
                    if {$targetline ne {}} {
                        if {$diffline == $targetline} {
@@ -7779,8 +7831,17 @@ proc getblobdiffline {bdf ids} {
                            incr diffline
                        }
                    }
-                   $ctext insert end "$line\n" $tags
+                   if {$dowords && $worddiff eq [mc "Markup words"]} {
+                       $ctext insert end "$words_pre_markup$line$words_post_markup" $tags
+                   } else {
+                       $ctext insert end "$line" $tags
+                   }
+                   if {!$dowords} {
+                       $ctext insert end "\n" $tags
+                   }
                }
+           } elseif {$dowords && $prefix eq "~"} {
+               $ctext insert end "\n" {}
            } else {
                # "\ No newline at end of file",
                # or something else we don't recognize
@@ -11391,6 +11452,7 @@ if {[tk windowingsystem] eq "win32"} {
 set diffcolors {red "#00a000" blue}
 set diffcontext 3
 set ignorespace 0
+set worddiff ""
 set markbgcolor "#e0e0ff"
 
 set circlecolors {white blue gray blue blue}
@@ -11521,6 +11583,11 @@ set NS [expr {$use_ttk ? "ttk" : ""}]
 
 set git_version [join [lrange [split [lindex [exec git version] end] .] 0 2] .]
 
+set show_notes {}
+if {[package vcompare $git_version "1.6.6.2"] >= 0} {
+    set show_notes "--show-notes"
+}
+
 set runq {}
 set history {}
 set historyindex 0
diff --git a/gitk-git/po/pt_br.po b/gitk-git/po/pt_br.po
new file mode 100644 (file)
index 0000000..1486e32
--- /dev/null
@@ -0,0 +1,1277 @@
+# Translation of gitk to Brazilian Portuguese.
+# Copyright (C) 2007 Paul Mackerras, et al.
+# This file is distributed under the same license as the gitk package.
+#
+# Alexandre Erwin Ittner <alexandre@ittner.com.br>, 2010.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: gitk\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2010-01-26 15:47-0800\n"
+"PO-Revision-Date: 2010-12-06 23:39-0200\n"
+"Last-Translator: Alexandre Erwin Ittner <alexandre@ittner.com.br>\n"
+"Language-Team: Brazilian Portuguese <>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: gitk:115
+msgid "Couldn't get list of unmerged files:"
+msgstr "Não foi possível obter a lista dos arquivos não mesclados:"
+
+#: gitk:274
+msgid "Error parsing revisions:"
+msgstr "Erro ao interpretar revisões:"
+
+#: gitk:330
+msgid "Error executing --argscmd command:"
+msgstr "Erro ao executar o comando--argscmd:"
+
+#: gitk:343
+msgid "No files selected: --merge specified but no files are unmerged."
+msgstr ""
+"Nenhum arquivo foi selecionado: --merge especificado mas não há arquivos não-"
+"mesclados."
+
+#: gitk:346
+msgid ""
+"No files selected: --merge specified but no unmerged files are within file "
+"limit."
+msgstr ""
+"Nenhum arquivo foi selecionado: --merge especificado mas não há arquivos não-"
+"mesclados dentro dos limites."
+
+#: gitk:368 gitk:516
+msgid "Error executing git log:"
+msgstr "Erro ao executar git log:"
+
+#: gitk:386 gitk:532
+msgid "Reading"
+msgstr "Lendo"
+
+#: gitk:446 gitk:4271
+msgid "Reading commits..."
+msgstr "Lendo revisões..."
+
+#: gitk:449 gitk:1580 gitk:4274
+msgid "No commits selected"
+msgstr "Nenhuma revisão foi selecionada"
+
+#: gitk:1456
+msgid "Can't parse git log output:"
+msgstr "Não foi possível interpretar a saída do \"git log\":"
+
+#: gitk:1676
+msgid "No commit information available"
+msgstr "Não há informações disponíveis sobre a revisão"
+
+#: gitk:1818
+msgid "mc"
+msgstr "mc"
+
+#: gitk:1853 gitk:4064 gitk:9067 gitk:10607 gitk:10817
+msgid "OK"
+msgstr "Ok"
+
+#: gitk:1855 gitk:4066 gitk:8657 gitk:8736 gitk:8851 gitk:8900 gitk:9069
+#: gitk:10608 gitk:10818
+msgid "Cancel"
+msgstr "Cancelar"
+
+#: gitk:1980
+msgid "Update"
+msgstr "Atualizar"
+
+#: gitk:1981
+msgid "Reload"
+msgstr "Recarregar"
+
+#: gitk:1982
+msgid "Reread references"
+msgstr "Ler as referências novamente"
+
+#: gitk:1983
+msgid "List references"
+msgstr "Listar referências"
+
+#: gitk:1985
+msgid "Start git gui"
+msgstr "Iniciar Git GUI"
+
+#: gitk:1987
+msgid "Quit"
+msgstr "Sair"
+
+#: gitk:1979
+msgid "File"
+msgstr "Arquivo"
+
+#: gitk:1991
+msgid "Preferences"
+msgstr "Preferências"
+
+#: gitk:1990
+msgid "Edit"
+msgstr "Editar"
+
+#: gitk:1995
+msgid "New view..."
+msgstr "Nova vista..."
+
+#: gitk:1996
+msgid "Edit view..."
+msgstr "Editar vista..."
+
+#: gitk:1997
+msgid "Delete view"
+msgstr "Apagar vista"
+
+#: gitk:1999
+msgid "All files"
+msgstr "Todos os arquivos"
+
+#: gitk:1994 gitk:3817
+msgid "View"
+msgstr "Exibir"
+
+#: gitk:2004 gitk:2014 gitk:2787
+msgid "About gitk"
+msgstr "Sobre o gitk"
+
+#: gitk:2005 gitk:2019
+msgid "Key bindings"
+msgstr "Atalhos de teclado"
+
+#: gitk:2003 gitk:2018
+msgid "Help"
+msgstr "Ajuda"
+
+#: gitk:2096 gitk:8132
+msgid "SHA1 ID:"
+msgstr "SHA1 ID:"
+
+#: gitk:2127
+msgid "Row"
+msgstr "Linha"
+
+#: gitk:2165
+msgid "Find"
+msgstr "Encontrar"
+
+#: gitk:2166
+msgid "next"
+msgstr "Próximo"
+
+#: gitk:2167
+msgid "prev"
+msgstr "Anterior"
+
+#: gitk:2168
+msgid "commit"
+msgstr "Revisão"
+
+#: gitk:2171 gitk:2173 gitk:4432 gitk:4455 gitk:4479 gitk:6420 gitk:6492
+#: gitk:6576
+msgid "containing:"
+msgstr "contendo:"
+
+#: gitk:2174 gitk:3298 gitk:3303 gitk:4507
+msgid "touching paths:"
+msgstr "envolvendo os caminhos:"
+
+#: gitk:2175 gitk:4512
+msgid "adding/removing string:"
+msgstr "Adicionando/removendo texto:"
+
+#: gitk:2184 gitk:2186
+msgid "Exact"
+msgstr "Exatamente"
+
+#: gitk:2186 gitk:4587 gitk:6388
+msgid "IgnCase"
+msgstr "Ignorar maiúsculas/minúsculas"
+
+#: gitk:2186 gitk:4481 gitk:4585 gitk:6384
+msgid "Regexp"
+msgstr "Expressão regular"
+
+#: gitk:2188 gitk:2189 gitk:4606 gitk:4636 gitk:4643 gitk:6512 gitk:6580
+msgid "All fields"
+msgstr "Todos os campos"
+
+#: gitk:2189 gitk:4604 gitk:4636 gitk:6451
+msgid "Headline"
+msgstr "Assunto"
+
+#: gitk:2190 gitk:4604 gitk:6451 gitk:6580 gitk:7013
+msgid "Comments"
+msgstr "Descrição da revisão"
+
+#: gitk:2190 gitk:4604 gitk:4608 gitk:4643 gitk:6451 gitk:6948 gitk:8307
+#: gitk:8322
+msgid "Author"
+msgstr "Autor"
+
+#: gitk:2190 gitk:4604 gitk:6451 gitk:6950
+msgid "Committer"
+msgstr "Revisor"
+
+#: gitk:2221
+msgid "Search"
+msgstr "Buscar"
+
+#: gitk:2229
+msgid "Diff"
+msgstr "Diferenças"
+
+#: gitk:2231
+msgid "Old version"
+msgstr "Versão antiga"
+
+#: gitk:2233
+msgid "New version"
+msgstr "Versão nova"
+
+#: gitk:2235
+msgid "Lines of context"
+msgstr "Número de linhas de contexto"
+
+#: gitk:2245
+msgid "Ignore space change"
+msgstr "Ignorar mudanças de caixa"
+
+#: gitk:2304
+msgid "Patch"
+msgstr "Diferenças"
+
+#: gitk:2306
+msgid "Tree"
+msgstr "Árvore"
+
+#: gitk:2463 gitk:2480
+msgid "Diff this -> selected"
+msgstr "Comparar esta revisão com a selecionada"
+
+#: gitk:2464 gitk:2481
+msgid "Diff selected -> this"
+msgstr "Comparar a revisão selecionada com esta"
+
+#: gitk:2465 gitk:2482
+msgid "Make patch"
+msgstr "Criar patch"
+
+#: gitk:2466 gitk:8715
+msgid "Create tag"
+msgstr "Criar etiqueta"
+
+#: gitk:2467 gitk:8831
+msgid "Write commit to file"
+msgstr "Salvar revisão para um arquivo"
+
+#: gitk:2468 gitk:8888
+msgid "Create new branch"
+msgstr "Criar novo ramo"
+
+#: gitk:2469
+msgid "Cherry-pick this commit"
+msgstr "Fazer cherry-pick desta revisão"
+
+#: gitk:2470
+msgid "Reset HEAD branch to here"
+msgstr "Redefinir HEAD para cá"
+
+#: gitk:2471
+msgid "Mark this commit"
+msgstr "Marcar esta revisão"
+
+#: gitk:2472
+msgid "Return to mark"
+msgstr "Voltar à marca"
+
+#: gitk:2473
+msgid "Find descendant of this and mark"
+msgstr "Encontrar descendente e marcar"
+
+#: gitk:2474
+msgid "Compare with marked commit"
+msgstr "Comparar com a revisão marcada"
+
+#: gitk:2488
+msgid "Check out this branch"
+msgstr "Efetuar checkout deste ramo"
+
+#: gitk:2489
+msgid "Remove this branch"
+msgstr "Excluir este ramo"
+
+#: gitk:2496
+msgid "Highlight this too"
+msgstr "Marcar este também"
+
+#: gitk:2497
+msgid "Highlight this only"
+msgstr "Marcar apenas este"
+
+#: gitk:2498
+msgid "External diff"
+msgstr "Diff externo"
+
+#: gitk:2499
+msgid "Blame parent commit"
+msgstr "Anotar revisão anterior"
+
+#: gitk:2506
+msgid "Show origin of this line"
+msgstr "Exibir origem desta linha"
+
+#: gitk:2507
+msgid "Run git gui blame on this line"
+msgstr "Executar 'git blame' nesta linha"
+
+#: gitk:2789
+msgid "\n"
+"Gitk - a commit viewer for git\n"
+"\n"
+"Copyright ©9 2005-2010 Paul Mackerras\n"
+"\n"
+"Use and redistribute under the terms of the GNU General Public License"
+msgstr "\n"
+"Gitk - um visualizador de revisões para o git \n"
+"\n"
+"Copyright ©9 2005-2010 Paul Mackerras\n"
+"\n"
+"Uso e distribuição segundo os termos da Licença Pública Geral GNU"
+
+#: gitk:2797 gitk:2862 gitk:9253
+msgid "Close"
+msgstr "Fechar"
+
+#: gitk:2818
+msgid "Gitk key bindings"
+msgstr "Atalhos de teclado"
+
+#: gitk:2821
+msgid "Gitk key bindings:"
+msgstr "Atalhos de teclado:"
+
+#: gitk:2823
+#, tcl-format
+msgid "<%s-Q>\t\tQuit"
+msgstr "<%s-Q>\t\tSair"
+
+#: gitk:2824
+#, tcl-format
+msgid "<%s-W>\t\tClose window"
+msgstr "<%s-W>\t\tFechar janela"
+
+#: gitk:2825
+msgid "<Home>\t\tMove to first commit"
+msgstr "<Home>\t\tIr para a primeira revisão"
+
+#: gitk:2826
+msgid "<End>\t\tMove to last commit"
+msgstr "<End>\t\tIr para a última revisão"
+
+#: gitk:2827
+msgid "<Up>, p, i\tMove up one commit"
+msgstr "<Up>, p, i\tIr para uma revisão acima"
+
+#: gitk:2828
+msgid "<Down>, n, k\tMove down one commit"
+msgstr "<Down>, n, k\tIr para uma revisão abaixo"
+
+#: gitk:2829
+msgid "<Left>, z, j\tGo back in history list"
+msgstr "<Left>, z, j\tVoltar no histórico"
+
+#: gitk:2830
+msgid "<Right>, x, l\tGo forward in history list"
+msgstr "<Right>, x, l\tAvançar no histórico"
+
+#: gitk:2831
+msgid "<PageUp>\tMove up one page in commit list"
+msgstr "<PageUp>\tSubir uma página na lista de revisões"
+
+#: gitk:2832
+msgid "<PageDown>\tMove down one page in commit list"
+msgstr "<PageDown>\tDescer uma página na lista de revisões"
+
+#: gitk:2833
+#, tcl-format
+msgid "<%s-Home>\tScroll to top of commit list"
+msgstr "<%s-Home>\tRolar para o início da lista de revisões"
+
+#: gitk:2834
+#, tcl-format
+msgid "<%s-End>\tScroll to bottom of commit list"
+msgstr "<%s-End>\tRolar para o final da lista de revisões"
+
+#: gitk:2835
+#, tcl-format
+msgid "<%s-Up>\tScroll commit list up one line"
+msgstr "<%s-Up>\tRolar uma linha acima na lista de revisões"
+
+#: gitk:2836
+#, tcl-format
+msgid "<%s-Down>\tScroll commit list down one line"
+msgstr "<%s-Down>\tRolar uma linha abaixo na lista de revisões"
+
+#: gitk:2837
+#, tcl-format
+msgid "<%s-PageUp>\tScroll commit list up one page"
+msgstr "<%s-PageUp>\tRolar uma página acima na lista de revisões"
+
+#: gitk:2838
+#, tcl-format
+msgid "<%s-PageDown>\tScroll commit list down one page"
+msgstr "<%s-PageDown>\tRolar uma página abaixo na lista de revisões"
+
+#: gitk:2839
+msgid "<Shift-Up>\tFind backwards (upwards, later commits)"
+msgstr "<Shift-Up>\tProcurar próxima (revisões mas recentes)"
+
+#: gitk:2840
+msgid "<Shift-Down>\tFind forwards (downwards, earlier commits)"
+msgstr "<Shift-Down>\tProcurar anterior (revisões mais antigas)"
+
+#: gitk:2841
+msgid "<Delete>, b\tScroll diff view up one page"
+msgstr "<Delete>, b\tRola alterações uma página acima"
+
+#: gitk:2842
+msgid "<Backspace>\tScroll diff view up one page"
+msgstr "<Backspace>\tRolar alterações uma página abaixo"
+
+#: gitk:2843
+msgid "<Space>\t\tScroll diff view down one page"
+msgstr "<Space>\t\tRolar alterações uma página abaixo"
+
+#: gitk:2844
+msgid "u\t\tScroll diff view up 18 lines"
+msgstr "u\t\tRolar alterações 18 linhas acima"
+
+#: gitk:2845
+msgid "d\t\tScroll diff view down 18 lines"
+msgstr "d\t\tRolar alterações 18 linhas abaixo"
+
+#: gitk:2846
+#, tcl-format
+msgid "<%s-F>\t\tFind"
+msgstr "<%s-F>\t\tProcurar"
+
+#: gitk:2847
+#, tcl-format
+msgid "<%s-G>\t\tMove to next find hit"
+msgstr "<%s-G>\t\tIr para a próxima ocorrência"
+
+#: gitk:2848
+msgid "<Return>\tMove to next find hit"
+msgstr "<Return>\tIr para a próxima ocorrência"
+
+#: gitk:2849
+msgid "/\t\tFocus the search box"
+msgstr "/\t\tPor foco na caixa de busca"
+
+#: gitk:2850
+msgid "?\t\tMove to previous find hit"
+msgstr "?\t\tIr para a ocorrência anterior"
+
+#: gitk:2851
+msgid "f\t\tScroll diff view to next file"
+msgstr "f\t\tRolar alterações para o próximo arquivo"
+
+#: gitk:2852
+#, tcl-format
+msgid "<%s-S>\t\tSearch for next hit in diff view"
+msgstr "<%s-S>\t\tProcurar a próxima ocorrência na lista de alterações"
+
+#: gitk:2853
+#, tcl-format
+msgid "<%s-R>\t\tSearch for previous hit in diff view"
+msgstr "<%s-R>\t\tProcurar ocorrência anterior na lista de alterações"
+
+#: gitk:2854
+#, tcl-format
+msgid "<%s-KP+>\tIncrease font size"
+msgstr "<%s-KP+>\tAumentar tamanho da fonte"
+
+#: gitk:2855
+#, tcl-format
+msgid "<%s-plus>\tIncrease font size"
+msgstr "<%s-plus>\tAumentar tamanho da fonte"
+
+#: gitk:2856
+#, tcl-format
+msgid "<%s-KP->\tDecrease font size"
+msgstr "<%s-KP->\tReduzir tamanho da fonte"
+
+#: gitk:2857
+#, tcl-format
+msgid "<%s-minus>\tDecrease font size"
+msgstr "<%s-minus>\tReduzir tamanho da fonte"
+
+#: gitk:2858
+msgid "<F5>\t\tUpdate"
+msgstr "<F5>\t\tAtualizar"
+
+#: gitk:3313 gitk:3322
+#, tcl-format
+msgid "Error creating temporary directory %s:"
+msgstr "Erro ao criar o diretório temporário %s:"
+
+#: gitk:3335
+#, tcl-format
+msgid "Error getting \"%s\" from %s:"
+msgstr "Erro ao ler \"%s\" de %s:"
+
+#: gitk:3398
+msgid "command failed:"
+msgstr "O comando falhou:"
+
+#: gitk:3547
+msgid "No such commit"
+msgstr "Revisão não encontrada"
+
+#: gitk:3561
+msgid "git gui blame: command failed:"
+msgstr "Comando 'git gui blame' falhou:"
+
+#: gitk:3592
+#, tcl-format
+msgid "Couldn't read merge head: %s"
+msgstr "Impossível ler merge head: %s"
+
+#: gitk:3600
+#, tcl-format
+msgid "Error reading index: %s"
+msgstr "Erro ao ler o índice: %s"
+
+#: gitk:3625
+#, tcl-format
+msgid "Couldn't start git blame: %s"
+msgstr "Não foi possível inciar o 'git blame': %s"
+
+#: gitk:3628 gitk:6419
+msgid "Searching"
+msgstr "Procurando"
+
+#: gitk:3660
+#, tcl-format
+msgid "Error running git blame: %s"
+msgstr "Erro ao executar 'git blame': %s"
+
+#: gitk:3688
+#, tcl-format
+msgid "That line comes from commit %s,  which is not in this view"
+msgstr "Esta linha vem da revisão %s, que não está nesta vista"
+
+#: gitk:3702
+msgid "External diff viewer failed:"
+msgstr "Erro do visualizador de alterações externo:"
+
+#: gitk:3820
+msgid "Gitk view definition"
+msgstr "Definir vista"
+
+#: gitk:3824
+msgid "Remember this view"
+msgstr "Lembrar esta vista"
+
+#: gitk:3825
+msgid "References (space separated list):"
+msgstr "Referências (separar a lista com um espaço):"
+
+#: gitk:3826
+msgid "Branches & tags:"
+msgstr "Ramos & etiquetas:"
+
+#: gitk:3827
+msgid "All refs"
+msgstr "Todas as referências"
+
+#: gitk:3828
+msgid "All (local) branches"
+msgstr "Todos os ramos locais"
+
+#: gitk:3829
+msgid "All tags"
+msgstr "Todas as etiquetas"
+
+#: gitk:3830
+msgid "All remote-tracking branches"
+msgstr "Todos os ramos de rastreio"
+
+#: gitk:3831
+msgid "Commit Info (regular expressions):"
+msgstr "Informações da revisão (expressões regulares):"
+
+#: gitk:3832
+msgid "Author:"
+msgstr "Autor:"
+
+#: gitk:3833
+msgid "Committer:"
+msgstr "Revisor:"
+
+#: gitk:3834
+msgid "Commit Message:"
+msgstr "Descrição da revisão:"
+
+#: gitk:3835
+msgid "Matches all Commit Info criteria"
+msgstr "Coincidir todos os critérios de informações da revisão"
+
+#: gitk:3836
+msgid "Changes to Files:"
+msgstr "Mudanças para os arquivos:"
+
+#: gitk:3837
+msgid "Fixed String"
+msgstr "Texto fixo"
+
+#: gitk:3838
+msgid "Regular Expression"
+msgstr "Expressão regular"
+
+#: gitk:3839
+msgid "Search string:"
+msgstr "Texto de busca"
+
+#: gitk:3840
+msgid ""
+"Commit Dates (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 "
+"15:27:38\"):"
+msgstr ""
+"Datas de revisão (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 "
+"15:27:38\"):"
+
+#: gitk:3841
+msgid "Since:"
+msgstr "Desde:"
+
+#: gitk:3842
+msgid "Until:"
+msgstr "Até:"
+
+#: gitk:3843
+msgid "Limit and/or skip a number of revisions (positive integer):"
+msgstr "Limitar e/ou ignorar um número de revisões (inteiro positivo):"
+
+#: gitk:3844
+msgid "Number to show:"
+msgstr "Número para mostrar:"
+
+#: gitk:3845
+msgid "Number to skip:"
+msgstr "Número para ignorar:"
+
+#: gitk:3846
+msgid "Miscellaneous options:"
+msgstr "Opções diversas:"
+
+#: gitk:3847
+msgid "Strictly sort by date"
+msgstr "Ordenar estritamente pela data"
+
+#: gitk:3848
+msgid "Mark branch sides"
+msgstr "Marcar os dois lados do ramo"
+
+#: gitk:3849
+msgid "Limit to first parent"
+msgstr "Limitar ao primeiro antecessor"
+
+#: gitk:3850
+msgid "Simple history"
+msgstr "Histórico simplificado"
+
+#: gitk:3851
+msgid "Additional arguments to git log:"
+msgstr "Argumentos adicionais para o 'git log':"
+
+#: gitk:3852
+msgid "Enter files and directories to include, one per line:"
+msgstr "Arquivos e diretórios para incluir, um por linha"
+
+#: gitk:3853
+msgid "Command to generate more commits to include:"
+msgstr "Comando para gerar mais revisões para incluir:"
+
+#: gitk:3977
+msgid "Gitk: edit view"
+msgstr "Gitk: editar vista"
+
+#: gitk:3985
+msgid "-- criteria for selecting revisions"
+msgstr "-- critérios para selecionar revisões"
+
+#: gitk:3990
+msgid "View Name"
+msgstr "Nome da vista"
+
+#: gitk:4065
+msgid "Apply (F5)"
+msgstr "Aplicar (F5)"
+
+#: gitk:4103
+msgid "Error in commit selection arguments:"
+msgstr "Erro nos argumentos de seleção de revisões:"
+
+#: gitk:4156 gitk:4208 gitk:4656 gitk:4670 gitk:5931 gitk:11551 gitk:11552
+msgid "None"
+msgstr "Nenhum"
+
+#: gitk:4604 gitk:6451 gitk:8309 gitk:8324
+msgid "Date"
+msgstr "Data"
+
+#: gitk:4604 gitk:6451
+msgid "CDate"
+msgstr "DataR"
+
+#: gitk:4753 gitk:4758
+msgid "Descendant"
+msgstr "Descendente de"
+
+#: gitk:4754
+msgid "Not descendant"
+msgstr "Não descendente de"
+
+#: gitk:4761 gitk:4766
+msgid "Ancestor"
+msgstr "Antecessor de"
+
+#: gitk:4762
+msgid "Not ancestor"
+msgstr "Não antecessor de"
+
+#: gitk:5052
+msgid "Local changes checked in to index but not committed"
+msgstr "Mudanças locais marcadas, porém não salvas"
+
+#: gitk:5088
+msgid "Local uncommitted changes, not checked in to index"
+msgstr "Mudanças locais não marcadas"
+
+#: gitk:6769
+msgid "many"
+msgstr "muitas"
+
+#: gitk:6952
+msgid "Tags:"
+msgstr "Etiquetas:"
+
+#: gitk:6969 gitk:6975 gitk:8302
+msgid "Parent"
+msgstr "Antecessor"
+
+#: gitk:6980
+msgid "Child"
+msgstr "Descendente"
+
+#: gitk:6989
+msgid "Branch"
+msgstr "Ramo"
+
+#: gitk:6992
+msgid "Follows"
+msgstr "Segue"
+
+#: gitk:6995
+msgid "Precedes"
+msgstr "Precede"
+
+#: gitk:7532
+#, tcl-format
+msgid "Error getting diffs: %s"
+msgstr "Erro ao obter diferenças: %s"
+
+#: gitk:8130
+msgid "Goto:"
+msgstr "Ir para:"
+
+#: gitk:8151
+#, tcl-format
+msgid "Short SHA1 id %s is ambiguous"
+msgstr "O id SHA1 %s é ambíguo"
+
+#: gitk:8158
+#, tcl-format
+msgid "Revision %s is not known"
+msgstr "Revisão %s desconhecida"
+
+#: gitk:8168
+#, tcl-format
+msgid "SHA1 id %s is not known"
+msgstr "Id SHA1 %s desconhecido"
+
+#: gitk:8170
+#, tcl-format
+msgid "Revision %s is not in the current view"
+msgstr "A revisão %s não está na vista atual"
+
+#: gitk:8312
+msgid "Children"
+msgstr "Descendentes"
+
+#: gitk:8370
+#, tcl-format
+msgid "Reset %s branch to here"
+msgstr "Redefinir ramo %s para este ponto"
+
+#: gitk:8372
+msgid "Detached head: can't reset"
+msgstr "Detached head: impossível redefinir"
+
+#: gitk:8481 gitk:8487
+msgid "Skipping merge commit "
+msgstr "Saltando revisão de mesclagem"
+
+#: gitk:8496 gitk:8501
+msgid "Error getting patch ID for "
+msgstr "Erro ao obter patch ID para"
+
+#: gitk:8497 gitk:8502
+msgid " - stopping\n"
+msgstr "- parando\n"
+
+#: gitk:8507 gitk:8510 gitk:8518 gitk:8532 gitk:8541
+msgid "Commit "
+msgstr "Revisão"
+
+#: gitk:8511
+msgid ""
+" is the same patch as\n"
+"       "
+msgstr ""
+"é o mesmo patch que\n"
+"       "
+
+#: gitk:8519
+msgid ""
+" differs from\n"
+"       "
+msgstr "difere de"
+
+#: gitk:8521
+msgid ""
+"Diff of commits:\n"
+"\n"
+msgstr ""
+"Diferença de revisões:\n"
+"\n"
+
+#: gitk:8533 gitk:8542
+#, tcl-format
+msgid " has %s children - stopping\n"
+msgstr "possui %s descendentes - parando\n"
+
+#: gitk:8561
+#, tcl-format
+msgid "Error writing commit to file: %s"
+msgstr "Erro ao salvar revisão para o arquivo: %s"
+
+#: gitk:8567
+#, tcl-format
+msgid "Error diffing commits: %s"
+msgstr "Erro ao comparar revisões: %s"
+
+#: gitk:8598
+msgid "Top"
+msgstr "Início"
+
+#: gitk:8599
+msgid "From"
+msgstr "De"
+
+#: gitk:8604
+msgid "To"
+msgstr "Para"
+
+#: gitk:8628
+msgid "Generate patch"
+msgstr "Gerar patch"
+
+#: gitk:8630
+msgid "From:"
+msgstr "De:"
+
+#: gitk:8639
+msgid "To:"
+msgstr "Para:"
+
+#: gitk:8648
+msgid "Reverse"
+msgstr "Inverter"
+
+#: gitk:8650 gitk:8845
+msgid "Output file:"
+msgstr "Arquivo de saída:"
+
+#: gitk:8656
+msgid "Generate"
+msgstr "Gerar"
+
+#: gitk:8694
+msgid "Error creating patch:"
+msgstr "Erro ao criar patch:"
+
+#: gitk:8717 gitk:8833 gitk:8890
+msgid "ID:"
+msgstr "ID:"
+
+#: gitk:8726
+msgid "Tag name:"
+msgstr "Nome da etiqueta:"
+
+#: gitk:8729
+msgid "Tag message is optional"
+msgstr "A descrição da etiqueta é opcional"
+
+#: gitk:8731
+msgid "Tag message:"
+msgstr "Descrição da etiqueta"
+
+#: gitk:8735 gitk:8899
+msgid "Create"
+msgstr "Criar"
+
+#: gitk:8753
+msgid "No tag name specified"
+msgstr "Nome da etiqueta não indicado"
+
+#: gitk:8757
+#, tcl-format
+msgid "Tag \"%s\" already exists"
+msgstr "Etiqueta \"%s\" já existe"
+
+#: gitk:8767
+msgid "Error creating tag:"
+msgstr "Erro ao criar etiqueta:"
+
+#: gitk:8842
+msgid "Command:"
+msgstr "Comando:"
+
+#: gitk:8850
+msgid "Write"
+msgstr "Exportar"
+
+#: gitk:8868
+msgid "Error writing commit:"
+msgstr "Erro ao exportar revisão"
+
+#: gitk:8895
+msgid "Name:"
+msgstr "Nome:"
+
+#: gitk:8918
+msgid "Please specify a name for the new branch"
+msgstr "Indique um nome para o novo ramo"
+
+#: gitk:8923
+#, tcl-format
+msgid "Branch '%s' already exists. Overwrite?"
+msgstr "O ramo \"%s\" já existe. Sobrescrever?"
+
+#: gitk:8989
+#, tcl-format
+msgid "Commit %s is already included in branch %s -- really re-apply it?"
+msgstr "Revisão %s já inclusa no ramo %s -- você realmente deseja reaplicá-la?"
+
+#: gitk:8994
+msgid "Cherry-picking"
+msgstr "Cherry-picking"
+
+#: gitk:9003
+#, tcl-format
+msgid ""
+"Cherry-pick failed because of local changes to file '%s'.\n"
+"Please commit, reset or stash your changes and try again."
+msgstr ""
+"O cherry-pick falhou porque o arquivo \"%s\" possui mudanças locais.\n"
+"Salve a uma revisão, redefina ou armazene (stash) suas mudanças e tente "
+"novamente."
+
+#: gitk:9009
+msgid ""
+"Cherry-pick failed because of merge conflict.\n"
+"Do you wish to run git citool to resolve it?"
+msgstr ""
+"O cherry-pick falhou porque houve um conflito na mesclagem.\n"
+"Executar o 'git citool' para resolvê-lo?"
+
+#: gitk:9025
+msgid "No changes committed"
+msgstr "Nenhuma revisão foi salva"
+
+#: gitk:9051
+msgid "Confirm reset"
+msgstr "Confirmar redefinição"
+
+#: gitk:9053
+#, tcl-format
+msgid "Reset branch %s to %s?"
+msgstr "Você realmente deseja redefinir o ramo %s para %s?"
+
+#: gitk:9055
+msgid "Reset type:"
+msgstr "Tipo de redefinição"
+
+#: gitk:9058
+msgid "Soft: Leave working tree and index untouched"
+msgstr "Soft: deixa a árvore de trabalho e o índice intocados"
+
+#: gitk:9061
+msgid "Mixed: Leave working tree untouched, reset index"
+msgstr "Misto: Deixa a árvore de trabalho intocada, redefine o índice"
+
+#: gitk:9064
+msgid ""
+"Hard: Reset working tree and index\n"
+"(discard ALL local changes)"
+msgstr ""
+"Hard: Redefine a árvore de trabalho e o índice\n"
+"(descarta TODAS as mudanças locais)"
+
+#: gitk:9081
+msgid "Resetting"
+msgstr "Redefinindo"
+
+#: gitk:9141
+msgid "Checking out"
+msgstr "Abrindo"
+
+#: gitk:9194
+msgid "Cannot delete the currently checked-out branch"
+msgstr "Impossível excluir o ramo atualmente aberto"
+
+#: gitk:9200
+#, tcl-format
+msgid ""
+"The commits on branch %s aren't on any other branch.\n"
+"Really delete branch %s?"
+msgstr ""
+"As revisões do ramo \"%s\" não existem em nenhum outro ramo.\n"
+"Você realmente deseja excluir ramo \"%s\"?"
+
+#: gitk:9231
+#, tcl-format
+msgid "Tags and heads: %s"
+msgstr "Referências: %s"
+
+#: gitk:9246
+msgid "Filter"
+msgstr "Filtro"
+
+#: gitk:9541
+msgid ""
+"Error reading commit topology information; branch and preceding/following "
+"tag information will be incomplete."
+msgstr ""
+"Erro ao ler a topologia das revisões; as informações dos ramos e etiquetas "
+"antecessoras/sucessoras estarão incompletas"
+
+#: gitk:10527
+msgid "Tag"
+msgstr "Etiqueta"
+
+#: gitk:10527
+msgid "Id"
+msgstr "Id"
+
+#: gitk:10576
+msgid "Gitk font chooser"
+msgstr "Selecionar fontes do Gitk"
+
+#: gitk:10593
+msgid "B"
+msgstr "B"
+
+#: gitk:10596
+msgid "I"
+msgstr "I"
+
+#: gitk:10714
+msgid "Gitk preferences"
+msgstr "Preferências do Gitk"
+
+#: gitk:10716
+msgid "Commit list display options"
+msgstr "Opções da lista de revisões"
+
+#: gitk:10719
+msgid "Maximum graph width (lines)"
+msgstr "Largura máxima do grafo (linhas)"
+
+#: gitk:10722
+#, tcl-format
+msgid "Maximum graph width (% of pane)"
+msgstr "Largura máxima do grafo (% do painel)"
+
+#: gitk:10725
+msgid "Show local changes"
+msgstr "Exibir mudanças locais"
+
+#: gitk:10728
+msgid "Auto-select SHA1"
+msgstr "Selecionar o SHA1 automaticamente"
+
+#: gitk:10731
+msgid "Hide remote refs"
+msgstr "Ocultar referências remotas"
+
+#: gitk:10735
+msgid "Diff display options"
+msgstr "Opções de exibição das alterações"
+
+#: gitk:10737
+msgid "Tab spacing"
+msgstr "Espaços por tabulação"
+
+#: gitk:10740
+msgid "Display nearby tags"
+msgstr "Exibir etiquetas próximas"
+
+#: gitk:10743
+msgid "Limit diffs to listed paths"
+msgstr "Limitar diferenças aos caminhos listados"
+
+#: gitk:10746
+msgid "Support per-file encodings"
+msgstr "Usar codificações distintas por arquivo"
+
+#: gitk:10752 gitk:10832
+msgid "External diff tool"
+msgstr "Ferramenta 'diff' externa"
+
+#: gitk:10753
+msgid "Choose..."
+msgstr "Selecionar..."
+
+#: gitk:10758
+msgid "General options"
+msgstr "Opções gerais"
+
+#: gitk:10761
+msgid "Use themed widgets"
+msgstr "Usar temas para as janelas"
+
+#: gitk:10763
+msgid "(change requires restart)"
+msgstr "(exige reinicialização)"
+
+#: gitk:10765
+msgid "(currently unavailable)"
+msgstr "(atualmente indisponível)"
+
+#: gitk:10769
+msgid "Colors: press to choose"
+msgstr "Cores: clique para escolher"
+
+#: gitk:10772
+msgid "Interface"
+msgstr "Interface"
+
+#: gitk:10773
+msgid "interface"
+msgstr "interface"
+
+#: gitk:10776
+msgid "Background"
+msgstr "Segundo plano"
+
+#: gitk:10777 gitk:10807
+msgid "background"
+msgstr "segundo plano"
+
+#: gitk:10780
+msgid "Foreground"
+msgstr "Primeiro plano"
+
+#: gitk:10781
+msgid "foreground"
+msgstr "primeiro plano"
+
+#: gitk:10784
+msgid "Diff: old lines"
+msgstr "Diff: linhas excluídas"
+
+#: gitk:10785
+msgid "diff old lines"
+msgstr "linhas excluídas"
+
+#: gitk:10789
+msgid "Diff: new lines"
+msgstr "Diff: linhas adicionadas"
+
+#: gitk:10790
+msgid "diff new lines"
+msgstr "linhas adicionadas"
+
+#: gitk:10794
+msgid "Diff: hunk header"
+msgstr "Diff: cabeçalho do bloco"
+
+#: gitk:10796
+msgid "diff hunk header"
+msgstr "cabeçalho do bloco"
+
+#: gitk:10800
+msgid "Marked line bg"
+msgstr "2º plano da linha marcada"
+
+#: gitk:10802
+msgid "marked line background"
+msgstr "segundo plano da linha marcada"
+
+#: gitk:10806
+msgid "Select bg"
+msgstr "2º plano da seleção"
+
+#: gitk:10810
+msgid "Fonts: press to choose"
+msgstr "Fontes: clique para escolher"
+
+#: gitk:10812
+msgid "Main font"
+msgstr "Fonte principal"
+
+#: gitk:10813
+msgid "Diff display font"
+msgstr "Fonte da lista de mudanças"
+
+#: gitk:10814
+msgid "User interface font"
+msgstr "Fonte da interface"
+
+#: gitk:10842
+#, tcl-format
+msgid "Gitk: choose color for %s"
+msgstr "Gitk: selecionar cor para %s"
+
+#: gitk:11445
+msgid "Cannot find a git repository here."
+msgstr "Não há nenhum repositório git aqui."
+
+#: gitk:11449
+#, tcl-format
+msgid "Cannot find the git directory \"%s\"."
+msgstr "Impossível encontrar o diretório git \"%s\"."
+
+#: gitk:11496
+#, tcl-format
+msgid "Ambiguous argument '%s': both revision and filename"
+msgstr ""
+"O argumento \"%s\" é ambíguo (especifica tanto uma revisão e um nome de "
+"arquivo)"
+
+#: gitk:11508
+msgid "Bad arguments to gitk:"
+msgstr "Argumentos incorretos para o gitk:"
+
+#: gitk:11604
+msgid "Command line"
+msgstr "Linha de comando"
index 386763ade786d96b657dd0ab737b633eef44b424..2f07a2e2d93d655cfe5cf2d3535e7b86422233c6 100644 (file)
@@ -1,5 +1,5 @@
 # Swedish translation for gitk
-# Copyright (C) 2005-2009 Paul Mackerras
+# Copyright (C) 2005-2010 Paul Mackerras
 # This file is distributed under the same license as the gitk package.
 #
 # Peter Krefting <peter@softwolves.pp.se>, 2008-2010.
@@ -8,8 +8,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: sv\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-01-28 13:16+0100\n"
-"PO-Revision-Date: 2010-01-28 13:48+0100\n"
+"POT-Creation-Date: 2010-09-12 21:14+0100\n"
+"PO-Revision-Date: 2010-09-12 21:16+0100\n"
 "Last-Translator: Peter Krefting <peter@softwolves.pp.se>\n"
 "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
 "MIME-Version: 1.0\n"
@@ -24,17 +24,17 @@ msgstr "Kunde inte hämta lista över ej sammanslagna filer:"
 msgid "Error parsing revisions:"
 msgstr "Fel vid tolkning av revisioner:"
 
-#: gitk:329
+#: gitk:330
 msgid "Error executing --argscmd command:"
 msgstr "Fel vid körning av --argscmd-kommando:"
 
-#: gitk:342
+#: gitk:343
 msgid "No files selected: --merge specified but no files are unmerged."
 msgstr ""
 "Inga filer valdes: --merge angavs men det finns inga filer som inte har "
 "slagits samman."
 
-#: gitk:345
+#: gitk:346
 msgid ""
 "No files selected: --merge specified but no unmerged files are within file "
 "limit."
@@ -42,600 +42,605 @@ msgstr ""
 "Inga filer valdes: --merge angavs men det finns inga filer inom "
 "filbegränsningen."
 
-#: gitk:367 gitk:514
+#: gitk:368 gitk:516
 msgid "Error executing git log:"
 msgstr "Fel vid körning av git log:"
 
-#: gitk:385 gitk:530
+#: gitk:386 gitk:532
 msgid "Reading"
 msgstr "Läser"
 
-#: gitk:445 gitk:4261
+#: gitk:446 gitk:4271
 msgid "Reading commits..."
 msgstr "Läser incheckningar..."
 
-#: gitk:448 gitk:1578 gitk:4264
+#: gitk:449 gitk:1580 gitk:4274
 msgid "No commits selected"
 msgstr "Inga incheckningar markerade"
 
-#: gitk:1454
+#: gitk:1456
 msgid "Can't parse git log output:"
 msgstr "Kan inte tolka utdata från git log:"
 
-#: gitk:1674
+#: gitk:1676
 msgid "No commit information available"
 msgstr "Ingen incheckningsinformation är tillgänglig"
 
-#: gitk:1816
+#: gitk:1818
 msgid "mc"
 msgstr "mc"
 
-#: gitk:1851 gitk:4054 gitk:9044 gitk:10585 gitk:10804
+#: gitk:1853 gitk:4064 gitk:9067 gitk:10607 gitk:10817
 msgid "OK"
 msgstr "OK"
 
-#: gitk:1853 gitk:4056 gitk:8634 gitk:8713 gitk:8828 gitk:8877 gitk:9046
-#: gitk:10586 gitk:10805
+#: gitk:1855 gitk:4066 gitk:8657 gitk:8736 gitk:8851 gitk:8900 gitk:9069
+#: gitk:10608 gitk:10818
 msgid "Cancel"
 msgstr "Avbryt"
 
-#: gitk:1975
+#: gitk:1980
 msgid "Update"
 msgstr "Uppdatera"
 
-#: gitk:1976
+#: gitk:1981
 msgid "Reload"
 msgstr "Ladda om"
 
-#: gitk:1977
+#: gitk:1982
 msgid "Reread references"
 msgstr "Läs om referenser"
 
-#: gitk:1978
+#: gitk:1983
 msgid "List references"
 msgstr "Visa referenser"
 
-#: gitk:1980
+#: gitk:1985
 msgid "Start git gui"
 msgstr "Starta git gui"
 
-#: gitk:1982
+#: gitk:1987
 msgid "Quit"
 msgstr "Avsluta"
 
-#: gitk:1974
+#: gitk:1979
 msgid "File"
 msgstr "Arkiv"
 
-#: gitk:1986
+#: gitk:1991
 msgid "Preferences"
 msgstr "Inställningar"
 
-#: gitk:1985
+#: gitk:1990
 msgid "Edit"
 msgstr "Redigera"
 
-#: gitk:1990
+#: gitk:1995
 msgid "New view..."
 msgstr "Ny vy..."
 
-#: gitk:1991
+#: gitk:1996
 msgid "Edit view..."
 msgstr "Ändra vy..."
 
-#: gitk:1992
+#: gitk:1997
 msgid "Delete view"
 msgstr "Ta bort vy"
 
-#: gitk:1994
+#: gitk:1999
 msgid "All files"
 msgstr "Alla filer"
 
-#: gitk:1989 gitk:3808
+#: gitk:1994 gitk:3817
 msgid "View"
 msgstr "Visa"
 
-#: gitk:1999 gitk:2009 gitk:2780
+#: gitk:2004 gitk:2014 gitk:2787
 msgid "About gitk"
 msgstr "Om gitk"
 
-#: gitk:2000 gitk:2014
+#: gitk:2005 gitk:2019
 msgid "Key bindings"
 msgstr "Tangentbordsbindningar"
 
-#: gitk:1998 gitk:2013
+#: gitk:2003 gitk:2018
 msgid "Help"
 msgstr "Hjälp"
 
-#: gitk:2091 gitk:8110
+#: gitk:2096 gitk:8132
 msgid "SHA1 ID:"
 msgstr "SHA1-id:"
 
-#: gitk:2122
+#: gitk:2127
 msgid "Row"
 msgstr "Rad"
 
-#: gitk:2160
+#: gitk:2165
 msgid "Find"
 msgstr "Sök"
 
-#: gitk:2161
+#: gitk:2166
 msgid "next"
 msgstr "nästa"
 
-#: gitk:2162
+#: gitk:2167
 msgid "prev"
 msgstr "föreg"
 
-#: gitk:2163
+#: gitk:2168
 msgid "commit"
 msgstr "incheckning"
 
-#: gitk:2166 gitk:2168 gitk:4422 gitk:4445 gitk:4469 gitk:6410 gitk:6482
-#: gitk:6566
+#: gitk:2171 gitk:2173 gitk:4432 gitk:4455 gitk:4479 gitk:6420 gitk:6492
+#: gitk:6576
 msgid "containing:"
 msgstr "som innehåller:"
 
-#: gitk:2169 gitk:3290 gitk:3295 gitk:4497
+#: gitk:2174 gitk:3298 gitk:3303 gitk:4507
 msgid "touching paths:"
 msgstr "som rör sökväg:"
 
-#: gitk:2170 gitk:4502
+#: gitk:2175 gitk:4512
 msgid "adding/removing string:"
 msgstr "som lägger/till tar bort sträng:"
 
-#: gitk:2179 gitk:2181
+#: gitk:2184 gitk:2186
 msgid "Exact"
 msgstr "Exakt"
 
-#: gitk:2181 gitk:4577 gitk:6378
+#: gitk:2186 gitk:4587 gitk:6388
 msgid "IgnCase"
 msgstr "IgnVersaler"
 
-#: gitk:2181 gitk:4471 gitk:4575 gitk:6374
+#: gitk:2186 gitk:4481 gitk:4585 gitk:6384
 msgid "Regexp"
 msgstr "Reg.uttr."
 
-#: gitk:2183 gitk:2184 gitk:4596 gitk:4626 gitk:4633 gitk:6502 gitk:6570
+#: gitk:2188 gitk:2189 gitk:4606 gitk:4636 gitk:4643 gitk:6512 gitk:6580
 msgid "All fields"
 msgstr "Alla fält"
 
-#: gitk:2184 gitk:4594 gitk:4626 gitk:6441
+#: gitk:2189 gitk:4604 gitk:4636 gitk:6451
 msgid "Headline"
 msgstr "Rubrik"
 
-#: gitk:2185 gitk:4594 gitk:6441 gitk:6570 gitk:7003
+#: gitk:2190 gitk:4604 gitk:6451 gitk:6580 gitk:7013
 msgid "Comments"
 msgstr "Kommentarer"
 
-#: gitk:2185 gitk:4594 gitk:4598 gitk:4633 gitk:6441 gitk:6938 gitk:8285
-#: gitk:8300
+#: gitk:2190 gitk:4604 gitk:4608 gitk:4643 gitk:6451 gitk:6948 gitk:8307
+#: gitk:8322
 msgid "Author"
 msgstr "Författare"
 
-#: gitk:2185 gitk:4594 gitk:6441 gitk:6940
+#: gitk:2190 gitk:4604 gitk:6451 gitk:6950
 msgid "Committer"
 msgstr "Incheckare"
 
-#: gitk:2216
+#: gitk:2221
 msgid "Search"
 msgstr "Sök"
 
-#: gitk:2224
+#: gitk:2229
 msgid "Diff"
 msgstr "Diff"
 
-#: gitk:2226
+#: gitk:2231
 msgid "Old version"
 msgstr "Gammal version"
 
-#: gitk:2228
+#: gitk:2233
 msgid "New version"
 msgstr "Ny version"
 
-#: gitk:2230
+#: gitk:2235
 msgid "Lines of context"
 msgstr "Rader sammanhang"
 
-#: gitk:2240
+#: gitk:2245
 msgid "Ignore space change"
 msgstr "Ignorera ändringar i blanksteg"
 
-#: gitk:2299
+#: gitk:2304
 msgid "Patch"
 msgstr "Patch"
 
-#: gitk:2301
+#: gitk:2306
 msgid "Tree"
 msgstr "Träd"
 
-#: gitk:2456 gitk:2473
+#: gitk:2463 gitk:2480
 msgid "Diff this -> selected"
 msgstr "Diff denna -> markerad"
 
-#: gitk:2457 gitk:2474
+#: gitk:2464 gitk:2481
 msgid "Diff selected -> this"
 msgstr "Diff markerad -> denna"
 
-#: gitk:2458 gitk:2475
+#: gitk:2465 gitk:2482
 msgid "Make patch"
 msgstr "Skapa patch"
 
-#: gitk:2459 gitk:8692
+#: gitk:2466 gitk:8715
 msgid "Create tag"
 msgstr "Skapa tagg"
 
-#: gitk:2460 gitk:8808
+#: gitk:2467 gitk:8831
 msgid "Write commit to file"
 msgstr "Skriv incheckning till fil"
 
-#: gitk:2461 gitk:8865
+#: gitk:2468 gitk:8888
 msgid "Create new branch"
 msgstr "Skapa ny gren"
 
-#: gitk:2462
+#: gitk:2469
 msgid "Cherry-pick this commit"
 msgstr "Plocka denna incheckning"
 
-#: gitk:2463
+#: gitk:2470
 msgid "Reset HEAD branch to here"
 msgstr "Återställ HEAD-grenen hit"
 
-#: gitk:2464
+#: gitk:2471
 msgid "Mark this commit"
 msgstr "Markera denna incheckning"
 
-#: gitk:2465
+#: gitk:2472
 msgid "Return to mark"
 msgstr "Återgå till markering"
 
-#: gitk:2466
+#: gitk:2473
 msgid "Find descendant of this and mark"
 msgstr "Hitta efterföljare till denna och markera"
 
-#: gitk:2467
+#: gitk:2474
 msgid "Compare with marked commit"
 msgstr "Jämför med markerad incheckning"
 
-#: gitk:2481
+#: gitk:2488
 msgid "Check out this branch"
 msgstr "Checka ut denna gren"
 
-#: gitk:2482
+#: gitk:2489
 msgid "Remove this branch"
 msgstr "Ta bort denna gren"
 
-#: gitk:2489
+#: gitk:2496
 msgid "Highlight this too"
 msgstr "Markera även detta"
 
-#: gitk:2490
+#: gitk:2497
 msgid "Highlight this only"
 msgstr "Markera bara detta"
 
-#: gitk:2491
+#: gitk:2498
 msgid "External diff"
 msgstr "Extern diff"
 
-#: gitk:2492
+#: gitk:2499
 msgid "Blame parent commit"
 msgstr "Klandra föräldraincheckning"
 
-#: gitk:2499
+#: gitk:2506
 msgid "Show origin of this line"
 msgstr "Visa ursprunget för den här raden"
 
-#: gitk:2500
+#: gitk:2507
 msgid "Run git gui blame on this line"
 msgstr "Kör git gui blame på den här raden"
 
-#: gitk:2782
+#: gitk:2789
 msgid ""
 "\n"
 "Gitk - a commit viewer for git\n"
 "\n"
-"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
+"Copyright ©9 2005-2010 Paul Mackerras\n"
 "\n"
 "Use and redistribute under the terms of the GNU General Public License"
 msgstr ""
 "\n"
 "Gitk - en incheckningsvisare för git\n"
 "\n"
-"Copyright \\u00a9 2005-2010 Paul Mackerras\n"
+"Copyright ©9 2005-2010 Paul Mackerras\n"
 "\n"
 "Använd och vidareförmedla enligt villkoren i GNU General Public License"
 
-#: gitk:2790 gitk:2854 gitk:9230
+#: gitk:2797 gitk:2862 gitk:9253
 msgid "Close"
 msgstr "Stäng"
 
-#: gitk:2811
+#: gitk:2818
 msgid "Gitk key bindings"
 msgstr "Tangentbordsbindningar för Gitk"
 
-#: gitk:2814
+#: gitk:2821
 msgid "Gitk key bindings:"
 msgstr "Tangentbordsbindningar för Gitk:"
 
-#: gitk:2816
+#: gitk:2823
 #, tcl-format
 msgid "<%s-Q>\t\tQuit"
 msgstr "<%s-Q>\t\tAvsluta"
 
-#: gitk:2817
+#: gitk:2824
+#, tcl-format
+msgid "<%s-W>\t\tClose window"
+msgstr "<%s-W>\t\tStäng fönster"
+
+#: gitk:2825
 msgid "<Home>\t\tMove to first commit"
 msgstr "<Home>\t\tGå till första incheckning"
 
-#: gitk:2818
+#: gitk:2826
 msgid "<End>\t\tMove to last commit"
 msgstr "<End>\t\tGå till sista incheckning"
 
-#: gitk:2819
+#: gitk:2827
 msgid "<Up>, p, i\tMove up one commit"
 msgstr "<Upp>, p, i\tGå en incheckning upp"
 
-#: gitk:2820
+#: gitk:2828
 msgid "<Down>, n, k\tMove down one commit"
 msgstr "<Ned>, n, k\tGå en incheckning ned"
 
-#: gitk:2821
+#: gitk:2829
 msgid "<Left>, z, j\tGo back in history list"
 msgstr "<Vänster>, z, j\tGå bakåt i historiken"
 
-#: gitk:2822
+#: gitk:2830
 msgid "<Right>, x, l\tGo forward in history list"
 msgstr "<Höger>, x, l\tGå framåt i historiken"
 
-#: gitk:2823
+#: gitk:2831
 msgid "<PageUp>\tMove up one page in commit list"
 msgstr "<PageUp>\tGå upp en sida i incheckningslistan"
 
-#: gitk:2824
+#: gitk:2832
 msgid "<PageDown>\tMove down one page in commit list"
 msgstr "<PageDown>\tGå ned en sida i incheckningslistan"
 
-#: gitk:2825
+#: gitk:2833
 #, tcl-format
 msgid "<%s-Home>\tScroll to top of commit list"
 msgstr "<%s-Home>\tRulla till början av incheckningslistan"
 
-#: gitk:2826
+#: gitk:2834
 #, tcl-format
 msgid "<%s-End>\tScroll to bottom of commit list"
 msgstr "<%s-End>\tRulla till slutet av incheckningslistan"
 
-#: gitk:2827
+#: gitk:2835
 #, tcl-format
 msgid "<%s-Up>\tScroll commit list up one line"
 msgstr "<%s-Upp>\tRulla incheckningslistan upp ett steg"
 
-#: gitk:2828
+#: gitk:2836
 #, tcl-format
 msgid "<%s-Down>\tScroll commit list down one line"
 msgstr "<%s-Ned>\tRulla incheckningslistan ned ett steg"
 
-#: gitk:2829
+#: gitk:2837
 #, tcl-format
 msgid "<%s-PageUp>\tScroll commit list up one page"
 msgstr "<%s-PageUp>\tRulla incheckningslistan upp en sida"
 
-#: gitk:2830
+#: gitk:2838
 #, tcl-format
 msgid "<%s-PageDown>\tScroll commit list down one page"
 msgstr "<%s-PageDown>\tRulla incheckningslistan ned en sida"
 
-#: gitk:2831
+#: gitk:2839
 msgid "<Shift-Up>\tFind backwards (upwards, later commits)"
 msgstr "<Skift-Upp>\tSök bakåt (uppåt, senare incheckningar)"
 
-#: gitk:2832
+#: gitk:2840
 msgid "<Shift-Down>\tFind forwards (downwards, earlier commits)"
 msgstr "<Skift-Ned>\tSök framåt (nedåt, tidigare incheckningar)"
 
-#: gitk:2833
+#: gitk:2841
 msgid "<Delete>, b\tScroll diff view up one page"
 msgstr "<Delete>, b\tRulla diffvisningen upp en sida"
 
-#: gitk:2834
+#: gitk:2842
 msgid "<Backspace>\tScroll diff view up one page"
 msgstr "<Baksteg>\tRulla diffvisningen upp en sida"
 
-#: gitk:2835
+#: gitk:2843
 msgid "<Space>\t\tScroll diff view down one page"
 msgstr "<Blanksteg>\tRulla diffvisningen ned en sida"
 
-#: gitk:2836
+#: gitk:2844
 msgid "u\t\tScroll diff view up 18 lines"
 msgstr "u\t\tRulla diffvisningen upp 18 rader"
 
-#: gitk:2837
+#: gitk:2845
 msgid "d\t\tScroll diff view down 18 lines"
 msgstr "d\t\tRulla diffvisningen ned 18 rader"
 
-#: gitk:2838
+#: gitk:2846
 #, tcl-format
 msgid "<%s-F>\t\tFind"
 msgstr "<%s-F>\t\tSök"
 
-#: gitk:2839
+#: gitk:2847
 #, tcl-format
 msgid "<%s-G>\t\tMove to next find hit"
 msgstr "<%s-G>\t\tGå till nästa sökträff"
 
-#: gitk:2840
+#: gitk:2848
 msgid "<Return>\tMove to next find hit"
 msgstr "<Return>\t\tGå till nästa sökträff"
 
-#: gitk:2841
+#: gitk:2849
 msgid "/\t\tFocus the search box"
 msgstr "/\t\tFokusera sökrutan"
 
-#: gitk:2842
+#: gitk:2850
 msgid "?\t\tMove to previous find hit"
 msgstr "?\t\tGå till föregående sökträff"
 
-#: gitk:2843
+#: gitk:2851
 msgid "f\t\tScroll diff view to next file"
 msgstr "f\t\tRulla diffvisningen till nästa fil"
 
-#: gitk:2844
+#: gitk:2852
 #, tcl-format
 msgid "<%s-S>\t\tSearch for next hit in diff view"
 msgstr "<%s-S>\t\tGå till nästa sökträff i diffvisningen"
 
-#: gitk:2845
+#: gitk:2853
 #, tcl-format
 msgid "<%s-R>\t\tSearch for previous hit in diff view"
 msgstr "<%s-R>\t\tGå till föregående sökträff i diffvisningen"
 
-#: gitk:2846
+#: gitk:2854
 #, tcl-format
 msgid "<%s-KP+>\tIncrease font size"
 msgstr "<%s-Num+>\tÖka teckenstorlek"
 
-#: gitk:2847
+#: gitk:2855
 #, tcl-format
 msgid "<%s-plus>\tIncrease font size"
 msgstr "<%s-plus>\tÖka teckenstorlek"
 
-#: gitk:2848
+#: gitk:2856
 #, tcl-format
 msgid "<%s-KP->\tDecrease font size"
 msgstr "<%s-Num->\tMinska teckenstorlek"
 
-#: gitk:2849
+#: gitk:2857
 #, tcl-format
 msgid "<%s-minus>\tDecrease font size"
 msgstr "<%s-minus>\tMinska teckenstorlek"
 
-#: gitk:2850
+#: gitk:2858
 msgid "<F5>\t\tUpdate"
 msgstr "<F5>\t\tUppdatera"
 
-#: gitk:3305 gitk:3314
+#: gitk:3313 gitk:3322
 #, tcl-format
 msgid "Error creating temporary directory %s:"
 msgstr "Fel vid skapande av temporär katalog %s:"
 
-#: gitk:3327
+#: gitk:3335
 #, tcl-format
 msgid "Error getting \"%s\" from %s:"
 msgstr "Fel vid hämtning av  \"%s\" från %s:"
 
-#: gitk:3390
+#: gitk:3398
 msgid "command failed:"
 msgstr "kommando misslyckades:"
 
-#: gitk:3539
+#: gitk:3547
 msgid "No such commit"
 msgstr "Incheckning saknas"
 
-#: gitk:3553
+#: gitk:3561
 msgid "git gui blame: command failed:"
 msgstr "git gui blame: kommando misslyckades:"
 
-#: gitk:3584
+#: gitk:3592
 #, tcl-format
 msgid "Couldn't read merge head: %s"
 msgstr "Kunde inte läsa sammanslagningshuvud: %s"
 
-#: gitk:3592
+#: gitk:3600
 #, tcl-format
 msgid "Error reading index: %s"
 msgstr "Fel vid läsning av index: %s"
 
-#: gitk:3617
+#: gitk:3625
 #, tcl-format
 msgid "Couldn't start git blame: %s"
 msgstr "Kunde inte starta git blame: %s"
 
-#: gitk:3620 gitk:6409
+#: gitk:3628 gitk:6419
 msgid "Searching"
 msgstr "Söker"
 
-#: gitk:3652
+#: gitk:3660
 #, tcl-format
 msgid "Error running git blame: %s"
 msgstr "Fel vid körning av git blame: %s"
 
-#: gitk:3680
+#: gitk:3688
 #, tcl-format
 msgid "That line comes from commit %s,  which is not in this view"
 msgstr "Raden kommer från incheckningen %s, som inte finns i denna vy"
 
-#: gitk:3694
+#: gitk:3702
 msgid "External diff viewer failed:"
 msgstr "Externt diff-verktyg misslyckades:"
 
-#: gitk:3812
+#: gitk:3820
 msgid "Gitk view definition"
 msgstr "Definition av Gitk-vy"
 
-#: gitk:3816
+#: gitk:3824
 msgid "Remember this view"
 msgstr "Spara denna vy"
 
-#: gitk:3817
+#: gitk:3825
 msgid "References (space separated list):"
 msgstr "Referenser (blankstegsavdelad lista):"
 
-#: gitk:3818
+#: gitk:3826
 msgid "Branches & tags:"
 msgstr "Grenar & taggar:"
 
-#: gitk:3819
+#: gitk:3827
 msgid "All refs"
 msgstr "Alla referenser"
 
-#: gitk:3820
+#: gitk:3828
 msgid "All (local) branches"
 msgstr "Alla (lokala) grenar"
 
-#: gitk:3821
+#: gitk:3829
 msgid "All tags"
 msgstr "Alla taggar"
 
-#: gitk:3822
+#: gitk:3830
 msgid "All remote-tracking branches"
 msgstr "Alla fjärrspårande grenar"
 
-#: gitk:3823
+#: gitk:3831
 msgid "Commit Info (regular expressions):"
 msgstr "Incheckningsinfo (reguljära uttryck):"
 
-#: gitk:3824
+#: gitk:3832
 msgid "Author:"
 msgstr "Författare:"
 
-#: gitk:3825
+#: gitk:3833
 msgid "Committer:"
 msgstr "Incheckare:"
 
-#: gitk:3826
+#: gitk:3834
 msgid "Commit Message:"
 msgstr "Incheckningsmeddelande:"
 
-#: gitk:3827
+#: gitk:3835
 msgid "Matches all Commit Info criteria"
 msgstr "Motsvarar alla kriterier för incheckningsinfo"
 
-#: gitk:3828
+#: gitk:3836
 msgid "Changes to Files:"
 msgstr "Ändringar av filer:"
 
-#: gitk:3829
+#: gitk:3837
 msgid "Fixed String"
 msgstr "Fast sträng"
 
-#: gitk:3830
+#: gitk:3838
 msgid "Regular Expression"
 msgstr "Reguljärt uttryck"
 
-#: gitk:3831
+#: gitk:3839
 msgid "Search string:"
 msgstr "Söksträng:"
 
-#: gitk:3832
+#: gitk:3840
 msgid ""
 "Commit Dates (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 "
 "15:27:38\"):"
@@ -643,201 +648,201 @@ msgstr ""
 "Incheckingsdatum (\"2 weeks ago\", \"2009-03-17 15:27:38\", \"March 17, 2009 "
 "15:27:38\"):"
 
-#: gitk:3833
+#: gitk:3841
 msgid "Since:"
 msgstr "Från:"
 
-#: gitk:3834
+#: gitk:3842
 msgid "Until:"
 msgstr "Till:"
 
-#: gitk:3835
+#: gitk:3843
 msgid "Limit and/or skip a number of revisions (positive integer):"
 msgstr "Begränsa och/eller hoppa över ett antal revisioner (positivt heltal):"
 
-#: gitk:3836
+#: gitk:3844
 msgid "Number to show:"
 msgstr "Antal att visa:"
 
-#: gitk:3837
+#: gitk:3845
 msgid "Number to skip:"
 msgstr "Antal att hoppa över:"
 
-#: gitk:3838
+#: gitk:3846
 msgid "Miscellaneous options:"
 msgstr "Diverse alternativ:"
 
-#: gitk:3839
+#: gitk:3847
 msgid "Strictly sort by date"
 msgstr "Strikt datumsortering"
 
-#: gitk:3840
+#: gitk:3848
 msgid "Mark branch sides"
 msgstr "Markera sidogrenar"
 
-#: gitk:3841
+#: gitk:3849
 msgid "Limit to first parent"
 msgstr "Begränsa till första förälder"
 
-#: gitk:3842
+#: gitk:3850
 msgid "Simple history"
 msgstr "Enkel historik"
 
-#: gitk:3843
+#: gitk:3851
 msgid "Additional arguments to git log:"
 msgstr "Ytterligare argument till git log:"
 
-#: gitk:3844
+#: gitk:3852
 msgid "Enter files and directories to include, one per line:"
 msgstr "Ange filer och kataloger att ta med, en per rad:"
 
-#: gitk:3845
+#: gitk:3853
 msgid "Command to generate more commits to include:"
 msgstr "Kommando för att generera fler incheckningar att ta med:"
 
-#: gitk:3967
+#: gitk:3977
 msgid "Gitk: edit view"
 msgstr "Gitk: redigera vy"
 
-#: gitk:3975
+#: gitk:3985
 msgid "-- criteria for selecting revisions"
 msgstr " - kriterier för val av revisioner"
 
-#: gitk:3980
+#: gitk:3990
 msgid "View Name"
 msgstr "Namn på vy"
 
-#: gitk:4055
+#: gitk:4065
 msgid "Apply (F5)"
 msgstr "Använd (F5)"
 
-#: gitk:4093
+#: gitk:4103
 msgid "Error in commit selection arguments:"
 msgstr "Fel i argument för val av incheckningar:"
 
-#: gitk:4146 gitk:4198 gitk:4646 gitk:4660 gitk:5921 gitk:11534 gitk:11535
+#: gitk:4156 gitk:4208 gitk:4656 gitk:4670 gitk:5931 gitk:11551 gitk:11552
 msgid "None"
 msgstr "Inget"
 
-#: gitk:4594 gitk:6441 gitk:8287 gitk:8302
+#: gitk:4604 gitk:6451 gitk:8309 gitk:8324
 msgid "Date"
 msgstr "Datum"
 
-#: gitk:4594 gitk:6441
+#: gitk:4604 gitk:6451
 msgid "CDate"
 msgstr "Skapat datum"
 
-#: gitk:4743 gitk:4748
+#: gitk:4753 gitk:4758
 msgid "Descendant"
 msgstr "Avkomling"
 
-#: gitk:4744
+#: gitk:4754
 msgid "Not descendant"
 msgstr "Inte avkomling"
 
-#: gitk:4751 gitk:4756
+#: gitk:4761 gitk:4766
 msgid "Ancestor"
 msgstr "Förfader"
 
-#: gitk:4752
+#: gitk:4762
 msgid "Not ancestor"
 msgstr "Inte förfader"
 
-#: gitk:5042
+#: gitk:5052
 msgid "Local changes checked in to index but not committed"
 msgstr "Lokala ändringar sparade i indexet men inte incheckade"
 
-#: gitk:5078
+#: gitk:5088
 msgid "Local uncommitted changes, not checked in to index"
 msgstr "Lokala ändringar, ej sparade i indexet"
 
-#: gitk:6759
+#: gitk:6769
 msgid "many"
 msgstr "många"
 
-#: gitk:6942
+#: gitk:6952
 msgid "Tags:"
 msgstr "Taggar:"
 
-#: gitk:6959 gitk:6965 gitk:8280
+#: gitk:6969 gitk:6975 gitk:8302
 msgid "Parent"
 msgstr "Förälder"
 
-#: gitk:6970
+#: gitk:6980
 msgid "Child"
 msgstr "Barn"
 
-#: gitk:6979
+#: gitk:6989
 msgid "Branch"
 msgstr "Gren"
 
-#: gitk:6982
+#: gitk:6992
 msgid "Follows"
 msgstr "Följer"
 
-#: gitk:6985
+#: gitk:6995
 msgid "Precedes"
 msgstr "Föregår"
 
-#: gitk:7522
+#: gitk:7532
 #, tcl-format
 msgid "Error getting diffs: %s"
 msgstr "Fel vid hämtning av diff: %s"
 
-#: gitk:8108
+#: gitk:8130
 msgid "Goto:"
 msgstr "Gå till:"
 
-#: gitk:8129
+#: gitk:8151
 #, tcl-format
 msgid "Short SHA1 id %s is ambiguous"
 msgstr "Förkortat SHA1-id %s är tvetydigt"
 
-#: gitk:8136
+#: gitk:8158
 #, tcl-format
 msgid "Revision %s is not known"
 msgstr "Revisionen %s är inte känd"
 
-#: gitk:8146
+#: gitk:8168
 #, tcl-format
 msgid "SHA1 id %s is not known"
 msgstr "SHA-id:t %s är inte känt"
 
-#: gitk:8148
+#: gitk:8170
 #, tcl-format
 msgid "Revision %s is not in the current view"
 msgstr "Revisionen %s finns inte i den nuvarande vyn"
 
-#: gitk:8290
+#: gitk:8312
 msgid "Children"
 msgstr "Barn"
 
-#: gitk:8348
+#: gitk:8370
 #, tcl-format
 msgid "Reset %s branch to here"
 msgstr "Återställ grenen %s hit"
 
-#: gitk:8350
+#: gitk:8372
 msgid "Detached head: can't reset"
 msgstr "Frånkopplad head: kan inte återställa"
 
-#: gitk:8459 gitk:8465
+#: gitk:8481 gitk:8487
 msgid "Skipping merge commit "
 msgstr "Hoppar över sammanslagningsincheckning "
 
-#: gitk:8474 gitk:8479
+#: gitk:8496 gitk:8501
 msgid "Error getting patch ID for "
 msgstr "Fel vid hämtning av patch-id för "
 
-#: gitk:8475 gitk:8480
+#: gitk:8497 gitk:8502
 msgid " - stopping\n"
 msgstr " - stannar\n"
 
-#: gitk:8485 gitk:8488 gitk:8496 gitk:8510 gitk:8519
+#: gitk:8507 gitk:8510 gitk:8518 gitk:8532 gitk:8541
 msgid "Commit "
 msgstr "Incheckning "
 
-#: gitk:8489
+#: gitk:8511
 msgid ""
 " is the same patch as\n"
 "       "
@@ -845,7 +850,7 @@ msgstr ""
 " är samma patch som\n"
 "       "
 
-#: gitk:8497
+#: gitk:8519
 msgid ""
 " differs from\n"
 "       "
@@ -853,139 +858,139 @@ msgstr ""
 " skiljer sig från\n"
 "       "
 
-#: gitk:8499
+#: gitk:8521
 msgid ""
 "Diff of commits:\n"
 "\n"
-msgstr "Skillnad mellan incheckningar:\n"
+msgstr ""
+"Skillnad mellan incheckningar:\n"
 "\n"
-""
 
-#: gitk:8511 gitk:8520
+#: gitk:8533 gitk:8542
 #, tcl-format
 msgid " has %s children - stopping\n"
 msgstr " har %s barn - stannar\n"
 
-#: gitk:8539
+#: gitk:8561
 #, tcl-format
 msgid "Error writing commit to file: %s"
 msgstr "Fel vid skrivning av incheckning till fil: %s"
 
-#: gitk:8545
+#: gitk:8567
 #, tcl-format
 msgid "Error diffing commits: %s"
 msgstr "Fel vid jämförelse av incheckningar: %s"
 
-#: gitk:8575
+#: gitk:8598
 msgid "Top"
 msgstr "Topp"
 
-#: gitk:8576
+#: gitk:8599
 msgid "From"
 msgstr "Från"
 
-#: gitk:8581
+#: gitk:8604
 msgid "To"
 msgstr "Till"
 
-#: gitk:8605
+#: gitk:8628
 msgid "Generate patch"
 msgstr "Generera patch"
 
-#: gitk:8607
+#: gitk:8630
 msgid "From:"
 msgstr "Från:"
 
-#: gitk:8616
+#: gitk:8639
 msgid "To:"
 msgstr "Till:"
 
-#: gitk:8625
+#: gitk:8648
 msgid "Reverse"
 msgstr "Vänd"
 
-#: gitk:8627 gitk:8822
+#: gitk:8650 gitk:8845
 msgid "Output file:"
 msgstr "Utdatafil:"
 
-#: gitk:8633
+#: gitk:8656
 msgid "Generate"
 msgstr "Generera"
 
-#: gitk:8671
+#: gitk:8694
 msgid "Error creating patch:"
 msgstr "Fel vid generering av patch:"
 
-#: gitk:8694 gitk:8810 gitk:8867
+#: gitk:8717 gitk:8833 gitk:8890
 msgid "ID:"
 msgstr "Id:"
 
-#: gitk:8703
+#: gitk:8726
 msgid "Tag name:"
 msgstr "Taggnamn:"
 
-#: gitk:8706
+#: gitk:8729
 msgid "Tag message is optional"
 msgstr "Taggmeddelandet är valfritt"
 
-#: gitk:8708
+#: gitk:8731
 msgid "Tag message:"
 msgstr "Taggmeddelande:"
 
-#: gitk:8712 gitk:8876
+#: gitk:8735 gitk:8899
 msgid "Create"
 msgstr "Skapa"
 
-#: gitk:8730
+#: gitk:8753
 msgid "No tag name specified"
 msgstr "Inget taggnamn angavs"
 
-#: gitk:8734
+#: gitk:8757
 #, tcl-format
 msgid "Tag \"%s\" already exists"
 msgstr "Taggen \"%s\" finns redan"
 
-#: gitk:8744
+#: gitk:8767
 msgid "Error creating tag:"
 msgstr "Fel vid skapande av tagg:"
 
-#: gitk:8819
+#: gitk:8842
 msgid "Command:"
 msgstr "Kommando:"
 
-#: gitk:8827
+#: gitk:8850
 msgid "Write"
 msgstr "Skriv"
 
-#: gitk:8845
+#: gitk:8868
 msgid "Error writing commit:"
 msgstr "Fel vid skrivning av incheckning:"
 
-#: gitk:8872
+#: gitk:8895
 msgid "Name:"
 msgstr "Namn:"
 
-#: gitk:8895
+#: gitk:8918
 msgid "Please specify a name for the new branch"
 msgstr "Ange ett namn för den nya grenen"
 
-#: gitk:8900
+#: gitk:8923
 #, tcl-format
 msgid "Branch '%s' already exists. Overwrite?"
 msgstr "Grenen \"%s\" finns redan. Skriva över?"
 
-#: gitk:8966
+#: gitk:8989
 #, tcl-format
 msgid "Commit %s is already included in branch %s -- really re-apply it?"
 msgstr ""
 "Incheckningen %s finns redan på grenen %s -- skall den verkligen appliceras "
 "på nytt?"
 
-#: gitk:8971
+#: gitk:8994
 msgid "Cherry-picking"
 msgstr "Plockar"
 
-#: gitk:8980
+#: gitk:9003
 #, tcl-format
 msgid ""
 "Cherry-pick failed because of local changes to file '%s'.\n"
@@ -995,7 +1000,7 @@ msgstr ""
 "Checka in, återställ eller spara undan (stash) dina ändringar och försök "
 "igen."
 
-#: gitk:8986
+#: gitk:9009
 msgid ""
 "Cherry-pick failed because of merge conflict.\n"
 "Do you wish to run git citool to resolve it?"
@@ -1003,32 +1008,32 @@ msgstr ""
 "Cherry-pick misslyckades på grund av en sammanslagningskonflikt.\n"
 "Vill du köra git citool för att lösa den?"
 
-#: gitk:9002
+#: gitk:9025
 msgid "No changes committed"
 msgstr "Inga ändringar incheckade"
 
-#: gitk:9028
+#: gitk:9051
 msgid "Confirm reset"
 msgstr "Bekräfta återställning"
 
-#: gitk:9030
+#: gitk:9053
 #, tcl-format
 msgid "Reset branch %s to %s?"
 msgstr "Återställa grenen %s till %s?"
 
-#: gitk:9032
+#: gitk:9055
 msgid "Reset type:"
 msgstr "Typ av återställning:"
 
-#: gitk:9035
+#: gitk:9058
 msgid "Soft: Leave working tree and index untouched"
 msgstr "Mjuk: Rör inte utcheckning och index"
 
-#: gitk:9038
+#: gitk:9061
 msgid "Mixed: Leave working tree untouched, reset index"
 msgstr "Blandad: Rör inte utcheckning, återställ index"
 
-#: gitk:9041
+#: gitk:9064
 msgid ""
 "Hard: Reset working tree and index\n"
 "(discard ALL local changes)"
@@ -1036,19 +1041,19 @@ msgstr ""
 "Hård: Återställ utcheckning och index\n"
 "(förkastar ALLA lokala ändringar)"
 
-#: gitk:9058
+#: gitk:9081
 msgid "Resetting"
 msgstr "Återställer"
 
-#: gitk:9118
+#: gitk:9141
 msgid "Checking out"
 msgstr "Checkar ut"
 
-#: gitk:9171
+#: gitk:9194
 msgid "Cannot delete the currently checked-out branch"
 msgstr "Kan inte ta bort den just nu utcheckade grenen"
 
-#: gitk:9177
+#: gitk:9200
 #, tcl-format
 msgid ""
 "The commits on branch %s aren't on any other branch.\n"
@@ -1057,16 +1062,16 @@ msgstr ""
 "Incheckningarna på grenen %s existerar inte på någon annan gren.\n"
 "Vill du verkligen ta bort grenen %s?"
 
-#: gitk:9208
+#: gitk:9231
 #, tcl-format
 msgid "Tags and heads: %s"
 msgstr "Taggar och huvuden: %s"
 
-#: gitk:9223
+#: gitk:9246
 msgid "Filter"
 msgstr "Filter"
 
-#: gitk:9518
+#: gitk:9541
 msgid ""
 "Error reading commit topology information; branch and preceding/following "
 "tag information will be incomplete."
@@ -1074,203 +1079,203 @@ msgstr ""
 "Fel vid läsning av information om incheckningstopologi; information om "
 "grenar och föregående/senare taggar kommer inte vara komplett."
 
-#: gitk:10504
+#: gitk:10527
 msgid "Tag"
 msgstr "Tagg"
 
-#: gitk:10504
+#: gitk:10527
 msgid "Id"
 msgstr "Id"
 
-#: gitk:10554
+#: gitk:10576
 msgid "Gitk font chooser"
 msgstr "Teckensnittsväljare för Gitk"
 
-#: gitk:10571
+#: gitk:10593
 msgid "B"
 msgstr "F"
 
-#: gitk:10574
+#: gitk:10596
 msgid "I"
 msgstr "K"
 
-#: gitk:10692
+#: gitk:10714
 msgid "Gitk preferences"
 msgstr "Inställningar för Gitk"
 
-#: gitk:10694
+#: gitk:10716
 msgid "Commit list display options"
 msgstr "Alternativ för incheckningslistvy"
 
-#: gitk:10697
+#: gitk:10719
 msgid "Maximum graph width (lines)"
 msgstr "Maximal grafbredd (rader)"
 
-#: gitk:10700
+#: gitk:10722
 #, tcl-format
 msgid "Maximum graph width (% of pane)"
 msgstr "Maximal grafbredd (% av ruta)"
 
-#: gitk:10703
+#: gitk:10725
 msgid "Show local changes"
 msgstr "Visa lokala ändringar"
 
-#: gitk:10706
+#: gitk:10728
 msgid "Auto-select SHA1"
 msgstr "Välj SHA1 automatiskt"
 
-#: gitk:10709
+#: gitk:10731
 msgid "Hide remote refs"
 msgstr "Dölj fjärr-referenser"
 
-#: gitk:10713
+#: gitk:10735
 msgid "Diff display options"
 msgstr "Alternativ för diffvy"
 
-#: gitk:10715
+#: gitk:10737
 msgid "Tab spacing"
 msgstr "Blanksteg för tabulatortecken"
 
-#: gitk:10718
+#: gitk:10740
 msgid "Display nearby tags"
 msgstr "Visa närliggande taggar"
 
-#: gitk:10721
+#: gitk:10743
 msgid "Limit diffs to listed paths"
 msgstr "Begränsa diff till listade sökvägar"
 
-#: gitk:10724
+#: gitk:10746
 msgid "Support per-file encodings"
 msgstr "Stöd för filspecifika teckenkodningar"
 
-#: gitk:10730 gitk:10819
+#: gitk:10752 gitk:10832
 msgid "External diff tool"
 msgstr "Externt diff-verktyg"
 
-#: gitk:10731
+#: gitk:10753
 msgid "Choose..."
 msgstr "Välj..."
 
-#: gitk:10736
+#: gitk:10758
 msgid "General options"
 msgstr "Allmänna inställningar"
 
-#: gitk:10739
+#: gitk:10761
 msgid "Use themed widgets"
 msgstr "Använd tema på fönsterelement"
 
-#: gitk:10741
+#: gitk:10763
 msgid "(change requires restart)"
 msgstr "(ändringen kräver omstart)"
 
-#: gitk:10743
+#: gitk:10765
 msgid "(currently unavailable)"
 msgstr "(för närvarande inte tillgängligt)"
 
-#: gitk:10747
+#: gitk:10769
 msgid "Colors: press to choose"
 msgstr "Färger: tryck för att välja"
 
-#: gitk:10750
+#: gitk:10772
 msgid "Interface"
 msgstr "Gränssnitt"
 
-#: gitk:10751
+#: gitk:10773
 msgid "interface"
 msgstr "gränssnitt"
 
-#: gitk:10754
+#: gitk:10776
 msgid "Background"
 msgstr "Bakgrund"
 
-#: gitk:10755 gitk:10785
+#: gitk:10777 gitk:10807
 msgid "background"
 msgstr "bakgrund"
 
-#: gitk:10758
+#: gitk:10780
 msgid "Foreground"
 msgstr "Förgrund"
 
-#: gitk:10759
+#: gitk:10781
 msgid "foreground"
 msgstr "förgrund"
 
-#: gitk:10762
+#: gitk:10784
 msgid "Diff: old lines"
 msgstr "Diff: gamla rader"
 
-#: gitk:10763
+#: gitk:10785
 msgid "diff old lines"
 msgstr "diff gamla rader"
 
-#: gitk:10767
+#: gitk:10789
 msgid "Diff: new lines"
 msgstr "Diff: nya rader"
 
-#: gitk:10768
+#: gitk:10790
 msgid "diff new lines"
 msgstr "diff nya rader"
 
-#: gitk:10772
+#: gitk:10794
 msgid "Diff: hunk header"
 msgstr "Diff: delhuvud"
 
-#: gitk:10774
+#: gitk:10796
 msgid "diff hunk header"
 msgstr "diff delhuvud"
 
-#: gitk:10778
+#: gitk:10800
 msgid "Marked line bg"
 msgstr "Markerad rad bakgrund"
 
-#: gitk:10780
+#: gitk:10802
 msgid "marked line background"
 msgstr "markerad rad bakgrund"
 
-#: gitk:10784
+#: gitk:10806
 msgid "Select bg"
 msgstr "Markerad bakgrund"
 
-#: gitk:10788
+#: gitk:10810
 msgid "Fonts: press to choose"
 msgstr "Teckensnitt: tryck för att välja"
 
-#: gitk:10790
+#: gitk:10812
 msgid "Main font"
 msgstr "Huvudteckensnitt"
 
-#: gitk:10791
+#: gitk:10813
 msgid "Diff display font"
 msgstr "Teckensnitt för diffvisning"
 
-#: gitk:10792
+#: gitk:10814
 msgid "User interface font"
 msgstr "Teckensnitt för användargränssnitt"
 
-#: gitk:10829
+#: gitk:10842
 #, tcl-format
 msgid "Gitk: choose color for %s"
 msgstr "Gitk: välj färg för %s"
 
-#: gitk:11433
+#: gitk:11445
 msgid "Cannot find a git repository here."
-msgstr "Hittar inget gitk-arkiv här."
+msgstr "Hittar inget git-arkiv här."
 
-#: gitk:11437
+#: gitk:11449
 #, tcl-format
 msgid "Cannot find the git directory \"%s\"."
 msgstr "Hittar inte git-katalogen \"%s\"."
 
-#: gitk:11484
+#: gitk:11496
 #, tcl-format
 msgid "Ambiguous argument '%s': both revision and filename"
 msgstr "Tvetydigt argument \"%s\": både revision och filnamn"
 
-#: gitk:11496
+#: gitk:11508
 msgid "Bad arguments to gitk:"
 msgstr "Felaktiga argument till gitk:"
 
-#: gitk:11587
+#: gitk:11604
 msgid "Command line"
 msgstr "Kommandorad"
 
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 62b2d21b846d8aaa850a451c0248cb71bb6b0741..1b9369d1a72f625bcb66e021bdab8559930cb0eb 100755 (executable)
@@ -250,13 +250,14 @@ sub evaluate_uri {
        # main extensions, defining name of syntax;
        # see files in /usr/share/highlight/langDefs/ directory
        map { $_ => $_ }
-               qw(py c cpp rb java css php sh pl js tex bib xml awk bat ini spec tcl),
+               qw(py c cpp rb java css php sh pl js tex bib xml awk bat ini spec tcl sql make),
        # alternate extensions, see /etc/highlight/filetypes.conf
        'h' => 'c',
+       map { $_ => 'sh'  } qw(bash zsh ksh),
        map { $_ => 'cpp' } qw(cxx c++ cc),
-       map { $_ => 'php' } qw(php3 php4),
+       map { $_ => 'php' } qw(php3 php4 php5 phps),
        map { $_ => 'pl'  } qw(perl pm), # perhaps also 'cgi'
-       'mak' => 'make',
+       map { $_ => 'make'} qw(mak mk),
        map { $_ => 'xml' } qw(xhtml html htm),
 );
 
@@ -1230,7 +1231,7 @@ sub href {
                $href =~ s,/$,,;
 
                # Then add the project name, if present
-               $href .= "/".esc_url($params{'project'});
+               $href .= "/".esc_path_info($params{'project'});
                delete $params{'project'};
 
                # since we destructively absorb parameters, we keep this
@@ -1240,7 +1241,8 @@ sub href {
                # Summary just uses the project path URL, any other action is
                # added to the URL
                if (defined $params{'action'}) {
-                       $href .= "/".esc_url($params{'action'}) unless $params{'action'} eq 'summary';
+                       $href .= "/".esc_path_info($params{'action'})
+                               unless $params{'action'} eq 'summary';
                        delete $params{'action'};
                }
 
@@ -1250,13 +1252,13 @@ sub href {
                        || $params{'hash_parent'} || $params{'hash'});
                if (defined $params{'hash_base'}) {
                        if (defined $params{'hash_parent_base'}) {
-                               $href .= esc_url($params{'hash_parent_base'});
+                               $href .= esc_path_info($params{'hash_parent_base'});
                                # skip the file_parent if it's the same as the file_name
                                if (defined $params{'file_parent'}) {
                                        if (defined $params{'file_name'} && $params{'file_parent'} eq $params{'file_name'}) {
                                                delete $params{'file_parent'};
                                        } elsif ($params{'file_parent'} !~ /\.\./) {
-                                               $href .= ":/".esc_url($params{'file_parent'});
+                                               $href .= ":/".esc_path_info($params{'file_parent'});
                                                delete $params{'file_parent'};
                                        }
                                }
@@ -1264,19 +1266,19 @@ sub href {
                                delete $params{'hash_parent'};
                                delete $params{'hash_parent_base'};
                        } elsif (defined $params{'hash_parent'}) {
-                               $href .= esc_url($params{'hash_parent'}). "..";
+                               $href .= esc_path_info($params{'hash_parent'}). "..";
                                delete $params{'hash_parent'};
                        }
 
-                       $href .= esc_url($params{'hash_base'});
+                       $href .= esc_path_info($params{'hash_base'});
                        if (defined $params{'file_name'} && $params{'file_name'} !~ /\.\./) {
-                               $href .= ":/".esc_url($params{'file_name'});
+                               $href .= ":/".esc_path_info($params{'file_name'});
                                delete $params{'file_name'};
                        }
                        delete $params{'hash'};
                        delete $params{'hash_base'};
                } elsif (defined $params{'hash'}) {
-                       $href .= esc_url($params{'hash'});
+                       $href .= esc_path_info($params{'hash'});
                        delete $params{'hash'};
                }
 
@@ -1309,6 +1311,9 @@ sub href {
        }
        $href .= "?" . join(';', @result) if scalar @result;
 
+       # final transformation: trailing spaces must be escaped (URI-encoded)
+       $href =~ s/(\s+)$/CGI::escape($1)/e;
+
        return $href;
 }
 
@@ -1391,6 +1396,17 @@ sub esc_param {
        return $str;
 }
 
+# the quoting rules for path_info fragment are slightly different
+sub esc_path_info {
+       my $str = shift;
+       return undef unless defined $str;
+
+       # path_info doesn't treat '+' as space (specially), but '?' must be escaped
+       $str =~ s/([^A-Za-z0-9\-_.~();\/;:@&= +]+)/CGI::escape($1)/eg;
+
+       return $str;
+}
+
 # quote unsafe chars in whole URL, so some characters cannot be quoted
 sub esc_url {
        my $str = shift;
@@ -1400,6 +1416,13 @@ sub esc_url {
        return $str;
 }
 
+# quote unsafe characters in HTML attributes
+sub esc_attr {
+
+       # for XHTML conformance escaping '"' to '&quot;' is not enough
+       return esc_html(@_);
+}
+
 # replace invalid utf8 character with SUBSTITUTION sequence
 sub esc_html {
        my $str = shift;
@@ -1805,7 +1828,7 @@ sub format_ref_marker {
                                        hash=>$dest
                                )}, $name);
 
-                       $markers .= " <span class=\"$class\" title=\"$ref\">" .
+                       $markers .= " <span class=\"".esc_attr($class)."\" title=\"".esc_attr($ref)."\">" .
                                $link . "</span>";
                }
        }
@@ -1889,7 +1912,7 @@ sub git_get_avatar {
                return $pre_white .
                       "<img width=\"$size\" " .
                            "class=\"avatar\" " .
-                           "src=\"$url\" " .
+                           "src=\"".esc_url($url)."\" " .
                            "alt=\"\" " .
                       "/>" . $post_white;
        } else {
@@ -2600,7 +2623,7 @@ sub git_show_project_tagcloud {
        } else {
                my @tags = sort { $cloud->{$a}->{count} <=> $cloud->{$b}->{count} } keys %$cloud;
                return '<p align="center">' . join (', ', map {
-                       "<a href=\"$home_link?by_tag=$_\">$cloud->{$_}->{topname}</a>"
+                       $cgi->a({-href=>"$home_link?by_tag=$_"}, $cloud->{$_}->{topname})
                } splice(@tags, 0, $count)) . '</p>';
        }
 }
@@ -3442,11 +3465,10 @@ sub run_highlighter {
        my ($fd, $highlight, $syntax) = @_;
        return $fd unless ($highlight && defined $syntax);
 
-       close $fd
-               or die_error(404, "Reading blob failed");
+       close $fd;
        open $fd, quote_command(git_cmd(), "cat-file", "blob", $hash)." | ".
                  quote_command($highlight_bin).
-                 " --xhtml --fragment --syntax $syntax |"
+                 " --fragment --syntax $syntax |"
                or die_error(500, "Couldn't open file or run syntax highlighter");
        return $fd;
 }
@@ -3472,6 +3494,51 @@ sub get_page_title {
        return $title;
 }
 
+sub print_feed_meta {
+       if (defined $project) {
+               my %href_params = get_feed_info();
+               if (!exists $href_params{'-title'}) {
+                       $href_params{'-title'} = 'log';
+               }
+
+               foreach my $format (qw(RSS Atom)) {
+                       my $type = lc($format);
+                       my %link_attr = (
+                               '-rel' => 'alternate',
+                               '-title' => esc_attr("$project - $href_params{'-title'} - $format feed"),
+                               '-type' => "application/$type+xml"
+                       );
+
+                       $href_params{'action'} = $type;
+                       $link_attr{'-href'} = href(%href_params);
+                       print "<link ".
+                             "rel=\"$link_attr{'-rel'}\" ".
+                             "title=\"$link_attr{'-title'}\" ".
+                             "href=\"$link_attr{'-href'}\" ".
+                             "type=\"$link_attr{'-type'}\" ".
+                             "/>\n";
+
+                       $href_params{'extra_options'} = '--no-merges';
+                       $link_attr{'-href'} = href(%href_params);
+                       $link_attr{'-title'} .= ' (no merges)';
+                       print "<link ".
+                             "rel=\"$link_attr{'-rel'}\" ".
+                             "title=\"$link_attr{'-title'}\" ".
+                             "href=\"$link_attr{'-href'}\" ".
+                             "type=\"$link_attr{'-type'}\" ".
+                             "/>\n";
+               }
+
+       } else {
+               printf('<link rel="alternate" title="%s projects list" '.
+                      'href="%s" type="text/plain; charset=utf-8" />'."\n",
+                      esc_attr($site_name), href(project=>undef, action=>"project_index"));
+               printf('<link rel="alternate" title="%s projects feeds" '.
+                      'href="%s" type="text/x-opml" />'."\n",
+                      esc_attr($site_name), href(project=>undef, action=>"opml"));
+       }
+}
+
 sub git_header_html {
        my $status = shift || "200 OK";
        my $expires = shift;
@@ -3514,57 +3581,17 @@ sub git_header_html {
        # print out each stylesheet that exist, providing backwards capability
        # for those people who defined $stylesheet in a config file
        if (defined $stylesheet) {
-               print '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'"/>'."\n";
+               print '<link rel="stylesheet" type="text/css" href="'.esc_url($stylesheet).'"/>'."\n";
        } else {
                foreach my $stylesheet (@stylesheets) {
                        next unless $stylesheet;
-                       print '<link rel="stylesheet" type="text/css" href="'.$stylesheet.'"/>'."\n";
-               }
-       }
-       if (defined $project) {
-               my %href_params = get_feed_info();
-               if (!exists $href_params{'-title'}) {
-                       $href_params{'-title'} = 'log';
-               }
-
-               foreach my $format qw(RSS Atom) {
-                       my $type = lc($format);
-                       my %link_attr = (
-                               '-rel' => 'alternate',
-                               '-title' => "$project - $href_params{'-title'} - $format feed",
-                               '-type' => "application/$type+xml"
-                       );
-
-                       $href_params{'action'} = $type;
-                       $link_attr{'-href'} = href(%href_params);
-                       print "<link ".
-                             "rel=\"$link_attr{'-rel'}\" ".
-                             "title=\"$link_attr{'-title'}\" ".
-                             "href=\"$link_attr{'-href'}\" ".
-                             "type=\"$link_attr{'-type'}\" ".
-                             "/>\n";
-
-                       $href_params{'extra_options'} = '--no-merges';
-                       $link_attr{'-href'} = href(%href_params);
-                       $link_attr{'-title'} .= ' (no merges)';
-                       print "<link ".
-                             "rel=\"$link_attr{'-rel'}\" ".
-                             "title=\"$link_attr{'-title'}\" ".
-                             "href=\"$link_attr{'-href'}\" ".
-                             "type=\"$link_attr{'-type'}\" ".
-                             "/>\n";
+                       print '<link rel="stylesheet" type="text/css" href="'.esc_url($stylesheet).'"/>'."\n";
                }
-
-       } else {
-               printf('<link rel="alternate" title="%s projects list" '.
-                      'href="%s" type="text/plain; charset=utf-8" />'."\n",
-                      $site_name, href(project=>undef, action=>"project_index"));
-               printf('<link rel="alternate" title="%s projects feeds" '.
-                      'href="%s" type="text/x-opml" />'."\n",
-                      $site_name, href(project=>undef, action=>"opml"));
        }
+       print_feed_meta()
+               if ($status eq '200 OK');
        if (defined $favicon) {
-               print qq(<link rel="shortcut icon" href="$favicon" type="image/png" />\n);
+               print qq(<link rel="shortcut icon" href=").esc_url($favicon).qq(" type="image/png" />\n);
        }
 
        print "</head>\n" .
@@ -3574,10 +3601,15 @@ sub git_header_html {
                insert_file($site_header);
        }
 
-       print "<div class=\"page_header\">\n" .
-             $cgi->a({-href => esc_url($logo_url),
-                      -title => $logo_label},
-                     qq(<img src="$logo" width="72" height="27" alt="git" class="logo"/>));
+       print "<div class=\"page_header\">\n";
+       if (defined $logo) {
+               print $cgi->a({-href => esc_url($logo_url),
+                              -title => $logo_label},
+                             $cgi->img({-src => esc_url($logo),
+                                        -width => 72, -height => 27,
+                                        -alt => "git",
+                                        -class => "logo"}));
+       }
        print $cgi->a({-href => esc_url($home_link)}, $home_link_str) . " / ";
        if (defined $project) {
                print $cgi->a({-href => href(action=>"summary")}, esc_html($project));
@@ -3650,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",
@@ -3683,7 +3715,7 @@ sub git_footer_html {
                insert_file($site_footer);
        }
 
-       print qq!<script type="text/javascript" src="$javascript"></script>\n!;
+       print qq!<script type="text/javascript" src="!.esc_url($javascript).qq!"></script>\n!;
        if (defined $action &&
            $action eq 'blame_incremental') {
                print qq!<script type="text/javascript">\n!.
@@ -4380,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'});
@@ -5894,14 +5926,14 @@ sub git_blob {
        } else {
                print "<div class=\"page_nav\">\n" .
                      "<br/><br/></div>\n" .
-                     "<div class=\"title\">$hash</div>\n";
+                     "<div class=\"title\">".esc_html($hash)."</div>\n";
        }
        git_print_page_path($file_name, "blob", $hash_base);
        print "<div class=\"page_body\">\n";
        if ($mimetype =~ m!^image/!) {
-               print qq!<img type="$mimetype"!;
+               print qq!<img type="!.esc_attr($mimetype).qq!"!;
                if ($file_name) {
-                       print qq! alt="$file_name" title="$file_name"!;
+                       print qq! alt="!.esc_attr($file_name).qq!" title="!.esc_attr($file_name).qq!"!;
                }
                print qq! src="! .
                      href(action=>"blob_plain", hash=>$hash,
@@ -5914,7 +5946,7 @@ sub git_blob {
                        $nr++;
                        $line = untabify($line);
                        printf qq!<div class="pre"><a id="l%i" href="%s#l%i" class="linenr">%4i</a> %s</div>\n!,
-                              $nr, href(-replay => 1), $nr, $nr, $syntax ? $line : esc_html($line, -nbsp=>1);
+                              $nr, esc_attr(href(-replay => 1)), $nr, $nr, $syntax ? $line : esc_html($line, -nbsp=>1);
                }
        }
        close $fd
@@ -5976,7 +6008,7 @@ sub git_tree {
                undef $hash_base;
                print "<div class=\"page_nav\">\n";
                print "<br/><br/></div>\n";
-               print "<div class=\"title\">$hash</div>\n";
+               print "<div class=\"title\">".esc_html($hash)."</div>\n";
        }
        if (defined $file_name) {
                $basedir = $file_name;
@@ -6444,7 +6476,7 @@ sub git_blobdiff {
                        git_print_header_div('commit', esc_html($co{'title'}), $hash_base);
                } else {
                        print "<div class=\"page_nav\"><br/>$formats_nav<br/></div>\n";
-                       print "<div class=\"title\">$hash vs $hash_parent</div>\n";
+                       print "<div class=\"title\">".esc_html("$hash vs $hash_parent")."</div>\n";
                }
                if (defined $file_name) {
                        git_print_page_path($file_name, "blob", $hash_base);
@@ -7142,7 +7174,7 @@ sub git_feed {
                if (defined $favicon) {
                        print "<icon>" . esc_url($favicon) . "</icon>\n";
                }
-               if (defined $logo_url) {
+               if (defined $logo) {
                        # not twice as wide as tall: 72 x 27 pixels
                        print "<logo>" . esc_url($logo) . "</logo>\n";
                }
diff --git a/ident.c b/ident.c
index 9e2438826dfce158e04549933d5c588dd6abcf5c..1c4adb0a9a7e94936ba64d286cedd65f4b8255a6 100644 (file)
--- a/ident.c
+++ b/ident.c
@@ -217,8 +217,10 @@ const char *fmt_ident(const char *name, const char *email,
        }
 
        strcpy(date, git_default_date);
-       if (!name_addr_only && date_str)
-               parse_date(date_str, date, sizeof(date));
+       if (!name_addr_only && date_str && date_str[0]) {
+               if (parse_date(date_str, date, sizeof(date)) < 0)
+                       die("invalid date format: %s", date_str);
+       }
 
        i = copy(buffer, sizeof(buffer), 0, name);
        i = add_raw(buffer, sizeof(buffer), i, " <");
index 8953548c07bb36f20798c7ca344d07960c22618c..61f6cc98d917c3e4395ec397ac74df6a40eeb07f 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,7 +169,9 @@ 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);
                show_commit(commit, data);
@@ -164,7 +189,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 +206,5 @@ void traverse_commit_list(struct rev_info *revs,
                revs->pending.alloc = 0;
                revs->pending.objects = NULL;
        }
+       strbuf_release(&base);
 }
index 007dd3e4d38ff657a29a06e559173b796f193763..6ce512efc4cce8042481e8a6947d033c272e78e6 100644 (file)
@@ -351,16 +351,13 @@ int ll_merge(mmbuffer_t *result_buf,
             const struct ll_merge_options *opts)
 {
        static struct git_attr_check check[2];
+       static const struct ll_merge_options default_opts;
        const char *ll_driver_name = NULL;
        int marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
        const struct ll_merge_driver *driver;
 
-       if (!opts) {
-               struct ll_merge_options default_opts = {0};
-               return ll_merge(result_buf, path, ancestor, ancestor_label,
-                               ours, our_label, theirs, their_label,
-                               &default_opts);
-       }
+       if (!opts)
+               opts = &default_opts;
 
        if (opts->renormalize) {
                normalize_file(ancestor, path);
index c8135b0ec70cc2eb92e5a6fd9353a134fda6b7bf..981ed6ac94b5ed73f15a3b0dca723586374ca0b8 100644 (file)
@@ -57,6 +57,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..1467ad31795ae21896f1e608e7cb032df2bc94a8 100644 (file)
@@ -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 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;
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;
 }
 
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..b97b5668ebc486561686d3e80b536e115dede513 100644 (file)
@@ -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 ded881263ba0ff703d9fd468e6785270ea68df5f..86d24704896d71de7bb554a3925ea88e2be3417b 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;
        }
 
@@ -444,15 +444,15 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
        commit->object.flags |= TREESAME;
 }
 
-static void insert_by_date_cached(struct commit *p, struct commit_list **head,
+static void commit_list_insert_by_date_cached(struct commit *p, struct commit_list **head,
                    struct commit_list *cached_base, struct commit_list **cache)
 {
        struct commit_list *new_entry;
 
        if (cached_base && p->date < cached_base->item->date)
-               new_entry = insert_by_date(p, &cached_base->next);
+               new_entry = commit_list_insert_by_date(p, &cached_base->next);
        else
-               new_entry = insert_by_date(p, head);
+               new_entry = commit_list_insert_by_date(p, head);
 
        if (cache && (!*cache || p->date < (*cache)->item->date))
                *cache = new_entry;
@@ -494,7 +494,7 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
                        if (p->object.flags & SEEN)
                                continue;
                        p->object.flags |= SEEN;
-                       insert_by_date_cached(p, list, cached_base, cache_ptr);
+                       commit_list_insert_by_date_cached(p, list, cached_base, cache_ptr);
                }
                return 0;
        }
@@ -521,7 +521,7 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
                p->object.flags |= left_flag;
                if (!(p->object.flags & SEEN)) {
                        p->object.flags |= SEEN;
-                       insert_by_date_cached(p, list, cached_base, cache_ptr);
+                       commit_list_insert_by_date_cached(p, list, cached_base, cache_ptr);
                }
                if (revs->first_parent_only)
                        break;
@@ -553,11 +553,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) {
@@ -973,7 +969,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 +979,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;
 }
 
@@ -1620,7 +1617,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 +1648,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;
@@ -1891,7 +1888,7 @@ int prepare_revision_walk(struct rev_info *revs)
                if (commit) {
                        if (!(commit->object.flags & SEEN)) {
                                commit->object.flags |= SEEN;
-                               insert_by_date(commit, &revs->commits);
+                               commit_list_insert_by_date(commit, &revs->commits);
                        }
                }
                e++;
index 05659c64acd7fe8eb7be011cee6174e397e57baf..82509dd1d9ad7b1824971be4884409060f10aee3 100644 (file)
@@ -34,7 +34,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 */
index 2a1041ef6599c84fff6a8d9faf5dea23a2af3ab0..f91e446c86be8e27f98554567143d7ce6f934bd1 100644 (file)
@@ -194,6 +194,7 @@ int start_command(struct child_process *cmd)
        }
 
        trace_argv_printf(cmd->argv, "trace: run_command:");
+       fflush(NULL);
 
 #ifndef WIN32
 {
@@ -201,7 +202,6 @@ int start_command(struct child_process *cmd)
        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 14f91e39353bcfa1ee2b08d6a5b5f53a024a280c..021d0133ae1d6cf7f3a6a8284cb5b6e9a42dbe0d 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -4,13 +4,16 @@
 static int inside_git_dir = -1;
 static int inside_work_tree = -1;
 
-const char *prefix_path(const char *prefix, int len, const char *path)
+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 = make_absolute_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);
@@ -208,24 +211,6 @@ int is_inside_work_tree(void)
        return inside_work_tree;
 }
 
-/*
- * set_work_tree() is only ever called if you set GIT_DIR explicitly.
- * The old behaviour (which we retain here) is to set the work tree root
- * to the cwd, unless overridden by the config, the command line, or
- * GIT_WORK_TREE.
- */
-static const char *set_work_tree(const char *dir)
-{
-       char buffer[PATH_MAX + 1];
-
-       if (!getcwd(buffer, sizeof(buffer)))
-               die ("Could not get the current working directory");
-       git_work_tree_cfg = xstrdup(buffer);
-       inside_work_tree = 1;
-
-       return NULL;
-}
-
 void setup_work_tree(void)
 {
        const char *work_tree, *git_dir;
@@ -239,13 +224,33 @@ void setup_work_tree(void)
                git_dir = make_absolute_path(git_dir);
        if (!work_tree || chdir(work_tree))
                die("This operation must be run in a work tree");
+
+       /*
+        * Make sure subsequent git processes find correct worktree
+        * if $GIT_WORK_TREE is set relative
+        */
+       if (getenv(GIT_WORK_TREE_ENVIRONMENT))
+               setenv(GIT_WORK_TREE_ENVIRONMENT, ".", 1);
+
        set_git_dir(make_relative_path(git_dir, work_tree));
        initialized = 1;
 }
 
-static int check_repository_format_gently(int *nongit_ok)
+static int check_repository_format_gently(const char *gitdir, int *nongit_ok)
 {
-       git_config(check_repository_format_version, NULL);
+       char repo_config[PATH_MAX+1];
+
+       /*
+        * git_config() can't be used here because it calls git_pathdup()
+        * to get $GIT_CONFIG/config. That call will make setup_git_env()
+        * set git_dir to ".git".
+        *
+        * We are in gitdir setup, no git dir has been found useable yet.
+        * Use a gentler version of git_config() to check if this repo
+        * is a good one.
+        */
+       snprintf(repo_config, PATH_MAX, "%s/config", gitdir);
+       git_config_early(check_repository_format_version, NULL, repo_config);
        if (GIT_REPO_VERSION < repository_format_version) {
                if (!nongit_ok)
                        die ("Expected git repo version <= %d, found %d",
@@ -314,64 +319,124 @@ const char *read_gitfile_gently(const char *path)
 }
 
 static const char *setup_explicit_git_dir(const char *gitdirenv,
-                               const char *work_tree_env, int *nongit_ok)
+                                         char *cwd, int len,
+                                         int *nongit_ok)
 {
-       static char buffer[1024 + 1];
-       const char *retval;
+       const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
+       const char *worktree;
+       char *gitfile;
 
        if (PATH_MAX - 40 < strlen(gitdirenv))
                die("'$%s' too big", GIT_DIR_ENVIRONMENT);
+
+       gitfile = (char*)read_gitfile_gently(gitdirenv);
+       if (gitfile) {
+               gitfile = xstrdup(gitfile);
+               gitdirenv = gitfile;
+       }
+
        if (!is_git_directory(gitdirenv)) {
                if (nongit_ok) {
                        *nongit_ok = 1;
+                       free(gitfile);
                        return NULL;
                }
                die("Not a git repository: '%s'", gitdirenv);
        }
-       if (!work_tree_env) {
-               retval = set_work_tree(gitdirenv);
-               /* config may override worktree */
-               if (check_repository_format_gently(nongit_ok))
-                       return NULL;
-               return retval;
+
+       if (check_repository_format_gently(gitdirenv, nongit_ok)) {
+               free(gitfile);
+               return NULL;
        }
-       if (check_repository_format_gently(nongit_ok))
+
+       /* #3, #7, #11, #15, #19, #23, #27, #31 (see t1510) */
+       if (work_tree_env)
+               set_git_work_tree(work_tree_env);
+       else if (is_bare_repository_cfg > 0) {
+               if (git_work_tree_cfg) /* #22.2, #30 */
+                       die("core.bare and core.worktree do not make sense");
+
+               /* #18, #26 */
+               set_git_dir(gitdirenv);
+               free(gitfile);
                return NULL;
-       retval = get_relative_cwd(buffer, sizeof(buffer) - 1,
-                       get_git_work_tree());
-       if (!retval || !*retval)
+       }
+       else if (git_work_tree_cfg) { /* #6, #14 */
+               if (is_absolute_path(git_work_tree_cfg))
+                       set_git_work_tree(git_work_tree_cfg);
+               else {
+                       char core_worktree[PATH_MAX];
+                       if (chdir(gitdirenv))
+                               die_errno("Could not chdir to '%s'", gitdirenv);
+                       if (chdir(git_work_tree_cfg))
+                               die_errno("Could not chdir to '%s'", git_work_tree_cfg);
+                       if (!getcwd(core_worktree, PATH_MAX))
+                               die_errno("Could not get directory '%s'", git_work_tree_cfg);
+                       if (chdir(cwd))
+                               die_errno("Could not come back to cwd");
+                       set_git_work_tree(core_worktree);
+               }
+       }
+       else /* #2, #10 */
+               set_git_work_tree(".");
+
+       /* set_git_work_tree() must have been called by now */
+       worktree = get_git_work_tree();
+
+       /* both get_git_work_tree() and cwd are already normalized */
+       if (!strcmp(cwd, worktree)) { /* cwd == worktree */
+               set_git_dir(gitdirenv);
+               free(gitfile);
                return NULL;
-       set_git_dir(make_absolute_path(gitdirenv));
-       if (chdir(work_tree_env) < 0)
-               die_errno ("Could not chdir to '%s'", work_tree_env);
-       strcat(buffer, "/");
-       return retval;
-}
+       }
 
-static int cwd_contains_git_dir(const char **gitfile_dirp)
-{
-       const char *gitfile_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
-       *gitfile_dirp = gitfile_dir;
-       if (gitfile_dir) {
-               if (set_git_dir(gitfile_dir))
-                       die("Repository setup failed");
-               return 1;
+       if (!prefixcmp(cwd, worktree) &&
+           cwd[strlen(worktree)] == '/') { /* cwd inside worktree */
+               set_git_dir(make_absolute_path(gitdirenv));
+               if (chdir(worktree))
+                       die_errno("Could not chdir to '%s'", worktree);
+               cwd[len++] = '/';
+               cwd[len] = '\0';
+               free(gitfile);
+               return cwd + strlen(worktree) + 1;
        }
-       return is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT);
+
+       /* cwd outside worktree */
+       set_git_dir(gitdirenv);
+       free(gitfile);
+       return NULL;
 }
 
-static const char *setup_discovered_git_dir(const char *work_tree_env,
-               int offset, int len, char *cwd, int *nongit_ok)
+static const char *setup_discovered_git_dir(const char *gitdir,
+                                           char *cwd, int offset, int len,
+                                           int *nongit_ok)
 {
-       int root_len;
+       if (check_repository_format_gently(gitdir, nongit_ok))
+               return NULL;
 
-       inside_git_dir = 0;
-       if (!work_tree_env)
-               inside_work_tree = 1;
-       root_len = offset_1st_component(cwd);
-       git_work_tree_cfg = xstrndup(cwd, offset > root_len ? offset : root_len);
-       if (check_repository_format_gently(nongit_ok))
+       /* --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));
+               if (chdir(cwd))
+                       die_errno("Could not come back to cwd");
+               return setup_explicit_git_dir(gitdir, cwd, len, nongit_ok);
+       }
+
+       /* #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));
+               if (chdir(cwd))
+                       die_errno("Could not come back to cwd");
                return NULL;
+       }
+
+       /* #0, #1, #5, #8, #9, #12, #13 */
+       set_git_work_tree(".");
+       if (strcmp(gitdir, DEFAULT_GIT_DIR_ENVIRONMENT))
+               set_git_dir(gitdir);
+       inside_git_dir = 0;
+       inside_work_tree = 1;
        if (offset == len)
                return NULL;
 
@@ -382,23 +447,35 @@ static const char *setup_discovered_git_dir(const char *work_tree_env,
        return cwd + offset;
 }
 
-static const char *setup_bare_git_dir(const char *work_tree_env,
-               int offset, int len, char *cwd, int *nongit_ok)
+/* #16.1, #17.1, #20.1, #21.1, #22.1 (see t1510) */
+static const char *setup_bare_git_dir(char *cwd, int offset, int len, int *nongit_ok)
 {
        int root_len;
 
+       if (check_repository_format_gently(".", nongit_ok))
+               return NULL;
+
+       /* --work-tree is set without --git-dir; use discovered one */
+       if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
+               const char *gitdir;
+
+               gitdir = offset == len ? "." : xmemdupz(cwd, offset);
+               if (chdir(cwd))
+                       die_errno("Could not come back to cwd");
+               return setup_explicit_git_dir(gitdir, cwd, len, nongit_ok);
+       }
+
        inside_git_dir = 1;
-       if (!work_tree_env)
-               inside_work_tree = 0;
+       inside_work_tree = 0;
        if (offset != len) {
                if (chdir(cwd))
                        die_errno("Cannot come back to cwd");
                root_len = offset_1st_component(cwd);
                cwd[offset > root_len ? offset : root_len] = '\0';
                set_git_dir(cwd);
-       } else
+       }
+       else
                set_git_dir(".");
-       check_repository_format_gently(nongit_ok);
        return NULL;
 }
 
@@ -428,11 +505,10 @@ static dev_t get_device_or_die(const char *path, const char *prefix)
  */
 static const char *setup_git_directory_gently_1(int *nongit_ok)
 {
-       const char *work_tree_env = getenv(GIT_WORK_TREE_ENVIRONMENT);
        const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
        static char cwd[PATH_MAX+1];
-       const char *gitdirenv;
-       const char *gitfile_dir;
+       const char *gitdirenv, *ret;
+       char *gitfile;
        int len, offset, ceil_offset;
        dev_t current_device = 0;
        int one_filesystem = 1;
@@ -445,6 +521,10 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
        if (nongit_ok)
                *nongit_ok = 0;
 
+       if (!getcwd(cwd, sizeof(cwd)-1))
+               die_errno("Unable to read current working directory");
+       offset = len = strlen(cwd);
+
        /*
         * If GIT_DIR is set explicitly, we're not going
         * to do any discovery, but we still do repository
@@ -452,10 +532,7 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
         */
        gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
        if (gitdirenv)
-               return setup_explicit_git_dir(gitdirenv, work_tree_env, nongit_ok);
-
-       if (!getcwd(cwd, sizeof(cwd)-1))
-               die_errno("Unable to read current working directory");
+               return setup_explicit_git_dir(gitdirenv, cwd, len, nongit_ok);
 
        ceil_offset = longest_ancestor_length(cwd, env_ceiling_dirs);
        if (ceil_offset < 0 && has_dos_drive_prefix(cwd))
@@ -472,17 +549,30 @@ static const char *setup_git_directory_gently_1(int *nongit_ok)
         * - ../../.git/
         *   etc.
         */
-       offset = len = strlen(cwd);
        one_filesystem = !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0);
        if (one_filesystem)
                current_device = get_device_or_die(".", NULL);
        for (;;) {
-               if (cwd_contains_git_dir(&gitfile_dir))
-                       return setup_discovered_git_dir(work_tree_env, offset,
-                                                       len, cwd, nongit_ok);
+               gitfile = (char*)read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
+               if (gitfile)
+                       gitdirenv = gitfile = xstrdup(gitfile);
+               else {
+                       if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT))
+                               gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT;
+               }
+
+               if (gitdirenv) {
+                       ret = setup_discovered_git_dir(gitdirenv,
+                                                      cwd, offset, len,
+                                                      nongit_ok);
+                       free(gitfile);
+                       return ret;
+               }
+               free(gitfile);
+
                if (is_git_directory("."))
-                       return setup_bare_git_dir(work_tree_env, offset,
-                                                       len, cwd, nongit_ok);
+                       return setup_bare_git_dir(cwd, offset, len, nongit_ok);
+
                while (--offset > ceil_offset && cwd[offset] != '/');
                if (offset <= ceil_offset)
                        return setup_nongit(cwd, nongit_ok);
@@ -592,7 +682,7 @@ int check_repository_format_version(const char *var, const char *value, void *cb
 
 int check_repository_format(void)
 {
-       return check_repository_format_gently(NULL);
+       return check_repository_format_gently(get_git_dir(), NULL);
 }
 
 /*
@@ -603,19 +693,5 @@ int check_repository_format(void)
  */
 const char *setup_git_directory(void)
 {
-       const char *retval = setup_git_directory_gently(NULL);
-
-       /* If the work tree is not the default one, recompute prefix */
-       if (inside_work_tree < 0) {
-               static char buffer[PATH_MAX + 1];
-               char *rel;
-               if (retval && chdir(retval))
-                       die_errno ("Could not jump back into original cwd");
-               rel = get_relative_cwd(buffer, PATH_MAX, get_git_work_tree());
-               if (rel && *rel && chdir(get_git_work_tree()))
-                       die_errno ("Could not jump to working directory");
-               return rel && *rel ? strcat(rel, "/") : NULL;
-       }
-
-       return retval;
+       return setup_git_directory_gently(NULL);
 }
index 1cafdfa617a833ec757b481826dc62282be8f374..27730c334cb433ef749a0efc5353a7f38032559c 100644 (file)
@@ -37,6 +37,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);
@@ -1985,9 +2020,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 +2076,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)
 {
@@ -2141,7 +2149,7 @@ void *read_sha1_file_repl(const unsigned char *sha1,
                return data;
        }
 
-       if (errno != ENOENT)
+       if (errno && errno != ENOENT)
                die_errno("failed to read object %s", sha1_to_hex(sha1));
 
        /* die if we replaced an object with one that does not exist */
index 2c3a5fb363ff9b11a971b45e85819b2c0aaad157..709ff2eee64cf106191ad274bede82a95d00e2a3 100644 (file)
@@ -7,6 +7,8 @@
 #include "refs.h"
 #include "remote.h"
 
+static int get_sha1_oneline(const char *, unsigned char *, struct commit_list *);
+
 static int find_short_object_filename(int len, const char *name, unsigned char *sha1)
 {
        struct alternate_object_database *alt;
@@ -562,6 +564,8 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
                expected_type = OBJ_BLOB;
        else if (sp[0] == '}')
                expected_type = OBJ_NONE;
+       else if (sp[0] == '/')
+               expected_type = OBJ_COMMIT;
        else
                return -1;
 
@@ -576,19 +580,37 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
                if (!o || (!o->parsed && !parse_object(o->sha1)))
                        return -1;
                hashcpy(sha1, o->sha1);
+               return 0;
        }
-       else {
+
+       /*
+        * At this point, the syntax look correct, so
+        * if we do not get the needed object, we should
+        * barf.
+        */
+       o = peel_to_type(name, len, o, expected_type);
+       if (!o)
+               return -1;
+
+       hashcpy(sha1, o->sha1);
+       if (sp[0] == '/') {
+               /* "$commit^{/foo}" */
+               char *prefix;
+               int ret;
+               struct commit_list *list = NULL;
+
                /*
-                * At this point, the syntax look correct, so
-                * if we do not get the needed object, we should
-                * barf.
+                * $commit^{/}. Some regex implementation may reject.
+                * We don't need regex anyway. '' pattern always matches.
                 */
-               o = peel_to_type(name, len, o, expected_type);
-               if (o) {
-                       hashcpy(sha1, o->sha1);
+               if (sp[1] == '}')
                        return 0;
-               }
-               return -1;
+
+               prefix = xstrndup(sp + 1, name + len - 1 - (sp + 1));
+               commit_list_insert((struct commit *)o, &list);
+               ret = get_sha1_oneline(prefix, sha1, list);
+               free(prefix);
+               return ret;
        }
        return 0;
 }
@@ -685,16 +707,15 @@ static int handle_one_ref(const char *path,
        }
        if (object->type != OBJ_COMMIT)
                return 0;
-       insert_by_date((struct commit *)object, list);
-       object->flags |= ONELINE_SEEN;
+       commit_list_insert_by_date((struct commit *)object, list);
        return 0;
 }
 
-static int get_sha1_oneline(const char *prefix, unsigned char *sha1)
+static int get_sha1_oneline(const char *prefix, unsigned char *sha1,
+                           struct commit_list *list)
 {
-       struct commit_list *list = NULL, *backup = NULL, *l;
-       int retval = -1;
-       char *temp_commit_buffer = NULL;
+       struct commit_list *backup = NULL, *l;
+       int found = 0;
        regex_t regex;
 
        if (prefix[0] == '!') {
@@ -706,41 +727,45 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1)
        if (regcomp(&regex, prefix, REG_EXTENDED))
                die("Invalid search pattern: %s", prefix);
 
-       for_each_ref(handle_one_ref, &list);
-       for (l = list; l; l = l->next)
+       for (l = list; l; l = l->next) {
+               l->item->object.flags |= ONELINE_SEEN;
                commit_list_insert(l->item, &backup);
+       }
        while (list) {
-               char *p;
+               char *p, *to_free = NULL;
                struct commit *commit;
                enum object_type type;
                unsigned long size;
+               int matches;
 
                commit = pop_most_recent_commit(&list, ONELINE_SEEN);
                if (!parse_object(commit->object.sha1))
                        continue;
-               free(temp_commit_buffer);
                if (commit->buffer)
                        p = commit->buffer;
                else {
                        p = read_sha1_file(commit->object.sha1, &type, &size);
                        if (!p)
                                continue;
-                       temp_commit_buffer = p;
+                       to_free = p;
                }
-               if (!(p = strstr(p, "\n\n")))
-                       continue;
-               if (!regexec(&regex, p + 2, 0, NULL, 0)) {
+
+               p = strstr(p, "\n\n");
+               matches = p && !regexec(&regex, p + 2, 0, NULL, 0);
+               free(to_free);
+
+               if (matches) {
                        hashcpy(sha1, commit->object.sha1);
-                       retval = 0;
+                       found = 1;
                        break;
                }
        }
        regfree(&regex);
-       free(temp_commit_buffer);
        free_commit_list(list);
        for (l = backup; l; l = l->next)
                clear_commit_marks(l->item, ONELINE_SEEN);
-       return retval;
+       free_commit_list(backup);
+       return found ? 0 : -1;
 }
 
 struct grab_nth_branch_switch_cbdata {
@@ -1066,6 +1091,23 @@ int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode,
        return ret;
 }
 
+static char *resolve_relative_path(const char *rel)
+{
+       if (prefixcmp(rel, "./") && prefixcmp(rel, "../"))
+               return NULL;
+
+       if (!startup_info)
+               die("BUG: startup_info struct is not initialized.");
+
+       if (!is_inside_work_tree())
+               die("relative path syntax can't be used outside working tree.");
+
+       /* die() inside prefix_path() if resolved path is outside worktree */
+       return prefix_path(startup_info->prefix,
+                          startup_info->prefix ? strlen(startup_info->prefix) : 0,
+                          rel);
+}
+
 int get_sha1_with_context_1(const char *name, unsigned char *sha1,
                            struct object_context *oc,
                            int gently, const char *prefix)
@@ -1080,17 +1122,21 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
        if (!ret)
                return ret;
        /* sha1:path --> object name of path in ent sha1
-        * :path -> object name of path in index
+        * :path -> object name of absolute path in index
+        * :./path -> object name of path relative to cwd in index
         * :[0-3]:path -> object name of path in index at stage
         * :/foo -> recent commit matching foo
         */
        if (name[0] == ':') {
                int stage = 0;
                struct cache_entry *ce;
+               char *new_path = NULL;
                int pos;
-               if (namelen > 2 && name[1] == '/')
-                       /* don't need mode for commit */
-                       return get_sha1_oneline(name + 2, sha1);
+               if (namelen > 2 && name[1] == '/') {
+                       struct commit_list *list = NULL;
+                       for_each_ref(handle_one_ref, &list);
+                       return get_sha1_oneline(name + 2, sha1, list);
+               }
                if (namelen < 3 ||
                    name[2] != ':' ||
                    name[1] < '0' || '3' < name[1])
@@ -1099,7 +1145,13 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
                        stage = name[1] - '0';
                        cp = name + 3;
                }
-               namelen = namelen - (cp - name);
+               new_path = resolve_relative_path(cp);
+               if (!new_path) {
+                       namelen = namelen - (cp - name);
+               } else {
+                       cp = new_path;
+                       namelen = strlen(cp);
+               }
 
                strncpy(oc->path, cp,
                        sizeof(oc->path));
@@ -1118,12 +1170,14 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
                        if (ce_stage(ce) == stage) {
                                hashcpy(sha1, ce->sha1);
                                oc->mode = ce->ce_mode;
+                               free(new_path);
                                return 0;
                        }
                        pos++;
                }
                if (!gently)
                        diagnose_invalid_index_path(stage, prefix, cp);
+               free(new_path);
                return -1;
        }
        for (cp = name, bracket_depth = 0; *cp; cp++) {
@@ -1144,6 +1198,11 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
                }
                if (!get_sha1_1(name, cp-name, tree_sha1)) {
                        const char *filename = cp+1;
+                       char *new_filename = NULL;
+
+                       new_filename = resolve_relative_path(filename);
+                       if (new_filename)
+                               filename = new_filename;
                        ret = get_tree_entry(tree_sha1, filename, sha1, &oc->mode);
                        if (!gently) {
                                diagnose_invalid_sha1_path(prefix, filename,
@@ -1155,6 +1214,7 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
                                sizeof(oc->path));
                        oc->path[sizeof(oc->path)-1] = '\0';
 
+                       free(new_filename);
                        return ret;
                } else {
                        if (!gently)
index 9b3c4457f229041784edfa65218aa09de7a5eff8..07e8883ceb297bdde79f06ffa2d0519581ee60b9 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");
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 91a47587478ae0550be8f41c00cb1749c85834f4..6f1c10722f744f4a27f18dae4867b15ecbf57d49 100644 (file)
@@ -10,7 +10,9 @@
 #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 int config_fetch_recurse_submodules;
 
 static int add_submodule_odb(const char *path)
 {
@@ -63,10 +65,14 @@ void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
        }
 }
 
-static int submodule_config(const char *var, const char *value, void *cb)
+int submodule_config(const char *var, const char *value, void *cb)
 {
        if (!prefixcmp(var, "submodule."))
                return parse_submodule_config_option(var, value);
+       else if (!strcmp(var, "fetch.recursesubmodules")) {
+               config_fetch_recurse_submodules = git_config_bool(var, value);
+               return 0;
+       }
        return 0;
 }
 
@@ -100,6 +106,14 @@ int parse_submodule_config_option(const char *var, const char *value)
                        config = string_list_append(&config_name_for_path, xstrdup(value));
                config->util = strbuf_detach(&submodname, NULL);
                strbuf_release(&submodname);
+       } else if ((len > 23) && !strcmp(var + len - 23, ".fetchrecursesubmodules")) {
+               strbuf_add(&submodname, var, len - 23);
+               config = unsorted_string_list_lookup(&config_fetch_recurse_submodules_for_name, submodname.buf);
+               if (!config)
+                       config = string_list_append(&config_fetch_recurse_submodules_for_name,
+                                                   strbuf_detach(&submodname, NULL));
+               config->util = git_config_bool(var, value) ? (void *)1 : NULL;
+               strbuf_release(&submodname);
        } else if ((len > 7) && !strcmp(var + len - 7, ".ignore")) {
                if (strcmp(value, "untracked") && strcmp(value, "dirty") &&
                    strcmp(value, "all") && strcmp(value, "none")) {
@@ -229,6 +243,89 @@ void show_submodule_summary(FILE *f, const char *path,
        strbuf_release(&sb);
 }
 
+void set_config_fetch_recurse_submodules(int value)
+{
+       config_fetch_recurse_submodules = value;
+}
+
+int fetch_populated_submodules(int num_options, const char **options,
+                              const char *prefix, int ignore_config,
+                              int quiet)
+{
+       int i, result = 0, argc = 0;
+       struct child_process cp;
+       const char **argv;
+       struct string_list_item *name_for_path;
+       const char *work_tree = get_git_work_tree();
+       if (!work_tree)
+               return 0;
+
+       if (!the_index.initialized)
+               if (read_cache() < 0)
+                       die("index file corrupt");
+
+       /* 4: "fetch" (options) "--submodule-prefix" prefix NULL */
+       argv = xcalloc(num_options + 4, sizeof(const char *));
+       argv[argc++] = "fetch";
+       for (i = 0; i < num_options; i++)
+               argv[argc++] = options[i];
+       argv[argc++] = "--submodule-prefix";
+
+       memset(&cp, 0, sizeof(cp));
+       cp.argv = argv;
+       cp.env = local_repo_env;
+       cp.git_cmd = 1;
+       cp.no_stdin = 1;
+
+       for (i = 0; i < active_nr; i++) {
+               struct strbuf submodule_path = STRBUF_INIT;
+               struct strbuf submodule_git_dir = STRBUF_INIT;
+               struct strbuf submodule_prefix = STRBUF_INIT;
+               struct cache_entry *ce = active_cache[i];
+               const char *git_dir, *name;
+
+               if (!S_ISGITLINK(ce->ce_mode))
+                       continue;
+
+               name = ce->name;
+               name_for_path = unsorted_string_list_lookup(&config_name_for_path, ce->name);
+               if (name_for_path)
+                       name = name_for_path->util;
+
+               if (!ignore_config) {
+                       struct string_list_item *fetch_recurse_submodules_option;
+                       fetch_recurse_submodules_option = unsorted_string_list_lookup(&config_fetch_recurse_submodules_for_name, name);
+                       if (fetch_recurse_submodules_option) {
+                               if (!fetch_recurse_submodules_option->util)
+                                       continue;
+                       } else {
+                               if (!config_fetch_recurse_submodules)
+                                       continue;
+                       }
+               }
+
+               strbuf_addf(&submodule_path, "%s/%s", work_tree, ce->name);
+               strbuf_addf(&submodule_git_dir, "%s/.git", submodule_path.buf);
+               strbuf_addf(&submodule_prefix, "%s%s/", prefix, ce->name);
+               git_dir = read_gitfile_gently(submodule_git_dir.buf);
+               if (!git_dir)
+                       git_dir = submodule_git_dir.buf;
+               if (is_directory(git_dir)) {
+                       if (!quiet)
+                               printf("Fetching submodule %s%s\n", prefix, ce->name);
+                       cp.dir = submodule_path.buf;
+                       argv[argc] = submodule_prefix.buf;
+                       if (run_command(&cp))
+                               result = 1;
+               }
+               strbuf_release(&submodule_path);
+               strbuf_release(&submodule_git_dir);
+               strbuf_release(&submodule_prefix);
+       }
+       free(argv);
+       return result;
+}
+
 unsigned is_submodule_modified(const char *path, int ignore_untracked)
 {
        ssize_t len;
index 386f410a66d9c431a61c0e26c773f1b3452f0d09..4729023aa5bbd7d7c95981b995c379407ba6423d 100644 (file)
@@ -5,6 +5,7 @@ struct diff_options;
 
 void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
                const char *path);
+int submodule_config(const char *var, const char *value, void *cb);
 void gitmodules_config();
 int parse_submodule_config_option(const char *var, const char *value);
 void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *);
@@ -12,6 +13,10 @@ 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);
+void set_config_fetch_recurse_submodules(int value);
+int fetch_populated_submodules(int num_options, const char **options,
+                              const char *prefix, int ignore_config,
+                              int quiet);
 unsigned is_submodule_modified(const char *path, int ignore_untracked);
 int merge_submodule(unsigned char result[20], const char *path, const unsigned char base[20],
                    const unsigned char a[20], const unsigned char b[20]);
index 73c6ec473da2d13b9e5bf3d6feb7cfca4937e109..47cbeb6e68ec910a691f2feca18b7b160efd0ced 100644 (file)
@@ -23,10 +23,10 @@ TGITWEB = $(wildcard t95[0-9][0-9]-*.sh)
 
 all: $(DEFAULT_TEST_TARGET)
 
-test: pre-clean
+test: pre-clean $(TEST_LINT)
        $(MAKE) aggregate-results-and-cleanup
 
-prove: pre-clean
+prove: pre-clean $(TEST_LINT)
        @echo "*** prove ***"; GIT_CONFIG=.git/config $(PROVE) --exec '$(SHELL_PATH_SQ)' $(GIT_PROVE_OPTS) $(T) :: $(GIT_TEST_OPTS)
        $(MAKE) clean
 
@@ -41,6 +41,18 @@ clean:
        $(RM) -r valgrind/bin
        $(RM) .prove
 
+test-lint: test-lint-duplicates test-lint-executable
+
+test-lint-duplicates:
+       @dups=`echo $(T) | tr ' ' '\n' | sed 's/-.*//' | sort | uniq -d` && \
+               test -z "$$dups" || { \
+               echo >&2 "duplicate test numbers:" $$dups; exit 1; }
+
+test-lint-executable:
+       @bad=`for i in $(T); do test -x "$$i" || echo $$i; done` && \
+               test -z "$$bad" || { \
+               echo >&2 "non-executable tests:" $$bad; exit 1; }
+
 aggregate-results-and-cleanup: $(T)
        $(MAKE) aggregate-results
        $(MAKE) clean
index 892d443f63428aea6d6b92458bdaa4575bc46da0..25f7d2d2e3cf70d54f5b854ad4199c831a74ae2a 100644 (file)
--- a/t/README
+++ b/t/README
@@ -283,6 +283,12 @@ Do:
    Tests that are likely to smoke out future regressions are better
    than tests that just inflate the coverage metrics.
 
+ - When a test checks for an absolute path that a git command generated,
+   construct the expected value using $(pwd) rather than $PWD,
+   $TEST_DIRECTORY, or $TRASH_DIRECTORY. It makes a difference on
+   Windows, where the shell (MSYS bash) mangles absolute path names.
+   For details, see the commit message of 4114156ae9.
+
 Don't:
 
  - exit() within a <script> part.
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 92d6d319428223de9205d4d162e3806aedee855b..199f22c231b5ac1479929a89cdf988ac7aff4268 100644 (file)
@@ -68,41 +68,46 @@ svn_cmd () {
        svn "$orig_svncmd" --config-dir "$svnconf" "$@"
 }
 
-for d in \
-       "$SVN_HTTPD_PATH" \
-       /usr/sbin/apache2 \
-       /usr/sbin/httpd \
-; do
-       if test -f "$d"
+prepare_httpd () {
+       for d in \
+               "$SVN_HTTPD_PATH" \
+               /usr/sbin/apache2 \
+               /usr/sbin/httpd \
+       ; do
+               if test -f "$d"
+               then
+                       SVN_HTTPD_PATH="$d"
+                       break
+               fi
+       done
+       if test -z "$SVN_HTTPD_PATH"
        then
-               SVN_HTTPD_PATH="$d"
-               break
+               echo >&2 '*** error: Apache not found'
+               return 1
        fi
-done
-for d in \
-       "$SVN_HTTPD_MODULE_PATH" \
-       /usr/lib/apache2/modules \
-       /usr/libexec/apache2 \
-; do
-       if test -d "$d"
+       for d in \
+               "$SVN_HTTPD_MODULE_PATH" \
+               /usr/lib/apache2/modules \
+               /usr/libexec/apache2 \
+       ; do
+               if test -d "$d"
+               then
+                       SVN_HTTPD_MODULE_PATH="$d"
+                       break
+               fi
+       done
+       if test -z "$SVN_HTTPD_MODULE_PATH"
        then
-               SVN_HTTPD_MODULE_PATH="$d"
-               break
+               echo >&2 '*** error: Apache module dir not found'
+               return 1
        fi
-done
-
-start_httpd () {
-       repo_base_path="$1"
-       if test -z "$SVN_HTTPD_PORT"
+       if test ! -f "$SVN_HTTPD_MODULE_PATH/mod_dav_svn.so"
        then
-               echo >&2 'SVN_HTTPD_PORT is not defined!'
-               return
-       fi
-       if test -z "$repo_base_path"
-       then
-               repo_base_path=svn
+               echo >&2 '*** error: Apache module "mod_dav_svn" not found'
+               return 1
        fi
 
+       repo_base_path="${1-svn}"
        mkdir "$GIT_DIR"/logs
 
        cat > "$GIT_DIR/httpd.conf" <<EOF
@@ -119,12 +124,24 @@ LoadModule dav_svn_module $SVN_HTTPD_MODULE_PATH/mod_dav_svn.so
        SVNPath "$rawsvnrepo"
 </Location>
 EOF
+}
+
+start_httpd () {
+       if test -z "$SVN_HTTPD_PORT"
+       then
+               echo >&2 'SVN_HTTPD_PORT is not defined!'
+               return
+       fi
+
+       prepare_httpd "$1" || return 1
+
        "$SVN_HTTPD_PATH" -f "$GIT_DIR"/httpd.conf -k start
        svnrepo="http://127.0.0.1:$SVN_HTTPD_PORT/$repo_base_path"
 }
 
 stop_httpd () {
        test -z "$SVN_HTTPD_PORT" && return
+       test ! -f "$GIT_DIR/httpd.conf" && return
        "$SVN_HTTPD_PATH" -f "$GIT_DIR"/httpd.conf -k stop
 }
 
index 2f7002a5e57d61a69d418cc55d1e939198c6ac20..8deec75c3a0eef961986a0bb313a918ab532f58d 100755 (executable)
@@ -80,11 +80,11 @@ EOF
     chmod +x passing-todo.sh &&
     ./passing-todo.sh >out 2>err &&
     ! test -s err &&
-cat >expect <<EOF &&
-ok 1 - pretend we have fixed a known breakage # TODO known breakage
-# fixed 1 known breakage(s)
-# passed all 1 test(s)
-1..1
+sed -e 's/^> //' >expect <<EOF &&
+ok 1 - pretend we have fixed a known breakage # TODO known breakage
+# fixed 1 known breakage(s)
+# passed all 1 test(s)
+1..1
 EOF
     test_cmp expect out)
 "
@@ -164,19 +164,19 @@ EOF
     test_must_fail ./failing-cleanup.sh >out 2>err &&
     ! test -s err &&
     ! test -f \"trash directory.failing-cleanup/clean-after-failure\" &&
-sed -e 's/Z$//' >expect <<\EOF &&
-not ok - 1 tests clean up even after a failure
-#      Z
-#          touch clean-after-failure &&
-#          test_when_finished rm clean-after-failure &&
-#          (exit 1)
-#      Z
-not ok - 2 failure to clean up causes the test to fail
-#      Z
-#          test_when_finished \"(exit 2)\"
-#      Z
-# failed 2 among 2 test(s)
-1..2
+sed -e 's/Z$//' -e 's/^> //' >expect <<\EOF &&
+not ok - 1 tests clean up even after a failure
+> #    Z
+> #        touch clean-after-failure &&
+> #        test_when_finished rm clean-after-failure &&
+> #        (exit 1)
+> #    Z
+not ok - 2 failure to clean up causes the test to fail
+> #    Z
+> #        test_when_finished \"(exit 2)\"
+> #    Z
+# failed 2 among 2 test(s)
+1..2
 EOF
     test_cmp expect out)
 "
index d44194c35fe5de72af0721a05bb1038f1720b4ac..f6849932112f1bbea1dafad09150857a707b64e4 100755 (executable)
@@ -33,6 +33,62 @@ test_expect_success 'plain' '
        check_config plain/.git false unset
 '
 
+test_expect_success 'plain nested in bare' '
+       (
+               sane_unset GIT_DIR GIT_WORK_TREE &&
+               git init --bare bare-ancestor.git &&
+               cd bare-ancestor.git &&
+               mkdir plain-nested &&
+               cd plain-nested &&
+               git init
+       ) &&
+       check_config bare-ancestor.git/plain-nested/.git false unset
+'
+
+test_expect_success 'plain through aliased command, outside any git repo' '
+       (
+               sane_unset GIT_DIR GIT_WORK_TREE GIT_CONFIG_NOGLOBAL &&
+               HOME=$(pwd)/alias-config &&
+               export HOME &&
+               mkdir alias-config &&
+               echo "[alias] aliasedinit = init" >alias-config/.gitconfig &&
+
+               GIT_CEILING_DIRECTORIES=$(pwd) &&
+               export GIT_CEILING_DIRECTORIES &&
+
+               mkdir plain-aliased &&
+               cd plain-aliased &&
+               git aliasedinit
+       ) &&
+       check_config plain-aliased/.git false unset
+'
+
+test_expect_failure 'plain nested through aliased command' '
+       (
+               sane_unset GIT_DIR GIT_WORK_TREE &&
+               git init plain-ancestor-aliased &&
+               cd plain-ancestor-aliased &&
+               echo "[alias] aliasedinit = init" >>.git/config &&
+               mkdir plain-nested &&
+               cd plain-nested &&
+               git aliasedinit
+       ) &&
+       check_config plain-ancestor-aliased/plain-nested/.git false unset
+'
+
+test_expect_failure 'plain nested in bare through aliased command' '
+       (
+               sane_unset GIT_DIR GIT_WORK_TREE &&
+               git init --bare bare-ancestor-aliased.git &&
+               cd bare-ancestor-aliased.git &&
+               echo "[alias] aliasedinit = init" >>config &&
+               mkdir plain-nested &&
+               cd plain-nested &&
+               git aliasedinit
+       ) &&
+       check_config bare-ancestor-aliased.git/plain-nested/.git false unset
+'
+
 test_expect_success 'plain with GIT_WORK_TREE' '
        if (
                sane_unset GIT_DIR &&
index 828e35baf72d94908ad1f30dbd2e1aa6f9376e69..9078b84ae68b430285312749f62daee103dcc428 100755 (executable)
@@ -93,4 +93,47 @@ test_expect_success expanded_in_repo '
        cmp expanded-keywords expected-output
 '
 
+# The use of %f in a filter definition is expanded to the path to
+# the filename being smudged or cleaned.  It must be shell escaped.
+# First, set up some interesting file names and pet them in
+# .gitattributes.
+test_expect_success 'filter shell-escaped filenames' '
+       cat >argc.sh <<-EOF &&
+       #!$SHELL_PATH
+       cat >/dev/null
+       echo argc: \$# "\$@"
+       EOF
+       normal=name-no-magic &&
+       special="name  with '\''sq'\'' and \$x" &&
+       echo some test text >"$normal" &&
+       echo some test text >"$special" &&
+       git add "$normal" "$special" &&
+       git commit -q -m "add files" &&
+       echo "name* filter=argc" >.gitattributes &&
+
+       # delete the files and check them out again, using a smudge filter
+       # that will count the args and echo the command-line back to us
+       git config filter.argc.smudge "sh ./argc.sh %f" &&
+       rm "$normal" "$special" &&
+       git checkout -- "$normal" "$special" &&
+
+       # make sure argc.sh counted the right number of args
+       echo "argc: 1 $normal" >expect &&
+       test_cmp expect "$normal" &&
+       echo "argc: 1 $special" >expect &&
+       test_cmp expect "$special" &&
+
+       # do the same thing, but with more args in the filter expression
+       git config filter.argc.smudge "sh ./argc.sh %f --my-extra-arg" &&
+       rm "$normal" "$special" &&
+       git checkout -- "$normal" "$special" &&
+
+       # make sure argc.sh counted the right number of args
+       echo "argc: 2 $normal --my-extra-arg" >expect &&
+       test_cmp expect "$normal" &&
+       echo "argc: 2 $special --my-extra-arg" >expect &&
+       test_cmp expect "$special" &&
+       :
+'
+
 test_done
index 057c97c49f26c354e25675e4489c0e94917de33f..1542cf6a1313963fccdf42702c620be9e05f7143 100755 (executable)
@@ -4,8 +4,8 @@ test_description='Various filesystem issues'
 
 . ./test-lib.sh
 
-auml=`printf '\xc3\xa4'`
-aumlcdiar=`printf '\x61\xcc\x88'`
+auml=$(printf '\303\244')
+aumlcdiar=$(printf '\141\314\210')
 
 case_insensitive=
 unibad=
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 0ef11bccb4a84b508b217d5d2bf4ef13c2d13282..de84e35c4357c7329b3fae749228df28f31a9d3f 100755 (executable)
@@ -94,12 +94,20 @@ test_expect_success 'match directories with trailing slash' '
        test -f sub/added
 '
 
-test_expect_failure 'match directories without trailing slash' '
-       echo init.t >.git/info/sparse-checkout &&
+test_expect_success 'match directories without trailing slash' '
        echo sub >>.git/info/sparse-checkout &&
        git read-tree -m -u HEAD &&
        git ls-files -t >result &&
-       test_cmp expected.swt result &&
+       test_cmp expected.swt-noinit result &&
+       test ! -f init.t &&
+       test -f sub/added
+'
+
+test_expect_success 'match directory pattern' '
+       echo "s?b" >>.git/info/sparse-checkout &&
+       git read-tree -m -u HEAD &&
+       git ls-files -t >result &&
+       test_cmp expected.swt-noinit result &&
        test ! -f init.t &&
        test -f sub/added
 '
index a3ac33801a28fe7bd2ce67d4d4ae306c1050f5c1..1fd187c5eb188671934f6afe85ca5003c529a942 100755 (executable)
@@ -110,6 +110,14 @@ test_expect_success 'read-tree' '
        )
 '
 
+test_expect_success 'alias expansion' '
+       (
+               git config alias.ss status &&
+               cd dir &&
+               git status &&
+               git ss
+       )
+'
 test_expect_success 'no file/rev ambiguity check inside .git' '
        git commit -a -m 1 &&
        (
index 2c8f01f6684cbe492132575209f79371ad761d87..da6252b1179c47d39393c983d88c75d84a507cb7 100755 (executable)
@@ -340,4 +340,11 @@ test_expect_success 'make_relative_path handles double slashes in GIT_DIR' '
        git --git-dir="$(pwd)//repo.git" --work-tree="$(pwd)" add dummy_file
 '
 
+test_expect_success 'relative $GIT_WORK_TREE and git subprocesses' '
+       GIT_DIR=repo.git GIT_WORK_TREE=repo.git/work \
+       test-subprocess --setup-work-tree rev-parse --show-toplevel >actual &&
+       echo "$(pwd)/repo.git/work" >expected &&
+       test_cmp expected actual
+'
+
 test_done
index 0eeeb0e45090661c0576607792ff9b91d096e282..9f8adb1f824a5bafe8829e5ab613e2ab83065f4f 100755 (executable)
@@ -31,6 +31,67 @@ test_expect_success 'correct file objects' '
         test $HASH_file = $(git rev-parse :0:file.txt) )
 '
 
+test_expect_success 'correct relative file objects (0)' '
+       git rev-parse :file.txt >expected &&
+       git rev-parse :./file.txt >result &&
+       test_cmp expected result &&
+       git rev-parse :0:./file.txt >result &&
+       test_cmp expected result
+'
+
+test_expect_success 'correct relative file objects (1)' '
+       git rev-parse HEAD:file.txt >expected &&
+       git rev-parse HEAD:./file.txt >result &&
+       test_cmp expected result
+'
+
+test_expect_success 'correct relative file objects (2)' '
+       (
+               cd subdir &&
+               git rev-parse HEAD:../file.txt >result &&
+               test_cmp ../expected result
+       )
+'
+
+test_expect_success 'correct relative file objects (3)' '
+       (
+               cd subdir &&
+               git rev-parse HEAD:../subdir/../file.txt >result &&
+               test_cmp ../expected result
+       )
+'
+
+test_expect_success 'correct relative file objects (4)' '
+       git rev-parse HEAD:subdir/file.txt >expected &&
+       (
+               cd subdir &&
+               git rev-parse HEAD:./file.txt >result &&
+               test_cmp ../expected result
+       )
+'
+
+test_expect_success 'correct relative file objects (5)' '
+       git rev-parse :subdir/file.txt >expected &&
+       (
+               cd subdir &&
+               git rev-parse :./file.txt >result &&
+               test_cmp ../expected result &&
+               git rev-parse :0:./file.txt >result &&
+               test_cmp ../expected result
+       )
+'
+
+test_expect_success 'correct relative file objects (6)' '
+       git rev-parse :file.txt >expected &&
+       (
+               cd subdir &&
+               git rev-parse :../file.txt >result &&
+               test_cmp ../expected result &&
+               git rev-parse :0:../file.txt >result &&
+               test_cmp ../expected result
+       )
+'
+
 test_expect_success 'incorrect revision id' '
        test_must_fail git rev-parse foobar:file.txt 2>error &&
        grep "Invalid object name '"'"'foobar'"'"'." error &&
@@ -75,4 +136,29 @@ test_expect_success 'invalid @{n} reference' '
        grep "fatal: Log for [^ ]* only has [0-9][0-9]* entries." error
 '
 
+test_expect_success 'relative path not found' '
+       (
+               cd subdir &&
+               test_must_fail git rev-parse HEAD:./nonexistent.txt 2>error &&
+               grep subdir/nonexistent.txt error
+       )
+'
+
+test_expect_success 'relative path outside worktree' '
+       test_must_fail git rev-parse HEAD:../file.txt >output 2>error &&
+       test -z "$(cat output)" &&
+       grep "outside repository" error
+'
+
+test_expect_success 'relative path when cwd is outside worktree' '
+       test_must_fail git --git-dir=.git --work-tree=subdir rev-parse HEAD:./file.txt >output 2>error &&
+       test -z "$(cat output)" &&
+       grep "relative path syntax can.t be used outside working tree." error
+'
+
+test_expect_success 'relative path when startup_info is NULL' '
+       test_must_fail test-match-trees HEAD:./file.txt HEAD:./file.txt 2>error &&
+       grep "BUG: startup_info struct is not initialized." error
+'
+
 test_done
diff --git a/t/t1510-repo-setup.sh b/t/t1510-repo-setup.sh
new file mode 100755 (executable)
index 0000000..15101d5
--- /dev/null
@@ -0,0 +1,776 @@
+#!/bin/sh
+
+test_description="Tests of cwd/prefix/worktree/gitdir setup in all cases
+
+A few rules for repo setup:
+
+1. GIT_DIR is relative to user's cwd. --git-dir is equivalent to
+   GIT_DIR.
+
+2. .git file is relative to parent directory. .git file is basically
+   symlink in disguise. The directory where .git file points to will
+   become new git_dir.
+
+3. core.worktree is relative to git_dir.
+
+4. GIT_WORK_TREE is relative to user's cwd. --work-tree is
+   equivalent to GIT_WORK_TREE.
+
+5. GIT_WORK_TREE/core.worktree was originally meant to work only if
+   GIT_DIR is set, but earlier git didn't enforce it, and some scripts
+   depend on the implementation that happened to first discover .git by
+   going up from the users $cwd and then using the specified working tree
+   that may or may not have any relation to where .git was found in.  This
+   historical behaviour must be kept.
+
+6. Effective GIT_WORK_TREE overrides core.worktree and core.bare
+
+7. Effective core.worktree conflicts with core.bare
+
+8. If GIT_DIR is set but neither worktree nor bare setting is given,
+   original cwd becomes worktree.
+
+9. If .git discovery is done inside a repo, the repo becomes a bare
+   repo. .git discovery is performed if GIT_DIR is not set.
+
+10. If no worktree is available, cwd remains unchanged, prefix is
+    NULL.
+
+11. When user's cwd is outside worktree, cwd remains unchanged,
+    prefix is NULL.
+"
+. ./test-lib.sh
+
+here=$(pwd)
+
+test_repo () {
+       (
+               cd "$1" &&
+               if test -n "$2"
+               then
+                       GIT_DIR="$2" &&
+                       export GIT_DIR
+               fi &&
+               if test -n "$3"
+               then
+                       GIT_WORK_TREE="$3" &&
+                       export GIT_WORK_TREE
+               fi &&
+               rm -f trace &&
+               GIT_TRACE="$(pwd)/trace" git symbolic-ref HEAD >/dev/null &&
+               grep '^setup: ' trace >result &&
+               test_cmp expected result
+       )
+}
+
+maybe_config () {
+       file=$1 var=$2 value=$3 &&
+       if test "$value" != unset
+       then
+               git config --file="$file" "$var" "$value"
+       fi
+}
+
+setup_repo () {
+       name=$1 worktreecfg=$2 gitfile=$3 barecfg=$4 &&
+       sane_unset GIT_DIR GIT_WORK_TREE &&
+
+       git init "$name" &&
+       maybe_config "$name/.git/config" core.worktree "$worktreecfg" &&
+       maybe_config "$name/.git/config" core.bare "$barecfg" &&
+       mkdir -p "$name/sub/sub" &&
+
+       if test "${gitfile:+set}"
+       then
+               mv "$name/.git" "$name.git" &&
+               echo "gitdir: ../$name.git" >"$name/.git"
+       fi
+}
+
+maybe_set () {
+       var=$1 value=$2 &&
+       if test "$value" != unset
+       then
+               eval "$var=\$value" &&
+               export $var
+       fi
+}
+
+setup_env () {
+       worktreenv=$1 gitdirenv=$2 &&
+       sane_unset GIT_DIR GIT_WORK_TREE &&
+       maybe_set GIT_DIR "$gitdirenv" &&
+       maybe_set GIT_WORK_TREE "$worktreeenv"
+}
+
+expect () {
+       cat >"$1/expected" <<-EOF
+       setup: git_dir: $2
+       setup: worktree: $3
+       setup: cwd: $4
+       setup: prefix: $5
+       EOF
+}
+
+try_case () {
+       name=$1 worktreeenv=$2 gitdirenv=$3 &&
+       setup_env "$worktreeenv" "$gitdirenv" &&
+       expect "$name" "$4" "$5" "$6" "$7" &&
+       test_repo "$name"
+}
+
+run_wt_tests () {
+       N=$1 gitfile=$2
+
+       absgit="$here/$N/.git"
+       dotgit=.git
+       dotdotgit=../../.git
+
+       if test "$gitfile"
+       then
+               absgit="$here/$N.git"
+               dotgit=$absgit dotdotgit=$absgit
+       fi
+
+       test_expect_success "#$N: explicit GIT_WORK_TREE and GIT_DIR at toplevel" '
+               try_case $N "$here/$N" .git \
+                       "$dotgit" "$here/$N" "$here/$N" "(null)" &&
+               try_case $N . .git \
+                       "$dotgit" "$here/$N" "$here/$N" "(null)" &&
+               try_case $N "$here/$N" "$here/$N/.git" \
+                       "$absgit" "$here/$N" "$here/$N" "(null)" &&
+               try_case $N . "$here/$N/.git" \
+                       "$absgit" "$here/$N" "$here/$N" "(null)"
+       '
+
+       test_expect_success "#$N: explicit GIT_WORK_TREE and GIT_DIR in subdir" '
+               try_case $N/sub/sub "$here/$N" ../../.git \
+                       "$absgit" "$here/$N" "$here/$N" sub/sub/ &&
+               try_case $N/sub/sub ../.. ../../.git \
+                       "$absgit" "$here/$N" "$here/$N" sub/sub/ &&
+               try_case $N/sub/sub "$here/$N" "$here/$N/.git" \
+                       "$absgit" "$here/$N" "$here/$N" sub/sub/ &&
+               try_case $N/sub/sub ../.. "$here/$N/.git" \
+                       "$absgit" "$here/$N" "$here/$N" sub/sub/
+       '
+
+       test_expect_success "#$N: explicit GIT_WORK_TREE from parent of worktree" '
+               try_case $N "$here/$N/wt" .git \
+                       "$dotgit" "$here/$N/wt" "$here/$N" "(null)" &&
+               try_case $N wt .git \
+                       "$dotgit" "$here/$N/wt" "$here/$N" "(null)" &&
+               try_case $N wt "$here/$N/.git" \
+                       "$absgit" "$here/$N/wt" "$here/$N" "(null)" &&
+               try_case $N "$here/$N/wt" "$here/$N/.git" \
+                       "$absgit" "$here/$N/wt" "$here/$N" "(null)"
+       '
+
+       test_expect_success "#$N: explicit GIT_WORK_TREE from nephew of worktree" '
+               try_case $N/sub/sub "$here/$N/wt" ../../.git \
+                       "$dotdotgit" "$here/$N/wt" "$here/$N/sub/sub" "(null)" &&
+               try_case $N/sub/sub ../../wt ../../.git \
+                       "$dotdotgit" "$here/$N/wt" "$here/$N/sub/sub" "(null)" &&
+               try_case $N/sub/sub ../../wt "$here/$N/.git" \
+                       "$absgit" "$here/$N/wt" "$here/$N/sub/sub" "(null)" &&
+               try_case $N/sub/sub "$here/$N/wt" "$here/$N/.git" \
+                       "$absgit" "$here/$N/wt" "$here/$N/sub/sub" "(null)"
+       '
+
+       test_expect_success "#$N: chdir_to_toplevel uses worktree, not git dir" '
+               try_case $N "$here" .git \
+                       "$absgit" "$here" "$here" $N/ &&
+               try_case $N .. .git \
+                       "$absgit" "$here" "$here" $N/ &&
+               try_case $N .. "$here/$N/.git" \
+                       "$absgit" "$here" "$here" $N/ &&
+               try_case $N "$here" "$here/$N/.git" \
+                       "$absgit" "$here" "$here" $N/
+       '
+
+       test_expect_success "#$N: chdir_to_toplevel uses worktree (from subdir)" '
+               try_case $N/sub/sub "$here" ../../.git \
+                       "$absgit" "$here" "$here" $N/sub/sub/ &&
+               try_case $N/sub/sub ../../.. ../../.git \
+                       "$absgit" "$here" "$here" $N/sub/sub/ &&
+               try_case $N/sub/sub ../../../ "$here/$N/.git" \
+                       "$absgit" "$here" "$here" $N/sub/sub/ &&
+               try_case $N/sub/sub "$here" "$here/$N/.git" \
+                       "$absgit" "$here" "$here" $N/sub/sub/
+       '
+}
+
+# try_repo #c GIT_WORK_TREE GIT_DIR core.worktree .gitfile? core.bare \
+#      (git dir) (work tree) (cwd) (prefix) \  <-- at toplevel
+#      (git dir) (work tree) (cwd) (prefix)    <-- from subdir
+try_repo () {
+       name=$1 worktreeenv=$2 gitdirenv=$3 &&
+       setup_repo "$name" "$4" "$5" "$6" &&
+       shift 6 &&
+       try_case "$name" "$worktreeenv" "$gitdirenv" \
+               "$1" "$2" "$3" "$4" &&
+       shift 4 &&
+       case "$gitdirenv" in
+       /* | ?:/* | unset) ;;
+       *)
+               gitdirenv=../$gitdirenv ;;
+       esac &&
+       try_case "$name/sub" "$worktreeenv" "$gitdirenv" \
+               "$1" "$2" "$3" "$4"
+}
+
+# Bit 0 = GIT_WORK_TREE
+# Bit 1 = GIT_DIR
+# Bit 2 = core.worktree
+# Bit 3 = .git is a file
+# Bit 4 = bare repo
+# Case# = encoding of the above 5 bits
+
+test_expect_success '#0: nonbare repo, no explicit configuration' '
+       try_repo 0 unset unset unset "" unset \
+               .git "$here/0" "$here/0" "(null)" \
+               .git "$here/0" "$here/0" sub/ 2>message &&
+       ! test -s message
+'
+
+test_expect_success '#1: GIT_WORK_TREE without explicit GIT_DIR is accepted' '
+       mkdir -p wt &&
+       try_repo 1 "$here" unset unset "" unset \
+               "$here/1/.git" "$here" "$here" 1/ \
+               "$here/1/.git" "$here" "$here" 1/sub/ 2>message &&
+       ! test -s message
+'
+
+test_expect_success '#2: worktree defaults to cwd with explicit GIT_DIR' '
+       try_repo 2 unset "$here/2/.git" unset "" unset \
+               "$here/2/.git" "$here/2" "$here/2" "(null)" \
+               "$here/2/.git" "$here/2/sub" "$here/2/sub" "(null)"
+'
+
+test_expect_success '#2b: relative GIT_DIR' '
+       try_repo 2b unset ".git" unset "" unset \
+               ".git" "$here/2b" "$here/2b" "(null)" \
+               "../.git" "$here/2b/sub" "$here/2b/sub" "(null)"
+'
+
+test_expect_success '#3: setup' '
+       setup_repo 3 unset "" unset &&
+       mkdir -p 3/sub/sub 3/wt/sub
+'
+run_wt_tests 3
+
+test_expect_success '#4: core.worktree without GIT_DIR set is accepted' '
+       setup_repo 4 ../sub "" unset &&
+       mkdir -p 4/sub sub &&
+       try_case 4 unset unset \
+               .git "$here/4/sub" "$here/4" "(null)" \
+               "$here/4/.git" "$here/4/sub" "$here/4/sub" "(null)" 2>message &&
+       ! test -s message
+'
+
+test_expect_success '#5: core.worktree + GIT_WORK_TREE is accepted' '
+       # or: you cannot intimidate away the lack of GIT_DIR setting
+       try_repo 5 "$here" unset "$here/5" "" unset \
+               "$here/5/.git" "$here" "$here" 5/ \
+               "$here/5/.git" "$here" "$here" 5/sub/ 2>message &&
+       try_repo 5a .. unset "$here/5a" "" unset \
+               "$here/5a/.git" "$here" "$here" 5a/ \
+               "$here/5a/.git" "$here/5a" "$here/5a" sub/ &&
+       ! test -s message
+'
+
+test_expect_success '#6: setting GIT_DIR brings core.worktree to life' '
+       setup_repo 6 "$here/6" "" unset &&
+       try_case 6 unset .git \
+               .git "$here/6" "$here/6" "(null)" &&
+       try_case 6 unset "$here/6/.git" \
+               "$here/6/.git" "$here/6" "$here/6" "(null)" &&
+       try_case 6/sub/sub unset ../../.git \
+               "$here/6/.git" "$here/6" "$here/6" sub/sub/ &&
+       try_case 6/sub/sub unset "$here/6/.git" \
+               "$here/6/.git" "$here/6" "$here/6" sub/sub/
+'
+
+test_expect_success '#6b: GIT_DIR set, core.worktree relative' '
+       setup_repo 6b .. "" unset &&
+       try_case 6b unset .git \
+               .git "$here/6b" "$here/6b" "(null)" &&
+       try_case 6b unset "$here/6b/.git" \
+               "$here/6b/.git" "$here/6b" "$here/6b" "(null)" &&
+       try_case 6b/sub/sub unset ../../.git \
+               "$here/6b/.git" "$here/6b" "$here/6b" sub/sub/ &&
+       try_case 6b/sub/sub unset "$here/6b/.git" \
+               "$here/6b/.git" "$here/6b" "$here/6b" sub/sub/
+'
+
+test_expect_success '#6c: GIT_DIR set, core.worktree=../wt (absolute)' '
+       setup_repo 6c "$here/6c/wt" "" unset &&
+       mkdir -p 6c/wt/sub &&
+
+       try_case 6c unset .git \
+               .git "$here/6c/wt" "$here/6c" "(null)" &&
+       try_case 6c unset "$here/6c/.git" \
+               "$here/6c/.git" "$here/6c/wt" "$here/6c" "(null)" &&
+       try_case 6c/sub/sub unset ../../.git \
+               ../../.git "$here/6c/wt" "$here/6c/sub/sub" "(null)" &&
+       try_case 6c/sub/sub unset "$here/6c/.git" \
+               "$here/6c/.git" "$here/6c/wt" "$here/6c/sub/sub" "(null)"
+'
+
+test_expect_success '#6d: GIT_DIR set, core.worktree=../wt (relative)' '
+       setup_repo 6d "$here/6d/wt" "" unset &&
+       mkdir -p 6d/wt/sub &&
+
+       try_case 6d unset .git \
+               .git "$here/6d/wt" "$here/6d" "(null)" &&
+       try_case 6d unset "$here/6d/.git" \
+               "$here/6d/.git" "$here/6d/wt" "$here/6d" "(null)" &&
+       try_case 6d/sub/sub unset ../../.git \
+               ../../.git "$here/6d/wt" "$here/6d/sub/sub" "(null)" &&
+       try_case 6d/sub/sub unset "$here/6d/.git" \
+               "$here/6d/.git" "$here/6d/wt" "$here/6d/sub/sub" "(null)"
+'
+
+test_expect_success '#6e: GIT_DIR set, core.worktree=../.. (absolute)' '
+       setup_repo 6e "$here" "" unset &&
+       try_case 6e unset .git \
+               "$here/6e/.git" "$here" "$here" 6e/ &&
+       try_case 6e unset "$here/6e/.git" \
+               "$here/6e/.git" "$here" "$here" 6e/ &&
+       try_case 6e/sub/sub unset ../../.git \
+               "$here/6e/.git" "$here" "$here" 6e/sub/sub/ &&
+       try_case 6e/sub/sub unset "$here/6e/.git" \
+               "$here/6e/.git" "$here" "$here" 6e/sub/sub/
+'
+
+test_expect_success '#6f: GIT_DIR set, core.worktree=../.. (relative)' '
+       setup_repo 6f ../../ "" unset &&
+       try_case 6f unset .git \
+               "$here/6f/.git" "$here" "$here" 6f/ &&
+       try_case 6f unset "$here/6f/.git" \
+               "$here/6f/.git" "$here" "$here" 6f/ &&
+       try_case 6f/sub/sub unset ../../.git \
+               "$here/6f/.git" "$here" "$here" 6f/sub/sub/ &&
+       try_case 6f/sub/sub unset "$here/6f/.git" \
+               "$here/6f/.git" "$here" "$here" 6f/sub/sub/
+'
+
+# case #7: GIT_WORK_TREE overrides core.worktree.
+test_expect_success '#7: setup' '
+       setup_repo 7 non-existent "" unset &&
+       mkdir -p 7/sub/sub 7/wt/sub
+'
+run_wt_tests 7
+
+test_expect_success '#8: gitfile, easy case' '
+       try_repo 8 unset unset unset gitfile unset \
+               "$here/8.git" "$here/8" "$here/8" "(null)" \
+               "$here/8.git" "$here/8" "$here/8" sub/
+'
+
+test_expect_success '#9: GIT_WORK_TREE accepted with gitfile' '
+       mkdir -p 9/wt &&
+       try_repo 9 wt unset unset gitfile unset \
+               "$here/9.git" "$here/9/wt" "$here/9" "(null)" \
+               "$here/9.git" "$here/9/sub/wt" "$here/9/sub" "(null)" 2>message &&
+       ! test -s message
+'
+
+test_expect_success '#10: GIT_DIR can point to gitfile' '
+       try_repo 10 unset "$here/10/.git" unset gitfile unset \
+               "$here/10.git" "$here/10" "$here/10" "(null)" \
+               "$here/10.git" "$here/10/sub" "$here/10/sub" "(null)"
+'
+
+test_expect_success '#10b: relative GIT_DIR can point to gitfile' '
+       try_repo 10b unset .git unset gitfile unset \
+               "$here/10b.git" "$here/10b" "$here/10b" "(null)" \
+               "$here/10b.git" "$here/10b/sub" "$here/10b/sub" "(null)"
+'
+
+# case #11: GIT_WORK_TREE works, gitfile case.
+test_expect_success '#11: setup' '
+       setup_repo 11 unset gitfile unset &&
+       mkdir -p 11/sub/sub 11/wt/sub
+'
+run_wt_tests 11 gitfile
+
+test_expect_success '#12: core.worktree with gitfile is accepted' '
+       try_repo 12 unset unset "$here/12" gitfile unset \
+               "$here/12.git" "$here/12" "$here/12" "(null)" \
+               "$here/12.git" "$here/12" "$here/12" sub/ 2>message &&
+       ! test -s message
+'
+
+test_expect_success '#13: core.worktree+GIT_WORK_TREE accepted (with gitfile)' '
+       # or: you cannot intimidate away the lack of GIT_DIR setting
+       try_repo 13 non-existent-too unset non-existent gitfile unset \
+               "$here/13.git" "$here/13/non-existent-too" "$here/13" "(null)" \
+               "$here/13.git" "$here/13/sub/non-existent-too" "$here/13/sub" "(null)" 2>message &&
+       ! test -s message
+'
+
+# case #14.
+# If this were more table-driven, it could share code with case #6.
+
+test_expect_success '#14: core.worktree with GIT_DIR pointing to gitfile' '
+       setup_repo 14 "$here/14" gitfile unset &&
+       try_case 14 unset .git \
+               "$here/14.git" "$here/14" "$here/14" "(null)" &&
+       try_case 14 unset "$here/14/.git" \
+               "$here/14.git" "$here/14" "$here/14" "(null)" &&
+       try_case 14/sub/sub unset ../../.git \
+               "$here/14.git" "$here/14" "$here/14" sub/sub/ &&
+       try_case 14/sub/sub unset "$here/14/.git" \
+               "$here/14.git" "$here/14" "$here/14" sub/sub/ &&
+
+       setup_repo 14c "$here/14c/wt" gitfile unset &&
+       mkdir -p 14c/wt/sub &&
+
+       try_case 14c unset .git \
+               "$here/14c.git" "$here/14c/wt" "$here/14c" "(null)" &&
+       try_case 14c unset "$here/14c/.git" \
+               "$here/14c.git" "$here/14c/wt" "$here/14c" "(null)" &&
+       try_case 14c/sub/sub unset ../../.git \
+               "$here/14c.git" "$here/14c/wt" "$here/14c/sub/sub" "(null)" &&
+       try_case 14c/sub/sub unset "$here/14c/.git" \
+               "$here/14c.git" "$here/14c/wt" "$here/14c/sub/sub" "(null)" &&
+
+       setup_repo 14d "$here/14d/wt" gitfile unset &&
+       mkdir -p 14d/wt/sub &&
+
+       try_case 14d unset .git \
+               "$here/14d.git" "$here/14d/wt" "$here/14d" "(null)" &&
+       try_case 14d unset "$here/14d/.git" \
+               "$here/14d.git" "$here/14d/wt" "$here/14d" "(null)" &&
+       try_case 14d/sub/sub unset ../../.git \
+               "$here/14d.git" "$here/14d/wt" "$here/14d/sub/sub" "(null)" &&
+       try_case 14d/sub/sub unset "$here/14d/.git" \
+               "$here/14d.git" "$here/14d/wt" "$here/14d/sub/sub" "(null)" &&
+
+       setup_repo 14e "$here" gitfile unset &&
+       try_case 14e unset .git \
+               "$here/14e.git" "$here" "$here" 14e/ &&
+       try_case 14e unset "$here/14e/.git" \
+               "$here/14e.git" "$here" "$here" 14e/ &&
+       try_case 14e/sub/sub unset ../../.git \
+               "$here/14e.git" "$here" "$here" 14e/sub/sub/ &&
+       try_case 14e/sub/sub unset "$here/14e/.git" \
+               "$here/14e.git" "$here" "$here" 14e/sub/sub/
+'
+
+test_expect_success '#14b: core.worktree is relative to actual git dir' '
+       setup_repo 14b ../14b gitfile unset &&
+       try_case 14b unset .git \
+               "$here/14b.git" "$here/14b" "$here/14b" "(null)" &&
+       try_case 14b unset "$here/14b/.git" \
+               "$here/14b.git" "$here/14b" "$here/14b" "(null)" &&
+       try_case 14b/sub/sub unset ../../.git \
+               "$here/14b.git" "$here/14b" "$here/14b" sub/sub/ &&
+       try_case 14b/sub/sub unset "$here/14b/.git" \
+               "$here/14b.git" "$here/14b" "$here/14b" sub/sub/ &&
+
+       setup_repo 14f ../ gitfile unset &&
+       try_case 14f unset .git \
+               "$here/14f.git" "$here" "$here" 14f/ &&
+       try_case 14f unset "$here/14f/.git" \
+               "$here/14f.git" "$here" "$here" 14f/ &&
+       try_case 14f/sub/sub unset ../../.git \
+               "$here/14f.git" "$here" "$here" 14f/sub/sub/ &&
+       try_case 14f/sub/sub unset "$here/14f/.git" \
+               "$here/14f.git" "$here" "$here" 14f/sub/sub/
+'
+
+# case #15: GIT_WORK_TREE overrides core.worktree (gitfile case).
+test_expect_success '#15: setup' '
+       setup_repo 15 non-existent gitfile unset &&
+       mkdir -p 15/sub/sub 15/wt/sub
+'
+run_wt_tests 15 gitfile
+
+test_expect_success '#16a: implicitly bare repo (cwd inside .git dir)' '
+       setup_repo 16a unset "" unset &&
+       mkdir -p 16a/.git/wt/sub &&
+
+       try_case 16a/.git unset unset \
+               . "(null)" "$here/16a/.git" "(null)" &&
+       try_case 16a/.git/wt unset unset \
+               "$here/16a/.git" "(null)" "$here/16a/.git/wt" "(null)" &&
+       try_case 16a/.git/wt/sub unset unset \
+               "$here/16a/.git" "(null)" "$here/16a/.git/wt/sub" "(null)"
+'
+
+test_expect_success '#16b: bare .git (cwd inside .git dir)' '
+       setup_repo 16b unset "" true &&
+       mkdir -p 16b/.git/wt/sub &&
+
+       try_case 16b/.git unset unset \
+               . "(null)" "$here/16b/.git" "(null)" &&
+       try_case 16b/.git/wt unset unset \
+               "$here/16b/.git" "(null)" "$here/16b/.git/wt" "(null)" &&
+       try_case 16b/.git/wt/sub unset unset \
+               "$here/16b/.git" "(null)" "$here/16b/.git/wt/sub" "(null)"
+'
+
+test_expect_success '#16c: bare .git has no worktree' '
+       try_repo 16c unset unset unset "" true \
+               .git "(null)" "$here/16c" "(null)" \
+               "$here/16c/.git" "(null)" "$here/16c/sub" "(null)"
+'
+
+test_expect_success '#17: GIT_WORK_TREE without explicit GIT_DIR is accepted (bare case)' '
+       # Just like #16.
+       setup_repo 17a unset "" true &&
+       setup_repo 17b unset "" true &&
+       mkdir -p 17a/.git/wt/sub &&
+       mkdir -p 17b/.git/wt/sub &&
+
+       try_case 17a/.git "$here/17a" unset \
+               "$here/17a/.git" "$here/17a" "$here/17a" .git/ \
+               2>message &&
+       try_case 17a/.git/wt "$here/17a" unset \
+               "$here/17a/.git" "$here/17a" "$here/17a" .git/wt/ &&
+       try_case 17a/.git/wt/sub "$here/17a" unset \
+               "$here/17a/.git" "$here/17a" "$here/17a" .git/wt/sub/ &&
+
+       try_case 17b/.git "$here/17b" unset \
+               "$here/17b/.git" "$here/17b" "$here/17b" .git/ &&
+       try_case 17b/.git/wt "$here/17b" unset \
+               "$here/17b/.git" "$here/17b" "$here/17b" .git/wt/ &&
+       try_case 17b/.git/wt/sub "$here/17b" unset \
+               "$here/17b/.git" "$here/17b" "$here/17b" .git/wt/sub/ &&
+
+       try_repo 17c "$here/17c" unset unset "" true \
+               .git "$here/17c" "$here/17c" "(null)" \
+               "$here/17c/.git" "$here/17c" "$here/17c" sub/ 2>message &&
+       ! test -s message
+'
+
+test_expect_success '#18: bare .git named by GIT_DIR has no worktree' '
+       try_repo 18 unset .git unset "" true \
+               .git "(null)" "$here/18" "(null)" \
+               ../.git "(null)" "$here/18/sub" "(null)" &&
+       try_repo 18b unset "$here/18b/.git" unset "" true \
+               "$here/18b/.git" "(null)" "$here/18b" "(null)" \
+               "$here/18b/.git" "(null)" "$here/18b/sub" "(null)"
+'
+
+# Case #19: GIT_DIR + GIT_WORK_TREE suppresses bareness.
+test_expect_success '#19: setup' '
+       setup_repo 19 unset "" true &&
+       mkdir -p 19/sub/sub 19/wt/sub
+'
+run_wt_tests 19
+
+test_expect_success '#20a: core.worktree without GIT_DIR accepted (inside .git)' '
+       # Unlike case #16a.
+       setup_repo 20a "$here/20a" "" unset &&
+       mkdir -p 20a/.git/wt/sub &&
+       try_case 20a/.git unset unset \
+               "$here/20a/.git" "$here/20a" "$here/20a" .git/ 2>message &&
+       try_case 20a/.git/wt unset unset \
+               "$here/20a/.git" "$here/20a" "$here/20a" .git/wt/ &&
+       try_case 20a/.git/wt/sub unset unset \
+               "$here/20a/.git" "$here/20a" "$here/20a" .git/wt/sub/ &&
+       ! test -s message
+'
+
+test_expect_success '#20b/c: core.worktree and core.bare conflict' '
+       setup_repo 20b non-existent "" true &&
+       mkdir -p 20b/.git/wt/sub &&
+       (
+               cd 20b/.git &&
+               test_must_fail git symbolic-ref HEAD >/dev/null
+       ) 2>message &&
+       grep "core.bare and core.worktree" message
+'
+
+# Case #21: core.worktree/GIT_WORK_TREE overrides core.bare' '
+test_expect_success '#21: setup, core.worktree warns before overriding core.bare' '
+       setup_repo 21 non-existent "" unset &&
+       mkdir -p 21/.git/wt/sub &&
+       (
+               cd 21/.git &&
+               GIT_WORK_TREE="$here/21" &&
+               export GIT_WORK_TREE &&
+               git symbolic-ref HEAD >/dev/null
+       ) 2>message &&
+       ! test -s message
+
+'
+run_wt_tests 21
+
+test_expect_success '#22a: core.worktree = GIT_DIR = .git dir' '
+       # like case #6.
+
+       setup_repo 22a "$here/22a/.git" "" unset &&
+       setup_repo 22ab . "" unset
+       mkdir -p 22a/.git/sub 22a/sub &&
+       mkdir -p 22ab/.git/sub 22ab/sub &&
+       try_case 22a/.git unset . \
+               . "$here/22a/.git" "$here/22a/.git" "(null)" &&
+       try_case 22a/.git unset "$here/22a/.git" \
+               "$here/22a/.git" "$here/22a/.git" "$here/22a/.git" "(null)" &&
+       try_case 22a/.git/sub unset .. \
+               "$here/22a/.git" "$here/22a/.git" "$here/22a/.git" sub/ &&
+       try_case 22a/.git/sub unset "$here/22a/.git" \
+               "$here/22a/.git" "$here/22a/.git" "$here/22a/.git" sub/ &&
+
+       try_case 22ab/.git unset . \
+               . "$here/22ab/.git" "$here/22ab/.git" "(null)" &&
+       try_case 22ab/.git unset "$here/22ab/.git" \
+               "$here/22ab/.git" "$here/22ab/.git" "$here/22ab/.git" "(null)" &&
+       try_case 22ab/.git/sub unset .. \
+               "$here/22ab/.git" "$here/22ab/.git" "$here/22ab/.git" sub/ &&
+       try_case 22ab/.git unset "$here/22ab/.git" \
+               "$here/22ab/.git" "$here/22ab/.git" "$here/22ab/.git" "(null)"
+'
+
+test_expect_success '#22b: core.worktree child of .git, GIT_DIR=.git' '
+       setup_repo 22b "$here/22b/.git/wt" "" unset &&
+       setup_repo 22bb wt "" unset &&
+       mkdir -p 22b/.git/sub 22b/sub 22b/.git/wt/sub 22b/wt/sub &&
+       mkdir -p 22bb/.git/sub 22bb/sub 22bb/.git/wt 22bb/wt &&
+
+       try_case 22b/.git unset . \
+               . "$here/22b/.git/wt" "$here/22b/.git" "(null)" &&
+       try_case 22b/.git unset "$here/22b/.git" \
+               "$here/22b/.git" "$here/22b/.git/wt" "$here/22b/.git" "(null)" &&
+       try_case 22b/.git/sub unset .. \
+               .. "$here/22b/.git/wt" "$here/22b/.git/sub" "(null)" &&
+       try_case 22b/.git/sub unset "$here/22b/.git" \
+               "$here/22b/.git" "$here/22b/.git/wt" "$here/22b/.git/sub" "(null)" &&
+
+       try_case 22bb/.git unset . \
+               . "$here/22bb/.git/wt" "$here/22bb/.git" "(null)" &&
+       try_case 22bb/.git unset "$here/22bb/.git" \
+               "$here/22bb/.git" "$here/22bb/.git/wt" "$here/22bb/.git" "(null)" &&
+       try_case 22bb/.git/sub unset .. \
+               .. "$here/22bb/.git/wt" "$here/22bb/.git/sub" "(null)" &&
+       try_case 22bb/.git/sub unset "$here/22bb/.git" \
+               "$here/22bb/.git" "$here/22bb/.git/wt" "$here/22bb/.git/sub" "(null)"
+'
+
+test_expect_success '#22c: core.worktree = .git/.., GIT_DIR=.git' '
+       setup_repo 22c "$here/22c" "" unset &&
+       setup_repo 22cb .. "" unset &&
+       mkdir -p 22c/.git/sub 22c/sub &&
+       mkdir -p 22cb/.git/sub 22cb/sub &&
+
+       try_case 22c/.git unset . \
+               "$here/22c/.git" "$here/22c" "$here/22c" .git/ &&
+       try_case 22c/.git unset "$here/22c/.git" \
+               "$here/22c/.git" "$here/22c" "$here/22c" .git/ &&
+       try_case 22c/.git/sub unset .. \
+               "$here/22c/.git" "$here/22c" "$here/22c" .git/sub/ &&
+       try_case 22c/.git/sub unset "$here/22c/.git" \
+               "$here/22c/.git" "$here/22c" "$here/22c" .git/sub/ &&
+
+       try_case 22cb/.git unset . \
+               "$here/22cb/.git" "$here/22cb" "$here/22cb" .git/ &&
+       try_case 22cb/.git unset "$here/22cb/.git" \
+               "$here/22cb/.git" "$here/22cb" "$here/22cb" .git/ &&
+       try_case 22cb/.git/sub unset .. \
+               "$here/22cb/.git" "$here/22cb" "$here/22cb" .git/sub/ &&
+       try_case 22cb/.git/sub unset "$here/22cb/.git" \
+               "$here/22cb/.git" "$here/22cb" "$here/22cb" .git/sub/
+'
+
+test_expect_success '#22.2: core.worktree and core.bare conflict' '
+       setup_repo 22 "$here/22" "" true &&
+       (
+               cd 22/.git &&
+               GIT_DIR=. &&
+               export GIT_DIR &&
+               test_must_fail git symbolic-ref HEAD 2>result
+       ) &&
+       (
+               cd 22 &&
+               GIT_DIR=.git &&
+               export GIT_DIR &&
+               test_must_fail git symbolic-ref HEAD 2>result
+       ) &&
+       grep "core.bare and core.worktree" 22/.git/result &&
+       grep "core.bare and core.worktree" 22/result
+'
+
+# Case #23: GIT_DIR + GIT_WORK_TREE(+core.worktree) suppresses bareness.
+test_expect_success '#23: setup' '
+       setup_repo 23 non-existent "" true &&
+       mkdir -p 23/sub/sub 23/wt/sub
+'
+run_wt_tests 23
+
+test_expect_success '#24: bare repo has no worktree (gitfile case)' '
+       try_repo 24 unset unset unset gitfile true \
+               "$here/24.git" "(null)" "$here/24" "(null)" \
+               "$here/24.git" "(null)" "$here/24/sub" "(null)"
+'
+
+test_expect_success '#25: GIT_WORK_TREE accepted if GIT_DIR unset (bare gitfile case)' '
+       try_repo 25 "$here/25" unset unset gitfile true \
+               "$here/25.git" "$here/25" "$here/25" "(null)"  \
+               "$here/25.git" "$here/25" "$here/25" "sub/" 2>message &&
+       ! test -s message
+'
+
+test_expect_success '#26: bare repo has no worktree (GIT_DIR -> gitfile case)' '
+       try_repo 26 unset "$here/26/.git" unset gitfile true \
+               "$here/26.git" "(null)" "$here/26" "(null)" \
+               "$here/26.git" "(null)" "$here/26/sub" "(null)" &&
+       try_repo 26b unset .git unset gitfile true \
+               "$here/26b.git" "(null)" "$here/26b" "(null)" \
+               "$here/26b.git" "(null)" "$here/26b/sub" "(null)"
+'
+
+# Case #27: GIT_DIR + GIT_WORK_TREE suppresses bareness (with gitfile).
+test_expect_success '#27: setup' '
+       setup_repo 27 unset gitfile true &&
+       mkdir -p 27/sub/sub 27/wt/sub
+'
+run_wt_tests 27 gitfile
+
+test_expect_success '#28: core.worktree and core.bare conflict (gitfile case)' '
+       setup_repo 28 "$here/28" gitfile true &&
+       (
+               cd 28 &&
+               test_must_fail git symbolic-ref HEAD
+       ) 2>message &&
+       ! grep "^warning:" message &&
+       grep "core.bare and core.worktree" message
+'
+
+# Case #29: GIT_WORK_TREE(+core.worktree) overrides core.bare (gitfile case).
+test_expect_success '#29: setup' '
+       setup_repo 29 non-existent gitfile true &&
+       mkdir -p 29/sub/sub 29/wt/sub
+       (
+               cd 29 &&
+               GIT_WORK_TREE="$here/29" &&
+               export GIT_WORK_TREE &&
+               git symbolic-ref HEAD >/dev/null
+       ) 2>message &&
+       ! test -s message
+'
+run_wt_tests 29 gitfile
+
+test_expect_success '#30: core.worktree and core.bare conflict (gitfile version)' '
+       # Just like case #22.
+       setup_repo 30 "$here/30" gitfile true &&
+       (
+               cd 30 &&
+               GIT_DIR=.git &&
+               export GIT_DIR &&
+               test_must_fail git symbolic-ref HEAD 2>result
+       ) &&
+       grep "core.bare and core.worktree" 30/result
+'
+
+# Case #31: GIT_DIR + GIT_WORK_TREE(+core.worktree) suppresses
+# bareness (gitfile version).
+test_expect_success '#31: setup' '
+       setup_repo 31 non-existent gitfile true &&
+       mkdir -p 31/sub/sub 31/wt/sub
+'
+run_wt_tests 31 gitfile
+
+test_done
diff --git a/t/t1511-rev-parse-caret.sh b/t/t1511-rev-parse-caret.sh
new file mode 100755 (executable)
index 0000000..e043cb7
--- /dev/null
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+test_description='tests for ref^{stuff}'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       echo blob >a-blob &&
+       git tag -a -m blob blob-tag `git hash-object -w a-blob`
+       mkdir a-tree &&
+       echo moreblobs >a-tree/another-blob &&
+       git add . &&
+       TREE_SHA1=`git write-tree` &&
+       git tag -a -m tree tree-tag "$TREE_SHA1" &&
+       git commit -m Initial &&
+       git tag -a -m commit commit-tag &&
+       git branch ref &&
+       git checkout master &&
+       echo modified >>a-blob &&
+       git add -u &&
+       git commit -m Modified
+'
+
+test_expect_success 'ref^{non-existent}' '
+       test_must_fail git rev-parse ref^{non-existent}
+'
+
+test_expect_success 'ref^{}' '
+       git rev-parse ref >expected &&
+       git rev-parse ref^{} >actual &&
+       test_cmp expected actual &&
+       git rev-parse commit-tag^{} >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'ref^{commit}' '
+       git rev-parse ref >expected &&
+       git rev-parse ref^{commit} >actual &&
+       test_cmp expected actual &&
+       git rev-parse commit-tag^{commit} >actual &&
+       test_cmp expected actual &&
+       test_must_fail git rev-parse tree-tag^{commit} &&
+       test_must_fail git rev-parse blob-tag^{commit}
+'
+
+test_expect_success 'ref^{tree}' '
+       echo $TREE_SHA1 >expected &&
+       git rev-parse ref^{tree} >actual &&
+       test_cmp expected actual &&
+       git rev-parse commit-tag^{tree} >actual &&
+       test_cmp expected actual &&
+       git rev-parse tree-tag^{tree} >actual &&
+       test_cmp expected actual &&
+       test_must_fail git rev-parse blob-tag^{tree}
+'
+
+test_expect_success 'ref^{/.}' '
+       git rev-parse master >expected &&
+       git rev-parse master^{/.} >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'ref^{/non-existent}' '
+       test_must_fail git rev-parse master^{/non-existent}
+'
+
+test_expect_success 'ref^{/Initial}' '
+       git rev-parse ref >expected &&
+       git rev-parse master^{/Initial} >actual &&
+       test_cmp expected actual
+'
+
+test_done
index 33f8be0cd7f805b7e3492d50a43abf7f16212130..809fafe208cbf68121295922a4c230b2a5e1aee3 100755 (executable)
@@ -13,7 +13,7 @@ test_expect_success 'update-index --nonsense fails' '
        test -s msg
 '
 
-test_expect_failure 'update-index --nonsense dumps usage' '
+test_expect_success 'update-index --nonsense dumps usage' '
        test_expect_code 129 git update-index --nonsense 2>err &&
        grep "[Uu]sage: git update-index" err
 '
index 2293797553d49c5221da10ca17f97eeba1f5d29d..2b17311cb0870ea210d9b5cbe167363d13641d67 100755 (executable)
@@ -13,16 +13,19 @@ test_description='merge-recursive options
 
 . ./test-lib.sh
 
+test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b
+test_have_prereq MINGW && export GREP_OPTIONS=-U
+
 test_expect_success 'setup' '
        conflict_hunks () {
-               sed -n -e "
-                       /^<<<</ b inconflict
+               sed $SED_OPTIONS -n -e "
+                       /^<<<</ b conflict
                        b
-                       : inconflict
+                       : conflict
                        p
                        /^>>>>/ b
                        n
-                       b inconflict
+                       b conflict
                " "$@"
        } &&
 
@@ -107,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 dc2e04a0161c8d6b3f6eefc1873852a377a26393..1921ca3a73370d378e6aedd0820fd8d2a030da03 100755 (executable)
@@ -1067,7 +1067,7 @@ test_expect_success 'git notes copy diagnoses too many or too few parameters' '
 
 test_expect_success 'git notes get-ref (no overrides)' '
        git config --unset core.notesRef &&
-       unset GIT_NOTES_REF &&
+       sane_unset GIT_NOTES_REF &&
        test "$(git notes get-ref)" = "refs/notes/commits"
 '
 
index d3a3bd2679e061ce391930d2b59831aa7610926f..7d8147bb93df482cf7e11338ac96acdf43cf551e 100755 (executable)
@@ -71,8 +71,9 @@ test_expect_success 'setup' '
 # "exec" commands are ran with the user shell by default, but this may
 # be non-POSIX. For example, if SHELL=zsh then ">file" doesn't work
 # to create a file. Unseting SHELL avoids such non-portable behavior
-# in tests.
+# in tests. It must be exported for it to take effect where needed.
 SHELL=
+export SHELL
 
 test_expect_success 'rebase -i with the exec command' '
        git checkout master &&
index 1aee4835105afa8658536120892b63580b36f462..bd8efaf005a9708f153ea873850acca994c64f29 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
 
 test_description='git rebase - test patch id computation'
 
@@ -27,7 +27,7 @@ scramble()
                then
                        echo "$x"
                fi
-               i=$(((i+1) % 10))
+               i=$((($i+1) % 10))
        done < "$1" > "$1.new"
        mv -f "$1.new" "$1"
 }
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 b26cabd571503696a2bfa356e4f6ac46febf74ba..cd093bd34730a3dba6eec7719d3b0170e517fb5e 100755 (executable)
@@ -96,7 +96,7 @@ test_expect_success FUNNYNAMES \
     "git rm -f 'space embedded' 'tab   embedded' 'newline
 embedded'"
 
-test_expect_success RO_DIR 'Test that "git rm -f" fails if its rm fails' '
+test_expect_success SANITY 'Test that "git rm -f" fails if its rm fails' '
        chmod a-w . &&
        test_must_fail git rm -f baz &&
        chmod 775 .
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..b8f81d07c33d3596fef5f5a361f4774d5e357fca 100755 (executable)
@@ -290,4 +290,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
index 0a61b57b5f6f00ae4c0734a34ce45c0ba1fcf098..364693062399228cd6a18b52a21db173519d8e94 100755 (executable)
@@ -32,7 +32,7 @@ EOF
 
 sed 's/beer\\/beer,\\/' < Beer.java > Beer-correct.java
 
-builtin_patterns="bibtex cpp csharp fortran html java objc pascal php python ruby tex"
+builtin_patterns="bibtex cpp csharp fortran html java objc pascal perl php python ruby tex"
 for p in $builtin_patterns
 do
        test_expect_success "builtin $p pattern compiles" '
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 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 b55c4117884744db8eda17e42fe05e0e65216215..c95c4ccc393d0863ad53b6a2a684893282d7d9e6 100755 (executable)
@@ -62,4 +62,13 @@ do
 
 done
 
+test_expect_success 'am --abort will keep the local commits intact' '
+       test_must_fail git am 0004-*.patch &&
+       test_commit unrelated &&
+       git rev-parse HEAD >expect &&
+       git am --abort &&
+       git rev-parse HEAD >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 552da65a61e8f78d40f8e19cfc5b73696ebcf283..baa670cea5d8a9d8b4b4578de69917fe76f71d46 100755 (executable)
@@ -10,7 +10,11 @@ test_expect_success 'setup' '
        test_commit A foo A &&
        test_commit B foo B &&
        test_commit C foo C &&
-       test_commit D foo D
+       test_commit D foo D &&
+       git checkout A^0 &&
+       test_commit E bar E &&
+       test_commit F foo F &&
+       git checkout master
 '
 
 mkdir .git/hooks
@@ -79,6 +83,18 @@ EOF
        verify_hook_input
 '
 
+test_expect_success 'git rebase --skip the last one' '
+       git reset --hard F &&
+       clear_hook_input &&
+       test_must_fail git rebase --onto D A &&
+       git rebase --skip &&
+       echo rebase >expected.args &&
+       cat >expected.data <<EOF &&
+$(git rev-parse E) $(git rev-parse HEAD)
+EOF
+       verify_hook_input
+'
+
 test_expect_success 'git rebase -m' '
        git reset --hard D &&
        clear_hook_input &&
diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh
new file mode 100755 (executable)
index 0000000..a5f4585
--- /dev/null
@@ -0,0 +1,195 @@
+#!/bin/sh
+# Copyright (c) 2010, Jens Lehmann
+
+test_description='Recursive "git fetch" for submodules'
+
+. ./test-lib.sh
+
+pwd=$(pwd)
+
+add_upstream_commit() {
+       (
+               cd submodule &&
+               head1=$(git rev-parse --short HEAD) &&
+               echo new >> subfile &&
+               test_tick &&
+               git add subfile &&
+               git commit -m new subfile &&
+               head2=$(git rev-parse --short HEAD) &&
+               echo "From $pwd/submodule" > ../expect.err &&
+               echo "   $head1..$head2  master     -> origin/master" >> ../expect.err
+       ) &&
+       (
+               cd deepsubmodule &&
+               head1=$(git rev-parse --short HEAD) &&
+               echo new >> deepsubfile &&
+               test_tick &&
+               git add deepsubfile &&
+               git commit -m new deepsubfile &&
+               head2=$(git rev-parse --short HEAD) &&
+               echo "From $pwd/deepsubmodule" >> ../expect.err &&
+               echo "   $head1..$head2  master     -> origin/master" >> ../expect.err
+       )
+}
+
+test_expect_success setup '
+       mkdir deepsubmodule &&
+       (
+               cd deepsubmodule &&
+               git init &&
+               echo deepsubcontent > deepsubfile &&
+               git add deepsubfile &&
+               git commit -m new deepsubfile
+       ) &&
+       mkdir submodule &&
+       (
+               cd submodule &&
+               git init &&
+               echo subcontent > subfile &&
+               git add subfile &&
+               git submodule add "$pwd/deepsubmodule" deepsubmodule &&
+               git commit -a -m new
+       ) &&
+       git submodule add "$pwd/submodule" submodule &&
+       git commit -am initial &&
+       git clone . downstream &&
+       (
+               cd downstream &&
+               git submodule update --init --recursive
+       ) &&
+       echo "Fetching submodule submodule" > expect.out &&
+       echo "Fetching submodule submodule/deepsubmodule" >> expect.out
+'
+
+test_expect_success "fetch --recurse-submodules recurses into submodules" '
+       add_upstream_commit &&
+       (
+               cd downstream &&
+               git fetch --recurse-submodules >../actual.out 2>../actual.err
+       ) &&
+       test_cmp expect.out actual.out &&
+       test_cmp expect.err actual.err
+'
+
+test_expect_success "fetch alone only fetches superproject" '
+       add_upstream_commit &&
+       (
+               cd downstream &&
+               git fetch >../actual.out 2>../actual.err
+       ) &&
+       ! test -s actual.out &&
+       ! test -s actual.err
+'
+
+test_expect_success "fetch --no-recurse-submodules only fetches superproject" '
+       (
+               cd downstream &&
+               git fetch --no-recurse-submodules >../actual.out 2>../actual.err
+       ) &&
+       ! test -s actual.out &&
+       ! test -s actual.err
+'
+
+test_expect_success "using fetchRecurseSubmodules=true in .gitmodules recurses into submodules" '
+       (
+               cd downstream &&
+               git config -f .gitmodules submodule.submodule.fetchRecurseSubmodules true &&
+               git fetch >../actual.out 2>../actual.err
+       ) &&
+       test_cmp expect.out actual.out &&
+       test_cmp expect.err actual.err
+'
+
+test_expect_success "--no-recurse-submodules overrides .gitmodules config" '
+       add_upstream_commit &&
+       (
+               cd downstream &&
+               git fetch --no-recurse-submodules >../actual.out 2>../actual.err
+       ) &&
+       ! test -s actual.out &&
+       ! test -s actual.err
+'
+
+test_expect_success "using fetchRecurseSubmodules=false in .git/config overrides setting in .gitmodules" '
+       (
+               cd downstream &&
+               git config submodule.submodule.fetchRecurseSubmodules false &&
+               git fetch >../actual.out 2>../actual.err
+       ) &&
+       ! test -s actual.out &&
+       ! test -s actual.err
+'
+
+test_expect_success "--recurse-submodules overrides fetchRecurseSubmodules setting from .git/config" '
+       (
+               cd downstream &&
+               git fetch --recurse-submodules >../actual.out 2>../actual.err &&
+               git config --unset -f .gitmodules submodule.submodule.fetchRecurseSubmodules &&
+               git config --unset submodule.submodule.fetchRecurseSubmodules
+       ) &&
+       test_cmp expect.out actual.out &&
+       test_cmp expect.err actual.err
+'
+
+test_expect_success "--quiet propagates to submodules" '
+       (
+               cd downstream &&
+               git fetch --recurse-submodules --quiet >../actual.out 2>../actual.err
+       ) &&
+       ! test -s actual.out &&
+       ! test -s actual.err
+'
+
+test_expect_success "--dry-run propagates to submodules" '
+       add_upstream_commit &&
+       (
+               cd downstream &&
+               git fetch --recurse-submodules --dry-run >../actual.out 2>../actual.err
+       ) &&
+       test_cmp expect.out actual.out &&
+       test_cmp expect.err actual.err &&
+       (
+               cd downstream &&
+               git fetch --recurse-submodules >../actual.out 2>../actual.err
+       ) &&
+       test_cmp expect.out actual.out &&
+       test_cmp expect.err actual.err
+'
+
+test_expect_success "recurseSubmodules=true propagates into submodules" '
+       add_upstream_commit &&
+       (
+               cd downstream &&
+               git config fetch.recurseSubmodules true
+               git fetch >../actual.out 2>../actual.err
+       ) &&
+       test_cmp expect.out actual.out &&
+       test_cmp expect.err actual.err
+'
+
+test_expect_success "--recurse-submodules overrides config in submodule" '
+       add_upstream_commit &&
+       (
+               cd downstream &&
+               (
+                       cd submodule &&
+                       git config fetch.recurseSubmodules false
+               ) &&
+               git fetch --recurse-submodules >../actual.out 2>../actual.err
+       ) &&
+       test_cmp expect.out actual.out &&
+       test_cmp expect.err actual.err
+'
+
+test_expect_success "--no-recurse-submodules overrides config setting" '
+       add_upstream_commit &&
+       (
+               cd downstream &&
+               git config fetch.recurseSubmodules true
+               git fetch --no-recurse-submodules >../actual.out 2>../actual.err
+       ) &&
+       ! test -s actual.out &&
+       ! test -s actual.err
+'
+
+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 460bf741b594d4d6b7f2220ac0f1a0d28c653619..d9c2d386ddf8caff4b87fa457c23757f76c293c7 100755 (executable)
@@ -14,7 +14,7 @@ test_description='CRLF merge conflict across text=auto change
 
 . ./test-lib.sh
 
-test_have_prereq MINGW && SED_OPTIONS=-b
+test_have_prereq SED_STRIPS_CR && SED_OPTIONS=-b
 
 test_expect_success setup '
        git config core.autocrlf false &&
index 782b0a3ece7724bf8df7cf4d405715a42ad21d44..874279e32da98ac2c20137a207a0d115f073e444 100755 (executable)
@@ -421,11 +421,67 @@ test_expect_success 'add submodules without specifying an explicit path' '
                git commit -m "repo commit 1"
        ) &&
        git clone --bare repo/ bare.git &&
-       cd addtest &&
-       git submodule add "$submodurl/repo" &&
-       git config -f .gitmodules submodule.repo.path repo &&
-       git submodule add "$submodurl/bare.git" &&
-       git config -f .gitmodules submodule.bare.path bare
+       (
+               cd addtest &&
+               git submodule add "$submodurl/repo" &&
+               git config -f .gitmodules submodule.repo.path repo &&
+               git submodule add "$submodurl/bare.git" &&
+               git config -f .gitmodules submodule.bare.path bare
+       )
+'
+
+test_expect_success 'add should fail when path is used by a file' '
+       (
+               cd addtest &&
+               touch file &&
+               test_must_fail  git submodule add "$submodurl/repo" file
+       )
+'
+
+test_expect_success 'add should fail when path is used by an existing directory' '
+       (
+               cd addtest &&
+               mkdir empty-dir &&
+               test_must_fail git submodule add "$submodurl/repo" empty-dir
+       )
+'
+
+test_expect_success 'set up for relative path tests' '
+       mkdir reltest &&
+       (
+               cd reltest &&
+               git init &&
+               mkdir sub &&
+               (
+                       cd sub &&
+                       git init &&
+                       test_commit foo
+               ) &&
+               git add sub &&
+               git config -f .gitmodules submodule.sub.path sub &&
+               git config -f .gitmodules submodule.sub.url ../subrepo &&
+               cp .git/config pristine-.git-config
+       )
+'
+
+test_expect_success 'relative path works with URL' '
+       (
+               cd reltest &&
+               cp pristine-.git-config .git/config &&
+               git config remote.origin.url ssh://hostname/repo &&
+               git submodule init &&
+               test "$(git config submodule.sub.url)" = ssh://hostname/subrepo
+       )
+'
+
+test_expect_success 'relative path works with user@host:path' '
+       (
+               cd reltest &&
+               cp pristine-.git-config .git/config &&
+               git config remote.origin.url user@host:repo &&
+               git submodule init &&
+               test "$(git config submodule.sub.url)" = user@host:subrepo
+       )
 '
 
 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..d551b77ce6d94acce80069f2197f0169ee59e6d5 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.
index 8297cb4f1e6e2d903dfbf6fde825d2c787082e58..8980738c7540b79eaa566d6054f3e76b202bd27e 100755 (executable)
@@ -230,6 +230,10 @@ test_expect_success 'amend commit to fix date' '
 
 '
 
+test_expect_success 'commit complains about bogus date' '
+       test_must_fail git commit --amend --date=10.11.2010
+'
+
 test_expect_success 'sign off (1)' '
 
        echo 1 >positive &&
index b73ab42936a8ea10dcdf40a6ad8b83d4a1d10056..f1dc5c3b6a36507e664e624bf9cebb1634bce335 100755 (executable)
@@ -405,12 +405,13 @@ test_expect_success 'status --porcelain ignores relative paths setting' '
 
 test_expect_success 'setup unique colors' '
 
-       git config status.color.untracked blue
+       git config status.color.untracked blue &&
+       git config status.color.branch green
 
 '
 
 cat >expect <<\EOF
-# On branch master
+# On branch <GREEN>master<RESET>
 # Changes to be committed:
 #   (use "git reset HEAD <file>..." to unstage)
 #
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
diff --git a/t/t7609-merge-abort.sh b/t/t7609-merge-abort.sh
deleted file mode 100755 (executable)
index 61890bc..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-#!/bin/sh
-
-test_description='test aborting in-progress merges
-
-Set up repo with conflicting and non-conflicting branches:
-
-There are three files foo/bar/baz, and the following graph illustrates the
-content of these files in each commit:
-
-# foo/bar/baz --- foo/bar/bazz     <-- master
-#             \
-#              --- foo/barf/bazf   <-- conflict_branch
-#               \
-#                --- foo/bart/baz  <-- clean_branch
-
-Next, test git merge --abort with the following variables:
-- before/after successful merge (should fail when not in merge context)
-- with/without conflicts
-- clean/dirty index before merge
-- clean/dirty worktree before merge
-- dirty index before merge matches contents on remote branch
-- changed/unchanged worktree after merge
-- changed/unchanged index after merge
-'
-. ./test-lib.sh
-
-test_expect_success 'setup' '
-       # Create the above repo
-       echo foo > foo &&
-       echo bar > bar &&
-       echo baz > baz &&
-       git add foo bar baz &&
-       git commit -m initial &&
-       echo bazz > baz &&
-       git commit -a -m "second" &&
-       git checkout -b conflict_branch HEAD^ &&
-       echo barf > bar &&
-       echo bazf > baz &&
-       git commit -a -m "conflict" &&
-       git checkout -b clean_branch HEAD^ &&
-       echo bart > bar &&
-       git commit -a -m "clean" &&
-       git checkout master
-'
-
-pre_merge_head="$(git rev-parse HEAD)"
-
-test_expect_success 'fails without MERGE_HEAD (unstarted merge)' '
-       test_must_fail git merge --abort 2>output &&
-       grep -q MERGE_HEAD output &&
-       test ! -f .git/MERGE_HEAD &&
-       test "$pre_merge_head" = "$(git rev-parse HEAD)"
-'
-
-test_expect_success 'fails without MERGE_HEAD (completed merge)' '
-       git merge clean_branch &&
-       test ! -f .git/MERGE_HEAD &&
-       # Merge successfully completed
-       post_merge_head="$(git rev-parse HEAD)" &&
-       test_must_fail git merge --abort 2>output &&
-       grep -q MERGE_HEAD output &&
-       test ! -f .git/MERGE_HEAD &&
-       test "$post_merge_head" = "$(git rev-parse HEAD)"
-'
-
-test_expect_success 'Forget previous merge' '
-       git reset --hard "$pre_merge_head"
-'
-
-test_expect_success 'Abort after --no-commit' '
-       # Redo merge, but stop before creating merge commit
-       git merge --no-commit clean_branch &&
-       test -f .git/MERGE_HEAD &&
-       # Abort non-conflicting merge
-       git merge --abort &&
-       test ! -f .git/MERGE_HEAD &&
-       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
-       test -z "$(git diff)" &&
-       test -z "$(git diff --staged)"
-'
-
-test_expect_success 'Abort after conflicts' '
-       # Create conflicting merge
-       test_must_fail git merge conflict_branch &&
-       test -f .git/MERGE_HEAD &&
-       # Abort conflicting merge
-       git merge --abort &&
-       test ! -f .git/MERGE_HEAD &&
-       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
-       test -z "$(git diff)" &&
-       test -z "$(git diff --staged)"
-'
-
-test_expect_success 'Clean merge with dirty index fails' '
-       echo xyzzy >> foo &&
-       git add foo &&
-       git diff --staged > expect &&
-       test_must_fail git merge clean_branch &&
-       test ! -f .git/MERGE_HEAD &&
-       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
-       test -z "$(git diff)" &&
-       git diff --staged > actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'Conflicting merge with dirty index fails' '
-       test_must_fail git merge conflict_branch &&
-       test ! -f .git/MERGE_HEAD &&
-       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
-       test -z "$(git diff)" &&
-       git diff --staged > actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'Reset index (but preserve worktree changes)' '
-       git reset "$pre_merge_head" &&
-       git diff > actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'Abort clean merge with non-conflicting dirty worktree' '
-       git merge --no-commit clean_branch &&
-       test -f .git/MERGE_HEAD &&
-       # Abort merge
-       git merge --abort &&
-       test ! -f .git/MERGE_HEAD &&
-       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
-       test -z "$(git diff --staged)" &&
-       git diff > actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'Abort conflicting merge with non-conflicting dirty worktree' '
-       test_must_fail git merge conflict_branch &&
-       test -f .git/MERGE_HEAD &&
-       # Abort merge
-       git merge --abort &&
-       test ! -f .git/MERGE_HEAD &&
-       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
-       test -z "$(git diff --staged)" &&
-       git diff > actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'Reset worktree changes' '
-       git reset --hard "$pre_merge_head"
-'
-
-test_expect_success 'Fail clean merge with conflicting dirty worktree' '
-       echo xyzzy >> bar &&
-       git diff > expect &&
-       test_must_fail git merge --no-commit clean_branch &&
-       test ! -f .git/MERGE_HEAD &&
-       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
-       test -z "$(git diff --staged)" &&
-       git diff > actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'Fail conflicting merge with conflicting dirty worktree' '
-       test_must_fail git merge conflict_branch &&
-       test ! -f .git/MERGE_HEAD &&
-       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
-       test -z "$(git diff --staged)" &&
-       git diff > actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'Reset worktree changes' '
-       git reset --hard "$pre_merge_head"
-'
-
-test_expect_success 'Fail clean merge with matching dirty worktree' '
-       echo bart > bar &&
-       git diff > expect &&
-       test_must_fail git merge --no-commit clean_branch &&
-       test ! -f .git/MERGE_HEAD &&
-       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
-       test -z "$(git diff --staged)" &&
-       git diff > actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'Abort clean merge with matching dirty index' '
-       git add bar &&
-       git diff --staged > expect &&
-       git merge --no-commit clean_branch &&
-       test -f .git/MERGE_HEAD &&
-       ### When aborting the merge, git will discard all staged changes,
-       ### including those that were staged pre-merge. In other words,
-       ### --abort will LOSE any staged changes (the staged changes that
-       ### are lost must match the merge result, or the merge would not
-       ### have been allowed to start). Change expectations accordingly:
-       rm expect &&
-       touch expect &&
-       # Abort merge
-       git merge --abort &&
-       test ! -f .git/MERGE_HEAD &&
-       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
-       git diff --staged > actual &&
-       test_cmp expect actual &&
-       test -z "$(git diff)"
-'
-
-test_expect_success 'Reset worktree changes' '
-       git reset --hard "$pre_merge_head"
-'
-
-test_expect_success 'Fail conflicting merge with matching dirty worktree' '
-       echo barf > bar &&
-       git diff > expect &&
-       test_must_fail git merge conflict_branch &&
-       test ! -f .git/MERGE_HEAD &&
-       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
-       test -z "$(git diff --staged)" &&
-       git diff > actual &&
-       test_cmp expect actual
-'
-
-test_expect_success 'Abort conflicting merge with matching dirty index' '
-       git add bar &&
-       git diff --staged > expect &&
-       test_must_fail git merge conflict_branch &&
-       test -f .git/MERGE_HEAD &&
-       ### When aborting the merge, git will discard all staged changes,
-       ### including those that were staged pre-merge. In other words,
-       ### --abort will LOSE any staged changes (the staged changes that
-       ### are lost must match the merge result, or the merge would not
-       ### have been allowed to start). Change expectations accordingly:
-       rm expect &&
-       touch expect &&
-       # Abort merge
-       git merge --abort &&
-       test ! -f .git/MERGE_HEAD &&
-       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
-       git diff --staged > actual &&
-       test_cmp expect actual &&
-       test -z "$(git diff)"
-'
-
-test_expect_success 'Reset worktree changes' '
-       git reset --hard "$pre_merge_head"
-'
-
-test_expect_success 'Abort merge with pre- and post-merge worktree changes' '
-       # Pre-merge worktree changes
-       echo xyzzy > foo &&
-       echo barf > bar &&
-       git add bar &&
-       git diff > expect &&
-       git diff --staged > expect-staged &&
-       # Perform merge
-       test_must_fail git merge conflict_branch &&
-       test -f .git/MERGE_HEAD &&
-       # Post-merge worktree changes
-       echo yzxxz > foo &&
-       echo blech > baz &&
-       ### When aborting the merge, git will discard staged changes (bar)
-       ### and unmerged changes (baz). Other changes that are neither
-       ### staged nor marked as unmerged (foo), will be preserved. For
-       ### these changed, git cannot tell pre-merge changes apart from
-       ### post-merge changes, so the post-merge changes will be
-       ### preserved. Change expectations accordingly:
-       git diff -- foo > expect &&
-       rm expect-staged &&
-       touch expect-staged &&
-       # Abort merge
-       git merge --abort &&
-       test ! -f .git/MERGE_HEAD &&
-       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
-       git diff > actual &&
-       test_cmp expect actual &&
-       git diff --staged > actual-staged &&
-       test_cmp expect-staged actual-staged
-'
-
-test_expect_success 'Reset worktree changes' '
-       git reset --hard "$pre_merge_head"
-'
-
-test_expect_success 'Abort merge with pre- and post-merge index changes' '
-       # Pre-merge worktree changes
-       echo xyzzy > foo &&
-       echo barf > bar &&
-       git add bar &&
-       git diff > expect &&
-       git diff --staged > expect-staged &&
-       # Perform merge
-       test_must_fail git merge conflict_branch &&
-       test -f .git/MERGE_HEAD &&
-       # Post-merge worktree changes
-       echo yzxxz > foo &&
-       echo blech > baz &&
-       git add foo bar &&
-       ### When aborting the merge, git will discard all staged changes
-       ### (foo, bar and baz), and no changes will be preserved. Whether
-       ### the changes were staged pre- or post-merge does not matter
-       ### (except for not preventing starting the merge).
-       ### Change expectations accordingly:
-       rm expect expect-staged &&
-       touch expect &&
-       touch expect-staged &&
-       # Abort merge
-       git merge --abort &&
-       test ! -f .git/MERGE_HEAD &&
-       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
-       git diff > actual &&
-       test_cmp expect actual &&
-       git diff --staged > actual-staged &&
-       test_cmp expect-staged actual-staged
-'
-
-test_done
diff --git a/t/t7611-merge-abort.sh b/t/t7611-merge-abort.sh
new file mode 100755 (executable)
index 0000000..61890bc
--- /dev/null
@@ -0,0 +1,313 @@
+#!/bin/sh
+
+test_description='test aborting in-progress merges
+
+Set up repo with conflicting and non-conflicting branches:
+
+There are three files foo/bar/baz, and the following graph illustrates the
+content of these files in each commit:
+
+# foo/bar/baz --- foo/bar/bazz     <-- master
+#             \
+#              --- foo/barf/bazf   <-- conflict_branch
+#               \
+#                --- foo/bart/baz  <-- clean_branch
+
+Next, test git merge --abort with the following variables:
+- before/after successful merge (should fail when not in merge context)
+- with/without conflicts
+- clean/dirty index before merge
+- clean/dirty worktree before merge
+- dirty index before merge matches contents on remote branch
+- changed/unchanged worktree after merge
+- changed/unchanged index after merge
+'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       # Create the above repo
+       echo foo > foo &&
+       echo bar > bar &&
+       echo baz > baz &&
+       git add foo bar baz &&
+       git commit -m initial &&
+       echo bazz > baz &&
+       git commit -a -m "second" &&
+       git checkout -b conflict_branch HEAD^ &&
+       echo barf > bar &&
+       echo bazf > baz &&
+       git commit -a -m "conflict" &&
+       git checkout -b clean_branch HEAD^ &&
+       echo bart > bar &&
+       git commit -a -m "clean" &&
+       git checkout master
+'
+
+pre_merge_head="$(git rev-parse HEAD)"
+
+test_expect_success 'fails without MERGE_HEAD (unstarted merge)' '
+       test_must_fail git merge --abort 2>output &&
+       grep -q MERGE_HEAD output &&
+       test ! -f .git/MERGE_HEAD &&
+       test "$pre_merge_head" = "$(git rev-parse HEAD)"
+'
+
+test_expect_success 'fails without MERGE_HEAD (completed merge)' '
+       git merge clean_branch &&
+       test ! -f .git/MERGE_HEAD &&
+       # Merge successfully completed
+       post_merge_head="$(git rev-parse HEAD)" &&
+       test_must_fail git merge --abort 2>output &&
+       grep -q MERGE_HEAD output &&
+       test ! -f .git/MERGE_HEAD &&
+       test "$post_merge_head" = "$(git rev-parse HEAD)"
+'
+
+test_expect_success 'Forget previous merge' '
+       git reset --hard "$pre_merge_head"
+'
+
+test_expect_success 'Abort after --no-commit' '
+       # Redo merge, but stop before creating merge commit
+       git merge --no-commit clean_branch &&
+       test -f .git/MERGE_HEAD &&
+       # Abort non-conflicting merge
+       git merge --abort &&
+       test ! -f .git/MERGE_HEAD &&
+       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
+       test -z "$(git diff)" &&
+       test -z "$(git diff --staged)"
+'
+
+test_expect_success 'Abort after conflicts' '
+       # Create conflicting merge
+       test_must_fail git merge conflict_branch &&
+       test -f .git/MERGE_HEAD &&
+       # Abort conflicting merge
+       git merge --abort &&
+       test ! -f .git/MERGE_HEAD &&
+       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
+       test -z "$(git diff)" &&
+       test -z "$(git diff --staged)"
+'
+
+test_expect_success 'Clean merge with dirty index fails' '
+       echo xyzzy >> foo &&
+       git add foo &&
+       git diff --staged > expect &&
+       test_must_fail git merge clean_branch &&
+       test ! -f .git/MERGE_HEAD &&
+       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
+       test -z "$(git diff)" &&
+       git diff --staged > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'Conflicting merge with dirty index fails' '
+       test_must_fail git merge conflict_branch &&
+       test ! -f .git/MERGE_HEAD &&
+       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
+       test -z "$(git diff)" &&
+       git diff --staged > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'Reset index (but preserve worktree changes)' '
+       git reset "$pre_merge_head" &&
+       git diff > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'Abort clean merge with non-conflicting dirty worktree' '
+       git merge --no-commit clean_branch &&
+       test -f .git/MERGE_HEAD &&
+       # Abort merge
+       git merge --abort &&
+       test ! -f .git/MERGE_HEAD &&
+       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
+       test -z "$(git diff --staged)" &&
+       git diff > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'Abort conflicting merge with non-conflicting dirty worktree' '
+       test_must_fail git merge conflict_branch &&
+       test -f .git/MERGE_HEAD &&
+       # Abort merge
+       git merge --abort &&
+       test ! -f .git/MERGE_HEAD &&
+       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
+       test -z "$(git diff --staged)" &&
+       git diff > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'Reset worktree changes' '
+       git reset --hard "$pre_merge_head"
+'
+
+test_expect_success 'Fail clean merge with conflicting dirty worktree' '
+       echo xyzzy >> bar &&
+       git diff > expect &&
+       test_must_fail git merge --no-commit clean_branch &&
+       test ! -f .git/MERGE_HEAD &&
+       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
+       test -z "$(git diff --staged)" &&
+       git diff > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'Fail conflicting merge with conflicting dirty worktree' '
+       test_must_fail git merge conflict_branch &&
+       test ! -f .git/MERGE_HEAD &&
+       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
+       test -z "$(git diff --staged)" &&
+       git diff > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'Reset worktree changes' '
+       git reset --hard "$pre_merge_head"
+'
+
+test_expect_success 'Fail clean merge with matching dirty worktree' '
+       echo bart > bar &&
+       git diff > expect &&
+       test_must_fail git merge --no-commit clean_branch &&
+       test ! -f .git/MERGE_HEAD &&
+       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
+       test -z "$(git diff --staged)" &&
+       git diff > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'Abort clean merge with matching dirty index' '
+       git add bar &&
+       git diff --staged > expect &&
+       git merge --no-commit clean_branch &&
+       test -f .git/MERGE_HEAD &&
+       ### When aborting the merge, git will discard all staged changes,
+       ### including those that were staged pre-merge. In other words,
+       ### --abort will LOSE any staged changes (the staged changes that
+       ### are lost must match the merge result, or the merge would not
+       ### have been allowed to start). Change expectations accordingly:
+       rm expect &&
+       touch expect &&
+       # Abort merge
+       git merge --abort &&
+       test ! -f .git/MERGE_HEAD &&
+       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
+       git diff --staged > actual &&
+       test_cmp expect actual &&
+       test -z "$(git diff)"
+'
+
+test_expect_success 'Reset worktree changes' '
+       git reset --hard "$pre_merge_head"
+'
+
+test_expect_success 'Fail conflicting merge with matching dirty worktree' '
+       echo barf > bar &&
+       git diff > expect &&
+       test_must_fail git merge conflict_branch &&
+       test ! -f .git/MERGE_HEAD &&
+       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
+       test -z "$(git diff --staged)" &&
+       git diff > actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'Abort conflicting merge with matching dirty index' '
+       git add bar &&
+       git diff --staged > expect &&
+       test_must_fail git merge conflict_branch &&
+       test -f .git/MERGE_HEAD &&
+       ### When aborting the merge, git will discard all staged changes,
+       ### including those that were staged pre-merge. In other words,
+       ### --abort will LOSE any staged changes (the staged changes that
+       ### are lost must match the merge result, or the merge would not
+       ### have been allowed to start). Change expectations accordingly:
+       rm expect &&
+       touch expect &&
+       # Abort merge
+       git merge --abort &&
+       test ! -f .git/MERGE_HEAD &&
+       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
+       git diff --staged > actual &&
+       test_cmp expect actual &&
+       test -z "$(git diff)"
+'
+
+test_expect_success 'Reset worktree changes' '
+       git reset --hard "$pre_merge_head"
+'
+
+test_expect_success 'Abort merge with pre- and post-merge worktree changes' '
+       # Pre-merge worktree changes
+       echo xyzzy > foo &&
+       echo barf > bar &&
+       git add bar &&
+       git diff > expect &&
+       git diff --staged > expect-staged &&
+       # Perform merge
+       test_must_fail git merge conflict_branch &&
+       test -f .git/MERGE_HEAD &&
+       # Post-merge worktree changes
+       echo yzxxz > foo &&
+       echo blech > baz &&
+       ### When aborting the merge, git will discard staged changes (bar)
+       ### and unmerged changes (baz). Other changes that are neither
+       ### staged nor marked as unmerged (foo), will be preserved. For
+       ### these changed, git cannot tell pre-merge changes apart from
+       ### post-merge changes, so the post-merge changes will be
+       ### preserved. Change expectations accordingly:
+       git diff -- foo > expect &&
+       rm expect-staged &&
+       touch expect-staged &&
+       # Abort merge
+       git merge --abort &&
+       test ! -f .git/MERGE_HEAD &&
+       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
+       git diff > actual &&
+       test_cmp expect actual &&
+       git diff --staged > actual-staged &&
+       test_cmp expect-staged actual-staged
+'
+
+test_expect_success 'Reset worktree changes' '
+       git reset --hard "$pre_merge_head"
+'
+
+test_expect_success 'Abort merge with pre- and post-merge index changes' '
+       # Pre-merge worktree changes
+       echo xyzzy > foo &&
+       echo barf > bar &&
+       git add bar &&
+       git diff > expect &&
+       git diff --staged > expect-staged &&
+       # Perform merge
+       test_must_fail git merge conflict_branch &&
+       test -f .git/MERGE_HEAD &&
+       # Post-merge worktree changes
+       echo yzxxz > foo &&
+       echo blech > baz &&
+       git add foo bar &&
+       ### When aborting the merge, git will discard all staged changes
+       ### (foo, bar and baz), and no changes will be preserved. Whether
+       ### the changes were staged pre- or post-merge does not matter
+       ### (except for not preventing starting the merge).
+       ### Change expectations accordingly:
+       rm expect expect-staged &&
+       touch expect &&
+       touch expect-staged &&
+       # Abort merge
+       git merge --abort &&
+       test ! -f .git/MERGE_HEAD &&
+       test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
+       git diff > actual &&
+       test_cmp expect actual &&
+       git diff --staged > actual-staged &&
+       test_cmp expect-staged actual-staged
+'
+
+test_done
index c8777589ca1c89825b570cfc05405a39df39aaba..8a7788dc39f236b15e60912c384d835fd1db5a28 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
diff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh
new file mode 100755 (executable)
index 0000000..230143c
--- /dev/null
@@ -0,0 +1,188 @@
+#!/bin/sh
+
+test_description='git blame corner cases'
+. ./test-lib.sh
+
+pick_fc='s/^[0-9a-f^]* *\([^ ]*\) *(\([^ ]*\) .*/\1-\2/'
+
+test_expect_success setup '
+
+       echo A A A A A >one &&
+       echo B B B B B >two &&
+       echo C C C C C >tres &&
+       echo ABC >mouse &&
+       for i in 1 2 3 4 5 6 7 8 9
+       do
+               echo $i
+       done >nine_lines &&
+       for i in 1 2 3 4 5 6 7 8 9 a
+       do
+               echo $i
+       done >ten_lines &&
+       git add one two tres mouse nine_lines ten_lines &&
+       test_tick &&
+       GIT_AUTHOR_NAME=Initial git commit -m Initial &&
+
+       cat one >uno &&
+       mv two dos &&
+       cat one >>tres &&
+       echo DEF >>mouse
+       git add uno dos tres mouse &&
+       test_tick &&
+       GIT_AUTHOR_NAME=Second git commit -a -m Second &&
+
+       echo GHIJK >>mouse &&
+       git add mouse &&
+       test_tick &&
+       GIT_AUTHOR_NAME=Third git commit -m Third &&
+
+       cat mouse >cow &&
+       git add cow &&
+       test_tick &&
+       GIT_AUTHOR_NAME=Fourth git commit -m Fourth &&
+
+       {
+               echo ABC
+               echo DEF
+               echo XXXX
+               echo GHIJK
+       } >cow &&
+       git add cow &&
+       test_tick &&
+       GIT_AUTHOR_NAME=Fifth git commit -m Fifth
+'
+
+test_expect_success 'straight copy without -C' '
+
+       git blame uno | grep Second
+
+'
+
+test_expect_success 'straight move without -C' '
+
+       git blame dos | grep Initial
+
+'
+
+test_expect_success 'straight copy with -C' '
+
+       git blame -C1 uno | grep Second
+
+'
+
+test_expect_success 'straight move with -C' '
+
+       git blame -C1 dos | grep Initial
+
+'
+
+test_expect_success 'straight copy with -C -C' '
+
+       git blame -C -C1 uno | grep Initial
+
+'
+
+test_expect_success 'straight move with -C -C' '
+
+       git blame -C -C1 dos | grep Initial
+
+'
+
+test_expect_success 'append without -C' '
+
+       git blame -L2 tres | grep Second
+
+'
+
+test_expect_success 'append with -C' '
+
+       git blame -L2 -C1 tres | grep Second
+
+'
+
+test_expect_success 'append with -C -C' '
+
+       git blame -L2 -C -C1 tres | grep Second
+
+'
+
+test_expect_success 'append with -C -C -C' '
+
+       git blame -L2 -C -C -C1 tres | grep Initial
+
+'
+
+test_expect_success 'blame wholesale copy' '
+
+       git blame -f -C -C1 HEAD^ -- cow | sed -e "$pick_fc" >current &&
+       {
+               echo mouse-Initial
+               echo mouse-Second
+               echo mouse-Third
+       } >expected &&
+       test_cmp expected current
+
+'
+
+test_expect_success 'blame wholesale copy and more' '
+
+       git blame -f -C -C1 HEAD -- cow | sed -e "$pick_fc" >current &&
+       {
+               echo mouse-Initial
+               echo mouse-Second
+               echo cow-Fifth
+               echo mouse-Third
+       } >expected &&
+       test_cmp expected current
+
+'
+
+test_expect_success 'blame path that used to be a directory' '
+       mkdir path &&
+       echo A A A A A >path/file &&
+       echo B B B B B >path/elif &&
+       git add path &&
+       test_tick &&
+       git commit -m "path was a directory" &&
+       rm -fr path &&
+       echo A A A A A >path &&
+       git add path &&
+       test_tick &&
+       git commit -m "path is a regular file" &&
+       git blame HEAD^.. -- path
+'
+
+test_expect_success 'blame to a commit with no author name' '
+  TREE=`git rev-parse HEAD:`
+  cat >badcommit <<EOF
+tree $TREE
+author <noname> 1234567890 +0000
+committer David Reiss <dreiss@facebook.com> 1234567890 +0000
+
+some message
+EOF
+  COMMIT=`git hash-object -t commit -w badcommit`
+  git --no-pager blame $COMMIT -- uno >/dev/null
+'
+
+test_expect_success 'blame -L with invalid start' '
+       test_must_fail git blame -L5 tres 2>errors &&
+       grep "has only 2 lines" errors
+'
+
+test_expect_success 'blame -L with invalid end' '
+       test_must_fail git blame -L1,5 tres 2>errors &&
+       grep "has only 2 lines" errors
+'
+
+test_expect_success 'indent of line numbers, nine lines' '
+       git blame nine_lines >actual &&
+       test $(grep -c "  " actual) = 0
+'
+
+test_expect_success 'indent of line numbers, ten lines' '
+       git blame ten_lines >actual &&
+       test $(grep -c "  " actual) = 9
+'
+
+test_done
diff --git a/t/t8003-blame.sh b/t/t8003-blame.sh
deleted file mode 100755 (executable)
index 230143c..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-#!/bin/sh
-
-test_description='git blame corner cases'
-. ./test-lib.sh
-
-pick_fc='s/^[0-9a-f^]* *\([^ ]*\) *(\([^ ]*\) .*/\1-\2/'
-
-test_expect_success setup '
-
-       echo A A A A A >one &&
-       echo B B B B B >two &&
-       echo C C C C C >tres &&
-       echo ABC >mouse &&
-       for i in 1 2 3 4 5 6 7 8 9
-       do
-               echo $i
-       done >nine_lines &&
-       for i in 1 2 3 4 5 6 7 8 9 a
-       do
-               echo $i
-       done >ten_lines &&
-       git add one two tres mouse nine_lines ten_lines &&
-       test_tick &&
-       GIT_AUTHOR_NAME=Initial git commit -m Initial &&
-
-       cat one >uno &&
-       mv two dos &&
-       cat one >>tres &&
-       echo DEF >>mouse
-       git add uno dos tres mouse &&
-       test_tick &&
-       GIT_AUTHOR_NAME=Second git commit -a -m Second &&
-
-       echo GHIJK >>mouse &&
-       git add mouse &&
-       test_tick &&
-       GIT_AUTHOR_NAME=Third git commit -m Third &&
-
-       cat mouse >cow &&
-       git add cow &&
-       test_tick &&
-       GIT_AUTHOR_NAME=Fourth git commit -m Fourth &&
-
-       {
-               echo ABC
-               echo DEF
-               echo XXXX
-               echo GHIJK
-       } >cow &&
-       git add cow &&
-       test_tick &&
-       GIT_AUTHOR_NAME=Fifth git commit -m Fifth
-'
-
-test_expect_success 'straight copy without -C' '
-
-       git blame uno | grep Second
-
-'
-
-test_expect_success 'straight move without -C' '
-
-       git blame dos | grep Initial
-
-'
-
-test_expect_success 'straight copy with -C' '
-
-       git blame -C1 uno | grep Second
-
-'
-
-test_expect_success 'straight move with -C' '
-
-       git blame -C1 dos | grep Initial
-
-'
-
-test_expect_success 'straight copy with -C -C' '
-
-       git blame -C -C1 uno | grep Initial
-
-'
-
-test_expect_success 'straight move with -C -C' '
-
-       git blame -C -C1 dos | grep Initial
-
-'
-
-test_expect_success 'append without -C' '
-
-       git blame -L2 tres | grep Second
-
-'
-
-test_expect_success 'append with -C' '
-
-       git blame -L2 -C1 tres | grep Second
-
-'
-
-test_expect_success 'append with -C -C' '
-
-       git blame -L2 -C -C1 tres | grep Second
-
-'
-
-test_expect_success 'append with -C -C -C' '
-
-       git blame -L2 -C -C -C1 tres | grep Initial
-
-'
-
-test_expect_success 'blame wholesale copy' '
-
-       git blame -f -C -C1 HEAD^ -- cow | sed -e "$pick_fc" >current &&
-       {
-               echo mouse-Initial
-               echo mouse-Second
-               echo mouse-Third
-       } >expected &&
-       test_cmp expected current
-
-'
-
-test_expect_success 'blame wholesale copy and more' '
-
-       git blame -f -C -C1 HEAD -- cow | sed -e "$pick_fc" >current &&
-       {
-               echo mouse-Initial
-               echo mouse-Second
-               echo cow-Fifth
-               echo mouse-Third
-       } >expected &&
-       test_cmp expected current
-
-'
-
-test_expect_success 'blame path that used to be a directory' '
-       mkdir path &&
-       echo A A A A A >path/file &&
-       echo B B B B B >path/elif &&
-       git add path &&
-       test_tick &&
-       git commit -m "path was a directory" &&
-       rm -fr path &&
-       echo A A A A A >path &&
-       git add path &&
-       test_tick &&
-       git commit -m "path is a regular file" &&
-       git blame HEAD^.. -- path
-'
-
-test_expect_success 'blame to a commit with no author name' '
-  TREE=`git rev-parse HEAD:`
-  cat >badcommit <<EOF
-tree $TREE
-author <noname> 1234567890 +0000
-committer David Reiss <dreiss@facebook.com> 1234567890 +0000
-
-some message
-EOF
-  COMMIT=`git hash-object -t commit -w badcommit`
-  git --no-pager blame $COMMIT -- uno >/dev/null
-'
-
-test_expect_success 'blame -L with invalid start' '
-       test_must_fail git blame -L5 tres 2>errors &&
-       grep "has only 2 lines" errors
-'
-
-test_expect_success 'blame -L with invalid end' '
-       test_must_fail git blame -L1,5 tres 2>errors &&
-       grep "has only 2 lines" errors
-'
-
-test_expect_success 'indent of line numbers, nine lines' '
-       git blame nine_lines >actual &&
-       test $(grep -c "  " actual) = 0
-'
-
-test_expect_success 'indent of line numbers, ten lines' '
-       git blame ten_lines >actual &&
-       test $(grep -c "  " actual) = 9
-'
-
-test_done
diff --git a/t/t8004-blame-with-conflicts.sh b/t/t8004-blame-with-conflicts.sh
new file mode 100755 (executable)
index 0000000..ba19ac1
--- /dev/null
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+# Based on a test case submitted by Björn Steinbrink.
+
+test_description='git blame on conflicted files'
+. ./test-lib.sh
+
+test_expect_success 'setup first case' '
+       # Create the old file
+       echo "Old line" > file1 &&
+       git add file1 &&
+       git commit --author "Old Line <ol@localhost>" -m file1.a &&
+
+       # Branch
+       git checkout -b foo &&
+
+       # Do an ugly move and change
+       git rm file1 &&
+       echo "New line ..."  > file2 &&
+       echo "... and more" >> file2 &&
+       git add file2 &&
+       git commit --author "U Gly <ug@localhost>" -m ugly &&
+
+       # Back to master and change something
+       git checkout master &&
+       echo "
+
+bla" >> file1 &&
+       git commit --author "Old Line <ol@localhost>" -a -m file1.b &&
+
+       # Back to foo and merge master
+       git checkout foo &&
+       if git merge master; then
+               echo needed conflict here
+               exit 1
+       else
+               echo merge failed - resolving automatically
+       fi &&
+       echo "New line ...
+... and more
+
+bla
+Even more" > file2 &&
+       git rm file1 &&
+       git commit --author "M Result <mr@localhost>" -a -m merged &&
+
+       # Back to master and change file1 again
+       git checkout master &&
+       sed s/bla/foo/ <file1 >X &&
+       rm file1 &&
+       mv X file1 &&
+       git commit --author "No Bla <nb@localhost>" -a -m replace &&
+
+       # Try to merge into foo again
+       git checkout foo &&
+       if git merge master; then
+               echo needed conflict here
+               exit 1
+       else
+               echo merge failed - test is setup
+       fi
+'
+
+test_expect_success \
+       'blame runs on unconflicted file while other file has conflicts' '
+       git blame file2
+'
+
+test_expect_success 'blame runs on conflicted file in stages 1,3' '
+       git blame file1
+'
+
+test_done
diff --git a/t/t8004-blame.sh b/t/t8004-blame.sh
deleted file mode 100755 (executable)
index ba19ac1..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/bin/sh
-
-# Based on a test case submitted by Björn Steinbrink.
-
-test_description='git blame on conflicted files'
-. ./test-lib.sh
-
-test_expect_success 'setup first case' '
-       # Create the old file
-       echo "Old line" > file1 &&
-       git add file1 &&
-       git commit --author "Old Line <ol@localhost>" -m file1.a &&
-
-       # Branch
-       git checkout -b foo &&
-
-       # Do an ugly move and change
-       git rm file1 &&
-       echo "New line ..."  > file2 &&
-       echo "... and more" >> file2 &&
-       git add file2 &&
-       git commit --author "U Gly <ug@localhost>" -m ugly &&
-
-       # Back to master and change something
-       git checkout master &&
-       echo "
-
-bla" >> file1 &&
-       git commit --author "Old Line <ol@localhost>" -a -m file1.b &&
-
-       # Back to foo and merge master
-       git checkout foo &&
-       if git merge master; then
-               echo needed conflict here
-               exit 1
-       else
-               echo merge failed - resolving automatically
-       fi &&
-       echo "New line ...
-... and more
-
-bla
-Even more" > file2 &&
-       git rm file1 &&
-       git commit --author "M Result <mr@localhost>" -a -m merged &&
-
-       # Back to master and change file1 again
-       git checkout master &&
-       sed s/bla/foo/ <file1 >X &&
-       rm file1 &&
-       mv X file1 &&
-       git commit --author "No Bla <nb@localhost>" -a -m replace &&
-
-       # Try to merge into foo again
-       git checkout foo &&
-       if git merge master; then
-               echo needed conflict here
-               exit 1
-       else
-               echo merge failed - test is setup
-       fi
-'
-
-test_expect_success \
-       'blame runs on unconflicted file while other file has conflicts' '
-       git blame file2
-'
-
-test_expect_success 'blame runs on conflicted file in stages 1,3' '
-       git blame file1
-'
-
-test_done
index dbf623bce5598860800fa463c26ec8145d6e2400..ea64cd8d0f02a3a08dca7742a29331c85e7da384 100755 (executable)
@@ -73,6 +73,27 @@ test_expect_success 'blame --textconv going through revisions' '
        test_cmp expected result
 '
 
+test_expect_success 'setup +cachetextconv' '
+       git config diff.test.cachetextconv true
+'
+
+cat >expected_one <<EOF
+(Number2 2010-01-01 20:00:00 +0000 1) converted: test 1 version 2
+EOF
+
+test_expect_success 'blame --textconv works with textconvcache' '
+       git blame --textconv two.bin >blame &&
+       find_blame <blame >result &&
+       test_cmp expected result &&
+       git blame --textconv one.bin >blame &&
+       find_blame  <blame >result &&
+       test_cmp expected_one result
+'
+
+test_expect_success 'setup -cachetextconv' '
+       git config diff.test.cachetextconv false
+'
+
 test_expect_success 'make a new commit' '
        echo "bin: test number 2 version 3" >>two.bin &&
        GIT_AUTHOR_NAME=Number3 git commit -a -m Third --date="2010-01-01 22:00:00"
index 5e48318013a5bf0e4c0ab80f2e5cad6d96887e6a..579ddb7572c27889060da315ddecb773b6fa1272 100755 (executable)
@@ -265,7 +265,7 @@ test_expect_success $PREREQ 'Author From: in message body' '
                --to=nobody@example.com \
                --smtp-server="$(pwd)/fake.sendmail" \
                $patches &&
-       sed "1,/^\$/d" < msgtxt1 > msgbody1
+       sed "1,/^\$/d" < msgtxt1 > msgbody1 &&
        grep "From: A <author@example.com>" msgbody1
 '
 
@@ -276,7 +276,7 @@ test_expect_success $PREREQ 'Author From: not in message body' '
                --to=nobody@example.com \
                --smtp-server="$(pwd)/fake.sendmail" \
                $patches &&
-       sed "1,/^\$/d" < msgtxt1 > msgbody1
+       sed "1,/^\$/d" < msgtxt1 > msgbody1 &&
        ! grep "From: A <author@example.com>" msgbody1
 '
 
@@ -298,7 +298,7 @@ test_expect_success $PREREQ 'Invalid In-Reply-To' '
                --in-reply-to=" " \
                --smtp-server="$(pwd)/fake.sendmail" \
                $patches \
-               2>errors
+               2>errors &&
        ! grep "^In-Reply-To: < *>" msgtxt1
 '
 
@@ -319,7 +319,7 @@ test_expect_success $PREREQ 'In-Reply-To without --chain-reply-to' '
        git send-email \
                --from="Example <nobody@example.com>" \
                --to=nobody@example.com \
-               --no-chain-reply-to \
+               --nochain-reply-to \
                --in-reply-to="$(cat expect)" \
                --smtp-server="$(pwd)/fake.sendmail" \
                $patches $patches $patches \
@@ -617,7 +617,7 @@ EOF
 "
 
 test_expect_success $PREREQ '--suppress-cc=sob' '
-       git config --unset sendemail.cccmd
+       test_might_fail git config --unset sendemail.cccmd &&
        test_suppression sob
 '
 
@@ -1135,7 +1135,7 @@ test_expect_success $PREREQ '--8bit-encoding also treats subject' '
 # Note that the patches in this test are deliberately out of order; we
 # want to make sure it works even if the cover-letter is not in the
 # first mail.
-test_expect_success 'refusing to send cover letter template' '
+test_expect_success $PREREQ 'refusing to send cover letter template' '
        clean_fake_sendmail &&
        rm -fr outdir &&
        git format-patch --cover-letter -2 -o outdir &&
@@ -1151,7 +1151,7 @@ test_expect_success 'refusing to send cover letter template' '
        test -z "$(ls msgtxt*)"
 '
 
-test_expect_success '--force sends cover letter template anyway' '
+test_expect_success $PREREQ '--force sends cover letter template anyway' '
        clean_fake_sendmail &&
        rm -fr outdir &&
        git format-patch --cover-letter -2 -o outdir &&
index a713dfc50bdd69878bb837b28e9f6c61c85f366a..88a9751dd3c73a39a15ec3d18d3dddb7790706bb 100755 (executable)
@@ -2,31 +2,57 @@
 
 test_description='check svn dumpfile importer'
 
-. ./lib-git-svn.sh
-
-test_dump() {
-       label=$1
-       dump=$2
-       test_expect_success "$dump" '
-               svnadmin create "$label-svn" &&
-               svnadmin load "$label-svn" < "$TEST_DIRECTORY/$dump" &&
-               svn_cmd export "file://$PWD/$label-svn" "$label-svnco" &&
-               git init "$label-git" &&
-               test-svn-fe "$TEST_DIRECTORY/$dump" >"$label.fe" &&
-               (
-                       cd "$label-git" &&
-                       git fast-import < ../"$label.fe"
-               ) &&
-               (
-                       cd "$label-svnco" &&
-                       git init &&
-                       git add . &&
-                       git fetch "../$label-git" master &&
-                       git diff --exit-code FETCH_HEAD
-               )
-       '
+. ./test-lib.sh
+
+reinit_git () {
+       rm -fr .git &&
+       git init
 }
 
-test_dump simple t9135/svn.dump
+>empty
+
+test_expect_success 'empty dump' '
+       reinit_git &&
+       echo "SVN-fs-dump-format-version: 2" >input &&
+       test-svn-fe input >stream &&
+       git fast-import <stream
+'
+
+test_expect_success 'v3 dumps not supported' '
+       reinit_git &&
+       echo "SVN-fs-dump-format-version: 3" >input &&
+       test_must_fail test-svn-fe input >stream &&
+       test_cmp empty stream
+'
+
+test_expect_success 'set up svn repo' '
+       svnconf=$PWD/svnconf &&
+       mkdir -p "$svnconf" &&
+
+       if
+               svnadmin -h >/dev/null 2>&1 &&
+               svnadmin create simple-svn &&
+               svnadmin load simple-svn <"$TEST_DIRECTORY/t9135/svn.dump" &&
+               svn export --config-dir "$svnconf" "file://$PWD/simple-svn" simple-svnco
+       then
+               test_set_prereq SVNREPO
+       fi
+'
+
+test_expect_success SVNREPO 't9135/svn.dump' '
+       git init simple-git &&
+       test-svn-fe "$TEST_DIRECTORY/t9135/svn.dump" >simple.fe &&
+       (
+               cd simple-git &&
+               git fast-import <../simple.fe
+       ) &&
+       (
+               cd simple-svnco &&
+               git init &&
+               git add . &&
+               git fetch ../simple-git master &&
+               git diff --exit-code FETCH_HEAD
+       )
+'
 
 test_done
index f3f397cdda4766ce6c02beac13e492d406ca14c4..ff19695e776f803aef03a18e70067c89aa3be218 100755 (executable)
@@ -18,21 +18,14 @@ case $v in
        ;;
 esac
 
-ptouch() {
-       perl -w -e '
-               use strict;
-               use POSIX qw(mktime);
-               die "ptouch requires exactly 2 arguments" if @ARGV != 2;
-               my $text_last_updated = shift @ARGV;
-               my $git_file = shift @ARGV;
-               die "\"$git_file\" does not exist" if ! -e $git_file;
-               if ($text_last_updated
-                   =~ /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/) {
-                       my $mtime = mktime($6, $5, $4, $3, $2 - 1, $1 - 1900);
-                       my $atime = $mtime;
-                       utime $atime, $mtime, $git_file;
-               }
-       ' "`svn_cmd info $2 | grep '^Text Last Updated:'`" "$1"
+# On the "Text Last Updated" line, "git svn info" does not return the
+# same value as "svn info" (i.e. the commit timestamp that touched the
+# path most recently); do not expect that field to match.
+test_cmp_info () {
+       sed -e '/^Text Last Updated:/d' "$1" >tmp.expect
+       sed -e '/^Text Last Updated:/d' "$2" >tmp.actual
+       test_cmp tmp.expect tmp.actual &&
+       rm -f tmp.expect tmp.actual
 }
 
 quoted_svnrepo="$(echo $svnrepo | sed 's/ /%20/')"
@@ -62,17 +55,13 @@ test_expect_success 'setup repository and import' '
                cd gitwc &&
                git svn init "$svnrepo" &&
                git svn fetch
-       ) &&
-       ptouch gitwc/file svnwc/file &&
-       ptouch gitwc/directory svnwc/directory &&
-       ptouch gitwc/symlink-file svnwc/symlink-file &&
-       ptouch gitwc/symlink-directory svnwc/symlink-directory
+       )
        '
 
 test_expect_success 'info' "
        (cd svnwc; svn info) > expected.info &&
        (cd gitwc; git svn info) > actual.info &&
-       test_cmp expected.info actual.info
+       test_cmp_info expected.info actual.info
        "
 
 test_expect_success 'info --url' '
@@ -82,7 +71,7 @@ test_expect_success 'info --url' '
 test_expect_success 'info .' "
        (cd svnwc; svn info .) > expected.info-dot &&
        (cd gitwc; git svn info .) > actual.info-dot &&
-       test_cmp expected.info-dot actual.info-dot
+       test_cmp_info expected.info-dot actual.info-dot
        "
 
 test_expect_success 'info --url .' '
@@ -92,7 +81,7 @@ test_expect_success 'info --url .' '
 test_expect_success 'info file' "
        (cd svnwc; svn info file) > expected.info-file &&
        (cd gitwc; git svn info file) > actual.info-file &&
-       test_cmp expected.info-file actual.info-file
+       test_cmp_info expected.info-file actual.info-file
        "
 
 test_expect_success 'info --url file' '
@@ -102,13 +91,13 @@ test_expect_success 'info --url file' '
 test_expect_success 'info directory' "
        (cd svnwc; svn info directory) > expected.info-directory &&
        (cd gitwc; git svn info directory) > actual.info-directory &&
-       test_cmp expected.info-directory actual.info-directory
+       test_cmp_info expected.info-directory actual.info-directory
        "
 
 test_expect_success 'info inside directory' "
        (cd svnwc/directory; svn info) > expected.info-inside-directory &&
        (cd gitwc/directory; git svn info) > actual.info-inside-directory &&
-       test_cmp expected.info-inside-directory actual.info-inside-directory
+       test_cmp_info expected.info-inside-directory actual.info-inside-directory
        "
 
 test_expect_success 'info --url directory' '
@@ -118,7 +107,7 @@ test_expect_success 'info --url directory' '
 test_expect_success 'info symlink-file' "
        (cd svnwc; svn info symlink-file) > expected.info-symlink-file &&
        (cd gitwc; git svn info symlink-file) > actual.info-symlink-file &&
-       test_cmp expected.info-symlink-file actual.info-symlink-file
+       test_cmp_info expected.info-symlink-file actual.info-symlink-file
        "
 
 test_expect_success 'info --url symlink-file' '
@@ -131,7 +120,7 @@ test_expect_success 'info symlink-directory' "
                > expected.info-symlink-directory &&
        (cd gitwc; git svn info symlink-directory) \
                > actual.info-symlink-directory &&
-       test_cmp expected.info-symlink-directory actual.info-symlink-directory
+       test_cmp_info expected.info-symlink-directory actual.info-symlink-directory
        "
 
 test_expect_success 'info --url symlink-directory' '
@@ -146,14 +135,13 @@ test_expect_success 'info added-file' "
                git add added-file
        ) &&
        cp gitwc/added-file svnwc/added-file &&
-       ptouch gitwc/added-file svnwc/added-file &&
        (
                cd svnwc &&
                svn_cmd add added-file > /dev/null
        ) &&
        (cd svnwc; svn info added-file) > expected.info-added-file &&
        (cd gitwc; git svn info added-file) > actual.info-added-file &&
-       test_cmp expected.info-added-file actual.info-added-file
+       test_cmp_info expected.info-added-file actual.info-added-file
        "
 
 test_expect_success 'info --url added-file' '
@@ -163,7 +151,6 @@ test_expect_success 'info --url added-file' '
 
 test_expect_success 'info added-directory' "
        mkdir gitwc/added-directory svnwc/added-directory &&
-       ptouch gitwc/added-directory svnwc/added-directory &&
        touch gitwc/added-directory/.placeholder &&
        (
                cd svnwc &&
@@ -177,7 +164,7 @@ test_expect_success 'info added-directory' "
                > expected.info-added-directory &&
        (cd gitwc; git svn info added-directory) \
                > actual.info-added-directory &&
-       test_cmp expected.info-added-directory actual.info-added-directory
+       test_cmp_info expected.info-added-directory actual.info-added-directory
        "
 
 test_expect_success 'info --url added-directory' '
@@ -196,13 +183,12 @@ test_expect_success 'info added-symlink-file' "
                ln -s added-file added-symlink-file &&
                svn_cmd add added-symlink-file > /dev/null
        ) &&
-       ptouch gitwc/added-symlink-file svnwc/added-symlink-file &&
        (cd svnwc; svn info added-symlink-file) \
                > expected.info-added-symlink-file &&
        (cd gitwc; git svn info added-symlink-file) \
                > actual.info-added-symlink-file &&
-       test_cmp expected.info-added-symlink-file \
-                actual.info-added-symlink-file
+       test_cmp_info expected.info-added-symlink-file \
+               actual.info-added-symlink-file
        "
 
 test_expect_success 'info --url added-symlink-file' '
@@ -221,13 +207,12 @@ test_expect_success 'info added-symlink-directory' "
                ln -s added-directory added-symlink-directory &&
                svn_cmd add added-symlink-directory > /dev/null
        ) &&
-       ptouch gitwc/added-symlink-directory svnwc/added-symlink-directory &&
        (cd svnwc; svn info added-symlink-directory) \
                > expected.info-added-symlink-directory &&
        (cd gitwc; git svn info added-symlink-directory) \
                > actual.info-added-symlink-directory &&
-       test_cmp expected.info-added-symlink-directory \
-                actual.info-added-symlink-directory
+       test_cmp_info expected.info-added-symlink-directory \
+               actual.info-added-symlink-directory
        "
 
 test_expect_success 'info --url added-symlink-directory' '
@@ -235,11 +220,6 @@ test_expect_success 'info --url added-symlink-directory' '
             = "$quoted_svnrepo/added-symlink-directory"
        '
 
-# The next few tests replace the "Text Last Updated" value with a
-# placeholder since git doesn't have a way to know the date that a
-# now-deleted file was last checked out locally.  Internally it
-# simply reuses the Last Changed Date.
-
 test_expect_success 'info deleted-file' "
        (
                cd gitwc &&
@@ -249,13 +229,9 @@ test_expect_success 'info deleted-file' "
                cd svnwc &&
                svn_cmd rm --force file > /dev/null
        ) &&
-       (cd svnwc; svn info file) |
-       sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
-               > expected.info-deleted-file &&
-       (cd gitwc; git svn info file) |
-       sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
-               > actual.info-deleted-file &&
-       test_cmp expected.info-deleted-file actual.info-deleted-file
+       (cd svnwc; svn info file) >expected.info-deleted-file &&
+       (cd gitwc; git svn info file) >actual.info-deleted-file &&
+       test_cmp_info expected.info-deleted-file actual.info-deleted-file
        "
 
 test_expect_success 'info --url file (deleted)' '
@@ -272,13 +248,9 @@ test_expect_success 'info deleted-directory' "
                cd svnwc &&
                svn_cmd rm --force directory > /dev/null
        ) &&
-       (cd svnwc; svn info directory) |
-       sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
-               > expected.info-deleted-directory &&
-       (cd gitwc; git svn info directory) |
-       sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
-               > actual.info-deleted-directory &&
-       test_cmp expected.info-deleted-directory actual.info-deleted-directory
+       (cd svnwc; svn info directory) >expected.info-deleted-directory &&
+       (cd gitwc; git svn info directory) >actual.info-deleted-directory &&
+       test_cmp_info expected.info-deleted-directory actual.info-deleted-directory
        "
 
 test_expect_success 'info --url directory (deleted)' '
@@ -295,14 +267,9 @@ test_expect_success 'info deleted-symlink-file' "
                cd svnwc &&
                svn_cmd rm --force symlink-file > /dev/null
        ) &&
-       (cd svnwc; svn info symlink-file) |
-       sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
-               > expected.info-deleted-symlink-file &&
-       (cd gitwc; git svn info symlink-file) |
-       sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
-               > actual.info-deleted-symlink-file &&
-       test_cmp expected.info-deleted-symlink-file \
-                actual.info-deleted-symlink-file
+       (cd svnwc; svn info symlink-file) >expected.info-deleted-symlink-file &&
+       (cd gitwc; git svn info symlink-file) >actual.info-deleted-symlink-file &&
+       test_cmp_info expected.info-deleted-symlink-file actual.info-deleted-symlink-file
        "
 
 test_expect_success 'info --url symlink-file (deleted)' '
@@ -319,14 +286,9 @@ test_expect_success 'info deleted-symlink-directory' "
                cd svnwc &&
                svn_cmd rm --force symlink-directory > /dev/null
        ) &&
-       (cd svnwc; svn info symlink-directory) |
-       sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
-                > expected.info-deleted-symlink-directory &&
-       (cd gitwc; git svn info symlink-directory) |
-       sed -e 's/^\(Text Last Updated:\).*/\1 TEXT-LAST-UPDATED-STRING/' \
-                > actual.info-deleted-symlink-directory &&
-       test_cmp expected.info-deleted-symlink-directory \
-                actual.info-deleted-symlink-directory
+       (cd svnwc; svn info symlink-directory) >expected.info-deleted-symlink-directory &&
+       (cd gitwc; git svn info symlink-directory) >actual.info-deleted-symlink-directory &&
+       test_cmp_info expected.info-deleted-symlink-directory actual.info-deleted-symlink-directory
        "
 
 test_expect_success 'info --url symlink-directory (deleted)' '
index 1236accd993d5bc1a80fbda720ce229f8e93940c..e21ee5f663ce8333625c5d9d483c42dde3394675 100755 (executable)
@@ -17,11 +17,10 @@ test_expect_success 'setup test repository' '
                > foo &&
                svn_cmd add foo &&
                svn_cmd commit -m "add foo"
-       )
+       ) &&
+       start_httpd
 '
 
-start_httpd
-
 test_expect_success 'clone trunk with "-r HEAD"' '
        git svn clone -r HEAD "$svnrepo/trunk" g &&
        ( cd g && git rev-parse --symbolic --verify HEAD )
index da582c53825a5719f6c9d82983e0951afcccd0df..991d2aa1be63c2440db93e6237201383e28a498a 100755 (executable)
@@ -6,6 +6,14 @@
 test_description='git svn merge detection'
 . ./lib-git-svn.sh
 
+svn_ver="$(svn --version --quiet)"
+case $svn_ver in
+0.* | 1.[0-4].*)
+       skip_all="skipping git-svn test - SVN too old ($svn_ver)"
+       test_done
+       ;;
+esac
+
 test_expect_success 'initialize source svn repo' '
        svn_cmd mkdir -m x "$svnrepo"/trunk &&
        svn_cmd mkdir -m x "$svnrepo"/branches &&
old mode 100644 (file)
new mode 100755 (executable)
index e8034d410fe50a770c3122c98967d80937bb1943..52ac0e56dce12016ab03155bd16b2b66b062fca3 100755 (executable)
@@ -7,6 +7,23 @@ test_description='test git fast-import utility'
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/diff-lib.sh ;# test-lib chdir's into trash
 
+# Print $1 bytes from stdin to stdout.
+#
+# This could be written as "head -c $1", but IRIX "head" does not
+# support the -c option.
+head_c () {
+       perl -e '
+               my $len = $ARGV[1];
+               while ($len > 0) {
+                       my $s;
+                       my $nread = sysread(STDIN, $s, $len);
+                       die "cannot read: $!" unless defined($nread);
+                       print $s;
+                       $len -= $nread;
+               }
+       ' - "$1"
+}
+
 file2_data='file2
 second line of EOF'
 
@@ -23,11 +40,18 @@ file5_data='an inline file.
 file6_data='#!/bin/sh
 echo "$@"'
 
+>empty
+
 ###
 ### series A
 ###
 
 test_tick
+
+test_expect_success 'empty stream succeeds' '
+       git fast-import </dev/null
+'
+
 cat >input <<INPUT_END
 blob
 mark :2
@@ -895,6 +919,48 @@ test_expect_success \
         git diff-tree -C --find-copies-harder -r N4 N6 >actual &&
         compare_diff_raw expect actual'
 
+test_expect_success \
+       'N: delete directory by copying' \
+       'cat >expect <<-\EOF &&
+       OBJID
+       :100644 000000 OBJID OBJID D    foo/bar/qux
+       OBJID
+       :000000 100644 OBJID OBJID A    foo/bar/baz
+       :000000 100644 OBJID OBJID A    foo/bar/qux
+       EOF
+        empty_tree=$(git mktree </dev/null) &&
+        cat >input <<-INPUT_END &&
+       commit refs/heads/N-delete
+       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+       data <<COMMIT
+       collect data to be deleted
+       COMMIT
+
+       deleteall
+       M 100644 inline foo/bar/baz
+       data <<DATA_END
+       hello
+       DATA_END
+       C "foo/bar/baz" "foo/bar/qux"
+       C "foo/bar/baz" "foo/bar/quux/1"
+       C "foo/bar/baz" "foo/bar/quuux"
+       M 040000 $empty_tree foo/bar/quux
+       M 040000 $empty_tree foo/bar/quuux
+
+       commit refs/heads/N-delete
+       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+       data <<COMMIT
+       delete subdirectory
+       COMMIT
+
+       M 040000 $empty_tree foo/bar/qux
+       INPUT_END
+        git fast-import <input &&
+        git rev-list N-delete |
+               git diff-tree -r --stdin --root --always |
+               sed -e "s/$_x40/OBJID/g" >actual &&
+        test_cmp expect actual'
+
 test_expect_success \
        'N: modify copied tree' \
        'cat >expect <<-\EOF &&
@@ -1682,6 +1748,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
@@ -1740,6 +1861,253 @@ test_expect_success 'R: feature no-relative-marks should be honoured' '
     test_cmp marks.new non-relative.out
 '
 
+test_expect_success 'R: feature cat-blob supported' '
+       echo "feature cat-blob" |
+       git fast-import
+'
+
+test_expect_success 'R: cat-blob-fd must be a nonnegative integer' '
+       test_must_fail git fast-import --cat-blob-fd=-1 </dev/null
+'
+
+test_expect_success 'R: print old blob' '
+       blob=$(echo "yes it can" | git hash-object -w --stdin) &&
+       cat >expect <<-EOF &&
+       ${blob} blob 11
+       yes it can
+
+       EOF
+       echo "cat-blob $blob" |
+       git fast-import --cat-blob-fd=6 6>actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'R: in-stream cat-blob-fd not respected' '
+       echo hello >greeting &&
+       blob=$(git hash-object -w greeting) &&
+       cat >expect <<-EOF &&
+       ${blob} blob 6
+       hello
+
+       EOF
+       git fast-import --cat-blob-fd=3 3>actual.3 >actual.1 <<-EOF &&
+       cat-blob $blob
+       EOF
+       test_cmp expect actual.3 &&
+       test_cmp empty actual.1 &&
+       git fast-import 3>actual.3 >actual.1 <<-EOF &&
+       option cat-blob-fd=3
+       cat-blob $blob
+       EOF
+       test_cmp empty actual.3 &&
+       test_cmp expect actual.1
+'
+
+test_expect_success 'R: print new blob' '
+       blob=$(echo "yep yep yep" | git hash-object --stdin) &&
+       cat >expect <<-EOF &&
+       ${blob} blob 12
+       yep yep yep
+
+       EOF
+       git fast-import --cat-blob-fd=6 6>actual <<-\EOF &&
+       blob
+       mark :1
+       data <<BLOB_END
+       yep yep yep
+       BLOB_END
+       cat-blob :1
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'R: print new blob by sha1' '
+       blob=$(echo "a new blob named by sha1" | git hash-object --stdin) &&
+       cat >expect <<-EOF &&
+       ${blob} blob 25
+       a new blob named by sha1
+
+       EOF
+       git fast-import --cat-blob-fd=6 6>actual <<-EOF &&
+       blob
+       data <<BLOB_END
+       a new blob named by sha1
+       BLOB_END
+       cat-blob $blob
+       EOF
+       test_cmp expect actual
+'
+
+test_expect_success 'setup: big file' '
+       (
+               echo "the quick brown fox jumps over the lazy dog" >big &&
+               for i in 1 2 3
+               do
+                       cat big big big big >bigger &&
+                       cat bigger bigger bigger bigger >big ||
+                       exit
+               done
+       )
+'
+
+test_expect_success 'R: print two blobs to stdout' '
+       blob1=$(git hash-object big) &&
+       blob1_len=$(wc -c <big) &&
+       blob2=$(echo hello | git hash-object --stdin) &&
+       {
+               echo ${blob1} blob $blob1_len &&
+               cat big &&
+               cat <<-EOF
+
+               ${blob2} blob 6
+               hello
+
+               EOF
+       } >expect &&
+       {
+               cat <<-\END_PART1 &&
+                       blob
+                       mark :1
+                       data <<data_end
+               END_PART1
+               cat big &&
+               cat <<-\EOF
+                       data_end
+                       blob
+                       mark :2
+                       data <<data_end
+                       hello
+                       data_end
+                       cat-blob :1
+                       cat-blob :2
+               EOF
+       } |
+       git fast-import >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 PIPE 'R: copy using cat-file' '
+       expect_id=$(git hash-object big) &&
+       expect_len=$(wc -c <big) &&
+       echo $expect_id blob $expect_len >expect.response &&
+
+       rm -f blobs &&
+       cat >frontend <<-\FRONTEND_END &&
+       #!/bin/sh
+       FRONTEND_END
+
+       mkfifo blobs &&
+       (
+               export GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL GIT_COMMITTER_DATE &&
+               cat <<-\EOF &&
+               feature cat-blob
+               blob
+               mark :1
+               data <<BLOB
+               EOF
+               cat big &&
+               cat <<-\EOF &&
+               BLOB
+               cat-blob :1
+               EOF
+
+               read blob_id type size <&3 &&
+               echo "$blob_id $type $size" >response &&
+               head_c $size >blob <&3 &&
+               read newline <&3 &&
+
+               cat <<-EOF &&
+               commit refs/heads/copied
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               copy big file as file3
+               COMMIT
+               M 644 inline file3
+               data <<BLOB
+               EOF
+               cat blob &&
+               echo BLOB
+       ) 3<blobs |
+       git fast-import --cat-blob-fd=3 3>blobs &&
+       git show copied:file3 >actual &&
+       test_cmp expect.response response &&
+       test_cmp big actual
+'
+
+test_expect_success PIPE 'R: print blob mid-commit' '
+       rm -f blobs &&
+       echo "A blob from _before_ the commit." >expect &&
+       mkfifo blobs &&
+       (
+               exec 3<blobs &&
+               cat <<-EOF &&
+               feature cat-blob
+               blob
+               mark :1
+               data <<BLOB
+               A blob from _before_ the commit.
+               BLOB
+               commit refs/heads/temporary
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               Empty commit
+               COMMIT
+               cat-blob :1
+               EOF
+
+               read blob_id type size <&3 &&
+               head_c $size >actual <&3 &&
+               read newline <&3 &&
+
+               echo
+       ) |
+       git fast-import --cat-blob-fd=3 3>blobs &&
+       test_cmp expect actual
+'
+
+test_expect_success PIPE 'R: print staged blob within commit' '
+       rm -f blobs &&
+       echo "A blob from _within_ the commit." >expect &&
+       mkfifo blobs &&
+       (
+               exec 3<blobs &&
+               cat <<-EOF &&
+               feature cat-blob
+               commit refs/heads/within
+               committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+               data <<COMMIT
+               Empty commit
+               COMMIT
+               M 644 inline within
+               data <<BLOB
+               A blob from _within_ the commit.
+               BLOB
+               EOF
+
+               to_get=$(
+                       echo "A blob from _within_ the commit." |
+                       git hash-object --stdin
+               ) &&
+               echo "cat-blob $to_get" &&
+
+               read blob_id type size <&3 &&
+               head_c $size >actual <&3 &&
+               read newline <&3 &&
+
+               echo deleteall
+       ) |
+       git fast-import --cat-blob-fd=3 3>blobs &&
+       test_cmp expect actual
+'
+
 cat >input << EOF
 option git quiet
 blob
@@ -1748,8 +2116,6 @@ hi
 
 EOF
 
-touch empty
-
 test_expect_success 'R: quiet option results in no stats being output' '
     cat input | git fast-import 2> output &&
     test_cmp empty output
@@ -1767,6 +2133,14 @@ test_expect_success 'R: unknown commandline options are rejected' '\
     test_must_fail git fast-import --non-existing-option < /dev/null
 '
 
+test_expect_success 'R: die on invalid option argument' '
+       echo "option git active-branches=-5" |
+       test_must_fail git fast-import &&
+       echo "option git depth=" |
+       test_must_fail git fast-import &&
+       test_must_fail git fast-import --depth="5 elephants" </dev/null
+'
+
 cat >input <<EOF
 option non-existing-vcs non-existing-option
 EOF
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 2487da1296da1a2508526f58a2e45fa750c49c8e..26102ee9b0c36a87ba17a75b0ca644cc42e2c1c4 100755 (executable)
@@ -16,7 +16,7 @@ code and message.'
 # snapshot settings
 
 test_expect_success 'setup' "
-       test_commit 'SnapshotTests' 'i can has snapshot?'
+       test_commit 'SnapshotTests' 'i can has snapshot'
 "
 
 
@@ -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 432b82e3d5a361d0eba329f5d5c56c17009738db..4c384ff02333e1413cc67b1b4a6bed47ae3d00db 100755 (executable)
@@ -89,7 +89,8 @@ EOF
 test_expect_success PERL 'update git module' '
 
        (cd module-git &&
-       git cvsimport -a -R -z 0 module &&
+       git config cvsimport.trackRevisions true &&
+       git cvsimport -a -z 0 module &&
        git merge origin
        ) &&
        test_cmp module-cvs/o_fortuna module-git/o_fortuna
@@ -117,7 +118,8 @@ test_expect_success PERL 'cvsimport.module config works' '
 
        (cd module-git &&
                git config cvsimport.module module &&
-               git cvsimport -a -R -z0 &&
+               git config cvsimport.trackRevisions true &&
+               git cvsimport -a -z0 &&
                git merge origin
        ) &&
        test_cmp module-cvs/tick module-git/tick
@@ -137,6 +139,7 @@ test_expect_success PERL 'import from a CVS working tree' '
 
        $CVS co -d import-from-wt module &&
        (cd import-from-wt &&
+               git config cvsimport.trackRevisions false &&
                git cvsimport -a -z0 &&
                echo 1 >expect &&
                git log -1 --pretty=format:%s%n >actual &&
index 48fa5160045d0bb2c14d034422b2ee5170889ec5..0fdc541a7cd7d6b694c4f4a3fd06b6cf21dc7380 100644 (file)
@@ -70,6 +70,9 @@ 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
@@ -260,7 +263,7 @@ test_decode_color () {
                        if (n == 47) return "BWHITE";
                }
                {
-                       while (match($0, /\x1b\[[0-9;]*m/) != 0) {
+                       while (match($0, /\033\[[0-9;]*m/) != 0) {
                                printf "%s<", substr($0, 1, RSTART-1);
                                codes = substr($0, RSTART+2, RLENGTH-3);
                                if (length(codes) == 0)
@@ -1057,6 +1060,13 @@ case $(uname -s) in
        # backslashes in pathspec are converted to '/'
        # exec does not inherit the PID
        test_set_prereq MINGW
+       test_set_prereq SED_STRIPS_CR
+       ;;
+*CYGWIN*)
+       test_set_prereq POSIXPERM
+       test_set_prereq EXECKEEPSPID
+       test_set_prereq NOT_MINGW
+       test_set_prereq SED_STRIPS_CR
        ;;
 *)
        test_set_prereq POSIXPERM
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);
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;
+}
diff --git a/test-subprocess.c b/test-subprocess.c
new file mode 100644 (file)
index 0000000..667d3e5
--- /dev/null
@@ -0,0 +1,21 @@
+#include "cache.h"
+#include "run-command.h"
+
+int main(int argc, char **argv)
+{
+       const char *prefix;
+       struct child_process cp;
+       int nogit = 0;
+
+       prefix = setup_git_directory_gently(&nogit);
+       if (nogit)
+               die("No git repo found");
+       if (!strcmp(argv[1], "--setup-work-tree")) {
+               setup_work_tree();
+               argv++;
+       }
+       memset(&cp, 0, sizeof(cp));
+       cp.git_cmd = 1;
+       cp.argv = (const char **)argv+1;
+       return run_command(&cp);
+}
index cdba5111e19cd850f262108a330ce5d4ce63a166..ab8c951c6eb39f54a9885dd15c173f974d7357d5 100644 (file)
@@ -38,9 +38,14 @@ int main(int argc, char *argv[])
                usage("test-treap < ints");
 
        while (strbuf_getline(&sb, stdin, '\n') != EOF) {
-               item = node_alloc(1);
-               strtonode(node_pointer(item), sb.buf);
-               treap_insert(&root, node_pointer(item));
+               struct int_node *node = node_pointer(node_alloc(1));
+
+               item = node_offset(node);
+               strtonode(node, sb.buf);
+               node = treap_insert(&root, node_pointer(item));
+               if (node_offset(node) != item)
+                       die("inserted %"PRIu32" in place of %"PRIu32"",
+                               node_offset(node), item);
        }
 
        item = node_offset(treap_first(&root));
diff --git a/trace.c b/trace.c
index 1e560cb0b977e19beeb095497c8e4f6280b7f0d6..35d388dce44a4a8e3d6053dfd6abcb652771818a 100644 (file)
--- a/trace.c
+++ b/trace.c
 #include "cache.h"
 #include "quote.h"
 
-void do_nothing(size_t unused)
-{
-}
-
 /* Get a trace file descriptor from GIT_TRACE env variable. */
 static int get_trace_fd(int *need_close)
 {
@@ -76,7 +72,7 @@ void trace_printf(const char *fmt, ...)
        if (!fd)
                return;
 
-       set_try_to_free_routine(do_nothing);    /* is never reset */
+       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);
@@ -108,7 +104,7 @@ void trace_argv_printf(const char **argv, const char *fmt, ...)
        if (!fd)
                return;
 
-       set_try_to_free_routine(do_nothing);    /* is never reset */
+       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);
@@ -131,3 +127,52 @@ void trace_argv_printf(const char **argv, const char *fmt, ...)
        if (need_close)
                close(fd);
 }
+
+static const char *quote_crnl(const char *path)
+{
+       static char new_path[PATH_MAX];
+       const char *p2 = path;
+       char *p1 = new_path;
+
+       if (!path)
+               return NULL;
+
+       while (*p2) {
+               switch (*p2) {
+               case '\\': *p1++ = '\\'; *p1++ = '\\'; break;
+               case '\n': *p1++ = '\\'; *p1++ = 'n'; break;
+               case '\r': *p1++ = '\\'; *p1++ = 'r'; break;
+               default:
+                       *p1++ = *p2;
+               }
+               p2++;
+       }
+       *p1 = '\0';
+       return new_path;
+}
+
+/* FIXME: move prefix to startup_info struct and get rid of this arg */
+void trace_repo_setup(const char *prefix)
+{
+       const char *git_work_tree;
+       char cwd[PATH_MAX];
+       char *trace = getenv("GIT_TRACE");
+
+       if (!trace || !strcmp(trace, "") ||
+           !strcmp(trace, "0") || !strcasecmp(trace, "false"))
+               return;
+
+       if (!getcwd(cwd, PATH_MAX))
+               die("Unable to get current working directory");
+
+       if (!(git_work_tree = get_git_work_tree()))
+               git_work_tree = "(null)";
+
+       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));
+}
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 d5a453079a02ff8b7a63a3453d07935e0807c005..b68ec820dde935eb2578a8983c265290d0511add 100644 (file)
@@ -231,20 +231,11 @@ static int check_updates(struct unpack_trees_options *o)
 static int verify_uptodate_sparse(struct cache_entry *ce, struct unpack_trees_options *o);
 static int verify_absent_sparse(struct cache_entry *ce, enum unpack_trees_error_types, struct unpack_trees_options *o);
 
-static int will_have_skip_worktree(const struct cache_entry *ce, struct unpack_trees_options *o)
-{
-       const char *basename;
-
-       basename = strrchr(ce->name, '/');
-       basename = basename ? basename+1 : ce->name;
-       return excluded_from_list(ce->name, ce_namelen(ce), basename, NULL, o->el) <= 0;
-}
-
 static int apply_sparse_checkout(struct cache_entry *ce, struct unpack_trees_options *o)
 {
        int was_skip_worktree = ce_skip_worktree(ce);
 
-       if (!ce_stage(ce) && will_have_skip_worktree(ce, o))
+       if (ce->ce_flags & CE_NEW_SKIP_WORKTREE)
                ce->ce_flags |= CE_SKIP_WORKTREE;
        else
                ce->ce_flags &= ~CE_SKIP_WORKTREE;
@@ -319,7 +310,7 @@ static void mark_all_ce_unused(struct index_state *index)
 {
        int i;
        for (i = 0; i < index->cache_nr; i++)
-               index->cache[i]->ce_flags &= ~CE_UNPACKED;
+               index->cache[i]->ce_flags &= ~(CE_UNPACKED | CE_ADDED | CE_NEW_SKIP_WORKTREE);
 }
 
 static int locate_in_src_index(struct cache_entry *ce,
@@ -390,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;
@@ -436,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];
@@ -820,9 +814,177 @@ static int unpack_callback(int n, unsigned long mask, unsigned long dirmask, str
        return mask;
 }
 
+/* Whole directory matching */
+static int clear_ce_flags_dir(struct cache_entry **cache, int nr,
+                             char *prefix, int prefix_len,
+                             char *basename,
+                             int select_mask, int clear_mask,
+                             struct exclude_list *el)
+{
+       struct cache_entry **cache_end = cache + nr;
+       int dtype = DT_DIR;
+       int ret = excluded_from_list(prefix, prefix_len, basename, &dtype, el);
+
+       prefix[prefix_len++] = '/';
+
+       /* included, no clearing for any entries under this directory */
+       if (!ret) {
+               for (; cache != cache_end; cache++) {
+                       struct cache_entry *ce = *cache;
+                       if (strncmp(ce->name, prefix, prefix_len))
+                               break;
+               }
+               return nr - (cache_end - cache);
+       }
+
+       /* excluded, clear all selected entries under this directory. */
+       if (ret == 1) {
+               for (; cache != cache_end; cache++) {
+                       struct cache_entry *ce = *cache;
+                       if (select_mask && !(ce->ce_flags & select_mask))
+                               continue;
+                       if (strncmp(ce->name, prefix, prefix_len))
+                               break;
+                       ce->ce_flags &= ~clear_mask;
+               }
+               return nr - (cache_end - cache);
+       }
+
+       return 0;
+}
+
+/*
+ * Traverse the index, find every entry that matches according to
+ * o->el. Do "ce_flags &= ~clear_mask" on those entries. Return the
+ * number of traversed entries.
+ *
+ * If select_mask is non-zero, only entries whose ce_flags has on of
+ * those bits enabled are traversed.
+ *
+ * cache       : pointer to an index entry
+ * prefix_len  : an offset to its path
+ *
+ * The current path ("prefix") including the trailing '/' is
+ *   cache[0]->name[0..(prefix_len-1)]
+ * Top level path has prefix_len zero.
+ */
+static int clear_ce_flags_1(struct cache_entry **cache, int nr,
+                           char *prefix, int prefix_len,
+                           int select_mask, int clear_mask,
+                           struct exclude_list *el)
+{
+       struct cache_entry **cache_end = cache + nr;
+
+       /*
+        * Process all entries that have the given prefix and meet
+        * select_mask condition
+        */
+       while(cache != cache_end) {
+               struct cache_entry *ce = *cache;
+               const char *name, *slash;
+               int len, dtype;
+
+               if (select_mask && !(ce->ce_flags & select_mask)) {
+                       cache++;
+                       continue;
+               }
+
+               if (prefix_len && strncmp(ce->name, prefix, prefix_len))
+                       break;
+
+               name = ce->name + prefix_len;
+               slash = strchr(name, '/');
+
+               /* If it's a directory, try whole directory match first */
+               if (slash) {
+                       int processed;
+
+                       len = slash - name;
+                       memcpy(prefix + prefix_len, name, len);
+
+                       /*
+                        * terminate the string (no trailing slash),
+                        * clear_c_f_dir needs it
+                        */
+                       prefix[prefix_len + len] = '\0';
+                       processed = clear_ce_flags_dir(cache, cache_end - cache,
+                                                      prefix, prefix_len + len,
+                                                      prefix + prefix_len,
+                                                      select_mask, clear_mask,
+                                                      el);
+
+                       /* clear_c_f_dir eats a whole dir already? */
+                       if (processed) {
+                               cache += processed;
+                               continue;
+                       }
+
+                       prefix[prefix_len + len++] = '/';
+                       cache += clear_ce_flags_1(cache, cache_end - cache,
+                                                 prefix, prefix_len + len,
+                                                 select_mask, clear_mask, el);
+                       continue;
+               }
+
+               /* Non-directory */
+               dtype = ce_to_dtype(ce);
+               if (excluded_from_list(ce->name, ce_namelen(ce), name, &dtype, el) > 0)
+                       ce->ce_flags &= ~clear_mask;
+               cache++;
+       }
+       return nr - (cache_end - cache);
+}
+
+static int clear_ce_flags(struct cache_entry **cache, int nr,
+                           int select_mask, int clear_mask,
+                           struct exclude_list *el)
+{
+       char prefix[PATH_MAX];
+       return clear_ce_flags_1(cache, nr,
+                               prefix, 0,
+                               select_mask, clear_mask,
+                               el);
+}
+
+/*
+ * Set/Clear CE_NEW_SKIP_WORKTREE according to $GIT_DIR/info/sparse-checkout
+ */
+static void mark_new_skip_worktree(struct exclude_list *el,
+                                  struct index_state *the_index,
+                                  int select_flag, int skip_wt_flag)
+{
+       int i;
+
+       /*
+        * 1. Pretend the narrowest worktree: only unmerged entries
+        * are checked out
+        */
+       for (i = 0; i < the_index->cache_nr; i++) {
+               struct cache_entry *ce = the_index->cache[i];
+
+               if (select_flag && !(ce->ce_flags & select_flag))
+                       continue;
+
+               if (!ce_stage(ce))
+                       ce->ce_flags |= skip_wt_flag;
+               else
+                       ce->ce_flags &= ~skip_wt_flag;
+       }
+
+       /*
+        * 2. Widen worktree according to sparse-checkout file.
+        * Matched entries will have skip_wt_flag cleared (i.e. "in")
+        */
+       clear_ce_flags(the_index->cache, the_index->cache_nr,
+                      select_flag, skip_wt_flag, el);
+}
+
+static int verify_absent(struct cache_entry *, enum unpack_trees_error_types, struct unpack_trees_options *);
 /*
  * N-way merge "len" trees.  Returns 0 on success, -1 on failure to manipulate the
  * resulting index, -2 on failure to reflect the changes to the work tree.
+ *
+ * CE_ADDED, CE_UNPACKED and CE_NEW_SKIP_WORKTREE are used internally
  */
 int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options *o)
 {
@@ -855,6 +1017,12 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
        o->merge_size = len;
        mark_all_ce_unused(o->src_index);
 
+       /*
+        * Sparse checkout loop #1: set NEW_SKIP_WORKTREE on existing entries
+        */
+       if (!o->skip_sparse_checkout)
+               mark_new_skip_worktree(o->el, o->src_index, 0, CE_NEW_SKIP_WORKTREE);
+
        if (!dfc)
                dfc = xcalloc(1, cache_entry_size(0));
        o->df_conflict_entry = dfc;
@@ -908,9 +1076,29 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 
        if (!o->skip_sparse_checkout) {
                int empty_worktree = 1;
-               for (i = 0;i < o->result.cache_nr;i++) {
+
+               /*
+                * Sparse checkout loop #2: set NEW_SKIP_WORKTREE on entries not in loop #1
+                * If the will have NEW_SKIP_WORKTREE, also set CE_SKIP_WORKTREE
+                * so apply_sparse_checkout() won't attempt to remove it from worktree
+                */
+               mark_new_skip_worktree(o->el, &o->result, CE_ADDED, CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE);
+
+               for (i = 0; i < o->result.cache_nr; i++) {
                        struct cache_entry *ce = o->result.cache[i];
 
+                       /*
+                        * Entries marked with CE_ADDED in merged_entry() do not have
+                        * verify_absent() check (the check is effectively disabled
+                        * because CE_NEW_SKIP_WORKTREE is set unconditionally).
+                        *
+                        * Do the real check now because we have had
+                        * correct CE_NEW_SKIP_WORKTREE
+                        */
+                       if (ce->ce_flags & CE_ADDED &&
+                           verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o))
+                                       return -1;
+
                        if (apply_sparse_checkout(ce, o)) {
                                ret = -1;
                                goto done;
@@ -920,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;
                }
@@ -931,11 +1120,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
                *o->dst_index = o->result;
 
 done:
-       for (i = 0;i < el.nr;i++)
-               free(el.excludes[i]);
-       if (el.excludes)
-               free(el.excludes);
-
+       free_excludes(&el);
        return ret;
 
 return_failed:
@@ -1003,7 +1188,7 @@ static int verify_uptodate_1(struct cache_entry *ce,
 static int verify_uptodate(struct cache_entry *ce,
                           struct unpack_trees_options *o)
 {
-       if (!o->skip_sparse_checkout && will_have_skip_worktree(ce, o))
+       if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE))
                return 0;
        return verify_uptodate_1(ce, o, ERROR_NOT_UPTODATE_FILE);
 }
@@ -1193,23 +1378,29 @@ 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,
                         enum unpack_trees_error_types error_type,
                         struct unpack_trees_options *o)
 {
-       if (!o->skip_sparse_checkout && will_have_skip_worktree(ce, o))
+       if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE))
                return 0;
        return verify_absent_1(ce, error_type, o);
 }
@@ -1231,10 +1422,23 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
        int update = CE_UPDATE;
 
        if (!old) {
+               /*
+                * New index entries. In sparse checkout, the following
+                * verify_absent() will be delayed until after
+                * traverse_trees() finishes in unpack_trees(), then:
+                *
+                *  - CE_NEW_SKIP_WORKTREE will be computed correctly
+                *  - verify_absent() be called again, this time with
+                *    correct CE_NEW_SKIP_WORKTREE
+                *
+                * verify_absent() call here does nothing in sparse
+                * checkout (i.e. o->skip_sparse_checkout == 0)
+                */
+               update |= CE_ADDED;
+               merge->ce_flags |= CE_NEW_SKIP_WORKTREE;
+
                if (verify_absent(merge, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o))
                        return -1;
-               if (!o->skip_sparse_checkout && will_have_skip_worktree(merge, o))
-                       update |= CE_SKIP_WORKTREE;
                invalidate_ce_path(merge, o);
        } else if (!(old->ce_flags & CE_CONFLICTED)) {
                /*
@@ -1250,8 +1454,8 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
                } else {
                        if (verify_uptodate(old, o))
                                return -1;
-                       if (ce_skip_worktree(old))
-                               update |= CE_SKIP_WORKTREE;
+                       /* Migrate old flags over */
+                       update |= old->ce_flags & (CE_SKIP_WORKTREE | CE_NEW_SKIP_WORKTREE);
                        invalidate_ce_path(old, o);
                }
        } else {
index f05e4229d0d3a3ed34b4bba6636f4d333c74dc22..b40a43f27d0e16f0305153f984741938b3a6ab89 100644 (file)
@@ -366,7 +366,7 @@ static int reachable(struct commit *want)
 {
        struct commit_list *work = NULL;
 
-       insert_by_date(want, &work);
+       commit_list_insert_by_date(want, &work);
        while (work) {
                struct commit_list *list = work->next;
                struct commit *commit = work->item;
@@ -387,7 +387,7 @@ static int reachable(struct commit *want)
                for (list = commit->parents; list; list = list->next) {
                        struct commit *parent = list->item;
                        if (!(parent->object.flags & REACHABLE))
-                               insert_by_date(parent, &work);
+                               commit_list_insert_by_date(parent, &work);
                }
        }
        want->object.flags |= REACHABLE;
index f9e05b548c2fdbc349a1d47d81619e266ec9fb83..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,43 +49,54 @@ 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",
-        "^((procedure|function|constructor|destructor|interface|"
+        "^(((class[ \t]+)?(procedure|function)|constructor|destructor|interface|"
                "implementation|initialization|finalization)[ \t]*.*)$"
         "\n"
         "^(.*=[ \t]*(class|record).*)$",
         /* -- */
         "[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"
+        "^[A-Z]+ \\{\n"        /* BEGIN, END, ... */
+        "^=head[0-9] ",        /* POD */
+        /* -- */
+        "[[:alpha:]_'][[:alnum:]_']*"
+        "|0[xb]?[0-9a-fA-F_]*"
+        /* taking care not to interpret 3..5 as (3.)(.5) */
+        "|[0-9a-fA-F_]+(\\.[0-9a-fA-F_]+)?([eE][-+]?[0-9_]+)?"
+        "|=>|-[rwxoRWXOezsfdlpSugkbctTBMAC>]|~~|::"
+        "|&&=|\\|\\|=|//=|\\*\\*="
+        "|&&|\\|\\||//|\\+\\+|--|\\*\\*|\\.\\.\\.?"
+        "|[-+*/%.^&<>=!|]="
+        "|=~|!~"
+        "|<<|<>|<=>|>>"),
 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"
@@ -96,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"
@@ -112,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
index e94d91d12966562e4cd43df9c34990dddc3465c3..e3d1fa35444dd693ab8723a030b9fc6265cad8bc 100644 (file)
@@ -131,7 +131,7 @@ static void repo_write_dirent(uint32_t *path, uint32_t mode,
                if (dent == key) {
                        dent->mode = REPO_MODE_DIR;
                        dent->content_offset = 0;
-                       dent_insert(&dir->entries, dent);
+                       dent = dent_insert(&dir->entries, dent);
                }
 
                if (dent_offset(dent) < dent_pool.committed) {
@@ -142,7 +142,7 @@ static void repo_write_dirent(uint32_t *path, uint32_t mode,
                        dent->name_offset = name;
                        dent->mode = REPO_MODE_DIR;
                        dent->content_offset = dir_o;
-                       dent_insert(&dir->entries, dent);
+                       dent = dent_insert(&dir->entries, dent);
                }
 
                dir = repo_dir_from_dirent(dent);
index 53d0215d2d8f38fee589321890c9305c8da4d2c5..2ad2c307dd6e8f4bddf5cbd9c588973a085bf870 100644 (file)
@@ -51,14 +51,14 @@ static struct {
 } rev_ctx;
 
 static struct {
-       uint32_t uuid, url;
+       uint32_t version, 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;
+               prop_content_length, content_length, svn_fs_dump_format_version;
 } keys;
 
 static void reset_node_ctx(char *fname)
@@ -85,6 +85,7 @@ static void reset_rev_ctx(uint32_t revision)
 static void reset_dump_ctx(uint32_t url)
 {
        dump_ctx.url = url;
+       dump_ctx.version = 1;
        dump_ctx.uuid = ~0;
 }
 
@@ -105,6 +106,7 @@ static void init_keys(void)
        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");
 }
 
 static void read_props(void)
@@ -206,7 +208,12 @@ void svndump_read(const char *url)
                *val++ = '\0';
                key = pool_intern(t);
 
-               if (key == keys.uuid) {
+               if (key == keys.svn_fs_dump_format_version) {
+                       dump_ctx.version = atoi(val);
+                       if (dump_ctx.version > 2)
+                               die("expected svn dump format version <= 2, found %"PRIu32,
+                                   dump_ctx.version);
+               } else if (key == keys.uuid) {
                        dump_ctx.uuid = pool_intern(val);
                } else if (key == keys.revision_number) {
                        if (active_ctx == NODE_CTX)
index ee35c688a0008ac210cdd28a82191c5a7cb7987e..c32b9184e9b8420e4d4e2904806bd2f14814132b 100644 (file)
@@ -188,11 +188,12 @@ a_attr uint32_t MAYBE_UNUSED a_pre##insert_recurse(uint32_t cur_node, uint32_t i
                return ret; \
        } \
 } \
-a_attr void MAYBE_UNUSED a_pre##insert(struct trp_root *treap, a_type *node) \
+a_attr a_type *MAYBE_UNUSED a_pre##insert(struct trp_root *treap, a_type *node) \
 { \
        uint32_t offset = trpn_offset(a_base, node); \
        trp_node_new(a_base, a_field, offset); \
        treap->trp_root = a_pre##insert_recurse(treap->trp_root, offset); \
+       return trpn_pointer(a_base, offset); \
 } \
 a_attr uint32_t MAYBE_UNUSED a_pre##remove_recurse(uint32_t cur_node, uint32_t rem_node) \
 { \
index eb4c191875f4580d18c1db1913cfe99f658a5f83..5ca6b42edb289c5f5714ae2f0a09710d40dd14f3 100644 (file)
@@ -21,7 +21,9 @@ The caller:
 
 . Allocates a `struct trp_root` variable and sets it to {~0}.
 
-. Adds new nodes to the set using `foo_insert`.
+. Adds new nodes to the set using `foo_insert`.  Any pointers
+  to existing nodes cannot be relied upon any more, so the caller
+  might retrieve them anew with `foo_pointer`.
 
 . Can find a specific item in the set using `foo_search`.
 
@@ -73,10 +75,14 @@ int (*cmp)(node_type \*a, node_type \*b)
 and returning a value less than, equal to, or greater than zero
 according to the result of comparison.
 
-void foo_insert(struct trp_root *treap, node_type \*node)::
+node_type {asterisk}foo_insert(struct trp_root *treap, node_type \*node)::
 
        Insert node into treap.  If inserted multiple times,
        a node will appear in the treap multiple times.
++
+The return value is the address of the node within the treap,
+which might differ from `node` if `pool_alloc` had to call
+`realloc` to expand the pool.
 
 void foo_remove(struct trp_root *treap, node_type \*node)::
 
index 11d9052ed86ab17b56ab86ef21b7c98095e410dc..dce7128daf8487a61e8d2f35cf15fca618964f86 100644 (file)
--- a/walker.c
+++ b/walker.c
@@ -207,7 +207,7 @@ static int mark_complete(const char *path, const unsigned char *sha1, int flag,
        struct commit *commit = lookup_commit_reference_gently(sha1, 1);
        if (commit) {
                commit->object.flags |= COMPLETE;
-               insert_by_date(commit, &complete);
+               commit_list_insert_by_date(commit, &complete);
        }
        return 0;
 }
index 4c1639f1536d259a2b64d574005ac973d042b273..4c147d6c48c000bab636fad3edc2fe7da6670948 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -12,6 +12,8 @@ static void (*try_to_free_routine)(size_t size) = do_nothing;
 try_to_free_t set_try_to_free_routine(try_to_free_t routine)
 {
        try_to_free_t old = try_to_free_routine;
+       if (!routine)
+               routine = do_nothing;
        try_to_free_routine = routine;
        return old;
 }
@@ -51,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;
@@ -196,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 = make_nonrelative_path(template);
+               errno = saved_errno;
+               die_errno("Unable to create temporary file '%s'",
+                       nonrelative_template);
+       }
        return fd;
 }
 
@@ -319,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 = make_nonrelative_path(template);
+               errno = saved_errno;
+               die_errno("Unable to create temporary file '%s'",
+                       nonrelative_template);
+       }
        return fd;
 }
 
index 06ae161c6707e893ab723812b268016a05b950fe..a82b11d341c9dddb541cc72a5568769d9f538780 100644 (file)
@@ -21,11 +21,15 @@ static char default_wt_status_colors[][COLOR_MAXLEN] = {
        GIT_COLOR_RED,    /* WT_STATUS_UNMERGED */
        GIT_COLOR_GREEN,  /* WT_STATUS_LOCAL_BRANCH */
        GIT_COLOR_RED,    /* WT_STATUS_REMOTE_BRANCH */
+       GIT_COLOR_NIL,    /* WT_STATUS_ONBRANCH */
 };
 
 static const char *color(int slot, struct wt_status *s)
 {
-       return s->use_color > 0 ? s->color_palette[slot] : "";
+       const char *c = s->use_color > 0 ? s->color_palette[slot] : "";
+       if (slot == WT_STATUS_ONBRANCH && color_is_nil(c))
+               c = s->color_palette[WT_STATUS_HEADER];
+       return c;
 }
 
 void wt_status_prepare(struct wt_status *s)
@@ -319,7 +323,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);
 }
 
@@ -344,20 +348,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;
@@ -372,6 +378,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)
@@ -625,7 +632,8 @@ static void wt_status_print_tracking(struct wt_status *s)
 
 void wt_status_print(struct wt_status *s)
 {
-       const char *branch_color = color(WT_STATUS_HEADER, s);
+       const char *branch_color = color(WT_STATUS_ONBRANCH, s);
+       const char *branch_status_color = color(WT_STATUS_HEADER, s);
 
        if (s->branch) {
                const char *on_what = "On branch ";
@@ -634,11 +642,12 @@ void wt_status_print(struct wt_status *s)
                        branch_name += 11;
                else if (!strcmp(branch_name, "HEAD")) {
                        branch_name = "";
-                       branch_color = color(WT_STATUS_NOBRANCH, 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_ln(s->fp, branch_color, "%s%s", on_what, branch_name);
+               color_fprintf(s->fp, branch_status_color, "%s", on_what);
+               color_fprintf_ln(s->fp, branch_color, "%s", branch_name);
                if (!s->is_initial)
                        wt_status_print_tracking(s);
        }
index 9df9c9fad2512d7c1d7d6456cdd645d641b5a089..20b17cf4393b8f9acce93320fb97998ad7cd609b 100644 (file)
@@ -13,7 +13,9 @@ enum color_wt_status {
        WT_STATUS_NOBRANCH,
        WT_STATUS_UNMERGED,
        WT_STATUS_LOCAL_BRANCH,
-       WT_STATUS_REMOTE_BRANCH
+       WT_STATUS_REMOTE_BRANCH,
+       WT_STATUS_ONBRANCH,
+       WT_STATUS_MAXSLOT
 };
 
 enum untracked_status_type {
@@ -46,7 +48,7 @@ struct wt_status {
        int show_ignored_files;
        enum untracked_status_type show_untracked_files;
        const char *ignore_submodule_arg;
-       char color_palette[WT_STATUS_REMOTE_BRANCH+1][COLOR_MAXLEN];
+       char color_palette[WT_STATUS_MAXSLOT][COLOR_MAXLEN];
 
        /* These are computed during processing of the individual sections */
        int commitable;
index e1e054e4d982de30d8a9c8c4109c6d62448f62a9..164581f87f49935f0d1b1885420960a4d11dea56 100644 (file)
@@ -212,8 +212,10 @@ int read_mmfile(mmfile_t *ptr, const char *filename)
                return error("Could not open %s", filename);
        sz = xsize_t(st.st_size);
        ptr->ptr = xmalloc(sz ? sz : 1);
-       if (sz && fread(ptr->ptr, sz, 1, f) != 1)
+       if (sz && fread(ptr->ptr, sz, 1, f) != 1) {
+               fclose(f);
                return error("Could not read %s", filename);
+       }
        fclose(f);
        ptr->size = sz;
        return 0;