aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap2
-rw-r--r--Documentation/CodingGuidelines25
-rw-r--r--Documentation/RelNotes/1.7.3.1.txt14
-rw-r--r--Documentation/RelNotes/1.7.3.2.txt5
-rw-r--r--Documentation/RelNotes/1.7.4.txt54
-rw-r--r--Documentation/SubmittingPatches21
-rw-r--r--Documentation/config.txt25
-rw-r--r--Documentation/diff-generate-patch.txt40
-rw-r--r--Documentation/diff-options.txt45
-rw-r--r--Documentation/git-am.txt4
-rw-r--r--Documentation/git-apply.txt6
-rw-r--r--Documentation/git-archimport.txt2
-rw-r--r--Documentation/git-archive.txt4
-rw-r--r--Documentation/git-bundle.txt6
-rw-r--r--Documentation/git-cat-file.txt2
-rw-r--r--Documentation/git-check-ref-format.txt2
-rw-r--r--Documentation/git-checkout-index.txt2
-rw-r--r--Documentation/git-checkout.txt16
-rw-r--r--Documentation/git-cherry-pick.txt2
-rw-r--r--Documentation/git-clone.txt7
-rw-r--r--Documentation/git-commit-tree.txt2
-rw-r--r--Documentation/git-cvsexportcommit.txt4
-rw-r--r--Documentation/git-cvsserver.txt4
-rw-r--r--Documentation/git-daemon.txt49
-rw-r--r--Documentation/git-diff.txt23
-rw-r--r--Documentation/git-fast-export.txt2
-rw-r--r--Documentation/git-fast-import.txt5
-rw-r--r--Documentation/git-fetch.txt2
-rw-r--r--Documentation/git-filter-branch.txt4
-rw-r--r--Documentation/git-fmt-merge-msg.txt16
-rw-r--r--Documentation/git-for-each-ref.txt2
-rw-r--r--Documentation/git-format-patch.txt4
-rw-r--r--Documentation/git-index-pack.txt4
-rw-r--r--Documentation/git-init.txt2
-rw-r--r--Documentation/git-log.txt2
-rw-r--r--Documentation/git-ls-files.txt2
-rw-r--r--Documentation/git-ls-tree.txt10
-rw-r--r--Documentation/git-mailsplit.txt2
-rw-r--r--Documentation/git-merge.txt14
-rw-r--r--Documentation/git-mergetool.txt2
-rw-r--r--Documentation/git-pack-objects.txt16
-rw-r--r--Documentation/git-pull.txt14
-rw-r--r--Documentation/git-push.txt2
-rw-r--r--Documentation/git-read-tree.txt6
-rw-r--r--Documentation/git-reflog.txt2
-rw-r--r--Documentation/git-relink.txt2
-rw-r--r--Documentation/git-remote.txt2
-rw-r--r--Documentation/git-repack.txt16
-rw-r--r--Documentation/git-reset.txt76
-rw-r--r--Documentation/git-rev-list.txt18
-rw-r--r--Documentation/git-rev-parse.txt2
-rw-r--r--Documentation/git-revert.txt2
-rw-r--r--Documentation/git-send-email.txt17
-rw-r--r--Documentation/git-shell.txt28
-rw-r--r--Documentation/git-shortlog.txt2
-rw-r--r--Documentation/git-show-branch.txt4
-rw-r--r--Documentation/git-show-ref.txt6
-rw-r--r--Documentation/git-show.txt6
-rw-r--r--Documentation/git-svn.txt19
-rw-r--r--Documentation/git-update-index.txt8
-rw-r--r--Documentation/git-web--browse.txt16
-rw-r--r--Documentation/git.txt18
-rw-r--r--Documentation/gitattributes.txt15
-rw-r--r--Documentation/gitcore-tutorial.txt2
-rw-r--r--Documentation/gitdiffcore.txt6
-rw-r--r--Documentation/gitk.txt2
-rw-r--r--Documentation/merge-config.txt6
-rw-r--r--Documentation/merge-options.txt6
-rw-r--r--Documentation/merge-strategies.txt28
-rw-r--r--Documentation/pretty-options.txt4
-rw-r--r--Documentation/rev-list-options.txt31
-rw-r--r--Documentation/revisions.txt4
-rw-r--r--Documentation/technical/api-merge.txt71
-rw-r--r--Documentation/technical/api-sigchain.txt41
-rw-r--r--Documentation/user-manual.txt25
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--INSTALL8
-rw-r--r--Makefile23
l---------RelNotes2
-rw-r--r--abspath.c6
-rw-r--r--archive.c4
-rw-r--r--attr.c52
-rw-r--r--builtin.h9
-rw-r--r--builtin/blame.c33
-rw-r--r--builtin/bundle.c4
-rw-r--r--builtin/cat-file.c2
-rw-r--r--builtin/checkout-index.c2
-rw-r--r--builtin/checkout.c14
-rw-r--r--builtin/clean.c8
-rw-r--r--builtin/commit-tree.c14
-rw-r--r--builtin/fetch.c2
-rw-r--r--builtin/fmt-merge-msg.c60
-rw-r--r--builtin/grep.c2
-rw-r--r--builtin/index-pack.c4
-rw-r--r--builtin/init-db.c32
-rw-r--r--builtin/log.c7
-rw-r--r--builtin/ls-files.c2
-rw-r--r--builtin/ls-tree.c2
-rw-r--r--builtin/mailsplit.c2
-rw-r--r--builtin/merge-file.c7
-rw-r--r--builtin/merge-recursive.c15
-rw-r--r--builtin/merge.c52
-rw-r--r--builtin/pack-objects.c14
-rw-r--r--builtin/read-tree.c10
-rw-r--r--builtin/remote.c2
-rw-r--r--builtin/rev-list.c14
-rw-r--r--builtin/revert.c2
-rw-r--r--builtin/send-pack.c5
-rw-r--r--builtin/show-branch.c2
-rw-r--r--builtin/unpack-objects.c2
-rw-r--r--builtin/update-index.c2
-rw-r--r--cache.h15
-rw-r--r--compat/mingw.c56
-rw-r--r--compat/mingw.h36
-rw-r--r--configure.ac10
-rw-r--r--connect.c8
-rwxr-xr-xcontrib/ciabot/ciabot.py2
-rwxr-xr-xcontrib/completion/git-completion.bash161
-rw-r--r--contrib/emacs/git-blame.el1
-rwxr-xr-xcontrib/examples/git-svnimport.perl4
-rwxr-xr-xcontrib/fast-import/git-p44
-rwxr-xr-xcontrib/fast-import/import-directories.perl3
-rw-r--r--contrib/git-shell-commands/README18
-rwxr-xr-xcontrib/git-shell-commands/help18
-rwxr-xr-xcontrib/git-shell-commands/list10
-rwxr-xr-xcontrib/hooks/post-receive-email47
-rwxr-xr-xcontrib/workdir/git-new-workdir2
-rw-r--r--daemon.c98
-rw-r--r--diff.c61
-rw-r--r--diff.h5
-rw-r--r--diffcore-pickaxe.c155
-rw-r--r--diffcore.h2
-rw-r--r--dir.c5
-rw-r--r--environment.c8
-rw-r--r--fast-import.c11
-rwxr-xr-xgit-add--interactive.perl4
-rwxr-xr-xgit-am.sh16
-rwxr-xr-xgit-archimport.perl3
-rwxr-xr-xgit-bisect.sh14
-rw-r--r--git-compat-util.h12
-rwxr-xr-xgit-cvsexportcommit.perl4
-rwxr-xr-xgit-cvsimport.perl5
-rwxr-xr-xgit-cvsserver.perl7
-rwxr-xr-xgit-difftool.perl1
-rwxr-xr-xgit-gui/git-gui.sh77
-rw-r--r--git-gui/lib/branch_rename.tcl2
-rw-r--r--git-gui/lib/diff.tcl34
-rwxr-xr-xgit-merge-octopus.sh5
-rw-r--r--git-mergetool--lib.sh26
-rwxr-xr-xgit-rebase.sh6
-rwxr-xr-xgit-relink.perl4
-rwxr-xr-xgit-repack.sh6
-rwxr-xr-xgit-send-email.perl173
-rw-r--r--git-sh-setup.sh18
-rwxr-xr-xgit-stash.sh23
-rwxr-xr-xgit-submodule.sh5
-rwxr-xr-xgit-svn.perl8
-rw-r--r--git.c8
-rw-r--r--git_remote_helpers/setup.cfg3
-rw-r--r--gitweb/Makefile16
-rw-r--r--gitweb/README11
-rwxr-xr-xgitweb/gitweb.perl27
-rw-r--r--grep.c102
-rw-r--r--grep.h2
-rw-r--r--ll-merge.c51
-rw-r--r--ll-merge.h22
-rw-r--r--merge-file.c2
-rw-r--r--merge-recursive.c58
-rw-r--r--merge-recursive.h4
-rw-r--r--perl/Git.pm1
-rw-r--r--rerere.c2
-rw-r--r--send-pack.h1
-rw-r--r--setup.c4
-rw-r--r--sha1_name.c3
-rw-r--r--shell.c133
-rw-r--r--strbuf.c2
-rw-r--r--strbuf.h2
-rw-r--r--t/Makefile14
-rw-r--r--t/README6
-rw-r--r--t/annotate-tests.sh12
-rw-r--r--t/gitweb-lib.sh31
-rw-r--r--t/lib-terminal.sh19
-rwxr-xr-xt/t0003-attributes.sh13
-rwxr-xr-xt/t0004-unwritable.sh52
-rwxr-xr-xt/t1011-read-tree-sparse-checkout.sh10
-rwxr-xr-xt/t1300-repo-config.sh6
-rwxr-xr-xt/t1503-rev-parse-verify.sh4
-rwxr-xr-xt/t1509-root-worktree.sh28
-rwxr-xr-xt/t3020-ls-files-error-unmatch.sh1
-rwxr-xr-xt/t3032-merge-recursive-options.sh186
-rwxr-xr-xt/t3402-rebase-merge.sh21
-rwxr-xr-xt/t3415-rebase-autosquash.sh6
-rwxr-xr-xt/t3419-rebase-patch-id.sh109
-rwxr-xr-xt/t3506-cherry-pick-ff.sh10
-rwxr-xr-xt/t3903-stash.sh69
-rwxr-xr-xt/t4011-diff-symlink.sh26
-rwxr-xr-xt/t4012-diff-binary.sh4
-rwxr-xr-xt/t4013-diff-various.sh3
-rw-r--r--t/t4013/diff.log_-GF_-p_--pickaxe-all_master27
-rw-r--r--t/t4013/diff.log_-GF_-p_master18
-rw-r--r--t/t4013/diff.log_-GF_master7
-rwxr-xr-xt/t4014-format-patch.sh21
-rwxr-xr-xt/t4018-diff-funcname.sh2
-rwxr-xr-xt/t4041-diff-submodule-option.sh96
-rwxr-xr-xt/t5000-tar-tree.sh2
-rwxr-xr-xt/t5503-tagfollow.sh9
-rwxr-xr-xt/t5523-push-upstream.sh44
-rwxr-xr-xt/t5560-http-backend-noserver.sh13
-rwxr-xr-xt/t556x_common4
-rwxr-xr-xt/t6006-rev-list-format.sh8
-rwxr-xr-xt/t6023-merge-file.sh8
-rwxr-xr-xt/t6038-merge-text-auto.sh4
-rwxr-xr-xt/t6050-replace.sh13
-rwxr-xr-xt/t6200-fmt-merge-msg.sh91
-rwxr-xr-xt/t7004-tag.sh20
-rwxr-xr-xt/t7006-pager.sh38
-rwxr-xr-xt/t7401-submodule-summary.sh45
-rwxr-xr-xt/t7403-submodule-sync.sh12
-rwxr-xr-xt/t7810-grep.sh29
-rwxr-xr-xt/t8006-blame-textconv.sh62
-rwxr-xr-xt/t8007-cat-file-textconv.sh38
-rwxr-xr-xt/t9001-send-email.sh97
-rwxr-xr-xt/t9100-git-svn-basic.sh6
-rwxr-xr-xt/t9131-git-svn-empty-symlink.sh2
-rwxr-xr-xt/t9157-git-svn-fetch-merge.sh50
-rwxr-xr-xt/t9300-fast-import.sh21
-rwxr-xr-xt/t9500-gitweb-standalone-no-errors.sh11
-rwxr-xr-xt/t9700/test.pl2
-rw-r--r--t/test-lib.sh32
-rwxr-xr-xt/test-terminal.perl (renamed from t/t7006/test-terminal.perl)32
-rw-r--r--transport.c1
-rw-r--r--tree-diff.c29
-rw-r--r--upload-pack.c2
-rw-r--r--userdiff.c17
-rw-r--r--wt-status.c16
-rw-r--r--xdiff/xemit.c38
-rw-r--r--xdiff/xmacros.h1
-rw-r--r--xdiff/xmerge.c2
-rw-r--r--xdiff/xutils.c18
239 files changed, 3491 insertions, 1159 deletions
diff --git a/.mailmap b/.mailmap
index a8091eb5d..19c872623 100644
--- 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>
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index b8bf618a3..09ffc4656 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -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
index 000000000..002c93b96
--- /dev/null
+++ b/Documentation/RelNotes/1.7.3.1.txt
@@ -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
index 000000000..5c93b85af
--- /dev/null
+++ b/Documentation/RelNotes/1.7.3.2.txt
@@ -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
index 000000000..05e8a43a3
--- /dev/null
+++ b/Documentation/RelNotes/1.7.4.txt
@@ -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
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index ece3c7748..72741ebda 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -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
diff --git a/Documentation/config.txt b/Documentation/config.txt
index d82c0da2c..538ebb5e2 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -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'.
diff --git a/Documentation/diff-generate-patch.txt b/Documentation/diff-generate-patch.txt
index 8f9a2412f..3ac2beac6 100644
--- a/Documentation/diff-generate-patch.txt
+++ b/Documentation/diff-generate-patch.txt
@@ -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
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 4656a97e6..f3e95389a 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -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>.
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 9e62f8778..51297d09e 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -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.
diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt
index 4a74b23d4..881652f49 100644
--- a/Documentation/git-apply.txt
+++ b/Documentation/git-apply.txt
@@ -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
diff --git a/Documentation/git-archimport.txt b/Documentation/git-archimport.txt
index 4f358c8d6..2411ce5bf 100644
--- a/Documentation/git-archimport.txt
+++ b/Documentation/git-archimport.txt
@@ -109,7 +109,7 @@ OPTIONS
Author
------
-Written by Martin Langhoff <martin@catalyst.net.nz>.
+Written by Martin Langhoff <martin@laptop.org>.
Documentation
--------------
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt
index 8d3e66626..4163a1bcb 100644
--- a/Documentation/git-archive.txt
+++ b/Documentation/git-archive.txt
@@ -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.
diff --git a/Documentation/git-bundle.txt b/Documentation/git-bundle.txt
index 38e59afb3..6266a3a60 100644
--- a/Documentation/git-bundle.txt
+++ b/Documentation/git-bundle.txt
@@ -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
diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt
index a3f56b07f..544ba7ba2 100644
--- a/Documentation/git-cat-file.txt
+++ b/Documentation/git-cat-file.txt
@@ -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
diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt
index f5c2e0601..205d83dd0 100644
--- a/Documentation/git-check-ref-format.txt
+++ b/Documentation/git-check-ref-format.txt
@@ -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
diff --git a/Documentation/git-checkout-index.txt b/Documentation/git-checkout-index.txt
index 62f9ab24c..0c0a9c14b 100644
--- a/Documentation/git-checkout-index.txt
+++ b/Documentation/git-checkout-index.txt
@@ -13,7 +13,7 @@ SYNOPSIS
[--stage=<number>|all]
[--temp]
[-z] [--stdin]
- [--] [<file>]*
+ [--] [<file>...]
DESCRIPTION
-----------
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index f88e9977d..22d36114d 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -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
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 2cef57931..3c96fa8c8 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -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].
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index dc7d3d17b..ab7293351 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -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>::
diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt
index 349366ee1..5dcf4278f 100644
--- a/Documentation/git-commit-tree.txt
+++ b/Documentation/git-commit-tree.txt
@@ -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
-----------
diff --git a/Documentation/git-cvsexportcommit.txt b/Documentation/git-cvsexportcommit.txt
index b2696efae..d25661eb2 100644
--- a/Documentation/git-cvsexportcommit.txt
+++ b/Documentation/git-cvsexportcommit.txt
@@ -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
---
diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt
index f4472c61d..70cbb2cae 100644
--- a/Documentation/git-cvsserver.txt
+++ b/Documentation/git-cvsserver.txt
@@ -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
---
diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt
index 01c9f8eb9..5054f790a 100644
--- a/Documentation/git-daemon.txt
+++ b/Documentation/git-daemon.txt
@@ -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.
diff --git a/Documentation/git-diff.txt b/Documentation/git-diff.txt
index 08fd4099a..dd1fb3278 100644
--- a/Documentation/git-diff.txt
+++ b/Documentation/git-diff.txt
@@ -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
------
diff --git a/Documentation/git-fast-export.txt b/Documentation/git-fast-export.txt
index fcad11327..e05b686b1 100644
--- a/Documentation/git-fast-export.txt
+++ b/Documentation/git-fast-export.txt
@@ -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
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index 966ba4f21..5d0c245e3 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -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),
diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt
index 400fe7f95..d159e8829 100644
--- a/Documentation/git-fetch.txt
+++ b/Documentation/git-fetch.txt
@@ -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>]
diff --git a/Documentation/git-filter-branch.txt b/Documentation/git-filter-branch.txt
index 7357c8879..796e7489f 100644
--- a/Documentation/git-filter-branch.txt
+++ b/Documentation/git-filter-branch.txt
@@ -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
diff --git a/Documentation/git-fmt-merge-msg.txt b/Documentation/git-fmt-merge-msg.txt
index 302f56b88..40dba8c0a 100644
--- a/Documentation/git-fmt-merge-msg.txt
+++ b/Documentation/git-fmt-merge-msg.txt
@@ -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
diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index d66fd9d23..fac1cf55e 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -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
-----------
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index 4b3f5ba53..9dcafc6d4 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -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>::
diff --git a/Documentation/git-index-pack.txt b/Documentation/git-index-pack.txt
index f3ccc72f0..c2bb81042 100644
--- a/Documentation/git-index-pack.txt
+++ b/Documentation/git-index-pack.txt
@@ -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.
diff --git a/Documentation/git-init.txt b/Documentation/git-init.txt
index 246b07ebf..00d4a124c 100644
--- a/Documentation/git-init.txt
+++ b/Documentation/git-init.txt
@@ -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
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index c213bdbdc..6d40f0011 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -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
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index 347f44798..86abd1345 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -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
-----------
diff --git a/Documentation/git-ls-tree.txt b/Documentation/git-ls-tree.txt
index 1f89d3680..76ed625e7 100644
--- a/Documentation/git-ls-tree.txt
+++ b/Documentation/git-ls-tree.txt
@@ -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.
diff --git a/Documentation/git-mailsplit.txt b/Documentation/git-mailsplit.txt
index a63448528..71912a19a 100644
--- a/Documentation/git-mailsplit.txt
+++ b/Documentation/git-mailsplit.txt
@@ -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
-----------
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index 84043cc5b..d43416d29 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -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::
diff --git a/Documentation/git-mergetool.txt b/Documentation/git-mergetool.txt
index e4ed01614..1f75a848b 100644
--- a/Documentation/git-mergetool.txt
+++ b/Documentation/git-mergetool.txt
@@ -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
-----------
diff --git a/Documentation/git-pack-objects.txt b/Documentation/git-pack-objects.txt
index 8ed09c0b3..65eff66af 100644
--- a/Documentation/git-pack-objects.txt
+++ b/Documentation/git-pack-objects.txt
@@ -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,
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index c50f7dcb8..e1b0bd286 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -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.
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index 020955ff5..e11660a2e 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -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
diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt
index 2e78da448..e88e9c2d5 100644
--- a/Documentation/git-read-tree.txt
+++ b/Documentation/git-read-tree.txt
@@ -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.
diff --git a/Documentation/git-reflog.txt b/Documentation/git-reflog.txt
index 5a0451aaf..e50bd9b68 100644
--- a/Documentation/git-reflog.txt
+++ b/Documentation/git-reflog.txt
@@ -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"
diff --git a/Documentation/git-relink.txt b/Documentation/git-relink.txt
index 8a5842bb9..8fc809f82 100644
--- a/Documentation/git-relink.txt
+++ b/Documentation/git-relink.txt
@@ -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
-----------
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index aa021b0cb..0d28febe1 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -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
-----------
diff --git a/Documentation/git-repack.txt b/Documentation/git-repack.txt
index 8c67d1724..27f7865b0 100644
--- a/Documentation/git-repack.txt
+++ b/Documentation/git-repack.txt
@@ -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.
diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt
index 9cf31485f..fd7297637 100644
--- a/Documentation/git-reset.txt
+++ b/Documentation/git-reset.txt
@@ -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 all, but
- 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.
diff --git a/Documentation/git-rev-list.txt b/Documentation/git-rev-list.txt
index 173f3fc78..8e1e32908 100644
--- a/Documentation/git-rev-list.txt
+++ b/Documentation/git-rev-list.txt
@@ -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 ]
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 341ca90c6..4a27643c1 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -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.
diff --git a/Documentation/git-revert.txt b/Documentation/git-revert.txt
index b7d9ef7e4..f40984d14 100644
--- a/Documentation/git-revert.txt
+++ b/Documentation/git-revert.txt
@@ -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.
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index c28308427..05904e0e7 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -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.
diff --git a/Documentation/git-shell.txt b/Documentation/git-shell.txt
index 0f3ad811c..6403126a0 100644
--- a/Documentation/git-shell.txt
+++ b/Documentation/git-shell.txt
@@ -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
------
diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt
index bc1ac7749..5cc3baf48 100644
--- a/Documentation/git-shortlog.txt
+++ b/Documentation/git-shortlog.txt
@@ -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'.
diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt
index 645326334..3b0c88271 100644
--- a/Documentation/git-show-branch.txt
+++ b/Documentation/git-show-branch.txt
@@ -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>::
diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.txt
index 4696af743..be0ec189a 100644
--- a/Documentation/git-show-ref.txt
+++ b/Documentation/git-show-ref.txt
@@ -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
------
diff --git a/Documentation/git-show.txt b/Documentation/git-show.txt
index 0002bfb04..f0a8a1aff 100644
--- a/Documentation/git-show.txt
+++ b/Documentation/git-show.txt
@@ -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
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index 4b84d08fc..139d314ba 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -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::
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index 74d1d49db..1ca56c85a 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -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.
diff --git a/Documentation/git-web--browse.txt b/Documentation/git-web--browse.txt
index e1586c78c..51e8e0af1 100644
--- a/Documentation/git-web--browse.txt
+++ b/Documentation/git-web--browse.txt
@@ -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
-----------------------
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 646e76178..0c897df6a 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -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
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index e5a27d875..c80ca5da4 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -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.
diff --git a/Documentation/gitcore-tutorial.txt b/Documentation/gitcore-tutorial.txt
index 5e9c5ebba..c27d086f6 100644
--- a/Documentation/gitcore-tutorial.txt
+++ b/Documentation/gitcore-tutorial.txt
@@ -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]
diff --git a/Documentation/gitdiffcore.txt b/Documentation/gitdiffcore.txt
index 5d91a7e5b..6af29a460 100644
--- a/Documentation/gitdiffcore.txt
+++ b/Documentation/gitdiffcore.txt
@@ -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
diff --git a/Documentation/gitk.txt b/Documentation/gitk.txt
index 05ac1c79f..e21bac4f3 100644
--- a/Documentation/gitk.txt
+++ b/Documentation/gitk.txt
@@ -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>...::
diff --git a/Documentation/merge-config.txt b/Documentation/merge-config.txt
index b72f53397..92772e7c4 100644
--- a/Documentation/merge-config.txt
+++ b/Documentation/merge-config.txt
@@ -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
diff --git a/Documentation/merge-options.txt b/Documentation/merge-options.txt
index 722d704ff..e33e0f8e1 100644
--- a/Documentation/merge-options.txt
+++ b/Documentation/merge-options.txt
@@ -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.
diff --git a/Documentation/merge-strategies.txt b/Documentation/merge-strategies.txt
index 049313d60..595a3cf1a 100644
--- a/Documentation/merge-strategies.txt
+++ b/Documentation/merge-strategies.txt
@@ -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
diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt
index 9b6f3899e..50923e2ce 100644
--- a/Documentation/pretty-options.txt
+++ b/Documentation/pretty-options.txt
@@ -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',
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index e2237ae4a..42ca05990 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -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.
diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt
index fe846f043..3d4b79c48 100644
--- a/Documentation/revisions.txt
+++ b/Documentation/revisions.txt
@@ -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
diff --git a/Documentation/technical/api-merge.txt b/Documentation/technical/api-merge.txt
index a7e050bb7..9dc1bed76 100644
--- a/Documentation/technical/api-merge.txt
+++ b/Documentation/technical/api-merge.txt
@@ -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
index 000000000..535cdff16
--- /dev/null
+++ b/Documentation/technical/api-sigchain.txt
@@ -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.
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index fecc4eb5b..fc56da677 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -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
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index ac9c4dbf2..d441d88d6 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -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 59200b730..10a1cba64 100644
--- 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.
diff --git a/Makefile b/Makefile
index b7a62cfdf..1f1ce04ed 100644
--- 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
#
diff --git a/RelNotes b/RelNotes
index 8c65931ff..b942e4994 120000
--- 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
diff --git a/abspath.c b/abspath.c
index c91a29cb2..91ca00f05 100644
--- 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;
diff --git a/archive.c b/archive.c
index edd68534f..f59afda6f 100644
--- 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 8ba606c93..6aff6951d 100644
--- 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
diff --git a/builtin.h b/builtin.h
index 0398d2474..8dd4569b3 100644
--- 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);
diff --git a/builtin/blame.c b/builtin/blame.c
index 101535448..f5fccc1f6 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -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
diff --git a/builtin/bundle.c b/builtin/bundle.c
index 80649ba0b..9b87fb9ac 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -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)
{
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 76ec3fec9..94632dbdb 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -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;
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
index a7a5ee10f..65cbee055 100644
--- a/builtin/checkout-index.c
+++ b/builtin/checkout-index.c
@@ -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
};
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 560eae171..9240fafb2 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -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"),
diff --git a/builtin/clean.c b/builtin/clean.c
index c8798f549..fb2403075 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -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++;
}
}
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
index 87f0591c2..d083795e2 100644
--- a/builtin/commit-tree.c
+++ b/builtin/commit-tree.c
@@ -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;
}
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 6fc504770..d35f000c0 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -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
};
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index e7e12eea2..78c77742b 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -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);
diff --git a/builtin/grep.c b/builtin/grep.c
index da32f3df3..3d5f6ace9 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -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
};
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 2e680d7a7..8dc5c0b54 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -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;
}
diff --git a/builtin/init-db.c b/builtin/init-db.c
index 0271285fa..9d4886c71 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -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];
diff --git a/builtin/log.c b/builtin/log.c
index eaa1ee0fa..22d12903a 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -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;
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index bb4f612b3..6a307ab78 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -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
};
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index a8187568b..f73e6bd96 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -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
};
diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 99654d022..2d4327801 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -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)
{
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index b6664d49b..6c4afb5a3 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -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",
diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c
index 78b9db76a..c33091b3e 100644
--- a/builtin/merge-recursive.c
+++ b/builtin/merge-recursive.c
@@ -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;
}
diff --git a/builtin/merge.c b/builtin/merge.c
index 5f65c0c8a..10f091b51 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -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)
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 0e8167311..f8eba53c8 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -23,15 +23,15 @@
#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;
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index 9ad1e6691..eb1e3e746 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -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)
diff --git a/builtin/remote.c b/builtin/remote.c
index 48e0a6bf2..e9a6e0925 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -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>",
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
index efe9360e2..ba27d39f9 100644
--- a/builtin/rev-list.c
+++ b/builtin/rev-list.c
@@ -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 {
diff --git a/builtin/revert.c b/builtin/revert.c
index 4b47ace36..57b51e4a0 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -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)
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 481602d8a..2cd1c40b7 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -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;
}
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index e8719aa9e..8663ccaa9 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -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
};
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
index 685566e0b..f63973c91 100644
--- a/builtin/unpack-objects.c
+++ b/builtin/unpack-objects.c
@@ -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;
}
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 3ab214d24..62d9f3f0f 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -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 2ef2fa3a5..33decd942 100644
--- 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 { \
diff --git a/compat/mingw.c b/compat/mingw.c
index f2d9e1fd9..6590f33cc 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -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)
diff --git a/compat/mingw.h b/compat/mingw.h
index 3b2477be5..83e35e833 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -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
@@ -66,6 +79,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); }
diff --git a/configure.ac b/configure.ac
index 56731c35c..cc55b6d4f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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.)
#
diff --git a/connect.c b/connect.c
index 3450cabd0..57dc20c43 100644
--- 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;
diff --git a/contrib/ciabot/ciabot.py b/contrib/ciabot/ciabot.py
index d0627e085..9775dffb5 100755
--- a/contrib/ciabot/ciabot.py
+++ b/contrib/ciabot/ciabot.py
@@ -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)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 67569901e..f71046947 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -21,6 +21,11 @@
# 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
diff --git a/contrib/emacs/git-blame.el b/contrib/emacs/git-blame.el
index 7f4c79297..d351cfb6e 100644
--- a/contrib/emacs/git-blame.el
+++ b/contrib/emacs/git-blame.el
@@ -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"
diff --git a/contrib/examples/git-svnimport.perl b/contrib/examples/git-svnimport.perl
index 4576c4a86..b09ff8f12 100755
--- a/contrib/examples/git-svnimport.perl
+++ b/contrib/examples/git-svnimport.perl
@@ -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;
diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
index c1ea643ac..04ce7e3b0 100755
--- a/contrib/fast-import/git-p4
+++ b/contrib/fast-import/git-p4
@@ -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:
diff --git a/contrib/fast-import/import-directories.perl b/contrib/fast-import/import-directories.perl
index 3a5da4ab0..7f3afa5ac 100755
--- a/contrib/fast-import/import-directories.perl
+++ b/contrib/fast-import/import-directories.perl
@@ -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
index 000000000..438463b16
--- /dev/null
+++ b/contrib/git-shell-commands/README
@@ -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
index 000000000..535770c6e
--- /dev/null
+++ b/contrib/git-shell-commands/help
@@ -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
index 000000000..6f8993882
--- /dev/null
+++ b/contrib/git-shell-commands/list
@@ -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
diff --git a/contrib/hooks/post-receive-email b/contrib/hooks/post-receive-email
index 008508643..85724bfc0 100755
--- a/contrib/hooks/post-receive-email
+++ b/contrib/hooks/post-receive-email
@@ -71,19 +71,10 @@
# ---------------------------- 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
diff --git a/contrib/workdir/git-new-workdir b/contrib/workdir/git-new-workdir
index 3ad2c0cea..75e8b2581 100755
--- a/contrib/workdir/git-new-workdir
+++ b/contrib/workdir/git-new-workdir
@@ -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."
diff --git a/daemon.c b/daemon.c
index e22a2b7fa..7ccd097e1 100644
--- 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 9a5c77c13..c248bc64c 100644
--- 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 bf2f44d84..0083d9243 100644
--- 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 */
diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c
index 929de15aa..ea03b9107 100644
--- a/diffcore-pickaxe.c
+++ b/diffcore-pickaxe.c
@@ -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);
+}
diff --git a/diffcore.h b/diffcore.h
index 8b3241ad1..b8f1fdecf 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -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 133f472a1..b2dfb69eb 100644
--- 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;
diff --git a/environment.c b/environment.c
index 2d0c31537..de5581fe5 100644
--- a/environment.c
+++ b/environment.c
@@ -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);
diff --git a/fast-import.c b/fast-import.c
index 2317b0fe7..77549ebd6 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -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)
{
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index 27fc79347..77f60fa39 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -1,6 +1,8 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
+use 5.008;
use strict;
+use warnings;
use Git;
binmode(STDOUT, ":raw");
diff --git a/git-am.sh b/git-am.sh
index e7f008c7b..df09b4284 100755
--- 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
diff --git a/git-archimport.perl b/git-archimport.perl
index 98f3ede56..bc32f18d6 100755
--- a/git-archimport.perl
+++ b/git-archimport.perl
@@ -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;
diff --git a/git-bisect.sh b/git-bisect.sh
index 6e2acb8ef..c21e33c8d 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -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 "$@" ;;
*)
diff --git a/git-compat-util.h b/git-compat-util.h
index 81883e727..2af8d3edb 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -28,6 +28,18 @@
#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
diff --git a/git-cvsexportcommit.perl b/git-cvsexportcommit.perl
index 59b672213..39a426e06 100755
--- a/git-cvsexportcommit.perl
+++ b/git-cvsexportcommit.perl
@@ -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;
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index 9e03eee45..d27abfe7f 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -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;
diff --git a/git-cvsserver.perl b/git-cvsserver.perl
index e9f3037df..1b8bff2ca 100755
--- a/git-cvsserver.perl
+++ b/git-cvsserver.perl
@@ -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>
####
####
diff --git a/git-difftool.perl b/git-difftool.perl
index adc42de87..e95e4ad97 100755
--- a/git-difftool.perl
+++ b/git-difftool.perl
@@ -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);
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh
index 4617f29c2..d3acf0d21 100755
--- a/git-gui/git-gui.sh
+++ b/git-gui/git-gui.sh
@@ -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
diff --git a/git-gui/lib/branch_rename.tcl b/git-gui/lib/branch_rename.tcl
index 63988773b..6e510ec2e 100644
--- a/git-gui/lib/branch_rename.tcl
+++ b/git-gui/lib/branch_rename.tcl
@@ -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
diff --git a/git-gui/lib/diff.tcl b/git-gui/lib/diff.tcl
index c62875027..dcf0711be 100644
--- a/git-gui/lib/diff.tcl
+++ b/git-gui/lib/diff.tcl
@@ -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
diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh
index 615753c83..8643f74cb 100755
--- a/git-merge-octopus.sh
+++ b/git-merge-octopus.sh
@@ -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"
diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh
index b5e1943b1..77d4aee20 100644
--- a/git-mergetool--lib.sh
+++ b/git-mergetool--lib.sh
@@ -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
;;
diff --git a/git-rebase.sh b/git-rebase.sh
index 3335cee70..10a238ae3 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -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=*|\
diff --git a/git-relink.perl b/git-relink.perl
index 937c69a74..e136732ce 100755
--- a/git-relink.perl
+++ b/git-relink.perl
@@ -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" .
diff --git a/git-repack.sh b/git-repack.sh
index 1eb3bca35..769baaf7e 100755
--- a/git-repack.sh
+++ b/git-repack.sh
@@ -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 ;;
diff --git a/git-send-email.perl b/git-send-email.perl
index 6dab3bf6a..f68ed5a5d 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -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;
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 613167086..ae031a137 100644
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -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
diff --git a/git-stash.sh b/git-stash.sh
index 7ce818bd1..7561b374d 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -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'
diff --git a/git-submodule.sh b/git-submodule.sh
index 9ebbab798..c291eed59 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -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)
diff --git a/git-svn.perl b/git-svn.perl
index 9b046b693..757de8216 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -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 50a14013c..0409ac9fd 100644
--- 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
index 000000000..4bff8878d
--- /dev/null
+++ b/git_remote_helpers/setup.cfg
@@ -0,0 +1,3 @@
+[build]
+build_purelib = build/lib
+build_platlib = build/lib
diff --git a/gitweb/Makefile b/gitweb/Makefile
index 2fb7c2d77..0a6ac0063 100644
--- a/gitweb/Makefile
+++ b/gitweb/Makefile
@@ -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
diff --git a/gitweb/README b/gitweb/README
index d48119879..bf3664f2b 100644
--- a/gitweb/README
+++ b/gitweb/README
@@ -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
~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index a85e2f631..679f2da3e 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -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 82fb349be..63c4280ca 100644
--- 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 efa8cff98..06621fe66 100644
--- 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
};
diff --git a/ll-merge.c b/ll-merge.c
index 6bb3095c3..007dd3e4d 100644
--- a/ll-merge.c
+++ b/ll-merge.c
@@ -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)
diff --git a/ll-merge.h b/ll-merge.h
index ff7ca87bf..244a31f55 100644
--- a/ll-merge.h
+++ b/ll-merge.h
@@ -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);
diff --git a/merge-file.c b/merge-file.c
index db4d0d50d..f7f453392 100644
--- a/merge-file.c
+++ b/merge-file.c
@@ -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;
diff --git a/merge-recursive.c b/merge-recursive.c
index c57469881..875859f68 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -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;
+}
diff --git a/merge-recursive.h b/merge-recursive.h
index 34492dbd6..c8135b0ec 100644
--- a/merge-recursive.h
+++ b/merge-recursive.h
@@ -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);
diff --git a/perl/Git.pm b/perl/Git.pm
index 6cb0dd193..205e48aa3 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -7,6 +7,7 @@ Git - Perl interface to the Git version control system
package Git;
+use 5.008;
use strict;
diff --git a/rerere.c b/rerere.c
index 861ca7c81..d26084347 100644
--- 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);
diff --git a/send-pack.h b/send-pack.h
index 60b4ba66e..05d7ab118 100644
--- a/send-pack.h
+++ b/send-pack.h
@@ -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 a3b76de2b..346ef2eb2 100644
--- 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++)
diff --git a/sha1_name.c b/sha1_name.c
index 7b7e61719..3e856b803 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -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 e4864e04d..dea4cfdd2 100644
--- 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));
+ }
}
diff --git a/strbuf.c b/strbuf.c
index bc3a0802e..65b4cf434 100644
--- 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);
}
diff --git a/strbuf.h b/strbuf.h
index fac2dbc24..675a91f93 100644
--- 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
diff --git a/t/Makefile b/t/Makefile
index c7baefb7e..73c6ec473 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -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)
diff --git a/t/README b/t/README
index a1eb7c872..c548bf1b7 100644
--- 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
diff --git a/t/annotate-tests.sh b/t/annotate-tests.sh
index 396b9653a..141b60cdc 100644
--- a/t/annotate-tests.sh
+++ b/t/annotate-tests.sh
@@ -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);
' "$@"
diff --git a/t/gitweb-lib.sh b/t/gitweb-lib.sh
index 81ef2a096..8b5b987f4 100644
--- a/t/gitweb-lib.sh
+++ b/t/gitweb-lib.sh
@@ -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
index 000000000..c383b57ed
--- /dev/null
+++ b/t/lib-terminal.sh
@@ -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
+'
diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
index de38c7f7a..e75153bde 100755
--- a/t/t0003-attributes.sh
+++ b/t/t0003-attributes.sh
@@ -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
diff --git a/t/t0004-unwritable.sh b/t/t0004-unwritable.sh
index 385b1265d..e3137d638 100755
--- a/t/t0004-unwritable.sh
+++ b/t/t0004-unwritable.sh
@@ -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
diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh
index 9a07de1a5..8008fa2d8 100755
--- a/t/t1011-read-tree-sparse-checkout.sh
+++ b/t/t1011-read-tree-sparse-checkout.sh
@@ -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 &&
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index 074f2f2e3..d0ab8ffe1 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -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 \
diff --git a/t/t1503-rev-parse-verify.sh b/t/t1503-rev-parse-verify.sh
index 100f857b1..813cc1b3e 100755
--- a/t/t1503-rev-parse-verify.sh
+++ b/t/t1503-rev-parse-verify.sh
@@ -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} &&
diff --git a/t/t1509-root-worktree.sh b/t/t1509-root-worktree.sh
index 7f60fd0b2..335420fd8 100755
--- a/t/t1509-root-worktree.sh
+++ b/t/t1509-root-worktree.sh
@@ -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
diff --git a/t/t3020-ls-files-error-unmatch.sh b/t/t3020-ls-files-error-unmatch.sh
index a7d818716..ca01053bc 100755
--- a/t/t3020-ls-files-error-unmatch.sh
+++ b/t/t3020-ls-files-error-unmatch.sh
@@ -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
index 000000000..229379755
--- /dev/null
+++ b/t/t3032-merge-recursive-options.sh
@@ -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
diff --git a/t/t3402-rebase-merge.sh b/t/t3402-rebase-merge.sh
index 2bea65634..be8c1d5ef 100755
--- a/t/t3402-rebase-merge.sh
+++ b/t/t3402-rebase-merge.sh
@@ -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
diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh
index 37cb89ab5..fd2184ce7 100755
--- a/t/t3415-rebase-autosquash.sh
+++ b/t/t3415-rebase-autosquash.sh
@@ -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
index 000000000..1aee48351
--- /dev/null
+++ b/t/t3419-rebase-patch-id.sh
@@ -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
diff --git a/t/t3506-cherry-pick-ff.sh b/t/t3506-cherry-pick-ff.sh
index e17ae712b..51ca391e4 100755
--- a/t/t3506-cherry-pick-ff.sh
+++ b/t/t3506-cherry-pick-ff.sh
@@ -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
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index a283dca25..903a122ef 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -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
diff --git a/t/t4011-diff-symlink.sh b/t/t4011-diff-symlink.sh
index 6f6948925..408a19c4c 100755
--- a/t/t4011-diff-symlink.sh
+++ b/t/t4011-diff-symlink.sh
@@ -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
diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh
index bc46563af..05ec06283 100755
--- a/t/t4012-diff-binary.sh
+++ b/t/t4012-diff-binary.sh
@@ -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
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 19857f432..9a6652058 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -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
index 000000000..d36f88098
--- /dev/null
+++ b/t/t4013/diff.log_-GF_-p_--pickaxe-all_master
@@ -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
index 000000000..9d93f2c23
--- /dev/null
+++ b/t/t4013/diff.log_-GF_-p_master
@@ -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
index 000000000..4c6708d2d
--- /dev/null
+++ b/t/t4013/diff.log_-GF_master
@@ -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
+$
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index f87434b9f..07bf6eb49 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -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 &&
diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh
index c8e19372b..0a61b57b5 100755
--- a/t/t4018-diff-funcname.sh
+++ b/t/t4018-diff-funcname.sh
@@ -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" '
diff --git a/t/t4041-diff-submodule-option.sh b/t/t4041-diff-submodule-option.sh
index 995bdfafe..bf9a7526b 100755
--- a/t/t4041-diff-submodule-option.sh
+++ b/t/t4041-diff-submodule-option.sh
@@ -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
diff --git a/t/t5000-tar-tree.sh b/t/t5000-tar-tree.sh
index 27bfba55b..cff1b3e05 100755
--- a/t/t5000-tar-tree.sh
+++ b/t/t5000-tar-tree.sh
@@ -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'
diff --git a/t/t5503-tagfollow.sh b/t/t5503-tagfollow.sh
index 8a298a655..aa0ada014 100755
--- a/t/t5503-tagfollow.sh
+++ b/t/t5503-tagfollow.sh
@@ -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:
#
diff --git a/t/t5523-push-upstream.sh b/t/t5523-push-upstream.sh
index 00da70763..c229fe68f 100755
--- a/t/t5523-push-upstream.sh
+++ b/t/t5523-push-upstream.sh
@@ -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
diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh
index 44885b850..0ad7ce07c 100755
--- a/t/t5560-http-backend-noserver.sh
+++ b/t/t5560-http-backend-noserver.sh
@@ -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
diff --git a/t/t556x_common b/t/t556x_common
index be024e551..51287d89d 100755
--- a/t/t556x_common
+++ b/t/t556x_common
@@ -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 &&
diff --git a/t/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh
index cccacd4ad..d918cc02d 100755
--- a/t/t6006-rev-list-format.sh
+++ b/t/t6006-rev-list-format.sh
@@ -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 &&
diff --git a/t/t6023-merge-file.sh b/t/t6023-merge-file.sh
index d486d7399..d9f343942 100755
--- a/t/t6023-merge-file.sh
+++ b/t/t6023-merge-file.sh
@@ -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"
diff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh
index 52d0dc4bb..460bf741b 100755
--- a/t/t6038-merge-text-auto.sh
+++ b/t/t6038-merge-text-auto.sh
@@ -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/" "$@"
}
'
diff --git a/t/t6050-replace.sh b/t/t6050-replace.sh
index c907523e7..95b180f46 100755
--- a/t/t6050-replace.sh
+++ b/t/t6050-replace.sh
@@ -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
)
'
diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh
index 71f6cad3c..9a1680692 100755
--- a/t/t6200-fmt-merge-msg.sh
+++ b/t/t6200-fmt-merge-msg.sh
@@ -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 &&
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index ac943f5ee..700b556fe 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -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
diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh
index fb744e3c4..5641b5955 100755
--- a/t/t7006-pager.sh
+++ b/t/t7006-pager.sh
@@ -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/t7401-submodule-summary.sh b/t/t7401-submodule-summary.sh
index 294584452..7d7fde057 100755
--- a/t/t7401-submodule-summary.sh
+++ b/t/t7401-submodule-summary.sh
@@ -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' "
diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh
index 02522f962..e5b19538b 100755
--- a/t/t7403-submodule-sync.sh
+++ b/t/t7403-submodule-sync.sh
@@ -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
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index 023f225a4..50658845c 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -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 &&
diff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh
index 9ad96d4d3..dbf623bce 100755
--- a/t/t8006-blame-textconv.sh
+++ b/t/t8006-blame-textconv.sh
@@ -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
diff --git a/t/t8007-cat-file-textconv.sh b/t/t8007-cat-file-textconv.sh
index 38ac05e4a..78a0085e6 100755
--- a/t/t8007-cat-file-textconv.sh
+++ b/t/t8007-cat-file-textconv.sh
@@ -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
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 71b3df9b5..d1ba25205 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -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
diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh
index 2f458f7a9..b041516a1 100755
--- a/t/t9100-git-svn-basic.sh
+++ b/t/t9100-git-svn-basic.sh
@@ -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"
diff --git a/t/t9131-git-svn-empty-symlink.sh b/t/t9131-git-svn-empty-symlink.sh
index 9a24a65b6..f762038f0 100755
--- a/t/t9131-git-svn-empty-symlink.sh
+++ b/t/t9131-git-svn-empty-symlink.sh
@@ -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
index 000000000..da582c538
--- /dev/null
+++ b/t/t9157-git-svn-fetch-merge.sh
@@ -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
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index 7c059204e..3c0cf0509 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -875,6 +875,27 @@ test_expect_success \
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 &&
:100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 C100 newdir/interesting file3/file5
diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh
index 4f2b9b062..21cd286bb 100755
--- a/t/t9500-gitweb-standalone-no-errors.sh
+++ b/t/t9500-gitweb-standalone-no-errors.sh
@@ -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 &&
diff --git a/t/t9700/test.pl b/t/t9700/test.pl
index 671f38db2..c15ca2d64 100755
--- a/t/t9700/test.pl
+++ b/t/t9700/test.pl
@@ -1,7 +1,7 @@
#!/usr/bin/perl
use lib (split(/:/, $ENV{GITPERLLIB}));
-use 5.006002;
+use 5.008;
use warnings;
use strict;
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 830e5e736..744f4364c 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -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/t7006/test-terminal.perl b/t/test-terminal.perl
index 73ff80937..ee01eb957 100755
--- a/t/t7006/test-terminal.perl
+++ b/t/test-terminal.perl
@@ -1,17 +1,19 @@
#!/usr/bin/perl
+use 5.008;
use strict;
use warnings;
use IO::Pty;
use File::Copy;
-# Run @$argv in the background with stdout redirected to $out.
+# Run @$argv in the background with stdio redirected to $out and $err.
sub start_child {
- my ($argv, $out) = @_;
+ 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]': $!"
}
@@ -47,12 +49,28 @@ sub xsendfile {
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 = new IO::Pty;
-my $slave = $master->slave;
-my $pid = start_child(\@ARGV, $slave);
-close $slave;
-xsendfile(\*STDOUT, $master);
+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));
diff --git a/transport.c b/transport.c
index 4dba6f881..007866061 100644
--- a/transport.c
+++ b/transport.c
@@ -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);
diff --git a/tree-diff.c b/tree-diff.c
index cd659c6fe..12c9a8888 100644
--- a/tree-diff.c
+++ b/tree-diff.c
@@ -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)
diff --git a/upload-pack.c b/upload-pack.c
index 92f9530c6..f05e4229d 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -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)
diff --git a/userdiff.c b/userdiff.c
index e5522159b..f9e05b548 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -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",
diff --git a/wt-status.c b/wt-status.c
index 54b6b03b9..fc2438f60 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -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);
}
}
diff --git a/xdiff/xemit.c b/xdiff/xemit.c
index c4bedf0d1..277e2eec5 100644
--- a/xdiff/xemit.c
+++ b/xdiff/xemit.c
@@ -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)
diff --git a/xdiff/xmacros.h b/xdiff/xmacros.h
index 8ef232cfa..165a895a9 100644
--- a/xdiff/xmacros.h
+++ b/xdiff/xmacros.h
@@ -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))
diff --git a/xdiff/xmerge.c b/xdiff/xmerge.c
index 6d6fc1bc5..9e13b25ab 100644
--- a/xdiff/xmerge.c
+++ b/xdiff/xmerge.c
@@ -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;
}
diff --git a/xdiff/xutils.c b/xdiff/xutils.c
index 22f9bd692..ab6503460 100644
--- a/xdiff/xutils.c
+++ b/xdiff/xutils.c
@@ -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');