Code

Merge branch 'tr/maint-git-repack-tmpfile'
authorJunio C Hamano <gitster@pobox.com>
Wed, 17 Nov 2010 23:01:23 +0000 (15:01 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 17 Nov 2010 23:01:23 +0000 (15:01 -0800)
* tr/maint-git-repack-tmpfile:
  repack: place temporary packs under .git/objects/pack/

242 files changed:
.mailmap
Documentation/CodingGuidelines
Documentation/RelNotes/1.7.3.1.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.3.2.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.4.txt [new file with mode: 0644]
Documentation/SubmittingPatches
Documentation/config.txt
Documentation/diff-generate-patch.txt
Documentation/diff-options.txt
Documentation/git-am.txt
Documentation/git-apply.txt
Documentation/git-archimport.txt
Documentation/git-archive.txt
Documentation/git-bundle.txt
Documentation/git-cat-file.txt
Documentation/git-check-ref-format.txt
Documentation/git-checkout-index.txt
Documentation/git-checkout.txt
Documentation/git-cherry-pick.txt
Documentation/git-clone.txt
Documentation/git-commit-tree.txt
Documentation/git-cvsexportcommit.txt
Documentation/git-cvsserver.txt
Documentation/git-daemon.txt
Documentation/git-diff.txt
Documentation/git-fast-export.txt
Documentation/git-fast-import.txt
Documentation/git-fetch.txt
Documentation/git-filter-branch.txt
Documentation/git-fmt-merge-msg.txt
Documentation/git-for-each-ref.txt
Documentation/git-format-patch.txt
Documentation/git-index-pack.txt
Documentation/git-init.txt
Documentation/git-log.txt
Documentation/git-ls-files.txt
Documentation/git-ls-tree.txt
Documentation/git-mailsplit.txt
Documentation/git-merge.txt
Documentation/git-mergetool.txt
Documentation/git-pack-objects.txt
Documentation/git-pull.txt
Documentation/git-push.txt
Documentation/git-read-tree.txt
Documentation/git-reflog.txt
Documentation/git-relink.txt
Documentation/git-remote.txt
Documentation/git-repack.txt
Documentation/git-reset.txt
Documentation/git-rev-list.txt
Documentation/git-rev-parse.txt
Documentation/git-revert.txt
Documentation/git-send-email.txt
Documentation/git-shell.txt
Documentation/git-shortlog.txt
Documentation/git-show-branch.txt
Documentation/git-show-ref.txt
Documentation/git-show.txt
Documentation/git-svn.txt
Documentation/git-update-index.txt
Documentation/git-web--browse.txt
Documentation/git.txt
Documentation/gitattributes.txt
Documentation/gitcore-tutorial.txt
Documentation/gitdiffcore.txt
Documentation/gitk.txt
Documentation/merge-config.txt
Documentation/merge-options.txt
Documentation/merge-strategies.txt
Documentation/pretty-options.txt
Documentation/rev-list-options.txt
Documentation/revisions.txt
Documentation/technical/api-merge.txt
Documentation/technical/api-sigchain.txt [new file with mode: 0644]
Documentation/user-manual.txt
GIT-VERSION-GEN
INSTALL
Makefile
RelNotes
abspath.c
archive.c
attr.c
builtin.h
builtin/apply.c
builtin/blame.c
builtin/bundle.c
builtin/cat-file.c
builtin/checkout-index.c
builtin/checkout.c
builtin/clean.c
builtin/commit-tree.c
builtin/fetch.c
builtin/fmt-merge-msg.c
builtin/grep.c
builtin/index-pack.c
builtin/init-db.c
builtin/log.c
builtin/ls-files.c
builtin/ls-tree.c
builtin/mailsplit.c
builtin/merge-file.c
builtin/merge-recursive.c
builtin/merge.c
builtin/pack-objects.c
builtin/read-tree.c
builtin/remote.c
builtin/rev-list.c
builtin/revert.c
builtin/send-pack.c
builtin/show-branch.c
builtin/unpack-objects.c
builtin/update-index.c
cache.h
compat/mingw.c
compat/mingw.h
configure.ac
connect.c
contrib/ciabot/ciabot.py
contrib/completion/git-completion.bash
contrib/emacs/git-blame.el
contrib/examples/git-svnimport.perl
contrib/fast-import/git-p4
contrib/fast-import/import-directories.perl
contrib/git-shell-commands/README [new file with mode: 0644]
contrib/git-shell-commands/help [new file with mode: 0755]
contrib/git-shell-commands/list [new file with mode: 0755]
contrib/hooks/post-receive-email
contrib/workdir/git-new-workdir
daemon.c
diff.c
diff.h
diffcore-pickaxe.c
diffcore.h
dir.c
environment.c
fast-import.c
git-add--interactive.perl
git-am.sh
git-archimport.perl
git-bisect.sh
git-compat-util.h
git-cvsexportcommit.perl
git-cvsimport.perl
git-cvsserver.perl
git-difftool.perl
git-gui/git-gui.sh
git-gui/lib/branch_rename.tcl
git-gui/lib/diff.tcl
git-merge-octopus.sh
git-mergetool--lib.sh
git-rebase.sh
git-relink.perl
git-repack.sh
git-send-email.perl
git-sh-setup.sh
git-stash.sh
git-submodule.sh
git-svn.perl
git.c
git_remote_helpers/setup.cfg [new file with mode: 0644]
gitweb/Makefile
gitweb/README
gitweb/gitweb.perl
grep.c
grep.h
ll-merge.c
ll-merge.h
merge-file.c
merge-recursive.c
merge-recursive.h
perl/Git.pm
rerere.c
send-pack.h
setup.c
sha1_name.c
shell.c
strbuf.c
strbuf.h
t/Makefile
t/README
t/annotate-tests.sh
t/gitweb-lib.sh
t/lib-terminal.sh [new file with mode: 0644]
t/t0003-attributes.sh
t/t0004-unwritable.sh
t/t1011-read-tree-sparse-checkout.sh
t/t1300-repo-config.sh
t/t1503-rev-parse-verify.sh
t/t1509-root-worktree.sh
t/t3020-ls-files-error-unmatch.sh
t/t3032-merge-recursive-options.sh [new file with mode: 0755]
t/t3402-rebase-merge.sh
t/t3415-rebase-autosquash.sh
t/t3419-rebase-patch-id.sh [new file with mode: 0755]
t/t3506-cherry-pick-ff.sh
t/t3903-stash.sh
t/t4011-diff-symlink.sh
t/t4012-diff-binary.sh
t/t4013-diff-various.sh
t/t4013/diff.log_-GF_-p_--pickaxe-all_master [new file with mode: 0644]
t/t4013/diff.log_-GF_-p_master [new file with mode: 0644]
t/t4013/diff.log_-GF_master [new file with mode: 0644]
t/t4014-format-patch.sh
t/t4018-diff-funcname.sh
t/t4041-diff-submodule-option.sh
t/t4103-apply-binary.sh
t/t5000-tar-tree.sh
t/t5503-tagfollow.sh
t/t5523-push-upstream.sh
t/t5560-http-backend-noserver.sh
t/t556x_common
t/t6006-rev-list-format.sh
t/t6023-merge-file.sh
t/t6038-merge-text-auto.sh
t/t6050-replace.sh
t/t6200-fmt-merge-msg.sh
t/t7004-tag.sh
t/t7006-pager.sh
t/t7006/test-terminal.perl [deleted file]
t/t7401-submodule-summary.sh
t/t7403-submodule-sync.sh
t/t7810-grep.sh
t/t8006-blame-textconv.sh
t/t8007-cat-file-textconv.sh
t/t9001-send-email.sh
t/t9100-git-svn-basic.sh
t/t9131-git-svn-empty-symlink.sh
t/t9157-git-svn-fetch-merge.sh [new file with mode: 0755]
t/t9300-fast-import.sh
t/t9500-gitweb-standalone-no-errors.sh
t/t9700/test.pl
t/test-lib.sh
t/test-terminal.perl [new file with mode: 0755]
transport.c
tree-diff.c
upload-pack.c
userdiff.c
wt-status.c
xdiff/xemit.c
xdiff/xmacros.h
xdiff/xmerge.c
xdiff/xutils.c

index a8091eb5dfa430bf1b0537da47a31e7cf88d8622..19c87262322cf5acc9d4fd5fa06f96eb3e988049 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -36,7 +36,7 @@ Lars Doelle <lars.doelle@on-line ! de>
 Lars Doelle <lars.doelle@on-line.de>
 Li Hong <leehong@pku.edu.cn>
 Lukas Sandström <lukass@etek.chalmers.se>
-Martin Langhoff <martin@catalyst.net.nz>
+Martin Langhoff <martin@laptop.org>
 Michael Coleman <tutufan@gmail.com>
 Michael J Gruber <git@drmicha.warpmail.net> <michaeljgruber+gmane@fastmail.fm>
 Michael W. Olson <mwolson@gnu.org>
index b8bf618a30fd32a014e41e1ba9914f5e652bdefd..09ffc46563cba1057b37ba4a5701858fb95c5dda 100644 (file)
@@ -35,21 +35,28 @@ For shell scripts specifically (not exhaustive):
    properly nests.  It should have been the way Bourne spelled
    it from day one, but unfortunately isn't.
 
- - We use ${parameter-word} and its [-=?+] siblings, and their
-   colon'ed "unset or null" form.
+ - We use POSIX compliant parameter substitutions and avoid bashisms;
+   namely:
 
- We use ${parameter#word} and its [#%] siblings, and their
-   doubled "longest matching" form.
  - We use ${parameter-word} and its [-=?+] siblings, and their
+     colon'ed "unset or null" form.
 
- - We use Arithmetic Expansion $(( ... )).
+   - We use ${parameter#word} and its [#%] siblings, and their
+     doubled "longest matching" form.
+
+   - No "Substring Expansion" ${parameter:offset:length}.
 
- No "Substring Expansion" ${parameter:offset:length}.
  - No shell arrays.
 
- No shell arrays.
  - No strlen ${#parameter}.
 
- - No strlen ${#parameter}.
+   - No pattern replacement ${parameter/pattern/string}.
+
+ - We use Arithmetic Expansion $(( ... )).
 
- - No regexp ${parameter/pattern/string}.
+ - Inside Arithmetic Expansion, spell shell variables with $ in front
+   of them, as some shells do not grok $((x)) while accepting $(($x))
+   just fine (e.g. dash older than 0.5.4).
 
  - We do not use Process Substitution <(list) or >(list).
 
diff --git a/Documentation/RelNotes/1.7.3.1.txt b/Documentation/RelNotes/1.7.3.1.txt
new file mode 100644 (file)
index 0000000..002c93b
--- /dev/null
@@ -0,0 +1,14 @@
+Git v1.7.3.1 Release Notes
+==========================
+
+Fixes since v1.7.3
+------------------
+
+ * "git stash show stash@{$n}" was accidentally broken in 1.7.3 ("git
+   stash show" without any argument still worked, though).
+
+ * "git stash branch $branch stash@{$n}" was accidentally broken in
+   1.7.3 and started dropping the named stash even when branch creation
+   failed.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.3.2.txt b/Documentation/RelNotes/1.7.3.2.txt
new file mode 100644 (file)
index 0000000..5c93b85
--- /dev/null
@@ -0,0 +1,5 @@
+Git v1.7.3.2 Release Notes
+==========================
+
+This is primarily to push out many documentation fixes accumulated since
+the 1.7.3.1 release.
diff --git a/Documentation/RelNotes/1.7.4.txt b/Documentation/RelNotes/1.7.4.txt
new file mode 100644 (file)
index 0000000..05e8a43
--- /dev/null
@@ -0,0 +1,54 @@
+Git v1.7.4 Release Notes (draft)
+================================
+
+Updates since v1.7.3
+--------------------
+
+ * The option parsers of various commands that create new branch (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.
+
+ * System-wide fallback default attributes can be stored in
+   /etc/gitattributes; core.attributesfile configuration variable can
+   be used to customize the path to this file.
+
+ * "git diff" and "git grep" learned how functions and subroutines
+   in Fortran look like.
+
+ * "git log -G<pattern>" limits the output to commits whose change has
+   added or deleted lines that match the given pattern.
+
+ * "git read-tree" with no argument as a way to empty the index is
+   deprecated; we might want to remove it in the future.  Users can
+   use the new --empty option to be more explicit instead.
+
+ * "git merge --log" used to limit the resulting merge log to 20
+   entries; this is now customizable by giving e.g. "--log=47".
+
+ * 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
+   commands.
+
+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
+release, unless otherwise noted.
+
+ * "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.
+
+
+---
+exec >/var/tmp/1
+O=v1.7.3
+O=v1.7.3.1-42-g34289ec
+echo O=$(git describe master)
+git shortlog --no-merges ^maint ^$O master
index ece3c77482b3ff006b973f1ed90b708e26556862..72741ebda12de8fbf786f12531d70ab465eecf42 100644 (file)
@@ -264,12 +264,21 @@ the change to its true author (see (2) above).
 Also notice that a real name is used in the Signed-off-by: line. Please
 don't hide your real name.
 
-Some people also put extra tags at the end.
-
-"Acked-by:" says that the patch was reviewed by the person who
-is more familiar with the issues and the area the patch attempts
-to modify.  "Tested-by:" says the patch was tested by the person
-and found to have the desired effect.
+If you like, you can put extra tags at the end:
+
+1. "Reported-by:" is used to to credit someone who found the bug that
+   the patch attempts to fix.
+2. "Acked-by:" says that the person who is more familiar with the area
+   the patch attempts to modify liked the patch.
+3. "Reviewed-by:", unlike the other tags, can only be offered by the
+   reviewer and means that she is completely satisfied that the patch
+   is ready for application.  It is usually offered only after a
+   detailed review.
+4. "Tested-by:" is used to indicate that the person applied the patch
+   and found it to have the desired effect.
+
+You can also create your own tag or use one that's in common usage
+such as "Thanks-to:", "Based-on-patch-by:", or "Mentored-by:".
 
 ------------------------------------------------
 An ideal patch flow
index d82c0da2cf470dbfe7936762d4645b7509647177..538ebb5e2ecc58f1ddcb7adb44ded3b027555ec2 100644 (file)
@@ -459,6 +459,12 @@ core.askpass::
        prompt. The external program shall be given a suitable prompt as
        command line argument and write the password on its STDOUT.
 
+core.attributesfile::
+       In addition to '.gitattributes' (per-directory) and
+       '.git/info/attributes', git looks into this file for attributes
+       (see linkgit:gitattributes[5]). Path expansions are made the same
+       way as for `core.excludesfile`.
+
 core.editor::
        Commands such as `commit` and `tag` that lets you edit
        messages by launching an editor uses the value of this
@@ -1466,6 +1472,10 @@ pack.compression::
        not set,  defaults to -1, the zlib default, which is "a default
        compromise between speed and compression (currently equivalent
        to level 6)."
++
+Note that changing the compression level will not automatically recompress
+all existing objects. You can force recompression by passing the -F option
+to linkgit:git-repack[1].
 
 pack.deltaCacheSize::
        The maximum memory in bytes used for caching deltas in
@@ -1550,12 +1560,12 @@ push.default::
        no refspec is implied by any of the options given on the command
        line. Possible values are:
 +
-* `nothing` do not push anything.
-* `matching` push all matching branches.
+* `nothing` do not push anything.
+* `matching` push all matching branches.
   All branches having the same name in both ends are considered to be
   matching. This is the default.
-* `tracking` push the current branch to its upstream branch.
-* `current` push the current branch to a branch of the same name.
+* `tracking` push the current branch to its upstream branch.
+* `current` push the current branch to a branch of the same name.
 
 rebase.stat::
        Whether to show a diffstat of what changed upstream since the last
@@ -1727,6 +1737,7 @@ sendemail.to::
 sendemail.smtpdomain::
 sendemail.smtpserver::
 sendemail.smtpserverport::
+sendemail.smtpserveroption::
 sendemail.smtpuser::
 sendemail.thread::
 sendemail.validate::
@@ -1755,9 +1766,9 @@ status.showUntrackedFiles::
        the untracked files. Possible values are:
 +
 --
-       - 'no'     - Show no untracked files
-       - 'normal' - Shows untracked files and directories
-       - 'all'    - Shows also individual files in untracked directories.
+* `no` - Show no untracked files.
+* `normal` - Show untracked files and directories.
+* `all` - Show also individual files in untracked directories.
 --
 +
 If this variable is not specified, it defaults to 'normal'.
index 8f9a2412fd44c80f2bf8d63271e2897ebeb3ddeb..3ac2beac6229955dc2534c428238c3d5ff57d25d 100644 (file)
@@ -9,16 +9,15 @@ patch file.  You can customize the creation of such patches via the
 GIT_EXTERNAL_DIFF and the GIT_DIFF_OPTS environment variables.
 
 What the -p option produces is slightly different from the traditional
-diff format.
+diff format:
 
-1.   It is preceded with a "git diff" header, that looks like
-     this:
+1.   It is preceded with a "git diff" header that looks like this:
 
        diff --git a/file1 b/file2
 +
 The `a/` and `b/` filenames are the same unless rename/copy is
 involved.  Especially, even for a creation or a deletion,
-`/dev/null` is _not_ used in place of `a/` or `b/` filenames.
+`/dev/null` is _not_ used in place of the `a/` or `b/` filenames.
 +
 When rename/copy is involved, `file1` and `file2` show the
 name of the source file of the rename/copy and the name of
@@ -37,18 +36,39 @@ the file that rename/copy produces, respectively.
        similarity index <number>
        dissimilarity index <number>
        index <hash>..<hash> <mode>
-
-3.  TAB, LF, double quote and backslash characters in pathnames
-    are represented as `\t`, `\n`, `\"` and `\\`, respectively.
-    If there is need for such substitution then the whole
-    pathname is put in double quotes.
-
++
+File modes are printed as 6-digit octal numbers including the file type
+and file permission bits.
++
+Path names in extended headers do not include the `a/` and `b/` prefixes.
++
 The similarity index is the percentage of unchanged lines, and
 the dissimilarity index is the percentage of changed lines.  It
 is a rounded down integer, followed by a percent sign.  The
 similarity index value of 100% is thus reserved for two equal
 files, while 100% dissimilarity means that no line from the old
 file made it into the new one.
++
+The index line includes the SHA-1 checksum before and after the change.
+The <mode> is included if the file mode does not change; otherwise,
+separate lines indicate the old and the new mode.
+
+3.  TAB, LF, double quote and backslash characters in pathnames
+    are represented as `\t`, `\n`, `\"` and `\\`, respectively.
+    If there is need for such substitution then the whole
+    pathname is put in double quotes.
+
+4.  All the `file1` files in the output refer to files before the
+    commit, and all the `file2` files refer to files after the commit.
+    It is incorrect to apply each change to each file sequentially.  For
+    example, this patch will swap a and b:
+
+      diff --git a/a b/b
+      rename from a
+      rename to b
+      diff --git a/b b/a
+      rename from b
+      rename to a
 
 
 combined diff format
index 4656a97e6012796f182a725e14c13dc03f71bba2..f3e95389aa5914cc05145625a5dd48bafbf086ba 100644 (file)
@@ -48,9 +48,9 @@ endif::git-format-patch[]
 --patience::
        Generate a diff using the "patience diff" algorithm.
 
---stat[=width[,name-width]]::
+--stat[=<width>[,<name-width>]]::
        Generate a diffstat.  You can override the default
-       output width for 80-column terminal by `--stat=width`.
+       output width for 80-column terminal by `--stat=<width>`.
        The width of the filename part can be controlled by
        giving another width to it separated by a comma.
 
@@ -66,14 +66,14 @@ endif::git-format-patch[]
        number of modified files, as well as number of added and deleted
        lines.
 
---dirstat[=limit]::
+--dirstat[=<limit>]::
        Output the distribution of relative amount of changes (number of lines added or
        removed) for each sub-directory. Directories with changes below
        a cut-off percent (3% by default) are not shown. The cut-off percent
-       can be set with `--dirstat=limit`. Changes in a child directory is not
+       can be set with `--dirstat=<limit>`. Changes in a child directory are not
        counted for the parent directory, unless `--cumulative` is used.
 
---dirstat-by-file[=limit]::
+--dirstat-by-file[=<limit>]::
        Same as `--dirstat`, but counts changed files instead of lines.
 
 --summary::
@@ -207,6 +207,7 @@ endif::git-format-patch[]
        digits can be specified with `--abbrev=<n>`.
 
 -B[<n>][/<m>]::
+--break-rewrites[=[<n>][/<m>]]::
        Break complete rewrite changes into pairs of delete and
        create. This serves two purposes:
 +
@@ -229,6 +230,7 @@ eligible for being picked up as a possible source of a rename to
 another file.
 
 -M[<n>]::
+--detect-renames[=<n>]::
 ifndef::git-log[]
        Detect renames.
 endif::git-log[]
@@ -244,23 +246,10 @@ endif::git-log[]
        hasn't changed.
 
 -C[<n>]::
+--detect-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>`.
 
-ifndef::git-format-patch[]
---diff-filter=[ACDMRTUXB*]::
-       Select only files that are Added (`A`), Copied (`C`),
-       Deleted (`D`), Modified (`M`), Renamed (`R`), have their
-       type (i.e. regular file, symlink, submodule, ...) changed (`T`),
-       are Unmerged (`U`), are
-       Unknown (`X`), or have had their pairing Broken (`B`).
-       Any combination of the filter characters may be used.
-       When `*` (All-or-none) is added to the combination, all
-       paths are selected if there is any file that matches
-       other criteria in the comparison; if there is no file
-       that matches other criteria, nothing is selected.
-endif::git-format-patch[]
-
 --find-copies-harder::
        For performance reasons, by default, `-C` option finds copies only
        if the original file of the copy was modified in the same
@@ -278,14 +267,30 @@ endif::git-format-patch[]
        number.
 
 ifndef::git-format-patch[]
+--diff-filter=[(A|C|D|M|R|T|U|X|B)...[*]]::
+       Select only files that are Added (`A`), Copied (`C`),
+       Deleted (`D`), Modified (`M`), Renamed (`R`), have their
+       type (i.e. regular file, symlink, submodule, ...) changed (`T`),
+       are Unmerged (`U`), are
+       Unknown (`X`), or have had their pairing Broken (`B`).
+       Any combination of the filter characters (including none) can be used.
+       When `*` (All-or-none) is added to the combination, all
+       paths are selected if there is any file that matches
+       other criteria in the comparison; if there is no file
+       that matches other criteria, nothing is selected.
+
 -S<string>::
        Look for differences that introduce or remove an instance of
        <string>. Note that this is different than the string simply
        appearing in diff output; see the 'pickaxe' entry in
        linkgit:gitdiffcore[7] for more details.
 
+-G<regex>::
+       Look for differences whose added or removed line matches
+       the given <regex>.
+
 --pickaxe-all::
-       When `-S` finds a change, show all the changes in that
+       When `-S` or `-G` finds a change, show all the changes in that
        changeset, not just the files that contain the change
        in <string>.
 
index 9e62f8778f6590328de4d9c0c7c08044e8019eac..51297d09ecdd3468ecd87a4f7aa6fac2b8ef6224 100644 (file)
@@ -14,7 +14,7 @@ SYNOPSIS
         [--ignore-date] [--ignore-space-change | --ignore-whitespace]
         [--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>]
         [--reject] [-q | --quiet] [--scissors | --no-scissors]
-        [<mbox> | <Maildir>...]
+        [(<mbox> | <Maildir>)...]
 'git am' (--continue | --skip | --abort)
 
 DESCRIPTION
@@ -25,7 +25,7 @@ current branch.
 
 OPTIONS
 -------
-<mbox>|<Maildir>...::
+(<mbox>|<Maildir>)...::
        The list of mailbox files to read patches from. If you do not
        supply this argument, the command reads from the standard input.
        If you supply directories, they will be treated as Maildirs.
index 4a74b23d403d970643fcb8e0438ab6649f54e54c..881652f4904c102104cfe0a0b1de07dbfc32da3f 100644 (file)
@@ -12,10 +12,10 @@ SYNOPSIS
 'git apply' [--stat] [--numstat] [--summary] [--check] [--index]
          [--apply] [--no-add] [--build-fake-ancestor=<file>] [-R | --reverse]
          [--allow-binary-replacement | --binary] [--reject] [-z]
-         [-pNUM] [-CNUM] [--inaccurate-eof] [--recount] [--cached]
+         [-p<n>] [-C<n>] [--inaccurate-eof] [--recount] [--cached]
          [--ignore-space-change | --ignore-whitespace ]
-         [--whitespace=<nowarn|warn|fix|error|error-all>]
-         [--exclude=PATH] [--include=PATH] [--directory=<root>]
+         [--whitespace=(nowarn|warn|fix|error|error-all)]
+         [--exclude=<path>] [--include=<path>] [--directory=<root>]
          [--verbose] [<patch>...]
 
 DESCRIPTION
index 4f358c8d6c3320c5ef0a78d6c4d155535433f3d0..2411ce5bfe05a14ed45c1546c3d1a6d92b39d8eb 100644 (file)
@@ -109,7 +109,7 @@ OPTIONS
 
 Author
 ------
-Written by Martin Langhoff <martin@catalyst.net.nz>.
+Written by Martin Langhoff <martin@laptop.org>.
 
 Documentation
 --------------
index 8d3e66626f7561b0ba7f8140288cfc15167bdc14..4163a1bcb1643e7f05b6a79034ac9f63135d6ac9 100644 (file)
@@ -12,7 +12,7 @@ SYNOPSIS
 'git archive' [--format=<fmt>] [--list] [--prefix=<prefix>/] [<extra>]
              [-o | --output=<file>] [--worktree-attributes]
              [--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish>
-             [path...]
+             [<path>...]
 
 DESCRIPTION
 -----------
@@ -73,7 +73,7 @@ OPTIONS
 <tree-ish>::
        The tree or commit to produce an archive for.
 
-path::
+<path>::
        Without an optional path parameter, all files and subdirectories
        of the current working directory are included in the archive.
        If one or more paths are specified, only these are included.
index 38e59afb34effd84da6d8a79da67e5ad3ae45c5a..6266a3a6020db72c8629ad521dfedccc9d790a03 100644 (file)
@@ -11,8 +11,8 @@ SYNOPSIS
 [verse]
 'git bundle' create <file> <git-rev-list-args>
 'git bundle' verify <file>
-'git bundle' list-heads <file> [refname...]
-'git bundle' unbundle <file> [refname...]
+'git bundle' list-heads <file> [<refname>...]
+'git bundle' unbundle <file> [<refname>...]
 
 DESCRIPTION
 -----------
@@ -68,7 +68,7 @@ unbundle <file>::
        packaged.
 
 
-[refname...]::
+[<refname>...]::
        A list of references used to limit the references reported as
        available. This is principally of use to 'git fetch', which
        expects to receive only those references asked for and not
index a3f56b07fd251cbd121c28189d1f9018b892b48e..544ba7ba218550ac1b09d9c95dc6f60ac604f7e8 100644 (file)
@@ -27,7 +27,7 @@ OPTIONS
 <object>::
        The name of the object to show.
        For a more complete list of ways to spell object names, see
-       the "SPECIFYING REVISIONS" section in linkgit:gitrevisions[1].
+       the "SPECIFYING REVISIONS" section in linkgit:gitrevisions[7].
 
 -t::
        Instead of the content, show the object type identified by
index f5c2e0601db6782b2a8690c687611b93da935024..205d83dd0b281d59e0f53284d29846c8eb58a246 100644 (file)
@@ -49,7 +49,7 @@ git imposes the following rules on how references are named:
 These rules make it easy for shell script based tools to parse
 reference names, pathname expansion by the shell when a reference name is used
 unquoted (by mistake), and also avoids ambiguities in certain
-reference name expressions (see linkgit:gitrevisions[1]):
+reference name expressions (see linkgit:gitrevisions[7]):
 
 . A double-dot `..` is often used as in `ref1..ref2`, and in some
   contexts this notation means `{caret}ref1 ref2` (i.e. not in
index 62f9ab24c97875df6f053aa11f8f5cde56377175..0c0a9c14bc8e78ada9fb9b7174fcb90698e497a0 100644 (file)
@@ -13,7 +13,7 @@ SYNOPSIS
                   [--stage=<number>|all]
                   [--temp]
                   [-z] [--stdin]
-                  [--] [<file>]*
+                  [--] [<file>...]
 
 DESCRIPTION
 -----------
index f88e9977d1137da0449736f5f8fe6746b42437e1..22d36114df68963811a80a6c311a98b1a26d88d3 100644 (file)
@@ -45,14 +45,14 @@ successful.
 
 'git checkout' [--patch] [<tree-ish>] [--] <pathspec>...::
 
-       When <paths> or `--patch` are given, 'git checkout' *not* switch
-       branches.  It updates the named paths in the working tree from
-       the index file or from a named <tree-ish> (most often a commit).  In
-       this case, the `-b` and `--track` options are meaningless and giving
-       either of them results in an error. The <tree-ish> argument can be
-       used to specify a specific tree-ish (i.e. commit, tag or tree)
-       to update the index for the given paths before updating the
-       working tree.
+       When <paths> or `--patch` are given, 'git checkout' does *not*
+       switch branches.  It updates the named paths in the working tree
+       from the index file or from a named <tree-ish> (most often a
+       commit).  In this case, the `-b` and `--track` options are
+       meaningless and giving either of them results in an error.  The
+       <tree-ish> argument can be used to specify a specific tree-ish
+       (i.e.  commit, tag or tree) to update the index for the given
+       paths before updating the working tree.
 +
 The index may contain unmerged entries because of a previous failed merge.
 By default, if you try to check out such an entry from the index, the
index 2cef579316ba11e68d65dc4d7309f2e56a465b3d..3c96fa8c86c34df2dced6cd9ec8a391ee3b7208e 100644 (file)
@@ -21,7 +21,7 @@ OPTIONS
 <commit>...::
        Commits to cherry-pick.
        For a more complete list of ways to spell commits, see
-       linkgit:gitrevisions[1].
+       linkgit:gitrevisions[7].
        Sets of commits can be passed but no traversal is done by
        default, as if the '--no-walk' option was specified, see
        linkgit:git-rev-list[1].
index dc7d3d17b151d05827925fdcd2806945e2e278cb..ab7293351d283e7ee3a8275c534c3667d6b4d696 100644 (file)
@@ -128,7 +128,12 @@ objects from the source repository into a pack in the cloned repository.
        configuration variables are created.
 
 --mirror::
-       Set up a mirror of the remote repository.  This implies `--bare`.
+       Set up a mirror of the source repository.  This implies `--bare`.
+       Compared to `--bare`, `--mirror` not only maps local branches of the
+       source to local branches of the target, it maps all refs (including
+       remote branches, notes etc.) and sets up a refspec configuration such
+       that all these refs are overwritten by a `git remote update` in the
+       target repository.
 
 --origin <name>::
 -o <name>::
index 349366ee1e2c414aed87745d2c717ea9a2149367..5dcf4278fc497e4d72093069bdcd18b4ecff0949 100644 (file)
@@ -8,7 +8,7 @@ git-commit-tree - Create a new commit object
 
 SYNOPSIS
 --------
-'git commit-tree' <tree> [-p <parent commit>]* < changelog
+'git commit-tree' <tree> [(-p <parent commit>)...] < changelog
 
 DESCRIPTION
 -----------
index b2696efae95b20b693251a9d9785405218285084..d25661eb215c8bd2002933a48dd6ad5ea360459a 100644 (file)
@@ -114,11 +114,11 @@ $ git cherry cvshead myhead | sed -n 's/^+ //p' | xargs -l1 git cvsexportcommit
 
 Author
 ------
-Written by Martin Langhoff <martin@catalyst.net.nz> and others.
+Written by Martin Langhoff <martin@laptop.org> and others.
 
 Documentation
 --------------
-Documentation by Martin Langhoff <martin@catalyst.net.nz> and others.
+Documentation by Martin Langhoff <martin@laptop.org> and others.
 
 GIT
 ---
index f4472c61dbb297d61053ef2e8503ad7c56d06148..70cbb2cae7b60a5c6514d0990da91ed5b23e0827 100644 (file)
@@ -399,13 +399,13 @@ This program is copyright The Open University UK - 2006.
 Authors:
 
 - Martyn Smith    <martyn@catalyst.net.nz>
-- Martin Langhoff <martin@catalyst.net.nz>
+- Martin Langhoff <martin@laptop.org>
 
 with ideas and patches from participants of the git-list <git@vger.kernel.org>.
 
 Documentation
 --------------
-Documentation by Martyn Smith <martyn@catalyst.net.nz>, Martin Langhoff <martin@catalyst.net.nz>, and Matthias Urlichs <smurf@smurf.noris.de>.
+Documentation by Martyn Smith <martyn@catalyst.net.nz>, Martin Langhoff <martin@laptop.org>, and Matthias Urlichs <smurf@smurf.noris.de>.
 
 GIT
 ---
index 01c9f8eb9eff634fe8ab99908c62207ebecd5e31..5054f790a140b43640d1e4d68a032d95da3daaca 100644 (file)
@@ -9,15 +9,15 @@ SYNOPSIS
 --------
 [verse]
 'git daemon' [--verbose] [--syslog] [--export-all]
-            [--timeout=n] [--init-timeout=n] [--max-connections=n]
-            [--strict-paths] [--base-path=path] [--base-path-relaxed]
-            [--user-path | --user-path=path]
-            [--interpolated-path=pathtemplate]
-            [--reuseaddr] [--detach] [--pid-file=file]
-            [--enable=service] [--disable=service]
-            [--allow-override=service] [--forbid-override=service]
-            [--inetd | [--listen=host_or_ipaddr] [--port=n] [--user=user [--group=group]]
-            [directory...]
+            [--timeout=<n>] [--init-timeout=<n>] [--max-connections=<n>]
+            [--strict-paths] [--base-path=<path>] [--base-path-relaxed]
+            [--user-path | --user-path=<path>]
+            [--interpolated-path=<pathtemplate>]
+            [--reuseaddr] [--detach] [--pid-file=<file>]
+            [--enable=<service>] [--disable=<service>]
+            [--allow-override=<service>] [--forbid-override=<service>]
+            [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>] [--user=<user> [--group=<group>]]
+            [<directory>...]
 
 DESCRIPTION
 -----------
@@ -48,7 +48,7 @@ OPTIONS
        'git daemon' will refuse to start when this option is enabled and no
        whitelist is specified.
 
---base-path=path::
+--base-path=<path>::
        Remap all the path requests as relative to the given path.
        This is sort of "GIT root" - if you run 'git daemon' with
        '--base-path=/srv/git' on example.com, then if you later try to pull
@@ -61,7 +61,7 @@ OPTIONS
        This is useful for switching to --base-path usage, while still
        allowing the old paths.
 
---interpolated-path=pathtemplate::
+--interpolated-path=<pathtemplate>::
        To support virtual hosting, an interpolated path template can be
        used to dynamically construct alternate paths.  The template
        supports %H for the target hostname as supplied by the client but
@@ -80,27 +80,28 @@ OPTIONS
        Have the server run as an inetd service. Implies --syslog.
        Incompatible with --port, --listen, --user and --group options.
 
---listen=host_or_ipaddr::
+--listen=<host_or_ipaddr>::
        Listen on a specific IP address or hostname.  IP addresses can
        be either an IPv4 address or an IPv6 address if supported.  If IPv6
        is not supported, then --listen=hostname is also not supported and
        --listen must be given an IPv4 address.
+       Can be given more than once.
        Incompatible with '--inetd' option.
 
---port=n::
+--port=<n>::
        Listen on an alternative port.  Incompatible with '--inetd' option.
 
---init-timeout=n::
+--init-timeout=<n>::
        Timeout between the moment the connection is established and the
        client request is received (typically a rather low value, since
        that should be basically immediate).
 
---timeout=n::
+--timeout=<n>::
        Timeout for specific client sub-requests. This includes the time
        it takes for the server to process the sub-request and the time spent
        waiting for the next client's request.
 
---max-connections=n::
+--max-connections=<n>::
        Maximum number of concurrent clients, defaults to 32.  Set it to
        zero for no limit.
 
@@ -109,7 +110,7 @@ OPTIONS
        --verbose, thus by default only error conditions will be logged.
 
 --user-path::
---user-path=path::
+--user-path=<path>::
        Allow {tilde}user notation to be used in requests.  When
        specified with no parameter, requests to
        git://host/{tilde}alice/foo is taken as a request to access
@@ -129,12 +130,12 @@ OPTIONS
 --detach::
        Detach from the shell. Implies --syslog.
 
---pid-file=file::
+--pid-file=<file>::
        Save the process id in 'file'.  Ignored when the daemon
        is run under `--inetd`.
 
---user=user::
---group=group::
+--user=<user>::
+--group=<group>::
        Change daemon's uid and gid before entering the service loop.
        When only `--user` is given without `--group`, the
        primary group ID for the user is used.  The values of
@@ -145,16 +146,16 @@ Giving these options is an error when used with `--inetd`; use
 the facility of inet daemon to achieve the same before spawning
 'git daemon' if needed.
 
---enable=service::
---disable=service::
+--enable=<service>::
+--disable=<service>::
        Enable/disable the service site-wide per default.  Note
        that a service disabled site-wide can still be enabled
        per repository if it is marked overridable and the
        repository enables the service with a configuration
        item.
 
---allow-override=service::
---forbid-override=service::
+--allow-override=<service>::
+--forbid-override=<service>::
        Allow/forbid overriding the site-wide default with per
        repository configuration.  By default, all the services
        are overridable.
index 08fd4099addac3959e5aedbd1a0668367f07bb21..dd1fb32786f6f467a1c46f2643fbc54d0390f2ec 100644 (file)
@@ -23,9 +23,9 @@ tree and the index file, or the index file and the working tree.
        further add to the index but you still haven't.  You can
        stage these changes by using linkgit:git-add[1].
 +
-If exactly two paths are given, and at least one is untracked,
-compare the two files / directories. This behavior can be
-forced by --no-index.
+If exactly two paths are given and at least one points outside
+the current repository, 'git diff' will compare the two files /
+directories. This behavior can be forced by --no-index.
 
 'git diff' [--options] --cached [<commit>] [--] [<path>...]::
 
@@ -64,15 +64,16 @@ forced by --no-index.
 
 Just in case if you are doing something exotic, it should be
 noted that all of the <commit> in the above description, except
-for the last two forms that use ".." notations, can be any
-<tree-ish>.
+in the last two forms that use ".." notations, can be any
+<tree>.  The third form ('git diff <commit> <commit>') can also
+be used to compare two <blob> objects.
 
 For a more complete list of ways to spell <commit>, see
-"SPECIFYING REVISIONS" section in linkgit:gitrevisions[1].
+"SPECIFYING REVISIONS" section in linkgit:gitrevisions[7].
 However, "diff" is about comparing two _endpoints_, not ranges,
 and the range notations ("<commit>..<commit>" and
 "<commit>\...<commit>") do not mean a range as defined in the
-"SPECIFYING RANGES" section in linkgit:gitrevisions[1].
+"SPECIFYING RANGES" section in linkgit:gitrevisions[7].
 
 OPTIONS
 -------
@@ -159,8 +160,12 @@ rewrites (very expensive).
 
 SEE ALSO
 --------
-linkgit:git-difftool[1]::
-       Show changes using common diff tools
+diff(1),
+linkgit:git-difftool[1],
+linkgit:git-log[1],
+linkgit:gitdiffcore[7],
+linkgit:git-format-patch[1],
+linkgit:git-apply[1]
 
 Author
 ------
index fcad1132767021a03a88cf084d5eaf4ae8780792..e05b686b1e4784290e40993469a2c5fab9b4ce5d 100644 (file)
@@ -96,7 +96,7 @@ marks the same across runs.
        in the commit (as opposed to just listing the files which are
        different from the commit's first parent).
 
-[git-rev-list-args...]::
+[<git-rev-list-args>...]::
        A list of arguments, acceptable to 'git rev-parse' and
        'git rev-list', that specifies the specific objects and references
        to export.  For example, `master{tilde}10..master` causes the
index 966ba4f21337e72f7be0a5b852e76a8b12192f7f..5d0c245e38ff751d8c40a6eb6d5b17b80930d526 100644 (file)
@@ -439,7 +439,7 @@ Marks must be declared (via `mark`) before they can be used.
 * A complete 40 byte or abbreviated commit SHA-1 in hex.
 
 * Any valid Git SHA-1 expression that resolves to a commit.  See
-  ``SPECIFYING REVISIONS'' in linkgit:gitrevisions[1] for details.
+  ``SPECIFYING REVISIONS'' in linkgit:gitrevisions[7] for details.
 
 The special case of restarting an incremental import from the
 current branch value should be written as:
@@ -524,6 +524,9 @@ 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),
index 400fe7f956961ba0ddf09d2dcc6e539adec7ff74..d159e88292cbab575be8153b381fffd1f4c85b6b 100644 (file)
@@ -12,7 +12,7 @@ SYNOPSIS
 
 'git fetch' [<options>] <group>
 
-'git fetch' --multiple [<options>] [<repository> | <group>]...
+'git fetch' --multiple [<options>] [(<repository> | <group>)...]
 
 'git fetch' --all [<options>]
 
index 7357c8879a941537fa6aee084b572e8aacced89d..796e7489ff7ee573a65647f4de33df932bd1bea1 100644 (file)
@@ -81,7 +81,7 @@ OPTIONS
        This filter may be used if you only need to modify the environment
        in which the commit will be performed.  Specifically, you might
        want to rewrite the author/committer name/email/time environment
-       variables (see linkgit:git-commit[1] for details).  Do not forget
+       variables (see linkgit:git-commit-tree[1] for details).  Do not forget
        to re-export the variables.
 
 --tree-filter <command>::
@@ -117,7 +117,7 @@ OPTIONS
        This is the filter for performing the commit.
        If this filter is specified, it will be called instead of the
        'git commit-tree' command, with arguments of the form
-       "<TREE_ID> [-p <PARENT_COMMIT_ID>]..." and the log message on
+       "<TREE_ID> [(-p <PARENT_COMMIT_ID>)...]" and the log message on
        stdin.  The commit id is expected on stdout.
 +
 As a special extension, the commit filter may emit multiple
index 302f56b88941cfaa002a8b75c078335bf8d86276..40dba8c0a9f308064f67d8f38ce8a22b2a42a77c 100644 (file)
@@ -9,8 +9,8 @@ git-fmt-merge-msg - Produce a merge commit message
 SYNOPSIS
 --------
 [verse]
-'git fmt-merge-msg' [-m <message>] [--log | --no-log] <$GIT_DIR/FETCH_HEAD
-'git fmt-merge-msg' [-m <message>] [--log | --no-log] -F <file>
+'git fmt-merge-msg' [-m <message>] [--log[=<n>] | --no-log] <$GIT_DIR/FETCH_HEAD
+'git fmt-merge-msg' [-m <message>] [--log[=<n>] | --no-log] -F <file>
 
 DESCRIPTION
 -----------
@@ -24,10 +24,12 @@ automatically invoking 'git merge'.
 OPTIONS
 -------
 
---log::
+--log[=<n>]::
        In addition to branch names, populate the log message with
        one-line descriptions from the actual commits that are being
-       merged.
+       merged.  At most <n> commits from each merge parent will be
+       used (20 if <n> is omitted).  This overrides the `merge.log`
+       configuration variable.
 
 --no-log::
        Do not list one-line descriptions from the actual commits being
@@ -52,8 +54,10 @@ CONFIGURATION
 -------------
 
 merge.log::
-       Whether to include summaries of merged commits in newly
-       merge commit messages. False by default.
+       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.
 
 merge.summary::
        Synonym to `merge.log`; this is deprecated and will be removed in
index d66fd9d2314774a0b31eadb23f8c00c199276d84..fac1cf55e51ff289167270de4f248dad959741c6 100644 (file)
@@ -9,7 +9,7 @@ SYNOPSIS
 --------
 [verse]
 'git for-each-ref' [--count=<count>] [--shell|--perl|--python|--tcl]
-                  [--sort=<key>]* [--format=<format>] [<pattern>...]
+                  [(--sort=<key>)...] [--format=<format>] [<pattern>...]
 
 DESCRIPTION
 -----------
index 4b3f5ba5358da469feff4e861e69717f16e81d21..9dcafc6d4442b6db66df642e92336537395b9919 100644 (file)
@@ -39,7 +39,7 @@ There are two ways to specify which commits to operate on.
    that leads to the <since> to be output.
 
 2. Generic <revision range> expression (see "SPECIFYING
-   REVISIONS" section in linkgit:gitrevisions[1]) means the
+   REVISIONS" section in linkgit:gitrevisions[7]) means the
    commits in the specified range.
 
 The first rule takes precedence in the case of a single <commit>.  To
@@ -74,7 +74,7 @@ OPTIONS
 include::diff-options.txt[]
 
 -<n>::
-       Limits the number of patches to prepare.
+       Prepare patches from the topmost <n> commits.
 
 -o <dir>::
 --output-directory <dir>::
index f3ccc72f0d68f03cd7b3fb6a36aabc8d7c7772a1..c2bb81042c80dbf93b7a651c47fc177358132f97 100644 (file)
@@ -59,10 +59,10 @@ OPTIONS
        the newly constructed pack and index before refs can be
        updated to use objects contained in the pack.
 
---keep='why'::
+--keep=<msg>::
        Like --keep create a .keep file before moving the index into
        its final destination, but rather than creating an empty file
-       place 'why' followed by an LF into the .keep file.  The 'why'
+       place '<msg>' followed by an LF into the .keep file.  The '<msg>'
        message can later be searched for within all .keep files to
        locate any which have outlived their usefulness.
 
index 246b07ebf94394d2079c2acc3e8c1a2e6c40bba9..00d4a124c918e7548628140646f698b9e37ab87a 100644 (file)
@@ -31,7 +31,7 @@ current working directory.
 Specify the directory from which templates will be used.  (See the "TEMPLATE
 DIRECTORY" section below.)
 
---shared[={false|true|umask|group|all|world|everybody|0xxx}]::
+--shared[=(false|true|umask|group|all|world|everybody|0xxx)]::
 
 Specify that the git repository is to be shared amongst several users.  This
 allows users belonging to the same group to push into that
index c213bdbdc500b1117805bc84cb2a0f31eeff3bcd..6d40f0011b0fd297e5676c8479e46989d7f47696 100644 (file)
@@ -31,7 +31,7 @@ OPTIONS
        either <since> or <until> is omitted, it defaults to
        `HEAD`, i.e. the tip of the current branch.
        For a more complete list of ways to spell <since>
-       and <until>, see linkgit:gitrevisions[1].
+       and <until>, see linkgit:gitrevisions[7].
 
 --follow::
        Continue listing the history of a file beyond renames
index 347f4479865419d010b874bc8b26f5f1b40a6f61..86abd1345178d4c5d2362509fc075de80d2fc7e3 100644 (file)
@@ -17,7 +17,7 @@ SYNOPSIS
                [--exclude-per-directory=<file>]
                [--exclude-standard]
                [--error-unmatch] [--with-tree=<tree-ish>]
-               [--full-name] [--abbrev] [--] [<file>]*
+               [--full-name] [--abbrev] [--] [<file>...]
 
 DESCRIPTION
 -----------
index 1f89d3680043cc98ad39facb1f43ae770ff66e14..76ed625e7b2fe503d3fb2262371ecd4de006411f 100644 (file)
@@ -10,8 +10,8 @@ SYNOPSIS
 --------
 [verse]
 'git ls-tree' [-d] [-r] [-t] [-l] [-z]
-           [--name-only] [--name-status] [--full-name] [--full-tree] [--abbrev=[<n>]]
-           <tree-ish> [paths...]
+           [--name-only] [--name-status] [--full-name] [--full-tree] [--abbrev[=<n>]]
+           <tree-ish> [<path>...]
 
 DESCRIPTION
 -----------
@@ -19,11 +19,11 @@ Lists the contents of a given tree object, like what "/bin/ls -a" does
 in the current working directory.  Note that:
 
  - the behaviour is slightly different from that of "/bin/ls" in that the
-   'paths' denote just a list of patterns to match, e.g. so specifying
+   '<path>' denotes just a list of patterns to match, e.g. so specifying
    directory name (without '-r') will behave differently, and order of the
    arguments does not matter.
 
- - the behaviour is similar to that of "/bin/ls" in that the 'paths' is
+ - the behaviour is similar to that of "/bin/ls" in that the '<path>' is
    taken as relative to the current working directory.  E.g. when you are
    in a directory 'sub' that has a directory 'dir', you can run 'git
    ls-tree -r HEAD dir' to list the contents of the tree (that is
@@ -72,7 +72,7 @@ OPTIONS
        Do not limit the listing to the current working directory.
        Implies --full-name.
 
-paths::
+[<path>...]::
        When paths are given, show them (note that this isn't really raw
        pathnames, but rather a list of patterns to match).  Otherwise
        implicitly uses the root level of the tree as the sole path argument.
index a634485281154cb665c8168cc3469dc0f5051697..71912a19a4dcda5f2b76d1c06b4c9ef5051265e3 100644 (file)
@@ -7,7 +7,7 @@ git-mailsplit - Simple UNIX mbox splitter program
 
 SYNOPSIS
 --------
-'git mailsplit' [-b] [-f<nn>] [-d<prec>] [--keep-cr] -o<directory> [--] [<mbox>|<Maildir>...]
+'git mailsplit' [-b] [-f<nn>] [-d<prec>] [--keep-cr] -o<directory> [--] [(<mbox>|<Maildir>)...]
 
 DESCRIPTION
 -----------
index 84043cc5b26db7d34c93a70ec005df913c345d85..d43416d299a7c028a88e8ddce89536c2c64e65c9 100644 (file)
@@ -59,13 +59,13 @@ include::merge-options.txt[]
 -m <msg>::
        Set the commit message to be used for the merge commit (in
        case one is created).
-
-       If `--log` is specified, a shortlog of the commits being merged
-       will be appended to the specified message.
-
-       The 'git fmt-merge-msg' command can be
-       used to give a good default for automated 'git merge'
-       invocations.
++
+If `--log` is specified, a shortlog of the commits being merged
+will be appended to the specified message.
++
+The 'git fmt-merge-msg' command can be
+used to give a good default for automated 'git merge'
+invocations.
 
 --rerere-autoupdate::
 --no-rerere-autoupdate::
index e4ed0161467866f731c89eb48e64453051c64281..1f75a848ba36728eeaa67e5cbbc209075393193b 100644 (file)
@@ -7,7 +7,7 @@ git-mergetool - Run merge conflict resolution tools to resolve merge conflicts
 
 SYNOPSIS
 --------
-'git mergetool' [--tool=<tool>] [-y|--no-prompt|--prompt] [<file>]...
+'git mergetool' [--tool=<tool>] [-y|--no-prompt|--prompt] [<file>...]
 
 DESCRIPTION
 -----------
index 8ed09c0b3cfc0fff2dbb8907fdc00e027c2c6d33..65eff66afe5990efc4af4f141809f355b7111bd3 100644 (file)
@@ -11,8 +11,8 @@ SYNOPSIS
 [verse]
 'git pack-objects' [-q | --progress | --all-progress] [--all-progress-implied]
        [--no-reuse-delta] [--delta-base-offset] [--non-empty]
-       [--local] [--incremental] [--window=N] [--depth=N]
-       [--revs [--unpacked | --all]*] [--stdout | base-name]
+       [--local] [--incremental] [--window=<n>] [--depth=<n>]
+       [--revs [--unpacked | --all]] [--stdout | base-name]
        [--keep-true-parents] < object-list
 
 
@@ -82,8 +82,8 @@ base-name::
        reference was included in the resulting packfile.  This
        can be useful to send new tags to native git clients.
 
---window=[N]::
---depth=[N]::
+--window=<n>::
+--depth=<n>::
        These two options affect how the objects contained in
        the pack are stored using delta compression.  The
        objects are first internally sorted by type, size and
@@ -95,10 +95,10 @@ base-name::
        times to get to the necessary object.
        The default value for --window is 10 and --depth is 50.
 
---window-memory=[N]::
+--window-memory=<n>::
        This option provides an additional limit on top of `--window`;
        the window size will dynamically scale down so as to not take
-       up more than N bytes in memory.  This is useful in
+       up more than '<n>' bytes in memory.  This is useful in
        repositories with a mix of large and small objects to not run
        out of memory with a large window, but still be able to take
        advantage of the large window for the smaller objects.  The
@@ -106,7 +106,7 @@ base-name::
        `--window-memory=0` makes memory usage unlimited, which is the
        default.
 
---max-pack-size=[N]::
+--max-pack-size=<n>::
        Maximum size of each output pack file. The size can be suffixed with
        "k", "m", or "g". The minimum size allowed is limited to 1 MiB.
        If specified,  multiple packfiles may be created.
@@ -171,7 +171,7 @@ base-name::
        wholesale enforcement of a different compression level on the
        packed data is desired.
 
---compression=[N]::
+--compression=<n>::
        Specifies compression level for newly-compressed data in the
        generated pack.  If not specified,  pack compression level is
        determined first by pack.compression,  then by core.compression,
index c50f7dcb890139d829bae51c30b513d54fd7761e..e1b0bd2868e5f4c489f698038c4d4aaae7740c52 100644 (file)
@@ -92,12 +92,14 @@ include::merge-options.txt[]
 :git-pull: 1
 
 --rebase::
-       Instead of a merge, perform a rebase after fetching.  If
-       there is a remote ref for the upstream branch, and this branch
-       was rebased since last fetched, the rebase uses that information
-       to avoid rebasing non-local changes. To make this the default
-       for branch `<name>`, set configuration `branch.<name>.rebase`
-       to `true`.
+       Rebase the current branch on top of the upstream branch after
+       fetching.  If there is a remote-tracking branch corresponding to
+       the upstream branch and the upstream branch was rebased since last
+       fetched, the rebase uses that information to avoid rebasing
+       non-local changes.
++
+See `branch.<name>.rebase` in linkgit:git-config[1] if you want to make
+`git pull` always use `{litdd}rebase` instead of merging.
 +
 [NOTE]
 This is a potentially _dangerous_ mode of operation.
index 020955ff5a8635e385208a6a89b1ad71125fb205..e11660a2e651b385251bef4f45dc36f212fa58bf 100644 (file)
@@ -41,7 +41,7 @@ OPTIONS[[OPTIONS]]
 +
 The <src> is often the name of the branch you would want to push, but
 it can be any arbitrary "SHA-1 expression", such as `master~4` or
-`HEAD` (see linkgit:gitrevisions[1]).
+`HEAD` (see linkgit:gitrevisions[7]).
 +
 The <dst> tells which ref on the remote side is updated with this
 push. Arbitrary expressions cannot be used here, an actual ref must
index 2e78da448f30ad260cb7683a5610f424d0c5ffea..e88e9c2d55d19844ca56bc2d5b7b683e329b6fb8 100644 (file)
@@ -11,7 +11,7 @@ SYNOPSIS
 'git read-tree' [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>]
                [-u [--exclude-per-directory=<gitignore>] | -i]]
                [--index-output=<file>] [--no-sparse-checkout]
-               <tree-ish1> [<tree-ish2> [<tree-ish3>]]
+               (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])
 
 
 DESCRIPTION
@@ -114,6 +114,10 @@ OPTIONS
        Disable sparse checkout support even if `core.sparseCheckout`
        is true.
 
+--empty::
+       Instead of reading tree object(s) into the index, just empty
+       it.
+
 <tree-ish#>::
        The id of the tree object(s) to be read/merged.
 
index 5a0451aaf377d13590d6112a9ee8cf51e217a21d..e50bd9b68d80e9be997de80252dec5afbb7452b4 100644 (file)
@@ -40,7 +40,7 @@ see linkgit:git-log[1].
 The reflog is useful in various git commands, to specify the old value
 of a reference. For example, `HEAD@\{2\}` means "where HEAD used to be
 two moves ago", `master@\{one.week.ago\}` means "where master used to
-point to one week ago", and so on. See linkgit:gitrevisions[1] for
+point to one week ago", and so on. See linkgit:gitrevisions[7] for
 more details.
 
 To delete single entries from the reflog, use the subcommand "delete"
index 8a5842bb937a0f8f89a561566d1d7ce129edc4b0..8fc809f82b2fae71f5cf6315dec707b649931382 100644 (file)
@@ -7,7 +7,7 @@ git-relink - Hardlink common objects in local repositories
 
 SYNOPSIS
 --------
-'git relink' [--safe] <dir> [<dir>]* <master_dir>
+'git relink' [--safe] <dir>... <master_dir>
 
 DESCRIPTION
 -----------
index aa021b0cb803a9cd9f08566f6a6fe407eb025e4b..0d28febe1b44fff289b772a0e0fb6e74a010b9eb 100644 (file)
@@ -20,7 +20,7 @@ SYNOPSIS
 'git remote set-url --delete' [--push] <name> <url>
 'git remote' [-v | --verbose] 'show' [-n] <name>
 'git remote prune' [-n | --dry-run] <name>
-'git remote' [-v | --verbose] 'update' [-p | --prune] [group | remote]...
+'git remote' [-v | --verbose] 'update' [-p | --prune] [(<group> | <remote>)...]
 
 DESCRIPTION
 -----------
index 8c67d1724f705c94fb8faf6801ee2bc7cd459629..27f7865b061cc96398f7aa052d162723e1f9255e 100644 (file)
@@ -8,7 +8,7 @@ git-repack - Pack unpacked objects in a repository
 
 SYNOPSIS
 --------
-'git repack' [-a] [-A] [-d] [-f] [-l] [-n] [-q] [--window=N] [--depth=N]
+'git repack' [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [--window=<n>] [--depth=<n>]
 
 DESCRIPTION
 -----------
@@ -62,6 +62,10 @@ other objects in that pack they already have locally.
        linkgit:git-pack-objects[1].
 
 -f::
+       Pass the `--no-reuse-delta` option to `git-pack-objects`, see
+       linkgit:git-pack-objects[1].
+
+-F::
        Pass the `--no-reuse-object` option to `git-pack-objects`, see
        linkgit:git-pack-objects[1].
 
@@ -76,8 +80,8 @@ other objects in that pack they already have locally.
        this repository (or a direct copy of it)
        over HTTP or FTP.  See linkgit:git-update-server-info[1].
 
---window=[N]::
---depth=[N]::
+--window=<n>::
+--depth=<n>::
        These two options affect how the objects contained in the pack are
        stored using delta compression. The objects are first internally
        sorted by type, size and optionally names and compared against the
@@ -87,10 +91,10 @@ other objects in that pack they already have locally.
        to be applied that many times to get to the necessary object.
        The default value for --window is 10 and --depth is 50.
 
---window-memory=[N]::
+--window-memory=<n>::
        This option provides an additional limit on top of `--window`;
        the window size will dynamically scale down so as to not take
-       up more than N bytes in memory.  This is useful in
+       up more than '<n>' bytes in memory.  This is useful in
        repositories with a mix of large and small objects to not run
        out of memory with a large window, but still be able to take
        advantage of the large window for the smaller objects.  The
@@ -98,7 +102,7 @@ other objects in that pack they already have locally.
        `--window-memory=0` makes memory usage unlimited, which is the
        default.
 
---max-pack-size=[N]::
+--max-pack-size=<n>::
        Maximum size of each output pack file. The size can be suffixed with
        "k", "m", or "g". The minimum size allowed is limited to 1 MiB.
        If specified,  multiple packfiles may be created.
index 9cf31485feec4b03850edb1f2f3a4b765245f4cc..fd72976371cee0fcd25e3419138eb13382dc6ab8 100644 (file)
@@ -15,17 +15,24 @@ SYNOPSIS
 DESCRIPTION
 -----------
 In the first and second form, copy entries from <commit> to the index.
-In the third form, set the current branch to <commit>, optionally
-modifying index and worktree to match.  The <commit> defaults to HEAD
+In the third form, set the current branch head (HEAD) to <commit>, optionally
+modifying index and working tree to match.  The <commit> defaults to HEAD
 in all forms.
 
 'git reset' [-q] [<commit>] [--] <paths>...::
        This form resets the index entries for all <paths> to their
-       state at the <commit>.  (It does not affect the worktree, nor
+       state at <commit>.  (It does not affect the working tree, nor
        the current branch.)
 +
 This means that `git reset <paths>` is the opposite of `git add
 <paths>`.
++
+After running `git reset <paths>` to update the index entry, you can
+use linkgit:git-checkout[1] to check the contents out of the index to
+the working tree.
+Alternatively, using linkgit:git-checkout[1] and specifying a commit, you
+can copy the contents of a path out of a commit to the index and to the
+working tree in one go.
 
 'git reset' --patch|-p [<commit>] [--] [<paths>...]::
        Interactively select hunks in the difference between the index
@@ -36,16 +43,17 @@ This means that `git reset -p` is the opposite of `git add -p` (see
 linkgit:git-add[1]).
 
 'git reset' [--<mode>] [<commit>]::
-       This form points the current branch to <commit> and then
-       updates index and working tree according to <mode>, which must
-       be one of the following:
+       This form resets the current branch head to <commit> and
+       possibly updates the index (resetting it to the tree of <commit>) and
+       the working tree depending on <mode>, which
+       must be one of the following:
 +
 --
 --soft::
-       Does not touch the index file nor the working tree at allbut
-       requires them to be in a good order. This leaves all your changed
-       files "Changes to be committed", as 'git status' would
-       put it.
+       Does not touch the index file nor the working tree at all (but
+       resets the head to <commit>, just like all modes do). This leaves
+       all your changed files "Changes to be committed", as 'git status'
+       would put it.
 
 --mixed::
        Resets the index but not the working tree (i.e., the changed files
@@ -53,22 +61,30 @@ linkgit:git-add[1]).
        been updated. This is the default action.
 
 --hard::
-       Matches the working tree and index to that of the tree being
-       switched to. Any changes to tracked files in the working tree
-       since <commit> are lost.
+       Resets the index and working tree. Any changes to tracked files in the
+       working tree since <commit> are discarded.
 
 --merge::
-       Resets the index to match the tree recorded by the named commit,
-       and updates the files that are different between the named commit
-       and the current commit in the working tree.
+       Resets the index and updates the files in the working tree that are
+       different between <commit> and HEAD, but keeps those which are
+       different between the index and working tree (i.e. which have changes
+       which have not been added).
+       If a file that is different between <commit> and the index has unstaged
+       changes, reset is aborted.
++
+In other words, --merge does something like a 'git read-tree -u -m <commit>',
+but carries forward unmerged index entries.
 
 --keep::
-       Reset the index to the given commit, keeping local changes in
-       the working tree since the current commit, while updating
-       working tree files without local changes to what appears in
-       the given commit.  If a file that is different between the
-       current commit and the given commit has local changes, reset
-       is aborted.
+       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).
+       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,
@@ -184,7 +200,7 @@ tip of the current branch in ORIG_HEAD, so resetting hard to it
 brings your index file and the working tree back to that state,
 and resets the tip of the branch to that commit.
 
-Undo a merge or pull inside a dirty work tree::
+Undo a merge or pull inside a dirty working tree::
 +
 ------------
 $ git pull                         <1>
@@ -257,7 +273,7 @@ Suppose you are working on something and you commit it, and then you
 continue working a bit more, but now you think that what you have in
 your working tree should be in another branch that has nothing to do
 with what you committed previously. You can start a new branch and
-reset it while keeping the changes in your work tree.
+reset it while keeping the changes in your working tree.
 +
 ------------
 $ git tag start
@@ -294,8 +310,10 @@ In these tables, A, B, C and D are some different states of a
 file. For example, the first line of the first table means that if a
 file is in state A in the working tree, in state B in the index, in
 state C in HEAD and in state D in the target, then "git reset --soft
-target" will put the file in state A in the working tree, in state B
-in the index and in state D in HEAD.
+target" will leave the file in the working tree in state A and in the
+index in state B.  It resets (i.e. moves) the HEAD (i.e. the tip of
+the current branch, if you are on one) to "target" (which has the file
+in state D).
 
       working index HEAD target         working index HEAD
       ----------------------------------------------------
@@ -346,11 +364,11 @@ in the index and in state D in HEAD.
                                --keep   B       C     C
 
 "reset --merge" is meant to be used when resetting out of a conflicted
-merge. Any mergy operation guarantees that the work tree file that is
+merge. Any mergy operation guarantees that the working tree file that is
 involved in the merge does not have local change wrt the index before
-it starts, and that it writes the result out to the work tree. So if
+it starts, and that it writes the result out to the working tree. So if
 we see some difference between the index and the target and also
-between the index and the work tree, then it means that we are not
+between the index and the working tree, then it means that we are not
 resetting out from a state that a mergy operation left after failing
 with a conflict. That is why we disallow --merge option in this case.
 
index 173f3fc78599f268c1e483c4d1abe51e95ad0e59..8e1e32908c31ddb8cb07046a25bcdb6dd38d74f5 100644 (file)
@@ -9,10 +9,10 @@ git-rev-list - Lists commit objects in reverse chronological order
 SYNOPSIS
 --------
 [verse]
-'git rev-list' [ \--max-count=number ]
-            [ \--skip=number ]
-            [ \--max-age=timestamp ]
-            [ \--min-age=timestamp ]
+'git rev-list' [ \--max-count=<number> ]
+            [ \--skip=<number> ]
+            [ \--max-age=<timestamp> ]
+            [ \--min-age=<timestamp> ]
             [ \--sparse ]
             [ \--merges ]
             [ \--no-merges ]
@@ -21,10 +21,10 @@ SYNOPSIS
             [ \--full-history ]
             [ \--not ]
             [ \--all ]
-            [ \--branches[=pattern] ]
-            [ \--tags[=pattern] ]
-            [ \--remotes[=pattern] ]
-            [ \--glob=glob-pattern ]
+            [ \--branches[=<pattern>] ]
+            [ \--tags[=<pattern>] ]
+            [ \--remotes[=<pattern>] ]
+            [ \--glob=<glob-pattern> ]
             [ \--stdin ]
             [ \--quiet ]
             [ \--topo-order ]
@@ -37,7 +37,7 @@ SYNOPSIS
             [ \--regexp-ignore-case | -i ]
             [ \--extended-regexp | -E ]
             [ \--fixed-strings | -F ]
-            [ \--date={local|relative|default|iso|rfc|short} ]
+            [ \--date=(local|relative|default|iso|rfc|short) ]
             [ [\--objects | \--objects-edge] [ \--unpacked ] ]
             [ \--pretty | \--header ]
             [ \--bisect ]
index 341ca90c6e2b40676d4be360118176a39955b11c..4a27643c1ea0e908a0a54b84f668d5a80f6d7100 100644 (file)
@@ -95,7 +95,7 @@ OPTIONS
        unfortunately named tag "master"), and show them as full
        refnames (e.g. "refs/heads/master").
 
---abbrev-ref[={strict|loose}]::
+--abbrev-ref[=(strict|loose)]::
        A non-ambiguous short name of the objects name.
        The option core.warnAmbiguousRefs is used to select the strict
        abbreviation mode.
index b7d9ef7e4726db40f3b0d1ec9474494bb6e07dcf..f40984d144e4ca276f84fc81a74c4ae726dcf497 100644 (file)
@@ -31,7 +31,7 @@ OPTIONS
 <commit>...::
        Commits to revert.
        For a more complete list of ways to spell commit names, see
-       linkgit:gitrevisions[1].
+       linkgit:gitrevisions[7].
        Sets of commits can also be given but no traversal is done by
        default, see linkgit:git-rev-list[1] and its '--no-walk'
        option.
index c283084272090c28d5529d200a1147c9f57c639b..05904e0e7f31896191bc10224c09d14e91372952 100644 (file)
@@ -97,7 +97,7 @@ See the CONFIGURATION section for 'sendemail.multiedit'.
        Specify the primary recipient of the emails generated. Generally, this
        will be the upstream maintainer of the project involved. Default is the
        value of the 'sendemail.to' configuration value; if that is unspecified,
-       this will be prompted for.
+       and --to-cmd is not specified, this will be prompted for.
 +
 The --to option must be repeated for each user you want on the to list.
 
@@ -165,6 +165,15 @@ user is prompted for a password while the input is masked for privacy.
        are also accepted. The port can also be set with the
        'sendemail.smtpserverport' configuration variable.
 
+--smtp-server-option=<option>::
+       If set, specifies the outgoing SMTP server option to use.
+       Default value can be specified by the 'sendemail.smtpserveroption'
+       configuration option.
++
+The --smtp-server-option option must be repeated for each option you want
+to pass to the server. Likewise, different lines in the configuration files
+must be used for each option.
+
 --smtp-ssl::
        Legacy alias for '--smtp-encryption ssl'.
 
@@ -177,6 +186,12 @@ user is prompted for a password while the input is masked for privacy.
 Automating
 ~~~~~~~~~~
 
+--to-cmd=<command>::
+       Specify a command to execute once per patch file which
+       should generate patch file specific "To:" entries.
+       Output of this command must be single email address per line.
+       Default is the value of 'sendemail.tocmd' configuration value.
+
 --cc-cmd=<command>::
        Specify a command to execute once per patch file which
        should generate patch file specific "Cc:" entries.
index 0f3ad811cfa41e65a3d807a5eb766ce2a66a7831..6403126a029bf43acaa219296353f7ab1f2040a0 100644 (file)
@@ -3,24 +3,30 @@ git-shell(1)
 
 NAME
 ----
-git-shell - Restricted login shell for GIT-only SSH access
+git-shell - Restricted login shell for Git-only SSH access
 
 
 SYNOPSIS
 --------
-'$(git --exec-path)/git-shell' -c <command> <argument>
+'git shell' [-c <command> <argument>]
 
 DESCRIPTION
 -----------
-This is meant to be used as a login shell for SSH accounts you want
-to restrict to GIT pull/push access only. It permits execution only
-of server-side GIT commands implementing the pull/push functionality.
-The commands can be executed only by the '-c' option; the shell is not
-interactive.
-
-Currently, only four commands are permitted to be called, 'git-receive-pack'
-'git-upload-pack' and 'git-upload-archive' with a single required argument, or
-'cvs server' (to invoke 'git-cvsserver').
+
+A login shell for SSH accounts to provide restricted Git access. When
+'-c' is given, the program executes <command> non-interactively;
+<command> can be one of 'git receive-pack', 'git upload-pack', 'git
+upload-archive', 'cvs server', or a command in COMMAND_DIR. The shell
+is started in interactive mode when no arguments are given; in this
+case, COMMAND_DIR must exist, and any of the executables in it can be
+invoked.
+
+'cvs server' is a special command which executes git-cvsserver.
+
+COMMAND_DIR is the path "$HOME/git-shell-commands". The user must have
+read and execute permissions to the directory in order to execute the
+programs in it. The programs are executed with a cwd of $HOME, and
+<argument> is parsed as a command-line string.
 
 Author
 ------
index bc1ac77495347967c941298e2da38f76d5d124c6..5cc3baf48dcbf86e976d5d4407831a6d0ceb108f 100644 (file)
@@ -44,7 +44,7 @@ OPTIONS
 --email::
        Show the email address of each author.
 
---format[='<format>']::
+--format[=<format>]::
        Instead of the commit subject, use some other information to
        describe each commit.  '<format>' can be any string accepted
        by the `--format` option of 'git log', such as '{asterisk} [%h] %s'.
index 64532633406bedb431c4c6755101ce117e71388f..3b0c88271a80ad9dfc989dcb44247479f09431bf 100644 (file)
@@ -12,7 +12,7 @@ SYNOPSIS
                [--current] [--color[=<when>] | --no-color] [--sparse]
                [--more=<n> | --list | --independent | --merge-base]
                [--no-name | --sha1-name] [--topics]
-               [<rev> | <glob>]...
+               [(<rev> | <glob>)...]
 
 'git show-branch' (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]
 
@@ -32,7 +32,7 @@ no <rev> nor <glob> is given on the command line.
 OPTIONS
 -------
 <rev>::
-       Arbitrary extended SHA1 expression (see linkgit:gitrevisions[1])
+       Arbitrary extended SHA1 expression (see linkgit:gitrevisions[7])
        that typically names a branch head or a tag.
 
 <glob>::
index 4696af743321d78d9e1d17115d29222f17cb4d55..be0ec189af45e1006134e5607bb76a7b6ad20699 100644 (file)
@@ -84,7 +84,11 @@ OPTIONS
 
 <pattern>...::
 
-       Show references matching one or more patterns.
+       Show references matching one or more patterns. Patterns are matched from
+       the end of the full name, and only complete parts are matched, e.g.
+       'master' matches 'refs/heads/master', 'refs/remotes/origin/master',
+       'refs/tags/jedi/master' but not 'refs/heads/mymaster' nor
+       'refs/remotes/master/jedi'.
 
 OUTPUT
 ------
index 0002bfb0455b38eecf6b29da6a2464058ba42c57..f0a8a1aff3694cf00587d8670a8fe9962fe98af3 100644 (file)
@@ -36,7 +36,7 @@ OPTIONS
 <object>...::
        The names of objects to show.
        For a more complete list of ways to spell object names, see
-       "SPECIFYING REVISIONS" section in linkgit:gitrevisions[1].
+       "SPECIFYING REVISIONS" section in linkgit:gitrevisions[7].
 
 include::pretty-options.txt[]
 
@@ -54,6 +54,10 @@ git show v1.0.0::
 git show v1.0.0^\{tree\}::
        Shows the tree pointed to by the tag `v1.0.0`.
 
+git show -s --format=%s v1.0.0^\{commit\}::
+       Shows the subject of the commit pointed to by the
+       tag `v1.0.0`.
+
 git show next~10:Documentation/README::
        Shows the contents of the file `Documentation/README` as
        they were current in the 10th last commit of the branch
index 4b84d08fc87c13f6db371ecc52710bd09865d784..139d314ba54c4e7897ffcf257a1fd847eb7939fa 100644 (file)
@@ -56,6 +56,8 @@ COMMANDS
        as well, they take precedence.
 --no-metadata;;
        Set the 'noMetadata' option in the [svn-remote] config.
+       This option is not recommended, please read the 'svn.noMetadata'
+       section of this manpage before using this option.
 --use-svm-props;;
        Set the 'useSvmProps' option in the [svn-remote] config.
 --use-svnsync-props;;
@@ -436,7 +438,7 @@ git rebase --onto remotes/git-svn A^ master
 OPTIONS
 -------
 
---shared[={false|true|umask|group|all|world|everybody}]::
+--shared[=(false|true|umask|group|all|world|everybody)]::
 --template=<template_directory>::
        Only used with the 'init' command.
        These are passed directly to 'git init'.
@@ -597,13 +599,22 @@ svn.noMetadata::
 svn-remote.<name>.noMetadata::
        This gets rid of the 'git-svn-id:' lines at the end of every commit.
 +
-If you lose your .git/svn/git-svn/.rev_db file, 'git svn' will not
-be able to rebuild it and you won't be able to fetch again,
-either.  This is fine for one-shot imports.
+This option can only be used for one-shot imports as 'git svn'
+will not be able to fetch again without metadata. Additionally,
+if you lose your .git/svn/**/.rev_map.* files, 'git svn' will not
+be able to rebuild them.
 +
 The 'git svn log' command will not work on repositories using
 this, either.  Using this conflicts with the 'useSvmProps'
 option for (hopefully) obvious reasons.
++
+This option is NOT recommended as it makes it difficult to track down
+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
+info for non-"svn.authorsFile" users.
 
 svn.useSvmProps::
 svn-remote.<name>.useSvmProps::
index 74d1d49dbffda60a00f6c195d77020b5ec7be979..1ca56c85aa66b96dc1774b77ba1e117d93847033 100644 (file)
@@ -12,7 +12,7 @@ SYNOPSIS
 'git update-index'
             [--add] [--remove | --force-remove] [--replace]
             [--refresh] [-q] [--unmerged] [--ignore-missing]
-            [--cacheinfo <mode> <object> <file>]*
+            [(--cacheinfo <mode> <object> <file>)...]
             [--chmod=(+|-)x]
             [--assume-unchanged | --no-assume-unchanged]
             [--skip-worktree | --no-skip-worktree]
@@ -21,7 +21,7 @@ SYNOPSIS
             [--info-only] [--index-info]
             [-z] [--stdin]
             [--verbose]
-            [--] [<file>]*
+            [--] [<file>...]
 
 DESCRIPTION
 -----------
@@ -144,8 +144,8 @@ you will need to handle the situation manually.
         Report what is being added and removed from index.
 
 -z::
-       Only meaningful with `--stdin`; paths are separated with
-       NUL character instead of LF.
+       Only meaningful with `--stdin` or `--index-info`; paths are
+       separated with NUL character instead of LF.
 
 \--::
        Do not interpret any more arguments as options.
index e1586c78c3d271c78bcf26827cf10ff234fcba62..51e8e0af1e7ff37ce4abfe53b6d52e9935b536a8 100644 (file)
@@ -32,19 +32,19 @@ Custom commands may also be specified.
 
 OPTIONS
 -------
--b BROWSER::
---browser=BROWSER::
-       Use the specified BROWSER. It must be in the list of supported
+-b <browser>::
+--browser=<browser>::
+       Use the specified browser. It must be in the list of supported
        browsers.
 
--t BROWSER::
---tool=BROWSER::
+-t <browser>::
+--tool=<browser>::
        Same as above.
 
--c CONF.VAR::
---config=CONF.VAR::
+-c <conf.var>::
+--config=<conf.var>::
        CONF.VAR is looked up in the git config files. If it's set,
-       then its value specify the browser that should be used.
+       then its value specifies the browser that should be used.
 
 CONFIGURATION VARIABLES
 -----------------------
index 646e76178935e7c702f3a2e56ab819e93e7b7609..0c897df6a71ddb5e7f4e960300c2b336ede5aab2 100644 (file)
@@ -9,11 +9,11 @@ git - the stupid content tracker
 SYNOPSIS
 --------
 [verse]
-'git' [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]
+'git' [--version] [--exec-path[=<path>]] [--html-path]
     [-p|--paginate|--no-pager] [--no-replace-objects]
-    [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]
-    [-c name=value]
-    [--help] COMMAND [ARGS]
+    [--bare] [--git-dir=<path>] [--work-tree=<path>]
+    [-c <name>=<value>]
+    [--help] <command> [<args>]
 
 DESCRIPTION
 -----------
@@ -28,7 +28,7 @@ also want to read linkgit:gitcvs-migration[7].  See
 the link:user-manual.html[Git User's Manual] for a more in-depth
 introduction.
 
-The COMMAND is either a name of a Git command (see below) or an alias
+The '<command>' is either a name of a Git command (see below) or an alias
 as defined in the configuration file (see linkgit:git-config[1]).
 
 Formatted and hyperlinked version of the latest git
@@ -44,9 +44,11 @@ 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/git.html[documentation for release 1.7.3]
+* link:v1.7.3.2/git.html[documentation for release 1.7.3.2]
 
 * release notes for
+  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.3/git.html[documentation for release 1.7.2.3]
@@ -251,7 +253,7 @@ help ...`.
        The <name> is expected in the same format as listed by
        'git config' (subkeys separated by dots).
 
---exec-path::
+--exec-path[=<path>]::
        Path to wherever your core git programs are installed.
        This can also be controlled by setting the GIT_EXEC_PATH
        environment variable. If no path is given, 'git' will print
@@ -494,7 +496,7 @@ HEAD::
        (i.e. the contents of `$GIT_DIR/refs/heads/<head>`).
 
 For a more complete list of ways to spell object names, see
-"SPECIFYING REVISIONS" section in linkgit:gitrevisions[1].
+"SPECIFYING REVISIONS" section in linkgit:gitrevisions[7].
 
 
 File/Directory Structure
index e5a27d875eb63dbfeccbf5357983f5c94668ffeb..c80ca5da4387e44f42b3bfd54132efc1def881b6 100644 (file)
@@ -62,14 +62,21 @@ consults `$GIT_DIR/info/attributes` file (which has the highest
 precedence), `.gitattributes` file in the same directory as the
 path in question, and its parent directories up to the toplevel of the
 work tree (the further the directory that contains `.gitattributes`
-is from the path in question, the lower its precedence).
+is from the path in question, the lower its precedence). Finally
+global and system-wide files are considered (they have the lowest
+precedence).
 
 If you wish to affect only a single repository (i.e., to assign
-attributes to files that are particular to one user's workflow), then
+attributes to files that are particular to
+one user's workflow for that repository), then
 attributes should be placed in the `$GIT_DIR/info/attributes` file.
 Attributes which should be version-controlled and distributed to other
 repositories (i.e., attributes of interest to all users) should go into
-`.gitattributes` files.
+`.gitattributes` files. Attributes that should affect all repositories
+for a single user should be placed in a file specified by the
+`core.attributesfile` configuration option (see linkgit:git-config[1]).
+Attributes for all users on a system should be placed in the
+`$(prefix)/etc/gitattributes` file.
 
 Sometimes you would need to override an setting of an attribute
 for a path to `unspecified` state.  This can be done by listing
@@ -477,6 +484,8 @@ patterns are available:
 
 - `csharp` suitable for source code in the C# language.
 
+- `fortran` suitable for source code in the Fortran language.
+
 - `html` suitable for HTML/XHTML documents.
 
 - `java` suitable for source code in the Java language.
index 5e9c5ebba3e3239f61195155448c960cfe476463..c27d086f68432d094a0fa7c1f9da353d6d3a0513 100644 (file)
@@ -971,7 +971,7 @@ commits from the master branch.  The string inside brackets
 before the commit log message is a short name you can use to
 name the commit.  In the above example, 'master' and 'mybranch'
 are branch heads.  'master^' is the first parent of 'master'
-branch head.  Please see linkgit:gitrevisions[1] if you want to
+branch head.  Please see linkgit:gitrevisions[7] if you want to
 see more complex cases.
 
 [NOTE]
index 5d91a7e5b3a40cbf41f03a81799c162775c36607..6af29a4603de57e0040c4bcd819b831dd6649f92 100644 (file)
@@ -227,9 +227,9 @@ changes that touch a specified string, and is controlled by the
 commands.
 
 When diffcore-pickaxe is in use, it checks if there are
-filepairs whose "result" side has the specified string and
-whose "origin" side does not.  Such a filepair represents "the
-string appeared in this changeset".  It also checks for the
+filepairs whose "result" side and whose "origin" side have
+different number of specified string.  Such a filepair represents
+"the string appeared in this changeset".  It also checks for the
 opposite case that loses the specified string.
 
 When `\--pickaxe-all` is not in effect, diffcore-pickaxe leaves
index 05ac1c79f768352be8756eeb483e71f0d09131de..e21bac4f3f16a6d0c0b1ff6d3062e8464e182e7f 100644 (file)
@@ -69,7 +69,7 @@ frequently used options.
        the form "'<from>'..'<to>'" to show all revisions between '<from>' and
        back to '<to>'. Note, more advanced revision selection can be applied.
        For a more complete list of ways to spell object names, see
-       linkgit:gitrevisions[1].
+       linkgit:gitrevisions[7].
 
 <path>...::
 
index b72f5339704e89087992b7d6060e88f43b9d661b..92772e7c4eb8921d3b2763fe1b533c380bd2b92b 100644 (file)
@@ -7,8 +7,10 @@ merge.conflictstyle::
        marker and the original text before the `=======` marker.
 
 merge.log::
-       Whether to include summaries of merged commits in newly created
-       merge commit messages. False by default.
+       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.
 
 merge.renameLimit::
        The number of files to consider when performing rename detection
index 722d704ff2de1abd3d77a18ca396ba96d5cab6bc..e33e0f8e110879a0cd6fe81d97ee6044290e5cfa 100644 (file)
@@ -16,11 +16,11 @@ inspect and further tweak the merge result before committing.
 With --no-ff Generate a merge commit even if the merge
 resolved as a fast-forward.
 
---log::
+--log[=<n>]::
 --no-log::
        In addition to branch names, populate the log message with
-       one-line descriptions from the actual commits that are being
-       merged.
+       one-line descriptions from at most <n> actual commits that are being
+       merged. See also linkgit:git-fmt-merge-msg[1].
 +
 With --no-log do not list one-line descriptions from the
 actual commits being merged.
index 049313d6015758fb3e95c21fecc40e021e8aa4bd..595a3cf1a7118ba29a1d57d7fc17d233d89cd3d0 100644 (file)
@@ -40,6 +40,28 @@ the other tree did, declaring 'our' history contains all that happened in it.
 theirs;;
        This is opposite of 'ours'.
 
+patience;;
+       With this option, 'merge-recursive' spends a little extra time
+       to avoid mismerges that sometimes occur due to unimportant
+       matching lines (e.g., braces from distinct functions).  Use
+       this when the branches to be merged have diverged wildly.
+       See also linkgit:git-diff[1] `--patience`.
+
+ignore-space-change;;
+ignore-all-space;;
+ignore-space-at-eol;;
+       Treats lines with the indicated type of whitespace change as
+       unchanged for the sake of a three-way merge.  Whitespace
+       changes mixed with other changes to a line are not ignored.
+       See also linkgit:git-diff[1] `-b`, `-w`, and
+       `--ignore-space-at-eol`.
++
+* If 'their' version only introduces whitespace changes to a line,
+  'our' version is used;
+* If 'our' version introduces whitespace changes but 'their'
+  version includes a substantial change, 'their' version is used;
+* Otherwise, the merge proceeds in the usual way.
+
 renormalize;;
        This runs a virtual check-out and check-in of all three stages
        of a file when resolving a three-way merge.  This option is
@@ -52,7 +74,11 @@ no-renormalize;;
        Disables the `renormalize` option.  This overrides the
        `merge.renormalize` configuration variable.
 
-subtree[=path];;
+rename-threshold=<n>;;
+       Controls the similarity threshold used for rename detection.
+       See also linkgit:git-diff[1] `-M`.
+
+subtree[=<path>];;
        This option is a more advanced form of 'subtree' strategy, where
        the strategy makes a guess on how two trees must be shifted to
        match with each other when merging.  Instead, the specified path
index 9b6f3899ec28fb431c1f3969bf5bfb717c12f346..50923e2ce9a5bdc3bcabb072a67921c6cf8171c1 100644 (file)
@@ -1,5 +1,5 @@
---pretty[='<format>']::
---format='<format>'::
+--pretty[=<format>]::
+--format=<format>::
 
        Pretty-print the contents of the commit logs in a given format,
        where '<format>' can be one of 'oneline', 'short', 'medium',
index e2237ae4a0a80b0e5aa22cbb13aa5a01ce4fb891..42ca059908b6af5726d958d92912705c96235d29 100644 (file)
@@ -13,7 +13,7 @@ include::pretty-options.txt[]
 
        Synonym for `--date=relative`.
 
---date={relative,local,default,iso,rfc,short,raw}::
+--date=(relative|local|default|iso|rfc|short|raw)::
 
        Only takes effect for dates shown in human-readable format, such
        as when using "--pretty". `log.date` config variable sets a default
@@ -45,13 +45,13 @@ endif::git-rev-list[]
 
 --parents::
 
-       Print the parents of the commit.  Also enables parent
-       rewriting, see 'History Simplification' below.
+       Print also the parents of the commit (in the form "commit parent...").
+       Also enables parent rewriting, see 'History Simplification' below.
 
 --children::
 
-       Print the children of the commit.  Also enables parent
-       rewriting, see 'History Simplification' below.
+       Print also the children of the commit (in the form "commit child...").
+       Also enables parent rewriting, see 'History Simplification' below.
 
 ifdef::git-rev-list[]
 --timestamp::
@@ -95,6 +95,8 @@ you would get an output like this:
        to be printed in between commits, in order for the graph history
        to be drawn properly.
 +
+This enables parent rewriting, see 'History Simplification' below.
++
 This implies the '--topo-order' option by default, but the
 '--date-order' option may also be specified.
 
@@ -146,6 +148,9 @@ options may be given. See linkgit:git-diff-files[1] for more options.
 -t::
 
        Show the tree objects in the diff output. This implies '-r'.
+
+-s::
+       Suppress diff output.
 endif::git-rev-list[]
 
 Commit Limiting
@@ -246,29 +251,29 @@ endif::git-rev-list[]
        Pretend as if all the refs in `refs/` are listed on the
        command line as '<commit>'.
 
---branches[=pattern]::
+--branches[=<pattern>]::
 
        Pretend as if all the refs in `refs/heads` are listed
-       on the command line as '<commit>'. If `pattern` is given, limit
+       on the command line as '<commit>'. If '<pattern>' is given, limit
        branches to ones matching given shell glob. If pattern lacks '?',
        '*', or '[', '/*' at the end is implied.
 
---tags[=pattern]::
+--tags[=<pattern>]::
 
        Pretend as if all the refs in `refs/tags` are listed
-       on the command line as '<commit>'. If `pattern` is given, limit
+       on the command line as '<commit>'. If '<pattern>' is given, limit
        tags to ones matching given shell glob. If pattern lacks '?', '*',
        or '[', '/*' at the end is implied.
 
---remotes[=pattern]::
+--remotes[=<pattern>]::
 
        Pretend as if all the refs in `refs/remotes` are listed
-       on the command line as '<commit>'. If `pattern`is given, limit
+       on the command line as '<commit>'. If '<pattern>' is given, limit
        remote tracking branches to ones matching given shell glob.
        If pattern lacks '?', '*', or '[', '/*' at the end is implied.
 
---glob=glob-pattern::
-       Pretend as if all the refs matching shell glob `glob-pattern`
+--glob=<glob-pattern>::
+       Pretend as if all the refs matching shell glob '<glob-pattern>'
        are listed on the command line as '<commit>'. Leading 'refs/',
        is automatically prepended if missing. If pattern lacks '?', '*',
        or '[', '/*' at the end is implied.
index fe846f043ca30fdfc3bc93b2dbba75154bd38804..3d4b79c480e2c84150bee96392ee2dd2a4b7d3ea 100644 (file)
@@ -107,11 +107,13 @@ the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file.
   found.
 
 * A colon, followed by a slash, followed by a text (e.g. `:/fix nasty bug`): this names
-  a commit whose commit message starts with the specified text.
+  a commit whose commit message matches the specified regular expression.
   This name returns the youngest matching commit which is
   reachable from any ref.  If the commit message starts with a
   '!', you have to repeat that;  the special sequence ':/!',
   followed by something else than '!' is reserved for now.
+  The regular expression can match any part of the commit message. To
+  match messages starting with a string, one can use e.g. `:/^foo`.
 
 * A suffix ':' followed by a path (e.g. `HEAD:README`); this names the blob or tree
   at the given path in the tree-ish object named by the part
index a7e050bb7acb59764c851b09cd488b6620c0a2dd..9dc1bed768a473317dd77c4d1ed93f65b2c4d483 100644 (file)
@@ -17,6 +17,40 @@ responsible for a few things.
    path-specific merge drivers (specified in `.gitattributes`)
    into account.
 
+Data structures
+---------------
+
+* `mmbuffer_t`, `mmfile_t`
+
+These store data usable for use by the xdiff backend, for writing and
+for reading, respectively.  See `xdiff/xdiff.h` for the definitions
+and `diff.c` for examples.
+
+* `struct ll_merge_options`
+
+This describes the set of options the calling program wants to affect
+the operation of a low-level (single file) merge.  Some options:
+
+`virtual_ancestor`::
+       Behave as though this were part of a merge between common
+       ancestors in a recursive merge.
+       If a helper program is specified by the
+       `[merge "<driver>"] recursive` configuration, it will
+       be used (see linkgit:gitattributes[5]).
+
+`variant`::
+       Resolve local conflicts automatically in favor
+       of one side or the other (as in 'git merge-file'
+       `--ours`/`--theirs`/`--union`).  Can be `0`,
+       `XDL_MERGE_FAVOR_OURS`, `XDL_MERGE_FAVOR_THEIRS`, or
+       `XDL_MERGE_FAVOR_UNION`.
+
+`renormalize`::
+       Resmudge and clean the "base", "theirs" and "ours" files
+       before merging.  Use this when the merge is likely to have
+       overlapped with a change in smudge/clean or end-of-line
+       normalization rules.
+
 Low-level (single file) merge
 -----------------------------
 
@@ -28,15 +62,24 @@ Low-level (single file) merge
        `.git/info/attributes` into account.  Returns 0 for a
        clean merge.
 
-The caller:
+Calling sequence:
 
-1. allocates an mmbuffer_t variable for the result;
-2. allocates and fills variables with the file's original content
-   and two modified versions (using `read_mmfile`, for example);
-3. calls ll_merge();
-4. reads the output from result_buf.ptr and result_buf.size;
-5. releases buffers when finished (free(ancestor.ptr); free(ours.ptr);
-   free(theirs.ptr); free(result_buf.ptr);).
+* Prepare a `struct ll_merge_options` to record options.
+  If you have no special requests, skip this and pass `NULL`
+  as the `opts` parameter to use the default options.
+
+* Allocate an mmbuffer_t variable for the result.
+
+* Allocate and fill variables with the file's original content
+  and two modified versions (using `read_mmfile`, for example).
+
+* Call `ll_merge()`.
+
+* Read the merged content from `result_buf.ptr` and `result_buf.size`.
+
+* Release buffers when finished.  A simple
+  `free(ancestor.ptr); free(ours.ptr); free(theirs.ptr);
+  free(result_buf.ptr);` will do.
 
 If the modifications do not merge cleanly, `ll_merge` will return a
 nonzero value and `result_buf` will generally include a description of
@@ -47,18 +90,6 @@ The `ancestor_label`, `our_label`, and `their_label` parameters are
 used to label the different sides of a conflict if the merge driver
 supports this.
 
-The `flag` parameter is a bitfield:
-
- - The `LL_OPT_VIRTUAL_ANCESTOR` bit indicates whether this is an
-   internal merge to consolidate ancestors for a recursive merge.
-
- - The `LL_OPT_FAVOR_MASK` bits allow local conflicts to be automatically
-   resolved in favor of one side or the other (as in 'git merge-file'
-   `--ours`/`--theirs`/`--union`).
-   They can be populated by `create_ll_flag`, whose argument can be
-   `XDL_MERGE_FAVOR_OURS`, `XDL_MERGE_FAVOR_THEIRS`, or
-   `XDL_MERGE_FAVOR_UNION`.
-
 Everything else
 ---------------
 
diff --git a/Documentation/technical/api-sigchain.txt b/Documentation/technical/api-sigchain.txt
new file mode 100644 (file)
index 0000000..535cdff
--- /dev/null
@@ -0,0 +1,41 @@
+sigchain API
+============
+
+Code often wants to set a signal handler to clean up temporary files or
+other work-in-progress when we die unexpectedly. For multiple pieces of
+code to do this without conflicting, each piece of code must remember
+the old value of the handler and restore it either when:
+
+  1. The work-in-progress is finished, and the handler is no longer
+     necessary. The handler should revert to the original behavior
+     (either another handler, SIG_DFL, or SIG_IGN).
+
+  2. The signal is received. We should then do our cleanup, then chain
+     to the next handler (or die if it is SIG_DFL).
+
+Sigchain is a tiny library for keeping a stack of handlers. Your handler
+and installation code should look something like:
+
+------------------------------------------
+  void clean_foo_on_signal(int sig)
+  {
+         clean_foo();
+         sigchain_pop(sig);
+         raise(sig);
+  }
+
+  void other_func()
+  {
+         sigchain_push_common(clean_foo_on_signal);
+         mess_up_foo();
+         clean_foo();
+  }
+------------------------------------------
+
+Handlers are given the typdef 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.
+
+You can sigchain_push and sigchain_pop individual signals. For
+convenience, sigchain_push_common will push the handler onto the stack
+for many common signals.
index fecc4eb5b3b853f4781c769fff8337e8bb6c3500..fc56da677cb0ed3d9243bfb928686b60df213243 100644 (file)
@@ -397,7 +397,7 @@ is usually a shortcut for the HEAD branch in the repository "origin".
 For the complete list of paths which git checks for references, and
 the order it uses to decide which to choose when there are multiple
 references with the same shorthand name, see the "SPECIFYING
-REVISIONS" section of linkgit:gitrevisions[1].
+REVISIONS" section of linkgit:gitrevisions[7].
 
 [[Updating-a-repository-With-git-fetch]]
 Updating a repository with git fetch
@@ -568,7 +568,7 @@ We have seen several ways of naming commits already:
        - HEAD: refers to the head of the current branch
 
 There are many more; see the "SPECIFYING REVISIONS" section of the
-linkgit:gitrevisions[1] man page for the complete list of ways to
+linkgit:gitrevisions[7] man page for the complete list of ways to
 name revisions.  Some examples:
 
 -------------------------------------------------
@@ -909,7 +909,7 @@ commits reachable from some head but not from any tag in the repository:
 $ gitk $( git show-ref --heads ) --not  $( git show-ref --tags )
 -------------------------------------------------
 
-(See linkgit:gitrevisions[1] for explanations of commit-selecting
+(See linkgit:gitrevisions[7] for explanations of commit-selecting
 syntax such as `--not`.)
 
 [[making-a-release]]
@@ -955,7 +955,7 @@ echo "git diff --stat --summary -M v$last v$new > ../diffstat-$new"
 and then he just cut-and-pastes the output commands after verifying that
 they look OK.
 
-[[Finding-comments-With-given-Content]]
+[[Finding-commits-With-given-Content]]
 Finding commits referencing a file with given content
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -1635,7 +1635,7 @@ you've checked out.
 The reflogs are kept by default for 30 days, after which they may be
 pruned.  See linkgit:git-reflog[1] and linkgit:git-gc[1] to learn
 how to control this pruning, and see the "SPECIFYING REVISIONS"
-section of linkgit:gitrevisions[1] for details.
+section of linkgit:gitrevisions[7] for details.
 
 Note that the reflog history is very different from normal git history.
 While normal history is shared by every repository that works on the
@@ -2171,11 +2171,14 @@ $ git push mytree release
 
 Now to apply some patches from the community.  Think of a short
 snappy name for a branch to hold this patch (or related group of
-patches), and create a new branch from the current tip of Linus's
-branch:
+patches), and create a new branch from a recent stable tag of
+Linus's branch. Picking a stable base for your branch will:
+1) help you: by avoiding inclusion of unrelated and perhaps lightly
+tested changes
+2) help future bug hunters that use "git bisect" to find problems
 
 -------------------------------------------------
-$ git checkout -b speed-up-spinlocks origin
+$ git checkout -b speed-up-spinlocks v2.6.35
 -------------------------------------------------
 
 Now you apply the patch(es), run some tests, and commit the change(s).  If
@@ -2439,9 +2442,9 @@ You have performed no merges into mywork, so it is just a simple linear
 sequence of patches on top of "origin":
 
 ................................................
- o--o--o <-- origin
+ o--o--O <-- origin
         \
-         o--o--o <-- mywork
+        a--b--c <-- mywork
 ................................................
 
 Some more interesting work has been done in the upstream project, and
@@ -3850,7 +3853,7 @@ You create a commit object by giving it the tree that describes the
 state at the time of the commit, and a list of parents:
 
 -------------------------------------------------
-$ git commit-tree <tree> -p <parent> [-p <parent2> ..]
+$ git commit-tree <tree> -p <parent> [(-p <parent2>)...]
 -------------------------------------------------
 
 and then giving the reason for the commit on stdin (either through
index ac9c4dbf2fe692fa8385c2d2c54f4122339204de..d441d88d6fbd6d98bb617e5cf5d2bd7704f86a45 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.3
+DEF_VER=v1.7.3.GIT
 
 LF='
 '
diff --git a/INSTALL b/INSTALL
index 59200b730ec00a63f981691f7fd37f2eacb11653..10a1cba643cc9e6cc9a441708b1d43f468fb8383 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -67,10 +67,10 @@ Issues of note:
        - A POSIX-compliant shell is required to run many scripts needed
          for everyday use (e.g. "bisect", "pull").
 
-       - "Perl" is needed to use some of the features (e.g. preparing a
-         partial commit using "git add -i/-p", interacting with svn
-         repositories with "git svn").  If you can live without these, use
-         NO_PERL.
+       - "Perl" version 5.8 or later is needed to use some of the
+         features (e.g. preparing a partial commit using "git add -i/-p",
+         interacting with svn repositories with "git svn").  If you can
+         live without these, use NO_PERL.
 
        - "openssl" library is used by git-imap-send to use IMAP over SSL.
          If you don't need it, use NO_OPENSSL.
index b7a62cfdf2ca4f05e47d69332976adabb73583e9..1f1ce04edf0b87f6fdbd579052d5ccaa538e6b93 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -270,6 +270,7 @@ STRIP ?= strip
 #   infodir
 #   htmldir
 #   ETC_GITCONFIG (but not sysconfdir)
+#   ETC_GITATTRIBUTES
 # can be specified as a relative path some/where/else;
 # this is interpreted as relative to $(prefix) and "git" at
 # runtime figures out where they are based on the path to the executable.
@@ -288,9 +289,11 @@ htmldir = share/doc/git-doc
 ifeq ($(prefix),/usr)
 sysconfdir = /etc
 ETC_GITCONFIG = $(sysconfdir)/gitconfig
+ETC_GITATTRIBUTES = $(sysconfdir)/gitattributes
 else
 sysconfdir = $(prefix)/etc
 ETC_GITCONFIG = etc/gitconfig
+ETC_GITATTRIBUTES = etc/gitattributes
 endif
 lib = lib
 # DESTDIR=
@@ -390,6 +393,8 @@ SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
          $(patsubst %.py,%,$(SCRIPT_PYTHON)) \
          git-instaweb
 
+ETAGS_TARGET = TAGS
+
 # Empty...
 EXTRA_PROGRAMS =
 
@@ -1122,6 +1127,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
        NO_REGEX = YesPlease
        NO_PYTHON = YesPlease
        BLK_SHA1 = YesPlease
+       ETAGS_TARGET = ETAGS
        COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat -Icompat/fnmatch -Icompat/win32
        COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
        COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o \
@@ -1520,6 +1526,7 @@ endif
 
 SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER))
 ETC_GITCONFIG_SQ = $(subst ','\'',$(ETC_GITCONFIG))
+ETC_GITATTRIBUTES_SQ = $(subst ','\'',$(ETC_GITATTRIBUTES))
 
 DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
 bindir_SQ = $(subst ','\'',$(bindir))
@@ -1898,6 +1905,8 @@ builtin/init-db.s builtin/init-db.o: EXTRA_CPPFLAGS = \
 
 config.s config.o: EXTRA_CPPFLAGS = -DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"'
 
+attr.s attr.o: EXTRA_CPPFLAGS = -DETC_GITATTRIBUTES='"$(ETC_GITATTRIBUTES_SQ)"'
+
 http.s http.o: EXTRA_CPPFLAGS = -DGIT_HTTP_USER_AGENT='"git/$(GIT_VERSION)"'
 
 ifdef NO_EXPAT
@@ -1961,11 +1970,11 @@ info:
 pdf:
        $(MAKE) -C Documentation pdf
 
-TAGS:
-       $(RM) TAGS
-       $(FIND) . -name '*.[hcS]' -print | xargs etags -a
+$(ETAGS_TARGET): FORCE
+       $(RM) $(ETAGS_TARGET)
+       $(FIND) . -name '*.[hcS]' -print | xargs etags -a -o $(ETAGS_TARGET)
 
-tags:
+tags: FORCE
        $(RM) tags
        $(FIND) . -name '*.[hcS]' -print | xargs ctags -a
 
@@ -1974,7 +1983,7 @@ cscope:
        $(FIND) . -name '*.[hcS]' -print | xargs cscope -b
 
 ### Detect prefix changes
-TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
+TRACK_CFLAGS = $(CC):$(subst ','\'',$(ALL_CFLAGS)):\
              $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ)
 
 GIT-CFLAGS: FORCE
@@ -2235,7 +2244,7 @@ clean:
        $(RM) $(TEST_PROGRAMS)
        $(RM) -r bin-wrappers
        $(RM) -r $(dep_dirs)
-       $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags cscope*
+       $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h $(ETAGS_TARGET) tags cscope*
        $(RM) -r autom4te.cache
        $(RM) config.log config.mak.autogen config.mak.append config.status config.cache
        $(RM) -r $(GIT_TARNAME) .doc-tmp-dir
@@ -2259,7 +2268,7 @@ endif
 
 .PHONY: all install clean strip
 .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
-.PHONY: FORCE TAGS tags cscope
+.PHONY: FORCE cscope
 
 ### Check documentation
 #
index 8c65931ff4d966ea7c76cdfa1fcb000c97ab1c19..b942e499449d97aeb50c73ca2bdc1c6e6d528743 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.7.3.txt
\ No newline at end of file
+Documentation/RelNotes/1.7.4.txt
\ No newline at end of file
index c91a29cb298a3ad792ff8745f3e8e0eb28d71678..91ca00f05f7d648fa801a36b78c749f9d691ba43 100644 (file)
--- a/abspath.c
+++ b/abspath.c
@@ -108,10 +108,14 @@ const char *make_nonrelative_path(const char *path)
                if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
                        die("Too long path: %.*s", 60, path);
        } else {
+               size_t len;
+               const char *fmt;
                const char *cwd = get_pwd_cwd();
                if (!cwd)
                        die_errno("Cannot determine the current working directory");
-               if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX)
+               len = strlen(cwd);
+               fmt = (len > 0 && is_dir_sep(cwd[len-1])) ? "%s%s" : "%s/%s";
+               if (snprintf(buf, PATH_MAX, fmt, cwd, path) >= PATH_MAX)
                        die("Too long path: %.*s", 60, path);
        }
        return buf;
index edd68534fa847ad839fe8554e6864b39de4fcde0..f59afda6ffda02920a50cabe1eb3e764221199ba 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -7,9 +7,9 @@
 #include "unpack-trees.h"
 
 static char const * const archive_usage[] = {
-       "git archive [options] <tree-ish> [path...]",
+       "git archive [options] <tree-ish> [<path>...]",
        "git archive --list",
-       "git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [path...]",
+       "git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]",
        "git archive --remote <repo> [--exec <cmd>] --list",
        NULL
 };
diff --git a/attr.c b/attr.c
index 8ba606c933088e27ac08aabb546b764745f8187e..6aff6951d38d7f672aeb9851eca88c6e5a26b950 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -1,5 +1,6 @@
 #define NO_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
+#include "exec_cmd.h"
 #include "attr.h"
 
 const char git_attr__true[] = "(builtin)true";
@@ -10,6 +11,8 @@ static const char git_attr__unknown[] = "(builtin)unknown";
 #define ATTR__UNSET NULL
 #define ATTR__UNKNOWN git_attr__unknown
 
+static const char *attributes_file;
+
 /*
  * The basic design decision here is that we are not going to have
  * insanely large number of attributes.
@@ -462,6 +465,32 @@ static void drop_attr_stack(void)
        }
 }
 
+const char *git_etc_gitattributes(void)
+{
+       static const char *system_wide;
+       if (!system_wide)
+               system_wide = system_path(ETC_GITATTRIBUTES);
+       return system_wide;
+}
+
+int git_attr_system(void)
+{
+       return !git_env_bool("GIT_ATTR_NOSYSTEM", 0);
+}
+
+int git_attr_global(void)
+{
+       return !git_env_bool("GIT_ATTR_NOGLOBAL", 0);
+}
+
+static int git_attr_config(const char *var, const char *value, void *dummy)
+{
+       if (!strcmp(var, "core.attributesfile"))
+               return git_config_pathname(&attributes_file, var, value);
+
+       return 0;
+}
+
 static void bootstrap_attr_stack(void)
 {
        if (!attr_stack) {
@@ -472,6 +501,25 @@ static void bootstrap_attr_stack(void)
                elem->prev = attr_stack;
                attr_stack = elem;
 
+               if (git_attr_system()) {
+                       elem = read_attr_from_file(git_etc_gitattributes(), 1);
+                       if (elem) {
+                               elem->origin = NULL;
+                               elem->prev = attr_stack;
+                               attr_stack = elem;
+                       }
+               }
+
+               git_config(git_attr_config, NULL);
+               if (git_attr_global() && attributes_file) {
+                       elem = read_attr_from_file(attributes_file, 1);
+                       if (elem) {
+                               elem->origin = NULL;
+                               elem->prev = attr_stack;
+                               attr_stack = elem;
+                       }
+               }
+
                if (!is_bare_repository() || direction == GIT_ATTR_INDEX) {
                        elem = read_attr(GITATTRIBUTES_FILE, 1);
                        elem->origin = strdup("");
@@ -499,7 +547,9 @@ static void prepare_attr_stack(const char *path, int dirlen)
 
        /*
         * At the bottom of the attribute stack is the built-in
-        * set of attribute definitions.  Then, contents from
+        * set of attribute definitions, followed by the contents
+        * of $(prefix)/etc/gitattributes and a file specified by
+        * core.attributesfile.  Then, contents from
         * .gitattribute files from directories closer to the
         * root to the ones in deeper directories are pushed
         * to the stack.  Finally, at the very top of the stack
index 0398d247400e55f2a2ededc054902374c7516d5b..8dd4569b3c06654826c298b6b52dcf2ac17481bb 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -7,14 +7,15 @@
 #include "commit.h"
 #include "notes.h"
 
+#define DEFAULT_MERGE_LOG_LEN 20
+
 extern const char git_version_string[];
 extern const char git_usage_string[];
 extern const char git_more_info_string[];
 
 extern void prune_packed_objects(int);
-extern int fmt_merge_msg(int merge_summary, struct strbuf *in,
-       struct strbuf *out);
-extern int fmt_merge_msg_shortlog(struct strbuf *in, struct strbuf *out);
+extern int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
+                        int merge_title, int shortlog_len);
 extern int commit_notes(struct notes_tree *t, const char *msg);
 
 struct notes_rewrite_cfg {
@@ -35,7 +36,7 @@ void finish_copy_notes_for_rewrite(struct notes_rewrite_cfg *c);
 
 extern int check_pager_config(const char *cmd);
 
-extern int textconv_object(const char *path, const unsigned char *sha1, char **buf, unsigned long *buf_size);
+extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, char **buf, unsigned long *buf_size);
 
 extern int cmd_add(int argc, const char **argv, const char *prefix);
 extern int cmd_annotate(int argc, const char **argv, const char *prefix);
index 23c18c573b9147b7aaa88a8d1d2f26748e803501..f051e66dcc5260e4e7ecb28c36e2c6da8e823d6b 100644 (file)
@@ -2645,6 +2645,12 @@ static int apply_binary_fragment(struct image *img, struct patch *patch)
        unsigned long len;
        void *dst;
 
+       if (!fragment)
+               return error("missing binary patch data for '%s'",
+                            patch->new_name ?
+                            patch->new_name :
+                            patch->old_name);
+
        /* Binary patch is irreversible without the optional second hunk */
        if (apply_in_reverse) {
                if (!fragment->next)
index 101535448f2b0405c280387b63f7ce82fb7dd350..f5fccc1f6767d7386e37f7273c560d0d4491ee91 100644 (file)
@@ -83,6 +83,7 @@ struct origin {
        struct commit *commit;
        mmfile_t file;
        unsigned char blob_sha1[20];
+       unsigned mode;
        char path[FLEX_ARRAY];
 };
 
@@ -92,6 +93,7 @@ struct origin {
  * Return 1 if the conversion succeeds, 0 otherwise.
  */
 int textconv_object(const char *path,
+                   unsigned mode,
                    const unsigned char *sha1,
                    char **buf,
                    unsigned long *buf_size)
@@ -100,7 +102,7 @@ int textconv_object(const char *path,
        struct userdiff_driver *textconv;
 
        df = alloc_filespec(path);
-       fill_filespec(df, sha1, S_IFREG | 0664);
+       fill_filespec(df, sha1, mode);
        textconv = get_textconv(df);
        if (!textconv) {
                free_filespec(df);
@@ -125,7 +127,7 @@ static void fill_origin_blob(struct diff_options *opt,
 
                num_read_blob++;
                if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
-                   textconv_object(o->path, o->blob_sha1, &file->ptr, &file_size))
+                   textconv_object(o->path, o->mode, o->blob_sha1, &file->ptr, &file_size))
                        ;
                else
                        file->ptr = read_sha1_file(o->blob_sha1, &type, &file_size);
@@ -313,21 +315,23 @@ static struct origin *get_origin(struct scoreboard *sb,
  * for an origin is also used to pass the blame for the entire file to
  * the parent to detect the case where a child's blob is identical to
  * that of its parent's.
+ *
+ * This also fills origin->mode for corresponding tree path.
  */
-static int fill_blob_sha1(struct origin *origin)
+static int fill_blob_sha1_and_mode(struct origin *origin)
 {
-       unsigned mode;
        if (!is_null_sha1(origin->blob_sha1))
                return 0;
        if (get_tree_entry(origin->commit->object.sha1,
                           origin->path,
-                          origin->blob_sha1, &mode))
+                          origin->blob_sha1, &origin->mode))
                goto error_out;
        if (sha1_object_info(origin->blob_sha1, NULL) != OBJ_BLOB)
                goto error_out;
        return 0;
  error_out:
        hashclr(origin->blob_sha1);
+       origin->mode = S_IFINVALID;
        return -1;
 }
 
@@ -360,12 +364,14 @@ static struct origin *find_origin(struct scoreboard *sb,
                        /*
                         * If the origin was newly created (i.e. get_origin
                         * would call make_origin if none is found in the
-                        * scoreboard), it does not know the blob_sha1,
+                        * scoreboard), it does not know the blob_sha1/mode,
                         * so copy it.  Otherwise porigin was in the
-                        * scoreboard and already knows blob_sha1.
+                        * scoreboard and already knows blob_sha1/mode.
                         */
-                       if (porigin->refcnt == 1)
+                       if (porigin->refcnt == 1) {
                                hashcpy(porigin->blob_sha1, cached->blob_sha1);
+                               porigin->mode = cached->mode;
+                       }
                        return porigin;
                }
                /* otherwise it was not very useful; free it */
@@ -400,6 +406,7 @@ static struct origin *find_origin(struct scoreboard *sb,
                /* The path is the same as parent */
                porigin = get_origin(sb, parent, origin->path);
                hashcpy(porigin->blob_sha1, origin->blob_sha1);
+               porigin->mode = origin->mode;
        } else {
                /*
                 * Since origin->path is a pathspec, if the parent
@@ -425,6 +432,7 @@ static struct origin *find_origin(struct scoreboard *sb,
                case 'M':
                        porigin = get_origin(sb, parent, origin->path);
                        hashcpy(porigin->blob_sha1, p->one->sha1);
+                       porigin->mode = p->one->mode;
                        break;
                case 'A':
                case 'T':
@@ -444,6 +452,7 @@ static struct origin *find_origin(struct scoreboard *sb,
 
                cached = make_origin(porigin->commit, porigin->path);
                hashcpy(cached->blob_sha1, porigin->blob_sha1);
+               cached->mode = porigin->mode;
                parent->util = cached;
        }
        return porigin;
@@ -486,6 +495,7 @@ static struct origin *find_rename(struct scoreboard *sb,
                    !strcmp(p->two->path, origin->path)) {
                        porigin = get_origin(sb, parent, p->one->path);
                        hashcpy(porigin->blob_sha1, p->one->sha1);
+                       porigin->mode = p->one->mode;
                        break;
                }
        }
@@ -1099,6 +1109,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
 
                        norigin = get_origin(sb, parent, p->one->path);
                        hashcpy(norigin->blob_sha1, p->one->sha1);
+                       norigin->mode = p->one->mode;
                        fill_origin_blob(&sb->revs->diffopt, norigin, &file_p);
                        if (!file_p.ptr)
                                continue;
@@ -2075,7 +2086,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
                switch (st.st_mode & S_IFMT) {
                case S_IFREG:
                        if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
-                           textconv_object(read_from, null_sha1, &buf.buf, &buf_len))
+                           textconv_object(read_from, mode, null_sha1, &buf.buf, &buf_len))
                                buf.len = buf_len;
                        else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
                                die_errno("cannot open or read '%s'", read_from);
@@ -2455,11 +2466,11 @@ parse_done:
        }
        else {
                o = get_origin(&sb, sb.final, path);
-               if (fill_blob_sha1(o))
+               if (fill_blob_sha1_and_mode(o))
                        die("no such path %s in %s", path, final_commit_name);
 
                if (DIFF_OPT_TST(&sb.revs->diffopt, ALLOW_TEXTCONV) &&
-                   textconv_object(path, o->blob_sha1, (char **) &sb.final_buf,
+                   textconv_object(path, o->mode, o->blob_sha1, (char **) &sb.final_buf,
                                    &sb.final_buf_size))
                        ;
                else
index 80649ba0b28846d09b49a791dd25af9a2907f75f..9b87fb9ac2505e746ae34db34740cdfb3cfde127 100644 (file)
@@ -12,8 +12,8 @@
 static const char builtin_bundle_usage[] =
   "git bundle create <file> <git-rev-list args>\n"
   "   or: git bundle verify <file>\n"
-  "   or: git bundle list-heads <file> [refname...]\n"
-  "   or: git bundle unbundle <file> [refname...]";
+  "   or: git bundle list-heads <file> [<refname>...]\n"
+  "   or: git bundle unbundle <file> [<refname>...]";
 
 int cmd_bundle(int argc, const char **argv, const char *prefix)
 {
index 76ec3fec9279f38520fa4b5b525ce2c03cc9cbb0..94632dbdb400f9a2986d10f06dd16119ce1b4e54 100644 (file)
@@ -143,7 +143,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
                        die("git cat-file --textconv %s: <object> must be <sha1:path>",
                            obj_name);
 
-               if (!textconv_object(obj_context.path, sha1, &buf, &size))
+               if (!textconv_object(obj_context.path, obj_context.mode, sha1, &buf, &size))
                        die("git cat-file --textconv: unable to run textconv on %s",
                            obj_name);
                break;
index a7a5ee10f32d52c7555f85f2dcf6c567425488dd..65cbee0552b8e2d5ed7cfd57781031d72c1cdd98 100644 (file)
@@ -155,7 +155,7 @@ static void checkout_all(const char *prefix, int prefix_length)
 }
 
 static const char * const builtin_checkout_index_usage[] = {
-       "git checkout-index [options] [--] <file>...",
+       "git checkout-index [options] [--] [<file>...]",
        NULL
 };
 
index 560eae17159290c5adcefd2e2e2da5825ac6b75d..9240fafb2ad17505bf407363e058d208a8a70497 100644 (file)
@@ -161,7 +161,7 @@ static int checkout_merged(int pos, struct checkout *state)
         * merge.renormalize set, too
         */
        status = ll_merge(&result_buf, path, &ancestor, "base",
-                         &ours, "ours", &theirs, "theirs", 0);
+                         &ours, "ours", &theirs, "theirs", NULL);
        free(ancestor.ptr);
        free(ours.ptr);
        free(theirs.ptr);
@@ -691,16 +691,16 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                           "create and checkout a new branch"),
                OPT_STRING('B', NULL, &opts.new_branch_force, "branch",
                           "create/reset and checkout a branch"),
-               OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "log for new branch"),
-               OPT_SET_INT('t', "track",  &opts.track, "track",
+               OPT_BOOLEAN('l', NULL, &opts.new_branch_log, "create reflog for new branch"),
+               OPT_SET_INT('t', "track",  &opts.track, "set upstream info for new branch",
                        BRANCH_TRACK_EXPLICIT),
                OPT_STRING(0, "orphan", &opts.new_orphan_branch, "new branch", "new unparented branch"),
-               OPT_SET_INT('2', "ours", &opts.writeout_stage, "stage",
+               OPT_SET_INT('2', "ours", &opts.writeout_stage, "checkout our version for unmerged files",
                            2),
-               OPT_SET_INT('3', "theirs", &opts.writeout_stage, "stage",
+               OPT_SET_INT('3', "theirs", &opts.writeout_stage, "checkout their version for unmerged files",
                            3),
-               OPT_BOOLEAN('f', "force", &opts.force, "force"),
-               OPT_BOOLEAN('m', "merge", &opts.merge, "merge"),
+               OPT_BOOLEAN('f', "force", &opts.force, "force checkout (throw away local modifications)"),
+               OPT_BOOLEAN('m', "merge", &opts.merge, "perform a 3-way merge with the new branch"),
                OPT_STRING(0, "conflict", &conflict_style, "style",
                           "conflict style (merge or diff3)"),
                OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks interactively"),
index c8798f549ed12192a098ab90b35c0437b8059351..fb24030751ec5e755009a97439ffa08ff55f67d5 100644 (file)
@@ -38,7 +38,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
 {
        int i;
        int show_only = 0, remove_directories = 0, quiet = 0, ignored = 0;
-       int ignored_only = 0, baselen = 0, config_set = 0, errors = 0;
+       int ignored_only = 0, config_set = 0, errors = 0;
        int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
        struct strbuf directory = STRBUF_INIT;
        struct dir_struct dir;
@@ -138,7 +138,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
                if (pathspec) {
                        memset(seen, 0, argc > 0 ? argc : 1);
                        matches = match_pathspec(pathspec, ent->name, len,
-                                                baselen, seen);
+                                                0, seen);
                }
 
                if (S_ISDIR(st.st_mode)) {
@@ -153,7 +153,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
                                        printf("Removing %s\n", qname);
                                if (remove_dir_recursively(&directory,
                                                           rm_flags) != 0) {
-                                       warning("failed to remove '%s'", qname);
+                                       warning("failed to remove %s", qname);
                                        errors++;
                                }
                        } else if (show_only) {
@@ -173,7 +173,7 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
                                printf("Removing %s\n", qname);
                        }
                        if (unlink(ent->name) != 0) {
-                               warning("failed to remove '%s'", qname);
+                               warning("failed to remove %s", qname);
                                errors++;
                        }
                }
index 87f0591c2f68a03e06c73b352282426b803450ba..d083795e26e7893c6b7d466f9bcf2be1311cfeb2 100644 (file)
@@ -9,7 +9,7 @@
 #include "builtin.h"
 #include "utf8.h"
 
-static const char commit_tree_usage[] = "git commit-tree <sha1> [-p <sha1>]* < changelog";
+static const char commit_tree_usage[] = "git commit-tree <sha1> [(-p <sha1>)...] < changelog";
 
 static void new_parent(struct commit *parent, struct commit_list **parents_p)
 {
@@ -56,10 +56,12 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
        if (strbuf_read(&buffer, 0, 0) < 0)
                die_errno("git commit-tree: failed to read");
 
-       if (!commit_tree(buffer.buf, tree_sha1, parents, commit_sha1, NULL)) {
-               printf("%s\n", sha1_to_hex(commit_sha1));
-               return 0;
-       }
-       else
+       if (commit_tree(buffer.buf, tree_sha1, parents, commit_sha1, NULL)) {
+               strbuf_release(&buffer);
                return 1;
+       }
+
+       printf("%s\n", sha1_to_hex(commit_sha1));
+       strbuf_release(&buffer);
+       return 0;
 }
index 6fc50477031c9c9f7be01fee7d90266c67b38c79..d35f000c034964ed600b1d8d45e2ef9260abcfb6 100644 (file)
@@ -16,7 +16,7 @@
 static const char * const builtin_fetch_usage[] = {
        "git fetch [<options>] [<repository> [<refspec>...]]",
        "git fetch [<options>] <group>",
-       "git fetch --multiple [<options>] [<repository> | <group>]...",
+       "git fetch --multiple [<options>] [(<repository> | <group>)...]",
        "git fetch --all [<options>]",
        NULL
 };
index e7e12eea250691a2c0d70964d1fffea0923dd292..78c77742b6e6863b1eb4d61750ae253710223aa2 100644 (file)
@@ -7,21 +7,22 @@
 #include "string-list.h"
 
 static const char * const fmt_merge_msg_usage[] = {
-       "git fmt-merge-msg [-m <message>] [--log|--no-log] [--file <file>]",
+       "git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]",
        NULL
 };
 
-static int merge_summary;
+static int shortlog_len;
 
 static int fmt_merge_msg_config(const char *key, const char *value, void *cb)
 {
-       static int found_merge_log = 0;
-       if (!strcmp("merge.log", key)) {
-               found_merge_log = 1;
-               merge_summary = git_config_bool(key, value);
+       if (!strcmp(key, "merge.log") || !strcmp(key, "merge.summary")) {
+               int is_bool;
+               shortlog_len = git_config_bool_or_int(key, value, &is_bool);
+               if (!is_bool && shortlog_len < 0)
+                       return error("%s: negative length %s", key, value);
+               if (is_bool && shortlog_len)
+                       shortlog_len = DEFAULT_MERGE_LOG_LEN;
        }
-       if (!found_merge_log && !strcmp("merge.summary", key))
-               merge_summary = git_config_bool(key, value);
        return 0;
 }
 
@@ -255,9 +256,9 @@ static void do_fmt_merge_msg_title(struct strbuf *out,
                strbuf_addf(out, " into %s\n", current_branch);
 }
 
-static int do_fmt_merge_msg(int merge_title, int merge_summary,
-       struct strbuf *in, struct strbuf *out) {
-       int limit = 20, i = 0, pos = 0;
+static int do_fmt_merge_msg(int merge_title, struct strbuf *in,
+       struct strbuf *out, int shortlog_len) {
+       int i = 0, pos = 0;
        unsigned char head_sha1[20];
        const char *current_branch;
 
@@ -288,7 +289,7 @@ static int do_fmt_merge_msg(int merge_title, int merge_summary,
        if (merge_title)
                do_fmt_merge_msg_title(out, current_branch);
 
-       if (merge_summary) {
+       if (shortlog_len) {
                struct commit *head;
                struct rev_info rev;
 
@@ -303,17 +304,14 @@ static int do_fmt_merge_msg(int merge_title, int merge_summary,
 
                for (i = 0; i < origins.nr; i++)
                        shortlog(origins.items[i].string, origins.items[i].util,
-                                       head, &rev, limit, out);
+                                       head, &rev, shortlog_len, out);
        }
        return 0;
 }
 
-int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
-       return do_fmt_merge_msg(1, merge_summary, in, out);
-}
-
-int fmt_merge_msg_shortlog(struct strbuf *in, struct strbuf *out) {
-       return do_fmt_merge_msg(0, 1, in, out);
+int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
+                 int merge_title, int shortlog_len) {
+       return do_fmt_merge_msg(merge_title, in, out, shortlog_len);
 }
 
 int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
@@ -321,10 +319,13 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
        const char *inpath = NULL;
        const char *message = NULL;
        struct option options[] = {
-               OPT_BOOLEAN(0, "log",     &merge_summary, "populate log with the shortlog"),
-               { OPTION_BOOLEAN, 0, "summary", &merge_summary, NULL,
+               { OPTION_INTEGER, 0, "log", &shortlog_len, "n",
+                 "populate log with at most <n> entries from shortlog",
+                 PARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN },
+               { OPTION_INTEGER, 0, "summary", &shortlog_len, "n",
                  "alias for --log (deprecated)",
-                 PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
+                 PARSE_OPT_OPTARG | PARSE_OPT_HIDDEN, NULL,
+                 DEFAULT_MERGE_LOG_LEN },
                OPT_STRING('m', "message", &message, "text",
                        "use <text> as start of message"),
                OPT_FILENAME('F', "file", &inpath, "file to read from"),
@@ -340,12 +341,14 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
                             0);
        if (argc > 0)
                usage_with_options(fmt_merge_msg_usage, options);
-       if (message && !merge_summary) {
+       if (message && !shortlog_len) {
                char nl = '\n';
                write_in_full(STDOUT_FILENO, message, strlen(message));
                write_in_full(STDOUT_FILENO, &nl, 1);
                return 0;
        }
+       if (shortlog_len < 0)
+               die("Negative --log=%d", shortlog_len);
 
        if (inpath && strcmp(inpath, "-")) {
                in = fopen(inpath, "r");
@@ -355,12 +358,13 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
 
        if (strbuf_read(&input, fileno(in), 0) < 0)
                die_errno("could not read input file");
-       if (message) {
+
+       if (message)
                strbuf_addstr(&output, message);
-               ret = fmt_merge_msg_shortlog(&input, &output);
-       } else {
-               ret = fmt_merge_msg(merge_summary, &input, &output);
-       }
+       ret = fmt_merge_msg(&input, &output,
+                           message ? 0 : 1,
+                           shortlog_len);
+
        if (ret)
                return ret;
        write_in_full(STDOUT_FILENO, output.buf, output.len);
index da32f3df34da7af3cdcb0a9dd6aa66061bdfe927..3d5f6ace97b806fd7dba9f8c5d62abcdbd903681 100644 (file)
@@ -24,7 +24,7 @@
 #endif
 
 static char const * const grep_usage[] = {
-       "git grep [options] [-e] <pattern> [<rev>...] [[--] path...]",
+       "git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]",
        NULL
 };
 
index 2e680d7a7ac3495c9d6bd10e0fa6a6ae28bb8670..8dc5c0b5410d4bb57607bab690126f22d954dd7a 100644 (file)
@@ -11,7 +11,7 @@
 #include "exec_cmd.h"
 
 static const char index_pack_usage[] =
-"git index-pack [-v] [-o <index-file>] [{ --keep | --keep=<msg> }] [--strict] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }";
+"git index-pack [-v] [-o <index-file>] [ --keep | --keep=<msg> ] [--strict] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
 
 struct object_entry
 {
@@ -161,7 +161,7 @@ static void use(int bytes)
        input_offset += bytes;
 
        /* make sure off_t is sufficiently large not to wrap */
-       if (consumed_bytes > consumed_bytes + bytes)
+       if (signed_add_overflows(consumed_bytes, bytes))
                die("pack too large for current definition of off_t");
        consumed_bytes += bytes;
 }
index 0271285fad6ad532a6133838f7188498476fd77b..9d4886c71675f2bc50671ea284875ebae9a34735 100644 (file)
@@ -294,11 +294,26 @@ static int create_default_files(const char *template_path)
        return reinit;
 }
 
+static void create_object_directory(void)
+{
+       const char *object_directory = get_object_directory();
+       int len = strlen(object_directory);
+       char *path = xmalloc(len + 40);
+
+       memcpy(path, object_directory, len);
+
+       safe_create_dir(object_directory, 1);
+       strcpy(path+len, "/pack");
+       safe_create_dir(path, 1);
+       strcpy(path+len, "/info");
+       safe_create_dir(path, 1);
+
+       free(path);
+}
+
 int init_db(const char *template_dir, unsigned int flags)
 {
-       const char *sha1_dir;
-       char *path;
-       int len, reinit;
+       int reinit;
 
        safe_create_dir(get_git_dir(), 0);
 
@@ -313,16 +328,7 @@ int init_db(const char *template_dir, unsigned int flags)
 
        reinit = create_default_files(template_dir);
 
-       sha1_dir = get_object_directory();
-       len = strlen(sha1_dir);
-       path = xmalloc(len + 40);
-       memcpy(path, sha1_dir, len);
-
-       safe_create_dir(sha1_dir, 1);
-       strcpy(path+len, "/pack");
-       safe_create_dir(path, 1);
-       strcpy(path+len, "/info");
-       safe_create_dir(path, 1);
+       create_object_directory();
 
        if (shared_repository) {
                char buf[10];
index eaa1ee0fa71a344af747dec038c6a5907c8273a5..22d12903ac06597979f30d0fd94267fc543afa29 100644 (file)
@@ -1056,8 +1056,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        rev.commit_format = CMIT_FMT_EMAIL;
        rev.verbose_header = 1;
        rev.diff = 1;
-       rev.combine_merges = 0;
-       rev.ignore_merges = 1;
+       rev.no_merges = 1;
        DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
        rev.subject_prefix = fmt_patch_subject_prefix;
        memset(&s_r_opt, 0, sizeof(s_r_opt));
@@ -1228,10 +1227,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                        continue;
                }
 
-               /* ignore merges */
-               if (commit->parents && commit->parents->next)
-                       continue;
-
                if (ignore_if_in_upstream &&
                                has_commit_patch_id(commit, &ids))
                        continue;
index bb4f612b3d48c453d551f251b65887beb283ec7b..6a307ab784a25c9f8d201392f79c7146a4a8eece 100644 (file)
@@ -424,7 +424,7 @@ int report_path_error(const char *ps_matched, const char **pathspec, int prefix_
 }
 
 static const char * const ls_files_usage[] = {
-       "git ls-files [options] [<file>]*",
+       "git ls-files [options] [<file>...]",
        NULL
 };
 
index a8187568bf99872e717c389b031331838544fe04..f73e6bd9626a0e929a513fed1fd1227c28732ec7 100644 (file)
@@ -24,7 +24,7 @@ static int chomp_prefix;
 static const char *ls_tree_prefix;
 
 static const  char * const ls_tree_usage[] = {
-       "git ls-tree [<options>] <tree-ish> [path...]",
+       "git ls-tree [<options>] <tree-ish> [<path>...]",
        NULL
 };
 
index 99654d02221c13ff98f268ad2dee99f16e794750..2d4327801e4f7766328389311c87dd63d4c5f8e4 100644 (file)
@@ -10,7 +10,7 @@
 #include "strbuf.h"
 
 static const char git_mailsplit_usage[] =
-"git mailsplit [-d<prec>] [-f<n>] [-b] [--keep-cr] -o<directory> [<mbox>|<Maildir>...]";
+"git mailsplit [-d<prec>] [-f<n>] [-b] [--keep-cr] -o<directory> [(<mbox>|<Maildir>)...]";
 
 static int is_from_line(const char *line, int len)
 {
index b6664d49be9454b703615af4e71f92231e053e07..6c4afb5a38bc954be836c441b9b09b22ef82b132 100644 (file)
@@ -28,6 +28,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
        xmparam_t xmp = {{0}};
        int ret = 0, i = 0, to_stdout = 0;
        int quiet = 0;
+       int prefixlen = 0;
        struct option options[] = {
                OPT_BOOLEAN('p', "stdout", &to_stdout, "send results to standard output"),
                OPT_SET_INT(0, "diff3", &xmp.style, "use a diff3 based merge", XDL_MERGE_DIFF3),
@@ -65,10 +66,14 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
                                     "%s\n", strerror(errno));
        }
 
+       if (prefix)
+               prefixlen = strlen(prefix);
+
        for (i = 0; i < 3; i++) {
+               const char *fname = prefix_filename(prefix, prefixlen, argv[i]);
                if (!names[i])
                        names[i] = argv[i];
-               if (read_mmfile(mmfs + i, argv[i]))
+               if (read_mmfile(mmfs + i, fname))
                        return -1;
                if (buffer_is_binary(mmfs[i].ptr, mmfs[i].size))
                        return error("Cannot merge binary files: %s\n",
index 78b9db76a0819529e7f6cab44319acd2978c9e9b..c33091b3ed52bc8539ff82f039ec8c7718f3dcc2 100644 (file)
@@ -2,6 +2,7 @@
 #include "commit.h"
 #include "tag.h"
 #include "merge-recursive.h"
+#include "xdiff-interface.h"
 
 static const char builtin_merge_recursive_usage[] =
        "git %s <base>... -- <head> <remote> ...";
@@ -40,19 +41,7 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
                if (!prefixcmp(arg, "--")) {
                        if (!arg[2])
                                break;
-                       if (!strcmp(arg+2, "ours"))
-                               o.recursive_variant = MERGE_RECURSIVE_OURS;
-                       else if (!strcmp(arg+2, "theirs"))
-                               o.recursive_variant = MERGE_RECURSIVE_THEIRS;
-                       else if (!strcmp(arg+2, "subtree"))
-                               o.subtree_shift = "";
-                       else if (!prefixcmp(arg+2, "subtree="))
-                               o.subtree_shift = arg + 10;
-                       else if (!strcmp(arg+2, "renormalize"))
-                               o.renormalize = 1;
-                       else if (!strcmp(arg+2, "no-renormalize"))
-                               o.renormalize = 0;
-                       else
+                       if (parse_merge_opt(&o, arg + 2))
                                die("Unknown option %s", arg);
                        continue;
                }
index 5f65c0c8a6eacd4c6d05602ad9de2821ec62a034..10f091b51960cd6ae913b1c4d2ab9e6931862351 100644 (file)
@@ -42,7 +42,7 @@ static const char * const builtin_merge_usage[] = {
        NULL
 };
 
-static int show_diffstat = 1, option_log, squash;
+static int show_diffstat = 1, shortlog_len, squash;
 static int option_commit = 1, allow_fast_forward = 1;
 static int fast_forward_only;
 static int allow_trivial = 1, have_message;
@@ -177,8 +177,9 @@ static struct option builtin_merge_options[] = {
        OPT_BOOLEAN(0, "stat", &show_diffstat,
                "show a diffstat at the end of the merge"),
        OPT_BOOLEAN(0, "summary", &show_diffstat, "(synonym to --stat)"),
-       OPT_BOOLEAN(0, "log", &option_log,
-               "add list of one-line log to merge commit message"),
+       { OPTION_INTEGER, 0, "log", &shortlog_len, "n",
+         "add (at most <n>) entries from shortlog to merge commit message",
+         PARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN },
        OPT_BOOLEAN(0, "squash", &squash,
                "create a single commit instead of doing a merge"),
        OPT_BOOLEAN(0, "commit", &option_commit,
@@ -504,10 +505,17 @@ static int git_merge_config(const char *k, const char *v, void *cb)
                return git_config_string(&pull_twohead, k, v);
        else if (!strcmp(k, "pull.octopus"))
                return git_config_string(&pull_octopus, k, v);
-       else if (!strcmp(k, "merge.log") || !strcmp(k, "merge.summary"))
-               option_log = git_config_bool(k, v);
        else if (!strcmp(k, "merge.renormalize"))
                option_renormalize = git_config_bool(k, v);
+       else if (!strcmp(k, "merge.log") || !strcmp(k, "merge.summary")) {
+               int is_bool;
+               shortlog_len = git_config_bool_or_int(k, v, &is_bool);
+               if (!is_bool && shortlog_len < 0)
+                       return error("%s: negative length %s", k, v);
+               if (is_bool && shortlog_len)
+                       shortlog_len = DEFAULT_MERGE_LOG_LEN;
+               return 0;
+       }
        return git_diff_ui_config(k, v, cb);
 }
 
@@ -631,25 +639,9 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
 
                o.renormalize = option_renormalize;
 
-               /*
-                * NEEDSWORK: merge with table in builtin/merge-recursive
-                */
-               for (x = 0; x < xopts_nr; x++) {
-                       if (!strcmp(xopts[x], "ours"))
-                               o.recursive_variant = MERGE_RECURSIVE_OURS;
-                       else if (!strcmp(xopts[x], "theirs"))
-                               o.recursive_variant = MERGE_RECURSIVE_THEIRS;
-                       else if (!strcmp(xopts[x], "subtree"))
-                               o.subtree_shift = "";
-                       else if (!prefixcmp(xopts[x], "subtree="))
-                               o.subtree_shift = xopts[x]+8;
-                       else if (!strcmp(xopts[x], "renormalize"))
-                               o.renormalize = 1;
-                       else if (!strcmp(xopts[x], "no-renormalize"))
-                               o.renormalize = 0;
-                       else
+               for (x = 0; x < xopts_nr; x++)
+                       if (parse_merge_opt(&o, xopts[x]))
                                die("Unknown option for merge-recursive: -X%s", xopts[x]);
-               }
 
                o.branch1 = head_arg;
                o.branch2 = remoteheads->item->util;
@@ -1012,14 +1004,12 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                for (i = 0; i < argc; i++)
                        merge_name(argv[i], &merge_names);
 
-               if (have_message && option_log)
-                       fmt_merge_msg_shortlog(&merge_names, &merge_msg);
-               else if (!have_message)
-                       fmt_merge_msg(option_log, &merge_names, &merge_msg);
-
-
-               if (!(have_message && !option_log) && merge_msg.len)
-                       strbuf_setlen(&merge_msg, merge_msg.len-1);
+               if (!have_message || shortlog_len) {
+                       fmt_merge_msg(&merge_names, &merge_msg, !have_message,
+                                     shortlog_len);
+                       if (merge_msg.len)
+                               strbuf_setlen(&merge_msg, merge_msg.len - 1);
+               }
        }
 
        if (head_invalid || !argc)
index 0e8167311884d38c48a9421bf8aede89e7f2c22d..f8eba53c82242d0c435524ab9ffab70ba2e2d5ad 100644 (file)
 #endif
 
 static const char pack_usage[] =
-  "git pack-objects [{ -q | --progress | --all-progress }]\n"
+  "git pack-objects [ -q | --progress | --all-progress ]\n"
   "        [--all-progress-implied]\n"
-  "        [--max-pack-size=N] [--local] [--incremental]\n"
-  "        [--window=N] [--window-memory=N] [--depth=N]\n"
+  "        [--max-pack-size=<n>] [--local] [--incremental]\n"
+  "        [--window=<n>] [--window-memory=<n>] [--depth=<n>]\n"
   "        [--no-reuse-delta] [--no-reuse-object] [--delta-base-offset]\n"
-  "        [--threads=N] [--non-empty] [--revs [--unpacked | --all]*]\n"
+  "        [--threads=<n>] [--non-empty] [--revs [--unpacked | --all]]\n"
   "        [--reflog] [--stdout | base-name] [--include-tag]\n"
-  "        [--keep-unreachable | --unpack-unreachable \n"
-  "        [<ref-list | <object-list]";
+  "        [--keep-unreachable | --unpack-unreachable]\n"
+  "        [< ref-list | < object-list]";
 
 struct object_entry {
        struct pack_idx_entry idx;
@@ -431,7 +431,7 @@ static int write_one(struct sha1file *f,
        written_list[nr_written++] = &e->idx;
 
        /* make sure off_t is sufficiently large not to wrap */
-       if (*offset > *offset + size)
+       if (signed_add_overflows(*offset, size))
                die("pack too large for current definition of off_t");
        *offset += size;
        return 1;
index 9ad1e66916545dd2aeeb110661e56edfa5921019..eb1e3e7467ac722f4b6cc1da03f7671d21abc676 100644 (file)
@@ -16,6 +16,7 @@
 #include "resolve-undo.h"
 
 static int nr_trees;
+static int read_empty;
 static struct tree *trees[MAX_UNPACK_TREES];
 
 static int list_tree(unsigned char *sha1)
@@ -32,7 +33,7 @@ static int list_tree(unsigned char *sha1)
 }
 
 static const char * const read_tree_usage[] = {
-       "git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--index-output=<file>] <tree-ish1> [<tree-ish2> [<tree-ish3>]]",
+       "git read-tree [[-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>] [-u [--exclude-per-directory=<gitignore>] | -i]] [--no-sparse-checkout] [--index-output=<file>] (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])",
        NULL
 };
 
@@ -106,6 +107,8 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
                { OPTION_CALLBACK, 0, "index-output", NULL, "FILE",
                  "write resulting index to <FILE>",
                  PARSE_OPT_NONEG, index_output_cb },
+               OPT_SET_INT(0, "empty", &read_empty,
+                           "only empty the index", 1),
                OPT__VERBOSE(&opts.verbose_update),
                OPT_GROUP("Merging"),
                OPT_SET_INT('m', NULL, &opts.merge,
@@ -166,6 +169,11 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
                        die("failed to unpack tree object %s", arg);
                stage++;
        }
+       if (nr_trees == 0 && !read_empty)
+               warning("read-tree: emptying the index with no arguments is deprecated; use --empty");
+       else if (nr_trees > 0 && read_empty)
+               die("passing trees as arguments contradicts --empty");
+
        if (1 < opts.index_only + opts.update)
                die("-u and -i at the same time makes no sense");
        if ((opts.update||opts.index_only) && !opts.merge)
index 48e0a6bf260cab18d44058ade554e3a9d5946b93..e9a6e09257f445b1c26833dd9fae89518369daa7 100644 (file)
@@ -15,7 +15,7 @@ static const char * const builtin_remote_usage[] = {
        "git remote set-head <name> (-a | -d | <branch>)",
        "git remote [-v | --verbose] show [-n] <name>",
        "git remote prune [-n | --dry-run] <name>",
-       "git remote [-v | --verbose] update [-p | --prune] [group | remote]",
+       "git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]",
        "git remote set-branches <name> [--add] <branch>...",
        "git remote set-url <name> <newurl> [<oldurl>]",
        "git remote set-url --add <name> <newurl>",
index efe9360e2fdb9aac3bae0c61c85531041f24708a..ba27d39f977f2807cddb6e18364837b9fd50e970 100644 (file)
@@ -11,9 +11,9 @@
 static const char rev_list_usage[] =
 "git rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
 "  limiting output:\n"
-"    --max-count=nr\n"
-"    --max-age=epoch\n"
-"    --min-age=epoch\n"
+"    --max-count=<n>\n"
+"    --max-age=<epoch>\n"
+"    --min-age=<epoch>\n"
 "    --sparse\n"
 "    --no-merges\n"
 "    --remove-empty\n"
@@ -33,7 +33,7 @@ static const char rev_list_usage[] =
 "    --objects | --objects-edge\n"
 "    --unpacked\n"
 "    --header | --pretty\n"
-"    --abbrev=nr | --no-abbrev\n"
+"    --abbrev=<n> | --no-abbrev\n"
 "    --abbrev-commit\n"
 "    --left-right\n"
 "  special purpose:\n"
@@ -147,8 +147,10 @@ static void show_commit(struct commit *commit, void *data)
                        }
                } else {
                        if (revs->commit_format != CMIT_FMT_USERFORMAT ||
-                           buf.len)
-                               printf("%s%c", buf.buf, info->hdr_termination);
+                           buf.len) {
+                               fwrite(buf.buf, 1, buf.len, stdout);
+                               putchar(info->hdr_termination);
+                       }
                }
                strbuf_release(&buf);
        } else {
index 4b47ace36b51566acb5b748f679070f02cbbf568..57b51e4a0e148062e1945d640b81559d65e4c2ba 100644 (file)
@@ -442,7 +442,7 @@ static int do_pick_commit(void)
        else
                parent = commit->parents->item;
 
-       if (allow_ff && !hashcmp(parent->object.sha1, head))
+       if (allow_ff && parent && !hashcmp(parent->object.sha1, head))
                return fast_forward_to(commit->object.sha1, head);
 
        if (parent && parse_commit(parent) < 0)
index 481602d8ae73612226bcc758f2aedea7f964779c..2cd1c40b70890732905ad9433e452aa9a9548533 100644 (file)
@@ -48,6 +48,7 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
                NULL,
                NULL,
                NULL,
+               NULL,
        };
        struct child_process po;
        int i;
@@ -59,6 +60,8 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
                argv[i++] = "--delta-base-offset";
        if (args->quiet)
                argv[i++] = "-q";
+       if (args->progress)
+               argv[i++] = "--progress";
        memset(&po, 0, sizeof(po));
        po.argv = argv;
        po.in = -1;
@@ -101,7 +104,7 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext
        }
 
        if (finish_command(&po))
-               return error("pack-objects died with strange error");
+               return -1;
        return 0;
 }
 
index e8719aa9e9f47c30b697332925fcdd206fdfd55c..8663ccaa99299447a42da64f9f2c77f772996902 100644 (file)
@@ -6,7 +6,7 @@
 #include "parse-options.h"
 
 static const char* show_branch_usage[] = {
-    "git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [--topics] [<rev> | <glob>]...",
+    "git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order] [--current] [--color[=<when>] | --no-color] [--sparse] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]",
     "git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]",
     NULL
 };
index 685566e0b5e458c510fdf989744d63dda29e28f0..f63973c9143c4109a3d1e40df9ec66a32498fe00 100644 (file)
@@ -83,7 +83,7 @@ static void use(int bytes)
        offset += bytes;
 
        /* make sure off_t is sufficiently large not to wrap */
-       if (consumed_bytes > consumed_bytes + bytes)
+       if (signed_add_overflows(consumed_bytes, bytes))
                die("pack too large for current definition of off_t");
        consumed_bytes += bytes;
 }
index 3ab214d24e537865875d6d1e3acd8cf6b019ff22..62d9f3f0fa358058fcf54e4fcbd4c3101b1279db 100644 (file)
@@ -398,7 +398,7 @@ static void read_index_info(int line_termination)
 }
 
 static const char update_index_usage[] =
-"git update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--skip-worktree|--no-skip-worktree] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again | -g] [--ignore-missing] [-z] [--verbose] [--] <file>...";
+"git update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--skip-worktree|--no-skip-worktree] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again | -g] [--ignore-missing] [-z] [--verbose] [--] [<file>...]";
 
 static unsigned char head_sha1[20];
 static unsigned char merge_head_sha1[20];
diff --git a/cache.h b/cache.h
index 2ef2fa3a5e166d94e5e981ca7c76afad13236e7e..33decd942d4985c8efc1c75fd3fa2f4adf4a56ca 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -277,9 +277,16 @@ static inline int ce_to_dtype(const struct cache_entry *ce)
        else
                return DT_UNKNOWN;
 }
-#define canon_mode(mode) \
-       (S_ISREG(mode) ? (S_IFREG | ce_permissions(mode)) : \
-       S_ISLNK(mode) ? S_IFLNK : S_ISDIR(mode) ? S_IFDIR : S_IFGITLINK)
+static inline unsigned int canon_mode(unsigned int mode)
+{
+       if (S_ISREG(mode))
+               return S_IFREG | ce_permissions(mode);
+       if (S_ISLNK(mode))
+               return S_IFLNK;
+       if (S_ISDIR(mode))
+               return S_IFDIR;
+       return S_IFGITLINK;
+}
 
 #define flexible_size(STRUCT,len) ((offsetof(struct STRUCT,name) + (len) + 8) & ~7)
 #define cache_entry_size(len) flexible_size(cache_entry,len)
@@ -438,7 +445,7 @@ extern int init_db(const char *template_dir, unsigned int flags);
  * at least 'nr' entries; the number of entries currently allocated
  * is 'alloc', using the standard growing factor alloc_nr() macro.
  *
- * DO NOT USE any expression with side-effect for 'x' or 'alloc'.
+ * DO NOT USE any expression with side-effect for 'x', 'nr', or 'alloc'.
  */
 #define ALLOC_GROW(x, nr, alloc) \
        do { \
index f2d9e1fd974b7271366da09370e10fafd2c50f08..6590f33cc8157f61ff7b6e0f6330bacf465ad39c 100644 (file)
@@ -127,7 +127,7 @@ int mingw_open (const char *filename, int oflags, ...)
        mode = va_arg(args, int);
        va_end(args);
 
-       if (!strcmp(filename, "/dev/null"))
+       if (filename && !strcmp(filename, "/dev/null"))
                filename = "nul";
 
        fd = open(filename, oflags, mode);
@@ -160,7 +160,7 @@ ssize_t mingw_write(int fd, const void *buf, size_t count)
 #undef fopen
 FILE *mingw_fopen (const char *filename, const char *otype)
 {
-       if (!strcmp(filename, "/dev/null"))
+       if (filename && !strcmp(filename, "/dev/null"))
                filename = "nul";
        return fopen(filename, otype);
 }
@@ -192,8 +192,11 @@ static inline time_t filetime_to_time_t(const FILETIME *ft)
 /* We keep the do_lstat code in a separate function to avoid recursion.
  * When a path ends with a slash, the stat will fail with ENOENT. In
  * this case, we strip the trailing slashes and stat again.
+ *
+ * If follow is true then act like stat() and report on the link
+ * target. Otherwise report on the link itself.
  */
-static int do_lstat(const char *file_name, struct stat *buf)
+static int do_lstat(int follow, const char *file_name, struct stat *buf)
 {
        WIN32_FILE_ATTRIBUTE_DATA fdata;
 
@@ -209,6 +212,25 @@ static int do_lstat(const char *file_name, struct stat *buf)
                buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
                buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
                buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
+               if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+                       WIN32_FIND_DATAA findbuf;
+                       HANDLE handle = FindFirstFileA(file_name, &findbuf);
+                       if (handle != INVALID_HANDLE_VALUE) {
+                               if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
+                                               (findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
+                                       if (follow) {
+                                               char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+                                               buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+                                       } else {
+                                               buf->st_mode = S_IFLNK;
+                                       }
+                                       buf->st_mode |= S_IREAD;
+                                       if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
+                                               buf->st_mode |= S_IWRITE;
+                               }
+                               FindClose(handle);
+                       }
+               }
                return 0;
        }
        return -1;
@@ -220,12 +242,12 @@ static int do_lstat(const char *file_name, struct stat *buf)
  * complete. Note that Git stat()s are redirected to mingw_lstat()
  * too, since Windows doesn't really handle symlinks that well.
  */
-int mingw_lstat(const char *file_name, struct stat *buf)
+static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
 {
        int namelen;
        static char alt_name[PATH_MAX];
 
-       if (!do_lstat(file_name, buf))
+       if (!do_lstat(follow, file_name, buf))
                return 0;
 
        /* if file_name ended in a '/', Windows returned ENOENT;
@@ -244,7 +266,16 @@ int mingw_lstat(const char *file_name, struct stat *buf)
 
        memcpy(alt_name, file_name, namelen);
        alt_name[namelen] = 0;
-       return do_lstat(alt_name, buf);
+       return do_lstat(follow, alt_name, buf);
+}
+
+int mingw_lstat(const char *file_name, struct stat *buf)
+{
+       return do_stat_internal(0, file_name, buf);
+}
+int mingw_stat(const char *file_name, struct stat *buf)
+{
+       return do_stat_internal(1, file_name, buf);
 }
 
 #undef fstat
@@ -873,6 +904,11 @@ void mingw_execvp(const char *cmd, char *const *argv)
        free_path_split(path);
 }
 
+void mingw_execv(const char *cmd, char *const *argv)
+{
+       mingw_execve(cmd, argv, environ);
+}
+
 static char **copy_environ(void)
 {
        char **env;
@@ -1386,6 +1422,7 @@ void mingw_open_html(const char *unixpath)
                        const char *, const char *, const char *, INT);
        T ShellExecute;
        HMODULE shell32;
+       int r;
 
        shell32 = LoadLibrary("shell32.dll");
        if (!shell32)
@@ -1395,9 +1432,12 @@ void mingw_open_html(const char *unixpath)
                die("cannot run browser");
 
        printf("Launching default browser to display HTML ...\n");
-       ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0);
-
+       r = (int)ShellExecute(NULL, "open", htmlpath, NULL, "\\", SW_SHOWNORMAL);
        FreeLibrary(shell32);
+       /* see the MSDN documentation referring to the result codes here */
+       if (r <= 32) {
+               die("failed to launch browser for %.*s", MAX_PATH, unixpath);
+       }
 }
 
 int link(const char *oldpath, const char *newpath)
index 3b2477be5f658be665f19a12b48cc47fa07d1c6b..83e35e833b7f214e5d10a3e74a75fb17d80c2e13 100644 (file)
@@ -6,17 +6,30 @@
  */
 
 typedef int pid_t;
+typedef int uid_t;
 #define hstrerror strerror
 
 #define S_IFLNK    0120000 /* Symbolic link */
 #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
-#define S_ISGID 0
+#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
 #define S_IROTH 0
+#define S_IWOTH 0
 #define S_IXOTH 0
+#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
+#define S_ISUID 0
+#define S_ISGID 0
+#define S_ISVTX 0
 
 #define WIFEXITED(x) 1
 #define WIFSIGNALED(x) 0
@@ -65,6 +78,12 @@ struct itimerval {
 };
 #define ITIMER_REAL 0
 
+/*
+ * sanitize preprocessor namespace polluted by Windows headers defining
+ * macros which collide with git local versions
+ */
+#undef HELP_COMMAND /* from winuser.h */
+
 /*
  * trivial stubs
  */
@@ -75,17 +94,17 @@ static inline int symlink(const char *oldpath, const char *newpath)
 { errno = ENOSYS; return -1; }
 static inline int fchmod(int fildes, mode_t mode)
 { errno = ENOSYS; return -1; }
-static inline int fork(void)
+static inline pid_t fork(void)
 { errno = ENOSYS; return -1; }
 static inline unsigned int alarm(unsigned int seconds)
 { return 0; }
 static inline int fsync(int fd)
 { return _commit(fd); }
-static inline int getppid(void)
+static inline pid_t getppid(void)
 { return 1; }
 static inline void sync(void)
 {}
-static inline int getuid()
+static inline uid_t getuid(void)
 { return 1; }
 static inline struct passwd *getpwnam(const char *name)
 { return NULL; }
@@ -117,7 +136,7 @@ static inline int mingw_unlink(const char *pathname)
 }
 #define unlink mingw_unlink
 
-static inline int waitpid(pid_t pid, int *status, unsigned options)
+static inline pid_t waitpid(pid_t pid, int *status, unsigned options)
 {
        if (options == 0)
                return _cwait(status, pid, 0);
@@ -158,7 +177,7 @@ int poll(struct pollfd *ufds, unsigned int nfds, int timeout);
 struct tm *gmtime_r(const time_t *timep, struct tm *result);
 struct tm *localtime_r(const time_t *timep, struct tm *result);
 int getpagesize(void); /* defined in MinGW's libgcc.a */
-struct passwd *getpwuid(int uid);
+struct passwd *getpwuid(uid_t uid);
 int setitimer(int type, struct itimerval *in, struct itimerval *out);
 int sigaction(int sig, struct sigaction *in, struct sigaction *out);
 int link(const char *oldpath, const char *newpath);
@@ -222,10 +241,11 @@ int mingw_getpagesize(void);
 #ifndef ALREADY_DECLARED_STAT_FUNCS
 #define stat _stati64
 int mingw_lstat(const char *file_name, struct stat *buf);
+int mingw_stat(const char *file_name, struct stat *buf);
 int mingw_fstat(int fd, struct stat *buf);
 #define fstat mingw_fstat
 #define lstat mingw_lstat
-#define _stati64(x,y) mingw_lstat(x,y)
+#define _stati64(x,y) mingw_stat(x,y)
 #endif
 
 int mingw_utime(const char *file_name, const struct utimbuf *times);
@@ -236,6 +256,8 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
                     int fhin, int fhout, int fherr);
 void mingw_execvp(const char *cmd, char *const *argv);
 #define execvp mingw_execvp
+void mingw_execv(const char *cmd, char *const *argv);
+#define execv mingw_execv
 
 static inline unsigned int git_ntohl(unsigned int x)
 { return (unsigned int)ntohl(x); }
index 56731c35c9d1b5e2d2c82cdff51ab496dcbac7f5..cc55b6d4f741948f3bd05c6299fabdb9f21d7f95 100644 (file)
@@ -282,7 +282,15 @@ GIT_PARSE_WITH(iconv))
 GIT_PARSE_WITH_SET_MAKE_VAR(gitconfig, ETC_GITCONFIG,
                        Use VALUE instead of /etc/gitconfig as the
                        global git configuration file.
-                       If VALUE is not fully qualified it will be interpretted
+                       If VALUE is not fully qualified it will be interpreted
+                       as a path relative to the computed prefix at runtime.)
+
+#
+# Allow user to set ETC_GITATTRIBUTES variable
+GIT_PARSE_WITH_SET_MAKE_VAR(gitattributes, ETC_GITATTRIBUTES,
+                       Use VALUE instead of /etc/gitattributes as the
+                       global git attributes file.
+                       If VALUE is not fully qualified it will be interpreted
                        as a path relative to the computed prefix at runtime.)
 
 #
index 3450cabd0e3281e0eeedeb35d331b95bf95f5afb..57dc20c43ca1ba205ec0a18e263f9dde081390f4 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -631,8 +631,12 @@ char *git_getpass(const char *prompt)
                askpass = askpass_program;
        if (!askpass)
                askpass = getenv("SSH_ASKPASS");
-       if (!askpass || !(*askpass))
-               return getpass(prompt);
+       if (!askpass || !(*askpass)) {
+               char *result = getpass(prompt);
+               if (!result)
+                       die_errno("Could not read password");
+               return result;
+       }
 
        args[0] = askpass;
        args[1] = prompt;
index d0627e0852cc47df3ffd29754254ccb99c3b2ad0..9775dffb5d49521a7078643104762cd136edffcc 100755 (executable)
@@ -122,7 +122,7 @@ def report(refname, merged):
     branch = os.path.basename(refname)
 
     # Compute a shortnane for the revision
-    rev = do("git describe ${merged} 2>/dev/null") or merged[:12]
+    rev = do("git describe '"+ merged +"' 2>/dev/null") or merged[:12]
 
     # Extract the neta-information for the commit
     rawcommit = do("git cat-file commit " + merged)
index 67569901e71e5062199e48304afc424f15b57ba1..f71046947febee2cacfd2a9ed2e0746582a5e54f 100755 (executable)
 #    2) Added the following line to your .bashrc:
 #        source ~/.git-completion.sh
 #
+#       Or, add the following lines to your .zshrc:
+#        autoload bashcompinit
+#        bashcompinit
+#        source ~/.git-completion.sh
+#
 #    3) Consider changing your PS1 to also show the current branch:
 #        PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
 #
@@ -138,11 +143,12 @@ __git_ps1_show_upstream ()
                # get the upstream from the "git-svn-id: ..." in a commit message
                # (git-svn uses essentially the same procedure internally)
                local svn_upstream=($(git log --first-parent -1 \
-                                       --grep="^git-svn-id: \(${svn_url_pattern:2}\)" 2>/dev/null))
+                                       --grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null))
                if [[ 0 -ne ${#svn_upstream[@]} ]]; then
                        svn_upstream=${svn_upstream[ ${#svn_upstream[@]} - 2 ]}
                        svn_upstream=${svn_upstream%@*}
-                       for ((n=1; "$n" <= "${#svn_remote[@]}"; ++n)); do
+                       local n_stop="${#svn_remote[@]}"
+                       for ((n=1; n <= n_stop; ++n)); do
                                svn_upstream=${svn_upstream#${svn_remote[$n]}}
                        done
 
@@ -380,16 +386,19 @@ __git_tags ()
        done
 }
 
-# __git_refs accepts 0 or 1 arguments (to pass to __gitdir)
+# __git_refs accepts 0, 1 (to pass to __gitdir), or 2 arguments
+# presence of 2nd argument means use the guess heuristic employed
+# by checkout for tracking branches
 __git_refs ()
 {
-       local i is_hash=y dir="$(__gitdir "${1-}")"
+       local i is_hash=y dir="$(__gitdir "${1-}")" track="${2-}"
        local cur="${COMP_WORDS[COMP_CWORD]}" format refs
        if [ -d "$dir" ]; then
                case "$cur" in
                refs|refs/*)
                        format="refname"
                        refs="${cur%/*}"
+                       track=""
                        ;;
                *)
                        for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do
@@ -401,6 +410,21 @@ __git_refs ()
                esac
                git --git-dir="$dir" for-each-ref --format="%($format)" \
                        $refs
+               if [ -n "$track" ]; then
+                       # employ the heuristic used by git checkout
+                       # Try to find a remote branch that matches the completion word
+                       # but only output if the branch name is unique
+                       local ref entry
+                       git --git-dir="$dir" for-each-ref --shell --format="ref=%(refname:short)" \
+                               "refs/remotes/" | \
+                       while read entry; do
+                               eval "$entry"
+                               ref="${ref#*/}"
+                               if [[ "$ref" == "$cur"* ]]; then
+                                       echo "$ref"
+                               fi
+                       done | uniq -u
+               fi
                return
        fi
        for i in $(git ls-remote "$dir" 2>/dev/null); do
@@ -750,6 +774,19 @@ __git_compute_porcelain_commands ()
        : ${__git_porcelain_commands:=$(__git_list_porcelain_commands)}
 }
 
+__git_pretty_aliases ()
+{
+       local i IFS=$'\n'
+       for i in $(git --git-dir="$(__gitdir)" config --get-regexp "pretty\..*" 2>/dev/null); do
+               case "$i" in
+               pretty.*)
+                       i="${i#pretty.}"
+                       echo "${i/ */}"
+                       ;;
+               esac
+       done
+}
+
 __git_aliases ()
 {
        local i IFS=$'\n'
@@ -907,12 +944,16 @@ _git_bisect ()
        local subcommands="start bad good skip reset visualize replay log run"
        local subcommand="$(__git_find_on_cmdline "$subcommands")"
        if [ -z "$subcommand" ]; then
-               __gitcomp "$subcommands"
+               if [ -f "$(__gitdir)"/BISECT_START ]; then
+                       __gitcomp "$subcommands"
+               else
+                       __gitcomp "replay start"
+               fi
                return
        fi
 
        case "$subcommand" in
-       bad|good|reset|skip)
+       bad|good|reset|skip|start)
                __gitcomp "$(__git_refs)"
                ;;
        *)
@@ -988,7 +1029,13 @@ _git_checkout ()
                        "
                ;;
        *)
-               __gitcomp "$(__git_refs)"
+               # check if --track, --no-track, or --no-guess was specified
+               # if so, disable DWIM mode
+               local flags="--track --no-track --no-guess" track=1
+               if [ -n "$(__git_find_on_cmdline "$flags")" ]; then
+                       track=''
+               fi
+               __gitcomp "$(__git_refs '' $track)"
                ;;
        esac
 }
@@ -1125,7 +1172,7 @@ _git_diff ()
        case "$cur" in
        --*)
                __gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
-                       --base --ours --theirs
+                       --base --ours --theirs --no-index
                        $__git_diff_common_options
                        "
                return
@@ -1368,12 +1415,12 @@ _git_log ()
        fi
        case "$cur" in
        --pretty=*)
-               __gitcomp "$__git_log_pretty_formats
+               __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
                        " "" "${cur##--pretty=}"
                return
                ;;
        --format=*)
-               __gitcomp "$__git_log_pretty_formats
+               __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
                        " "" "${cur##--format=}"
                return
                ;;
@@ -1468,18 +1515,50 @@ _git_name_rev ()
 
 _git_notes ()
 {
-       local subcommands="edit show"
-       if [ -z "$(__git_find_on_cmdline "$subcommands")" ]; then
-               __gitcomp "$subcommands"
-               return
-       fi
+       local subcommands='add append copy edit list prune remove show'
+       local subcommand="$(__git_find_on_cmdline "$subcommands")"
+       local cur="${COMP_WORDS[COMP_CWORD]}"
 
-       case "${COMP_WORDS[COMP_CWORD-1]}" in
-       -m|-F)
-               COMPREPLY=()
+       case "$subcommand,$cur" in
+       ,--*)
+               __gitcomp '--ref'
+               ;;
+       ,*)
+               case "${COMP_WORDS[COMP_CWORD-1]}" in
+               --ref)
+                       __gitcomp "$(__git_refs)"
+                       ;;
+               *)
+                       __gitcomp "$subcommands --ref"
+                       ;;
+               esac
+               ;;
+       add,--reuse-message=*|append,--reuse-message=*)
+               __gitcomp "$(__git_refs)" "" "${cur##--reuse-message=}"
+               ;;
+       add,--reedit-message=*|append,--reedit-message=*)
+               __gitcomp "$(__git_refs)" "" "${cur##--reedit-message=}"
+               ;;
+       add,--*|append,--*)
+               __gitcomp '--file= --message= --reedit-message=
+                               --reuse-message='
+               ;;
+       copy,--*)
+               __gitcomp '--stdin'
+               ;;
+       prune,--*)
+               __gitcomp '--dry-run --verbose'
+               ;;
+       prune,*)
                ;;
        *)
-               __gitcomp "$(__git_refs)"
+               case "${COMP_WORDS[COMP_CWORD-1]}" in
+               -m|-F)
+                       ;;
+               *)
+                       __gitcomp "$(__git_refs)"
+                       ;;
+               esac
                ;;
        esac
 }
@@ -2100,12 +2179,12 @@ _git_show ()
        local cur="${COMP_WORDS[COMP_CWORD]}"
        case "$cur" in
        --pretty=*)
-               __gitcomp "$__git_log_pretty_formats
+               __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
                        " "" "${cur##--pretty=}"
                return
                ;;
        --format=*)
-               __gitcomp "$__git_log_pretty_formats
+               __gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
                        " "" "${cur##--format=}"
                return
                ;;
@@ -2339,6 +2418,11 @@ _git ()
 {
        local i c=1 command __git_dir
 
+       if [[ -n ${ZSH_VERSION-} ]]; then
+               emulate -L bash
+               setopt KSH_TYPESET
+       fi
+
        while [ $c -lt $COMP_CWORD ]; do
                i="${COMP_WORDS[c]}"
                case "$i" in
@@ -2372,17 +2456,22 @@ _git ()
        fi
 
        local completion_func="_git_${command//-/_}"
-       declare -F $completion_func >/dev/null && $completion_func && return
+       declare -f $completion_func >/dev/null && $completion_func && return
 
        local expansion=$(__git_aliased_command "$command")
        if [ -n "$expansion" ]; then
                completion_func="_git_${expansion//-/_}"
-               declare -F $completion_func >/dev/null && $completion_func
+               declare -f $completion_func >/dev/null && $completion_func
        fi
 }
 
 _gitk ()
 {
+       if [[ -n ${ZSH_VERSION-} ]]; then
+               emulate -L bash
+               setopt KSH_TYPESET
+       fi
+
        __git_has_doubledash && return
 
        local cur="${COMP_WORDS[COMP_CWORD]}"
@@ -2417,3 +2506,29 @@ if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then
 complete -o bashdefault -o default -o nospace -F _git git.exe 2>/dev/null \
        || complete -o default -o nospace -F _git git.exe
 fi
+
+if [[ -n ${ZSH_VERSION-} ]]; then
+       shopt () {
+               local option
+               if [ $# -ne 2 ]; then
+                       echo "USAGE: $0 (-q|-s|-u) <option>" >&2
+                       return 1
+               fi
+               case "$2" in
+               nullglob)
+                       option="$2"
+                       ;;
+               *)
+                       echo "$0: invalid option: $2" >&2
+                       return 1
+               esac
+               case "$1" in
+               -q)     setopt | grep -q "$option" ;;
+               -u)     unsetopt "$option" ;;
+               -s)     setopt "$option" ;;
+               *)
+                       echo "$0: invalid flag: $1" >&2
+                       return 1
+               esac
+       }
+fi
index 7f4c7929784f8e2d8b24b0eaf9f05a2f10c1c6eb..d351cfb6e7e818f5f760e83889586c6dbf6e3a11 100644 (file)
@@ -79,6 +79,7 @@
 ;;; Code:
 
 (eval-when-compile (require 'cl))                            ; to use `push', `pop'
+(require 'format-spec)
 
 (defface git-blame-prefix-face
   '((((background dark)) (:foreground "gray"
index 4576c4a862c8ea0565a67eccdae6ef1ac4d9af9a..b09ff8f12f7e5b5b6faeaf857d7c61973de8590e 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
 
 # This tool is copyright (c) 2005, Matthias Urlichs.
 # It is released under the Gnu Public License, version 2.
@@ -289,7 +289,7 @@ my $current_rev = $opt_s || 1;
 unless(-d $git_dir) {
        system("git init");
        die "Cannot init the GIT db at $git_tree: $?\n" if $?;
-       system("git read-tree");
+       system("git read-tree --empty");
        die "Cannot init an empty tree: $?\n" if $?;
 
        $last_branch = $opt_o;
index c1ea643ace920e83a5577948553d4c9d1046abec..04ce7e3b020f489d59fe103970fc989d7b351127 100755 (executable)
@@ -706,7 +706,9 @@ class P4Submit(Command):
             submitTemplate = self.prepareLogMessage(template, logMessage)
             if os.environ.has_key("P4DIFF"):
                 del(os.environ["P4DIFF"])
-            diff = p4_read_pipe("diff -du ...")
+            diff = ""
+            for editedFile in editedFiles:
+                diff += p4_read_pipe("diff -du %r" % editedFile)
 
             newdiff = ""
             for newFile in filesToAdd:
index 3a5da4ab00f2e29c3244611f40d776293e796e7d..7f3afa5ac4a4ca979a4e5dd63ebc59344f20857b 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
 #
 # Copyright 2008-2009 Peter Krefting <peter@softwolves.pp.se>
 #
@@ -140,6 +140,7 @@ by whitespace or other characters.
 
 # Globals
 use strict;
+use warnings;
 use integer;
 my $crlfmode = 0;
 my @revs;
diff --git a/contrib/git-shell-commands/README b/contrib/git-shell-commands/README
new file mode 100644 (file)
index 0000000..438463b
--- /dev/null
@@ -0,0 +1,18 @@
+Sample programs callable through git-shell.  Place a directory named
+'git-shell-commands' in the home directory of a user whose shell is
+git-shell.  Then anyone logging in as that user will be able to run
+executables in the 'git-shell-commands' directory.
+
+Provided commands:
+
+help: Prints out the names of available commands.  When run
+interactively, git-shell will automatically run 'help' on startup,
+provided it exists.
+
+list: Displays any bare repository whose name ends with ".git" under
+user's home directory.  No other git repositories are visible,
+although they might be clonable through git-shell.  'list' is designed
+to minimize the number of calls to git that must be made in finding
+available repositories; if your setup has additional repositories that
+should be user-discoverable, you may wish to modify 'list'
+accordingly.
diff --git a/contrib/git-shell-commands/help b/contrib/git-shell-commands/help
new file mode 100755 (executable)
index 0000000..535770c
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+if tty -s
+then
+       echo "Run 'help' for help, or 'exit' to leave.  Available commands:"
+else
+       echo "Run 'help' for help.  Available commands:"
+fi
+
+cd "$(dirname "$0")"
+
+for cmd in *
+do
+       case "$cmd" in
+       help) ;;
+       *) [ -f "$cmd" ] && [ -x "$cmd" ] && echo "$cmd" ;;
+       esac
+done
diff --git a/contrib/git-shell-commands/list b/contrib/git-shell-commands/list
new file mode 100755 (executable)
index 0000000..6f89938
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+print_if_bare_repo='
+       if "$(git --git-dir="$1" rev-parse --is-bare-repository)" = true
+       then
+               printf "%s\n" "${1#./}"
+       fi
+'
+
+find -type d -name "*.git" -exec sh -c "$print_if_bare_repo" -- \{} \; -prune 2>/dev/null
index 00850864371e16d1fa572b0d0e5832b8a88d8666..85724bfc08f61d3b928460a8d2ad5ec03cf80b52 100755 (executable)
 # ---------------------------- Functions
 
 #
-# Top level email generation function.  This decides what type of update
-# this is and calls the appropriate body-generation routine after outputting
-# the common header
+# Function to prepare for email generation. This decides what type
+# of update this is and whether an email should even be generated.
 #
-# Note this function doesn't actually generate any email output, that is
-# taken care of by the functions it calls:
-#  - generate_email_header
-#  - generate_create_XXXX_email
-#  - generate_update_XXXX_email
-#  - generate_delete_XXXX_email
-#  - generate_email_footer
-#
-generate_email()
+prep_for_email()
 {
        # --- Arguments
        oldrev=$(git rev-parse $1)
@@ -159,7 +150,7 @@ generate_email()
                        # Anything else (is there anything else?)
                        echo >&2 "*** Unknown type of update to $refname ($rev_type)"
                        echo >&2 "***  - no email generated"
-                       exit 1
+                       return 0
                        ;;
        esac
 
@@ -175,9 +166,32 @@ generate_email()
                esac
                echo >&2 "*** $config_name is not set so no email will be sent"
                echo >&2 "*** for $refname update $oldrev->$newrev"
-               exit 0
+               return 0
        fi
 
+       return 1
+}
+
+#
+# Top level email generation function.  This calls the appropriate
+# body-generation routine after outputting the common header.
+#
+# Note this function doesn't actually generate any email output, that is
+# taken care of by the functions it calls:
+#  - generate_email_header
+#  - generate_create_XXXX_email
+#  - generate_update_XXXX_email
+#  - generate_delete_XXXX_email
+#  - generate_email_footer
+#
+# Note also that this function cannot 'exit' from the script; when this
+# function is running (in hook script mode), the send_mail() function
+# is already executing in another process, connected via a pipe, and
+# if this function exits without, whatever has been generated to that
+# point will be sent as an email... even if nothing has been generated.
+#
+generate_email()
+{
        # Email parameters
        # The email subject will contain the best description of the ref
        # that we can build from the parameters
@@ -717,10 +731,11 @@ if [ -n "$1" -a -n "$2" -a -n "$3" ]; then
        # Output to the terminal in command line mode - if someone wanted to
        # resend an email; they could redirect the output to sendmail
        # themselves
-       PAGER= generate_email $2 $3 $1
+       prep_for_email $2 $3 $1 && PAGER= generate_email
 else
        while read oldrev newrev refname
        do
-               generate_email $oldrev $newrev $refname $maxlines | send_mail
+               prep_for_email $oldrev $newrev $refname || continue
+               generate_email $maxlines | send_mail
        done
 fi
index 3ad2c0cea56392fb941282ec6225c5f9a3ce05ea..75e8b258177f7f04dadcac125f2bf7ebea4d0f81 100755 (executable)
@@ -42,7 +42,7 @@ then
 fi
 
 # don't link to a workdir
-if test -L "$git_dir/config"
+if test -h "$git_dir/config"
 then
        die "\"$orig_git\" is a working directory only, please specify" \
                "a complete repository."
index e22a2b7fa5f6fcfc5b26541a21c10d3c8b7eda81..7ccd097e1d1234d06316e8b7f271e86127750f85 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -3,6 +3,7 @@
 #include "exec_cmd.h"
 #include "run-command.h"
 #include "strbuf.h"
+#include "string-list.h"
 
 #include <syslog.h>
 
@@ -20,15 +21,15 @@ static int reuseaddr;
 
 static const char daemon_usage[] =
 "git daemon [--verbose] [--syslog] [--export-all]\n"
-"           [--timeout=n] [--init-timeout=n] [--max-connections=n]\n"
-"           [--strict-paths] [--base-path=path] [--base-path-relaxed]\n"
-"           [--user-path | --user-path=path]\n"
-"           [--interpolated-path=path]\n"
-"           [--reuseaddr] [--detach] [--pid-file=file]\n"
-"           [--[enable|disable|allow-override|forbid-override]=service]\n"
-"           [--inetd | [--listen=host_or_ipaddr] [--port=n]\n"
-"                      [--user=user [--group=group]]\n"
-"           [directory...]";
+"           [--timeout=<n>] [--init-timeout=<n>] [--max-connections=<n>]\n"
+"           [--strict-paths] [--base-path=<path>] [--base-path-relaxed]\n"
+"           [--user-path | --user-path=<path>]\n"
+"           [--interpolated-path=<path>]\n"
+"           [--reuseaddr] [--detach] [--pid-file=<file>]\n"
+"           [--(enable|disable|allow-override|forbid-override)=<service>]\n"
+"           [--inetd | [--listen=<host_or_ipaddr>] [--port=<n>]\n"
+"                      [--user=<user> [--group=<group>]]\n"
+"           [<directory>...]";
 
 /* List of acceptable pathname prefixes */
 static char **ok_paths;
@@ -734,11 +735,17 @@ static int set_reuse_addr(int sockfd)
                          &on, sizeof(on));
 }
 
+struct socketlist {
+       int *list;
+       size_t nr;
+       size_t alloc;
+};
+
 #ifndef NO_IPV6
 
-static int socksetup(char *listen_addr, int listen_port, int **socklist_p)
+static int setup_named_sock(char *listen_addr, int listen_port, struct socketlist *socklist)
 {
-       int socknum = 0, *socklist = NULL;
+       int socknum = 0;
        int maxfd = -1;
        char pbuf[NI_MAXSERV];
        struct addrinfo hints, *ai0, *ai;
@@ -753,8 +760,10 @@ static int socksetup(char *listen_addr, int listen_port, int **socklist_p)
        hints.ai_flags = AI_PASSIVE;
 
        gai = getaddrinfo(listen_addr, pbuf, &hints, &ai0);
-       if (gai)
-               die("getaddrinfo() failed: %s", gai_strerror(gai));
+       if (gai) {
+               logerror("getaddrinfo() for %s failed: %s", listen_addr, gai_strerror(gai));
+               return 0;
+       }
 
        for (ai = ai0; ai; ai = ai->ai_next) {
                int sockfd;
@@ -795,8 +804,9 @@ static int socksetup(char *listen_addr, int listen_port, int **socklist_p)
                if (flags >= 0)
                        fcntl(sockfd, F_SETFD, flags | FD_CLOEXEC);
 
-               socklist = xrealloc(socklist, sizeof(int) * (socknum + 1));
-               socklist[socknum++] = sockfd;
+               ALLOC_GROW(socklist->list, socklist->nr + 1, socklist->alloc);
+               socklist->list[socklist->nr++] = sockfd;
+               socknum++;
 
                if (maxfd < sockfd)
                        maxfd = sockfd;
@@ -804,13 +814,12 @@ static int socksetup(char *listen_addr, int listen_port, int **socklist_p)
 
        freeaddrinfo(ai0);
 
-       *socklist_p = socklist;
        return socknum;
 }
 
 #else /* NO_IPV6 */
 
-static int socksetup(char *listen_addr, int listen_port, int **socklist_p)
+static int setup_named_sock(char *listen_addr, int listen_port, struct socketlist *socklist)
 {
        struct sockaddr_in sin;
        int sockfd;
@@ -851,22 +860,39 @@ static int socksetup(char *listen_addr, int listen_port, int **socklist_p)
        if (flags >= 0)
                fcntl(sockfd, F_SETFD, flags | FD_CLOEXEC);
 
-       *socklist_p = xmalloc(sizeof(int));
-       **socklist_p = sockfd;
+       ALLOC_GROW(socklist->list, socklist->nr + 1, socklist->alloc);
+       socklist->list[socklist->nr++] = sockfd;
        return 1;
 }
 
 #endif
 
-static int service_loop(int socknum, int *socklist)
+static void socksetup(struct string_list *listen_addr, int listen_port, struct socketlist *socklist)
+{
+       if (!listen_addr->nr)
+               setup_named_sock(NULL, listen_port, socklist);
+       else {
+               int i, socknum;
+               for (i = 0; i < listen_addr->nr; i++) {
+                       socknum = setup_named_sock(listen_addr->items[i].string,
+                                                  listen_port, socklist);
+
+                       if (socknum == 0)
+                               logerror("unable to allocate any listen sockets for host %s on port %u",
+                                        listen_addr->items[i].string, listen_port);
+               }
+       }
+}
+
+static int service_loop(struct socketlist *socklist)
 {
        struct pollfd *pfd;
        int i;
 
-       pfd = xcalloc(socknum, sizeof(struct pollfd));
+       pfd = xcalloc(socklist->nr, sizeof(struct pollfd));
 
-       for (i = 0; i < socknum; i++) {
-               pfd[i].fd = socklist[i];
+       for (i = 0; i < socklist->nr; i++) {
+               pfd[i].fd = socklist->list[i];
                pfd[i].events = POLLIN;
        }
 
@@ -877,7 +903,7 @@ static int service_loop(int socknum, int *socklist)
 
                check_dead_children();
 
-               if (poll(pfd, socknum, -1) < 0) {
+               if (poll(pfd, socklist->nr, -1) < 0) {
                        if (errno != EINTR) {
                                logerror("Poll failed, resuming: %s",
                                      strerror(errno));
@@ -886,7 +912,7 @@ static int service_loop(int socknum, int *socklist)
                        continue;
                }
 
-               for (i = 0; i < socknum; i++) {
+               for (i = 0; i < socklist->nr; i++) {
                        if (pfd[i].revents & POLLIN) {
                                struct sockaddr_storage ss;
                                unsigned int sslen = sizeof(ss);
@@ -946,27 +972,27 @@ static void store_pid(const char *path)
                die_errno("failed to write pid file '%s'", path);
 }
 
-static int serve(char *listen_addr, int listen_port, struct passwd *pass, gid_t gid)
+static int serve(struct string_list *listen_addr, int listen_port, struct passwd *pass, gid_t gid)
 {
-       int socknum, *socklist;
+       struct socketlist socklist = { NULL, 0, 0 };
 
-       socknum = socksetup(listen_addr, listen_port, &socklist);
-       if (socknum == 0)
-               die("unable to allocate any listen sockets on host %s port %u",
-                   listen_addr, listen_port);
+       socksetup(listen_addr, listen_port, &socklist);
+       if (socklist.nr == 0)
+               die("unable to allocate any listen sockets on port %u",
+                   listen_port);
 
        if (pass && gid &&
            (initgroups(pass->pw_name, gid) || setgid (gid) ||
             setuid(pass->pw_uid)))
                die("cannot drop privileges");
 
-       return service_loop(socknum, socklist);
+       return service_loop(&socklist);
 }
 
 int main(int argc, char **argv)
 {
        int listen_port = 0;
-       char *listen_addr = NULL;
+       struct string_list listen_addr = STRING_LIST_INIT_NODUP;
        int inetd_mode = 0;
        const char *pid_file = NULL, *user_name = NULL, *group_name = NULL;
        int detach = 0;
@@ -981,7 +1007,7 @@ int main(int argc, char **argv)
                char *arg = argv[i];
 
                if (!prefixcmp(arg, "--listen=")) {
-                       listen_addr = xstrdup_tolower(arg + 9);
+                       string_list_append(&listen_addr, xstrdup_tolower(arg + 9));
                        continue;
                }
                if (!prefixcmp(arg, "--port=")) {
@@ -1106,7 +1132,7 @@ int main(int argc, char **argv)
        if (inetd_mode && (group_name || user_name))
                die("--user and --group are incompatible with --inetd");
 
-       if (inetd_mode && (listen_port || listen_addr))
+       if (inetd_mode && (listen_port || (listen_addr.nr > 0)))
                die("--listen= and --port= are incompatible with --inetd");
        else if (listen_port == 0)
                listen_port = DEFAULT_GIT_PORT;
@@ -1161,5 +1187,5 @@ int main(int argc, char **argv)
        if (pid_file)
                store_pid(pid_file);
 
-       return serve(listen_addr, listen_port, pass, gid);
+       return serve(&listen_addr, listen_port, pass, gid);
 }
diff --git a/diff.c b/diff.c
index 9a5c77c13ff3406a85e8a94f309a639529f2d88b..c248bc64c57b3206905dd8e6f72a702073a137cc 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -1771,8 +1771,14 @@ static void emit_binary_diff(FILE *file, mmfile_t *one, mmfile_t *two, char *pre
 
 static void diff_filespec_load_driver(struct diff_filespec *one)
 {
-       if (!one->driver)
+       /* Use already-loaded driver */
+       if (one->driver)
+               return;
+
+       if (S_ISREG(one->mode))
                one->driver = userdiff_find_by_path(one->path);
+
+       /* Fallback to default settings */
        if (!one->driver)
                one->driver = userdiff_find_by_name("default");
 }
@@ -1820,8 +1826,7 @@ struct userdiff_driver *get_textconv(struct diff_filespec *one)
 {
        if (!DIFF_FILE_VALID(one))
                return NULL;
-       if (!S_ISREG(one->mode))
-               return NULL;
+
        diff_filespec_load_driver(one);
        if (!one->driver->textconv)
                return NULL;
@@ -3140,16 +3145,19 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                return stat_opt(options, av);
 
        /* renames options */
-       else if (!prefixcmp(arg, "-B")) {
+       else if (!prefixcmp(arg, "-B") || !prefixcmp(arg, "--break-rewrites=") ||
+                !strcmp(arg, "--break-rewrites")) {
                if ((options->break_opt = diff_scoreopt_parse(arg)) == -1)
                        return -1;
        }
-       else if (!prefixcmp(arg, "-M")) {
+       else if (!prefixcmp(arg, "-M") || !prefixcmp(arg, "--detect-renames=") ||
+                !strcmp(arg, "--detect-renames")) {
                if ((options->rename_score = diff_scoreopt_parse(arg)) == -1)
                        return -1;
                options->detect_rename = DIFF_DETECT_RENAME;
        }
-       else if (!prefixcmp(arg, "-C")) {
+       else if (!prefixcmp(arg, "-C") || !prefixcmp(arg, "--detect-copies=") ||
+                !strcmp(arg, "--detect-copies")) {
                if (options->detect_rename == DIFF_DETECT_COPY)
                        DIFF_OPT_SET(options, FIND_COPIES_HARDER);
                if ((options->rename_score = diff_scoreopt_parse(arg)) == -1)
@@ -3271,12 +3279,17 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
        }
        else if ((argcount = short_opt('S', av, &optarg))) {
                options->pickaxe = optarg;
+               options->pickaxe_opts |= DIFF_PICKAXE_KIND_S;
+               return argcount;
+       } else if ((argcount = short_opt('G', av, &optarg))) {
+               options->pickaxe = optarg;
+               options->pickaxe_opts |= DIFF_PICKAXE_KIND_G;
                return argcount;
        }
        else if (!strcmp(arg, "--pickaxe-all"))
-               options->pickaxe_opts = DIFF_PICKAXE_ALL;
+               options->pickaxe_opts |= DIFF_PICKAXE_ALL;
        else if (!strcmp(arg, "--pickaxe-regex"))
-               options->pickaxe_opts = DIFF_PICKAXE_REGEX;
+               options->pickaxe_opts |= DIFF_PICKAXE_REGEX;
        else if ((argcount = short_opt('O', av, &optarg))) {
                options->orderfile = optarg;
                return argcount;
@@ -3310,7 +3323,7 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
        else if ((argcount = parse_long_opt("output", av, &optarg))) {
                options->file = fopen(optarg, "w");
                if (!options->file)
-                       die_errno("Could not open '%s'", arg + strlen("--output="));
+                       die_errno("Could not open '%s'", optarg);
                options->close_file = 1;
                return argcount;
        } else
@@ -3318,7 +3331,7 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
        return 1;
 }
 
-static int parse_num(const char **cp_p)
+int parse_rename_score(const char **cp_p)
 {
        unsigned long num, scale;
        int ch, dot;
@@ -3361,10 +3374,26 @@ static int diff_scoreopt_parse(const char *opt)
        if (*opt++ != '-')
                return -1;
        cmd = *opt++;
+       if (cmd == '-') {
+               /* convert the long-form arguments into short-form versions */
+               if (!prefixcmp(opt, "break-rewrites")) {
+                       opt += strlen("break-rewrites");
+                       if (*opt == 0 || *opt++ == '=')
+                               cmd = 'B';
+               } else if (!prefixcmp(opt, "detect-copies")) {
+                       opt += strlen("detect-copies");
+                       if (*opt == 0 || *opt++ == '=')
+                               cmd = 'C';
+               } else if (!prefixcmp(opt, "detect-renames")) {
+                       opt += strlen("detect-renames");
+                       if (*opt == 0 || *opt++ == '=')
+                               cmd = 'M';
+               }
+       }
        if (cmd != 'M' && cmd != 'C' && cmd != 'B')
                return -1; /* that is not a -M, -C nor -B option */
 
-       opt1 = parse_num(&opt);
+       opt1 = parse_rename_score(&opt);
        if (cmd != 'B')
                opt2 = 0;
        else {
@@ -3374,7 +3403,7 @@ static int diff_scoreopt_parse(const char *opt)
                        return -1; /* we expect -B80/99 or -B80 */
                else {
                        opt++;
-                       opt2 = parse_num(&opt);
+                       opt2 = parse_rename_score(&opt);
                }
        }
        if (*opt != 0)
@@ -3527,7 +3556,7 @@ static void diff_flush_stat(struct diff_filepair *p, struct diff_options *o,
 
        if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) ||
            (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
-               return; /* no tree diffs in patch format */
+               return; /* no useful stat for tree diffs */
 
        run_diffstat(p, o, diffstat);
 }
@@ -3540,7 +3569,7 @@ static void diff_flush_checkdiff(struct diff_filepair *p,
 
        if ((DIFF_FILE_VALID(p->one) && S_ISDIR(p->one->mode)) ||
            (DIFF_FILE_VALID(p->two) && S_ISDIR(p->two->mode)))
-               return; /* no tree diffs in patch format */
+               return; /* nothing to check in tree diffs */
 
        run_checkdiff(p, o);
 }
@@ -3865,7 +3894,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
 
                xpp.flags = 0;
                xecfg.ctxlen = 3;
-               xecfg.flags = XDL_EMIT_FUNCNAMES;
+               xecfg.flags = 0;
                xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data,
                              &xpp, &xecfg);
        }
@@ -4176,7 +4205,7 @@ void diffcore_std(struct diff_options *options)
                        diffcore_merge_broken();
        }
        if (options->pickaxe)
-               diffcore_pickaxe(options->pickaxe, options->pickaxe_opts);
+               diffcore_pickaxe(options);
        if (options->orderfile)
                diffcore_order(options->orderfile);
        if (!options->found_follow)
diff --git a/diff.h b/diff.h
index bf2f44d840735684c89f654ee6f3b3a935af2c55..0083d92438916a8188656df140ba70d6acc8c6f6 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -238,6 +238,9 @@ extern int diff_setup_done(struct diff_options *);
 #define DIFF_PICKAXE_ALL       1
 #define DIFF_PICKAXE_REGEX     2
 
+#define DIFF_PICKAXE_KIND_S    4 /* traditional plumbing counter */
+#define DIFF_PICKAXE_KIND_G    8 /* grep in the patch */
+
 extern void diffcore_std(struct diff_options *);
 extern void diffcore_fix_diff_index(struct diff_options *);
 
@@ -312,4 +315,6 @@ extern size_t fill_textconv(struct userdiff_driver *driver,
 
 extern struct userdiff_driver *get_textconv(struct diff_filespec *one);
 
+extern int parse_rename_score(const char **cp_p);
+
 #endif /* DIFF_H */
index 929de15aa9228099b3a772be788d746e440a9e8c..ea03b9107eb2e85dd4a4c5ad93ac08dfe7e1c9f0 100644 (file)
@@ -1,9 +1,148 @@
 /*
  * Copyright (C) 2005 Junio C Hamano
+ * Copyright (C) 2010 Google Inc.
  */
 #include "cache.h"
 #include "diff.h"
 #include "diffcore.h"
+#include "xdiff-interface.h"
+
+struct diffgrep_cb {
+       regex_t *regexp;
+       int hit;
+};
+
+static void diffgrep_consume(void *priv, char *line, unsigned long len)
+{
+       struct diffgrep_cb *data = priv;
+       regmatch_t regmatch;
+       int hold;
+
+       if (line[0] != '+' && line[0] != '-')
+               return;
+       if (data->hit)
+               /*
+                * NEEDSWORK: we should have a way to terminate the
+                * caller early.
+                */
+               return;
+       /* Yuck -- line ought to be "const char *"! */
+       hold = line[len];
+       line[len] = '\0';
+       data->hit = !regexec(data->regexp, line + 1, 1, &regmatch, 0);
+       line[len] = hold;
+}
+
+static void fill_one(struct diff_filespec *one,
+                    mmfile_t *mf, struct userdiff_driver **textconv)
+{
+       if (DIFF_FILE_VALID(one)) {
+               *textconv = get_textconv(one);
+               mf->size = fill_textconv(*textconv, one, &mf->ptr);
+       } else {
+               memset(mf, 0, sizeof(*mf));
+       }
+}
+
+static int diff_grep(struct diff_filepair *p, regex_t *regexp, struct diff_options *o)
+{
+       regmatch_t regmatch;
+       struct userdiff_driver *textconv_one = NULL;
+       struct userdiff_driver *textconv_two = NULL;
+       mmfile_t mf1, mf2;
+       int hit;
+
+       if (diff_unmodified_pair(p))
+               return 0;
+
+       fill_one(p->one, &mf1, &textconv_one);
+       fill_one(p->two, &mf2, &textconv_two);
+
+       if (!mf1.ptr) {
+               if (!mf2.ptr)
+                       return 0; /* ignore unmerged */
+               /* created "two" -- does it have what we are looking for? */
+               hit = !regexec(regexp, p->two->data, 1, &regmatch, 0);
+       } else if (!mf2.ptr) {
+               /* removed "one" -- did it have what we are looking for? */
+               hit = !regexec(regexp, p->one->data, 1, &regmatch, 0);
+       } else {
+               /*
+                * We have both sides; need to run textual diff and see if
+                * the pattern appears on added/deleted lines.
+                */
+               struct diffgrep_cb ecbdata;
+               xpparam_t xpp;
+               xdemitconf_t xecfg;
+
+               memset(&xpp, 0, sizeof(xpp));
+               memset(&xecfg, 0, sizeof(xecfg));
+               ecbdata.regexp = regexp;
+               ecbdata.hit = 0;
+               xecfg.ctxlen = o->context;
+               xecfg.interhunkctxlen = o->interhunkcontext;
+               xdi_diff_outf(&mf1, &mf2, diffgrep_consume, &ecbdata,
+                             &xpp, &xecfg);
+               hit = ecbdata.hit;
+       }
+       if (textconv_one)
+               free(mf1.ptr);
+       if (textconv_two)
+               free(mf2.ptr);
+       return hit;
+}
+
+static void diffcore_pickaxe_grep(struct diff_options *o)
+{
+       struct diff_queue_struct *q = &diff_queued_diff;
+       int i, has_changes, err;
+       regex_t regex;
+       struct diff_queue_struct outq;
+       outq.queue = NULL;
+       outq.nr = outq.alloc = 0;
+
+       err = regcomp(&regex, o->pickaxe, REG_EXTENDED | REG_NEWLINE);
+       if (err) {
+               char errbuf[1024];
+               regerror(err, &regex, errbuf, 1024);
+               regfree(&regex);
+               die("invalid log-grep regex: %s", errbuf);
+       }
+
+       if (o->pickaxe_opts & DIFF_PICKAXE_ALL) {
+               /* Showing the whole changeset if needle exists */
+               for (i = has_changes = 0; !has_changes && i < q->nr; i++) {
+                       struct diff_filepair *p = q->queue[i];
+                       if (diff_grep(p, &regex, o))
+                               has_changes++;
+               }
+               if (has_changes)
+                       return; /* do not munge the queue */
+
+               /*
+                * Otherwise we will clear the whole queue by copying
+                * the empty outq at the end of this function, but
+                * first clear the current entries in the queue.
+                */
+               for (i = 0; i < q->nr; i++)
+                       diff_free_filepair(q->queue[i]);
+       } else {
+               /* Showing only the filepairs that has the needle */
+               for (i = 0; i < q->nr; i++) {
+                       struct diff_filepair *p = q->queue[i];
+                       if (diff_grep(p, &regex, o))
+                               diff_q(&outq, p);
+                       else
+                               diff_free_filepair(p);
+               }
+       }
+
+       regfree(&regex);
+
+       free(q->queue);
+       *q = outq;
+       return;
+}
 
 static unsigned int contains(struct diff_filespec *one,
                             const char *needle, unsigned long len,
@@ -48,8 +187,10 @@ static unsigned int contains(struct diff_filespec *one,
        return cnt;
 }
 
-void diffcore_pickaxe(const char *needle, int opts)
+static void diffcore_pickaxe_count(struct diff_options *o)
 {
+       const char *needle = o->pickaxe;
+       int opts = o->pickaxe_opts;
        struct diff_queue_struct *q = &diff_queued_diff;
        unsigned long len = strlen(needle);
        int i, has_changes;
@@ -128,11 +269,19 @@ void diffcore_pickaxe(const char *needle, int opts)
                                diff_free_filepair(p);
                }
 
-       if (opts & DIFF_PICKAXE_REGEX) {
+       if (opts & DIFF_PICKAXE_REGEX)
                regfree(&regex);
-       }
 
        free(q->queue);
        *q = outq;
        return;
 }
+
+void diffcore_pickaxe(struct diff_options *o)
+{
+       /* Might want to warn when both S and G are on; I don't care... */
+       if (o->pickaxe_opts & DIFF_PICKAXE_KIND_G)
+               diffcore_pickaxe_grep(o);
+       else
+               diffcore_pickaxe_count(o);
+}
index 8b3241ad137f5934e32336cd1caf8d99ca11d1f5..b8f1fdecf4d9e5e8f8e834eb55a374f1af8352fd 100644 (file)
@@ -107,7 +107,7 @@ extern void diff_q(struct diff_queue_struct *, struct diff_filepair *);
 extern void diffcore_break(int);
 extern void diffcore_rename(struct diff_options *);
 extern void diffcore_merge_broken(void);
-extern void diffcore_pickaxe(const char *needle, int opts);
+extern void diffcore_pickaxe(struct diff_options *);
 extern void diffcore_order(const char *orderfile);
 
 #define DIFF_DEBUG 0
diff --git a/dir.c b/dir.c
index 133f472a1e73786e781c1021eea17e543858937f..b2dfb69eb5606a7538cc5e1876a91f703ec4969c 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -232,7 +232,7 @@ int add_excludes_from_file_to_list(const char *fname,
 {
        struct stat st;
        int fd, i;
-       size_t size;
+       size_t size = 0;
        char *buf, *entry;
 
        fd = open(fname, O_RDONLY);
@@ -360,7 +360,8 @@ int excluded_from_list(const char *pathname,
 
                        if (x->flags & EXC_FLAG_MUSTBEDIR) {
                                if (!dtype) {
-                                       if (!prefixcmp(pathname, exclude))
+                                       if (!prefixcmp(pathname, exclude) &&
+                                           pathname[x->patternlen] == '/')
                                                return to_exclude;
                                        else
                                                continue;
index 2d0c3153791d7cceffb12f50dd5a7716b8c0a8c0..de5581fe51d532231b0121bd2ef2e46669015bda 100644 (file)
@@ -64,7 +64,7 @@ char *git_work_tree_cfg;
 static char *work_tree;
 
 static const char *git_dir;
-static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file;
+static char *git_object_dir, *git_index_file, *git_graft_file;
 
 /*
  * Repository-local GIT_* environment variables
@@ -87,8 +87,10 @@ const char * const local_repo_env[LOCAL_REPO_ENV_SIZE + 1] = {
 static void setup_git_env(void)
 {
        git_dir = getenv(GIT_DIR_ENVIRONMENT);
-       if (!git_dir)
+       if (!git_dir) {
                git_dir = read_gitfile_gently(DEFAULT_GIT_DIR_ENVIRONMENT);
+               git_dir = git_dir ? xstrdup(git_dir) : NULL;
+       }
        if (!git_dir)
                git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
        git_object_dir = getenv(DB_ENVIRONMENT);
@@ -96,8 +98,6 @@ static void setup_git_env(void)
                git_object_dir = xmalloc(strlen(git_dir) + 9);
                sprintf(git_object_dir, "%s/objects", git_dir);
        }
-       git_refs_dir = xmalloc(strlen(git_dir) + 6);
-       sprintf(git_refs_dir, "%s/refs", git_dir);
        git_index_file = getenv(INDEX_ENVIRONMENT);
        if (!git_index_file) {
                git_index_file = xmalloc(strlen(git_dir) + 7);
index 2317b0fe7509b957577234890135509143c0872b..77549ebd6fbfbea051901d4ab474eebc8e2dbdbd 100644 (file)
@@ -1454,6 +1454,15 @@ static int tree_content_set(
                n = slash1 - p;
        else
                n = strlen(p);
+       if (!slash1 && !n) {
+               if (!S_ISDIR(mode))
+                       die("Root cannot be a non-directory");
+               hashcpy(root->versions[1].sha1, sha1);
+               if (root->tree)
+                       release_tree_content_recursive(root->tree);
+               root->tree = subtree;
+               return 1;
+       }
        if (!n)
                die("Empty path component found in input");
        if (!slash1 && !S_ISDIR(mode) && subtree)
@@ -2884,7 +2893,7 @@ static int git_pack_config(const char *k, const char *v, void *cb)
 }
 
 static const char fast_import_usage[] =
-"git fast-import [--date-format=f] [--max-pack-size=n] [--big-file-threshold=n] [--depth=n] [--active-branches=n] [--export-marks=marks.file]";
+"git fast-import [--date-format=<f>] [--max-pack-size=<n>] [--big-file-threshold=<n>] [--depth=<n>] [--active-branches=<n>] [--export-marks=<marks.file>]";
 
 static void parse_argv(void)
 {
index 27fc79347af428dd39daa5b550814cc6cf980510..77f60fa3960323e412f8d09968e63865cc639298 100755 (executable)
@@ -1,6 +1,8 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
 
+use 5.008;
 use strict;
+use warnings;
 use Git;
 
 binmode(STDOUT, ":raw");
index e7f008c7baae2ff484e16882e199b6b9d75195aa..df09b42840b7675e135605f9108894ce93e6d477 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -5,7 +5,7 @@
 SUBDIRECTORY_OK=Yes
 OPTIONS_KEEPDASHDASH=
 OPTIONS_SPEC="\
-git am [options] [<mbox>|<Maildir>...]
+git am [options] [(<mbox>|<Maildir>)...]
 git am [options] (--resolved | --skip | --abort)
 --
 i,interactive   run interactively
@@ -137,7 +137,7 @@ It does not apply to blobs recorded in its index."
     export GITHEAD_$his_tree
     if test -n "$GIT_QUIET"
     then
-           export GIT_MERGE_VERBOSITY=0
+           GIT_MERGE_VERBOSITY=0 && export GIT_MERGE_VERBOSITY
     fi
     git-merge-recursive $orig_tree -- HEAD $his_tree || {
            git rerere $allow_rerere_autoupdate
@@ -444,12 +444,12 @@ else
                                set x
                                first=
                        }
-                       case "$arg" in
-                       /*)
-                               set "$@" "$arg" ;;
-                       *)
-                               set "$@" "$prefix$arg" ;;
-                       esac
+                       if is_absolute_path "$arg"
+                       then
+                               set "$@" "$arg"
+                       else
+                               set "$@" "$prefix$arg"
+                       fi
                done
                shift
        fi
index 98f3ede566a6cb0c902ce84795f7de8f8afbe633..bc32f18d6d9cbf915eb7797817390adbbc111506 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
 #
 # This tool is copyright (c) 2005, Martin Langhoff.
 # It is released under the Gnu Public License, version 2.
@@ -54,6 +54,7 @@ and can contain multiple, unrelated branches.
 
 =cut
 
+use 5.008;
 use strict;
 use warnings;
 use Getopt::Std;
index 6e2acb8ef29e5003945bed17014a68b141ada454..c21e33c8d133af0e9e0ae3edaffd0a5593ff4ac3 100755 (executable)
@@ -316,7 +316,12 @@ bisect_reset() {
        *)
            usage ;;
        esac
-       git checkout "$branch" -- && bisect_clean_state
+       if git checkout "$branch" -- ; then
+               bisect_clean_state
+       else
+               die "Could not check out original HEAD '$branch'." \
+                               "Try 'git bisect reset <commit>'."
+       fi
 }
 
 bisect_clean_state() {
@@ -338,6 +343,7 @@ bisect_clean_state() {
 }
 
 bisect_replay () {
+       test "$#" -eq 1 || die "No logfile given"
        test -r "$1" || die "cannot read $1 for replaying"
        bisect_reset
        while read git bisect command rev
@@ -412,6 +418,10 @@ bisect_run () {
     done
 }
 
+bisect_log () {
+       test -s "$GIT_DIR/BISECT_LOG" || die "We are not bisecting."
+       cat "$GIT_DIR/BISECT_LOG"
+}
 
 case "$#" in
 0)
@@ -438,7 +448,7 @@ case "$#" in
     replay)
        bisect_replay "$@" ;;
     log)
-       cat "$GIT_DIR/BISECT_LOG" ;;
+       bisect_log ;;
     run)
         bisect_run "$@" ;;
     *)
index 81883e7270daadafb4d827e894fa4645ff2e2b66..2af8d3edbe35dce35e940c5cccb91f9e06ebeff8 100644 (file)
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
 #define bitsizeof(x)  (CHAR_BIT * sizeof(x))
 
+#define maximum_signed_value_of_type(a) \
+    (INTMAX_MAX >> (bitsizeof(intmax_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.
+ *
+ * Requires: a >= 0, typeof(a) equals typeof(b)
+ */
+#define signed_add_overflows(a, b) \
+    ((b) > maximum_signed_value_of_type(a) - (a))
+
 #ifdef __GNUC__
 #define TYPEOF(x) (__typeof__(x))
 #else
index 59b672213bfc36f95db089f0e13bafc1c2f2ed71..39a426e067c76e01d3f2a0d63243ec494436da46 100755 (executable)
@@ -1,6 +1,8 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
 
+use 5.008;
 use strict;
+use warnings;
 use Getopt::Std;
 use File::Temp qw(tempdir);
 use Data::Dumper;
index 9e03eee4586ca3b7476b56f66e9dcf6ffe3088cf..d27abfe7f32ef47ee8b613293110147ca3006575 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
 
 # This tool is copyright (c) 2005, Matthias Urlichs.
 # It is released under the Gnu Public License, version 2.
@@ -13,6 +13,7 @@
 # The head revision is on branch "origin" by default.
 # You can change that with the '-o' option.
 
+use 5.008;
 use strict;
 use warnings;
 use Getopt::Long;
@@ -611,7 +612,7 @@ my %index; # holds filenames of one index per branch
 unless (-d $git_dir) {
        system(qw(git init));
        die "Cannot init the GIT db at $git_tree: $?\n" if $?;
-       system(qw(git read-tree));
+       system(qw(git read-tree --empty));
        die "Cannot init an empty tree: $?\n" if $?;
 
        $last_branch = $opt_o;
index e9f3037df351ceed0262a8995f19903464163af8..1b8bff2cac163a6588df397168f57214c30b4784 100755 (executable)
@@ -8,13 +8,14 @@
 #### Copyright The Open University UK - 2006.
 ####
 #### Authors: Martyn Smith    <martyn@catalyst.net.nz>
-####          Martin Langhoff <martin@catalyst.net.nz>
+####          Martin Langhoff <martin@laptop.org>
 ####
 ####
 #### Released under the GNU Public License, version 2.
 ####
 ####
 
+use 5.008;
 use strict;
 use warnings;
 use bytes;
@@ -2680,7 +2681,7 @@ package GITCVS::log;
 #### Copyright The Open University UK - 2006.
 ####
 #### Authors: Martyn Smith    <martyn@catalyst.net.nz>
-####          Martin Langhoff <martin@catalyst.net.nz>
+####          Martin Langhoff <martin@laptop.org>
 ####
 ####
 
@@ -2847,7 +2848,7 @@ package GITCVS::updater;
 #### Copyright The Open University UK - 2006.
 ####
 #### Authors: Martyn Smith    <martyn@catalyst.net.nz>
-####          Martin Langhoff <martin@catalyst.net.nz>
+####          Martin Langhoff <martin@laptop.org>
 ####
 ####
 
index adc42de8752fd395707f1e395c61991b3146cebb..e95e4ad973f21dd104950dc6ebb28485844b36f4 100755 (executable)
@@ -10,6 +10,7 @@
 #
 # Any arguments that are unknown to this script are forwarded to 'git diff'.
 
+use 5.008;
 use strict;
 use warnings;
 use Cwd qw(abs_path);
index 4617f29c26726c2cd438f160be21a8422e66b352..d3acf0d2134b40b8ffb3d0e8c3229f71fa6db663 100755 (executable)
@@ -83,6 +83,7 @@ if {![catch {set _verbose $env(GITGUI_VERBOSE)}]} {
                puts stderr "source    $name"
                uplevel 1 real__source $name
        }
+       if {[tk windowingsystem] eq "win32"} { console show }
 }
 
 ######################################################################
@@ -444,6 +445,8 @@ proc _lappend_nice {cmd_var} {
                set _nice [_which nice]
                if {[catch {exec $_nice git version}]} {
                        set _nice {}
+               } elseif {[is_Windows] && [file dirname $_nice] ne [file dirname $::_git]} {
+                       set _nice {}
                }
        }
        if {$_nice ne {}} {
@@ -673,6 +676,7 @@ bind . <Visibility> {
 if {[is_Windows]} {
        wm iconbitmap . -default $oguilib/git-gui.ico
        set ::tk::AlwaysShowSelection 1
+       bind . <Control-F2> {console show}
 
        # Spoof an X11 display for SSH
        if {![info exists env(DISPLAY)]} {
@@ -874,12 +878,19 @@ if {![regsub {^git version } $_git_version {} _git_version]} {
        exit 1
 }
 
+proc get_trimmed_version {s} {
+    set r {}
+    foreach x [split $s -._] {
+        if {[string is integer -strict $x]} {
+            lappend r $x
+        } else {
+            break
+        }
+    }
+    return [join $r .]
+}
 set _real_git_version $_git_version
-regsub -- {[\-\.]dirty$} $_git_version {} _git_version
-regsub {\.[0-9]+\.g[0-9a-f]+$} $_git_version {} _git_version
-regsub {\.[a-zA-Z]+\.?[0-9]+$} $_git_version {} _git_version
-regsub {\.GIT$} $_git_version {} _git_version
-regsub {\.[a-zA-Z]+\.?[0-9]+$} $_git_version {} _git_version
+set _git_version [get_trimmed_version $_git_version]
 
 if {![regexp {^[1-9]+(\.[0-9]+)+$} $_git_version]} {
        catch {wm withdraw .}
@@ -1183,13 +1194,22 @@ if {![file isdirectory $_gitdir]} {
 # _gitdir exists, so try loading the config
 load_config 0
 apply_config
-# try to set work tree from environment, falling back to core.worktree
-if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} {
-       set _gitworktree [get_config core.worktree]
-       if {$_gitworktree eq ""} {
-               set _gitworktree [file dirname [file normalize $_gitdir]]
+
+# v1.7.0 introduced --show-toplevel to return the canonical work-tree
+if {[package vsatisfies $_git_version 1.7.0]} {
+       set _gitworktree [git rev-parse --show-toplevel]
+} else {
+       # try to set work tree from environment, core.worktree or use
+       # cdup to obtain a relative path to the top of the worktree. If
+       # run from the top, the ./ prefix ensures normalize expands pwd.
+       if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} {
+               set _gitworktree [get_config core.worktree]
+               if {$_gitworktree eq ""} {
+                       set _gitworktree [file normalize ./[git rev-parse --show-cdup]]
+               }
        }
 }
+
 if {$_prefix ne {}} {
        if {$_gitworktree eq {}} {
                regsub -all {[^/]+/} $_prefix ../ cdup
@@ -2861,7 +2881,8 @@ proc usage {} {
        set s "usage: $::argv0 $::subcommand $::subcommand_args"
        if {[tk windowingsystem] eq "win32"} {
                wm withdraw .
-               tk_messageBox -icon info -title "Usage" -message $s
+               tk_messageBox -icon info -message $s \
+                       -title [mc "Usage"]
        } else {
                puts stderr $s
        }
@@ -2934,7 +2955,11 @@ blame {
                        if {[catch {
                                        set head [git rev-parse --verify $head]
                                } err]} {
-                               puts stderr $err
+                               if {[tk windowingsystem] eq "win32"} {
+                                       tk_messageBox -icon error -title [mc Error] -message $err
+                               } else {
+                                       puts stderr $err
+                               }
                                exit 1
                        }
                }
@@ -2973,18 +2998,19 @@ blame {
 citool -
 gui {
        if {[llength $argv] != 0} {
-               puts -nonewline stderr "usage: $argv0"
-               if {$subcommand ne {gui}
-                       && [file tail $argv0] ne "git-$subcommand"} {
-                       puts -nonewline stderr " $subcommand"
-               }
-               puts stderr {}
-               exit 1
+               usage
        }
        # fall through to setup UI for commits
 }
 default {
-       puts stderr "usage: $argv0 \[{blame|browser|citool}\]"
+       set err "usage: $argv0 \[{blame|browser|citool}\]"
+       if {[tk windowingsystem] eq "win32"} {
+               wm withdraw .
+               tk_messageBox -icon error -message $err \
+                       -title [mc "Usage"]
+       } else {
+               puts stderr $err
+       }
        exit 1
 }
 }
@@ -3286,6 +3312,7 @@ text $ui_diff -background white -foreground black \
        -xscrollcommand {.vpane.lower.diff.body.sbx set} \
        -yscrollcommand {.vpane.lower.diff.body.sby set} \
        -state disabled
+catch {$ui_diff configure -tabstyle wordprocessor}
 ${NS}::scrollbar .vpane.lower.diff.body.sbx -orient horizontal \
        -command [list $ui_diff xview]
 ${NS}::scrollbar .vpane.lower.diff.body.sby -orient vertical \
@@ -3296,8 +3323,16 @@ pack $ui_diff -side left -fill both -expand 1
 pack .vpane.lower.diff.header -side top -fill x
 pack .vpane.lower.diff.body -side bottom -fill both -expand 1
 
+foreach {n c} {0 black 1 red4 2 green4 3 yellow4 4 blue4 5 magenta4 6 cyan4 7 grey60} {
+       $ui_diff tag configure clr4$n -background $c
+       $ui_diff tag configure clri4$n -foreground $c
+       $ui_diff tag configure clr3$n -foreground $c
+       $ui_diff tag configure clri3$n -background $c
+}
+$ui_diff tag configure clr1 -font font_diffbold
+
 $ui_diff tag conf d_cr -elide true
-$ui_diff tag conf d_@ -foreground blue -font font_diffbold
+$ui_diff tag conf d_@ -font font_diffbold
 $ui_diff tag conf d_+ -foreground {#00a000}
 $ui_diff tag conf d_- -foreground red
 
index 63988773ba0d02af3dc91474b4a1669ecda27c5c..6e510ec2e39305e6d89de61ab2c925bcbc821a65 100644 (file)
@@ -53,7 +53,7 @@ constructor dialog {} {
                        return 1
                }
 
-       grid $w.rename.oldname_l $w.rename.oldname_m -sticky w  -padx {0 5}
+       grid $w.rename.oldname_l $w.rename.oldname_m -sticky we -padx {0 5}
        grid $w.rename.newname_l $w.rename.newname_t -sticky we -padx {0 5}
        grid columnconfigure $w.rename 1 -weight 1
        pack $w.rename -anchor nw -fill x -pady 5 -padx 5
index c628750276303fca620c9292463c4c59690c764f..dcf0711be0119a8f5ec42b48d97980330f7113b3 100644 (file)
@@ -294,7 +294,7 @@ proc start_show_diff {cont_info {add_opts {}}} {
        }
 
        lappend cmd -p
-       lappend cmd --no-color
+       lappend cmd --color
        if {$repo_config(gui.diffcontext) >= 1} {
                lappend cmd "-U$repo_config(gui.diffcontext)"
        }
@@ -332,6 +332,23 @@ proc start_show_diff {cont_info {add_opts {}}} {
        fileevent $fd readable [list read_diff $fd $cont_info]
 }
 
+proc parse_color_line {line} {
+       set start 0
+       set result ""
+       set markup [list]
+       set regexp {\033\[((?:\d+;)*\d+)?m}
+       while {[regexp -indices -start $start $regexp $line match code]} {
+               foreach {begin end} $match break
+               append result [string range $line $start [expr {$begin - 1}]]
+               lappend markup [string length $result] \
+                       [eval [linsert $code 0 string range $line]]
+               set start [incr end]
+       }
+       append result [string range $line $start end]
+       if {[llength $markup] < 4} {set markup {}}
+       return [list $result $markup]
+}
+
 proc read_diff {fd cont_info} {
        global ui_diff diff_active is_submodule_diff
        global is_3way_diff is_conflict_diff current_diff_header
@@ -340,6 +357,9 @@ proc read_diff {fd cont_info} {
 
        $ui_diff conf -state normal
        while {[gets $fd line] >= 0} {
+               foreach {line markup} [parse_color_line $line] break
+               set line [string map {\033 ^} $line]
+
                # -- Cleanup uninteresting diff header lines.
                #
                if {$::current_diff_inheader} {
@@ -434,11 +454,23 @@ proc read_diff {fd cont_info} {
                        }
                        }
                }
+               set mark [$ui_diff index "end - 1 line linestart"]
                $ui_diff insert end $line $tags
                if {[string index $line end] eq "\r"} {
                        $ui_diff tag add d_cr {end - 2c}
                }
                $ui_diff insert end "\n" $tags
+
+               foreach {posbegin colbegin posend colend} $markup {
+                       set prefix clr
+                       foreach style [split $colbegin ";"] {
+                               if {$style eq "7"} {append prefix i; continue}
+                               if {$style < 30 || $style > 47} {continue}
+                               set a "$mark linestart + $posbegin chars"
+                               set b "$mark linestart + $posend chars"
+                               catch {$ui_diff tag add $prefix$style $a $b}
+                       }
+               }
        }
        $ui_diff conf -state disabled
 
index 615753c83c38f4a97752d5ca3400beeef4acd5f1..8643f74cb09f278c37851c418e839c7d160f36ca 100755 (executable)
@@ -61,6 +61,11 @@ do
        esac
 
        eval pretty_name=\${GITHEAD_$SHA1:-$SHA1}
+       if test "$SHA1" = "$pretty_name"
+       then
+               SHA1_UP="$(echo "$SHA1" | tr a-z A-Z)"
+               eval pretty_name=\${GITHEAD_$SHA1_UP:-$pretty_name}
+       fi
        common=$(git merge-base --all $SHA1 $MRC) ||
                die "Unable to find common commit with $pretty_name"
 
index b5e1943b1d166b543998c80579c65e82de36516a..77d4aee20ee5b8b01f9a0e3d1f8dbc9f7fdf3eb9 100644 (file)
@@ -10,10 +10,10 @@ merge_mode() {
 
 translate_merge_tool_path () {
        case "$1" in
-       vimdiff)
+       vimdiff|vimdiff2)
                echo vim
                ;;
-       gvimdiff)
+       gvimdiff|gvimdiff2)
                echo gvim
                ;;
        emerge)
@@ -47,7 +47,8 @@ check_unchanged () {
 valid_tool () {
        case "$1" in
        kdiff3 | tkdiff | xxdiff | meld | opendiff | \
-       emerge | vimdiff | gvimdiff | ecmerge | diffuse | araxis | p4merge)
+       vimdiff | gvimdiff | vimdiff2 | gvimdiff2 | \
+       emerge | ecmerge | diffuse | araxis | p4merge)
                ;; # happy
        tortoisemerge)
                if ! merge_mode; then
@@ -169,25 +170,30 @@ run_merge_tool () {
                        "$merge_tool_path" "$LOCAL" "$REMOTE" | cat
                fi
                ;;
-       vimdiff)
+       vimdiff|gvimdiff)
                if merge_mode; then
                        touch "$BACKUP"
-                       "$merge_tool_path" -d -c "wincmd l" \
-                               "$LOCAL" "$MERGED" "$REMOTE"
+                       if $base_present; then
+                               "$merge_tool_path" -f -d -c "wincmd J" \
+                                       "$MERGED" "$LOCAL" "$BASE" "$REMOTE"
+                       else
+                               "$merge_tool_path" -f -d -c "wincmd l" \
+                                       "$LOCAL" "$MERGED" "$REMOTE"
+                       fi
                        check_unchanged
                else
-                       "$merge_tool_path" -d -c "wincmd l" \
+                       "$merge_tool_path" -f -d -c "wincmd l" \
                                "$LOCAL" "$REMOTE"
                fi
                ;;
-       gvimdiff)
+       vimdiff2|gvimdiff2)
                if merge_mode; then
                        touch "$BACKUP"
-                       "$merge_tool_path" -d -c "wincmd l" -f \
+                       "$merge_tool_path" -f -d -c "wincmd l" \
                                "$LOCAL" "$MERGED" "$REMOTE"
                        check_unchanged
                else
-                       "$merge_tool_path" -d -c "wincmd l" -f \
+                       "$merge_tool_path" -f -d -c "wincmd l" \
                                "$LOCAL" "$REMOTE"
                fi
                ;;
index 3335cee70b8ea5510f109da83d8470d3bbabab52..10a238ae3cc942bc021db18195b7098e2866c266 100755 (executable)
@@ -111,7 +111,7 @@ call_merge () {
        export GITHEAD_$cmt GITHEAD_$hd
        if test -n "$GIT_QUIET"
        then
-               export GIT_MERGE_VERBOSITY=1
+               GIT_MERGE_VERBOSITY=1 && export GIT_MERGE_VERBOSITY
        fi
        eval 'git-merge-$strategy' $strategy_opts '"$cmt^" -- "$hd" "$cmt"'
        rv=$?
@@ -311,10 +311,6 @@ do
                esac
                strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--$newopt")"
                do_merge=t
-               if test -n "$strategy"
-               then
-                       strategy=recursive
-               fi
                ;;
        -s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\
                --strateg=*|--strategy=*|\
index 937c69a74858a8a3c63bb41a23705b579df1b3a3..e136732cea80c1594ac02c93cf246e8c77ff89b8 100755 (executable)
@@ -6,7 +6,7 @@
 #
 # Scan two git object-trees, and hardlink any common objects between them.
 
-use 5.006;
+use 5.008;
 use strict;
 use warnings;
 use Getopt::Long;
@@ -163,7 +163,7 @@ sub link_two_files($$) {
 
 
 sub usage() {
-       print("Usage: git relink [--safe] <dir> [<dir> ...] <master_dir> \n");
+       print("Usage: git relink [--safe] <dir>... <master_dir> \n");
        print("All directories should contain a .git/objects/ subdirectory.\n");
        print("Options\n");
        print("\t--safe\t" .
index d21b274de9a8a24684d86d71f1c224cce9dda113..624feec26f66b15926ffa11767c146222bc9a185 100755 (executable)
@@ -10,7 +10,8 @@ git repack [options]
 a               pack everything in a single pack
 A               same as -a, and turn unreachable objects loose
 d               remove redundant packs, and run git-prune-packed
-f               pass --no-reuse-object to git-pack-objects
+f               pass --no-reuse-delta to git-pack-objects
+F               pass --no-reuse-object to git-pack-objects
 n               do not run git-update-server-info
 q,quiet         be quiet
 l               pass --local to git-pack-objects
@@ -34,7 +35,8 @@ do
                unpack_unreachable=--unpack-unreachable ;;
        -d)     remove_redundant=t ;;
        -q)     GIT_QUIET=t ;;
-       -f)     no_reuse=--no-reuse-object ;;
+       -f)     no_reuse=--no-reuse-delta ;;
+       -F)     no_reuse=--no-reuse-object ;;
        -l)     local=--local ;;
        --max-pack-size|--window|--window-memory|--depth)
                extra="$extra $1=$2"; shift ;;
index 6dab3bf6a74bb52c7294e33dbac5bf87b51a9fdf..f68ed5a5d3208eb0669d7dc1289f40c567e077c7 100755 (executable)
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
 #
 # Copyright 2002,2005 Greg Kroah-Hartman <greg@kroah.com>
 # Copyright 2005 Ryan Anderson <ryan@michonline.com>
@@ -16,6 +16,7 @@
 #    and second line is the subject of the message.
 #
 
+use 5.008;
 use strict;
 use warnings;
 use Term::ReadLine;
@@ -24,6 +25,7 @@ use Text::ParseWords;
 use Data::Dumper;
 use Term::ANSIColor;
 use File::Temp qw/ tempdir tempfile /;
+use File::Spec::Functions qw(catfile);
 use Error qw(:try);
 use Git;
 
@@ -60,6 +62,7 @@ git send-email [options] <file | directory | rev-list options >
     --envelope-sender       <str>  * Email envelope sender.
     --smtp-server       <str:int>  * Outgoing SMTP server to use. The port
                                      is optional. Default 'localhost'.
+    --smtp-server-option    <str>  * Outgoing SMTP server option to use.
     --smtp-server-port      <int>  * Outgoing SMTP server port.
     --smtp-user             <str>  * Username for SMTP-AUTH.
     --smtp-pass             <str>  * Password for SMTP-AUTH; not necessary.
@@ -70,6 +73,7 @@ git send-email [options] <file | directory | rev-list options >
 
   Automating:
     --identity              <str>  * Use the sendemail.<id> options.
+    --to-cmd                <str>  * Email To: via `<str> \$patch_path`
     --cc-cmd                <str>  * Email Cc: via `<str> \$patch_path`
     --suppress-cc           <str>  * author, self, sob, cc, cccmd, body, bodycc, all.
     --[no-]signed-off-by-cc        * Send to Signed-off-by: addresses. Default on.
@@ -85,6 +89,7 @@ git send-email [options] <file | directory | rev-list options >
     --[no-]validate                * Perform patch sanity checks. Default on.
     --[no-]format-patch            * understand any non optional arguments as
                                      `git format-patch` ones.
+    --force                        * Send even if safety checks would prevent it.
 
 EOT
        exit(1);
@@ -134,11 +139,8 @@ my $have_mail_address = eval { require Mail::Address; 1 };
 my $smtp;
 my $auth;
 
-sub unique_email_list(@);
-sub cleanup_compose_files();
-
 # Variables we fill in automatically, or via prompting:
-my (@to,$no_to,@cc,$no_cc,@initial_cc,@bcclist,$no_bcc,@xh,
+my (@to,$no_to,@initial_to,@cc,$no_cc,@initial_cc,@bcclist,$no_bcc,@xh,
        $initial_reply_to,$initial_subject,@files,
        $author,$sender,$smtp_authpass,$annotate,$compose,$time);
 
@@ -162,6 +164,7 @@ if ($@) {
 my ($quiet, $dry_run) = (0, 0);
 my $format_patch;
 my $compose_filename;
+my $force = 0;
 
 # Handle interactive edition of files.
 my $multiedit;
@@ -187,9 +190,11 @@ sub do_edit {
 }
 
 # Variables with corresponding config settings
-my ($thread, $chain_reply_to, $suppress_from, $signed_off_by_cc, $cc_cmd);
-my ($smtp_server, $smtp_server_port, $smtp_authuser, $smtp_encryption);
-my ($identity, $aliasfiletype, @alias_files, @smtp_host_parts, $smtp_domain);
+my ($thread, $chain_reply_to, $suppress_from, $signed_off_by_cc);
+my ($to_cmd, $cc_cmd);
+my ($smtp_server, $smtp_server_port, @smtp_server_options);
+my ($smtp_authuser, $smtp_encryption);
+my ($identity, $aliasfiletype, @alias_files, $smtp_domain);
 my ($validate, $confirm);
 my (@suppress_cc);
 my ($auto_8bit_encoding);
@@ -210,10 +215,12 @@ my %config_bool_settings = (
 my %config_settings = (
     "smtpserver" => \$smtp_server,
     "smtpserverport" => \$smtp_server_port,
+    "smtpserveroption" => \@smtp_server_options,
     "smtpuser" => \$smtp_authuser,
     "smtppass" => \$smtp_authpass,
-       "smtpdomain" => \$smtp_domain,
-    "to" => \@to,
+    "smtpdomain" => \$smtp_domain,
+    "to" => \@initial_to,
+    "tocmd" => \$to_cmd,
     "cc" => \@initial_cc,
     "cccmd" => \$cc_cmd,
     "aliasfiletype" => \$aliasfiletype,
@@ -271,7 +278,8 @@ $SIG{INT}  = \&signal_handler;
 my $rc = GetOptions("sender|from=s" => \$sender,
                     "in-reply-to=s" => \$initial_reply_to,
                    "subject=s" => \$initial_subject,
-                   "to=s" => \@to,
+                   "to=s" => \@initial_to,
+                   "to-cmd=s" => \$to_cmd,
                    "no-to" => \$no_to,
                    "cc=s" => \@initial_cc,
                    "no-cc" => \$no_cc,
@@ -279,6 +287,7 @@ my $rc = GetOptions("sender|from=s" => \$sender,
                    "no-bcc" => \$no_bcc,
                    "chain-reply-to!" => \$chain_reply_to,
                    "smtp-server=s" => \$smtp_server,
+                   "smtp-server-option=s" => \@smtp_server_options,
                    "smtp-server-port=s" => \$smtp_server_port,
                    "smtp-user=s" => \$smtp_authuser,
                    "smtp-pass:s" => \$smtp_authpass,
@@ -301,6 +310,7 @@ my $rc = GetOptions("sender|from=s" => \$sender,
                    "validate!" => \$validate,
                    "format-patch!" => \$format_patch,
                    "8bit-encoding=s" => \$auto_8bit_encoding,
+                   "force" => \$force,
         );
 
 unless ($rc) {
@@ -364,7 +374,7 @@ my(%suppress_cc);
 if (@suppress_cc) {
        foreach my $entry (@suppress_cc) {
                die "Unknown --suppress-cc field: '$entry'\n"
-                       unless $entry =~ /^(all|cccmd|cc|author|self|sob|body|bodycc)$/;
+                       unless $entry =~ /^(?:all|cccmd|cc|author|self|sob|body|bodycc)$/;
                $suppress_cc{$entry} = 1;
        }
 }
@@ -409,7 +419,7 @@ my ($repoauthor, $repocommitter);
 
 # Verify the user input
 
-foreach my $entry (@to) {
+foreach my $entry (@initial_to) {
        die "Comma in --to entry: $entry'\n" unless $entry !~ m/,/;
 }
 
@@ -508,12 +518,12 @@ while (defined(my $f = shift @ARGV)) {
                push @rev_list_opts, "--", @ARGV;
                @ARGV = ();
        } elsif (-d $f and !check_file_rev_conflict($f)) {
-               opendir(DH,$f)
+               opendir my $dh, $f
                        or die "Failed to opendir $f: $!";
 
-               push @files, grep { -f $_ } map { +$f . "/" . $_ }
-                               sort readdir(DH);
-               closedir(DH);
+               push @files, grep { -f $_ } map { catfile($f, $_) }
+                               sort readdir $dh;
+               closedir $dh;
        } elsif ((-f $f or -p $f) and !check_file_rev_conflict($f)) {
                push @files, $f;
        } else {
@@ -545,7 +555,7 @@ if (@files) {
        usage();
 }
 
-sub get_patch_subject($) {
+sub get_patch_subject {
        my $fn = shift;
        open (my $fh, '<', $fn);
        while (my $line = <$fh>) {
@@ -563,7 +573,7 @@ if ($compose) {
        $compose_filename = ($repo ?
                tempfile(".gitsendemail.msg.XXXXXX", DIR => $repo->repo_path()) :
                tempfile(".gitsendemail.msg.XXXXXX", DIR => "."))[1];
-       open(C,">",$compose_filename)
+       open my $c, ">", $compose_filename
                or die "Failed to open for writing $compose_filename: $!";
 
 
@@ -571,7 +581,7 @@ if ($compose) {
        my $tpl_subject = $initial_subject || '';
        my $tpl_reply_to = $initial_reply_to || '';
 
-       print C <<EOT;
+       print $c <<EOT;
 From $tpl_sender # This line is ignored.
 GIT: Lines beginning in "GIT:" will be removed.
 GIT: Consider including an overall diffstat or table of contents
@@ -584,9 +594,9 @@ In-Reply-To: $tpl_reply_to
 
 EOT
        for my $f (@files) {
-               print C get_patch_subject($f);
+               print $c get_patch_subject($f);
        }
-       close(C);
+       close $c;
 
        if ($annotate) {
                do_edit($compose_filename, @files);
@@ -594,23 +604,23 @@ EOT
                do_edit($compose_filename);
        }
 
-       open(C2,">",$compose_filename . ".final")
+       open my $c2, ">", $compose_filename . ".final"
                or die "Failed to open $compose_filename.final : " . $!;
 
-       open(C,"<",$compose_filename)
+       open $c, "<", $compose_filename
                or die "Failed to open $compose_filename : " . $!;
 
        my $need_8bit_cte = file_has_nonascii($compose_filename);
        my $in_body = 0;
        my $summary_empty = 1;
-       while(<C>) {
+       while(<$c>) {
                next if m/^GIT:/;
                if ($in_body) {
                        $summary_empty = 0 unless (/^\n$/);
                } elsif (/^\n$/) {
                        $in_body = 1;
                        if ($need_8bit_cte) {
-                               print C2 "MIME-Version: 1.0\n",
+                               print $c2 "MIME-Version: 1.0\n",
                                         "Content-Type: text/plain; ",
                                           "charset=UTF-8\n",
                                         "Content-Transfer-Encoding: 8bit\n";
@@ -635,10 +645,10 @@ EOT
                        print "To/Cc/Bcc fields are not interpreted yet, they have been ignored\n";
                        next;
                }
-               print C2 $_;
+               print $c2 $_;
        }
-       close(C);
-       close(C2);
+       close $c;
+       close $c2;
 
        if ($summary_empty) {
                print "Summary email is empty, skipping it\n";
@@ -675,7 +685,7 @@ sub ask {
 
 my %broken_encoding;
 
-sub file_declares_8bit_cte($) {
+sub file_declares_8bit_cte {
        my $fn = shift;
        open (my $fh, '<', $fn);
        while (my $line = <$fh>) {
@@ -702,6 +712,16 @@ if (!defined $auto_8bit_encoding && scalar %broken_encoding) {
                                  default => "UTF-8");
 }
 
+if (!$force) {
+       for my $f (@files) {
+               if (get_patch_subject($f) =~ /\Q*** SUBJECT HERE ***\E/) {
+                       die "Refusing to send because the patch\n\t$f\n"
+                               . "has the template subject '*** SUBJECT HERE ***'. "
+                               . "Pass --force if you really want to send.\n";
+               }
+       }
+}
+
 my $prompting = 0;
 if (!defined $sender) {
        $sender = $repoauthor || $repocommitter || '';
@@ -711,9 +731,9 @@ if (!defined $sender) {
        $prompting++;
 }
 
-if (!@to) {
+if (!@initial_to && !defined $to_cmd) {
        my $to = ask("Who should the emails be sent to? ");
-       push @to, parse_address_line($to) if defined $to; # sanitized/validated later
+       push @initial_to, parse_address_line($to) if defined $to; # sanitized/validated later
        $prompting++;
 }
 
@@ -731,8 +751,8 @@ sub expand_one_alias {
        return $aliases{$alias} ? expand_aliases(@{$aliases{$alias}}) : $alias;
 }
 
-@to = expand_aliases(@to);
-@to = (map { sanitize_address($_) } @to);
+@initial_to = expand_aliases(@initial_to);
+@initial_to = (map { sanitize_address($_) } @initial_to);
 @initial_cc = expand_aliases(@initial_cc);
 @bcclist = expand_aliases(@bcclist);
 
@@ -766,8 +786,8 @@ our ($message_id, %mail, $subject, $reply_to, $references, $message,
 
 sub extract_valid_address {
        my $address = shift;
-       my $local_part_regexp = '[^<>"\s@]+';
-       my $domain_regexp = '[^.<>"\s@]+(?:\.[^.<>"\s@]+)+';
+       my $local_part_regexp = qr/[^<>"\s@]+/;
+       my $domain_regexp = qr/[^.<>"\s@]+(?:\.[^.<>"\s@]+)+/;
 
        # check for a local address:
        return $address if ($address =~ /^($local_part_regexp)$/);
@@ -808,7 +828,7 @@ sub make_message_id {
                last if (defined $du_part and $du_part ne '');
        }
        if (not defined $du_part or $du_part eq '') {
-               use Sys::Hostname qw();
+               require Sys::Hostname;
                $du_part = 'user@' . Sys::Hostname::hostname();
        }
        my $message_id_template = "<%s-git-send-email-%s>";
@@ -841,8 +861,8 @@ sub quote_rfc2047 {
 
 sub is_rfc2047_quoted {
        my $s = shift;
-       my $token = '[^][()<>@,;:"\/?.= \000-\037\177-\377]+';
-       my $encoded_text = '[!->@-~]+';
+       my $token = qr/[^][()<>@,;:"\/?.= \000-\037\177-\377]+/;
+       my $encoded_text = qr/[!->@-~]+/;
        length($s) <= 75 &&
        $s =~ m/^(?:"[[:ascii:]]*"|=\?$token\?$token\?$encoded_text\?=)$/o;
 }
@@ -853,7 +873,7 @@ sub sanitize_address {
        my ($recipient_name, $recipient_addr) = ($recipient =~ /^(.*?)\s*(<.*)/);
 
        if (not $recipient_name) {
-               return "$recipient";
+               return $recipient;
        }
 
        # if recipient_name is already quoted, do nothing
@@ -870,7 +890,7 @@ sub sanitize_address {
        # double quotes are needed if specials or CTLs are included
        elsif ($recipient_name =~ /[][()<>@,;:\\".\000-\037\177]/) {
                $recipient_name =~ s/(["\\\r])/\\$1/g;
-               $recipient_name = "\"$recipient_name\"";
+               $recipient_name = qq["$recipient_name"];
        }
 
        return "$recipient_name $recipient_addr";
@@ -895,7 +915,7 @@ sub sanitize_address {
 
 sub valid_fqdn {
        my $domain = shift;
-       return !($^O eq 'darwin' && $domain =~ /\.local$/) && $domain =~ /\./;
+       return defined $domain && !($^O eq 'darwin' && $domain =~ /\.local$/) && $domain =~ /\./;
 }
 
 sub maildomain_net {
@@ -1015,6 +1035,8 @@ X-Mailer: git-send-email $gitversion
                }
        }
 
+       unshift (@sendmail_parameters, @smtp_server_options);
+
        if ($dry_run) {
                # We don't want to send the email.
        } elsif ($smtp_server =~ m#^/#) {
@@ -1024,7 +1046,7 @@ X-Mailer: git-send-email $gitversion
                        exec($smtp_server, @sendmail_parameters) or die $!;
                }
                print $sm "$header\n$message";
-               close $sm or die $?;
+               close $sm or die $!;
        } else {
 
                if (!defined $smtp_server) {
@@ -1130,12 +1152,13 @@ $subject = $initial_subject;
 $message_num = 0;
 
 foreach my $t (@files) {
-       open(F,"<",$t) or die "can't open file $t";
+       open my $fh, "<", $t or die "can't open file $t";
 
        my $author = undef;
        my $author_encoding;
        my $has_content_type;
        my $body_encoding;
+       @to = ();
        @cc = ();
        @xh = ();
        my $input_format = undef;
@@ -1143,7 +1166,7 @@ foreach my $t (@files) {
        $message = "";
        $message_num++;
        # First unfold multiline header fields
-       while(<F>) {
+       while(<$fh>) {
                last if /^\s*$/;
                if (/^\s+\S/ and @header) {
                        chomp($header[$#header]);
@@ -1176,6 +1199,13 @@ foreach my $t (@files) {
                                        $1, $_) unless $quiet;
                                push @cc, $1;
                        }
+                       elsif (/^To:\s+(.*)$/) {
+                               foreach my $addr (parse_address_line($1)) {
+                                       printf("(mbox) Adding to: %s from line '%s'\n",
+                                               $addr, $_) unless $quiet;
+                                       push @to, sanitize_address($addr);
+                               }
+                       }
                        elsif (/^Cc:\s+(.*)$/) {
                                foreach my $addr (parse_address_line($1)) {
                                        if (unquote_rfc2047($addr) eq $sender) {
@@ -1219,7 +1249,7 @@ foreach my $t (@files) {
                }
        }
        # Now parse the message body
-       while(<F>) {
+       while(<$fh>) {
                $message .=  $_;
                if (/^(Signed-off-by|Cc): (.*)$/i) {
                        chomp;
@@ -1236,23 +1266,12 @@ foreach my $t (@files) {
                                $c, $_) unless $quiet;
                }
        }
-       close F;
-
-       if (defined $cc_cmd && !$suppress_cc{'cccmd'}) {
-               open(F, "$cc_cmd \Q$t\E |")
-                       or die "(cc-cmd) Could not execute '$cc_cmd'";
-               while(<F>) {
-                       my $c = $_;
-                       $c =~ s/^\s*//g;
-                       $c =~ s/\n$//g;
-                       next if ($c eq $sender and $suppress_from);
-                       push @cc, $c;
-                       printf("(cc-cmd) Adding cc: %s from: '%s'\n",
-                               $c, $cc_cmd) unless $quiet;
-               }
-               close F
-                       or die "(cc-cmd) failed to close pipe to '$cc_cmd'";
-       }
+       close $fh;
+
+       push @to, recipients_cmd("to-cmd", "to", $to_cmd, $t)
+               if defined $to_cmd;
+       push @cc, recipients_cmd("cc-cmd", "cc", $cc_cmd, $t)
+               if defined $cc_cmd && !$suppress_cc{'cccmd'};
 
        if ($broken_encoding{$t} && !$has_content_type) {
                $has_content_type = 1;
@@ -1293,6 +1312,7 @@ foreach my $t (@files) {
                ($confirm =~ /^(?:auto|compose)$/ && $compose && $message_num == 1));
        $needs_confirm = "inform" if ($needs_confirm && $confirm_unconfigured && @cc);
 
+       @to = (@initial_to, @to);
        @cc = (@initial_cc, @cc);
 
        my $message_was_sent = send_message();
@@ -1310,15 +1330,38 @@ foreach my $t (@files) {
        $message_id = undef;
 }
 
+# Execute a command (e.g. $to_cmd) to get a list of email addresses
+# and return a results array
+sub recipients_cmd {
+       my ($prefix, $what, $cmd, $file) = @_;
+
+       my $sanitized_sender = sanitize_address($sender);
+       my @addresses = ();
+       open my $fh, "$cmd \Q$file\E |"
+           or die "($prefix) Could not execute '$cmd'";
+       while (my $address = <$fh>) {
+               $address =~ s/^\s*//g;
+               $address =~ s/\s*$//g;
+               $address = sanitize_address($address);
+               next if ($address eq $sanitized_sender and $suppress_from);
+               push @addresses, $address;
+               printf("($prefix) Adding %s: %s from: '%s'\n",
+                      $what, $address, $cmd) unless $quiet;
+               }
+       close $fh
+           or die "($prefix) failed to close pipe to '$cmd'";
+       return @addresses;
+}
+
 cleanup_compose_files();
 
-sub cleanup_compose_files() {
+sub cleanup_compose_files {
        unlink($compose_filename, $compose_filename . ".final") if $compose;
 }
 
 $smtp->quit if $smtp;
 
-sub unique_email_list(@) {
+sub unique_email_list {
        my %seen;
        my @emails;
 
index 6131670860514c215a6b9b7417dd05c3124e81b4..ae031a1375e9c674d80b9fa3d3d3b76780deaf9f 100644 (file)
@@ -151,17 +151,14 @@ get_author_ident_from_commit () {
                s/'\''/'\''\\'\'\''/g
                h
                s/^author \([^<]*\) <[^>]*> .*$/\1/
-               s/'\''/'\''\'\'\''/g
                s/.*/GIT_AUTHOR_NAME='\''&'\''/p
 
                g
                s/^author [^<]* <\([^>]*\)> .*$/\1/
-               s/'\''/'\''\'\'\''/g
                s/.*/GIT_AUTHOR_EMAIL='\''&'\''/p
 
                g
                s/^author [^<]* <[^>]*> \(.*\)$/\1/
-               s/'\''/'\''\'\'\''/g
                s/.*/GIT_AUTHOR_DATE='\''&'\''/p
 
                q
@@ -209,5 +206,20 @@ case $(uname -s) in
        find () {
                /usr/bin/find "$@"
        }
+       is_absolute_path () {
+               case "$1" in
+               [/\\]* | [A-Za-z]:*)
+                       return 0 ;;
+               esac
+               return 1
+       }
        ;;
+*)
+       is_absolute_path () {
+               case "$1" in
+               /*)
+                       return 0 ;;
+               esac
+               return 1
+       }
 esac
index 7ce818bd1baecfb48447f862bb2654ccbd3cf2ff..7561b374d2ec90fe774e98e39a121a1a3a3cdfa9 100755 (executable)
@@ -265,28 +265,21 @@ parse_flags_and_rev()
        i_tree=
 
        REV=$(git rev-parse --no-flags --symbolic "$@" 2>/dev/null)
-       FLAGS=$(git rev-parse --no-revs -- "$@" 2>/dev/null)
-
-       set -- $FLAGS
 
        FLAGS=
-       while test $# -ne 0
+       for opt
        do
-               case "$1" in
+               case "$opt" in
                        -q|--quiet)
                                GIT_QUIET=-t
                        ;;
                        --index)
                                INDEX_OPTION=--index
                        ;;
-                       --)
-                               :
-                       ;;
-                       *)
-                               FLAGS="${FLAGS}${FLAGS:+ }$1"
+                       -*)
+                               FLAGS="${FLAGS}${FLAGS:+ }$opt"
                        ;;
                esac
-               shift
        done
 
        set -- $REV
@@ -380,7 +373,7 @@ apply_stash () {
 
        if test -n "$GIT_QUIET"
        then
-               export GIT_MERGE_VERBOSITY=0
+               GIT_MERGE_VERBOSITY=0 && export GIT_MERGE_VERBOSITY
        fi
        if git merge-recursive $b_tree -- $c_tree $w_tree
        then
@@ -439,9 +432,9 @@ apply_to_branch () {
        assert_stash_like "$@"
 
        git checkout -b $branch $REV^ &&
-       apply_stash "$@"
-
-       test -z "$IS_STASH_REF" || drop_stash "$@"
+       apply_stash "$@" && {
+               test -z "$IS_STASH_REF" || drop_stash "$@"
+       }
 }
 
 PARSE_CACHE='--not-parsed'
index 9ebbab798d21147fc019b6183cad0c462c9dafca..c291eed59cca35d4b08285133acaca29bd80d372 100755 (executable)
@@ -836,11 +836,12 @@ cmd_sync()
                        ;;
                esac
 
+               say "Synchronizing submodule url for '$name'"
+               git config submodule."$name".url "$url"
+
                if test -e "$path"/.git
                then
                (
-                       say "Synchronizing submodule url for '$name'"
-                       git config submodule."$name".url "$url"
                        clear_local_git_env
                        cd "$path"
                        remote=$(get_default_remote)
index 9b046b693fe82c992b3844bf6e8f79214dfa7a59..757de82161e05b9d12c489efeff05c7fec341fe4 100755 (executable)
@@ -1,6 +1,7 @@
 #!/usr/bin/env perl
 # Copyright (C) 2006, Eric Wong <normalperson@yhbt.net>
 # License: GPL v2 or later
+use 5.008;
 use warnings;
 use strict;
 use vars qw/   $AUTHOR $VERSION
@@ -1513,7 +1514,8 @@ sub cmt_sha2rev_batch {
 
 sub working_head_info {
        my ($head, $refs) = @_;
-       my @args = ('log', '--no-color', '--first-parent', '--pretty=medium');
+       my @args = qw/log --no-color --no-decorate --first-parent
+                     --pretty=medium/;
        my ($fh, $ctx) = command_output_pipe(@args, $head);
        my $hash;
        my %max;
@@ -3118,9 +3120,10 @@ sub _rev_list {
 sub check_cherry_pick {
        my $base = shift;
        my $tip = shift;
+       my $parents = shift;
        my @ranges = @_;
        my %commits = map { $_ => 1 }
-               _rev_list("--no-merges", $tip, "--not", $base);
+               _rev_list("--no-merges", $tip, "--not", $base, @$parents);
        for my $range ( @ranges ) {
                delete @commits{_rev_list($range)};
        }
@@ -3296,6 +3299,7 @@ sub find_extra_svn_parents {
                # double check that there are no missing non-merge commits
                my (@incomplete) = check_cherry_pick(
                        $merge_base, $merge_tip,
+                       $parents,
                        @$ranges,
                       );
 
diff --git a/git.c b/git.c
index 50a14013c5a87fed200df0a5a4ec6db0f1e2c223..0409ac9fd3f1ea36680189e07116e58b2630ccad 100644 (file)
--- a/git.c
+++ b/git.c
@@ -6,14 +6,14 @@
 #include "run-command.h"
 
 const char git_usage_string[] =
-       "git [--version] [--exec-path[=GIT_EXEC_PATH]] [--html-path]\n"
+       "git [--version] [--exec-path[=<path>]] [--html-path]\n"
        "           [-p|--paginate|--no-pager] [--no-replace-objects]\n"
-       "           [--bare] [--git-dir=GIT_DIR] [--work-tree=GIT_WORK_TREE]\n"
+       "           [--bare] [--git-dir=<path>] [--work-tree=<path>]\n"
        "           [-c name=value] [--help]\n"
-       "           COMMAND [ARGS]";
+       "           <command> [<args>]";
 
 const char git_more_info_string[] =
-       "See 'git help COMMAND' for more information on a specific command.";
+       "See 'git help <command>' for more information on a specific command.";
 
 static struct startup_info git_startup_info;
 static int use_pager = -1;
diff --git a/git_remote_helpers/setup.cfg b/git_remote_helpers/setup.cfg
new file mode 100644 (file)
index 0000000..4bff887
--- /dev/null
@@ -0,0 +1,3 @@
+[build]
+build_purelib = build/lib
+build_platlib = build/lib
index 2fb7c2d77bbd5f2041341822859dce51ae504d83..0a6ac00631ed8eac5c20248a345074e4b8ff3707 100644 (file)
@@ -35,10 +35,12 @@ GITWEB_FAVICON = static/git-favicon.png
 GITWEB_JS = static/gitweb.js
 GITWEB_SITE_HEADER =
 GITWEB_SITE_FOOTER =
+HIGHLIGHT_BIN = highlight
 
 # include user config
 -include ../config.mak.autogen
 -include ../config.mak
+-include config.mak
 
 # determine version
 ../GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
@@ -129,7 +131,8 @@ GITWEB_REPLACE = \
        -e 's|++GITWEB_FAVICON++|$(GITWEB_FAVICON)|g' \
        -e 's|++GITWEB_JS++|$(GITWEB_JS)|g' \
        -e 's|++GITWEB_SITE_HEADER++|$(GITWEB_SITE_HEADER)|g' \
-       -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g'
+       -e 's|++GITWEB_SITE_FOOTER++|$(GITWEB_SITE_FOOTER)|g' \
+       -e 's|++HIGHLIGHT_BIN++|$(HIGHLIGHT_BIN)|g'
 
 GITWEB-BUILD-OPTIONS: FORCE
        @rm -f $@+
@@ -143,6 +146,15 @@ gitweb.cgi: gitweb.perl GITWEB-BUILD-OPTIONS
        chmod +x $@+ && \
        mv $@+ $@
 
+### Testing rules
+
+test:
+       $(MAKE) -C ../t gitweb-test
+
+test-installed:
+       GITWEB_TEST_INSTALLED='$(DESTDIR_SQ)$(gitwebdir_SQ)' \
+               $(MAKE) -C ../t gitweb-test
+
 ### Installation rules
 
 install: all
@@ -156,5 +168,5 @@ install: all
 clean:
        $(RM) gitweb.cgi static/gitweb.min.js static/gitweb.min.css GITWEB-BUILD-OPTIONS
 
-.PHONY: all clean install .FORCE-GIT-VERSION-FILE FORCE
+.PHONY: all clean install test test-installed .FORCE-GIT-VERSION-FILE FORCE
 
index d4811987965e5a5036b7ed71e32d93578579073a..bf3664f2b7b7b4b5177d172c6b99a84940244469 100644 (file)
@@ -114,6 +114,11 @@ You can specify the following configuration variables when building GIT:
    when gitweb.cgi is executed, then the file specified in the environment
    variable will be loaded instead of the file specified when gitweb.cgi was
    created.  [Default: /etc/gitweb.conf]
+ * HIGHLIGHT_BIN
+   Path to the highlight executable to use (must be the one from
+   http://www.andre-simon.de due to assumptions about parameters and output).
+   Useful if highlight is not installed on your webserver's PATH.
+   [Default: highlight]
 
 
 Runtime gitweb configuration
@@ -236,7 +241,11 @@ not include variables usually directly set during build):
    If server load exceed this value then return "503 Service Unavailable" error.
    Server load is taken to be 0 if gitweb cannot determine its value.  Set it to
    undefined value to turn it off.  The default is 300.
-
+ * $highlight_bin
+   Path to the highlight executable to use (must be the one from
+   http://www.andre-simon.de due to assumptions about parameters and output).
+   Useful if highlight is not installed on your webserver's PATH.
+   [Default: highlight]
 
 Projects list file format
 ~~~~~~~~~~~~~~~~~~~~~~~~~
index a85e2f63197649bff4842ea2970448205618c104..679f2da3ee0c59413d34bf020e242887bfd4f28c 100755 (executable)
@@ -7,6 +7,7 @@
 #
 # This program is licensed under the GPLv2
 
+use 5.008;
 use strict;
 use warnings;
 use CGI qw(:standard :escapeHTML -nosticky);
@@ -165,6 +166,12 @@ our @diff_opts = ('-M'); # taken from git_commit
 # the gitweb domain.
 our $prevent_xss = 0;
 
+# Path to the highlight executable to use (must be the one from
+# http://www.andre-simon.de due to assumptions about parameters and output).
+# Useful if highlight is not installed on your webserver's PATH.
+# [Default: highlight]
+our $highlight_bin = "++HIGHLIGHT_BIN++";
+
 # information about snapshot formats that gitweb is capable of serving
 our %known_snapshot_formats = (
        # name => {
@@ -774,10 +781,10 @@ sub evaluate_path_info {
                'history',
        );
 
-       # we want to catch
+       # we want to catch, among others
        # [$hash_parent_base[:$file_parent]..]$hash_parent[:$file_name]
        my ($parentrefname, $parentpathname, $refname, $pathname) =
-               ($path_info =~ /^(?:(.+?)(?::(.+))?\.\.)?(.+?)(?::(.+))?$/);
+               ($path_info =~ /^(?:(.+?)(?::(.+))?\.\.)?([^:]+?)?(?::(.+))?$/);
 
        # first, analyze the 'current' part
        if (defined $pathname) {
@@ -813,8 +820,15 @@ sub evaluate_path_info {
                # hash_base instead. It should also be noted that hand-crafted
                # links having 'history' as an action and no pathname or hash
                # set will fail, but that happens regardless of PATH_INFO.
-               $input_params{'action'} ||= "shortlog";
-               if (grep { $_ eq $input_params{'action'} } @wants_base) {
+               if (defined $parentrefname) {
+                       # if there is parent let the default be 'shortlog' action
+                       # (for http://git.example.com/repo.git/A..B links); if there
+                       # is no parent, dispatch will detect type of object and set
+                       # action appropriately if required (if action is not set)
+                       $input_params{'action'} ||= "shortlog";
+               }
+               if ($input_params{'action'} &&
+                   grep { $_ eq $input_params{'action'} } @wants_base) {
                        $input_params{'hash_base'} ||= $refname;
                } else {
                        $input_params{'hash'} ||= $refname;
@@ -1061,6 +1075,7 @@ sub run_request {
 
        evaluate_uri();
        evaluate_gitweb_config();
+       evaluate_git_version();
        check_loadavg();
 
        # $projectroot and $projects_list might be set in gitweb config file
@@ -1113,7 +1128,6 @@ sub evaluate_argv {
 
 sub run {
        evaluate_argv();
-       evaluate_git_version();
 
        $pre_listen_hook->()
                if $pre_listen_hook;
@@ -3360,7 +3374,8 @@ sub run_highlighter {
        close $fd
                or die_error(404, "Reading blob failed");
        open $fd, quote_command(git_cmd(), "cat-file", "blob", $hash)." | ".
-                 "highlight --xhtml --fragment --syntax $syntax |"
+                 quote_command($highlight_bin).
+                 " --xhtml --fragment --syntax $syntax |"
                or die_error(500, "Couldn't open file or run syntax highlighter");
        return $fd;
 }
diff --git a/grep.c b/grep.c
index 82fb349be6f6ef8211d4828101cd8e88bcbb304f..63c4280cac9a87f867451c0d9787d1fe21ea9c2d 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -189,30 +189,74 @@ static struct grep_expr *compile_pattern_expr(struct grep_pat **list)
        return compile_pattern_or(list);
 }
 
-void compile_grep_patterns(struct grep_opt *opt)
+static struct grep_expr *grep_true_expr(void)
+{
+       struct grep_expr *z = xcalloc(1, sizeof(*z));
+       z->node = GREP_NODE_TRUE;
+       return z;
+}
+
+static struct grep_expr *grep_or_expr(struct grep_expr *left, struct grep_expr *right)
+{
+       struct grep_expr *z = xcalloc(1, sizeof(*z));
+       z->node = GREP_NODE_OR;
+       z->u.binary.left = left;
+       z->u.binary.right = right;
+       return z;
+}
+
+static struct grep_expr *prep_header_patterns(struct grep_opt *opt)
 {
        struct grep_pat *p;
-       struct grep_expr *header_expr = NULL;
-
-       if (opt->header_list) {
-               p = opt->header_list;
-               header_expr = compile_pattern_expr(&p);
-               if (p)
-                       die("incomplete pattern expression: %s", p->pattern);
-               for (p = opt->header_list; p; p = p->next) {
-                       switch (p->token) {
-                       case GREP_PATTERN: /* atom */
-                       case GREP_PATTERN_HEAD:
-                       case GREP_PATTERN_BODY:
-                               compile_regexp(p, opt);
-                               break;
-                       default:
-                               opt->extended = 1;
-                               break;
-                       }
+       struct grep_expr *header_expr;
+       struct grep_expr *(header_group[GREP_HEADER_FIELD_MAX]);
+       enum grep_header_field fld;
+
+       if (!opt->header_list)
+               return NULL;
+       p = opt->header_list;
+       for (p = opt->header_list; p; p = p->next) {
+               if (p->token != GREP_PATTERN_HEAD)
+                       die("bug: a non-header pattern in grep header list.");
+               if (p->field < 0 || GREP_HEADER_FIELD_MAX <= p->field)
+                       die("bug: unknown header field %d", p->field);
+               compile_regexp(p, opt);
+       }
+
+       for (fld = 0; fld < GREP_HEADER_FIELD_MAX; fld++)
+               header_group[fld] = NULL;
+
+       for (p = opt->header_list; p; p = p->next) {
+               struct grep_expr *h;
+               struct grep_pat *pp = p;
+
+               h = compile_pattern_atom(&pp);
+               if (!h || pp != p->next)
+                       die("bug: malformed header expr");
+               if (!header_group[p->field]) {
+                       header_group[p->field] = h;
+                       continue;
                }
+               header_group[p->field] = grep_or_expr(h, header_group[p->field]);
        }
 
+       header_expr = NULL;
+
+       for (fld = 0; fld < GREP_HEADER_FIELD_MAX; fld++) {
+               if (!header_group[fld])
+                       continue;
+               if (!header_expr)
+                       header_expr = grep_true_expr();
+               header_expr = grep_or_expr(header_group[fld], header_expr);
+       }
+       return header_expr;
+}
+
+void compile_grep_patterns(struct grep_opt *opt)
+{
+       struct grep_pat *p;
+       struct grep_expr *header_expr = prep_header_patterns(opt);
+
        for (p = opt->pattern_list; p; p = p->next) {
                switch (p->token) {
                case GREP_PATTERN: /* atom */
@@ -231,9 +275,6 @@ void compile_grep_patterns(struct grep_opt *opt)
        else if (!opt->extended)
                return;
 
-       /* Then bundle them up in an expression.
-        * A classic recursive descent parser would do.
-        */
        p = opt->pattern_list;
        if (p)
                opt->pattern_expression = compile_pattern_expr(&p);
@@ -243,22 +284,18 @@ void compile_grep_patterns(struct grep_opt *opt)
        if (!header_expr)
                return;
 
-       if (opt->pattern_expression) {
-               struct grep_expr *z;
-               z = xcalloc(1, sizeof(*z));
-               z->node = GREP_NODE_OR;
-               z->u.binary.left = opt->pattern_expression;
-               z->u.binary.right = header_expr;
-               opt->pattern_expression = z;
-       } else {
+       if (!opt->pattern_expression)
                opt->pattern_expression = header_expr;
-       }
+       else
+               opt->pattern_expression = grep_or_expr(opt->pattern_expression,
+                                                      header_expr);
        opt->all_match = 1;
 }
 
 static void free_pattern_expr(struct grep_expr *x)
 {
        switch (x->node) {
+       case GREP_NODE_TRUE:
        case GREP_NODE_ATOM:
                break;
        case GREP_NODE_NOT:
@@ -487,6 +524,9 @@ static int match_expr_eval(struct grep_expr *x, char *bol, char *eol,
        if (!x)
                die("Not a valid grep expression");
        switch (x->node) {
+       case GREP_NODE_TRUE:
+               h = 1;
+               break;
        case GREP_NODE_ATOM:
                h = match_one_pattern(x->u.atom, bol, eol, ctx, &match, 0);
                break;
diff --git a/grep.h b/grep.h
index efa8cff980af2b2c06dad080876637d16b5c4985..06621fe663545af52fbc42827a8374ab5bd42f38 100644 (file)
--- a/grep.h
+++ b/grep.h
@@ -22,6 +22,7 @@ enum grep_header_field {
        GREP_HEADER_AUTHOR = 0,
        GREP_HEADER_COMMITTER
 };
+#define GREP_HEADER_FIELD_MAX (GREP_HEADER_COMMITTER + 1)
 
 struct grep_pat {
        struct grep_pat *next;
@@ -41,6 +42,7 @@ enum grep_expr_node {
        GREP_NODE_ATOM,
        GREP_NODE_NOT,
        GREP_NODE_AND,
+       GREP_NODE_TRUE,
        GREP_NODE_OR
 };
 
index 6bb3095c3a85d771bb60e8f2f025287d16e792df..007dd3e4d38ff657a29a06e559173b796f193763 100644 (file)
@@ -18,7 +18,7 @@ typedef int (*ll_merge_fn)(const struct ll_merge_driver *,
                           mmfile_t *orig, const char *orig_name,
                           mmfile_t *src1, const char *name1,
                           mmfile_t *src2, const char *name2,
-                          int flag,
+                          const struct ll_merge_options *opts,
                           int marker_size);
 
 struct ll_merge_driver {
@@ -39,14 +39,18 @@ static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
                           mmfile_t *orig, const char *orig_name,
                           mmfile_t *src1, const char *name1,
                           mmfile_t *src2, const char *name2,
-                          int flag, int marker_size)
+                          const struct ll_merge_options *opts,
+                          int marker_size)
 {
+       mmfile_t *stolen;
+       assert(opts);
+
        /*
         * The tentative merge result is "ours" for the final round,
         * or common ancestor for an internal merge.  Still return
         * "conflicted merge" status.
         */
-       mmfile_t *stolen = (flag & LL_OPT_VIRTUAL_ANCESTOR) ? orig : src1;
+       stolen = opts->virtual_ancestor ? orig : src1;
 
        result->ptr = stolen->ptr;
        result->size = stolen->size;
@@ -60,9 +64,11 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
                        mmfile_t *orig, const char *orig_name,
                        mmfile_t *src1, const char *name1,
                        mmfile_t *src2, const char *name2,
-                       int flag, int marker_size)
+                       const struct ll_merge_options *opts,
+                       int marker_size)
 {
        xmparam_t xmp;
+       assert(opts);
 
        if (buffer_is_binary(orig->ptr, orig->size) ||
            buffer_is_binary(src1->ptr, src1->size) ||
@@ -74,12 +80,13 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
                                       orig, orig_name,
                                       src1, name1,
                                       src2, name2,
-                                      flag, marker_size);
+                                      opts, marker_size);
        }
 
        memset(&xmp, 0, sizeof(xmp));
        xmp.level = XDL_MERGE_ZEALOUS;
-       xmp.favor = ll_opt_favor(flag);
+       xmp.favor = opts->variant;
+       xmp.xpp.flags = opts->xdl_opts;
        if (git_xmerge_style >= 0)
                xmp.style = git_xmerge_style;
        if (marker_size > 0)
@@ -96,15 +103,17 @@ static int ll_union_merge(const struct ll_merge_driver *drv_unused,
                          mmfile_t *orig, const char *orig_name,
                          mmfile_t *src1, const char *name1,
                          mmfile_t *src2, const char *name2,
-                         int flag, int marker_size)
+                         const struct ll_merge_options *opts,
+                         int marker_size)
 {
        /* Use union favor */
-       flag &= ~LL_OPT_FAVOR_MASK;
-       flag |= create_ll_flag(XDL_MERGE_FAVOR_UNION);
+       struct ll_merge_options o;
+       assert(opts);
+       o = *opts;
+       o.variant = XDL_MERGE_FAVOR_UNION;
        return ll_xdl_merge(drv_unused, result, path_unused,
                            orig, NULL, src1, NULL, src2, NULL,
-                           flag, marker_size);
-       return 0;
+                           &o, marker_size);
 }
 
 #define LL_BINARY_MERGE 0
@@ -136,7 +145,8 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,
                        mmfile_t *orig, const char *orig_name,
                        mmfile_t *src1, const char *name1,
                        mmfile_t *src2, const char *name2,
-                       int flag, int marker_size)
+                       const struct ll_merge_options *opts,
+                       int marker_size)
 {
        char temp[4][50];
        struct strbuf cmd = STRBUF_INIT;
@@ -144,6 +154,7 @@ static int ll_ext_merge(const struct ll_merge_driver *fn,
        const char *args[] = { NULL, NULL };
        int status, fd, i;
        struct stat st;
+       assert(opts);
 
        dict[0].placeholder = "O"; dict[0].value = temp[0];
        dict[1].placeholder = "A"; dict[1].value = temp[1];
@@ -337,15 +348,21 @@ int ll_merge(mmbuffer_t *result_buf,
             mmfile_t *ancestor, const char *ancestor_label,
             mmfile_t *ours, const char *our_label,
             mmfile_t *theirs, const char *their_label,
-            int flag)
+            const struct ll_merge_options *opts)
 {
        static struct git_attr_check check[2];
        const char *ll_driver_name = NULL;
        int marker_size = DEFAULT_CONFLICT_MARKER_SIZE;
        const struct ll_merge_driver *driver;
-       int virtual_ancestor = flag & LL_OPT_VIRTUAL_ANCESTOR;
 
-       if (flag & LL_OPT_RENORMALIZE) {
+       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->renormalize) {
                normalize_file(ancestor, path);
                normalize_file(ours, path);
                normalize_file(theirs, path);
@@ -359,11 +376,11 @@ int ll_merge(mmbuffer_t *result_buf,
                }
        }
        driver = find_ll_merge_driver(ll_driver_name);
-       if (virtual_ancestor && driver->recursive)
+       if (opts->virtual_ancestor && driver->recursive)
                driver = find_ll_merge_driver(driver->recursive);
        return driver->fn(driver, result_buf, path, ancestor, ancestor_label,
                          ours, our_label, theirs, their_label,
-                         flag, marker_size);
+                         opts, marker_size);
 }
 
 int ll_merge_marker_size(const char *path)
index ff7ca87bfa01d0e9705f4bfd83b9e4d2c155d588..244a31f55ac7375b59d7c257bfc2391957fdca94 100644 (file)
@@ -5,27 +5,19 @@
 #ifndef LL_MERGE_H
 #define LL_MERGE_H
 
-#define LL_OPT_VIRTUAL_ANCESTOR        (1 << 0)
-#define LL_OPT_FAVOR_MASK      ((1 << 1) | (1 << 2))
-#define LL_OPT_FAVOR_SHIFT 1
-#define LL_OPT_RENORMALIZE     (1 << 3)
-
-static inline int ll_opt_favor(int flag)
-{
-       return (flag & LL_OPT_FAVOR_MASK) >> LL_OPT_FAVOR_SHIFT;
-}
-
-static inline int create_ll_flag(int favor)
-{
-       return ((favor << LL_OPT_FAVOR_SHIFT) & LL_OPT_FAVOR_MASK);
-}
+struct ll_merge_options {
+       unsigned virtual_ancestor : 1;
+       unsigned variant : 2;   /* favor ours, favor theirs, or union merge */
+       unsigned renormalize : 1;
+       long xdl_opts;
+};
 
 int ll_merge(mmbuffer_t *result_buf,
             const char *path,
             mmfile_t *ancestor, const char *ancestor_label,
             mmfile_t *ours, const char *our_label,
             mmfile_t *theirs, const char *their_label,
-            int flag);
+            const struct ll_merge_options *opts);
 
 int ll_merge_marker_size(const char *path);
 
index db4d0d50d32d8852d1cb5173125e4173c3badb49..f7f4533926e35867725db00f0c89522c4b290898 100644 (file)
@@ -37,7 +37,7 @@ static void *three_way_filemerge(const char *path, mmfile_t *base, mmfile_t *our
         * common ancestor.
         */
        merge_status = ll_merge(&res, path, base, NULL,
-                               our, ".our", their, ".their", 0);
+                               our, ".our", their, ".their", NULL);
        if (merge_status < 0)
                return NULL;
 
index c5746988196b8139ca3234f8b30d03af56d33324..875859f68efaab5113785896326140c8d0543f45 100644 (file)
@@ -334,6 +334,7 @@ static struct string_list *get_renames(struct merge_options *o,
        opts.rename_limit = o->merge_rename_limit >= 0 ? o->merge_rename_limit :
                            o->diff_rename_limit >= 0 ? o->diff_rename_limit :
                            500;
+       opts.rename_score = o->rename_score;
        opts.warn_on_too_large_rename = 1;
        opts.output_format = DIFF_FORMAT_NO_OUTPUT;
        if (diff_setup_done(&opts) < 0)
@@ -605,22 +606,26 @@ static int merge_3way(struct merge_options *o,
                      const char *branch2)
 {
        mmfile_t orig, src1, src2;
+       struct ll_merge_options ll_opts = {0};
        char *base_name, *name1, *name2;
        int merge_status;
-       int favor;
 
-       if (o->call_depth)
-               favor = 0;
-       else {
+       ll_opts.renormalize = o->renormalize;
+       ll_opts.xdl_opts = o->xdl_opts;
+
+       if (o->call_depth) {
+               ll_opts.virtual_ancestor = 1;
+               ll_opts.variant = 0;
+       } else {
                switch (o->recursive_variant) {
                case MERGE_RECURSIVE_OURS:
-                       favor = XDL_MERGE_FAVOR_OURS;
+                       ll_opts.variant = XDL_MERGE_FAVOR_OURS;
                        break;
                case MERGE_RECURSIVE_THEIRS:
-                       favor = XDL_MERGE_FAVOR_THEIRS;
+                       ll_opts.variant = XDL_MERGE_FAVOR_THEIRS;
                        break;
                default:
-                       favor = 0;
+                       ll_opts.variant = 0;
                        break;
                }
        }
@@ -643,10 +648,7 @@ static int merge_3way(struct merge_options *o,
        read_mmblob(&src2, b->sha1);
 
        merge_status = ll_merge(result_buf, a->path, &orig, base_name,
-                               &src1, name1, &src2, name2,
-                               ((o->call_depth ? LL_OPT_VIRTUAL_ANCESTOR : 0) |
-                                (o->renormalize ? LL_OPT_RENORMALIZE : 0) |
-                                create_ll_flag(favor)));
+                               &src1, name1, &src2, name2, &ll_opts);
 
        free(name1);
        free(name2);
@@ -1550,3 +1552,37 @@ void init_merge_options(struct merge_options *o)
        memset(&o->current_directory_set, 0, sizeof(struct string_list));
        o->current_directory_set.strdup_strings = 1;
 }
+
+int parse_merge_opt(struct merge_options *o, const char *s)
+{
+       if (!s || !*s)
+               return -1;
+       if (!strcmp(s, "ours"))
+               o->recursive_variant = MERGE_RECURSIVE_OURS;
+       else if (!strcmp(s, "theirs"))
+               o->recursive_variant = MERGE_RECURSIVE_THEIRS;
+       else if (!strcmp(s, "subtree"))
+               o->subtree_shift = "";
+       else if (!prefixcmp(s, "subtree="))
+               o->subtree_shift = s + strlen("subtree=");
+       else if (!strcmp(s, "patience"))
+               o->xdl_opts |= XDF_PATIENCE_DIFF;
+       else if (!strcmp(s, "ignore-space-change"))
+               o->xdl_opts |= XDF_IGNORE_WHITESPACE_CHANGE;
+       else if (!strcmp(s, "ignore-all-space"))
+               o->xdl_opts |= XDF_IGNORE_WHITESPACE;
+       else if (!strcmp(s, "ignore-space-at-eol"))
+               o->xdl_opts |= XDF_IGNORE_WHITESPACE_AT_EOL;
+       else if (!strcmp(s, "renormalize"))
+               o->renormalize = 1;
+       else if (!strcmp(s, "no-renormalize"))
+               o->renormalize = 0;
+       else if (!prefixcmp(s, "rename-threshold=")) {
+               const char *score = s + strlen("rename-threshold=");
+               if ((o->rename_score = parse_rename_score(&score)) == -1 || *score != 0)
+                       return -1;
+       }
+       else
+               return -1;
+       return 0;
+}
index 34492dbd6ea22d715c98acbeeabe04033ff9a794..c8135b0ec70cc2eb92e5a6fd9353a134fda6b7bf 100644 (file)
@@ -15,9 +15,11 @@ struct merge_options {
        const char *subtree_shift;
        unsigned buffer_output : 1;
        unsigned renormalize : 1;
+       long xdl_opts;
        int verbosity;
        int diff_rename_limit;
        int merge_rename_limit;
+       int rename_score;
        int call_depth;
        struct strbuf obuf;
        struct string_list current_file_set;
@@ -52,6 +54,8 @@ int merge_recursive_generic(struct merge_options *o,
 void init_merge_options(struct merge_options *o);
 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);
 
index 6cb0dd19344ba1169b23b7e4949033f8a9088a00..205e48aa3a7b912005565ac9c296205a897a1476 100644 (file)
@@ -7,6 +7,7 @@ Git - Perl interface to the Git version control system
 
 package Git;
 
+use 5.008;
 use strict;
 
 
index 861ca7c815b4857f1fde399617860e5a179e2ca3..d2608434750c336c3f3881efda8373b7c67d4b11 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -325,7 +325,7 @@ static int handle_cache(const char *path, unsigned char *sha1, const char *outpu
         */
        ll_merge(&result, path, &mmfile[0], NULL,
                 &mmfile[1], "ours",
-                &mmfile[2], "theirs", 0);
+                &mmfile[2], "theirs", NULL);
        for (i = 0; i < 3; i++)
                free(mmfile[i].ptr);
 
index 60b4ba66eb8cac3378326378dc4e0cbdb88162ac..05d7ab118b3e1473cdf559d3f6337b26bb9aac81 100644 (file)
@@ -5,6 +5,7 @@ struct send_pack_args {
        unsigned verbose:1,
                quiet:1,
                porcelain:1,
+               progress:1,
                send_mirror:1,
                force_update:1,
                use_thin_pack:1,
diff --git a/setup.c b/setup.c
index a3b76de2bb1c18e2f3b8cdf5799c3c650b16d027..346ef2eb2d678b742280c0816a09b8ca174ca799 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -46,7 +46,7 @@ const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
 {
        static char path[PATH_MAX];
 #ifndef WIN32
-       if (!pfx || !*pfx || is_absolute_path(arg))
+       if (!pfx_len || is_absolute_path(arg))
                return arg;
        memcpy(path, pfx, pfx_len);
        strcpy(path + pfx_len, arg);
@@ -55,7 +55,7 @@ const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
        /* don't add prefix to absolute paths, but still replace '\' by '/' */
        if (is_absolute_path(arg))
                pfx_len = 0;
-       else
+       else if (pfx_len)
                memcpy(path, pfx, pfx_len);
        strcpy(path + pfx_len, arg);
        for (p = path + pfx_len; *p; p++)
index 7b7e61719fa63e41917b41240061c68e3cbabf01..3e856b80369c289a3d9399d60ec3be22bbbc6788 100644 (file)
@@ -1062,12 +1062,14 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
        /* sha1:path --> object name of path in ent sha1
         * :path -> object name of path 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;
                int pos;
                if (namelen > 2 && name[1] == '/')
+                       /* don't need mode for commit */
                        return get_sha1_oneline(name + 2, sha1);
                if (namelen < 3 ||
                    name[2] != ':' ||
@@ -1095,6 +1097,7 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
                                break;
                        if (ce_stage(ce) == stage) {
                                hashcpy(sha1, ce->sha1);
+                               oc->mode = ce->ce_mode;
                                return 0;
                        }
                        pos++;
diff --git a/shell.c b/shell.c
index e4864e04da3b0e237342c2ca0548c0ec0082c171..dea4cfdd2c230af6afd6233cacfa5c776a9962f9 100644 (file)
--- a/shell.c
+++ b/shell.c
@@ -2,6 +2,10 @@
 #include "quote.h"
 #include "exec_cmd.h"
 #include "strbuf.h"
+#include "run-command.h"
+
+#define COMMAND_DIR "git-shell-commands"
+#define HELP_COMMAND COMMAND_DIR "/help"
 
 static int do_generic_cmd(const char *me, char *arg)
 {
@@ -33,6 +37,86 @@ static int do_cvs_cmd(const char *me, char *arg)
        return execv_git_cmd(cvsserver_argv);
 }
 
+static int is_valid_cmd_name(const char *cmd)
+{
+       /* Test command contains no . or / characters */
+       return cmd[strcspn(cmd, "./")] == '\0';
+}
+
+static char *make_cmd(const char *prog)
+{
+       char *prefix = xmalloc((strlen(prog) + strlen(COMMAND_DIR) + 2));
+       strcpy(prefix, COMMAND_DIR);
+       strcat(prefix, "/");
+       strcat(prefix, prog);
+       return prefix;
+}
+
+static void cd_to_homedir(void)
+{
+       const char *home = getenv("HOME");
+       if (!home)
+               die("could not determine user's home directory; HOME is unset");
+       if (chdir(home) == -1)
+               die("could not chdir to user's home directory");
+}
+
+static void run_shell(void)
+{
+       int done = 0;
+       static const char *help_argv[] = { HELP_COMMAND, NULL };
+       /* Print help if enabled */
+       run_command_v_opt(help_argv, RUN_SILENT_EXEC_FAILURE);
+
+       do {
+               struct strbuf line = STRBUF_INIT;
+               const char *prog;
+               char *full_cmd;
+               char *rawargs;
+               char *split_args;
+               const char **argv;
+               int code;
+               int count;
+
+               fprintf(stderr, "git> ");
+               if (strbuf_getline(&line, stdin, '\n') == EOF) {
+                       fprintf(stderr, "\n");
+                       strbuf_release(&line);
+                       break;
+               }
+               strbuf_trim(&line);
+               rawargs = strbuf_detach(&line, NULL);
+               split_args = xstrdup(rawargs);
+               count = split_cmdline(split_args, &argv);
+               if (count < 0) {
+                       fprintf(stderr, "invalid command format '%s': %s\n", rawargs,
+                               split_cmdline_strerror(count));
+                       free(split_args);
+                       free(rawargs);
+                       continue;
+               }
+
+               prog = argv[0];
+               if (!strcmp(prog, "")) {
+               } else if (!strcmp(prog, "quit") || !strcmp(prog, "logout") ||
+                          !strcmp(prog, "exit") || !strcmp(prog, "bye")) {
+                       done = 1;
+               } else if (is_valid_cmd_name(prog)) {
+                       full_cmd = make_cmd(prog);
+                       argv[0] = full_cmd;
+                       code = run_command_v_opt(argv, RUN_SILENT_EXEC_FAILURE);
+                       if (code == -1 && errno == ENOENT) {
+                               fprintf(stderr, "unrecognized command '%s'\n", prog);
+                       }
+                       free(full_cmd);
+               } else {
+                       fprintf(stderr, "invalid command format '%s'\n", prog);
+               }
+
+               free(argv);
+               free(rawargs);
+       } while (!done);
+}
 
 static struct commands {
        const char *name;
@@ -48,8 +132,10 @@ static struct commands {
 int main(int argc, char **argv)
 {
        char *prog;
+       const char **user_argv;
        struct commands *cmd;
        int devnull_fd;
+       int count;
 
        /*
         * Always open file descriptors 0/1/2 to avoid clobbering files
@@ -66,17 +152,28 @@ int main(int argc, char **argv)
        /*
         * Special hack to pretend to be a CVS server
         */
-       if (argc == 2 && !strcmp(argv[1], "cvs server"))
+       if (argc == 2 && !strcmp(argv[1], "cvs server")) {
                argv--;
+       } else if (argc == 1) {
+               /* Allow the user to run an interactive shell */
+               cd_to_homedir();
+               if (access(COMMAND_DIR, R_OK | X_OK) == -1) {
+                       die("Interactive git shell is not enabled.\n"
+                           "hint: ~/" COMMAND_DIR " should exist "
+                           "and have read and execute access.");
+               }
+               run_shell();
+               exit(0);
+       } else if (argc != 3 || strcmp(argv[1], "-c")) {
+               /*
+                * We do not accept any other modes except "-c" followed by
+                * "cmd arg", where "cmd" is a very limited subset of git
+                * commands or a command in the COMMAND_DIR
+                */
+               die("Run with no arguments or with -c cmd");
+       }
 
-       /*
-        * We do not accept anything but "-c" followed by "cmd arg",
-        * where "cmd" is a very limited subset of git commands.
-        */
-       else if (argc != 3 || strcmp(argv[1], "-c"))
-               die("What do you think I am? A shell?");
-
-       prog = argv[2];
+       prog = xstrdup(argv[2]);
        if (!strncmp(prog, "git", 3) && isspace(prog[3]))
                /* Accept "git foo" as if the caller said "git-foo". */
                prog[3] = '-';
@@ -99,5 +196,21 @@ int main(int argc, char **argv)
                }
                exit(cmd->exec(cmd->name, arg));
        }
-       die("unrecognized command '%s'", prog);
+
+       cd_to_homedir();
+       count = split_cmdline(prog, &user_argv);
+       if (count >= 0) {
+               if (is_valid_cmd_name(user_argv[0])) {
+                       prog = make_cmd(user_argv[0]);
+                       user_argv[0] = prog;
+                       execv(user_argv[0], (char *const *) user_argv);
+               }
+               free(prog);
+               free(user_argv);
+               die("unrecognized command '%s'", argv[2]);
+       } else {
+               free(prog);
+               die("invalid command format '%s': %s", argv[2],
+                   split_cmdline_strerror(count));
+       }
 }
index bc3a0802ea7e7b1743602972de182391b4bf0b3f..65b4cf43434a8b7327565d0e0f87d5378d098f99 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -399,6 +399,8 @@ int strbuf_branchname(struct strbuf *sb, const char *name)
 int strbuf_check_branch_ref(struct strbuf *sb, const char *name)
 {
        strbuf_branchname(sb, name);
+       if (name[0] == '-')
+               return CHECK_REF_FORMAT_ERROR;
        strbuf_splice(sb, 0, 0, "refs/heads/", 11);
        return check_ref_format(sb->buf);
 }
index fac2dbc24fc654e58840727204043a198d065921..675a91f93821421aa79de51857b22a4960da8ec1 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
@@ -16,7 +16,7 @@
  *
  * 2. the ->buf member is a byte array that has at least ->len + 1 bytes
  *    allocated. The extra byte is used to store a '\0', allowing the ->buf
- *    member to be a valid C-string. Every strbuf function ensure this
+ *    member to be a valid C-string. Every strbuf function ensures this
  *    invariant is preserved.
  *
  *    Note that it is OK to "play" with the buffer directly if you work it
index c7baefb7eac27fff31e3e78c7862eb2bf73d9068..73c6ec473da2d13b9e5bf3d6feb7cfca4937e109 100644 (file)
@@ -11,16 +11,25 @@ SHELL_PATH ?= $(SHELL)
 PERL_PATH ?= /usr/bin/perl
 TAR ?= $(TAR)
 RM ?= rm -f
+PROVE ?= prove
+DEFAULT_TEST_TARGET ?= test
 
 # Shell quote;
 SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
 
 T = $(wildcard t[0-9][0-9][0-9][0-9]-*.sh)
 TSVN = $(wildcard t91[0-9][0-9]-*.sh)
+TGITWEB = $(wildcard t95[0-9][0-9]-*.sh)
 
-all: pre-clean
+all: $(DEFAULT_TEST_TARGET)
+
+test: pre-clean
        $(MAKE) aggregate-results-and-cleanup
 
+prove: pre-clean
+       @echo "*** prove ***"; GIT_CONFIG=.git/config $(PROVE) --exec '$(SHELL_PATH_SQ)' $(GIT_PROVE_OPTS) $(T) :: $(GIT_TEST_OPTS)
+       $(MAKE) clean
+
 $(T):
        @echo "*** $@ ***"; GIT_CONFIG=.git/config '$(SHELL_PATH_SQ)' $@ $(GIT_TEST_OPTS)
 
@@ -46,6 +55,9 @@ full-svn-test:
        $(MAKE) $(TSVN) GIT_SVN_NO_OPTIMIZE_COMMITS=1 LC_ALL=C
        $(MAKE) $(TSVN) GIT_SVN_NO_OPTIMIZE_COMMITS=0 LC_ALL=en_US.UTF-8
 
+gitweb-test:
+       $(MAKE) $(TGITWEB)
+
 valgrind:
        GIT_TEST_OPTS=--valgrind $(MAKE)
 
index a1eb7c8720ad3e91f78fca6d58acd336c71171a0..c548bf1b7eb17b861d8f26bd2381ed6bbae2aa52 100644 (file)
--- a/t/README
+++ b/t/README
@@ -50,6 +50,12 @@ prove and other harnesses come with a lot of useful options. The
     # Repeat until no more failures
     $ prove -j 15 --state=failed,save ./t[0-9]*.sh
 
+You can give DEFAULT_TEST_TARGET=prove on the make command (or define it
+in config.mak) to cause "make test" to run tests under prove.
+GIT_PROVE_OPTS can be used to pass additional options, e.g.
+
+    $ make DEFAULT_TEST_TARGET=prove GIT_PROVE_OPTS='--timer --jobs 16' test
+
 You can also run each test individually from command line, like this:
 
     $ sh ./t3010-ls-files-killed-modified.sh
index 396b9653a3ad80490cf360c86a910edff58862a2..141b60cdcbf4c8f70813e090a950c5d736853a8e 100644 (file)
@@ -8,27 +8,27 @@ check_count () {
        $PROG file $head >.result || return 1
        cat .result | perl -e '
                my %expect = (@ARGV);
-               my %count = ();
+               my %count = map { $_ => 0 } keys %expect;
                while (<STDIN>) {
                        if (/^[0-9a-f]+\t\(([^\t]+)\t/) {
                                my $author = $1;
                                for ($author) { s/^\s*//; s/\s*$//; }
-                               if (exists $expect{$author}) {
-                                       $count{$author}++;
-                               }
+                               $count{$author}++;
                        }
                }
                my $bad = 0;
                while (my ($author, $count) = each %count) {
                        my $ok;
-                       if ($expect{$author} != $count) {
+                       my $value = 0;
+                       $value = $expect{$author} if defined $expect{$author};
+                       if ($value != $count) {
                                $bad = 1;
                                $ok = "bad";
                        }
                        else {
                                $ok = "good";
                        }
-                       print STDERR "Author $author (expected $expect{$author}, attributed $count) $ok\n";
+                       print STDERR "Author $author (expected $value, attributed $count) $ok\n";
                }
                exit($bad);
        ' "$@"
index 81ef2a0969d98f05ce22cd8a06fcb55a7af9aee8..8b5b987f45853da5d24148acc398b838ada7e616 100644 (file)
@@ -19,9 +19,9 @@ our \$site_name = '[localhost]';
 our \$site_header = '';
 our \$site_footer = '';
 our \$home_text = 'indextext.html';
-our @stylesheets = ('file:///$TEST_DIRECTORY/../gitweb/static/gitweb.css');
-our \$logo = 'file:///$TEST_DIRECTORY/../gitweb/static/git-logo.png';
-our \$favicon = 'file:///$TEST_DIRECTORY/../gitweb/static/git-favicon.png';
+our @stylesheets = ('file:///$GIT_BUILD_DIR/gitweb/static/gitweb.css');
+our \$logo = 'file:///$GIT_BUILD_DIR/gitweb/static/git-logo.png';
+our \$favicon = 'file:///$GIT_BUILD_DIR/gitweb/static/git-favicon.png';
 our \$projects_list = '';
 our \$export_ok = '';
 our \$strict_export = '';
@@ -32,17 +32,34 @@ EOF
        cat >.git/description <<EOF
 $0 test repository
 EOF
+
+       # You can set the GITWEB_TEST_INSTALLED environment variable to
+       # the gitwebdir (the directory where gitweb is installed / deployed to)
+       # of an existing gitweb instalation to test that installation,
+       # or simply to pathname of installed gitweb script.
+       if test -n "$GITWEB_TEST_INSTALLED" ; then
+               if test -d $GITWEB_TEST_INSTALLED; then
+                       SCRIPT_NAME="$GITWEB_TEST_INSTALLED/gitweb.cgi"
+               else
+                       SCRIPT_NAME="$GITWEB_TEST_INSTALLED"
+               fi
+               test -f "$SCRIPT_NAME" ||
+               error "Cannot find gitweb at $GITWEB_TEST_INSTALLED."
+               say "# Testing $SCRIPT_NAME"
+       else # normal case, use source version of gitweb
+               SCRIPT_NAME="$GIT_BUILD_DIR/gitweb/gitweb.perl"
+       fi
+       export SCRIPT_NAME
 }
 
 gitweb_run () {
        GATEWAY_INTERFACE='CGI/1.1'
        HTTP_ACCEPT='*/*'
        REQUEST_METHOD='GET'
-       SCRIPT_NAME="$TEST_DIRECTORY/../gitweb/gitweb.perl"
        QUERY_STRING=""$1""
        PATH_INFO=""$2""
        export GATEWAY_INTERFACE HTTP_ACCEPT REQUEST_METHOD \
-               SCRIPT_NAME QUERY_STRING PATH_INFO
+               QUERY_STRING PATH_INFO
 
        GITWEB_CONFIG=$(pwd)/gitweb_config.perl
        export GITWEB_CONFIG
@@ -81,8 +98,8 @@ if ! test_have_prereq PERL; then
 fi
 
 perl -MEncode -e 'decode_utf8("", Encode::FB_CROAK)' >/dev/null 2>&1 || {
-    skip_all='skipping gitweb tests, perl version is too old'
-    test_done
+       skip_all='skipping gitweb tests, perl version is too old'
+       test_done
 }
 
 gitweb_init
diff --git a/t/lib-terminal.sh b/t/lib-terminal.sh
new file mode 100644 (file)
index 0000000..c383b57
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+test_expect_success 'set up terminal for tests' '
+       if
+               test_have_prereq PERL &&
+               "$PERL_PATH" "$TEST_DIRECTORY"/test-terminal.perl \
+                       sh -c "test -t 1 && test -t 2"
+       then
+               test_set_prereq TTY &&
+               test_terminal () {
+                       if ! test_declared_prereq TTY
+                       then
+                               echo >&4 "test_terminal: need to declare TTY prerequisite"
+                               return 127
+                       fi
+                       "$PERL_PATH" "$TEST_DIRECTORY"/test-terminal.perl "$@"
+               }
+       fi
+'
index de38c7f7aab16a0c2766ef020a3fc03fadece555..e75153bdea05d2e34570aaf03fbb3902694ddedf 100755 (executable)
@@ -36,6 +36,9 @@ test_expect_success 'setup' '
                echo "d/* test=a/b/d/*"
                echo "d/yes notest"
        ) >a/b/.gitattributes
+       (
+               echo "global test=global"
+       ) >"$HOME"/global-gitattributes
 
 '
 
@@ -57,6 +60,16 @@ test_expect_success 'attribute test' '
 
 '
 
+test_expect_success 'core.attributesfile' '
+       attr_check global unspecified &&
+       git config core.attributesfile "$HOME/global-gitattributes" &&
+       attr_check global global &&
+       git config core.attributesfile "~/global-gitattributes" &&
+       attr_check global global &&
+       echo "global test=precedence" >> .gitattributes &&
+       attr_check global precedence
+'
+
 test_expect_success 'attribute test: read paths from stdin' '
 
        cat <<EOF > expect
index 385b1265de53829053bae40f111a0bf30004b98b..e3137d638ee5bb07b9278c1a9b90a207ad024a08 100755 (executable)
@@ -16,53 +16,29 @@ test_expect_success setup '
 '
 
 test_expect_success POSIXPERM,SANITY 'write-tree should notice unwritable repository' '
-
-       (
-               chmod a-w .git/objects .git/objects/?? &&
-               test_must_fail git write-tree
-       )
-       status=$?
-       chmod 775 .git/objects .git/objects/??
-       (exit $status)
-
+       test_when_finished "chmod 775 .git/objects .git/objects/??" &&
+       chmod a-w .git/objects .git/objects/?? &&
+       test_must_fail git write-tree
 '
 
 test_expect_success POSIXPERM,SANITY 'commit should notice unwritable repository' '
-
-       (
-               chmod a-w .git/objects .git/objects/?? &&
-               test_must_fail git commit -m second
-       )
-       status=$?
-       chmod 775 .git/objects .git/objects/??
-       (exit $status)
-
+       test_when_finished "chmod 775 .git/objects .git/objects/??" &&
+       chmod a-w .git/objects .git/objects/?? &&
+       test_must_fail git commit -m second
 '
 
 test_expect_success POSIXPERM,SANITY 'update-index should notice unwritable repository' '
-
-       (
-               echo 6O >file &&
-               chmod a-w .git/objects .git/objects/?? &&
-               test_must_fail git update-index file
-       )
-       status=$?
-       chmod 775 .git/objects .git/objects/??
-       (exit $status)
-
+       test_when_finished "chmod 775 .git/objects .git/objects/??" &&
+       echo 6O >file &&
+       chmod a-w .git/objects .git/objects/?? &&
+       test_must_fail git update-index file
 '
 
 test_expect_success POSIXPERM,SANITY 'add should notice unwritable repository' '
-
-       (
-               echo b >file &&
-               chmod a-w .git/objects .git/objects/?? &&
-               test_must_fail git add file
-       )
-       status=$?
-       chmod 775 .git/objects .git/objects/??
-       (exit $status)
-
+       test_when_finished "chmod 775 .git/objects .git/objects/??" &&
+       echo b >file &&
+       chmod a-w .git/objects .git/objects/?? &&
+       test_must_fail git add file
 '
 
 test_done
index 9a07de1a5b6d3a98c0db0b24cdd9c3a68cef79b5..8008fa2d894baf76a19168a020ed4f4640619ce7 100755 (executable)
@@ -17,17 +17,19 @@ test_expect_success 'setup' '
        cat >expected <<-\EOF &&
        100644 77f0ba1734ed79d12881f81b36ee134de6a3327b 0       init.t
        100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0       sub/added
+       100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0       subsub/added
        EOF
        cat >expected.swt <<-\EOF &&
        H init.t
        H sub/added
+       H subsub/added
        EOF
 
        test_commit init &&
        echo modified >>init.t &&
-       mkdir sub &&
-       touch sub/added &&
-       git add init.t sub/added &&
+       mkdir sub subsub &&
+       touch sub/added subsub/added &&
+       git add init.t sub/added subsub/added &&
        git commit -m "modified and added" &&
        git tag top &&
        git rm sub/added &&
@@ -81,6 +83,7 @@ test_expect_success 'match directories with trailing slash' '
        cat >expected.swt-noinit <<-\EOF &&
        S init.t
        H sub/added
+       S subsub/added
        EOF
 
        echo sub/ > .git/info/sparse-checkout &&
@@ -105,6 +108,7 @@ test_expect_success 'checkout area changes' '
        cat >expected.swt-nosub <<-\EOF &&
        H init.t
        S sub/added
+       S subsub/added
        EOF
 
        echo init.t >.git/info/sparse-checkout &&
index 074f2f2e3e57f76b01f16502998e95b493676711..d0ab8ffe1b91a7fa37dfc7939cb3d5ae2c3cc100 100755 (executable)
@@ -701,13 +701,13 @@ cat >expect <<\EOF
        trailingtilde = foo~
 EOF
 
-test_expect_success 'set --path' '
+test_expect_success NOT_MINGW 'set --path' '
        git config --path path.home "~/" &&
        git config --path path.normal "/dev/null" &&
        git config --path path.trailingtilde "foo~" &&
        test_cmp expect .git/config'
 
-if test "${HOME+set}"
+if test_have_prereq NOT_MINGW && test "${HOME+set}"
 then
        test_set_prereq HOMEVAR
 fi
@@ -730,7 +730,7 @@ cat >expect <<\EOF
 foo~
 EOF
 
-test_expect_success 'get --path copes with unset $HOME' '
+test_expect_success NOT_MINGW 'get --path copes with unset $HOME' '
        (
                unset HOME;
                test_must_fail git config --get --path path.home \
index 100f857b168b1d8b88ea1a1e7e31ba42a2beee6c..813cc1b3e29ec840deb63ad9c3c1dffd2187cdc5 100755 (executable)
@@ -106,8 +106,8 @@ test_expect_success 'use --default' '
 
 test_expect_success 'master@{n} for various n' '
        N=$(git reflog | wc -l) &&
-       Nm1=$((N-1)) &&
-       Np1=$((N+1)) &&
+       Nm1=$(($N-1)) &&
+       Np1=$(($N+1)) &&
        git rev-parse --verify master@{0} &&
        git rev-parse --verify master@{1} &&
        git rev-parse --verify master@{$Nm1} &&
index 7f60fd0b2e8904ec231975df3d65e66c9363ff45..335420fd87f87727f323156f461e520374b7da0b 100755 (executable)
@@ -134,8 +134,8 @@ cat >ls.expected <<EOF
 100644 $ONE_SHA1 0     me
 EOF
 
-export GIT_DIR="$TRASH_DIRECTORY/.git"
-export GIT_WORK_TREE=/
+GIT_DIR="$TRASH_DIRECTORY/.git" && export GIT_DIR
+GIT_WORK_TREE=/ && export GIT_WORK_TREE
 
 test_vars 'abs gitdir, root' "$GIT_DIR" "/" ""
 test_foobar_root
@@ -154,24 +154,24 @@ say "GIT_DIR relative, GIT_WORK_TREE set"
 
 test_expect_success 'go to /' 'cd /'
 
-export GIT_DIR="$(echo $TRASH_DIRECTORY|sed 's,^/,,')/.git"
-export GIT_WORK_TREE=/
+GIT_DIR="$(echo $TRASH_DIRECTORY|sed 's,^/,,')/.git" && export GIT_DIR
+GIT_WORK_TREE=/ && export GIT_WORK_TREE
 
 test_vars 'rel gitdir, root' "$GIT_DIR" "/" ""
 test_foobar_root
 
 test_expect_success 'go to /foo' 'cd /foo'
 
-export GIT_DIR="../$TRASH_DIRECTORY/.git"
-export GIT_WORK_TREE=/
+GIT_DIR="../$TRASH_DIRECTORY/.git" && export GIT_DIR
+GIT_WORK_TREE=/ && export GIT_WORK_TREE
 
 test_vars 'rel gitdir, foo' "$TRASH_DIRECTORY/.git" "/" "foo/"
 test_foobar_foo
 
 test_expect_success 'go to /foo/bar' 'cd /foo/bar'
 
-export GIT_DIR="../../$TRASH_DIRECTORY/.git"
-export GIT_WORK_TREE=/
+GIT_DIR="../../$TRASH_DIRECTORY/.git" && export GIT_DIR
+GIT_WORK_TREE=/ && export GIT_WORK_TREE
 
 test_vars 'rel gitdir, foo/bar' "$TRASH_DIRECTORY/.git" "/" "foo/bar/"
 test_foobar_foobar
@@ -180,24 +180,24 @@ say "GIT_DIR relative, GIT_WORK_TREE relative"
 
 test_expect_success 'go to /' 'cd /'
 
-export GIT_DIR="$(echo $TRASH_DIRECTORY|sed 's,^/,,')/.git"
-export GIT_WORK_TREE=.
+GIT_DIR="$(echo $TRASH_DIRECTORY|sed 's,^/,,')/.git" && export GIT_DIR
+GIT_WORK_TREE=. && export GIT_WORK_TREE
 
 test_vars 'rel gitdir, root' "$GIT_DIR" "/" ""
 test_foobar_root
 
 test_expect_success 'go to /' 'cd /foo'
 
-export GIT_DIR="../$TRASH_DIRECTORY/.git"
-export GIT_WORK_TREE=..
+GIT_DIR="../$TRASH_DIRECTORY/.git" && export GIT_DIR
+GIT_WORK_TREE=.. && export GIT_WORK_TREE
 
 test_vars 'rel gitdir, foo' "$TRASH_DIRECTORY/.git" "/" "foo/"
 test_foobar_foo
 
 test_expect_success 'go to /foo/bar' 'cd /foo/bar'
 
-export GIT_DIR="../../$TRASH_DIRECTORY/.git"
-export GIT_WORK_TREE=../..
+GIT_DIR="../../$TRASH_DIRECTORY/.git" && export GIT_DIR
+GIT_WORK_TREE=../.. && export GIT_WORK_TREE
 
 test_vars 'rel gitdir, foo/bar' "$TRASH_DIRECTORY/.git" "/" "foo/bar/"
 test_foobar_foobar
index a7d8187169a36f708bd7dc39d97604dd9cc21565..ca01053bcc88806aae9abde5892b8c163b3936d0 100755 (executable)
@@ -26,4 +26,3 @@ test_expect_success \
     'git ls-files --error-unmatch foo bar'
 
 test_done
-1
diff --git a/t/t3032-merge-recursive-options.sh b/t/t3032-merge-recursive-options.sh
new file mode 100755 (executable)
index 0000000..2293797
--- /dev/null
@@ -0,0 +1,186 @@
+#!/bin/sh
+
+test_description='merge-recursive options
+
+* [master] Clarify
+ ! [remote] Remove cruft
+--
+ + [remote] Remove cruft
+*  [master] Clarify
+*+ [remote^] Initial revision
+*   ok 1: setup
+'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+       conflict_hunks () {
+               sed -n -e "
+                       /^<<<</ b inconflict
+                       b
+                       : inconflict
+                       p
+                       /^>>>>/ b
+                       n
+                       b inconflict
+               " "$@"
+       } &&
+
+       cat <<-\EOF >text.txt &&
+           Hope, he says, cherishes the soul of him who lives in
+           justice and holiness and is the nurse of his age and the
+           companion of his journey;--hope which is mightiest to sway
+           the restless soul of man.
+
+       How admirable are his words!  And the great blessing of riches, I do
+       not say to every man, but to a good man, is, that he has had no
+       occasion to deceive or to defraud others, either intentionally or
+       unintentionally; and when he departs to the world below he is not in
+       any apprehension about offerings due to the gods or debts which he owes
+       to men.  Now to this peace of mind the possession of wealth greatly
+       contributes; and therefore I say, that, setting one thing against
+       another, of the many advantages which wealth has to give, to a man of
+       sense this is in my opinion the greatest.
+
+       Well said, Cephalus, I replied; but as concerning justice, what is
+       it?--to speak the truth and to pay your debts--no more than this?  And
+       even to this are there not exceptions?  Suppose that a friend when in
+       his right mind has deposited arms with me and he asks for them when he
+       is not in his right mind, ought I to give them back to him?  No one
+       would say that I ought or that I should be right in doing so, any more
+       than they would say that I ought always to speak the truth to one who
+       is in his condition.
+
+       You are quite right, he replied.
+
+       But then, I said, speaking the truth and paying your debts is not a
+       correct definition of justice.
+
+       CEPHALUS - SOCRATES - POLEMARCHUS
+
+       Quite correct, Socrates, if Simonides is to be believed, said
+       Polemarchus interposing.
+
+       I fear, said Cephalus, that I must go now, for I have to look after the
+       sacrifices, and I hand over the argument to Polemarchus and the company.
+       EOF
+       git add text.txt &&
+       test_tick &&
+       git commit -m "Initial revision" &&
+
+       git checkout -b remote &&
+       sed -e "
+                       s/\.  /\. /g
+                       s/[?]  /? /g
+                       s/    / /g
+                       s/--/---/g
+                       s/but as concerning/but as con cerning/
+                       /CEPHALUS - SOCRATES - POLEMARCHUS/ d
+               " text.txt >text.txt+ &&
+       mv text.txt+ text.txt &&
+       git commit -a -m "Remove cruft" &&
+
+       git checkout master &&
+       sed -e "
+                       s/\(not in his right mind\),\(.*\)/\1;\2Q/
+                       s/Quite correct\(.*\)/It is too correct\1Q/
+                       s/unintentionally/un intentionally/
+                       /un intentionally/ s/$/Q/
+                       s/Polemarchus interposing./Polemarchus, interposing.Q/
+                       /justice and holiness/ s/$/Q/
+                       /pay your debts/ s/$/Q/
+               " text.txt | q_to_cr >text.txt+ &&
+       mv text.txt+ text.txt &&
+       git commit -a -m "Clarify" &&
+       git show-branch --all
+'
+
+test_expect_success 'naive merge fails' '
+       git read-tree --reset -u HEAD &&
+       test_must_fail git merge-recursive HEAD^ -- HEAD remote &&
+       test_must_fail git update-index --refresh &&
+       grep "<<<<<<" text.txt
+'
+
+test_expect_success '--ignore-space-change makes merge succeed' '
+       git read-tree --reset -u HEAD &&
+       git merge-recursive --ignore-space-change HEAD^ -- HEAD 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
+       EOF
+
+       git read-tree --reset -u HEAD &&
+       git merge-recursive --ignore-space-change HEAD^ -- HEAD remote &&
+       grep "justice and holiness" text.txt >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success '--ignore-space-change: their real change wins over w/s' '
+       cat <<-\EOF >expected &&
+       it?---to speak the truth and to pay your debts---no more than this? And
+       EOF
+
+       git read-tree --reset -u HEAD &&
+       git merge-recursive --ignore-space-change HEAD^ -- HEAD remote &&
+       grep "pay your debts" text.txt >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success '--ignore-space-change: does not ignore new spaces' '
+       cat <<-\EOF >expected1 &&
+       Well said, Cephalus, I replied; but as con cerning justice, what is
+       EOF
+       q_to_cr <<-\EOF >expected2 &&
+       un intentionally; and when he departs to the world below he is not inQ
+       EOF
+
+       git read-tree --reset -u HEAD &&
+       git merge-recursive --ignore-space-change HEAD^ -- HEAD remote &&
+       grep "Well said" text.txt >actual1 &&
+       grep "when he departs" text.txt >actual2 &&
+       test_cmp expected1 actual1 &&
+       test_cmp expected2 actual2
+'
+
+test_expect_success '--ignore-all-space drops their new spaces' '
+       cat <<-\EOF >expected &&
+       Well said, Cephalus, I replied; but as concerning justice, what is
+       EOF
+
+       git read-tree --reset -u HEAD &&
+       git merge-recursive --ignore-all-space HEAD^ -- HEAD remote &&
+       grep "Well said" text.txt >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success '--ignore-all-space keeps our new spaces' '
+       q_to_cr <<-\EOF >expected &&
+       un intentionally; and when he departs to the world below he is not inQ
+       EOF
+
+       git read-tree --reset -u HEAD &&
+       git merge-recursive --ignore-all-space HEAD^ -- HEAD remote &&
+       grep "when he departs" text.txt >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success '--ignore-space-at-eol' '
+       q_to_cr <<-\EOF >expected &&
+       <<<<<<< HEAD
+       is not in his right mind; ought I to give them back to him?  No oneQ
+       =======
+       is not in his right mind, ought I to give them back to him? No one
+       >>>>>>> remote
+       EOF
+
+       git read-tree --reset -u HEAD &&
+       test_must_fail git merge-recursive --ignore-space-at-eol \
+                                                HEAD^ -- HEAD remote &&
+       conflict_hunks text.txt >actual &&
+       test_cmp expected actual
+'
+
+test_done
index 2bea65634a1790ceecf824309c1fbb66250f58d5..be8c1d5ef9fd650c128a9fe7126cbcd8db6c5a95 100755 (executable)
@@ -117,4 +117,25 @@ test_expect_success 'picking rebase' '
        esac
 '
 
+test_expect_success 'rebase -s funny -Xopt' '
+       test_when_finished "rm -fr test-bin funny.was.run" &&
+       mkdir test-bin &&
+       cat >test-bin/git-merge-funny <<-EOF &&
+       #!$SHELL_PATH
+       case "\$1" in --opt) ;; *) exit 2 ;; esac
+       shift &&
+       >funny.was.run &&
+       exec git merge-recursive "\$@"
+       EOF
+       chmod +x test-bin/git-merge-funny &&
+       git reset --hard &&
+       git checkout -b test-funny master^ &&
+       test_commit funny &&
+       (
+               PATH=./test-bin:$PATH
+               git rebase -s funny -Xopt master
+       ) &&
+       test -f funny.was.run
+'
+
 test_done
index 37cb89ab53055099db3d5f774d00ade1c4da6c69..fd2184ce7159122ae8d1d65f5a228a7b91c5e02a 100755 (executable)
@@ -26,7 +26,7 @@ test_auto_fixup() {
        echo 1 >file1 &&
        git add -u &&
        test_tick &&
-       git commit -m "fixup! first"
+       git commit -m "fixup! first" &&
 
        git tag $1 &&
        test_tick &&
@@ -55,7 +55,7 @@ test_auto_squash() {
        echo 1 >file1 &&
        git add -u &&
        test_tick &&
-       git commit -m "squash! first"
+       git commit -m "squash! first" &&
 
        git tag $1 &&
        test_tick &&
@@ -84,7 +84,7 @@ test_expect_success 'misspelled auto squash' '
        echo 1 >file1 &&
        git add -u &&
        test_tick &&
-       git commit -m "squash! forst"
+       git commit -m "squash! forst" &&
        git tag final-missquash &&
        test_tick &&
        git rebase --autosquash -i HEAD^^^ &&
diff --git a/t/t3419-rebase-patch-id.sh b/t/t3419-rebase-patch-id.sh
new file mode 100755 (executable)
index 0000000..1aee483
--- /dev/null
@@ -0,0 +1,109 @@
+#!/bin/bash
+
+test_description='git rebase - test patch id computation'
+
+. ./test-lib.sh
+
+test_set_prereq NOT_EXPENSIVE
+test -n "$GIT_PATCHID_TIMING_TESTS" && test_set_prereq EXPENSIVE
+test -x /usr/bin/time && test_set_prereq USR_BIN_TIME
+
+count()
+{
+       i=0
+       while test $i -lt $1
+       do
+               echo "$i"
+               i=$(($i+1))
+       done
+}
+
+scramble()
+{
+       i=0
+       while read x
+       do
+               if test $i -ne 0
+               then
+                       echo "$x"
+               fi
+               i=$(((i+1) % 10))
+       done < "$1" > "$1.new"
+       mv -f "$1.new" "$1"
+}
+
+run()
+{
+       echo \$ "$@"
+       /usr/bin/time "$@" >/dev/null
+}
+
+test_expect_success 'setup' '
+       git commit --allow-empty -m initial
+       git tag root
+'
+
+do_tests()
+{
+       pr=$1
+       nlines=$2
+
+       test_expect_success $pr "setup: $nlines lines" "
+               rm -f .gitattributes &&
+               git checkout -q -f master &&
+               git reset --hard root &&
+               count $nlines >file &&
+               git add file &&
+               git commit -q -m initial &&
+               git branch -f other &&
+
+               scramble file &&
+               git add file &&
+               git commit -q -m 'change big file' &&
+
+               git checkout -q other &&
+               : >newfile &&
+               git add newfile &&
+               git commit -q -m 'add small file' &&
+
+               git cherry-pick master >/dev/null 2>&1
+       "
+
+       test_debug "
+               run git diff master^\!
+       "
+
+       test_expect_success $pr 'setup attributes' "
+               echo 'file binary' >.gitattributes
+       "
+
+       test_debug "
+               run git format-patch --stdout master &&
+               run git format-patch --stdout --ignore-if-in-upstream master
+       "
+
+       test_expect_success $pr 'detect upstream patch' "
+               git checkout -q master &&
+               scramble file &&
+               git add file &&
+               git commit -q -m 'change big file again' &&
+               git checkout -q other^{} &&
+               git rebase master &&
+               test_must_fail test -n \"\$(git rev-list master...HEAD~)\"
+       "
+
+       test_expect_success $pr 'do not drop patch' "
+               git branch -f squashed master &&
+               git checkout -q -f squashed &&
+               git reset -q --soft HEAD~2 &&
+               git commit -q -m squashed &&
+               git checkout -q other^{} &&
+               test_must_fail git rebase squashed &&
+               rm -rf .git/rebase-apply
+       "
+}
+
+do_tests NOT_EXPENSIVE 500
+do_tests EXPENSIVE 50000
+
+test_done
index e17ae712b1078333fa191b97764177016bc01b84..51ca391e472441d2d503e721795d609bfaad1100 100755 (executable)
@@ -95,4 +95,14 @@ test_expect_success 'cherry pick a merge relative to nonexistent parent with --f
        test_must_fail git cherry-pick --ff -m 3 C
 '
 
+test_expect_success 'cherry pick a root commit with --ff' '
+       git reset --hard first -- &&
+       git rm file1 &&
+       echo first >file2 &&
+       git add file2 &&
+       git commit --amend -m "file2" &&
+       git cherry-pick --ff first &&
+       test "$(git rev-parse --verify HEAD)" = "1df192cd8bc58a2b275d842cede4d221ad9000d1"
+'
+
 test_done
index a283dca25fe9b5d75841626337e0e68244fdbbf2..903a122efe0c54cb44eb6c3e7ed04bdbab81439d 100755 (executable)
@@ -416,8 +416,37 @@ test_expect_success 'stash show - stashes on stack, stash-like argument' '
        echo bar >> file &&
        STASH_ID=$(git stash create) &&
        git reset --hard &&
-       git stash show ${STASH_ID}
+       cat >expected <<-EOF &&
+        file |    1 +
+        1 files changed, 1 insertions(+), 0 deletions(-)
+       EOF
+       git stash show ${STASH_ID} >actual &&
+       test_cmp expected actual
 '
+
+test_expect_success 'stash show -p - stashes on stack, stash-like argument' '
+       git stash clear &&
+       test_when_finished "git reset --hard HEAD" &&
+       git reset --hard &&
+       echo foo >> file &&
+       git stash &&
+       test_when_finished "git stash drop" &&
+       echo bar >> file &&
+       STASH_ID=$(git stash create) &&
+       git reset --hard &&
+       cat >expected <<-EOF &&
+       diff --git a/file b/file
+       index 7601807..935fbd3 100644
+       --- a/file
+       +++ b/file
+       @@ -1 +1,2 @@
+        baz
+       +bar
+       EOF
+       git stash show -p ${STASH_ID} >actual &&
+       test_cmp expected actual
+'
+
 test_expect_success 'stash show - no stashes on stack, stash-like argument' '
        git stash clear &&
        test_when_finished "git reset --hard HEAD" &&
@@ -425,7 +454,32 @@ test_expect_success 'stash show - no stashes on stack, stash-like argument' '
        echo foo >> file &&
        STASH_ID=$(git stash create) &&
        git reset --hard &&
-       git stash show ${STASH_ID}
+       cat >expected <<-EOF &&
+        file |    1 +
+        1 files changed, 1 insertions(+), 0 deletions(-)
+       EOF
+       git stash show ${STASH_ID} >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'stash show -p - no stashes on stack, stash-like argument' '
+       git stash clear &&
+       test_when_finished "git reset --hard HEAD" &&
+       git reset --hard &&
+       echo foo >> file &&
+       STASH_ID=$(git stash create) &&
+       git reset --hard &&
+       cat >expected <<-EOF &&
+       diff --git a/file b/file
+       index 7601807..71b52c4 100644
+       --- a/file
+       +++ b/file
+       @@ -1 +1,2 @@
+        baz
+       +foo
+       EOF
+       git stash show -p ${STASH_ID} >actual &&
+       test_cmp expected actual
 '
 
 test_expect_success 'stash drop - fail early if specified stash is not a stash reference' '
@@ -491,4 +545,15 @@ test_expect_success 'invalid ref of the form stash@{n}, n >= N' '
        git stash drop
 '
 
+test_expect_success 'stash branch should not drop the stash if the branch exists' '
+       git stash clear &&
+       echo foo >file &&
+       git add file &&
+       git commit -m initial &&
+       echo bar >file &&
+       git stash &&
+       test_must_fail git stash branch master stash@{0} &&
+       git rev-parse stash@{0} --
+'
+
 test_done
index 6f6948925fed1b99f37ec94dd7e4aa2075eb6bb7..408a19c4c258da9b7860edffea314b181e273edf 100755 (executable)
@@ -88,4 +88,30 @@ test_expect_success SYMLINKS \
     test_must_fail git diff --no-index pinky brain > output 2> output.err &&
     grep narf output &&
     ! grep error output.err'
+
+test_expect_success SYMLINKS 'setup symlinks with attributes' '
+       echo "*.bin diff=bin" >>.gitattributes &&
+       echo content >file.bin &&
+       ln -s file.bin link.bin &&
+       git add -N file.bin link.bin
+'
+
+cat >expect <<'EOF'
+diff --git a/file.bin b/file.bin
+index e69de29..d95f3ad 100644
+Binary files a/file.bin and b/file.bin differ
+diff --git a/link.bin b/link.bin
+index e69de29..dce41ec 120000
+--- a/link.bin
++++ b/link.bin
+@@ -0,0 +1 @@
++file.bin
+\ No newline at end of file
+EOF
+test_expect_success SYMLINKS 'symlinks do not respect userdiff config by path' '
+       git config diff.bin.binary true &&
+       git diff file.bin link.bin >actual &&
+       test_cmp expect actual
+'
+
 test_done
index bc46563afc607e6fba9acbd2773d88207c878981..05ec0628322ccc103343515feb70d27a9a0e6c76 100755 (executable)
@@ -77,10 +77,6 @@ test_expect_success 'apply binary patch' \
         tree1=`git write-tree` &&
         test "$tree1" = "$tree0"'
 
-nul_to_q() {
-       perl -pe 'y/\000/Q/'
-}
-
 test_expect_success 'diff --no-index with binary creation' '
        echo Q | q_to_nul >binary &&
        (: hide error code from diff, which just indicates differences
index 19857f4326aa491a4c7d292900a0a766e7c45f80..9a665205884fcdb1c5888558d6edf960e335e013 100755 (executable)
@@ -210,6 +210,9 @@ log -m -p master
 log -SF master
 log -S F master
 log -SF -p master
+log -GF master
+log -GF -p master
+log -GF -p --pickaxe-all master
 log --decorate --all
 log --decorate=full --all
 
diff --git a/t/t4013/diff.log_-GF_-p_--pickaxe-all_master b/t/t4013/diff.log_-GF_-p_--pickaxe-all_master
new file mode 100644 (file)
index 0000000..d36f880
--- /dev/null
@@ -0,0 +1,27 @@
+$ git log -GF -p --pickaxe-all master
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+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.log_-GF_-p_master b/t/t4013/diff.log_-GF_-p_master
new file mode 100644 (file)
index 0000000..9d93f2c
--- /dev/null
@@ -0,0 +1,18 @@
+$ git log -GF -p master
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+
+diff --git a/dir/sub b/dir/sub
+index 8422d40..cead32e 100644
+--- a/dir/sub
++++ b/dir/sub
+@@ -2,3 +2,5 @@ A
+ B
+ C
+ D
++E
++F
+$
diff --git a/t/t4013/diff.log_-GF_master b/t/t4013/diff.log_-GF_master
new file mode 100644 (file)
index 0000000..4c6708d
--- /dev/null
@@ -0,0 +1,7 @@
+$ git log -GF master
+commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
+Author: A U Thor <author@example.com>
+Date:   Mon Jun 26 00:02:00 2006 +0000
+
+    Third
+$
index f87434b9f8e0d520813389e6ea7c94f74222767b..07bf6eb49dd2879758f64a8c09a0ae8d7e54dd45 100755 (executable)
@@ -12,24 +12,29 @@ test_expect_success setup '
        for i in 1 2 3 4 5 6 7 8 9 10; do echo "$i"; done >file &&
        cat file >elif &&
        git add file elif &&
+       test_tick &&
        git commit -m Initial &&
        git checkout -b side &&
 
        for i in 1 2 5 6 A B C 7 8 9 10; do echo "$i"; done >file &&
        test_chmod +x elif &&
+       test_tick &&
        git commit -m "Side changes #1" &&
 
        for i in D E F; do echo "$i"; done >>file &&
        git update-index file &&
+       test_tick &&
        git commit -m "Side changes #2" &&
        git tag C2 &&
 
        for i in 5 6 1 2 3 A 4 B C 7 8 9 10 D E F; do echo "$i"; done >file &&
        git update-index file &&
+       test_tick &&
        git commit -m "Side changes #3 with \\n backslash-n in it." &&
 
        git checkout master &&
        git diff-tree -p C2 | git apply --index &&
+       test_tick &&
        git commit -m "Master accepts moral equivalent of #2"
 
 '
@@ -51,6 +56,22 @@ test_expect_success "format-patch --ignore-if-in-upstream" '
 
 '
 
+test_expect_success "format-patch doesn't consider merge commits" '
+
+       git checkout -b slave master &&
+       echo "Another line" >>file &&
+       test_tick &&
+       git commit -am "Slave change #1" &&
+       echo "Yet another line" >>file &&
+       test_tick &&
+       git commit -am "Slave change #2" &&
+       git checkout -b merger master &&
+       test_tick &&
+       git merge --no-ff slave &&
+       cnt=`git format-patch -3 --stdout | grep "^From " | wc -l` &&
+       test $cnt = 3
+'
+
 test_expect_success "format-patch result applies" '
 
        git checkout -b rebuild-0 master &&
index c8e19372b00f128646b809e1f5723d88b58a3f30..0a61b57b5f6f00ae4c0734a34ce45c0ba1fcf098 100755 (executable)
@@ -32,7 +32,7 @@ EOF
 
 sed 's/beer\\/beer,\\/' < Beer.java > Beer-correct.java
 
-builtin_patterns="bibtex cpp csharp html java objc pascal php python ruby tex"
+builtin_patterns="bibtex cpp csharp fortran html java objc pascal php python ruby tex"
 for p in $builtin_patterns
 do
        test_expect_success "builtin $p pattern compiles" '
index 995bdfafecedf6b629acdb3300732a4bb691f23c..bf9a7526bd38a17e0e991739db8c4a1f8541b2f6 100755 (executable)
@@ -37,9 +37,10 @@ head1=$(add_file sm1 foo1 foo2)
 test_expect_success 'added submodule' "
        git add sm1 &&
        git diff-index -p --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 0000000...$head1 (new submodule)
 EOF
+       test_cmp expected actual
 "
 
 commit_file sm1 &&
@@ -47,33 +48,36 @@ head2=$(add_file sm1 foo3)
 
 test_expect_success 'modified submodule(forward)' "
        git diff-index -p --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 $head1..$head2:
   > Add foo3
 EOF
+       test_cmp expected actual
 "
 
 test_expect_success 'modified submodule(forward)' "
        git diff --submodule=log >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 $head1..$head2:
   > Add foo3
 EOF
+       test_cmp expected actual
 "
 
 test_expect_success 'modified submodule(forward) --submodule' "
        git diff --submodule >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 $head1..$head2:
   > Add foo3
 EOF
+       test_cmp expected actual
 "
 
 fullhead1=$(cd sm1; git rev-list --max-count=1 $head1)
 fullhead2=$(cd sm1; git rev-list --max-count=1 $head2)
 test_expect_success 'modified submodule(forward) --submodule=short' "
        git diff --submodule=short >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 diff --git a/sm1 b/sm1
 index $head1..$head2 160000
 --- a/sm1
@@ -82,6 +86,7 @@ index $head1..$head2 160000
 -Subproject commit $fullhead1
 +Subproject commit $fullhead2
 EOF
+       test_cmp expected actual
 "
 
 commit_file sm1 &&
@@ -93,24 +98,26 @@ head3=$(
 
 test_expect_success 'modified submodule(backward)' "
        git diff-index -p --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 $head2..$head3 (rewind):
   < Add foo3
   < Add foo2
 EOF
+       test_cmp expected actual
 "
 
 head4=$(add_file sm1 foo4 foo5) &&
 head4_full=$(GIT_DIR=sm1/.git git rev-parse --verify HEAD)
 test_expect_success 'modified submodule(backward and forward)' "
        git diff-index -p --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 $head2...$head4:
   > Add foo5
   > Add foo4
   < Add foo3
   < Add foo2
 EOF
+       test_cmp expected actual
 "
 
 commit_file sm1 &&
@@ -123,7 +130,7 @@ mv sm1-bak sm1
 
 test_expect_success 'typechanged submodule(submodule->blob), --cached' "
        git diff --submodule=log --cached >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 41fbea9...0000000 (submodule deleted)
 diff --git a/sm1 b/sm1
 new file mode 100644
@@ -133,11 +140,12 @@ index 0000000..9da5fb8
 @@ -0,0 +1 @@
 +sm1
 EOF
+       test_cmp expected actual
 "
 
 test_expect_success 'typechanged submodule(submodule->blob)' "
        git diff --submodule=log >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 diff --git a/sm1 b/sm1
 deleted file mode 100644
 index 9da5fb8..0000000
@@ -147,13 +155,14 @@ index 9da5fb8..0000000
 -sm1
 Submodule sm1 0000000...$head4 (new submodule)
 EOF
+       test_cmp expected actual
 "
 
 rm -rf sm1 &&
 git checkout-index sm1
 test_expect_success 'typechanged submodule(submodule->blob)' "
        git diff-index -p --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 $head4...0000000 (submodule deleted)
 diff --git a/sm1 b/sm1
 new file mode 100644
@@ -163,6 +172,7 @@ index 0000000..$head5
 @@ -0,0 +1 @@
 +sm1
 EOF
+       test_cmp expected actual
 "
 
 rm -f sm1 &&
@@ -171,15 +181,16 @@ head6=$(add_file sm1 foo6 foo7)
 fullhead6=$(cd sm1; git rev-list --max-count=1 $head6)
 test_expect_success 'nonexistent commit' "
        git diff-index -p --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 $head4...$head6 (commits not present)
 EOF
+       test_cmp expected actual
 "
 
 commit_file
 test_expect_success 'typechanged submodule(blob->submodule)' "
        git diff-index -p --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 diff --git a/sm1 b/sm1
 deleted file mode 100644
 index $head5..0000000
@@ -189,21 +200,24 @@ index $head5..0000000
 -sm1
 Submodule sm1 0000000...$head6 (new submodule)
 EOF
+       test_cmp expected actual
 "
 
 commit_file sm1 &&
 test_expect_success 'submodule is up to date' "
        git diff-index -p --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 EOF
+       test_cmp expected actual
 "
 
 test_expect_success 'submodule contains untracked content' "
        echo new > sm1/new-file &&
        git diff-index -p --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 contains untracked content
 EOF
+       test_cmp expected actual
 "
 
 test_expect_success 'submodule contains untracked content (untracked ignored)' "
@@ -224,18 +238,20 @@ test_expect_success 'submodule contains untracked content (all ignored)' "
 test_expect_success 'submodule contains untracked and modifed content' "
        echo new > sm1/foo6 &&
        git diff-index -p --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 contains untracked content
 Submodule sm1 contains modified content
 EOF
+       test_cmp expected actual
 "
 
 test_expect_success 'submodule contains untracked and modifed content (untracked ignored)' "
        echo new > sm1/foo6 &&
        git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 contains modified content
 EOF
+       test_cmp expected actual
 "
 
 test_expect_success 'submodule contains untracked and modifed content (dirty ignored)' "
@@ -253,45 +269,50 @@ test_expect_success 'submodule contains untracked and modifed content (all ignor
 test_expect_success 'submodule contains modifed content' "
        rm -f sm1/new-file &&
        git diff-index -p --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 contains modified content
 EOF
+       test_cmp expected actual
 "
 
 (cd sm1; git commit -mchange foo6 >/dev/null) &&
 head8=$(cd sm1; git rev-parse --verify HEAD | cut -c1-7) &&
 test_expect_success 'submodule is modified' "
        git diff-index -p --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 $head6..$head8:
   > change
 EOF
+       test_cmp expected actual
 "
 
 test_expect_success 'modified submodule contains untracked content' "
        echo new > sm1/new-file &&
        git diff-index -p --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 contains untracked content
 Submodule sm1 $head6..$head8:
   > change
 EOF
+       test_cmp expected actual
 "
 
 test_expect_success 'modified submodule contains untracked content (untracked ignored)' "
        git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 $head6..$head8:
   > change
 EOF
+       test_cmp expected actual
 "
 
 test_expect_success 'modified submodule contains untracked content (dirty ignored)' "
        git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 $head6..$head8:
   > change
 EOF
+       test_cmp expected actual
 "
 
 test_expect_success 'modified submodule contains untracked content (all ignored)' "
@@ -302,31 +323,34 @@ test_expect_success 'modified submodule contains untracked content (all ignored)
 test_expect_success 'modified submodule contains untracked and modifed content' "
        echo modification >> sm1/foo6 &&
        git diff-index -p --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 contains untracked content
 Submodule sm1 contains modified content
 Submodule sm1 $head6..$head8:
   > change
 EOF
+       test_cmp expected actual
 "
 
 test_expect_success 'modified submodule contains untracked and modifed content (untracked ignored)' "
        echo modification >> sm1/foo6 &&
        git diff-index -p --ignore-submodules=untracked --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 contains modified content
 Submodule sm1 $head6..$head8:
   > change
 EOF
+       test_cmp expected actual
 "
 
 test_expect_success 'modified submodule contains untracked and modifed content (dirty ignored)' "
        echo modification >> sm1/foo6 &&
        git diff-index -p --ignore-submodules=dirty --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 $head6..$head8:
   > change
 EOF
+       test_cmp expected actual
 "
 
 test_expect_success 'modified submodule contains untracked and modifed content (all ignored)' "
@@ -338,19 +362,21 @@ test_expect_success 'modified submodule contains untracked and modifed content (
 test_expect_success 'modified submodule contains modifed content' "
        rm -f sm1/new-file &&
        git diff-index -p --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 contains modified content
 Submodule sm1 $head6..$head8:
   > change
 EOF
+       test_cmp expected actual
 "
 
 rm -rf sm1
 test_expect_success 'deleted submodule' "
        git diff-index -p --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 $head6...0000000 (submodule deleted)
 EOF
+       test_cmp expected actual
 "
 
 test_create_repo sm2 &&
@@ -359,41 +385,45 @@ git add sm2
 
 test_expect_success 'multiple submodules' "
        git diff-index -p --submodule=log HEAD >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 $head6...0000000 (submodule deleted)
 Submodule sm2 0000000...$head7 (new submodule)
 EOF
+       test_cmp expected actual
 "
 
 test_expect_success 'path filter' "
        git diff-index -p --submodule=log HEAD sm2 >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm2 0000000...$head7 (new submodule)
 EOF
+       test_cmp expected actual
 "
 
 commit_file sm2
 test_expect_success 'given commit' "
        git diff-index -p --submodule=log HEAD^ >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 $head6...0000000 (submodule deleted)
 Submodule sm2 0000000...$head7 (new submodule)
 EOF
+       test_cmp expected actual
 "
 
 test_expect_success 'given commit --submodule' "
        git diff-index -p --submodule HEAD^ >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 $head6...0000000 (submodule deleted)
 Submodule sm2 0000000...$head7 (new submodule)
 EOF
+       test_cmp expected actual
 "
 
 fullhead7=$(cd sm2; git rev-list --max-count=1 $head7)
 
 test_expect_success 'given commit --submodule=short' "
        git diff-index -p --submodule=short HEAD^ >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 diff --git a/sm1 b/sm1
 deleted file mode 160000
 index $head6..0000000
@@ -409,6 +439,7 @@ index 0000000..$head7
 @@ -0,0 +1 @@
 +Subproject commit $fullhead7
 EOF
+       test_cmp expected actual
 "
 
 test_expect_success 'setup .git file for sm2' '
@@ -420,10 +451,11 @@ test_expect_success 'setup .git file for sm2' '
 
 test_expect_success 'diff --submodule with .git file' '
        git diff --submodule HEAD^ >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 Submodule sm1 $head6...0000000 (submodule deleted)
 Submodule sm2 0000000...$head7 (new submodule)
 EOF
+       test_cmp expected actual
 '
 
 test_done
index 9692f16f3581f261c4c10a29f03751990adb7897..08ad6d8b9e6b2869bfd2b574779380895709972d 100755 (executable)
@@ -37,7 +37,16 @@ test_expect_success 'setup' "
        git diff-tree -p -C master binary >C.diff &&
 
        git diff-tree -p --binary master binary >BF.diff &&
-       git diff-tree -p --binary -C master binary >CF.diff
+       git diff-tree -p --binary -C master binary >CF.diff &&
+
+       git diff-tree -p --full-index master binary >B-index.diff &&
+       git diff-tree -p -C --full-index master binary >C-index.diff &&
+
+       git init other-repo &&
+       (cd other-repo &&
+        git fetch .. master &&
+        git reset --hard FETCH_HEAD
+       )
 "
 
 test_expect_success 'stat binary diff -- should not fail.' \
@@ -100,6 +109,22 @@ test_expect_success 'apply binary diff (copy) -- should fail.' \
        'do_reset &&
         test_must_fail git apply --index C.diff'
 
+test_expect_success 'apply binary diff with full-index' '
+       do_reset &&
+       git apply B-index.diff
+'
+
+test_expect_success 'apply binary diff with full-index (copy)' '
+       do_reset &&
+       git apply C-index.diff
+'
+
+test_expect_success 'apply full-index binary diff in new repo' '
+       (cd other-repo &&
+        do_reset &&
+        test_must_fail git apply ../B-index.diff)
+'
+
 test_expect_success 'apply binary diff without replacement.' \
        'do_reset &&
         git apply BF.diff'
index 27bfba55bd9631a666ee382b343c3c04af1ad26d..cff1b3e0502e96ff6232611ef70c24752a970a96 100755 (executable)
@@ -94,7 +94,7 @@ test_expect_success 'git archive with --output' \
     'git archive --output=b4.tar HEAD &&
     test_cmp b.tar b4.tar'
 
-test_expect_success 'git archive --remote' \
+test_expect_success NOT_MINGW 'git archive --remote' \
     'git archive --remote=. HEAD >b5.tar &&
     test_cmp b.tar b5.tar'
 
index 8a298a655fa007fbd9a43d6212b53f749c980eb6..aa0ada01476b89f3f284dda42f892155496f3467 100755 (executable)
@@ -4,14 +4,9 @@ test_description='test automatic tag following'
 
 . ./test-lib.sh
 
-case $(uname -s) in
-*MINGW*)
+if ! test_have_prereq NOT_MINGW; then
        say "GIT_DEBUG_SEND_PACK not supported - skipping tests"
-       ;;
-*)
-       test_set_prereq NOT_MINGW
-       ;;
-esac
+fi
 
 # End state of the repository:
 #
index 00da70763bc34fe05dcba90a48799e32880571ce..c229fe68f11007fbb96d7b3837c18fd2f306a0bf 100755 (executable)
@@ -2,9 +2,14 @@
 
 test_description='push with --set-upstream'
 . ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
+
+ensure_fresh_upstream() {
+       rm -rf parent && git init --bare parent
+}
 
 test_expect_success 'setup bare parent' '
-       git init --bare parent &&
+       ensure_fresh_upstream &&
        git remote add upstream parent
 '
 
@@ -66,4 +71,41 @@ test_expect_success 'push -u HEAD' '
        check_config headbranch upstream refs/heads/headbranch
 '
 
+test_expect_success TTY 'progress messages go to tty' '
+       ensure_fresh_upstream &&
+
+       test_terminal git push -u upstream master >out 2>err &&
+       grep "Writing objects" err
+'
+
+test_expect_success 'progress messages do not go to non-tty' '
+       ensure_fresh_upstream &&
+
+       # skip progress messages, since stderr is non-tty
+       git push -u upstream master >out 2>err &&
+       ! grep "Writing objects" err
+'
+
+test_expect_success 'progress messages go to non-tty (forced)' '
+       ensure_fresh_upstream &&
+
+       # force progress messages to stderr, even though it is non-tty
+       git push -u --progress upstream master >out 2>err &&
+       grep "Writing objects" err
+'
+
+test_expect_success TTY 'push -q suppresses progress' '
+       ensure_fresh_upstream &&
+
+       test_terminal git push -u -q upstream master >out 2>err &&
+       ! grep "Writing objects" err
+'
+
+test_expect_failure TTY 'push --no-progress suppresses progress' '
+       ensure_fresh_upstream &&
+
+       test_terminal git push -u --no-progress upstream master >out 2>err &&
+       ! grep "Writing objects" err
+'
+
 test_done
index 44885b850c4a1c3a09b8b078a643cf7cd8918213..0ad7ce07c4550ed28a22743a3c543e16f4d4c558 100755 (executable)
@@ -5,16 +5,17 @@ test_description='test git-http-backend-noserver'
 
 HTTPD_DOCUMENT_ROOT_PATH="$TRASH_DIRECTORY"
 
+test_have_prereq MINGW && export GREP_OPTIONS=-U
+
 run_backend() {
        echo "$2" |
        QUERY_STRING="${1#*\?}" \
-       GIT_PROJECT_ROOT="$HTTPD_DOCUMENT_ROOT_PATH" \
-       PATH_INFO="${1%%\?*}" \
+       PATH_TRANSLATED="$HTTPD_DOCUMENT_ROOT_PATH/${1%%\?*}" \
        git http-backend >act.out 2>act.err
 }
 
 GET() {
-       export REQUEST_METHOD="GET" &&
+       REQUEST_METHOD="GET" && export REQUEST_METHOD &&
        run_backend "/repo.git/$1" &&
        unset REQUEST_METHOD &&
        if ! grep "Status" act.out >act
@@ -26,8 +27,8 @@ GET() {
 }
 
 POST() {
-       export REQUEST_METHOD="POST" &&
-       export CONTENT_TYPE="application/x-$1-request" &&
+       REQUEST_METHOD="POST" && export REQUEST_METHOD &&
+       CONTENT_TYPE="application/x-$1-request" && export CONTENT_TYPE &&
        run_backend "/repo.git/$1" "$2" &&
        unset REQUEST_METHOD &&
        unset CONTENT_TYPE &&
@@ -46,7 +47,7 @@ log_div() {
 . "$TEST_DIRECTORY"/t556x_common
 
 expect_aliased() {
-       export REQUEST_METHOD="GET" &&
+       REQUEST_METHOD="GET" && export REQUEST_METHOD &&
        if test $1 = 0; then
                run_backend "$2"
        else
index be024e551c977355d8611c2134a4eda97a2bcc7d..51287d89d8deb27ae2ae49fec84268422377eb29 100755 (executable)
@@ -50,7 +50,7 @@ get_static_files() {
 }
 
 SMART=smart
-export GIT_HTTP_EXPORT_ALL=1
+GIT_HTTP_EXPORT_ALL=1 && export GIT_HTTP_EXPORT_ALL
 test_expect_success 'direct refs/heads/master not found' '
        log_div "refs/heads/master"
        GET refs/heads/master "404 Not Found"
@@ -73,7 +73,7 @@ test_expect_success 'export if git-daemon-export-ok' '
         get_static_files "200 OK"
 '
 SMART=smart
-export GIT_HTTP_EXPORT_ALL=1
+GIT_HTTP_EXPORT_ALL=1 && export GIT_HTTP_EXPORT_ALL
 test_expect_success 'static file if http.getanyfile true is ok' '
        log_div "getanyfile true"
        config http.getanyfile true &&
index cccacd4add48524abd4a3021f8048a6c45c245ea..d918cc02d090157485d404d34d49005e50cd9f1a 100755 (executable)
@@ -162,6 +162,14 @@ commit 131a310eb913d107dd3c09a65d1651175898735d
 commit 86c75cfd708a0e5868dc876ed5b8bb66c80b4873
 EOF
 
+test_expect_success '%x00 shows NUL' '
+       echo  >expect commit f58db70b055c5718631e5c61528b28b12090cdea &&
+       echo >>expect fooQbar &&
+       git rev-list -1 --format=foo%x00bar HEAD >actual.nul &&
+       nul_to_q <actual.nul >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success '%ad respects --date=' '
        echo 2005-04-07 >expect.ad-short &&
        git log -1 --date=short --pretty=tformat:%ad >output.ad-short master &&
index d486d73994cf563063b578ec5e212331e87bf67f..d9f343942c7eb9d1e80e98db2252cb29135544fa 100755 (executable)
@@ -64,6 +64,14 @@ cp new1.txt test.txt
 test_expect_success "merge without conflict" \
        "git merge-file test.txt orig.txt new2.txt"
 
+test_expect_success 'works in subdirectory' '
+       mkdir dir &&
+       cp new1.txt dir/a.txt &&
+       cp orig.txt dir/o.txt &&
+       cp new2.txt dir/b.txt &&
+       ( cd dir && git merge-file a.txt o.txt b.txt )
+'
+
 cp new1.txt test.txt
 test_expect_success "merge without conflict (--quiet)" \
        "git merge-file --quiet test.txt orig.txt new2.txt"
index 52d0dc4bb8f80393c79935f9c951b5323287e41c..460bf741b594d4d6b7f2220ac0f1a0d28c653619 100755 (executable)
@@ -14,6 +14,8 @@ test_description='CRLF merge conflict across text=auto change
 
 . ./test-lib.sh
 
+test_have_prereq MINGW && SED_OPTIONS=-b
+
 test_expect_success setup '
        git config core.autocrlf false &&
 
@@ -60,7 +62,7 @@ test_expect_success setup '
 
 test_expect_success 'set up fuzz_conflict() helper' '
        fuzz_conflict() {
-               sed -e "s/^\([<>=]......\) .*/\1/" "$@"
+               sed $SED_OPTIONS -e "s/^\([<>=]......\) .*/\1/" "$@"
        }
 '
 
index c907523e7e04542c6aada74f9b355ebcbae8c562..95b180f4693658504fa44d8199efc2a31e85b43d 100755 (executable)
@@ -205,9 +205,16 @@ test_expect_success 'fetch branch with replacement' '
      git branch tofetch $HASH6 &&
      (
          cd clone_dir &&
-         git fetch origin refs/heads/tofetch:refs/heads/parallel3
-         git log --pretty=oneline parallel3 | grep $PARA3
-         git show $PARA3 | grep "A U Thor"
+         git fetch origin refs/heads/tofetch:refs/heads/parallel3 &&
+         git log --pretty=oneline parallel3 > output.txt &&
+         ! grep $PARA3 output.txt &&
+         git show $PARA3 > para3.txt &&
+         grep "A U Thor" para3.txt &&
+         git fetch origin "refs/replace/*:refs/replace/*" &&
+         git log --pretty=oneline parallel3 > output.txt &&
+         grep $PARA3 output.txt &&
+         git show $PARA3 > para3.txt &&
+         grep "O Thor" para3.txt
      )
 '
 
index 71f6cad3c2b8e8ed0b16d292f4922760901702ef..9a168069217ef8d82173e563a04eaefe58d99f2a 100755 (executable)
@@ -129,6 +129,97 @@ test_expect_success '[merge] summary/log configuration' '
        test_cmp expected actual2
 '
 
+test_expect_success 'setup: clear [merge] configuration' '
+       test_might_fail git config --unset-all merge.log &&
+       test_might_fail git config --unset-all merge.summary
+'
+
+test_expect_success 'setup FETCH_HEAD' '
+       git checkout master &&
+       test_tick &&
+       git fetch . left
+'
+
+test_expect_success 'merge.log=3 limits shortlog length' '
+       cat >expected <<-EOF &&
+       Merge branch ${apos}left${apos}
+
+       * left: (5 commits)
+         Left #5
+         Left #4
+         Left #3
+         ...
+       EOF
+
+       git -c merge.log=3 fmt-merge-msg <.git/FETCH_HEAD >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'merge.log=5 shows all 5 commits' '
+       cat >expected <<-EOF &&
+       Merge branch ${apos}left${apos}
+
+       * left:
+         Left #5
+         Left #4
+         Left #3
+         Common #2
+         Common #1
+       EOF
+
+       git -c merge.log=5 fmt-merge-msg <.git/FETCH_HEAD >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'merge.log=0 disables shortlog' '
+       echo "Merge branch ${apos}left${apos}" >expected
+       git -c merge.log=0 fmt-merge-msg <.git/FETCH_HEAD >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success '--log=3 limits shortlog length' '
+       cat >expected <<-EOF &&
+       Merge branch ${apos}left${apos}
+
+       * left: (5 commits)
+         Left #5
+         Left #4
+         Left #3
+         ...
+       EOF
+
+       git fmt-merge-msg --log=3 <.git/FETCH_HEAD >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success '--log=5 shows all 5 commits' '
+       cat >expected <<-EOF &&
+       Merge branch ${apos}left${apos}
+
+       * left:
+         Left #5
+         Left #4
+         Left #3
+         Common #2
+         Common #1
+       EOF
+
+       git fmt-merge-msg --log=5 <.git/FETCH_HEAD >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success '--no-log disables shortlog' '
+       echo "Merge branch ${apos}left${apos}" >expected &&
+       git fmt-merge-msg --no-log <.git/FETCH_HEAD >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success '--log=0 disables shortlog' '
+       echo "Merge branch ${apos}left${apos}" >expected &&
+       git fmt-merge-msg --no-log <.git/FETCH_HEAD >actual &&
+       test_cmp expected actual
+'
+
 test_expect_success 'fmt-merge-msg -m' '
        echo "Sync with left" >expected &&
        cat >expected.log <<-EOF &&
index ac943f5eeecd17dd1edc5834265df9e16e5032f2..700b556fe886ff8e6927591e4a047542bc00ef83 100755 (executable)
@@ -1051,13 +1051,23 @@ test_expect_success \
 
 test_expect_success \
        'message in editor has initial comment' '
-       GIT_EDITOR=cat git tag -a initial-comment > actual
+       ! (GIT_EDITOR=cat git tag -a initial-comment > actual)
+'
+
+test_expect_success \
+       'message in editor has initial comment: first line' '
        # check the first line --- should be empty
-       first=$(sed -e 1q <actual) &&
-       test -z "$first" &&
+       echo >first.expect &&
+       sed -e 1q <actual >first.actual &&
+       test_cmp first.expect first.actual
+'
+
+test_expect_success \
+       'message in editor has initial comment: remainder' '
        # remove commented lines from the remainder -- should be empty
-       rest=$(sed -e 1d -e '/^#/d' <actual) &&
-       test -z "$rest"
+       >rest.expect
+       sed -e 1d -e '/^#/d' <actual >rest.actual &&
+       test_cmp rest.expect rest.actual
 '
 
 get_tag_header reuse $commit commit $time >expect
index fb744e3c4a9a19d9285fc04053044242ffed0c65..5641b595596ea462ec649c531e7173709a012274 100755 (executable)
@@ -4,42 +4,13 @@ test_description='Test automatic use of a pager.'
 
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-pager.sh
+. "$TEST_DIRECTORY"/lib-terminal.sh
 
 cleanup_fail() {
        echo >&2 cleanup failed
        (exit 1)
 }
 
-test_expect_success 'set up terminal for tests' '
-       rm -f stdout_is_tty ||
-       cleanup_fail &&
-
-       if test -t 1
-       then
-               >stdout_is_tty
-       elif
-               test_have_prereq PERL &&
-               "$PERL_PATH" "$TEST_DIRECTORY"/t7006/test-terminal.perl \
-                       sh -c "test -t 1"
-       then
-               >test_terminal_works
-       fi
-'
-
-if test -e stdout_is_tty
-then
-       test_terminal() { "$@"; }
-       test_set_prereq TTY
-elif test -e test_terminal_works
-then
-       test_terminal() {
-               "$PERL_PATH" "$TEST_DIRECTORY"/t7006/test-terminal.perl "$@"
-       }
-       test_set_prereq TTY
-else
-       say "# no usable terminal, so skipping some tests"
-fi
-
 test_expect_success 'setup' '
        unset GIT_PAGER GIT_PAGER_IN_USE;
        test_might_fail git config --unset core.pager &&
@@ -213,11 +184,6 @@ test_expect_success 'color when writing to a file intended for a pager' '
        colorful colorful.log
 '
 
-if test_have_prereq SIMPLEPAGER && test_have_prereq TTY
-then
-       test_set_prereq SIMPLEPAGERTTY
-fi
-
 # Use this helper to make it easy for the caller of your
 # terminal-using function to specify whether it should fail.
 # If you write
@@ -253,7 +219,7 @@ parse_args() {
 test_default_pager() {
        parse_args "$@"
 
-       $test_expectation SIMPLEPAGERTTY "$cmd - default pager is used by default" "
+       $test_expectation SIMPLEPAGER,TTY "$cmd - default pager is used by default" "
                unset PAGER GIT_PAGER;
                test_might_fail git config --unset core.pager &&
                rm -f default_pager_used ||
diff --git a/t/t7006/test-terminal.perl b/t/t7006/test-terminal.perl
deleted file mode 100755 (executable)
index 73ff809..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/perl
-use strict;
-use warnings;
-use IO::Pty;
-use File::Copy;
-
-# Run @$argv in the background with stdout redirected to $out.
-sub start_child {
-       my ($argv, $out) = @_;
-       my $pid = fork;
-       if (not defined $pid) {
-               die "fork failed: $!"
-       } elsif ($pid == 0) {
-               open STDOUT, ">&", $out;
-               close $out;
-               exec(@$argv) or die "cannot exec '$argv->[0]': $!"
-       }
-       return $pid;
-}
-
-# Wait for $pid to finish.
-sub finish_child {
-       # Simplified from wait_or_whine() in run-command.c.
-       my ($pid) = @_;
-
-       my $waiting = waitpid($pid, 0);
-       if ($waiting < 0) {
-               die "waitpid failed: $!";
-       } elsif ($? & 127) {
-               my $code = $? & 127;
-               warn "died of signal $code";
-               return $code - 128;
-       } else {
-               return $? >> 8;
-       }
-}
-
-sub xsendfile {
-       my ($out, $in) = @_;
-
-       # Note: the real sendfile() cannot read from a terminal.
-
-       # It is unspecified by POSIX whether reads
-       # from a disconnected terminal will return
-       # EIO (as in AIX 4.x, IRIX, and Linux) or
-       # end-of-file.  Either is fine.
-       copy($in, $out, 4096) or $!{EIO} or die "cannot copy from child: $!";
-}
-
-if ($#ARGV < 1) {
-       die "usage: test-terminal program args";
-}
-my $master = new IO::Pty;
-my $slave = $master->slave;
-my $pid = start_child(\@ARGV, $slave);
-close $slave;
-xsendfile(\*STDOUT, $master);
-exit(finish_child($pid));
index 294584452bbc3226e631ce0b81c546b04cd8d992..7d7fde057b04e4615e32b0ddc71fd3b07968a129 100755 (executable)
@@ -37,11 +37,12 @@ head1=$(add_file sm1 foo1 foo2)
 test_expect_success 'added submodule' "
        git add sm1 &&
        git submodule summary >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 * sm1 0000000...$head1 (2):
   > Add foo2
 
 EOF
+       test_cmp expected actual
 "
 
 commit_file sm1 &&
@@ -49,20 +50,22 @@ head2=$(add_file sm1 foo3)
 
 test_expect_success 'modified submodule(forward)' "
        git submodule summary >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 * sm1 $head1...$head2 (1):
   > Add foo3
 
 EOF
+       test_cmp expected actual
 "
 
 test_expect_success 'modified submodule(forward), --files' "
        git submodule summary --files >actual &&
-       diff actual - <<-EOF
+       cat >expected <<-EOF &&
 * sm1 $head1...$head2 (1):
   > Add foo3
 
 EOF
+       test_cmp expected actual
 "
 
 commit_file sm1 &&
@@ -74,19 +77,20 @@ head3=$(
 
 test_expect_success 'modified submodule(backward)' "
     git submodule summary >actual &&
-    diff actual - <<-EOF
+    cat >expected <<-EOF &&
 * sm1 $head2...$head3 (2):
   < Add foo3
   < Add foo2
 
 EOF
+       test_cmp expected actual
 "
 
 head4=$(add_file sm1 foo4 foo5) &&
 head4_full=$(GIT_DIR=sm1/.git git rev-parse --verify HEAD)
 test_expect_success 'modified submodule(backward and forward)' "
     git submodule summary >actual &&
-    diff actual - <<-EOF
+    cat >expected <<-EOF &&
 * sm1 $head2...$head4 (4):
   > Add foo5
   > Add foo4
@@ -94,17 +98,19 @@ test_expect_success 'modified submodule(backward and forward)' "
   < Add foo2
 
 EOF
+       test_cmp expected actual
 "
 
 test_expect_success '--summary-limit' "
     git submodule summary -n 3 >actual &&
-    diff actual - <<-EOF
+    cat >expected <<-EOF &&
 * sm1 $head2...$head4 (4):
   > Add foo5
   > Add foo4
   < Add foo3
 
 EOF
+    test_cmp expected actual
 "
 
 commit_file sm1 &&
@@ -117,30 +123,33 @@ mv sm1-bak sm1
 
 test_expect_success 'typechanged submodule(submodule->blob), --cached' "
     git submodule summary --cached >actual &&
-    diff actual - <<-EOF
+    cat >expected <<-EOF &&
 * sm1 $head4(submodule)->$head5(blob) (3):
   < Add foo5
 
 EOF
+       test_cmp actual expected
 "
 
 test_expect_success 'typechanged submodule(submodule->blob), --files' "
     git submodule summary --files >actual &&
-    diff actual - <<-EOF
+    cat >expected <<-EOF &&
 * sm1 $head5(blob)->$head4(submodule) (3):
   > Add foo5
 
 EOF
+    test_cmp actual expected
 "
 
 rm -rf sm1 &&
 git checkout-index sm1
 test_expect_success 'typechanged submodule(submodule->blob)' "
     git submodule summary >actual &&
-    diff actual - <<-EOF
+    cat >expected <<-EOF &&
 * sm1 $head4(submodule)->$head5(blob):
 
 EOF
+    test_cmp actual expected
 "
 
 rm -f sm1 &&
@@ -148,31 +157,34 @@ test_create_repo sm1 &&
 head6=$(add_file sm1 foo6 foo7)
 test_expect_success 'nonexistent commit' "
     git submodule summary >actual &&
-    diff actual - <<-EOF
+    cat >expected <<-EOF &&
 * sm1 $head4...$head6:
   Warn: sm1 doesn't contain commit $head4_full
 
 EOF
+    test_cmp actual expected
 "
 
 commit_file
 test_expect_success 'typechanged submodule(blob->submodule)' "
     git submodule summary >actual &&
-    diff actual - <<-EOF
+    cat >expected <<-EOF &&
 * sm1 $head5(blob)->$head6(submodule) (2):
   > Add foo7
 
 EOF
+    test_cmp expected actual
 "
 
 commit_file sm1 &&
 rm -rf sm1
 test_expect_success 'deleted submodule' "
     git submodule summary >actual &&
-    diff actual - <<-EOF
+    cat >expected <<-EOF &&
 * sm1 $head6...0000000:
 
 EOF
+    test_cmp expected actual
 "
 
 test_create_repo sm2 &&
@@ -181,34 +193,37 @@ git add sm2
 
 test_expect_success 'multiple submodules' "
     git submodule summary >actual &&
-    diff actual - <<-EOF
+    cat >expected <<-EOF &&
 * sm1 $head6...0000000:
 
 * sm2 0000000...$head7 (2):
   > Add foo9
 
 EOF
+    test_cmp expected actual
 "
 
 test_expect_success 'path filter' "
     git submodule summary sm2 >actual &&
-    diff actual - <<-EOF
+    cat >expected <<-EOF &&
 * sm2 0000000...$head7 (2):
   > Add foo9
 
 EOF
+    test_cmp expected actual
 "
 
 commit_file sm2
 test_expect_success 'given commit' "
     git submodule summary HEAD^ >actual &&
-    diff actual - <<-EOF
+    cat >expected <<-EOF &&
 * sm1 $head6...0000000:
 
 * sm2 0000000...$head7 (2):
   > Add foo9
 
 EOF
+    test_cmp expected actual
 "
 
 test_expect_success '--for-status' "
index 02522f9627eea8166b2d4709ef3519b23c8dd3d5..e5b19538b0192e5ab5f9081b0c10ac0dc8497cb6 100755 (executable)
@@ -23,7 +23,9 @@ test_expect_success setup '
         git commit -m "submodule"
        ) &&
        git clone super super-clone &&
-       (cd super-clone && git submodule update --init)
+       (cd super-clone && git submodule update --init) &&
+       git clone super empty-clone &&
+       (cd empty-clone && git submodule init)
 '
 
 test_expect_success 'change submodule' '
@@ -64,4 +66,12 @@ test_expect_success '"git submodule sync" should update submodule URLs' '
        )
 '
 
+test_expect_success '"git submodule sync" should update submodule URLs if not yet cloned' '
+       (cd empty-clone &&
+        git pull &&
+        git submodule sync &&
+        test -d "$(git config submodule.submodule.url)"
+       )
+'
+
 test_done
index 023f225a4b1f22c66fb291a76690564696d56035..50658845ca8769e963cfc13b20efb892f1f63cc0 100755 (executable)
@@ -324,8 +324,13 @@ test_expect_success 'log grep setup' '
 
        echo a >>file &&
        test_tick &&
-       git commit -a -m "third"
+       git commit -a -m "third" &&
 
+       echo a >>file &&
+       test_tick &&
+       GIT_AUTHOR_NAME="Night Fall" \
+       GIT_AUTHOR_EMAIL="nitfol@frobozz.com" \
+       git commit -a -m "fourth"
 '
 
 test_expect_success 'log grep (1)' '
@@ -372,6 +377,28 @@ test_expect_success 'log --grep --author implicitly uses all-match' '
        test_cmp expect actual
 '
 
+test_expect_success 'log with multiple --author uses union' '
+       git log --author="Thor" --author="Aster" --format=%s >actual &&
+       {
+           echo third && echo second && echo initial
+       } >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log with --grep and multiple --author uses all-match' '
+       git log --author="Thor" --author="Night" --grep=i --format=%s >actual &&
+       {
+           echo third && echo initial
+       } >expect &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log with --grep and multiple --author uses all-match' '
+       git log --author="Thor" --author="Night" --grep=q --format=%s >actual &&
+       >expect &&
+       test_cmp expect actual
+'
+
 test_expect_success 'grep with CE_VALID file' '
        git update-index --assume-unchanged t/t &&
        rm t/t &&
index 9ad96d4d32390081ba97c336d80b2294cf69dc44..dbf623bce5598860800fa463c26ec8145d6e2400 100755 (executable)
@@ -9,22 +9,29 @@ find_blame() {
 
 cat >helper <<'EOF'
 #!/bin/sh
-sed 's/^/converted: /' "$@"
+grep -q '^bin: ' "$1" || { echo "E: $1 is not \"binary\" file" 1>&2; exit 1; }
+sed 's/^bin: /converted: /' "$1"
 EOF
 chmod +x helper
 
 test_expect_success 'setup ' '
-       echo test 1 >one.bin &&
-       echo test number 2 >two.bin &&
+       echo "bin: test 1" >one.bin &&
+       echo "bin: test number 2" >two.bin &&
+       if test_have_prereq SYMLINKS; then
+               ln -s one.bin symlink.bin
+       fi &&
        git add . &&
        GIT_AUTHOR_NAME=Number1 git commit -a -m First --date="2010-01-01 18:00:00" &&
-       echo test 1 version 2 >one.bin &&
-       echo test number 2 version 2 >>two.bin &&
+       echo "bin: test 1 version 2" >one.bin &&
+       echo "bin: test number 2 version 2" >>two.bin &&
+       if test_have_prereq SYMLINKS; then
+               ln -sf two.bin symlink.bin
+       fi &&
        GIT_AUTHOR_NAME=Number2 git commit -a -m Second --date="2010-01-01 20:00:00"
 '
 
 cat >expected <<EOF
-(Number2 2010-01-01 20:00:00 +0000 1) test 1 version 2
+(Number2 2010-01-01 20:00:00 +0000 1) bin: test 1 version 2
 EOF
 
 test_expect_success 'no filter specified' '
@@ -67,7 +74,7 @@ test_expect_success 'blame --textconv going through revisions' '
 '
 
 test_expect_success 'make a new commit' '
-       echo "test number 2 version 3" >>two.bin &&
+       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"
 '
 
@@ -77,4 +84,45 @@ test_expect_success 'blame from previous revision' '
        test_cmp expected result
 '
 
+cat >expected <<EOF
+(Number2 2010-01-01 20:00:00 +0000 1) two.bin
+EOF
+
+test_expect_success SYMLINKS 'blame with --no-textconv (on symlink)' '
+       git blame --no-textconv symlink.bin >blame &&
+       find_blame <blame >result &&
+       test_cmp expected result
+'
+
+test_expect_success SYMLINKS 'blame --textconv (on symlink)' '
+       git blame --textconv symlink.bin >blame &&
+       find_blame <blame >result &&
+       test_cmp expected result
+'
+
+# cp two.bin three.bin  and make small tweak
+# (this will direct blame -C -C three.bin to consider two.bin and symlink.bin)
+test_expect_success SYMLINKS 'make another new commit' '
+       cat >three.bin <<\EOF &&
+bin: test number 2
+bin: test number 2 version 2
+bin: test number 2 version 3
+bin: test number 3
+EOF
+       git add three.bin &&
+       GIT_AUTHOR_NAME=Number4 git commit -a -m Fourth --date="2010-01-01 23:00:00"
+'
+
+test_expect_success SYMLINKS 'blame on last commit (-C -C, symlink)' '
+       git blame -C -C three.bin >blame &&
+       find_blame <blame >result &&
+       cat >expected <<\EOF &&
+(Number1 2010-01-01 18:00:00 +0000 1) converted: test number 2
+(Number2 2010-01-01 20:00:00 +0000 2) converted: test number 2 version 2
+(Number3 2010-01-01 22:00:00 +0000 3) converted: test number 2 version 3
+(Number4 2010-01-01 23:00:00 +0000 4) converted: test number 3
+EOF
+       test_cmp expected result
+'
+
 test_done
index 38ac05e4a0b62e9105a400b4583d5504b42b3e7d..78a0085e648b8fa6773b47e86959853cf29ccdf9 100755 (executable)
@@ -5,15 +5,19 @@ test_description='git cat-file textconv support'
 
 cat >helper <<'EOF'
 #!/bin/sh
-sed 's/^/converted: /' "$@"
+grep -q '^bin: ' "$1" || { echo "E: $1 is not \"binary\" file" 1>&2; exit 1; }
+sed 's/^bin: /converted: /' "$1"
 EOF
 chmod +x helper
 
 test_expect_success 'setup ' '
-       echo test >one.bin &&
+       echo "bin: test" >one.bin &&
+       if test_have_prereq SYMLINKS; then
+               ln -s one.bin symlink.bin
+       fi &&
        git add . &&
        GIT_AUTHOR_NAME=Number1 git commit -a -m First --date="2010-01-01 18:00:00" &&
-       echo test version 2 >one.bin &&
+       echo "bin: test version 2" >one.bin &&
        GIT_AUTHOR_NAME=Number2 git commit -a -m Second --date="2010-01-01 20:00:00"
 '
 
@@ -33,7 +37,7 @@ test_expect_success 'setup textconv filters' '
 '
 
 cat >expected <<EOF
-test version 2
+bin: test version 2
 EOF
 
 test_expect_success 'cat-file without --textconv' '
@@ -42,7 +46,7 @@ test_expect_success 'cat-file without --textconv' '
 '
 
 cat >expected <<EOF
-test
+bin: test
 EOF
 
 test_expect_success 'cat-file without --textconv on previous commit' '
@@ -67,4 +71,28 @@ test_expect_success 'cat-file --textconv on previous commit' '
        git cat-file --textconv HEAD^:one.bin >result &&
        test_cmp expected result
 '
+
+test_expect_success SYMLINKS 'cat-file without --textconv (symlink)' '
+       git cat-file blob :symlink.bin >result &&
+       printf "%s" "one.bin" >expected
+       test_cmp expected result
+'
+
+
+test_expect_success SYMLINKS 'cat-file --textconv on index (symlink)' '
+       ! git cat-file --textconv :symlink.bin 2>result &&
+       cat >expected <<\EOF &&
+fatal: git cat-file --textconv: unable to run textconv on :symlink.bin
+EOF
+       test_cmp expected result
+'
+
+test_expect_success SYMLINKS 'cat-file --textconv on HEAD (symlink)' '
+       ! git cat-file --textconv HEAD:symlink.bin 2>result &&
+       cat >expected <<EOF &&
+fatal: git cat-file --textconv: unable to run textconv on HEAD:symlink.bin
+EOF
+       test_cmp expected result
+'
+
 test_done
index 71b3df9b55d7009def5ea11ff519cae4f28dea6d..d1ba25205b86c3a4aeca16ec988e2ed2ecca1da2 100755 (executable)
@@ -201,10 +201,28 @@ test_expect_success $PREREQ 'Prompting works' '
                grep "^To: to@example.com\$" msgtxt1
 '
 
+test_expect_success $PREREQ 'tocmd works' '
+       clean_fake_sendmail &&
+       cp $patches tocmd.patch &&
+       echo tocmd--tocmd@example.com >>tocmd.patch &&
+       {
+         echo "#!$SHELL_PATH"
+         echo sed -n -e s/^tocmd--//p \"\$1\"
+       } > tocmd-sed &&
+       chmod +x tocmd-sed &&
+       git send-email \
+               --from="Example <nobody@example.com>" \
+               --to-cmd=./tocmd-sed \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               tocmd.patch \
+               &&
+       grep "^To: tocmd@example.com" msgtxt1
+'
+
 test_expect_success $PREREQ 'cccmd works' '
        clean_fake_sendmail &&
        cp $patches cccmd.patch &&
-       echo cccmd--cccmd@example.com >>cccmd.patch &&
+       echo "cccmd--  cccmd@example.com" >>cccmd.patch &&
        {
          echo "#!$SHELL_PATH"
          echo sed -n -e s/^cccmd--//p \"\$1\"
@@ -279,7 +297,7 @@ test_expect_success $PREREQ 'Invalid In-Reply-To' '
                --to=nobody@example.com \
                --in-reply-to=" " \
                --smtp-server="$(pwd)/fake.sendmail" \
-               $patches
+               $patches \
                2>errors
        ! grep "^In-Reply-To: < *>" msgtxt1
 '
@@ -947,6 +965,45 @@ test_expect_success $PREREQ '--no-bcc overrides sendemail.bcc' '
        ! grep "RCPT TO:<other@ex.com>" stdout
 '
 
+test_expect_success $PREREQ 'patches To headers are used by default' '
+       patch=`git format-patch -1 --to="bodies@example.com"` &&
+       test_when_finished "rm $patch" &&
+       git send-email \
+               --dry-run \
+               --from="Example <nobody@example.com>" \
+               --smtp-server relay.example.com \
+               $patch >stdout &&
+       grep "RCPT TO:<bodies@example.com>" stdout
+'
+
+test_expect_success $PREREQ 'patches To headers are appended to' '
+       patch=`git format-patch -1 --to="bodies@example.com"` &&
+       test_when_finished "rm $patch" &&
+       git send-email \
+               --dry-run \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --smtp-server relay.example.com \
+               $patch >stdout &&
+       grep "RCPT TO:<bodies@example.com>" stdout &&
+       grep "RCPT TO:<nobody@example.com>" stdout
+'
+
+test_expect_success $PREREQ 'To headers from files reset each patch' '
+       patch1=`git format-patch -1 --to="bodies@example.com"` &&
+       patch2=`git format-patch -1 --to="other@example.com" HEAD~` &&
+       test_when_finished "rm $patch1 && rm $patch2" &&
+       git send-email \
+               --dry-run \
+               --from="Example <nobody@example.com>" \
+               --to="nobody@example.com" \
+               --smtp-server relay.example.com \
+               $patch1 $patch2 >stdout &&
+       test $(grep -c "RCPT TO:<bodies@example.com>" stdout) = 1 &&
+       test $(grep -c "RCPT TO:<nobody@example.com>" stdout) = 2 &&
+       test $(grep -c "RCPT TO:<other@example.com>" stdout) = 1
+'
+
 test_expect_success $PREREQ 'setup expect' '
 cat >email-using-8bit <<EOF
 From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
@@ -1032,4 +1089,40 @@ test_expect_success $PREREQ '--8bit-encoding also treats subject' '
        test_cmp expected actual
 '
 
+# 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' '
+       clean_fake_sendmail &&
+       rm -fr outdir &&
+       git format-patch --cover-letter -2 -o outdir &&
+       test_must_fail git send-email \
+         --from="Example <nobody@example.com>" \
+         --to=nobody@example.com \
+         --smtp-server="$(pwd)/fake.sendmail" \
+         outdir/0002-*.patch \
+         outdir/0000-*.patch \
+         outdir/0001-*.patch \
+         2>errors >out &&
+       grep "SUBJECT HERE" errors &&
+       test -z "$(ls msgtxt*)"
+'
+
+test_expect_success '--force sends cover letter template anyway' '
+       clean_fake_sendmail &&
+       rm -fr outdir &&
+       git format-patch --cover-letter -2 -o outdir &&
+       git send-email \
+         --force \
+         --from="Example <nobody@example.com>" \
+         --to=nobody@example.com \
+         --smtp-server="$(pwd)/fake.sendmail" \
+         outdir/0002-*.patch \
+         outdir/0000-*.patch \
+         outdir/0001-*.patch \
+         2>errors >out &&
+       ! grep "SUBJECT HERE" errors &&
+       test -n "$(ls msgtxt*)"
+'
+
 test_done
index 2f458f7a999a69c623052898726567b9d7ce67c9..b041516a1d6316dd36657b582c15100c0a7359d0 100755 (executable)
@@ -143,7 +143,7 @@ test_expect_success "$name" '
        git svn set-tree --find-copies-harder --rmdir \
                ${remotes_git_svn}..mybranch5 &&
        svn_cmd up "$SVN_TREE" &&
-       test -L "$SVN_TREE"/exec.sh'
+       test -h "$SVN_TREE"/exec.sh'
 
 name='new symlink is added to a file that was also just made executable'
 
@@ -156,7 +156,7 @@ test_expect_success "$name" '
                ${remotes_git_svn}..mybranch5 &&
        svn_cmd up "$SVN_TREE" &&
        test -x "$SVN_TREE"/bar/zzz &&
-       test -L "$SVN_TREE"/exec-2.sh'
+       test -h "$SVN_TREE"/exec-2.sh'
 
 name='modify a symlink to become a file'
 test_expect_success "$name" '
@@ -169,7 +169,7 @@ test_expect_success "$name" '
                ${remotes_git_svn}..mybranch5 &&
        svn_cmd up "$SVN_TREE" &&
        test -f "$SVN_TREE"/exec-2.sh &&
-       test ! -L "$SVN_TREE"/exec-2.sh &&
+       test ! -h "$SVN_TREE"/exec-2.sh &&
        test_cmp help "$SVN_TREE"/exec-2.sh'
 
 name="commit with UTF-8 message: locale: $GIT_SVN_LC_ALL"
index 9a24a65b64111b4540db28315fedd4efd3b19ae7..f762038f0ea95ce0f9d411ff6f494088ee1fc22c 100755 (executable)
@@ -88,7 +88,7 @@ test_expect_success 'enable broken symlink workaround' \
 test_expect_success '"bar" is an empty file' 'test -f x/bar && ! test -s x/bar'
 test_expect_success 'get "bar" => symlink fix from svn' \
                '(cd x && git svn rebase)'
-test_expect_success SYMLINKS '"bar" becomes a symlink' 'test -L x/bar'
+test_expect_success SYMLINKS '"bar" becomes a symlink' 'test -h x/bar'
 
 
 test_expect_success 'clone using git svn' 'git svn clone -r1 "$svnrepo" y'
diff --git a/t/t9157-git-svn-fetch-merge.sh b/t/t9157-git-svn-fetch-merge.sh
new file mode 100755 (executable)
index 0000000..da582c5
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 Steven Walter
+#
+
+test_description='git svn merge detection'
+. ./lib-git-svn.sh
+
+test_expect_success 'initialize source svn repo' '
+       svn_cmd mkdir -m x "$svnrepo"/trunk &&
+       svn_cmd mkdir -m x "$svnrepo"/branches &&
+       svn_cmd co "$svnrepo"/trunk "$SVN_TREE" &&
+       (
+               cd "$SVN_TREE" &&
+               touch foo &&
+               svn add foo &&
+               svn commit -m "initial commit" &&
+               svn cp -m branch "$svnrepo"/trunk "$svnrepo"/branches/branch1 &&
+               touch bar &&
+               svn add bar &&
+               svn commit -m x &&
+               svn cp -m branch "$svnrepo"/trunk "$svnrepo"/branches/branch2 &&
+               svn switch "$svnrepo"/branches/branch1 &&
+               touch baz &&
+               svn add baz &&
+               svn commit -m x &&
+               svn switch "$svnrepo"/trunk &&
+               svn merge "$svnrepo"/branches/branch1 &&
+               svn commit -m "merge" &&
+               svn switch "$svnrepo"/branches/branch1 &&
+               svn commit -m x &&
+               svn switch "$svnrepo"/branches/branch2 &&
+               svn merge "$svnrepo"/branches/branch1 &&
+               svn commit -m "merge branch1" &&
+               svn switch "$svnrepo"/trunk &&
+               svn merge "$svnrepo"/branches/branch2 &&
+               svn resolved baz &&
+               svn commit -m "merge branch2"
+       ) &&
+       rm -rf "$SVN_TREE"
+'
+
+test_expect_success 'clone svn repo' '
+       git svn init -s "$svnrepo" &&
+       git svn fetch
+'
+
+test_expect_success 'verify merge commit' 'git rev-parse HEAD^2'
+
+test_done
index 7c059204e90722db20bae1d10a0988853f852262..3c0cf0509d2cfe3afc0316ed50ea85cb0d2d14de 100755 (executable)
@@ -874,6 +874,27 @@ test_expect_success \
         git diff-tree -C --find-copies-harder -r N4^ N4 >actual &&
         compare_diff_raw expect actual'
 
+test_expect_success \
+       'N: copy root directory by tree hash' \
+       'cat >expect <<-\EOF &&
+       :100755 000000 f1fb5da718392694d0076d677d6d0e364c79b0bc 0000000000000000000000000000000000000000 D      file3/newf
+       :100644 000000 7123f7f44e39be127c5eb701e5968176ee9d78b1 0000000000000000000000000000000000000000 D      file3/oldf
+       EOF
+        root=$(git rev-parse refs/heads/branch^0^{tree}) &&
+        cat >input <<-INPUT_END &&
+       commit refs/heads/N6
+       committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+       data <<COMMIT
+       copy root directory by tree hash
+       COMMIT
+
+       from refs/heads/branch^0
+       M 040000 $root ""
+       INPUT_END
+        git fast-import <input &&
+        git diff-tree -C --find-copies-harder -r N4 N6 >actual &&
+        compare_diff_raw expect actual'
+
 test_expect_success \
        'N: modify copied tree' \
        'cat >expect <<-\EOF &&
index 4f2b9b062b08302aedab42dcdd0a33776559c05e..21cd286bb7abf33c944a8758ce8d702e83ca2022 100755 (executable)
@@ -650,25 +650,26 @@ test_debug 'cat gitweb.log'
 # ----------------------------------------------------------------------
 # syntax highlighting
 
-cat >>gitweb_config.perl <<\EOF
-$feature{'highlight'}{'override'} = 1;
-EOF
 
 highlight --version >/dev/null 2>&1
 if [ $? -eq 127 ]; then
        say "Skipping syntax highlighting test, because 'highlight' was not found"
 else
        test_set_prereq HIGHLIGHT
+       cat >>gitweb_config.perl <<-\EOF
+       our $highlight_bin = "highlight";
+       $feature{'highlight'}{'override'} = 1;
+       EOF
 fi
 
 test_expect_success HIGHLIGHT \
-       'syntax highlighting (no 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)' \
+       'syntax highlighting (highlighted, shell script)' \
        'git config gitweb.highlight yes &&
         echo "#!/usr/bin/sh" > test.sh &&
         git add test.sh &&
index 671f38db2bb78c076b281602ca5b87f10fdf4d00..c15ca2d6479a814d7649a38a671a554b6ed8b68f 100755 (executable)
@@ -1,7 +1,7 @@
 #!/usr/bin/perl
 use lib (split(/:/, $ENV{GITPERLLIB}));
 
-use 5.006002;
+use 5.008;
 use warnings;
 use strict;
 
index 830e5e7360350a424a2fe6016a03c913209f7557..744f4364c2b41724e9c395c386fd8048338a2435 100644 (file)
@@ -248,6 +248,10 @@ test_decode_color () {
                -e 's/.\[m/<RESET>/g'
 }
 
+nul_to_q () {
+       perl -pe 'y/\000/Q/'
+}
+
 q_to_nul () {
        perl -pe 'y/Q/\000/'
 }
@@ -362,6 +366,15 @@ test_have_prereq () {
        test $total_prereq = $ok_prereq
 }
 
+test_declared_prereq () {
+       case ",$test_prereq," in
+       *,$1,*)
+               return 0
+               ;;
+       esac
+       return 1
+}
+
 # You are not expected to call test_ok_ and test_failure_ directly, use
 # the text_expect_* functions instead.
 
@@ -414,17 +427,17 @@ test_skip () {
                        break
                esac
        done
-       if test -z "$to_skip" && test -n "$prereq" &&
-          ! test_have_prereq "$prereq"
+       if test -z "$to_skip" && test -n "$test_prereq" &&
+          ! test_have_prereq "$test_prereq"
        then
                to_skip=t
        fi
        case "$to_skip" in
        t)
                of_prereq=
-               if test "$missing_prereq" != "$prereq"
+               if test "$missing_prereq" != "$test_prereq"
                then
-                       of_prereq=" of $prereq"
+                       of_prereq=" of $test_prereq"
                fi
 
                say_color skip >&3 "skipping test: $@"
@@ -438,9 +451,10 @@ test_skip () {
 }
 
 test_expect_failure () {
-       test "$#" = 3 && { prereq=$1; shift; } || prereq=
+       test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
        test "$#" = 2 ||
        error "bug in the test script: not 2 or 3 parameters to test-expect-failure"
+       export test_prereq
        if ! test_skip "$@"
        then
                say >&3 "checking known breakage: $2"
@@ -456,9 +470,10 @@ test_expect_failure () {
 }
 
 test_expect_success () {
-       test "$#" = 3 && { prereq=$1; shift; } || prereq=
+       test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
        test "$#" = 2 ||
        error "bug in the test script: not 2 or 3 parameters to test-expect-success"
+       export test_prereq
        if ! test_skip "$@"
        then
                say >&3 "expecting success: $2"
@@ -500,11 +515,12 @@ test_expect_code () {
 # Usage: test_external description command arguments...
 # Example: test_external 'Perl API' perl ../path/to/test.pl
 test_external () {
-       test "$#" = 4 && { prereq=$1; shift; } || prereq=
+       test "$#" = 4 && { test_prereq=$1; shift; } || test_prereq=
        test "$#" = 3 ||
        error >&5 "bug in the test script: not 3 or 4 parameters to test_external"
        descr="$1"
        shift
+       export test_prereq
        if ! test_skip "$descr" "$@"
        then
                # Announce the script to reduce confusion about the
@@ -970,11 +986,13 @@ case $(uname -s) in
        # no POSIX permissions
        # backslashes in pathspec are converted to '/'
        # exec does not inherit the PID
+       test_set_prereq MINGW
        ;;
 *)
        test_set_prereq POSIXPERM
        test_set_prereq BSLASHPSPEC
        test_set_prereq EXECKEEPSPID
+       test_set_prereq NOT_MINGW
        ;;
 esac
 
diff --git a/t/test-terminal.perl b/t/test-terminal.perl
new file mode 100755 (executable)
index 0000000..ee01eb9
--- /dev/null
@@ -0,0 +1,76 @@
+#!/usr/bin/perl
+use 5.008;
+use strict;
+use warnings;
+use IO::Pty;
+use File::Copy;
+
+# Run @$argv in the background with stdio redirected to $out and $err.
+sub start_child {
+       my ($argv, $out, $err) = @_;
+       my $pid = fork;
+       if (not defined $pid) {
+               die "fork failed: $!"
+       } elsif ($pid == 0) {
+               open STDOUT, ">&", $out;
+               open STDERR, ">&", $err;
+               close $out;
+               exec(@$argv) or die "cannot exec '$argv->[0]': $!"
+       }
+       return $pid;
+}
+
+# Wait for $pid to finish.
+sub finish_child {
+       # Simplified from wait_or_whine() in run-command.c.
+       my ($pid) = @_;
+
+       my $waiting = waitpid($pid, 0);
+       if ($waiting < 0) {
+               die "waitpid failed: $!";
+       } elsif ($? & 127) {
+               my $code = $? & 127;
+               warn "died of signal $code";
+               return $code - 128;
+       } else {
+               return $? >> 8;
+       }
+}
+
+sub xsendfile {
+       my ($out, $in) = @_;
+
+       # Note: the real sendfile() cannot read from a terminal.
+
+       # It is unspecified by POSIX whether reads
+       # from a disconnected terminal will return
+       # EIO (as in AIX 4.x, IRIX, and Linux) or
+       # end-of-file.  Either is fine.
+       copy($in, $out, 4096) or $!{EIO} or die "cannot copy from child: $!";
+}
+
+sub copy_stdio {
+       my ($out, $err) = @_;
+       my $pid = fork;
+       defined $pid or die "fork failed: $!";
+       if (!$pid) {
+               close($out);
+               xsendfile(\*STDERR, $err);
+               exit 0;
+       }
+       close($err);
+       xsendfile(\*STDOUT, $out);
+       finish_child($pid) == 0
+               or exit 1;
+}
+
+if ($#ARGV < 1) {
+       die "usage: test-terminal program args";
+}
+my $master_out = new IO::Pty;
+my $master_err = new IO::Pty;
+my $pid = start_child(\@ARGV, $master_out->slave, $master_err->slave);
+close $master_out->slave;
+close $master_err->slave;
+copy_stdio($master_out, $master_err);
+exit(finish_child($pid));
index 4dba6f8815a80093a8ac9edc226d99bba1bb6394..00786606117feea4b33b7e632b8ff8a3c26de4e4 100644 (file)
@@ -789,6 +789,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
        args.use_thin_pack = data->options.thin;
        args.verbose = (transport->verbose > 0);
        args.quiet = (transport->verbose < 0);
+       args.progress = transport->progress;
        args.dry_run = !!(flags & TRANSPORT_PUSH_DRY_RUN);
        args.porcelain = !!(flags & TRANSPORT_PUSH_PORCELAIN);
 
index cd659c6fe447b6fcdedee2843113feb358f23849..12c9a88884ec3bb70a1744e44235c578a44e08e6 100644 (file)
@@ -85,6 +85,8 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const
 /*
  * 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
@@ -101,7 +103,7 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int
        int never_interesting = -1;
 
        if (!opt->nr_paths)
-               return 1;
+               return 2;
 
        sha1 = tree_entry_extract(desc, &path, &mode);
 
@@ -257,19 +259,12 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree
        }
 }
 
-static void skip_uninteresting(struct tree_desc *t, const char *base, int baselen, struct diff_options *opt)
+static void skip_uninteresting(struct tree_desc *t, const char *base, int baselen, struct diff_options *opt, int *all_interesting)
 {
-       int all_interesting = 0;
        while (t->size) {
-               int show;
-
-               if (all_interesting)
-                       show = 1;
-               else {
-                       show = tree_entry_interesting(t, base, baselen, opt);
-                       if (show == 2)
-                               all_interesting = 1;
-               }
+               int show = tree_entry_interesting(t, base, baselen, opt);
+               if (show == 2)
+                       *all_interesting = 1;
                if (!show) {
                        update_tree_entry(t);
                        continue;
@@ -284,14 +279,20 @@ 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 baselen = strlen(base);
+       int all_t1_interesting = 0;
+       int all_t2_interesting = 0;
 
        for (;;) {
                if (DIFF_OPT_TST(opt, QUICK) &&
                    DIFF_OPT_TST(opt, HAS_CHANGES))
                        break;
                if (opt->nr_paths) {
-                       skip_uninteresting(t1, base, baselen, opt);
-                       skip_uninteresting(t2, base, baselen, opt);
+                       if (!all_t1_interesting)
+                               skip_uninteresting(t1, base, baselen, opt,
+                                                  &all_t1_interesting);
+                       if (!all_t2_interesting)
+                               skip_uninteresting(t2, base, baselen, opt,
+                                                  &all_t2_interesting);
                }
                if (!t1->size) {
                        if (!t2->size)
index 92f9530c6572a212c12ac917d774736286325e52..f05e4229d0d3a3ed34b4bba6636f4d333c74dc22 100644 (file)
@@ -11,7 +11,7 @@
 #include "list-objects.h"
 #include "run-command.h"
 
-static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=nn] <dir>";
+static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=<n>] <dir>";
 
 /* bits #0..7 in revision.h, #8..10 in commit.c */
 #define THEY_HAVE      (1u << 11)
index e5522159b362811346b4306246391e960a4e7041..f9e05b548c2fdbc349a1d47d81619e266ec9fb83 100644 (file)
@@ -9,7 +9,23 @@ static int drivers_alloc;
 
 #define PATTERNS(name, pattern, word_regex)                    \
        { name, NULL, -1, { pattern, REG_EXTENDED }, word_regex }
+#define IPATTERN(name, pattern, word_regex)                    \
+       { name, NULL, -1, { pattern, REG_EXTENDED | REG_ICASE }, word_regex }
 static struct userdiff_driver builtin_drivers[] = {
+IPATTERN("fortran",
+        "!^([C*]|[ \t]*!)\n"
+        "!^[ \t]*MODULE[ \t]+PROCEDURE[ \t]\n"
+        "^[ \t]*((END[ \t]+)?(PROGRAM|MODULE|BLOCK[ \t]+DATA"
+               "|([^'\" \t]+[ \t]+)*(SUBROUTINE|FUNCTION))[ \t]+[A-Z].*)$",
+        /* -- */
+        "[a-zA-Z][a-zA-Z0-9_]*"
+        "|\\.([Ee][Qq]|[Nn][Ee]|[Gg][TtEe]|[Ll][TtEe]|[Tt][Rr][Uu][Ee]|[Ff][Aa][Ll][Ss][Ee]|[Aa][Nn][Dd]|[Oo][Rr]|[Nn]?[Ee][Qq][Vv]|[Nn][Oo][Tt])\\."
+        /* numbers and format statements like 2E14.4, or ES12.6, 9X.
+         * 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]+"),
 PATTERNS("java",
@@ -101,6 +117,7 @@ PATTERNS("csharp",
 { "default", NULL, -1, { NULL, 0 } },
 };
 #undef PATTERNS
+#undef IPATTERN
 
 static struct userdiff_driver driver_true = {
        "diff=true",
index 54b6b03b9cc4e168e6b6429679b61dc2a1d5197b..fc2438f60b0e0e87772db2a9f3e407f351bb03d0 100644 (file)
@@ -390,11 +390,9 @@ static void wt_status_collect_untracked(struct wt_status *s)
        fill_directory(&dir, s->pathspec);
        for (i = 0; i < dir.nr; i++) {
                struct dir_entry *ent = dir.entries[i];
-               if (!cache_name_is_other(ent->name, ent->len))
-                       continue;
-               if (!match_pathspec(s->pathspec, ent->name, ent->len, 0, NULL))
-                       continue;
-               string_list_insert(&s->untracked, ent->name);
+               if (cache_name_is_other(ent->name, ent->len) &&
+                   match_pathspec(s->pathspec, ent->name, ent->len, 0, NULL))
+                       string_list_insert(&s->untracked, ent->name);
                free(ent);
        }
 
@@ -404,11 +402,9 @@ static void wt_status_collect_untracked(struct wt_status *s)
                fill_directory(&dir, s->pathspec);
                for (i = 0; i < dir.nr; i++) {
                        struct dir_entry *ent = dir.entries[i];
-                       if (!cache_name_is_other(ent->name, ent->len))
-                               continue;
-                       if (!match_pathspec(s->pathspec, ent->name, ent->len, 0, NULL))
-                               continue;
-                       string_list_insert(&s->ignored, ent->name);
+                       if (cache_name_is_other(ent->name, ent->len) &&
+                           match_pathspec(s->pathspec, ent->name, ent->len, 0, NULL))
+                               string_list_insert(&s->ignored, ent->name);
                        free(ent);
                }
        }
index c4bedf0d1ce1252563d7f36da7d846f5943343b0..277e2eec5b4cced5882f37ac42af7f22efe92902 100644 (file)
@@ -85,27 +85,6 @@ static long def_ff(const char *rec, long len, char *buf, long sz, void *priv)
        return -1;
 }
 
-static void xdl_find_func(xdfile_t *xf, long i, char *buf, long sz, long *ll,
-               find_func_t ff, void *ff_priv) {
-
-       /*
-        * Be quite stupid about this for now.  Find a line in the old file
-        * before the start of the hunk (and context) which starts with a
-        * plausible character.
-        */
-
-       const char *rec;
-       long len;
-
-       while (i-- > 0) {
-               len = xdl_get_rec(xf, i, &rec);
-               if ((*ll = ff(rec, len, buf, sz, ff_priv)) >= 0)
-                       return;
-       }
-       *ll = 0;
-}
-
-
 static int xdl_emit_common(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
                            xdemitconf_t const *xecfg) {
        xdfile_t *xdf = &xe->xdf1;
@@ -127,6 +106,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
        xdchange_t *xch, *xche;
        char funcbuf[80];
        long funclen = 0;
+       long funclineprev = -1;
        find_func_t ff = xecfg->find_func ?  xecfg->find_func : def_ff;
 
        if (xecfg->flags & XDL_EMIT_COMMON)
@@ -150,9 +130,19 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
                 */
 
                if (xecfg->flags & XDL_EMIT_FUNCNAMES) {
-                       xdl_find_func(&xe->xdf1, s1, funcbuf,
-                                     sizeof(funcbuf), &funclen,
-                                     ff, xecfg->find_func_priv);
+                       long l;
+                       for (l = s1 - 1; l >= 0 && l > funclineprev; l--) {
+                               const char *rec;
+                               long reclen = xdl_get_rec(&xe->xdf1, l, &rec);
+                               long newfunclen = ff(rec, reclen, funcbuf,
+                                                    sizeof(funcbuf),
+                                                    xecfg->find_func_priv);
+                               if (newfunclen >= 0) {
+                                       funclen = newfunclen;
+                                       break;
+                               }
+                       }
+                       funclineprev = s1 - 1;
                }
                if (xdl_emit_hunk_hdr(s1 + 1, e1 - s1, s2 + 1, e2 - s2,
                                      funcbuf, funclen, ecb) < 0)
index 8ef232cfad12d706aaafe705bf16c546f3597182..165a895a93e04b33ca7c8f3839ee85e0eccb4a07 100644 (file)
@@ -30,6 +30,7 @@
 #define XDL_MAX(a, b) ((a) > (b) ? (a): (b))
 #define XDL_ABS(v) ((v) >= 0 ? (v): -(v))
 #define XDL_ISDIGIT(c) ((c) >= '0' && (c) <= '9')
+#define XDL_ISSPACE(c) (isspace((unsigned char)(c)))
 #define XDL_ADDBITS(v,b)       ((v) + ((v) >> (b)))
 #define XDL_MASKBITS(b)                ((1UL << (b)) - 1)
 #define XDL_HASHLONG(v,b)      (XDL_ADDBITS((unsigned long)(v), b) & XDL_MASKBITS(b))
index 6d6fc1bc5e01be7305ec5101f43645a1dce69bd3..9e13b25abc90350de4488276074dc282edc216b1 100644 (file)
@@ -336,7 +336,7 @@ static int xdl_refine_conflicts(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m,
 static int line_contains_alnum(const char *ptr, long size)
 {
        while (size--)
-               if (isalnum(*(ptr++)))
+               if (isalnum((unsigned char)*(ptr++)))
                        return 1;
        return 0;
 }
index 22f9bd692c2706136b4938bbcb2e0fc3dab212b8..ab6503460f760356a393a3c7b3b8438213e1ee94 100644 (file)
@@ -211,18 +211,18 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
                        if (l1[i1++] != l2[i2++])
                                return 0;
                skip_ws:
-                       while (i1 < s1 && isspace(l1[i1]))
+                       while (i1 < s1 && XDL_ISSPACE(l1[i1]))
                                i1++;
-                       while (i2 < s2 && isspace(l2[i2]))
+                       while (i2 < s2 && XDL_ISSPACE(l2[i2]))
                                i2++;
                }
        } else if (flags & XDF_IGNORE_WHITESPACE_CHANGE) {
                while (i1 < s1 && i2 < s2) {
-                       if (isspace(l1[i1]) && isspace(l2[i2])) {
+                       if (XDL_ISSPACE(l1[i1]) && XDL_ISSPACE(l2[i2])) {
                                /* Skip matching spaces and try again */
-                               while (i1 < s1 && isspace(l1[i1]))
+                               while (i1 < s1 && XDL_ISSPACE(l1[i1]))
                                        i1++;
-                               while (i2 < s2 && isspace(l2[i2]))
+                               while (i2 < s2 && XDL_ISSPACE(l2[i2]))
                                        i2++;
                                continue;
                        }
@@ -241,13 +241,13 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
         * while there still are characters remaining on both lines.
         */
        if (i1 < s1) {
-               while (i1 < s1 && isspace(l1[i1]))
+               while (i1 < s1 && XDL_ISSPACE(l1[i1]))
                        i1++;
                if (s1 != i1)
                        return 0;
        }
        if (i2 < s2) {
-               while (i2 < s2 && isspace(l2[i2]))
+               while (i2 < s2 && XDL_ISSPACE(l2[i2]))
                        i2++;
                return (s2 == i2);
        }
@@ -260,10 +260,10 @@ static unsigned long xdl_hash_record_with_whitespace(char const **data,
        char const *ptr = *data;
 
        for (; ptr < top && *ptr != '\n'; ptr++) {
-               if (isspace(*ptr)) {
+               if (XDL_ISSPACE(*ptr)) {
                        const char *ptr2 = ptr;
                        int at_eol;
-                       while (ptr + 1 < top && isspace(ptr[1])
+                       while (ptr + 1 < top && XDL_ISSPACE(ptr[1])
                                        && ptr[1] != '\n')
                                ptr++;
                        at_eol = (top <= ptr + 1 || ptr[1] == '\n');