summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/RelNotes-1.7.1.1.txt46
-rw-r--r--Documentation/RelNotes-1.7.2.txt89
-rw-r--r--Documentation/SubmittingPatches2
-rw-r--r--Documentation/config.txt33
-rw-r--r--Documentation/diff-options.txt7
-rw-r--r--Documentation/git-add.txt6
-rw-r--r--Documentation/git-checkout.txt4
-rw-r--r--Documentation/git-commit.txt9
-rw-r--r--Documentation/git-cvsserver.txt37
-rw-r--r--Documentation/git-log.txt42
-rw-r--r--Documentation/git-mailinfo.txt8
-rw-r--r--Documentation/git-merge.txt7
-rw-r--r--Documentation/git-notes.txt186
-rw-r--r--Documentation/git-rebase.txt4
-rw-r--r--Documentation/git-remote.txt13
-rw-r--r--Documentation/git-submodule.txt6
-rw-r--r--Documentation/git-update-index.txt2
-rw-r--r--Documentation/gitignore.txt14
-rw-r--r--Documentation/pretty-formats.txt11
-rw-r--r--Documentation/pretty-options.txt5
-rw-r--r--Makefile14
-rw-r--r--builtin.h1
-rw-r--r--builtin/blame.c4
-rw-r--r--builtin/clone.c3
-rw-r--r--builtin/commit.c20
-rw-r--r--builtin/fmt-merge-msg.c76
-rw-r--r--builtin/for-each-ref.c4
-rw-r--r--builtin/grep.c8
-rw-r--r--builtin/ls-remote.c10
-rw-r--r--builtin/merge-file.c2
-rw-r--r--builtin/merge-tree.c2
-rw-r--r--builtin/merge.c20
-rw-r--r--builtin/notes.c15
-rw-r--r--builtin/pack-objects.c6
-rw-r--r--builtin/remote.c102
-rw-r--r--builtin/rerere.c2
-rw-r--r--combine-diff.c2
-rw-r--r--compat/mingw.h2
-rw-r--r--connect.c8
-rwxr-xr-xcontrib/completion/git-completion.bash1
-rw-r--r--convert.c28
-rw-r--r--date.c3
-rw-r--r--diff.c71
-rw-r--r--dir.c9
-rw-r--r--fsck.c2
-rwxr-xr-xgit-add--interactive.perl6
-rw-r--r--git-compat-util.h5
-rwxr-xr-xgit-cvsserver.perl94
-rwxr-xr-xgit-pull.sh7
-rwxr-xr-xgit-submodule.sh2
-rwxr-xr-xgit-svn.perl7
-rwxr-xr-xgitweb/gitweb.perl81
-rw-r--r--gitweb/static/gitweb.css18
-rw-r--r--grep.c98
-rw-r--r--grep.h2
-rw-r--r--http-backend.c59
-rw-r--r--merge-file.c2
-rw-r--r--notes.c7
-rw-r--r--notes.h5
-rw-r--r--pretty.c154
-rw-r--r--remote.c2
-rw-r--r--setup.c6
-rw-r--r--sha1_file.c28
-rw-r--r--t/README6
-rw-r--r--t/lib-t6000.sh (renamed from t/t6000lib.sh)0
-rwxr-xr-xt/t0021-conversion.sh16
-rwxr-xr-xt/t1450-fsck.sh8
-rwxr-xr-xt/t1501-worktree.sh12
-rwxr-xr-xt/t2007-checkout-symlink.sh6
-rwxr-xr-xt/t2106-update-index-assume-unchanged.sh24
-rwxr-xr-xt/t3030-merge-recursive.sh29
-rwxr-xr-xt/t3306-notes-prune.sh48
-rwxr-xr-xt/t3307-notes-man.sh38
-rwxr-xr-xt/t4205-log-pretty-formats.sh74
-rwxr-xr-xt/t5505-remote.sh88
-rwxr-xr-xt/t5512-ls-remote.sh24
-rwxr-xr-xt/t5601-clone.sh12
-rwxr-xr-xt/t6002-rev-list-bisect.sh2
-rwxr-xr-xt/t6003-rev-list-topo-order.sh2
-rwxr-xr-xt/t6101-rev-parse-parents.sh2
-rwxr-xr-xt/t7008-grep-binary.sh102
-rwxr-xr-xt/t7407-submodule-foreach.sh10
-rwxr-xr-xt/t7509-commit.sh46
-rwxr-xr-xt/t7604-merge-custom-message.sh24
-rwxr-xr-xt/t9400-git-cvsserver-server.sh16
-rwxr-xr-xt/t9500-gitweb-standalone-no-errors.sh29
-rw-r--r--trace.c6
-rw-r--r--transport.c51
-rw-r--r--unpack-trees.c2
-rw-r--r--url.c118
-rw-r--r--url.h10
-rw-r--r--userdiff.c4
-rw-r--r--wrapper.c6
93 files changed, 1915 insertions, 429 deletions
diff --git a/Documentation/RelNotes-1.7.1.1.txt b/Documentation/RelNotes-1.7.1.1.txt
new file mode 100644
index 0000000000..2eef0380ea
--- /dev/null
+++ b/Documentation/RelNotes-1.7.1.1.txt
@@ -0,0 +1,46 @@
+Git v1.7.1.1 Release Notes (draft)
+==================================
+
+Fixes since v1.7.1
+------------------
+
+ * Authentication over http transport can now be made lazily, in that the
+ request can first go to a URL without username, get a 401 response and
+ then the client will ask for the username to use.
+
+ * We used to mistakenly think "../work" is a subdirectory of the current
+ directory when we are in "../work-xyz".
+
+ * The attribute mechanism now allows an entry that uses an attribute
+ macro that set/unset one attribute, immediately followed by an
+ overriding setting; this makes attribute macros much easier to use.
+
+ * "git am -3" did not show diagnosis when the patch in the message was corrupt.
+
+ * "git bundle --stdin" segfaulted.
+
+ * "git describe" did not tie-break tags that point at the same commit
+ correctly; newer ones are preferred by paying attention to the
+ tagger date now.
+
+ * "git fetch" over HTTP verifies the downloaded packfiles more robustly.
+
+ * The memory usage by "git index-pack" (run during "git fetch" and "git
+ push") got leaner.
+
+ * "GIT_DIR=foo.git git init --bare bar.git" created foo.git instead of bar.git.
+
+ * "git log --abbrev=$num --format='%h' ignored --abbrev=$num.
+
+ * "git send-email" lacked a way to specify the domainname used in the
+ EHLO/HELO exchange, causing rejected connection from picky servers.
+ It learned --smtp-domain option to solve this issue.
+
+ * "git stash" incorrectly lost paths in the working tree that were
+ previously removed from the index.
+
+ * "git status" stopped refreshing the index by mistake in 1.7.1.
+
+ * "git status" showed excess "hints" even when advice.statusHints is set to false.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes-1.7.2.txt b/Documentation/RelNotes-1.7.2.txt
index 37781b4f14..1df22be126 100644
--- a/Documentation/RelNotes-1.7.2.txt
+++ b/Documentation/RelNotes-1.7.2.txt
@@ -4,37 +4,104 @@ Git v1.7.2 Release Notes (draft)
Updates since v1.7.1
--------------------
+ * The whitespace rules used in "git apply --whitespace" and "git diff"
+ gained a new member in the family (tab-in-indent) to help projects with
+ policy to indent only with spaces.
+
+ * When working from a subdirectory, by default, git does not look for its
+ metadirectory ".git" across filesystems, primarily to help people who
+ have invocations of git in their custom PS1 prompts, as being outside
+ of a git repository would look for ".git" all the way up to the root
+ directory, and NFS mounts are often slow. DISCOVERY_ACROSS_FILESYSTEM
+ environment variable can be used to tell git not to stop at a
+ filesystem boundary.
+
+ * "git" wrapper learned "-c name=value" option to override configuration
+ variable from the command line.
+
* After "git apply --whitespace=fix" removed trailing blank lines in an
patch in a patch series, it failed to apply later patches that depend
on the presense of such blank lines.
+ * "git checkout --orphan newbranch" is similar to "-b newbranch" but
+ prepares to create a root commit that is not connected to any existing
+ commit.
+
+ * "git commit --amend" on a commit with an invalid author-name line that
+ lacks the display name didn't work (fb7749e4).
+
+ * "git cvsserver" can be told to use pserver; its password file can be
+ stored outside the repository.
+
* The output from the textconv filter used by "git diff" can be cached to
speed up their reuse.
- * "git send-email" learned --smtp-domain option to specify the domainname
- used in the EHLO/HELO exchange.
+ * "git diff --color" did not paint extended diff headers per line
+ (i.e. the coloring escape sequence didn't end at the end of line),
+ which confused "less -R".
+
+ * "git diff --word-diff=<mode>" extends the existing "--color-words"
+ option, making it more useful in color-challenged environments.
+
+ * The regexp to detect function headers used by "git diff" for PHP has
+ been enhanced for visibility modifiers (public, protected, etc.) to
+ better support PHP5.
+
+ * "git for-each-ref" learned "%(objectname:short)" that gives the object
+ name abbreviated.
+
+ * Various options to "git grep" (e.g. --count, --name-only) work better
+ with binary files.
+
+ * "git log --follow <path>" follows across copies (it used to only follow
+ renames). This may make the processing more expensive.
+
+ * "git notes prune" learned "-n" (dry-run) and "-v" options, similar to
+ what "git prune" has.
+
+ * "git patch-id" can be fed a mbox without getting confused by the
+ signature line in the format-patch output.
* "git revert" learned --strategy option to specify the merge strategy.
- * The whitespace rules used in "git apply --whitespace" and "git diff"
- gained a new member in the family (tab-in-indent) to help projects with
- policy to indent only with spaces.
+ * "git status [-s] --ignored" can be used to list ignored paths.
- * Authentication over http transport can now be made lazily, in that the
- request can first go to a URL without username, get a 401 response and
- then the client will ask for the username to use.
+ * Various "gitweb" enhancements and clean-ups, including syntax
+ highlighting.
Fixes since v1.7.1
------------------
- * In 1.7.1, "git status" stopped refreshing the index by mistake.
-
All of the fixes in v1.7.1.X maintenance series are included in this
release, unless otherwise noted.
+ * We didn't recognize timezone "Z" as a synonym for "UTC" (75b37e70).
+
+ * "git checkout" and "git rebase" overwrote paths that are marked "assume
+ unchanged" (aecda37c).
+
+ * "git clone/fetch/pull" issued an incorrect error message when a ref and
+ a symref that points to the ref were updated at the same time. This
+ obviously would update them to the same value, and should not result in
+ an error condition (7223dcaf).
+
+ * "git clone" did not configure remote.origin.url correctly for bare
+ clones (df61c889).
+
+ * "git diff" used to tell underlying xdiff machinery to work very hard to
+ minimize the output, but this often was spending too many extra cycles
+ for very little gain (582aa00).
+
+ * "git pull" accepted "--dry-run", gave it to underlying "git fetch" but
+ ignored the option itself, resulting in a bogus attempt to merge
+ unrelated commit (29609e68).
+
+ * "git reset --hard" started from a wrong directory and a working tree in
+ a nonstandard location is in use got confused (560fb6a1).
+
--
exec >/var/tmp/1
-O=v1.7.1-77-gb751157
+O=v1.7.1-336-g0925c02
echo O=$(git describe master)
git shortlog --no-merges master ^maint ^$O
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index b9204c77d3..eb53e0636e 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -547,7 +547,7 @@ Gmail
GMail does not appear to have any way to turn off line wrapping in the web
interface, so this will mangle any emails that you send. You can however
-use "git send e-mail" and send your patches through the GMail SMTP server, or
+use "git send-email" and send your patches through the GMail SMTP server, or
use any IMAP email client to connect to the google IMAP server and forward
the emails through that.
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 87f397ed96..95cf73cd47 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -520,18 +520,12 @@ check that makes sure that existing object files will not get overwritten.
core.notesRef::
When showing commit messages, also show notes which are stored in
- the given ref. This ref is expected to contain files named
- after the full SHA-1 of the commit they annotate. The ref
- must be fully qualified.
+ the given ref. The ref must be fully qualified. If the given
+ ref does not exist, it is not an error but means that no
+ notes should be printed.
+
-If such a file exists in the given ref, the referenced blob is read, and
-appended to the commit message, separated by a "Notes (<refname>):"
-line (shortened to "Notes:" in the case of "refs/notes/commits"). If the
-given ref itself does not exist, it is not an error, but means that no
-notes should be printed.
-+
-This setting defaults to "refs/notes/commits", and can be overridden by
-the `GIT_NOTES_REF` environment variable.
+This setting defaults to "refs/notes/commits", and it can be overridden by
+the 'GIT_NOTES_REF' environment variable. See linkgit:git-notes[1].
core.sparseCheckout::
Enable "sparse checkout" feature. See section "Sparse checkout" in
@@ -1481,6 +1475,16 @@ pager.<cmd>::
it takes precedence over this option. To disable pagination for
all commands, set `core.pager` or `GIT_PAGER` to `cat`.
+pretty.<name>::
+ Alias for a --pretty= format string, as specified in
+ linkgit:git-log[1]. Any aliases defined here can be used just
+ as the built-in pretty formats could. For example,
+ running `git config pretty.changelog "format:{asterisk} %H %s"`
+ would cause the invocation `git log --pretty=changelog`
+ to be equivalent to running `git log "--pretty=format:{asterisk} %H %s"`.
+ Note that an alias with the same name as a built-in format
+ will be silently ignored.
+
pull.octopus::
The default merge strategy to use when pulling multiple branches
at once.
@@ -1699,6 +1703,13 @@ If this variable is not specified, it defaults to 'normal'.
This variable can be overridden with the -u|--untracked-files option
of linkgit:git-status[1] and linkgit:git-commit[1].
+status.submodulesummary::
+ Defaults to false.
+ If this is set to a non zero number or true (identical to -1 or an
+ unlimited number), the submodule summary will be enabled and a
+ summary of commits for modified submodules will be shown (see
+ --summary-limit option of linkgit:git-submodule[1]).
+
tar.umask::
This variable can be used to restrict the permission bits of
tar archive entries. The default is 0002, which turns off the
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 0d89aaaf2a..e745a3ccdc 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -210,7 +210,14 @@ endif::git-format-patch[]
Break complete rewrite changes into pairs of delete and create.
-M::
+ifndef::git-log[]
Detect renames.
+endif::git-log[]
+ifdef::git-log[]
+ If generating diffs, detect and report renames for each commit.
+ For following files across renames while traversing history, see
+ `--follow`.
+endif::git-log[]
-C::
Detect copies as well as renames. See also `--find-copies-harder`.
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index 51cbeb7032..74741a42f4 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -266,9 +266,9 @@ patch::
y - stage this hunk
n - do not stage this hunk
- q - quit, do not stage this hunk nor any of the remaining ones
- a - stage this and all the remaining hunks in the file
- d - do not stage this hunk nor any of the remaining hunks in the file
+ q - quit; do not stage this hunk nor any of the remaining ones
+ a - stage this hunk and all later hunks in the file
+ d - do not stage this hunk nor any of the later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 4505eb6d84..afda5c36b5 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -154,6 +154,10 @@ edits from your current working tree.
As a special case, the `"@\{-N\}"` syntax for the N-th last branch
checks out the branch (instead of detaching). You may also specify
`-` which is synonymous with `"@\{-1\}"`.
++
+As a further special case, you may use `"A...B"` as a shortcut for the
+merge base of `A` and `B` if there is exactly one merge base. You can
+leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
<new_branch>::
Name for the new branch.
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index 32c482f33f..c28603ecf5 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -95,10 +95,11 @@ OPTIONS
read the message from the standard input.
--author=<author>::
- Override the author name used in the commit. You can use the
- standard `A U Thor <author@example.com>` format. Otherwise,
- an existing commit that matches the given string and its author
- name is used.
+ Override the commit author. Specify an explicit author using the
+ standard `A U Thor <author@example.com>` format. Otherwise <author>
+ is assumed to be a pattern and is used to search for an existing
+ commit by that author (i.e. rev-list --all -i --author=<author>);
+ the commit author is then copied from the first such commit found.
--date=<date>::
Override the author date used in the commit.
diff --git a/Documentation/git-cvsserver.txt b/Documentation/git-cvsserver.txt
index dbb053ee17..c27ca4350e 100644
--- a/Documentation/git-cvsserver.txt
+++ b/Documentation/git-cvsserver.txt
@@ -72,9 +72,6 @@ plugin. Most functionality works fine with both of these clients.
LIMITATIONS
-----------
-Currently cvsserver works over SSH connections for read/write clients, and
-over pserver for anonymous CVS access.
-
CVS clients cannot tag, branch or perform GIT merges.
'git-cvsserver' maps GIT branches to CVS modules. This is very different
@@ -84,7 +81,7 @@ one or more directories.
INSTALLATION
------------
-1. If you are going to offer anonymous CVS access via pserver, add a line in
+1. If you are going to offer CVS access via pserver, add a line in
/etc/inetd.conf like
+
--
@@ -101,6 +98,38 @@ looks like
cvspserver stream tcp nowait nobody /usr/bin/git-cvsserver git-cvsserver pserver
------
+
+Only anonymous access is provided by pserve by default. To commit you
+will have to create pserver accounts, simply add a gitcvs.authdb
+setting in the config file of the repositories you want the cvsserver
+to allow writes to, for example:
+
+------
+
+ [gitcvs]
+ authdb = /etc/cvsserver/passwd
+
+------
+The format of these files is username followed by the crypted password,
+for example:
+
+------
+ myuser:$1Oyx5r9mdGZ2
+ myuser:$1$BA)@$vbnMJMDym7tA32AamXrm./
+------
+You can use the 'htpasswd' facility that comes with Apache to make these
+files, but Apache's MD5 crypt method differs from the one used by most C
+library's crypt() function, so don't use the -m option.
+
+Alternatively you can produce the password with perl's crypt() operator:
+-----
+ perl -e 'my ($user, $pass) = @ARGV; printf "%s:%s\n", $user, crypt($user, $pass)' $USER password
+-----
+
+Then provide your password via the pserver method, for example:
+------
+ cvs -d:pserver:someuser:somepassword <at> server/path/repo.git co <HEAD_name>
+------
No special setup is needed for SSH access, other than having GIT tools
in the PATH. If you have clients that do not accept the CVS_SERVER
environment variable, you can rename 'git-cvsserver' to `cvs`.
diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt
index a2d55f9745..0e6ff31823 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -133,6 +133,48 @@ Discussion
include::i18n.txt[]
+Configuration
+-------------
+
+See linkgit:git-config[1] for core variables and linkgit:git-diff[1]
+for settings related to diff generation.
+
+format.pretty::
+ Default for the `--format` option. (See "PRETTY FORMATS" above.)
+ Defaults to "medium".
+
+i18n.logOutputEncoding::
+ Encoding to use when displaying logs. (See "Discussion", above.)
+ Defaults to the value of `i18n.commitEncoding` if set, UTF-8
+ otherwise.
+
+log.date::
+ Default format for human-readable dates. (Compare the
+ `--date` option.) Defaults to "default", which means to write
+ dates like `Sat May 8 19:35:34 2010 -0500`.
+
+log.showroot::
+ If `false`, 'git log' and related commands will not treat the
+ initial commit as a big creation event. Any root commits in
+ `git log -p` output would be shown without a diff attached.
+ The default is `true`.
+
+mailmap.file::
+ See linkgit:git-shortlog[1].
+
+notes.displayRef::
+ Which refs, in addition to the default set by `core.notesRef`
+ or 'GIT_NOTES_REF', to read notes from when showing commit
+ messages with the 'log' family of commands. See
+ linkgit:git-notes[1].
++
+May be an unabbreviated ref name or a glob and may be specified
+multiple times. A warning will be issued for refs that do not exist,
+but a glob that does not match any refs is silently ignored.
++
+This setting can be disabled by the `--no-standard-notes` option,
+overridden by the 'GIT_NOTES_DISPLAY_REF' environment variable,
+and supplemented by the `--show-notes` option.
Author
------
diff --git a/Documentation/git-mailinfo.txt b/Documentation/git-mailinfo.txt
index e3d58cbac3..3ea5aad56c 100644
--- a/Documentation/git-mailinfo.txt
+++ b/Documentation/git-mailinfo.txt
@@ -40,16 +40,16 @@ OPTIONS
-u::
The commit log message, author name and author email are
taken from the e-mail, and after minimally decoding MIME
- transfer encoding, re-coded in UTF-8 by transliterating
+ transfer encoding, re-coded in the charset specified by
+ i18n.commitencoding (defaulting to UTF-8) by transliterating
them. This used to be optional but now it is the default.
+
Note that the patch is always used as-is without charset
conversion, even with this flag.
--encoding=<encoding>::
- Similar to -u but if the local convention is different
- from what is specified by i18n.commitencoding, this flag
- can be used to override it.
+ Similar to -u. But when re-coding, the charset specified here is
+ used instead of the one specified by i18n.commitencoding or UTF-8.
-n::
Disable all charset re-coding of the metadata.
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index c2325ef90e..84043cc5b2 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -58,7 +58,12 @@ include::merge-options.txt[]
-m <msg>::
Set the commit message to be used for the merge commit (in
- case one is created). The 'git fmt-merge-msg' command can be
+ 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.
diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt
index 4e5113b837..5540af5d16 100644
--- a/Documentation/git-notes.txt
+++ b/Documentation/git-notes.txt
@@ -3,7 +3,7 @@ git-notes(1)
NAME
----
-git-notes - Add/inspect object notes
+git-notes - Add or inspect object notes
SYNOPSIS
--------
@@ -15,29 +15,31 @@ SYNOPSIS
'git notes' edit [<object>]
'git notes' show [<object>]
'git notes' remove [<object>]
-'git notes' prune
+'git notes' prune [-n | -v]
DESCRIPTION
-----------
-This command allows you to add/remove notes to/from objects, without
-changing the objects themselves.
+Adds, removes, or reads notes attached to objects, without touching
+the objects themselves.
-A typical use of notes is to extend a commit message without having
-to change the commit itself. Such commit notes can be shown by `git log`
-along with the original commit message. To discern these notes from the
+By default, notes are saved to and read from `refs/notes/commits`, but
+this default can be overridden. See the OPTIONS, CONFIGURATION, and
+ENVIRONMENT sections below. If this ref does not exist, it will be
+quietly created when it is first needed to store a note.
+
+A typical use of notes is to supplement a commit message without
+changing the commit itself. Notes can be shown by 'git log' along with
+the original commit message. To distinguish these notes from the
message stored in the commit object, the notes are indented like the
message, after an unindented line saying "Notes (<refname>):" (or
-"Notes:" for the default setting).
+"Notes:" for `refs/notes/commits`).
-This command always manipulates the notes specified in "core.notesRef"
-(see linkgit:git-config[1]), which can be overridden by GIT_NOTES_REF.
-To change which notes are shown by 'git-log', see the
-"notes.displayRef" configuration.
+To change which notes are shown by 'git log', see the
+"notes.displayRef" configuration in linkgit:git-log[1].
-See the description of "notes.rewrite.<command>" in
-linkgit:git-config[1] for a way of carrying your notes across commands
-that rewrite commits.
+See the "notes.rewrite.<command>" configuration for a way to carry
+notes across commands that rewrite commits.
SUBCOMMANDS
@@ -101,15 +103,20 @@ OPTIONS
Use the given note message (instead of prompting).
If multiple `-m` options are given, their values
are concatenated as separate paragraphs.
+ Lines starting with `#` and empty lines other than a
+ single line between paragraphs will be stripped out.
-F <file>::
--file=<file>::
Take the note message from the given file. Use '-' to
read the note message from the standard input.
+ Lines starting with `#` and empty lines other than a
+ single line between paragraphs will be stripped out.
-C <object>::
--reuse-message=<object>::
- Reuse the note message from the given note object.
+ Take the note message from the given blob object (for
+ example, another note).
-c <object>::
--reedit-message=<object>::
@@ -117,22 +124,151 @@ OPTIONS
the user can further edit the note message.
--ref <ref>::
- Manipulate the notes tree in <ref>. This overrides both
- GIT_NOTES_REF and the "core.notesRef" configuration. The ref
+ Manipulate the notes tree in <ref>. This overrides
+ 'GIT_NOTES_REF' and the "core.notesRef" configuration. The ref
is taken to be in `refs/notes/` if it is not qualified.
+-n::
+ Do not remove anything; just report the object names whose notes
+ would be removed.
+
+-v::
+ Report all object names whose notes are removed.
+
+
+DISCUSSION
+----------
-NOTES
------
+Commit notes are blobs containing extra information about an object
+(usually information to supplement a commit's message). These blobs
+are taken from notes refs. A notes ref is usually a branch which
+contains "files" whose paths are the object names for the objects
+they describe, with some directory separators included for performance
+reasons footnote:[Permitted pathnames have the form
+'ab'`/`'cd'`/`'ef'`/`'...'`/`'abcdef...': a sequence of directory
+names of two hexadecimal digits each followed by a filename with the
+rest of the object ID.].
Every notes change creates a new commit at the specified notes ref.
You can therefore inspect the history of the notes by invoking, e.g.,
-`git log -p notes/commits`.
+`git log -p notes/commits`. Currently the commit message only records
+which operation triggered the update, and the commit authorship is
+determined according to the usual rules (see linkgit:git-commit[1]).
+These details may change in the future.
+
+It is also permitted for a notes ref to point directly to a tree
+object, in which case the history of the notes can be read with
+`git log -p -g <refname>`.
+
+
+EXAMPLES
+--------
+
+You can use notes to add annotations with information that was not
+available at the time a commit was written.
+
+------------
+$ git notes add -m 'Tested-by: Johannes Sixt <j6t@kdbg.org>' 72a144e2
+$ git show -s 72a144e
+[...]
+ Signed-off-by: Junio C Hamano <gitster@pobox.com>
+
+Notes:
+ Tested-by: Johannes Sixt <j6t@kdbg.org>
+------------
+
+In principle, a note is a regular Git blob, and any kind of
+(non-)format is accepted. You can binary-safely create notes from
+arbitrary files using 'git hash-object':
+
+------------
+$ cc *.c
+$ blob=$(git hash-object -w a.out)
+$ git notes --ref=built add -C "$blob" HEAD
+------------
+
+Of course, it doesn't make much sense to display non-text-format notes
+with 'git log', so if you use such notes, you'll probably need to write
+some special-purpose tools to do something useful with them.
+
+
+CONFIGURATION
+-------------
-Currently the commit message only records which operation triggered
-the update, and the commit authorship is determined according to the
-usual rules (see linkgit:git-commit[1]). These details may change in
-the future.
+core.notesRef::
+ Notes ref to read and manipulate instead of
+ `refs/notes/commits`. Must be an unabbreviated ref name.
+ This setting can be overridden through the environment and
+ command line.
+
+notes.displayRef::
+ Which ref (or refs, if a glob or specified more than once), in
+ addition to the default set by `core.notesRef` or
+ 'GIT_NOTES_REF', to read notes from when showing commit
+ messages with the 'git log' family of commands.
+ This setting can be overridden on the command line or by the
+ 'GIT_NOTES_DISPLAY_REF' environment variable.
+ See linkgit:git-log[1].
+
+notes.rewrite.<command>::
+ When rewriting commits with <command> (currently `amend` or
+ `rebase`), if this variable is `false`, git will not copy
+ notes from the original to the rewritten commit. Defaults to
+ `true`. See also "`notes.rewriteRef`" below.
++
+This setting can be overridden by the 'GIT_NOTES_REWRITE_REF'
+environment variable.
+
+notes.rewriteMode::
+ When copying notes during a rewrite, what to do if the target
+ commit already has a note. Must be one of `overwrite`,
+ `concatenate`, and `ignore`. Defaults to `concatenate`.
++
+This setting can be overridden with the `GIT_NOTES_REWRITE_MODE`
+environment variable.
+
+notes.rewriteRef::
+ When copying notes during a rewrite, specifies the (fully
+ qualified) ref whose notes should be copied. May be a glob,
+ in which case notes in all matching refs will be copied. You
+ may also specify this configuration several times.
++
+Does not have a default value; you must configure this variable to
+enable note rewriting.
++
+Can be overridden with the 'GIT_NOTES_REWRITE_REF' environment variable.
+
+
+ENVIRONMENT
+-----------
+
+'GIT_NOTES_REF'::
+ Which ref to manipulate notes from, instead of `refs/notes/commits`.
+ This overrides the `core.notesRef` setting.
+
+'GIT_NOTES_DISPLAY_REF'::
+ Colon-delimited list of refs or globs indicating which refs,
+ in addition to the default from `core.notesRef` or
+ 'GIT_NOTES_REF', to read notes from when showing commit
+ messages.
+ This overrides the `notes.displayRef` setting.
++
+A warning will be issued for refs that do not exist, but a glob that
+does not match any refs is silently ignored.
+
+'GIT_NOTES_REWRITE_MODE'::
+ When copying notes during a rewrite, what to do if the target
+ commit already has a note.
+ Must be one of `overwrite`, `concatenate`, and `ignore`.
+ This overrides the `core.rewriteMode` setting.
+
+'GIT_NOTES_REWRITE_REF'::
+ When rewriting commits, which notes to copy from the original
+ to the rewritten commit. Must be a colon-delimited list of
+ refs or globs.
++
+If not set in the environment, the list of notes to copy depends
+on the `notes.rewrite.<command>` and `notes.rewriteRef` settings.
Author
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 5863decdc9..50ba2e469f 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -206,6 +206,10 @@ OPTIONS
--onto option is not specified, the starting point is
<upstream>. May be any valid commit, and not just an
existing branch name.
++
+As a special case, you may use "A...B" as a shortcut for the
+merge base of A and B if there is exactly one merge base. You can
+leave out at most one of A and B, in which case it defaults to HEAD.
<upstream>::
Upstream branch to compare against. May be any valid commit,
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index ebaaadc178..aa021b0cb8 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -14,6 +14,7 @@ SYNOPSIS
'git remote rename' <old> <new>
'git remote rm' <name>
'git remote set-head' <name> (-a | -d | <branch>)
+'git remote set-branches' <name> [--add] <branch>...
'git remote set-url' [--push] <name> <newurl> [<oldurl>]
'git remote set-url --add' [--push] <name> <newurl>
'git remote set-url --delete' [--push] <name> <url>
@@ -110,6 +111,18 @@ remote set-head origin master" will set `$GIT_DIR/refs/remotes/origin/HEAD` to
`refs/remotes/origin/master` already exists; if not it must be fetched first.
+
+'set-branches'::
+
+Changes the list of branches tracked by the named remote.
+This can be used to track a subset of the available remote branches
+after the initial setup for a remote.
++
+The named branches will be interpreted as if specified with the
+`-t` option on the 'git remote add' command line.
++
+With `--add`, instead of replacing the list of currently tracked
+branches, adds to that list.
+
'set-url'::
Changes URL remote points to. Sets first URL remote points to matching
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index 2502531a3d..cdabfd29ad 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -145,10 +145,12 @@ summary::
foreach::
Evaluates an arbitrary shell command in each checked out submodule.
- The command has access to the variables $name, $path and $sha1:
+ The command has access to the variables $name, $path, $sha1 and
+ $toplevel:
$name is the name of the relevant submodule section in .gitmodules,
$path is the name of the submodule directory relative to the
- superproject, and $sha1 is the commit as recorded in the superproject.
+ superproject, $sha1 is the commit as recorded in the superproject,
+ and $toplevel is the absolute path to the top-level of the superproject.
Any submodules defined in the superproject but not checked out are
ignored by this command. Unless given --quiet, foreach prints the name
of each submodule before evaluating the command.
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index 68dc1879fe..765d4b312e 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -93,8 +93,6 @@ OPTIONS
This option can be also used as a coarse file-level mechanism
to ignore uncommitted changes in tracked files (akin to what
`.gitignore` does for untracked files).
-You should remember that an explicit 'git add' operation will
-still cause the file to be refreshed from the working tree.
Git will fail (gracefully) in case it needs to modify this file
in the index e.g. when merging in a commit;
thus, in case the assumed-untracked file is changed upstream,
diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt
index 98c459dc82..e10fa88b8c 100644
--- a/Documentation/gitignore.txt
+++ b/Documentation/gitignore.txt
@@ -83,16 +83,20 @@ Patterns have the following format:
- If the pattern does not contain a slash '/', git treats it as
a shell glob pattern and checks for a match against the
- pathname without leading directories.
+ pathname relative to the location of the `.gitignore` file
+ (relative to the toplevel of the work tree if not from a
+ `.gitignore` file).
- Otherwise, git treats the pattern as a shell glob suitable
for consumption by fnmatch(3) with the FNM_PATHNAME flag:
wildcards in the pattern will not match a / in the pathname.
For example, "Documentation/\*.html" matches
- "Documentation/git.html" but not
- "Documentation/ppc/ppc.html". A leading slash matches the
- beginning of the pathname; for example, "/*.c" matches
- "cat-file.c" but not "mozilla-sha1/sha1.c".
+ "Documentation/git.html" but not "Documentation/ppc/ppc.html"
+ or "tools/perf/Documentation/perf.html".
+
+ - A leading slash matches the beginning of the pathname.
+ For example, "/*.c" matches "cat-file.c" but not
+ "mozilla-sha1/sha1.c".
An example:
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index bd760d3bd1..8c68ce94f9 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -11,7 +11,12 @@ have limited your view of history: for example, if you are
only interested in changes related to a certain directory or
file.
-Here are some additional details for each format:
+There are several built-in formats, and you can define
+additional formats by setting a pretty.<name>
+config option to either another format name, or a
+'format:' string, as described below (see
+linkgit:git-config[1]). Here are the details of the
+built-in formats:
* 'oneline'
@@ -76,9 +81,9 @@ displayed in full, regardless of whether --abbrev or
true parent commits, without taking grafts nor history
simplification into account.
-* 'format:'
+* 'format:<string>'
+
-The 'format:' format allows you to specify which information
+The 'format:<string>' format allows you to specify which information
you want to show. It works a little bit like printf format,
with the notable exception that you get a newline with '%n'
instead of '\n'.
diff --git a/Documentation/pretty-options.txt b/Documentation/pretty-options.txt
index af6d2b995a..d78e121c76 100644
--- a/Documentation/pretty-options.txt
+++ b/Documentation/pretty-options.txt
@@ -3,8 +3,9 @@
Pretty-print the contents of the commit logs in a given format,
where '<format>' can be one of 'oneline', 'short', 'medium',
- 'full', 'fuller', 'email', 'raw' and 'format:<string>'.
- When omitted, the format defaults to 'medium'.
+ 'full', 'fuller', 'email', 'raw' and 'format:<string>'. See
+ the "PRETTY FORMATS" section for some additional details for each
+ format. When omitted, the format defaults to 'medium'.
+
Note: you can specify the default pretty format in the repository
configuration (see linkgit:git-config[1]).
diff --git a/Makefile b/Makefile
index cc2b3b147d..0a8dff3a1a 100644
--- a/Makefile
+++ b/Makefile
@@ -628,6 +628,7 @@ LIB_OBJS += tree-diff.o
LIB_OBJS += tree.o
LIB_OBJS += tree-walk.o
LIB_OBJS += unpack-trees.o
+LIB_OBJS += url.o
LIB_OBJS += usage.o
LIB_OBJS += userdiff.o
LIB_OBJS += utf8.o
@@ -899,6 +900,7 @@ ifeq ($(uname_S),NetBSD)
HAVE_PATHS_H = YesPlease
endif
ifeq ($(uname_S),AIX)
+ DEFAULT_PAGER = more
NO_STRCASESTR=YesPlease
NO_MEMMEM = YesPlease
NO_MKDTEMP = YesPlease
@@ -1040,7 +1042,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
NO_STRTOUMAX = YesPlease
NO_MKDTEMP = YesPlease
NO_MKSTEMPS = YesPlease
- SNPRINTF_RETURNS_BOGUS = YesPlease
NO_SVN_TESTS = YesPlease
NO_PERL_MAKEMAKER = YesPlease
RUNTIME_PREFIX = YesPlease
@@ -1077,6 +1078,7 @@ endif
-include config.mak
ifdef CHECK_HEADER_DEPENDENCIES
+COMPUTE_HEADER_DEPENDENCIES =
USE_COMPUTED_HEADER_DEPENDENCIES =
endif
@@ -1663,7 +1665,10 @@ git.o git.spec \
TEST_OBJS := $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
GIT_OBJS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
- git.o http.o http-walker.o remote-curl.o
+ git.o
+ifndef NO_CURL
+ GIT_OBJS += http.o http-walker.o remote-curl.o
+endif
XDIFF_OBJS = xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \
xdiff/xmerge.o xdiff/xpatience.o
OBJECTS := $(GIT_OBJS) $(XDIFF_OBJS)
@@ -2004,12 +2009,13 @@ endif
ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \
cp "$$execdir/git$X" "$$execdir/$$p" || exit; \
done; } && \
- { for p in $(REMOTE_CURL_ALIASES); do \
+ { test x"$(REMOTE_CURL_ALIASES)" = x || \
+ { for p in $(REMOTE_CURL_ALIASES); do \
$(RM) "$$execdir/$$p" && \
ln "$$execdir/git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
ln -s "git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
cp "$$execdir/git-remote-http$X" "$$execdir/$$p" || exit; \
- done; } && \
+ done; } ; } && \
./check_bindir "z$$bindir" "z$$execdir" "$$bindir/git-add$X"
install-gitweb:
diff --git a/builtin.h b/builtin.h
index 5c887ef61b..b614d12b9f 100644
--- a/builtin.h
+++ b/builtin.h
@@ -16,6 +16,7 @@ extern const char *help_unknown_cmd(const char *cmd);
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 commit_notes(struct notes_tree *t, const char *msg);
struct notes_rewrite_cfg {
diff --git a/builtin/blame.c b/builtin/blame.c
index fc1586350f..8506286dd2 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -39,7 +39,7 @@ static int show_root;
static int reverse;
static int blank_boundary;
static int incremental;
-static int xdl_opts = XDF_NEED_MINIMAL;
+static int xdl_opts;
static enum date_mode blame_date_mode = DATE_ISO8601;
static size_t blame_date_width;
@@ -1589,7 +1589,7 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent)
strcpy(hex, sha1_to_hex(suspect->commit->object.sha1));
printf("%s%c%d %d %d\n",
hex,
- ent->guilty ? ' ' : '*', // purely for debugging
+ ent->guilty ? ' ' : '*', /* purely for debugging */
ent->s_lno + 1,
ent->lno + 1,
ent->num_lines);
diff --git a/builtin/clone.c b/builtin/clone.c
index 4457922427..efb1e6faa5 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -464,7 +464,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
set_git_dir(make_absolute_path(git_dir));
if (0 <= option_verbosity)
- printf("Cloning into %s...\n", get_git_dir());
+ printf("Cloning into %s%s...\n",
+ option_bare ? "bare repository " : "", dir);
init_db(option_template, INIT_DB_QUIET);
/*
diff --git a/builtin/commit.c b/builtin/commit.c
index ddf77e48e1..a4e4966319 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -462,15 +462,21 @@ static void determine_author_info(void)
if (!a)
die("invalid commit: %s", use_message);
- lb = strstr(a + 8, " <");
- rb = strstr(a + 8, "> ");
- eol = strchr(a + 8, '\n');
- if (!lb || !rb || !eol)
+ lb = strchrnul(a + strlen("\nauthor "), '<');
+ rb = strchrnul(lb, '>');
+ eol = strchrnul(rb, '\n');
+ if (!*lb || !*rb || !*eol)
die("invalid commit: %s", use_message);
- name = xstrndup(a + 8, lb - (a + 8));
- email = xstrndup(lb + 2, rb - (lb + 2));
- date = xstrndup(rb + 2, eol - (rb + 2));
+ if (lb == a + strlen("\nauthor "))
+ /* \nauthor <foo@example.com> */
+ name = xcalloc(1, 1);
+ else
+ name = xmemdupz(a + strlen("\nauthor "),
+ (lb - strlen(" ") -
+ (a + strlen("\nauthor "))));
+ email = xmemdupz(lb + strlen("<"), rb - (lb + strlen("<")));
+ date = xmemdupz(rb + strlen("> "), eol - (rb + strlen("> ")));
}
if (force_author) {
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
index 379a03131f..44204257c7 100644
--- a/builtin/fmt-merge-msg.c
+++ b/builtin/fmt-merge-msg.c
@@ -202,35 +202,10 @@ static void shortlog(const char *name, unsigned char *sha1,
string_list_clear(&subjects, 0);
}
-int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
- int limit = 20, i = 0, pos = 0;
+static void do_fmt_merge_msg_title(struct strbuf *out,
+ const char *current_branch) {
+ int i = 0;
char *sep = "";
- unsigned char head_sha1[20];
- const char *current_branch;
-
- /* get current branch */
- current_branch = resolve_ref("HEAD", head_sha1, 1, NULL);
- if (!current_branch)
- die("No current branch");
- if (!prefixcmp(current_branch, "refs/heads/"))
- current_branch += 11;
-
- /* get a line */
- while (pos < in->len) {
- int len;
- char *newline, *p = in->buf + pos;
-
- newline = strchr(p, '\n');
- len = newline ? newline - p : strlen(p);
- pos += len + !!newline;
- i++;
- p[len] = 0;
- if (handle_line(p))
- die ("Error in line %d: %.*s", i, len, p);
- }
-
- if (!srcs.nr)
- return 0;
strbuf_addstr(out, "Merge ");
for (i = 0; i < srcs.nr; i++) {
@@ -278,6 +253,40 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
strbuf_addch(out, '\n');
else
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;
+ unsigned char head_sha1[20];
+ const char *current_branch;
+
+ /* get current branch */
+ current_branch = resolve_ref("HEAD", head_sha1, 1, NULL);
+ if (!current_branch)
+ die("No current branch");
+ if (!prefixcmp(current_branch, "refs/heads/"))
+ current_branch += 11;
+
+ /* get a line */
+ while (pos < in->len) {
+ int len;
+ char *newline, *p = in->buf + pos;
+
+ newline = strchr(p, '\n');
+ len = newline ? newline - p : strlen(p);
+ pos += len + !!newline;
+ i++;
+ p[len] = 0;
+ if (handle_line(p))
+ die ("Error in line %d: %.*s", i, len, p);
+ }
+
+ if (!srcs.nr)
+ return 0;
+
+ if (merge_title)
+ do_fmt_merge_msg_title(out, current_branch);
if (merge_summary) {
struct commit *head;
@@ -289,6 +298,9 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *out) {
rev.ignore_merges = 1;
rev.limited = 1;
+ if (suffixcmp(out->buf, "\n"))
+ strbuf_addch(out, '\n');
+
for (i = 0; i < origins.nr; i++)
shortlog(origins.items[i].string, origins.items[i].util,
head, &rev, limit, out);
@@ -296,6 +308,14 @@ int fmt_merge_msg(int merge_summary, struct strbuf *in, struct strbuf *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 cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix)
{
const char *inpath = NULL;
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 3a97953177..a2b28c6962 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -552,10 +552,10 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, v
grab_person("committer", val, deref, obj, buf, sz);
break;
case OBJ_TREE:
- // grab_tree_values(val, deref, obj, buf, sz);
+ /* grab_tree_values(val, deref, obj, buf, sz); */
break;
case OBJ_BLOB:
- // grab_blob_values(val, deref, obj, buf, sz);
+ /* grab_blob_values(val, deref, obj, buf, sz); */
break;
default:
die("Eh? Object of type %d?", obj->type);
diff --git a/builtin/grep.c b/builtin/grep.c
index b194ea3cea..d0a73da07a 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -724,11 +724,15 @@ static int file_callback(const struct option *opt, const char *arg, int unset)
if (!patterns)
die_errno("cannot open '%s'", arg);
while (strbuf_getline(&sb, patterns, '\n') == 0) {
+ char *s;
+ size_t len;
+
/* ignore empty line like grep does */
if (sb.len == 0)
continue;
- append_grep_pattern(grep_opt, strbuf_detach(&sb, NULL), arg,
- ++lno, GREP_PATTERN);
+
+ s = strbuf_detach(&sb, &len);
+ append_grep_pat(grep_opt, s, len, arg, ++lno, GREP_PATTERN);
}
fclose(patterns);
strbuf_release(&sb);
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 8ee91eb547..34480cfad6 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -5,7 +5,7 @@
static const char ls_remote_usage[] =
"git ls-remote [--heads] [--tags] [-u <exec> | --upload-pack <exec>]\n"
-" [<repository> [<refs>...]]";
+" [-q|--quiet] [<repository> [<refs>...]]";
/*
* Is there one among the list of patterns that match the tail part
@@ -34,6 +34,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
const char *dest = NULL;
int nongit;
unsigned flags = 0;
+ int quiet = 0;
const char *uploadpack = NULL;
const char **pattern = NULL;
@@ -67,6 +68,10 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
flags |= REF_NORMAL;
continue;
}
+ if (!strcmp("--quiet", arg) || !strcmp("-q", arg)) {
+ quiet = 1;
+ continue;
+ }
usage(ls_remote_usage);
}
dest = arg;
@@ -99,6 +104,9 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
ref = transport_get_remote_refs(transport);
if (transport_disconnect(transport))
return 1;
+
+ if (!dest && !quiet)
+ fprintf(stderr, "From %s\n", *remote->url);
for ( ; ref; ref = ref->next) {
if (!check_ref_type(ref, flags))
continue;
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index 610849a653..b8e9e5ba01 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -25,7 +25,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
const char *names[3] = { NULL, NULL, NULL };
mmfile_t mmfs[3];
mmbuffer_t result = {NULL, 0};
- xmparam_t xmp = {{XDF_NEED_MINIMAL}};
+ xmparam_t xmp = {{0}};
int ret = 0, i = 0, to_stdout = 0;
int quiet = 0;
int nongit;
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index a4a4f2ce4c..fc00d794d6 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -106,7 +106,7 @@ static void show_diff(struct merge_list *entry)
xdemitconf_t xecfg;
xdemitcb_t ecb;
- xpp.flags = XDF_NEED_MINIMAL;
+ xpp.flags = 0;
memset(&xecfg, 0, sizeof(xecfg));
xecfg.ctxlen = 3;
ecb.outf = show_outf;
diff --git a/builtin/merge.c b/builtin/merge.c
index 37d414b3ba..37ce4f589f 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -982,7 +982,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
reset_hard(remote_head->sha1, 0);
return 0;
} else {
- struct strbuf msg = STRBUF_INIT;
+ struct strbuf merge_names = STRBUF_INIT;
/* We are invoked directly as the first-class UI. */
head_arg = "HEAD";
@@ -995,13 +995,17 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
* codepath so we discard the error in this
* loop.
*/
- if (!have_message) {
- for (i = 0; i < argc; i++)
- merge_name(argv[i], &msg);
- fmt_merge_msg(option_log, &msg, &merge_msg);
- if (merge_msg.len)
- strbuf_setlen(&merge_msg, merge_msg.len-1);
- }
+ 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 (head_invalid || !argc)
diff --git a/builtin/notes.c b/builtin/notes.c
index 52b72fca68..648033c27e 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -26,7 +26,7 @@ static const char * const git_notes_usage[] = {
"git notes [--ref <notes_ref>] edit [<object>]",
"git notes [--ref <notes_ref>] show [<object>]",
"git notes [--ref <notes_ref>] remove [<object>]",
- "git notes [--ref <notes_ref>] prune",
+ "git notes [--ref <notes_ref>] prune [-n | -v]",
NULL
};
@@ -67,7 +67,7 @@ static const char * const git_notes_remove_usage[] = {
};
static const char * const git_notes_prune_usage[] = {
- "git notes prune",
+ "git notes prune [<options>]",
NULL
};
@@ -416,7 +416,7 @@ int notes_copy_from_stdin(int force, const char *rewrite_cmd)
{
struct strbuf buf = STRBUF_INIT;
struct notes_rewrite_cfg *c = NULL;
- struct notes_tree *t;
+ struct notes_tree *t = NULL;
int ret = 0;
if (rewrite_cmd) {
@@ -792,7 +792,10 @@ static int remove_cmd(int argc, const char **argv, const char *prefix)
static int prune(int argc, const char **argv, const char *prefix)
{
struct notes_tree *t;
+ int show_only = 0, verbose = 0;
struct option options[] = {
+ OPT_BOOLEAN('n', NULL, &show_only, "do not remove, show only"),
+ OPT_BOOLEAN('v', NULL, &verbose, "report pruned notes"),
OPT_END()
};
@@ -806,8 +809,10 @@ static int prune(int argc, const char **argv, const char *prefix)
t = init_notes_check("prune");
- prune_notes(t);
- commit_notes(t, "Notes removed by 'git notes prune'");
+ prune_notes(t, (verbose ? NOTES_PRUNE_VERBOSE : 0) |
+ (show_only ? NOTES_PRUNE_VERBOSE|NOTES_PRUNE_DRYRUN : 0) );
+ if (!show_only)
+ commit_notes(t, "Notes removed by 'git notes prune'");
free_notes(t);
return 0;
}
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 214d7ef2b1..0e81673118 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1529,6 +1529,8 @@ static void try_to_free_from_threads(size_t size)
read_unlock();
}
+try_to_free_t old_try_to_free_routine;
+
/*
* The main thread waits on the condition that (at least) one of the workers
* has stopped working (which is indicated in the .working member of
@@ -1563,12 +1565,12 @@ static void init_threaded_search(void)
pthread_mutex_init(&cache_mutex, NULL);
pthread_mutex_init(&progress_mutex, NULL);
pthread_cond_init(&progress_cond, NULL);
- set_try_to_free_routine(try_to_free_from_threads);
+ old_try_to_free_routine = set_try_to_free_routine(try_to_free_from_threads);
}
static void cleanup_threaded_search(void)
{
- set_try_to_free_routine(NULL);
+ set_try_to_free_routine(old_try_to_free_routine);
pthread_cond_destroy(&progress_cond);
pthread_mutex_destroy(&read_mutex);
pthread_mutex_destroy(&cache_mutex);
diff --git a/builtin/remote.c b/builtin/remote.c
index 0e99a9957d..4745957b96 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -16,6 +16,7 @@ static const char * const builtin_remote_usage[] = {
"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 set-branches <name> [--add] <branch>...",
"git remote set-url <name> <newurl> [<oldurl>]",
"git remote set-url --add <name> <newurl>",
"git remote set-url --delete <name> <url>",
@@ -42,6 +43,12 @@ static const char * const builtin_remote_sethead_usage[] = {
NULL
};
+static const char * const builtin_remote_setbranches_usage[] = {
+ "git remote set-branches <name> <branch>...",
+ "git remote set-branches --add <name> <branch>...",
+ NULL
+};
+
static const char * const builtin_remote_show_usage[] = {
"git remote show [<options>] <name>",
NULL
@@ -110,6 +117,20 @@ enum {
TAGS_SET = 2
};
+static int add_branch(const char *key, const char *branchname,
+ const char *remotename, int mirror, struct strbuf *tmp)
+{
+ strbuf_reset(tmp);
+ strbuf_addch(tmp, '+');
+ if (mirror)
+ strbuf_addf(tmp, "refs/%s:refs/%s",
+ branchname, branchname);
+ else
+ strbuf_addf(tmp, "refs/heads/%s:refs/remotes/%s/%s",
+ branchname, remotename, branchname);
+ return git_config_set_multivar(key, tmp->buf, "^$", 0);
+}
+
static int add(int argc, const char **argv)
{
int fetch = 0, mirror = 0, fetch_tags = TAGS_DEFAULT;
@@ -162,17 +183,8 @@ static int add(int argc, const char **argv)
if (track.nr == 0)
string_list_append("*", &track);
for (i = 0; i < track.nr; i++) {
- struct string_list_item *item = track.items + i;
-
- strbuf_reset(&buf2);
- strbuf_addch(&buf2, '+');
- if (mirror)
- strbuf_addf(&buf2, "refs/%s:refs/%s",
- item->string, item->string);
- else
- strbuf_addf(&buf2, "refs/heads/%s:refs/remotes/%s/%s",
- item->string, name, item->string);
- if (git_config_set_multivar(buf.buf, buf2.buf, "^$", 0))
+ if (add_branch(buf.buf, track.items[i].string,
+ name, mirror, &buf2))
return 1;
}
@@ -1284,6 +1296,72 @@ static int update(int argc, const char **argv)
return run_command_v_opt(fetch_argv, RUN_GIT_CMD);
}
+static int remove_all_fetch_refspecs(const char *remote, const char *key)
+{
+ return git_config_set_multivar(key, NULL, NULL, 1);
+}
+
+static int add_branches(struct remote *remote, const char **branches,
+ const char *key)
+{
+ const char *remotename = remote->name;
+ int mirror = remote->mirror;
+ struct strbuf refspec = STRBUF_INIT;
+
+ for (; *branches; branches++)
+ if (add_branch(key, *branches, remotename, mirror, &refspec)) {
+ strbuf_release(&refspec);
+ return 1;
+ }
+
+ strbuf_release(&refspec);
+ return 0;
+}
+
+static int set_remote_branches(const char *remotename, const char **branches,
+ int add_mode)
+{
+ struct strbuf key = STRBUF_INIT;
+ struct remote *remote;
+
+ strbuf_addf(&key, "remote.%s.fetch", remotename);
+
+ if (!remote_is_configured(remotename))
+ die("No such remote '%s'", remotename);
+ remote = remote_get(remotename);
+
+ if (!add_mode && remove_all_fetch_refspecs(remotename, key.buf)) {
+ strbuf_release(&key);
+ return 1;
+ }
+ if (add_branches(remote, branches, key.buf)) {
+ strbuf_release(&key);
+ return 1;
+ }
+
+ strbuf_release(&key);
+ return 0;
+}
+
+static int set_branches(int argc, const char **argv)
+{
+ int add_mode = 0;
+ struct option options[] = {
+ OPT_BOOLEAN('\0', "add", &add_mode, "add branch"),
+ OPT_END()
+ };
+
+ argc = parse_options(argc, argv, NULL, options,
+ builtin_remote_setbranches_usage, 0);
+ if (argc == 0) {
+ error("no remote specified");
+ usage_with_options(builtin_remote_seturl_usage, options);
+ }
+ argv[argc] = NULL;
+
+ return set_remote_branches(argv[0], argv + 1, add_mode);
+}
+
static int set_url(int argc, const char **argv)
{
int i, push_mode = 0, add_mode = 0, delete_mode = 0;
@@ -1449,6 +1527,8 @@ int cmd_remote(int argc, const char **argv, const char *prefix)
result = rm(argc, argv);
else if (!strcmp(argv[0], "set-head"))
result = set_head(argc, argv);
+ else if (!strcmp(argv[0], "set-branches"))
+ result = set_branches(argc, argv);
else if (!strcmp(argv[0], "set-url"))
result = set_url(argc, argv);
else if (!strcmp(argv[0], "show"))
diff --git a/builtin/rerere.c b/builtin/rerere.c
index 34f9acee91..0048f9ef7f 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -89,7 +89,7 @@ static int diff_two(const char *file1, const char *label1,
printf("--- a/%s\n+++ b/%s\n", label1, label2);
fflush(stdout);
memset(&xpp, 0, sizeof(xpp));
- xpp.flags = XDF_NEED_MINIMAL;
+ xpp.flags = 0;
memset(&xecfg, 0, sizeof(xecfg));
xecfg.ctxlen = 3;
ecb.outf = outf;
diff --git a/combine-diff.c b/combine-diff.c
index 7557136c82..655fa89d8a 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -220,7 +220,7 @@ static void combine_diff(const unsigned char *parent, unsigned int mode,
parent_file.ptr = grab_blob(parent, mode, &sz);
parent_file.size = sz;
memset(&xpp, 0, sizeof(xpp));
- xpp.flags = XDF_NEED_MINIMAL;
+ xpp.flags = 0;
memset(&xecfg, 0, sizeof(xecfg));
memset(&state, 0, sizeof(state));
state.nmask = nmask;
diff --git a/compat/mingw.h b/compat/mingw.h
index 0e3e743041..f465566b7a 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -80,7 +80,7 @@ static inline int fork(void)
static inline unsigned int alarm(unsigned int seconds)
{ return 0; }
static inline int fsync(int fd)
-{ return 0; }
+{ return _commit(fd); }
static inline int getppid(void)
{ return 1; }
static inline void sync(void)
diff --git a/connect.c b/connect.c
index 9ae991ac42..0119bd377b 100644
--- a/connect.c
+++ b/connect.c
@@ -5,6 +5,7 @@
#include "refs.h"
#include "run-command.h"
#include "remote.h"
+#include "url.h"
static char *server_capabilities;
@@ -450,7 +451,7 @@ static struct child_process no_fork;
struct child_process *git_connect(int fd[2], const char *url_orig,
const char *prog, int flags)
{
- char *url = xstrdup(url_orig);
+ char *url;
char *host, *path;
char *end;
int c;
@@ -466,6 +467,11 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
*/
signal(SIGCHLD, SIG_DFL);
+ if (is_url(url_orig))
+ url = url_decode(url_orig);
+ else
+ url = xstrdup(url_orig);
+
host = strstr(url, "://");
if (host) {
*host = '\0';
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 545bd4b383..57245a8c01 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -797,6 +797,7 @@ _git_branch ()
__gitcomp "
--color --no-color --verbose --abbrev= --no-abbrev
--track --no-track --contains --merged --no-merged
+ --set-upstream
"
;;
*)
diff --git a/convert.c b/convert.c
index 4f8fcb7bbb..5a0b7fbca4 100644
--- a/convert.c
+++ b/convert.c
@@ -425,6 +425,8 @@ static int count_ident(const char *cp, unsigned long size)
cnt++;
break;
}
+ if (ch == '\n')
+ break;
}
}
return cnt;
@@ -455,6 +457,11 @@ static int ident_to_git(const char *path, const char *src, size_t len,
dollar = memchr(src + 3, '$', len - 3);
if (!dollar)
break;
+ if (memchr(src + 3, '\n', dollar - src - 3)) {
+ /* Line break before the next dollar. */
+ continue;
+ }
+
memcpy(dst, "Id$", 3);
dst += 3;
len -= dollar + 1 - src;
@@ -470,7 +477,7 @@ static int ident_to_worktree(const char *path, const char *src, size_t len,
struct strbuf *buf, int ident)
{
unsigned char sha1[20];
- char *to_free = NULL, *dollar;
+ char *to_free = NULL, *dollar, *spc;
int cnt;
if (!ident)
@@ -506,7 +513,10 @@ static int ident_to_worktree(const char *path, const char *src, size_t len,
} else if (src[2] == ':') {
/*
* It's possible that an expanded Id has crept its way into the
- * repository, we cope with that by stripping the expansion out
+ * repository, we cope with that by stripping the expansion out.
+ * This is probably not a good idea, since it will cause changes
+ * on checkout, which won't go away by stash, but let's keep it
+ * for git-style ids.
*/
dollar = memchr(src + 3, '$', len - 3);
if (!dollar) {
@@ -514,6 +524,20 @@ static int ident_to_worktree(const char *path, const char *src, size_t len,
break;
}
+ if (memchr(src + 3, '\n', dollar - src - 3)) {
+ /* Line break before the next dollar. */
+ continue;
+ }
+
+ spc = memchr(src + 4, ' ', dollar - src - 4);
+ if (spc && spc < dollar-1) {
+ /* There are spaces in unexpected places.
+ * This is probably an id from some other
+ * versioning system. Keep it for now.
+ */
+ continue;
+ }
+
len -= dollar + 1 - src;
src = dollar + 1;
} else {
diff --git a/date.c b/date.c
index 002aa3c8d6..6bae49ca33 100644
--- a/date.c
+++ b/date.c
@@ -229,6 +229,7 @@ static const struct {
{ "GMT", 0, 0, }, /* Greenwich Mean */
{ "UTC", 0, 0, }, /* Universal (Coordinated) */
+ { "Z", 0, 0, }, /* Zulu, alias for UTC */
{ "WET", 0, 0, }, /* Western European */
{ "BST", 0, 1, }, /* British Summer */
@@ -305,7 +306,7 @@ static int match_alpha(const char *date, struct tm *tm, int *offset)
for (i = 0; i < ARRAY_SIZE(timezone_names); i++) {
int match = match_string(date, timezone_names[i].name);
- if (match >= 3) {
+ if (match >= 3 || match == strlen(timezone_names[i].name)) {
int off = timezone_names[i].offset;
/* This is bogus, but we like summer */
diff --git a/diff.c b/diff.c
index 494f5601e9..4e077445c6 100644
--- a/diff.c
+++ b/diff.c
@@ -754,7 +754,7 @@ static void diff_words_show(struct diff_words_data *diff_words)
memset(&xecfg, 0, sizeof(xecfg));
diff_words_fill(&diff_words->minus, &minus, diff_words->word_regex);
diff_words_fill(&diff_words->plus, &plus, diff_words->word_regex);
- xpp.flags = XDF_NEED_MINIMAL;
+ xpp.flags = 0;
/* as only the hunk header will be parsed, we need a 0-context */
xecfg.ctxlen = 0;
xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words,
@@ -1706,21 +1706,21 @@ static void builtin_diff(const char *name_a,
if (lbl[0][0] == '/') {
/* /dev/null */
strbuf_addf(&header, "%snew file mode %06o%s\n", set, two->mode, reset);
- if (xfrm_msg && xfrm_msg[0])
- strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset);
+ if (xfrm_msg)
+ strbuf_addstr(&header, xfrm_msg);
}
else if (lbl[1][0] == '/') {
strbuf_addf(&header, "%sdeleted file mode %06o%s\n", set, one->mode, reset);
- if (xfrm_msg && xfrm_msg[0])
- strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset);
+ if (xfrm_msg)
+ strbuf_addstr(&header, xfrm_msg);
}
else {
if (one->mode != two->mode) {
strbuf_addf(&header, "%sold mode %06o%s\n", set, one->mode, reset);
strbuf_addf(&header, "%snew mode %06o%s\n", set, two->mode, reset);
}
- if (xfrm_msg && xfrm_msg[0])
- strbuf_addf(&header, "%s%s%s\n", set, xfrm_msg, reset);
+ if (xfrm_msg)
+ strbuf_addstr(&header, xfrm_msg);
/*
* we do not run diff between different kind
@@ -1789,7 +1789,7 @@ static void builtin_diff(const char *name_a,
check_blank_at_eof(&mf1, &mf2, &ecbdata);
ecbdata.file = o->file;
ecbdata.header = header.len ? &header : NULL;
- xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
+ xpp.flags = o->xdl_opts;
xecfg.ctxlen = o->context;
xecfg.interhunkctxlen = o->interhunkcontext;
xecfg.flags = XDL_EMIT_FUNCNAMES;
@@ -1894,7 +1894,7 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
memset(&xpp, 0, sizeof(xpp));
memset(&xecfg, 0, sizeof(xecfg));
- xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
+ xpp.flags = o->xdl_opts;
xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat,
&xpp, &xecfg);
}
@@ -1942,7 +1942,7 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
memset(&xpp, 0, sizeof(xpp));
memset(&xecfg, 0, sizeof(xecfg));
xecfg.ctxlen = 1; /* at least one context line */
- xpp.flags = XDF_NEED_MINIMAL;
+ xpp.flags = 0;
xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data,
&xpp, &xecfg);
@@ -2379,30 +2379,36 @@ static void fill_metainfo(struct strbuf *msg,
struct diff_filespec *one,
struct diff_filespec *two,
struct diff_options *o,
- struct diff_filepair *p)
+ struct diff_filepair *p,
+ int use_color)
{
+ const char *set = diff_get_color(use_color, DIFF_METAINFO);
+ const char *reset = diff_get_color(use_color, DIFF_RESET);
+
strbuf_init(msg, PATH_MAX * 2 + 300);
switch (p->status) {
case DIFF_STATUS_COPIED:
- strbuf_addf(msg, "similarity index %d%%", similarity_index(p));
- strbuf_addstr(msg, "\ncopy from ");
+ strbuf_addf(msg, "%ssimilarity index %d%%",
+ set, similarity_index(p));
+ strbuf_addf(msg, "%s\n%scopy from ", reset, set);
quote_c_style(name, msg, NULL, 0);
- strbuf_addstr(msg, "\ncopy to ");
+ strbuf_addf(msg, "%s\n%scopy to ", reset, set);
quote_c_style(other, msg, NULL, 0);
- strbuf_addch(msg, '\n');
+ strbuf_addf(msg, "%s\n", reset);
break;
case DIFF_STATUS_RENAMED:
- strbuf_addf(msg, "similarity index %d%%", similarity_index(p));
- strbuf_addstr(msg, "\nrename from ");
+ strbuf_addf(msg, "%ssimilarity index %d%%",
+ set, similarity_index(p));
+ strbuf_addf(msg, "%s\n%srename from ", reset, set);
quote_c_style(name, msg, NULL, 0);
- strbuf_addstr(msg, "\nrename to ");
+ strbuf_addf(msg, "%s\n%srename to ", reset, set);
quote_c_style(other, msg, NULL, 0);
- strbuf_addch(msg, '\n');
+ strbuf_addf(msg, "%s\n", reset);
break;
case DIFF_STATUS_MODIFIED:
if (p->score) {
- strbuf_addf(msg, "dissimilarity index %d%%\n",
- similarity_index(p));
+ strbuf_addf(msg, "%sdissimilarity index %d%%%s\n",
+ set, similarity_index(p), reset);
break;
}
/* fallthru */
@@ -2419,15 +2425,13 @@ static void fill_metainfo(struct strbuf *msg,
(!fill_mmfile(&mf, two) && diff_filespec_is_binary(two)))
abbrev = 40;
}
- strbuf_addf(msg, "index %.*s..%.*s",
+ strbuf_addf(msg, "%sindex %.*s..%.*s", set,
abbrev, sha1_to_hex(one->sha1),
abbrev, sha1_to_hex(two->sha1));
if (one->mode == two->mode)
strbuf_addf(msg, " %06o", one->mode);
- strbuf_addch(msg, '\n');
+ strbuf_addf(msg, "%s\n", reset);
}
- if (msg->len)
- strbuf_setlen(msg, msg->len - 1);
}
static void run_diff_cmd(const char *pgm,
@@ -2443,11 +2447,6 @@ static void run_diff_cmd(const char *pgm,
const char *xfrm_msg = NULL;
int complete_rewrite = (p->status == DIFF_STATUS_MODIFIED) && p->score;
- if (msg) {
- fill_metainfo(msg, name, other, one, two, o, p);
- xfrm_msg = msg->len ? msg->buf : NULL;
- }
-
if (!DIFF_OPT_TST(o, ALLOW_EXTERNAL))
pgm = NULL;
else {
@@ -2456,6 +2455,16 @@ static void run_diff_cmd(const char *pgm,
pgm = drv->external;
}
+ if (msg) {
+ /*
+ * don't use colors when the header is intended for an
+ * external diff driver
+ */
+ fill_metainfo(msg, name, other, one, two, o, p,
+ DIFF_OPT_TST(o, COLOR_DIFF) && !pgm);
+ xfrm_msg = msg->len ? msg->buf : NULL;
+ }
+
if (pgm) {
run_external_diff(pgm, name, other, one, two, xfrm_msg,
complete_rewrite);
@@ -3521,7 +3530,7 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
len2, p->two->path);
git_SHA1_Update(&ctx, buffer, len1);
- xpp.flags = XDF_NEED_MINIMAL;
+ xpp.flags = 0;
xecfg.ctxlen = 3;
xecfg.flags = XDL_EMIT_FUNCNAMES;
xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data,
diff --git a/dir.c b/dir.c
index cb83332a26..5615f33af1 100644
--- a/dir.c
+++ b/dir.c
@@ -958,9 +958,14 @@ char *get_relative_cwd(char *buffer, int size, const char *dir)
}
if (*dir)
return NULL;
- if (*cwd == '/')
+ switch (*cwd) {
+ case '\0':
+ return cwd;
+ case '/':
return cwd + 1;
- return cwd;
+ default:
+ return NULL;
+ }
}
int is_inside_dir(const char *dir)
diff --git a/fsck.c b/fsck.c
index ae9ae1abee..3d05d4a794 100644
--- a/fsck.c
+++ b/fsck.c
@@ -311,8 +311,6 @@ static int fsck_commit(struct commit *commit, fsck_error error_func)
err = fsck_ident(&buffer, &commit->object, error_func);
if (err)
return err;
- if (*buffer != '\n')
- return error_func(&commit->object, FSCK_ERROR, "invalid format - expected blank line");
if (!commit->tree)
return error_func(&commit->object, FSCK_ERROR, "could not load commit's tree %s", sha1_to_hex(tree_sha1));
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index 21f1330a5b..27fc79347a 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -1111,9 +1111,9 @@ sub help_patch_cmd {
print colored $help_color, <<EOF ;
y - $verb this hunk$target
n - do not $verb this hunk$target
-q - quit, do not $verb this hunk nor any of the remaining ones
-a - $verb this and all the remaining hunks in the file
-d - do not $verb this hunk nor any of the remaining hunks in the file
+q - quit; do not $verb this hunk nor any of the remaining ones
+a - $verb this hunk and all later hunks in the file
+d - do not $verb this hunk nor any of the later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
diff --git a/git-compat-util.h b/git-compat-util.h
index edf352dee2..81ceb7f906 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -56,7 +56,7 @@
# define _XOPEN_SOURCE 500
# endif
#elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && \
- !defined(_M_UNIX) && !defined(sgi) && !defined(__DragonFly__)
+ !defined(_M_UNIX) && !defined(__sgi) && !defined(__DragonFly__)
#define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
#define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
#endif
@@ -363,7 +363,8 @@ static inline void *gitmempcpy(void *dest, const void *src, size_t n)
extern void release_pack_memory(size_t, int);
-extern void set_try_to_free_routine(void (*routine)(size_t));
+typedef void (*try_to_free_t)(size_t);
+extern try_to_free_t set_try_to_free_routine(try_to_free_t);
extern char *xstrdup(const char *str);
extern void *xmalloc(size_t size);
diff --git a/git-cvsserver.perl b/git-cvsserver.perl
index 13751db882..3833beeef3 100755
--- a/git-cvsserver.perl
+++ b/git-cvsserver.perl
@@ -183,12 +183,58 @@ if ($state->{method} eq 'pserver') {
exit 1;
}
$line = <STDIN>; chomp $line;
- unless ($line eq 'anonymous') {
- print "E Only anonymous user allowed via pserver\n";
- print "I HATE YOU\n";
- exit 1;
+ my $user = $line;
+ $line = <STDIN>; chomp $line;
+ my $password = $line;
+
+ if ($user eq 'anonymous') {
+ # "A" will be 1 byte, use length instead in case the
+ # encryption method ever changes (yeah, right!)
+ if (length($password) > 1 ) {
+ print "E Don't supply a password for the `anonymous' user\n";
+ print "I HATE YOU\n";
+ exit 1;
+ }
+
+ # Fall through to LOVE
+ } else {
+ # Trying to authenticate a user
+ if (not exists $cfg->{gitcvs}->{authdb}) {
+ print "E the repo config file needs a [gitcvs] section with an 'authdb' parameter set to the filename of the authentication database\n";
+ print "I HATE YOU\n";
+ exit 1;
+ }
+
+ my $authdb = $cfg->{gitcvs}->{authdb};
+
+ unless (-e $authdb) {
+ print "E The authentication database specified in [gitcvs.authdb] does not exist\n";
+ print "I HATE YOU\n";
+ exit 1;
+ }
+
+ my $auth_ok;
+ open my $passwd, "<", $authdb or die $!;
+ while (<$passwd>) {
+ if (m{^\Q$user\E:(.*)}) {
+ if (crypt($user, descramble($password)) eq $1) {
+ $auth_ok = 1;
+ }
+ };
+ }
+ close $passwd;
+
+ unless ($auth_ok) {
+ print "I HATE YOU\n";
+ exit 1;
+ }
+
+ # Fall through to LOVE
}
- $line = <STDIN>; chomp $line; # validate the password?
+
+ # For checking whether the user is anonymous on commit
+ $state->{user} = $user;
+
$line = <STDIN>; chomp $line;
unless ($line eq "END $request REQUEST") {
die "E Do not understand $line -- expecting END $request REQUEST\n";
@@ -1271,9 +1317,9 @@ sub req_ci
$log->info("req_ci : " . ( defined($data) ? $data : "[NULL]" ));
- if ( $state->{method} eq 'pserver')
+ if ( $state->{method} eq 'pserver' and $state->{user} eq 'anonymous' )
{
- print "error 1 pserver access cannot commit\n";
+ print "error 1 anonymous user cannot commit via pserver\n";
cleanupWorkTree();
exit;
}
@@ -2586,6 +2632,40 @@ sub cvs_author
$author;
}
+
+sub descramble
+{
+ # This table is from src/scramble.c in the CVS source
+ my @SHIFTS = (
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 114,120, 53, 79, 96,109, 72,108, 70, 64, 76, 67,116, 74, 68, 87,
+ 111, 52, 75,119, 49, 34, 82, 81, 95, 65,112, 86,118,110,122,105,
+ 41, 57, 83, 43, 46,102, 40, 89, 38,103, 45, 50, 42,123, 91, 35,
+ 125, 55, 54, 66,124,126, 59, 47, 92, 71,115, 78, 88,107,106, 56,
+ 36,121,117,104,101,100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48,
+ 58,113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85,223,
+ 225,216,187,166,229,189,222,188,141,249,148,200,184,136,248,190,
+ 199,170,181,204,138,232,218,183,255,234,220,247,213,203,226,193,
+ 174,172,228,252,217,201,131,230,197,211,145,238,161,179,160,212,
+ 207,221,254,173,202,146,224,151,140,196,205,130,135,133,143,246,
+ 192,159,244,239,185,168,215,144,139,165,180,157,147,186,214,176,
+ 227,231,219,169,175,156,206,198,129,164,150,210,154,177,134,127,
+ 182,128,158,208,162,132,167,209,149,241,153,251,237,236,171,195,
+ 243,233,253,240,194,250,191,155,142,137,245,235,163,242,178,152
+ );
+ my ($str) = @_;
+
+ # This should never happen, the same password format (A) bas been
+ # used by CVS since the beginning of time
+ die "invalid password format $1" unless substr($str, 0, 1) eq 'A';
+
+ my @str = unpack "C*", substr($str, 1);
+ my $ret = join '', map { chr $SHIFTS[$_] } @str;
+ return $ret;
+}
+
+
package GITCVS::log;
####
diff --git a/git-pull.sh b/git-pull.sh
index 1a4729f7bb..a09a44ec4c 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -43,6 +43,7 @@ merge_args=
curr_branch=$(git symbolic-ref -q HEAD)
curr_branch_short="${curr_branch#refs/heads/}"
rebase=$(git config --bool branch.$curr_branch_short.rebase)
+dry_run=
while :
do
case "$1" in
@@ -104,6 +105,9 @@ do
--no-r|--no-re|--no-reb|--no-reba|--no-rebas|--no-rebase)
rebase=false
;;
+ --d|--dr|--dry|--dry-|--dry-r|--dry-ru|--dry-run)
+ dry_run=--dry-run
+ ;;
-h|--h|--he|--hel|--help)
usage
;;
@@ -216,7 +220,8 @@ test true = "$rebase" && {
done
}
orig_head=$(git rev-parse -q --verify HEAD)
-git fetch $verbosity $progress --update-head-ok "$@" || exit 1
+git fetch $verbosity $progress $dry_run --update-head-ok "$@" || exit 1
+test -z "$dry_run" || exit 0
curr_head=$(git rev-parse -q --verify HEAD)
if test -n "$orig_head" && test "$curr_head" != "$orig_head"
diff --git a/git-submodule.sh b/git-submodule.sh
index 8175cb279d..8c562a72e6 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -271,6 +271,8 @@ cmd_foreach()
shift
done
+ toplevel=$(pwd)
+
module_list |
while read mode sha1 stage path
do
diff --git a/git-svn.perl b/git-svn.perl
index b3b6964f95..19d6848d0e 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -963,6 +963,7 @@ sub cmd_multi_init {
}
do_git_init_db();
if (defined $_trunk) {
+ $_trunk =~ s#^/+##;
my $trunk_ref = 'refs/remotes/' . $_prefix . 'trunk';
# try both old-style and new-style lookups:
my $gs_trunk = eval { Git::SVN->new($trunk_ref) };
@@ -2054,6 +2055,9 @@ sub new {
"\":$ref_id\$\" in config\n";
($self->{path}, undef) = split(/\s*:\s*/, $fetch);
}
+ $self->{path} =~ s{/+}{/}g;
+ $self->{path} =~ s{\A/}{};
+ $self->{path} =~ s{/\z}{};
$self->{url} = command_oneline('config', '--get',
"svn-remote.$repo_id.url") or
die "Failed to read \"svn-remote.$repo_id.url\" in config\n";
@@ -2836,8 +2840,9 @@ sub mkemptydirs {
foreach my $d (sort keys %empty_dirs) {
$d = uri_decode($d);
$d =~ s/$strip//;
+ next unless length($d);
next if -d $d;
- if (-e _) {
+ if (-e $d) {
warn "$d exists but is not a directory\n";
} else {
print "creating empty directory: $d\n";
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 934aacb614..2365311d94 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -445,6 +445,19 @@ our %feature = (
'javascript-actions' => {
'override' => 0,
'default' => [0]},
+
+ # Syntax highlighting support. This is based on Daniel Svensson's
+ # and Sham Chukoury's work in gitweb-xmms2.git.
+ # It requires the 'highlight' program present in $PATH,
+ # and therefore is disabled by default.
+
+ # To enable system wide have in $GITWEB_CONFIG
+ # $feature{'highlight'}{'default'} = [1];
+
+ 'highlight' => {
+ 'sub' => sub { feature_bool('highlight', @_) },
+ 'override' => 0,
+ 'default' => [0]},
);
sub gitweb_get_feature {
@@ -3179,6 +3192,61 @@ sub blob_contenttype {
return $type;
}
+# guess file syntax for syntax highlighting; return undef if no highlighting
+# the name of syntax can (in the future) depend on syntax highlighter used
+sub guess_file_syntax {
+ my ($highlight, $mimetype, $file_name) = @_;
+ return undef unless ($highlight && defined $file_name);
+
+ # configuration for 'highlight' (http://www.andre-simon.de/)
+ # match by basename
+ my %highlight_basename = (
+ #'Program' => 'py',
+ #'Library' => 'py',
+ 'SConstruct' => 'py', # SCons equivalent of Makefile
+ 'Makefile' => 'make',
+ );
+ # match by extension
+ my %highlight_ext = (
+ # main extensions, defining name of syntax;
+ # see files in /usr/share/highlight/langDefs/ directory
+ map { $_ => $_ }
+ qw(py c cpp rb java css php sh pl js tex bib xml awk bat ini spec tcl),
+ # alternate extensions, see /etc/highlight/filetypes.conf
+ 'h' => 'c',
+ map { $_ => 'cpp' } qw(cxx c++ cc),
+ map { $_ => 'php' } qw(php3 php4),
+ map { $_ => 'pl' } qw(perl pm), # perhaps also 'cgi'
+ 'mak' => 'make',
+ map { $_ => 'xml' } qw(xhtml html htm),
+ );
+
+ my $basename = basename($file_name, '.in');
+ return $highlight_basename{$basename}
+ if exists $highlight_basename{$basename};
+
+ $basename =~ /\.([^.]*)$/;
+ my $ext = $1 or return undef;
+ return $highlight_ext{$ext}
+ if exists $highlight_ext{$ext};
+
+ return undef;
+}
+
+# run highlighter and return FD of its output,
+# or return original FD if no highlighting
+sub run_highlighter {
+ my ($fd, $highlight, $syntax) = @_;
+ return $fd unless ($highlight && defined $syntax);
+
+ close $fd
+ or die_error(404, "Reading blob failed");
+ open $fd, quote_command(git_cmd(), "cat-file", "blob", $hash)." | ".
+ "highlight --xhtml --fragment --syntax $syntax |"
+ or die_error(500, "Couldn't open file or run syntax highlighter");
+ return $fd;
+}
+
## ======================================================================
## functions printing HTML: header, footer, error page
@@ -3220,7 +3288,7 @@ sub git_header_html {
}
print $cgi->header(-type=>$content_type, -charset => 'utf-8',
-status=> $status, -expires => $expires)
- unless ($opts{'-no_http_headers'});
+ unless ($opts{'-no_http_header'});
my $mod_perl_version = $ENV{'MOD_PERL'} ? " $ENV{'MOD_PERL'}" : '';
print <<EOF;
<?xml version="1.0" encoding="utf-8"?>
@@ -5380,6 +5448,7 @@ sub git_blob {
open my $fd, "-|", git_cmd(), "cat-file", "blob", $hash
or die_error(500, "Couldn't cat $file_name, $hash");
my $mimetype = blob_mimetype($fd, $file_name);
+ # use 'blob_plain' (aka 'raw') view for files that cannot be displayed
if ($mimetype !~ m!^(?:text/|image/(?:gif|png|jpeg)$)! && -B $fd) {
close $fd;
return git_blob_plain($mimetype);
@@ -5387,6 +5456,11 @@ sub git_blob {
# we can have blame only for text/* mimetype
$have_blame &&= ($mimetype =~ m!^text/!);
+ my $highlight = gitweb_check_feature('highlight');
+ my $syntax = guess_file_syntax($highlight, $mimetype, $file_name);
+ $fd = run_highlighter($fd, $highlight, $syntax)
+ if $syntax;
+
git_header_html(undef, $expires);
my $formats_nav = '';
if (defined $hash_base && (my %co = parse_commit($hash_base))) {
@@ -5436,9 +5510,8 @@ sub git_blob {
chomp $line;
$nr++;
$line = untabify($line);
- printf "<div class=\"pre\"><a id=\"l%i\" href=\"" . href(-replay => 1)
- . "#l%i\" class=\"linenr\">%4i</a> %s</div>\n",
- $nr, $nr, $nr, esc_html($line, -nbsp=>1);
+ printf qq!<div class="pre"><a id="l%i" href="%s#l%i" class="linenr">%4i</a> %s</div>\n!,
+ $nr, href(-replay => 1), $nr, $nr, $syntax ? $line : esc_html($line, -nbsp=>1);
}
}
close $fd
diff --git a/gitweb/static/gitweb.css b/gitweb/static/gitweb.css
index 50067f2e0d..4132aabcdb 100644
--- a/gitweb/static/gitweb.css
+++ b/gitweb/static/gitweb.css
@@ -572,3 +572,21 @@ span.match {
div.binary {
font-style: italic;
}
+
+/* Style definition generated by highlight 2.4.5, http://www.andre-simon.de/ */
+
+/* Highlighting theme definition: */
+
+.num { color:#2928ff; }
+.esc { color:#ff00ff; }
+.str { color:#ff0000; }
+.dstr { color:#818100; }
+.slc { color:#838183; font-style:italic; }
+.com { color:#838183; font-style:italic; }
+.dir { color:#008200; }
+.sym { color:#000000; }
+.line { color:#555555; }
+.kwa { color:#000000; font-weight:bold; }
+.kwb { color:#830000; }
+.kwc { color:#000000; font-weight:bold; }
+.kwd { color:#010181; }
diff --git a/grep.c b/grep.c
index 543b1d5378..82fb349be6 100644
--- a/grep.c
+++ b/grep.c
@@ -7,6 +7,7 @@ void append_header_grep_pattern(struct grep_opt *opt, enum grep_header_field fie
{
struct grep_pat *p = xcalloc(1, sizeof(*p));
p->pattern = pat;
+ p->patternlen = strlen(pat);
p->origin = "header";
p->no = 0;
p->token = GREP_PATTERN_HEAD;
@@ -19,8 +20,15 @@ void append_header_grep_pattern(struct grep_opt *opt, enum grep_header_field fie
void append_grep_pattern(struct grep_opt *opt, const char *pat,
const char *origin, int no, enum grep_pat_token t)
{
+ append_grep_pat(opt, pat, strlen(pat), origin, no, t);
+}
+
+void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen,
+ const char *origin, int no, enum grep_pat_token t)
+{
struct grep_pat *p = xcalloc(1, sizeof(*p));
p->pattern = pat;
+ p->patternlen = patlen;
p->origin = origin;
p->no = no;
p->token = t;
@@ -44,8 +52,8 @@ struct grep_opt *grep_opt_dup(const struct grep_opt *opt)
append_header_grep_pattern(ret, pat->field,
pat->pattern);
else
- append_grep_pattern(ret, pat->pattern, pat->origin,
- pat->no, pat->token);
+ append_grep_pat(ret, pat->pattern, pat->patternlen,
+ pat->origin, pat->no, pat->token);
}
return ret;
@@ -329,14 +337,21 @@ static void show_name(struct grep_opt *opt, const char *name)
opt->output(opt, opt->null_following_name ? "\0" : "\n", 1);
}
-
-static int fixmatch(const char *pattern, char *line, int ignore_case, regmatch_t *match)
+static int fixmatch(struct grep_pat *p, char *line, char *eol,
+ regmatch_t *match)
{
char *hit;
- if (ignore_case)
- hit = strcasestr(line, pattern);
- else
- hit = strstr(line, pattern);
+
+ if (p->ignore_case) {
+ char *s = line;
+ do {
+ hit = strcasestr(s, p->pattern);
+ if (hit)
+ break;
+ s += strlen(s) + 1;
+ } while (s < eol);
+ } else
+ hit = memmem(line, eol - line, p->pattern, p->patternlen);
if (!hit) {
match->rm_so = match->rm_eo = -1;
@@ -344,11 +359,22 @@ static int fixmatch(const char *pattern, char *line, int ignore_case, regmatch_t
}
else {
match->rm_so = hit - line;
- match->rm_eo = match->rm_so + strlen(pattern);
+ match->rm_eo = match->rm_so + p->patternlen;
return 0;
}
}
+static int regmatch(const regex_t *preg, char *line, char *eol,
+ regmatch_t *match, int eflags)
+{
+#ifdef REG_STARTEND
+ match->rm_so = 0;
+ match->rm_eo = eol - line;
+ eflags |= REG_STARTEND;
+#endif
+ return regexec(preg, line, 1, match, eflags);
+}
+
static int strip_timestamp(char *bol, char **eol_p)
{
char *eol = *eol_p;
@@ -399,9 +425,9 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
again:
if (p->fixed)
- hit = !fixmatch(p->pattern, bol, p->ignore_case, pmatch);
+ hit = !fixmatch(p, bol, eol, pmatch);
else
- hit = !regexec(&p->regexp, bol, 1, pmatch, eflags);
+ hit = !regmatch(&p->regexp, bol, eol, pmatch, eflags);
if (hit && p->word_regexp) {
if ((pmatch[0].rm_so < 0) ||
@@ -726,16 +752,9 @@ static int look_ahead(struct grep_opt *opt,
regmatch_t m;
if (p->fixed)
- hit = !fixmatch(p->pattern, bol, p->ignore_case, &m);
- else {
-#ifdef REG_STARTEND
- m.rm_so = 0;
- m.rm_eo = *left_p;
- hit = !regexec(&p->regexp, bol, 1, &m, REG_STARTEND);
-#else
- hit = !regexec(&p->regexp, bol, 1, &m, 0);
-#endif
- }
+ hit = !fixmatch(p, bol, bol + *left_p, &m);
+ else
+ hit = !regmatch(&p->regexp, bol, bol + *left_p, &m, 0);
if (!hit || m.rm_so < 0 || m.rm_eo < 0)
continue;
if (earliest < 0 || m.rm_so < earliest)
@@ -800,17 +819,19 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
opt->show_hunk_mark = 1;
opt->last_shown = 0;
- if (buffer_is_binary(buf, size)) {
- switch (opt->binary) {
- case GREP_BINARY_DEFAULT:
+ switch (opt->binary) {
+ case GREP_BINARY_DEFAULT:
+ if (buffer_is_binary(buf, size))
binary_match_only = 1;
- break;
- case GREP_BINARY_NOMATCH:
+ break;
+ case GREP_BINARY_NOMATCH:
+ if (buffer_is_binary(buf, size))
return 0; /* Assume unmatch */
- break;
- default:
- break;
- }
+ break;
+ case GREP_BINARY_TEXT:
+ break;
+ default:
+ die("bug: unknown binary handling mode");
}
memset(&xecfg, 0, sizeof(xecfg));
@@ -871,6 +892,12 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
count++;
if (opt->status_only)
return 1;
+ if (opt->name_only) {
+ show_name(opt, name);
+ return 1;
+ }
+ if (opt->count)
+ goto next_line;
if (binary_match_only) {
opt->output(opt, "Binary file ", 12);
output_color(opt, name, strlen(name),
@@ -878,22 +905,14 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
opt->output(opt, " matches\n", 9);
return 1;
}
- if (opt->name_only) {
- show_name(opt, name);
- return 1;
- }
/* Hit at this line. If we haven't shown the
* pre-context lines, we would need to show them.
- * When asked to do "count", this still show
- * the context which is nonsense, but the user
- * deserves to get that ;-).
*/
if (opt->pre_context)
show_pre_context(opt, name, buf, bol, lno);
else if (opt->funcname)
show_funcname_line(opt, name, buf, bol, lno);
- if (!opt->count)
- show_line(opt, bol, eol, name, lno, ':');
+ show_line(opt, bol, eol, name, lno, ':');
last_hit = lno;
}
else if (last_hit &&
@@ -937,6 +956,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
output_sep(opt, ':');
snprintf(buf, sizeof(buf), "%u\n", count);
opt->output(opt, buf, strlen(buf));
+ return 1;
}
return !!last_hit;
}
diff --git a/grep.h b/grep.h
index 89342e5b47..0aebebd966 100644
--- a/grep.h
+++ b/grep.h
@@ -29,6 +29,7 @@ struct grep_pat {
int no;
enum grep_pat_token token;
const char *pattern;
+ size_t patternlen;
enum grep_header_field field;
regex_t regexp;
unsigned fixed:1;
@@ -104,6 +105,7 @@ struct grep_opt {
void *output_priv;
};
+extern void append_grep_pat(struct grep_opt *opt, const char *pat, size_t patlen, const char *origin, int no, enum grep_pat_token t);
extern void append_grep_pattern(struct grep_opt *opt, const char *pat, const char *origin, int no, enum grep_pat_token t);
extern void append_header_grep_pattern(struct grep_opt *, enum grep_header_field, const char *);
extern void compile_grep_patterns(struct grep_opt *opt);
diff --git a/http-backend.c b/http-backend.c
index d1e83d0906..f0e787e37d 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -6,6 +6,7 @@
#include "exec_cmd.h"
#include "run-command.h"
#include "string-list.h"
+#include "url.h"
static const char content_type[] = "Content-Type";
static const char content_length[] = "Content-Length";
@@ -25,60 +26,6 @@ static struct rpc_service rpc_service[] = {
{ "receive-pack", "receivepack", -1 },
};
-static int decode_char(const char *q)
-{
- int i;
- unsigned char val = 0;
- for (i = 0; i < 2; i++) {
- unsigned char c = *q++;
- val <<= 4;
- if (c >= '0' && c <= '9')
- val += c - '0';
- else if (c >= 'a' && c <= 'f')
- val += c - 'a' + 10;
- else if (c >= 'A' && c <= 'F')
- val += c - 'A' + 10;
- else
- return -1;
- }
- return val;
-}
-
-static char *decode_parameter(const char **query, int is_name)
-{
- const char *q = *query;
- struct strbuf out;
-
- strbuf_init(&out, 16);
- do {
- unsigned char c = *q;
-
- if (!c)
- break;
- if (c == '&' || (is_name && c == '=')) {
- q++;
- break;
- }
-
- if (c == '%') {
- int val = decode_char(q + 1);
- if (0 <= val) {
- strbuf_addch(&out, val);
- q += 3;
- continue;
- }
- }
-
- if (c == '+')
- strbuf_addch(&out, ' ');
- else
- strbuf_addch(&out, c);
- q++;
- } while (1);
- *query = q;
- return strbuf_detach(&out, NULL);
-}
-
static struct string_list *get_parameters(void)
{
if (!query_params) {
@@ -86,8 +33,8 @@ static struct string_list *get_parameters(void)
query_params = xcalloc(1, sizeof(*query_params));
while (query && *query) {
- char *name = decode_parameter(&query, 1);
- char *value = decode_parameter(&query, 0);
+ char *name = url_decode_parameter_name(&query);
+ char *value = url_decode_parameter_value(&query);
struct string_list_item *i;
i = string_list_lookup(name, query_params);
diff --git a/merge-file.c b/merge-file.c
index c336c93c01..db4d0d50d3 100644
--- a/merge-file.c
+++ b/merge-file.c
@@ -66,7 +66,7 @@ static int generate_common_file(mmfile_t *res, mmfile_t *f1, mmfile_t *f2)
xdemitcb_t ecb;
memset(&xpp, 0, sizeof(xpp));
- xpp.flags = XDF_NEED_MINIMAL;
+ xpp.flags = 0;
memset(&xecfg, 0, sizeof(xecfg));
xecfg.ctxlen = 3;
xecfg.flags = XDL_EMIT_COMMON;
diff --git a/notes.c b/notes.c
index e425e19827..6ee04e79e9 100644
--- a/notes.c
+++ b/notes.c
@@ -1083,7 +1083,7 @@ int write_notes_tree(struct notes_tree *t, unsigned char *result)
return ret;
}
-void prune_notes(struct notes_tree *t)
+void prune_notes(struct notes_tree *t, int flags)
{
struct note_delete_list *l = NULL;
@@ -1094,7 +1094,10 @@ void prune_notes(struct notes_tree *t)
for_each_note(t, 0, prune_notes_helper, &l);
while (l) {
- remove_note(t, l->sha1);
+ if (flags & NOTES_PRUNE_VERBOSE)
+ printf("%s\n", sha1_to_hex(l->sha1));
+ if (!(flags & NOTES_PRUNE_DRYRUN))
+ remove_note(t, l->sha1);
l = l->next;
}
}
diff --git a/notes.h b/notes.h
index 9f59277c51..cc2dff22a1 100644
--- a/notes.h
+++ b/notes.h
@@ -171,6 +171,9 @@ int for_each_note(struct notes_tree *t, int flags, each_note_fn fn,
*/
int write_notes_tree(struct notes_tree *t, unsigned char *result);
+/* Flags controlling the operation of prune */
+#define NOTES_PRUNE_VERBOSE 1
+#define NOTES_PRUNE_DRYRUN 2
/*
* Remove all notes annotating non-existing objects from the given notes tree
*
@@ -181,7 +184,7 @@ int write_notes_tree(struct notes_tree *t, unsigned char *result);
* structure are not persistent until a subsequent call to write_notes_tree()
* returns zero.
*/
-void prune_notes(struct notes_tree *t);
+void prune_notes(struct notes_tree *t, int flags);
/*
* Free (and de-initialize) the given notes_tree structure
diff --git a/pretty.c b/pretty.c
index 74cda1b44e..8b18efda9c 100644
--- a/pretty.c
+++ b/pretty.c
@@ -11,6 +11,17 @@
#include "reflog-walk.h"
static char *user_format;
+static struct cmt_fmt_map {
+ const char *name;
+ enum cmit_fmt format;
+ int is_tformat;
+ int is_alias;
+ const char *user_format;
+} *commit_formats;
+static size_t builtin_formats_len;
+static size_t commit_formats_len;
+static size_t commit_formats_alloc;
+static struct cmt_fmt_map *find_commit_format(const char *sought);
static void save_user_format(struct rev_info *rev, const char *cp, int is_tformat)
{
@@ -21,22 +32,118 @@ static void save_user_format(struct rev_info *rev, const char *cp, int is_tforma
rev->commit_format = CMIT_FMT_USERFORMAT;
}
-void get_commit_format(const char *arg, struct rev_info *rev)
+static int git_pretty_formats_config(const char *var, const char *value, void *cb)
{
+ struct cmt_fmt_map *commit_format = NULL;
+ const char *name;
+ const char *fmt;
int i;
- static struct cmt_fmt_map {
- const char *n;
- size_t cmp_len;
- enum cmit_fmt v;
- } cmt_fmts[] = {
- { "raw", 1, CMIT_FMT_RAW },
- { "medium", 1, CMIT_FMT_MEDIUM },
- { "short", 1, CMIT_FMT_SHORT },
- { "email", 1, CMIT_FMT_EMAIL },
- { "full", 5, CMIT_FMT_FULL },
- { "fuller", 5, CMIT_FMT_FULLER },
- { "oneline", 1, CMIT_FMT_ONELINE },
+
+ if (prefixcmp(var, "pretty."))
+ return 0;
+
+ name = var + strlen("pretty.");
+ for (i = 0; i < builtin_formats_len; i++) {
+ if (!strcmp(commit_formats[i].name, name))
+ return 0;
+ }
+
+ for (i = builtin_formats_len; i < commit_formats_len; i++) {
+ if (!strcmp(commit_formats[i].name, name)) {
+ commit_format = &commit_formats[i];
+ break;
+ }
+ }
+
+ if (!commit_format) {
+ ALLOC_GROW(commit_formats, commit_formats_len+1,
+ commit_formats_alloc);
+ commit_format = &commit_formats[commit_formats_len];
+ memset(commit_format, 0, sizeof(*commit_format));
+ commit_formats_len++;
+ }
+
+ commit_format->name = xstrdup(name);
+ commit_format->format = CMIT_FMT_USERFORMAT;
+ git_config_string(&fmt, var, value);
+ if (!prefixcmp(fmt, "format:") || !prefixcmp(fmt, "tformat:")) {
+ commit_format->is_tformat = fmt[0] == 't';
+ fmt = strchr(fmt, ':') + 1;
+ } else if (strchr(fmt, '%'))
+ commit_format->is_tformat = 1;
+ else
+ commit_format->is_alias = 1;
+ commit_format->user_format = fmt;
+
+ return 0;
+}
+
+static void setup_commit_formats(void)
+{
+ struct cmt_fmt_map builtin_formats[] = {
+ { "raw", CMIT_FMT_RAW, 0 },
+ { "medium", CMIT_FMT_MEDIUM, 0 },
+ { "short", CMIT_FMT_SHORT, 0 },
+ { "email", CMIT_FMT_EMAIL, 0 },
+ { "fuller", CMIT_FMT_FULLER, 0 },
+ { "full", CMIT_FMT_FULL, 0 },
+ { "oneline", CMIT_FMT_ONELINE, 1 }
};
+ commit_formats_len = ARRAY_SIZE(builtin_formats);
+ builtin_formats_len = commit_formats_len;
+ ALLOC_GROW(commit_formats, commit_formats_len, commit_formats_alloc);
+ memcpy(commit_formats, builtin_formats,
+ sizeof(*builtin_formats)*ARRAY_SIZE(builtin_formats));
+
+ git_config(git_pretty_formats_config, NULL);
+}
+
+static struct cmt_fmt_map *find_commit_format_recursive(const char *sought,
+ const char *original,
+ int num_redirections)
+{
+ struct cmt_fmt_map *found = NULL;
+ size_t found_match_len = 0;
+ int i;
+
+ if (num_redirections >= commit_formats_len)
+ die("invalid --pretty format: "
+ "'%s' references an alias which points to itself",
+ original);
+
+ for (i = 0; i < commit_formats_len; i++) {
+ size_t match_len;
+
+ if (prefixcmp(commit_formats[i].name, sought))
+ continue;
+
+ match_len = strlen(commit_formats[i].name);
+ if (found == NULL || found_match_len > match_len) {
+ found = &commit_formats[i];
+ found_match_len = match_len;
+ }
+ }
+
+ if (found && found->is_alias) {
+ found = find_commit_format_recursive(found->user_format,
+ original,
+ num_redirections+1);
+ }
+
+ return found;
+}
+
+static struct cmt_fmt_map *find_commit_format(const char *sought)
+{
+ if (!commit_formats)
+ setup_commit_formats();
+
+ return find_commit_format_recursive(sought, sought, 0);
+}
+
+void get_commit_format(const char *arg, struct rev_info *rev)
+{
+ struct cmt_fmt_map *commit_format;
rev->use_terminator = 0;
if (!arg || !*arg) {
@@ -47,21 +154,22 @@ void get_commit_format(const char *arg, struct rev_info *rev)
save_user_format(rev, strchr(arg, ':') + 1, arg[0] == 't');
return;
}
- for (i = 0; i < ARRAY_SIZE(cmt_fmts); i++) {
- if (!strncmp(arg, cmt_fmts[i].n, cmt_fmts[i].cmp_len) &&
- !strncmp(arg, cmt_fmts[i].n, strlen(arg))) {
- if (cmt_fmts[i].v == CMIT_FMT_ONELINE)
- rev->use_terminator = 1;
- rev->commit_format = cmt_fmts[i].v;
- return;
- }
- }
+
if (strchr(arg, '%')) {
save_user_format(rev, arg, 1);
return;
}
- die("invalid --pretty format: %s", arg);
+ commit_format = find_commit_format(arg);
+ if (!commit_format)
+ die("invalid --pretty format: %s", arg);
+
+ rev->commit_format = commit_format->format;
+ rev->use_terminator = commit_format->is_tformat;
+ if (commit_format->format == CMIT_FMT_USERFORMAT) {
+ save_user_format(rev, commit_format->user_format,
+ commit_format->is_tformat);
+ }
}
/*
diff --git a/remote.c b/remote.c
index 0f073e0b5f..ea2323bac3 100644
--- a/remote.c
+++ b/remote.c
@@ -478,7 +478,7 @@ static void read_config(void)
unsigned char sha1[20];
const char *head_ref;
int flag;
- if (default_remote_name) // did this already
+ if (default_remote_name) /* did this already */
return;
default_remote_name = xstrdup("origin");
current_branch = NULL;
diff --git a/setup.c b/setup.c
index 5a083fa77d..7e0460205d 100644
--- a/setup.c
+++ b/setup.c
@@ -546,6 +546,12 @@ int check_repository_format(void)
return check_repository_format_gently(NULL);
}
+/*
+ * Returns the "prefix", a path to the current working directory
+ * relative to the work tree root, or NULL, if the current working
+ * directory is not a strict subdirectory of the work tree root. The
+ * prefix always ends with a '/' character.
+ */
const char *setup_git_directory(void)
{
const char *retval = setup_git_directory_gently(NULL);
diff --git a/sha1_file.c b/sha1_file.c
index d8e61a65d1..e42ef96d45 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -102,20 +102,22 @@ static void fill_sha1_path(char *pathbuf, const unsigned char *sha1)
*/
char *sha1_file_name(const unsigned char *sha1)
{
- static char *name, *base;
+ static char buf[PATH_MAX];
+ const char *objdir;
+ int len;
- if (!base) {
- const char *sha1_file_directory = get_object_directory();
- int len = strlen(sha1_file_directory);
- base = xmalloc(len + 60);
- memcpy(base, sha1_file_directory, len);
- memset(base+len, 0, 60);
- base[len] = '/';
- base[len+3] = '/';
- name = base + len + 1;
- }
- fill_sha1_path(name, sha1);
- return base;
+ objdir = get_object_directory();
+ len = strlen(objdir);
+
+ /* '/' + sha1(2) + '/' + sha1(38) + '\0' */
+ if (len + 43 > PATH_MAX)
+ die("insanely long object directory %s", objdir);
+ memcpy(buf, objdir, len);
+ buf[len] = '/';
+ buf[len+3] = '/';
+ buf[len+42] = '\0';
+ fill_sha1_path(buf + len + 1, sha1);
+ return buf;
}
static char *sha1_get_pack_name(const unsigned char *sha1,
diff --git a/t/README b/t/README
index dcd3ebb5f2..0e4e8d8862 100644
--- a/t/README
+++ b/t/README
@@ -84,6 +84,12 @@ appropriately before running "make".
implied by other options like --valgrind and
GIT_TEST_INSTALLED.
+--root=<directory>::
+ Create "trash" directories used to store all temporary data during
+ testing under <directory>, instead of the t/ directory.
+ Using this option with a RAM-based filesystem (such as tmpfs)
+ can massively speed up the test suite.
+
You can also set the GIT_TEST_INSTALLED environment variable to
the bindir of an existing git installation to test that installation.
You still need to have built this git sandbox, from which various
diff --git a/t/t6000lib.sh b/t/lib-t6000.sh
index 985d517a1c..985d517a1c 100644
--- a/t/t6000lib.sh
+++ b/t/lib-t6000.sh
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 6cb8d60ea2..828e35baf7 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -65,17 +65,21 @@ test_expect_success expanded_in_repo '
echo "\$Id:NoSpaceAtFront \$"
echo "\$Id:NoSpaceAtEitherEnd\$"
echo "\$Id: NoTerminatingSymbol"
+ echo "\$Id: Foreign Commit With Spaces \$"
+ echo "\$Id: NoTerminatingSymbolAtEOF"
} > expanded-keywords &&
{
echo "File with expanded keywords"
- echo "\$Id: 4f21723e7b15065df7de95bd46c8ba6fb1818f4c \$"
- echo "\$Id: 4f21723e7b15065df7de95bd46c8ba6fb1818f4c \$"
- echo "\$Id: 4f21723e7b15065df7de95bd46c8ba6fb1818f4c \$"
- echo "\$Id: 4f21723e7b15065df7de95bd46c8ba6fb1818f4c \$"
- echo "\$Id: 4f21723e7b15065df7de95bd46c8ba6fb1818f4c \$"
- echo "\$Id: 4f21723e7b15065df7de95bd46c8ba6fb1818f4c \$"
+ echo "\$Id: fd0478f5f1486f3d5177d4c3f6eb2765e8fc56b9 \$"
+ echo "\$Id: fd0478f5f1486f3d5177d4c3f6eb2765e8fc56b9 \$"
+ echo "\$Id: fd0478f5f1486f3d5177d4c3f6eb2765e8fc56b9 \$"
+ echo "\$Id: fd0478f5f1486f3d5177d4c3f6eb2765e8fc56b9 \$"
+ echo "\$Id: fd0478f5f1486f3d5177d4c3f6eb2765e8fc56b9 \$"
+ echo "\$Id: fd0478f5f1486f3d5177d4c3f6eb2765e8fc56b9 \$"
echo "\$Id: NoTerminatingSymbol"
+ echo "\$Id: Foreign Commit With Spaces \$"
+ echo "\$Id: NoTerminatingSymbolAtEOF"
} > expected-output &&
git add expanded-keywords &&
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 22a80c8268..759cf12e16 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -5,7 +5,9 @@ test_description='git fsck random collection of tests'
. ./test-lib.sh
test_expect_success setup '
+ git config i18n.commitencoding ISO-8859-1 &&
test_commit A fileA one &&
+ git config --unset i18n.commitencoding &&
git checkout HEAD^0 &&
test_commit B fileB two &&
git tag -d A B &&
@@ -28,6 +30,12 @@ test_expect_success 'loose objects borrowed from alternate are not missing' '
)
'
+test_expect_success 'valid objects appear valid' '
+ { git fsck 2>out; true; } &&
+ ! grep error out &&
+ ! grep fatal out
+'
+
# Corruption tests follow. Make sure to remove all traces of the
# specific corruption you test afterwards, lest a later test trip over
# it.
diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index 9df301211c..bd8b60732b 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -30,6 +30,7 @@ test_rev_parse() {
EMPTY_TREE=$(git write-tree)
mkdir -p work/sub/dir || exit 1
+mkdir -p work2 || exit 1
mv .git repo.git || exit 1
say "core.worktree = relative path"
@@ -54,7 +55,9 @@ GIT_DIR=$(pwd)/repo.git
GIT_CONFIG=$GIT_DIR/config
git config core.worktree "$(pwd)/work"
test_rev_parse 'outside' false false false
-cd work || exit 1
+cd work2
+test_rev_parse 'outside2' false false false
+cd ../work || exit 1
test_rev_parse 'inside' false false true ''
cd sub/dir || exit 1
test_rev_parse 'subdirectory' false false true sub/dir/
@@ -67,7 +70,9 @@ git config core.worktree non-existent
GIT_WORK_TREE=work
export GIT_WORK_TREE
test_rev_parse 'outside' false false false
-cd work || exit 1
+cd work2
+test_rev_parse 'outside' false false false
+cd ../work || exit 1
GIT_WORK_TREE=.
test_rev_parse 'inside' false false true ''
cd sub/dir || exit 1
@@ -76,6 +81,7 @@ test_rev_parse 'subdirectory' false false true sub/dir/
cd ../../.. || exit 1
mv work repo.git/work
+mv work2 repo.git/work2
say "GIT_WORK_TREE=absolute path, work tree below git dir"
GIT_DIR=$(pwd)/repo.git
@@ -86,6 +92,8 @@ cd repo.git || exit 1
test_rev_parse 'in repo.git' false true false
cd objects || exit 1
test_rev_parse 'in repo.git/objects' false true false
+cd ../work2 || exit 1
+test_rev_parse 'in repo.git/work2' false true false
cd ../work || exit 1
test_rev_parse 'in repo.git/work' false true true ''
cd sub/dir || exit 1
diff --git a/t/t2007-checkout-symlink.sh b/t/t2007-checkout-symlink.sh
index 20f33436d0..27e2127afe 100755
--- a/t/t2007-checkout-symlink.sh
+++ b/t/t2007-checkout-symlink.sh
@@ -44,8 +44,10 @@ test_expect_success 'switch from symlink to dir' '
'
-rm -fr frotz xyzzy nitfol &&
-git checkout -f master || exit
+test_expect_success 'Remove temporary directories & switch to master' '
+ rm -fr frotz xyzzy nitfol &&
+ git checkout -f master
+'
test_expect_success 'switch from dir to symlink' '
diff --git a/t/t2106-update-index-assume-unchanged.sh b/t/t2106-update-index-assume-unchanged.sh
new file mode 100755
index 0000000000..99d858c6b7
--- /dev/null
+++ b/t/t2106-update-index-assume-unchanged.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+test_description='git update-index --assume-unchanged test.
+'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' \
+ ': >file &&
+ git add file &&
+ git commit -m initial &&
+ git branch other &&
+ echo upstream >file &&
+ git add file &&
+ git commit -m upstream'
+
+test_expect_success 'do not switch branches with dirty file' \
+ 'git reset --hard &&
+ git checkout other &&
+ echo dirt >file &&
+ git update-index --assume-unchanged file &&
+ test_must_fail git checkout master'
+
+test_done
diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh
index 9929f82021..d541544537 100755
--- a/t/t3030-merge-recursive.sh
+++ b/t/t3030-merge-recursive.sh
@@ -22,6 +22,7 @@ test_expect_success 'setup 1' '
git branch df-2 &&
git branch df-3 &&
git branch remove &&
+ git branch submod &&
echo hello >>a &&
cp a d/e &&
@@ -236,6 +237,17 @@ test_expect_success 'setup 6' '
test_cmp expected actual
'
+test_expect_success 'setup 7' '
+
+ git checkout submod &&
+ git rm d/e &&
+ test_tick &&
+ git commit -m "remove d/e" &&
+ git update-index --add --cacheinfo 160000 $c1 d &&
+ test_tick &&
+ git commit -m "make d/ a submodule"
+'
+
test_expect_success 'merge-recursive simple' '
rm -fr [abcd] &&
@@ -551,4 +563,21 @@ test_expect_success 'merge removes empty directories' '
test_must_fail test -d d
'
+test_expect_failure 'merge-recursive simple w/submodule' '
+
+ git checkout submod &&
+ git merge remove
+'
+
+test_expect_failure 'merge-recursive simple w/submodule result' '
+
+ git ls-files -s >actual &&
+ (
+ echo "100644 $o5 0 a"
+ echo "100644 $o0 0 c"
+ echo "160000 $c1 0 d"
+ ) >expected &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t3306-notes-prune.sh b/t/t3306-notes-prune.sh
index a0ed0353e6..b4554041b4 100755
--- a/t/t3306-notes-prune.sh
+++ b/t/t3306-notes-prune.sh
@@ -60,7 +60,7 @@ test_expect_success 'verify commits and notes' '
test_expect_success 'remove some commits' '
- git reset --hard HEAD~2 &&
+ git reset --hard HEAD~1 &&
git reflog expire --expire=now HEAD &&
git gc --prune=now
'
@@ -68,7 +68,7 @@ test_expect_success 'remove some commits' '
test_expect_success 'verify that commits are gone' '
! git cat-file -p 5ee1c35e83ea47cd3cc4f8cbee0568915fbbbd29 &&
- ! git cat-file -p 08341ad9e94faa089d60fd3f523affb25c6da189 &&
+ git cat-file -p 08341ad9e94faa089d60fd3f523affb25c6da189 &&
git cat-file -p ab5f302035f2e7aaf04265f08b42034c23256e1f
'
@@ -79,6 +79,26 @@ test_expect_success 'verify that notes are still present' '
git notes show ab5f302035f2e7aaf04265f08b42034c23256e1f
'
+test_expect_success 'prune -n does not remove notes' '
+
+ git notes list > expect &&
+ git notes prune -n &&
+ git notes list > actual &&
+ test_cmp expect actual
+'
+
+cat > expect <<EOF
+5ee1c35e83ea47cd3cc4f8cbee0568915fbbbd29
+EOF
+
+test_expect_success 'prune -n lists prunable notes' '
+
+
+ git notes prune -n > actual &&
+ test_cmp expect actual
+'
+
+
test_expect_success 'prune notes' '
git notes prune
@@ -87,6 +107,30 @@ test_expect_success 'prune notes' '
test_expect_success 'verify that notes are gone' '
! git notes show 5ee1c35e83ea47cd3cc4f8cbee0568915fbbbd29 &&
+ git notes show 08341ad9e94faa089d60fd3f523affb25c6da189 &&
+ git notes show ab5f302035f2e7aaf04265f08b42034c23256e1f
+'
+
+test_expect_success 'remove some commits' '
+
+ git reset --hard HEAD~1 &&
+ git reflog expire --expire=now HEAD &&
+ git gc --prune=now
+'
+
+cat > expect <<EOF
+08341ad9e94faa089d60fd3f523affb25c6da189
+EOF
+
+test_expect_success 'prune -v notes' '
+
+ git notes prune -v > actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'verify that notes are gone' '
+
+ ! git notes show 5ee1c35e83ea47cd3cc4f8cbee0568915fbbbd29 &&
! git notes show 08341ad9e94faa089d60fd3f523affb25c6da189 &&
git notes show ab5f302035f2e7aaf04265f08b42034c23256e1f
'
diff --git a/t/t3307-notes-man.sh b/t/t3307-notes-man.sh
new file mode 100755
index 0000000000..3269f2eebd
--- /dev/null
+++ b/t/t3307-notes-man.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+test_description='Examples from the git-notes man page
+
+Make sure the manual is not full of lies.'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+ test_commit A &&
+ test_commit B &&
+ test_commit C
+'
+
+test_expect_success 'example 1: notes to add an Acked-by line' '
+ cat <<-\EOF >expect &&
+ B
+
+ Notes:
+ Acked-by: A C Ker <acker@example.com>
+ EOF
+ git notes add -m "Acked-by: A C Ker <acker@example.com>" B &&
+ git show -s B^{commit} >log &&
+ tail -n 4 log >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'example 2: binary notes' '
+ cp "$TEST_DIRECTORY"/test4012.png .
+ git checkout B &&
+ blob=$(git hash-object -w test4012.png) &&
+ git notes --ref=logo add -C "$blob" &&
+ git notes --ref=logo copy B C &&
+ git notes --ref=logo show C >actual &&
+ test_cmp test4012.png actual
+'
+
+test_done
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
new file mode 100755
index 0000000000..cb9f2bdd29
--- /dev/null
+++ b/t/t4205-log-pretty-formats.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+#
+# Copyright (c) 2010, Will Palmer
+#
+
+test_description='Test pretty formats'
+. ./test-lib.sh
+
+test_expect_success 'set up basic repos' '
+ >foo &&
+ >bar &&
+ git add foo &&
+ test_tick &&
+ git commit -m initial &&
+ git add bar &&
+ test_tick &&
+ git commit -m "add bar"
+'
+
+test_expect_success 'alias builtin format' '
+ git log --pretty=oneline >expected &&
+ git config pretty.test-alias oneline &&
+ git log --pretty=test-alias >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'alias masking builtin format' '
+ git log --pretty=oneline >expected &&
+ git config pretty.oneline "%H" &&
+ git log --pretty=oneline >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'alias user-defined format' '
+ git log --pretty="format:%h" >expected &&
+ git config pretty.test-alias "format:%h" &&
+ git log --pretty=test-alias >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'alias user-defined tformat' '
+ git log --pretty="tformat:%h" >expected &&
+ git config pretty.test-alias "tformat:%h" &&
+ git log --pretty=test-alias >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'alias non-existant format' '
+ git config pretty.test-alias format-that-will-never-exist &&
+ test_must_fail git log --pretty=test-alias
+'
+
+test_expect_success 'alias of an alias' '
+ git log --pretty="tformat:%h" >expected &&
+ git config pretty.test-foo "tformat:%h" &&
+ git config pretty.test-bar test-foo &&
+ git log --pretty=test-bar >actual && test_cmp expected actual
+'
+
+test_expect_success 'alias masking an alias' '
+ git log --pretty=format:"Two %H" >expected &&
+ git config pretty.duplicate "format:One %H" &&
+ git config --add pretty.duplicate "format:Two %H" &&
+ git log --pretty=duplicate >actual &&
+ test_cmp expected actual
+'
+
+test_expect_success 'alias loop' '
+ git config pretty.test-foo test-bar &&
+ git config pretty.test-bar test-foo &&
+ test_must_fail git log --pretty=test-foo
+'
+
+test_done
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 41f17e7693..4c498b1902 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -597,6 +597,94 @@ test_expect_success 'show empty remote' '
)
'
+test_expect_success 'remote set-branches requires a remote' '
+ test_must_fail git remote set-branches &&
+ test_must_fail git remote set-branches --add
+'
+
+test_expect_success 'remote set-branches' '
+ echo "+refs/heads/*:refs/remotes/scratch/*" >expect.initial &&
+ sort <<-\EOF >expect.add &&
+ +refs/heads/*:refs/remotes/scratch/*
+ +refs/heads/other:refs/remotes/scratch/other
+ EOF
+ sort <<-\EOF >expect.replace &&
+ +refs/heads/maint:refs/remotes/scratch/maint
+ +refs/heads/master:refs/remotes/scratch/master
+ +refs/heads/next:refs/remotes/scratch/next
+ EOF
+ sort <<-\EOF >expect.add-two &&
+ +refs/heads/maint:refs/remotes/scratch/maint
+ +refs/heads/master:refs/remotes/scratch/master
+ +refs/heads/next:refs/remotes/scratch/next
+ +refs/heads/pu:refs/remotes/scratch/pu
+ +refs/heads/t/topic:refs/remotes/scratch/t/topic
+ EOF
+ sort <<-\EOF >expect.setup-ffonly &&
+ refs/heads/master:refs/remotes/scratch/master
+ +refs/heads/next:refs/remotes/scratch/next
+ EOF
+ sort <<-\EOF >expect.respect-ffonly &&
+ refs/heads/master:refs/remotes/scratch/master
+ +refs/heads/next:refs/remotes/scratch/next
+ +refs/heads/pu:refs/remotes/scratch/pu
+ EOF
+
+ git clone .git/ setbranches &&
+ (
+ cd setbranches &&
+ git remote rename origin scratch &&
+ git config --get-all remote.scratch.fetch >config-result &&
+ sort <config-result >../actual.initial &&
+
+ git remote set-branches scratch --add other &&
+ git config --get-all remote.scratch.fetch >config-result &&
+ sort <config-result >../actual.add &&
+
+ git remote set-branches scratch maint master next &&
+ git config --get-all remote.scratch.fetch >config-result &&
+ sort <config-result >../actual.replace &&
+
+ git remote set-branches --add scratch pu t/topic &&
+ git config --get-all remote.scratch.fetch >config-result &&
+ sort <config-result >../actual.add-two &&
+
+ git config --unset-all remote.scratch.fetch &&
+ git config remote.scratch.fetch \
+ refs/heads/master:refs/remotes/scratch/master &&
+ git config --add remote.scratch.fetch \
+ +refs/heads/next:refs/remotes/scratch/next &&
+ git config --get-all remote.scratch.fetch >config-result &&
+ sort <config-result >../actual.setup-ffonly &&
+
+ git remote set-branches --add scratch pu &&
+ git config --get-all remote.scratch.fetch >config-result &&
+ sort <config-result >../actual.respect-ffonly
+ ) &&
+ test_cmp expect.initial actual.initial &&
+ test_cmp expect.add actual.add &&
+ test_cmp expect.replace actual.replace &&
+ test_cmp expect.add-two actual.add-two &&
+ test_cmp expect.setup-ffonly actual.setup-ffonly &&
+ test_cmp expect.respect-ffonly actual.respect-ffonly
+'
+
+test_expect_success 'remote set-branches with --mirror' '
+ echo "+refs/*:refs/*" >expect.initial &&
+ echo "+refs/heads/master:refs/heads/master" >expect.replace &&
+ git clone --mirror .git/ setbranches-mirror &&
+ (
+ cd setbranches-mirror &&
+ git remote rename origin scratch &&
+ git config --get-all remote.scratch.fetch >../actual.initial &&
+
+ git remote set-branches scratch heads/master &&
+ git config --get-all remote.scratch.fetch >../actual.replace
+ ) &&
+ test_cmp expect.initial actual.initial &&
+ test_cmp expect.replace actual.replace
+'
+
test_expect_success 'new remote' '
git remote add someremote foo &&
echo foo >expect &&
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index 3cf1b3da40..d1912351db 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -57,12 +57,24 @@ test_expect_success 'dies when no remote specified and no default remotes found'
test_expect_success 'use "origin" when no remote specified' '
- git remote add origin "$(pwd)/.git" &&
- git ls-remote >actual &&
+ URL="$(pwd)/.git" &&
+ echo "From $URL" >exp_err &&
+
+ git remote add origin "$URL" &&
+ git ls-remote 2>actual_err >actual &&
+
+ test_cmp exp_err actual_err &&
test_cmp expected.all actual
'
+test_expect_success 'suppress "From <url>" with -q' '
+
+ git ls-remote -q 2>actual_err &&
+ test_must_fail test_cmp exp_err actual_err
+
+'
+
test_expect_success 'use branch.<name>.remote if possible' '
#
@@ -78,10 +90,14 @@ test_expect_success 'use branch.<name>.remote if possible' '
git show-ref | sed -e "s/ / /"
) >exp &&
- git remote add other other.git &&
+ URL="other.git" &&
+ echo "From $URL" >exp_err &&
+
+ git remote add other $URL &&
git config branch.master.remote other &&
- git ls-remote >actual &&
+ git ls-remote 2>actual_err >actual &&
+ test_cmp exp_err actual_err &&
test_cmp exp actual
'
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 678cee502d..8abb71afcd 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -176,4 +176,16 @@ test_expect_success 'clone respects global branch.autosetuprebase' '
)
'
+test_expect_success 'respect url-encoding of file://' '
+ git init x+y &&
+ test_must_fail git clone "file://$PWD/x+y" xy-url &&
+ git clone "file://$PWD/x%2By" xy-url
+'
+
+test_expect_success 'do not respect url-encoding of non-url path' '
+ git init x+y &&
+ test_must_fail git clone x%2By xy-regular &&
+ git clone x+y xy-regular
+'
+
test_done
diff --git a/t/t6002-rev-list-bisect.sh b/t/t6002-rev-list-bisect.sh
index b4e8fbaa5e..fb07536a0f 100755
--- a/t/t6002-rev-list-bisect.sh
+++ b/t/t6002-rev-list-bisect.sh
@@ -5,7 +5,7 @@
test_description='Tests git rev-list --bisect functionality'
. ./test-lib.sh
-. "$TEST_DIRECTORY"/t6000lib.sh # t6xxx specific functions
+. "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
# usage: test_bisection max-diff bisect-option head ^prune...
#
diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh
index 2c73f2da7b..e4c52b0214 100755
--- a/t/t6003-rev-list-topo-order.sh
+++ b/t/t6003-rev-list-topo-order.sh
@@ -6,7 +6,7 @@
test_description='Tests git rev-list --topo-order functionality'
. ./test-lib.sh
-. "$TEST_DIRECTORY"/t6000lib.sh # t6xxx specific functions
+. "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
list_duplicates()
{
diff --git a/t/t6101-rev-parse-parents.sh b/t/t6101-rev-parse-parents.sh
index f105fab98e..e673c25e94 100755
--- a/t/t6101-rev-parse-parents.sh
+++ b/t/t6101-rev-parse-parents.sh
@@ -6,7 +6,7 @@
test_description='Test git rev-parse with different parent options'
. ./test-lib.sh
-. "$TEST_DIRECTORY"/t6000lib.sh # t6xxx specific functions
+. "$TEST_DIRECTORY"/lib-t6000.sh # t6xxx specific functions
date >path0
git update-index --add path0
diff --git a/t/t7008-grep-binary.sh b/t/t7008-grep-binary.sh
new file mode 100755
index 0000000000..eb8ca88cce
--- /dev/null
+++ b/t/t7008-grep-binary.sh
@@ -0,0 +1,102 @@
+#!/bin/sh
+
+test_description='git grep in binary files'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' "
+ printf 'binary\000file\n' >a &&
+ git add a &&
+ git commit -m.
+"
+
+test_expect_success 'git grep ina a' '
+ echo Binary file a matches >expect &&
+ git grep ina a >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git grep -ah ina a' '
+ git grep -ah ina a >actual &&
+ test_cmp a actual
+'
+
+test_expect_success 'git grep -I ina a' '
+ : >expect &&
+ test_must_fail git grep -I ina a >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git grep -c ina a' '
+ echo a:1 >expect &&
+ git grep -c ina a >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git grep -l ina a' '
+ echo a >expect &&
+ git grep -l ina a >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git grep -L bar a' '
+ echo a >expect &&
+ git grep -L bar a >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git grep -q ina a' '
+ : >expect &&
+ git grep -q ina a >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git grep -F ile a' '
+ git grep -F ile a
+'
+
+test_expect_success 'git grep -Fi iLE a' '
+ git grep -Fi iLE a
+'
+
+# This test actually passes on platforms where regexec() supports the
+# flag REG_STARTEND.
+test_expect_failure 'git grep ile a' '
+ git grep ile a
+'
+
+test_expect_failure 'git grep .fi a' '
+ git grep .fi a
+'
+
+test_expect_success 'git grep -F y<NUL>f a' "
+ printf 'y\000f' >f &&
+ git grep -f f -F a
+"
+
+test_expect_success 'git grep -F y<NUL>x a' "
+ printf 'y\000x' >f &&
+ test_must_fail git grep -f f -F a
+"
+
+test_expect_success 'git grep -Fi Y<NUL>f a' "
+ printf 'Y\000f' >f &&
+ git grep -f f -Fi a
+"
+
+test_expect_failure 'git grep -Fi Y<NUL>x a' "
+ printf 'Y\000x' >f &&
+ test_must_fail git grep -f f -Fi a
+"
+
+test_expect_success 'git grep y<NUL>f a' "
+ printf 'y\000f' >f &&
+ git grep -f f a
+"
+
+test_expect_failure 'git grep y<NUL>x a' "
+ printf 'y\000x' >f &&
+ test_must_fail git grep -f f a
+"
+
+test_done
diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index 2a527750ce..db9365b645 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -59,11 +59,13 @@ test_expect_success 'setup a submodule tree' '
sub1sha1=$(cd super/sub1 && git rev-parse HEAD)
sub3sha1=$(cd super/sub3 && git rev-parse HEAD)
+pwd=$(pwd)
+
cat > expect <<EOF
Entering 'sub1'
-foo1-sub1-$sub1sha1
+$pwd/clone-foo1-sub1-$sub1sha1
Entering 'sub3'
-foo3-sub3-$sub3sha1
+$pwd/clone-foo3-sub3-$sub3sha1
EOF
test_expect_success 'test basic "submodule foreach" usage' '
@@ -71,7 +73,9 @@ test_expect_success 'test basic "submodule foreach" usage' '
(
cd clone &&
git submodule update --init -- sub1 sub3 &&
- git submodule foreach "echo \$name-\$path-\$sha1" > ../actual
+ git submodule foreach "echo \$toplevel-\$name-\$path-\$sha1" > ../actual &&
+ git config foo.bar zar &&
+ git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar"
) &&
test_cmp expect actual
'
diff --git a/t/t7509-commit.sh b/t/t7509-commit.sh
index d52c060b06..3ea33db6c7 100755
--- a/t/t7509-commit.sh
+++ b/t/t7509-commit.sh
@@ -83,6 +83,52 @@ test_expect_success '--amend option copies authorship' '
test_cmp expect actual
'
+sha1_file() {
+ echo "$*" | sed "s#..#.git/objects/&/#"
+}
+remove_object() {
+ rm -f $(sha1_file "$*")
+}
+no_reflog() {
+ cp .git/config .git/config.saved &&
+ echo "[core] logallrefupdates = false" >>.git/config &&
+ test_when_finished "mv -f .git/config.saved .git/config" &&
+
+ if test -e .git/logs
+ then
+ mv .git/logs . &&
+ test_when_finished "mv logs .git/"
+ fi
+}
+
+test_expect_success '--amend option with empty author' '
+ git cat-file commit Initial >tmp &&
+ sed "s/author [^<]* </author </" tmp >empty-author &&
+ no_reflog &&
+ sha=$(git hash-object -t commit -w empty-author) &&
+ test_when_finished "remove_object $sha" &&
+ git checkout $sha &&
+ test_when_finished "git checkout Initial" &&
+ echo "Empty author test" >>foo &&
+ test_tick &&
+ ! git commit -a -m "empty author" --amend 2>err &&
+ grep "empty ident" err
+'
+
+test_expect_success '--amend option with missing author' '
+ git cat-file commit Initial >tmp &&
+ sed "s/author [^<]* </author </" tmp >malformed &&
+ no_reflog &&
+ sha=$(git hash-object -t commit -w malformed) &&
+ test_when_finished "remove_object $sha" &&
+ git checkout $sha &&
+ test_when_finished "git checkout Initial" &&
+ echo "Missing author test" >>foo &&
+ test_tick &&
+ ! git commit -a -m "malformed author" --amend 2>err &&
+ grep "empty ident" err
+'
+
test_expect_success '--reset-author makes the commit ours even with --amend option' '
git checkout Initial &&
echo "Test 6" >>foo &&
diff --git a/t/t7604-merge-custom-message.sh b/t/t7604-merge-custom-message.sh
index 269cfdf267..9114785ef7 100755
--- a/t/t7604-merge-custom-message.sh
+++ b/t/t7604-merge-custom-message.sh
@@ -6,6 +6,15 @@ Testing merge when using a custom message for the merge commit.'
. ./test-lib.sh
+create_merge_msgs() {
+ echo >exp.subject "custom message"
+
+ cp exp.subject exp.log &&
+ echo >>exp.log "" &&
+ echo >>exp.log "* commit 'c2':" &&
+ echo >>exp.log " c2"
+}
+
test_expect_success 'setup' '
echo c0 > c0.c &&
git add c0.c &&
@@ -19,16 +28,23 @@ test_expect_success 'setup' '
echo c2 > c2.c &&
git add c2.c &&
git commit -m c2 &&
- git tag c2
+ git tag c2 &&
+ create_merge_msgs
'
test_expect_success 'merge c2 with a custom message' '
git reset --hard c1 &&
- echo >expected "custom message" &&
- git merge -m "custom message" c2 &&
+ git merge -m "$(cat exp.subject)" c2 &&
+ git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
+ test_cmp exp.subject actual
+'
+
+test_expect_success 'merge --log appends to custom message' '
+ git reset --hard c1 &&
+ git merge --log -m "$(cat exp.subject)" c2 &&
git cat-file commit HEAD | sed -e "1,/^$/d" >actual &&
- test_cmp expected actual
+ test_cmp exp.log actual
'
test_done
diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh
index daef2d6c23..437e9b8112 100755
--- a/t/t9400-git-cvsserver-server.sh
+++ b/t/t9400-git-cvsserver-server.sh
@@ -48,7 +48,9 @@ test_expect_success 'setup' '
git pull secondroot master &&
git clone -q --bare "$WORKDIR/.git" "$SERVERDIR" >/dev/null 2>&1 &&
GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true &&
- GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log"
+ GIT_DIR="$SERVERDIR" git config gitcvs.logfile "$SERVERDIR/gitcvs.log" &&
+ GIT_DIR="$SERVERDIR" git config gitcvs.authdb "$SERVERDIR/auth.db" &&
+ echo cvsuser:cvGVEarMLnhlA > "$SERVERDIR/auth.db"
'
# note that cvs doesn't accept absolute pathnames
@@ -94,6 +96,14 @@ git
END VERIFICATION REQUEST
EOF
+cat >login-git-ok <<EOF
+BEGIN VERIFICATION REQUEST
+$SERVERDIR
+cvsuser
+Ah<Z:yZZ30 e
+END VERIFICATION REQUEST
+EOF
+
test_expect_success 'pserver authentication' \
'cat request-anonymous | git-cvsserver pserver >log 2>&1 &&
sed -ne \$p log | grep "^I LOVE YOU\$"'
@@ -107,6 +117,10 @@ test_expect_success 'pserver authentication failure (non-anonymous user)' \
fi &&
sed -ne \$p log | grep "^I HATE YOU\$"'
+test_expect_success 'pserver authentication success (non-anonymous user with password)' \
+ 'cat login-git-ok | git-cvsserver pserver >log 2>&1 &&
+ sed -ne \$p log | grep "^I LOVE YOU\$"'
+
test_expect_success 'pserver authentication (login)' \
'cat login-anonymous | git-cvsserver pserver >log 2>&1 &&
sed -ne \$p log | grep "^I LOVE YOU\$"'
diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh
index 63b6b060e6..4f2b9b062b 100755
--- a/t/t9500-gitweb-standalone-no-errors.sh
+++ b/t/t9500-gitweb-standalone-no-errors.sh
@@ -647,4 +647,33 @@ test_expect_success \
gitweb_run "p=.git;a=summary"'
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
+fi
+
+test_expect_success HIGHLIGHT \
+ 'syntax highlighting (no highlight)' \
+ '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)' \
+ 'git config gitweb.highlight yes &&
+ echo "#!/usr/bin/sh" > test.sh &&
+ git add test.sh &&
+ git commit -m "Add test.sh" &&
+ gitweb_run "p=.git;a=blob;f=test.sh"'
+test_debug 'cat gitweb.log'
+
test_done
diff --git a/trace.c b/trace.c
index 4229ae1231..1e560cb0b9 100644
--- a/trace.c
+++ b/trace.c
@@ -25,6 +25,10 @@
#include "cache.h"
#include "quote.h"
+void do_nothing(size_t unused)
+{
+}
+
/* Get a trace file descriptor from GIT_TRACE env variable. */
static int get_trace_fd(int *need_close)
{
@@ -72,6 +76,7 @@ void trace_printf(const char *fmt, ...)
if (!fd)
return;
+ set_try_to_free_routine(do_nothing); /* is never reset */
strbuf_init(&buf, 64);
va_start(ap, fmt);
len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap);
@@ -103,6 +108,7 @@ void trace_argv_printf(const char **argv, const char *fmt, ...)
if (!fd)
return;
+ set_try_to_free_routine(do_nothing); /* is never reset */
strbuf_init(&buf, 64);
va_start(ap, fmt);
len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap);
diff --git a/transport.c b/transport.c
index 8ce39364a1..4dba6f8815 100644
--- a/transport.c
+++ b/transport.c
@@ -9,6 +9,7 @@
#include "dir.h"
#include "refs.h"
#include "branch.h"
+#include "url.h"
/* rsync support */
@@ -871,54 +872,6 @@ static int is_file(const char *url)
return S_ISREG(buf.st_mode);
}
-static int isurlschemechar(int first_flag, int ch)
-{
- /*
- * The set of valid URL schemes, as per STD66 (RFC3986) is
- * '[A-Za-z][A-Za-z0-9+.-]*'. But use sightly looser check
- * of '[A-Za-z0-9][A-Za-z0-9+.-]*' because earlier version
- * of check used '[A-Za-z0-9]+' so not to break any remote
- * helpers.
- */
- int alphanumeric, special;
- alphanumeric = ch > 0 && isalnum(ch);
- special = ch == '+' || ch == '-' || ch == '.';
- return alphanumeric || (!first_flag && special);
-}
-
-static int is_url(const char *url)
-{
- const char *url2, *first_slash;
-
- if (!url)
- return 0;
- url2 = url;
- first_slash = strchr(url, '/');
-
- /* Input with no slash at all or slash first can't be URL. */
- if (!first_slash || first_slash == url)
- return 0;
- /* Character before must be : and next must be /. */
- if (first_slash[-1] != ':' || first_slash[1] != '/')
- return 0;
- /* There must be something before the :// */
- if (first_slash == url + 1)
- return 0;
- /*
- * Check all characters up to first slash - 1. Only alphanum
- * is allowed.
- */
- url2 = url;
- while (url2 < first_slash - 1) {
- if (!isurlschemechar(url2 == url, (unsigned char)*url2))
- return 0;
- url2++;
- }
-
- /* Valid enough. */
- return 1;
-}
-
static int external_specification_len(const char *url)
{
return strchr(url, ':') - url;
@@ -946,7 +899,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
if (url) {
const char *p = url;
- while (isurlschemechar(p == url, *p))
+ while (is_urlschemechar(p == url, *p))
p++;
if (!prefixcmp(p, "::"))
helper = xstrndup(url, p - url);
diff --git a/unpack-trees.c b/unpack-trees.c
index c29a9e067f..490cd5f6f4 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -854,7 +854,7 @@ static int verify_uptodate_1(struct cache_entry *ce,
{
struct stat st;
- if (o->index_only || (!ce_skip_worktree(ce) && (o->reset || ce_uptodate(ce))))
+ if (o->index_only || (!((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) && (o->reset || ce_uptodate(ce))))
return 0;
if (!lstat(ce->name, &st)) {
diff --git a/url.c b/url.c
new file mode 100644
index 0000000000..cd32b927a4
--- /dev/null
+++ b/url.c
@@ -0,0 +1,118 @@
+#include "cache.h"
+
+int is_urlschemechar(int first_flag, int ch)
+{
+ /*
+ * The set of valid URL schemes, as per STD66 (RFC3986) is
+ * '[A-Za-z][A-Za-z0-9+.-]*'. But use sightly looser check
+ * of '[A-Za-z0-9][A-Za-z0-9+.-]*' because earlier version
+ * of check used '[A-Za-z0-9]+' so not to break any remote
+ * helpers.
+ */
+ int alphanumeric, special;
+ alphanumeric = ch > 0 && isalnum(ch);
+ special = ch == '+' || ch == '-' || ch == '.';
+ return alphanumeric || (!first_flag && special);
+}
+
+int is_url(const char *url)
+{
+ const char *url2, *first_slash;
+
+ if (!url)
+ return 0;
+ url2 = url;
+ first_slash = strchr(url, '/');
+
+ /* Input with no slash at all or slash first can't be URL. */
+ if (!first_slash || first_slash == url)
+ return 0;
+ /* Character before must be : and next must be /. */
+ if (first_slash[-1] != ':' || first_slash[1] != '/')
+ return 0;
+ /* There must be something before the :// */
+ if (first_slash == url + 1)
+ return 0;
+ /*
+ * Check all characters up to first slash - 1. Only alphanum
+ * is allowed.
+ */
+ url2 = url;
+ while (url2 < first_slash - 1) {
+ if (!is_urlschemechar(url2 == url, (unsigned char)*url2))
+ return 0;
+ url2++;
+ }
+
+ /* Valid enough. */
+ return 1;
+}
+
+static int url_decode_char(const char *q)
+{
+ int i;
+ unsigned char val = 0;
+ for (i = 0; i < 2; i++) {
+ unsigned char c = *q++;
+ val <<= 4;
+ if (c >= '0' && c <= '9')
+ val += c - '0';
+ else if (c >= 'a' && c <= 'f')
+ val += c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ val += c - 'A' + 10;
+ else
+ return -1;
+ }
+ return val;
+}
+
+static char *url_decode_internal(const char **query, const char *stop_at)
+{
+ const char *q = *query;
+ struct strbuf out;
+
+ strbuf_init(&out, 16);
+ do {
+ unsigned char c = *q;
+
+ if (!c)
+ break;
+ if (stop_at && strchr(stop_at, c)) {
+ q++;
+ break;
+ }
+
+ if (c == '%') {
+ int val = url_decode_char(q + 1);
+ if (0 <= val) {
+ strbuf_addch(&out, val);
+ q += 3;
+ continue;
+ }
+ }
+
+ if (c == '+')
+ strbuf_addch(&out, ' ');
+ else
+ strbuf_addch(&out, c);
+ q++;
+ } while (1);
+ *query = q;
+ return strbuf_detach(&out, NULL);
+}
+
+char *url_decode(const char *url)
+{
+ return url_decode_internal(&url, NULL);
+}
+
+char *url_decode_parameter_name(const char **query)
+{
+ return url_decode_internal(query, "&=");
+}
+
+char *url_decode_parameter_value(const char **query)
+{
+ return url_decode_internal(query, "&");
+}
diff --git a/url.h b/url.h
new file mode 100644
index 0000000000..15817f8f93
--- /dev/null
+++ b/url.h
@@ -0,0 +1,10 @@
+#ifndef URL_H
+#define URL_H
+
+extern int is_url(const char *url);
+extern int is_urlschemechar(int first_flag, int ch);
+extern char *url_decode(const char *url);
+extern char *url_decode_parameter_name(const char **query);
+extern char *url_decode_parameter_value(const char **query);
+
+#endif /* URL_H */
diff --git a/userdiff.c b/userdiff.c
index 67003fbb23..c49cc1b67e 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -45,7 +45,9 @@ PATTERNS("pascal",
"|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+"
"|<>|<=|>=|:=|\\.\\."
"|[^[:space:]]|[\x80-\xff]+"),
-PATTERNS("php", "^[\t ]*((function|class).*)",
+PATTERNS("php",
+ "^[\t ]*(((public|protected|private|static)[\t ]+)*function.*)$\n"
+ "^[\t ]*(class.*)$",
/* -- */
"[a-zA-Z_][a-zA-Z0-9_]*"
"|[-+0-9.e]+|0[xXbB]?[0-9a-fA-F]+"
diff --git a/wrapper.c b/wrapper.c
index 58201b6bcb..afb4f6f773 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -10,9 +10,11 @@ static void try_to_free_builtin(size_t size)
static void (*try_to_free_routine)(size_t size) = try_to_free_builtin;
-void set_try_to_free_routine(void (*routine)(size_t))
+try_to_free_t set_try_to_free_routine(try_to_free_t routine)
{
- try_to_free_routine = (routine) ? routine : try_to_free_builtin;
+ try_to_free_t old = try_to_free_routine;
+ try_to_free_routine = routine;
+ return old;
}
char *xstrdup(const char *str)