summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/RelNotes-1.7.1.1.txt67
-rw-r--r--Documentation/SubmittingPatches89
-rw-r--r--Documentation/blame-options.txt10
-rw-r--r--Documentation/config.txt34
-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-log.txt42
-rw-r--r--Documentation/git-mailinfo.txt8
-rw-r--r--Documentation/git-notes.txt177
-rw-r--r--Documentation/git-rebase.txt5
-rw-r--r--Documentation/git-send-email.txt22
-rw-r--r--Documentation/git-shortlog.txt15
-rw-r--r--Documentation/git-update-index.txt2
-rw-r--r--Documentation/gitdiffcore.txt4
-rw-r--r--Documentation/gitignore.txt14
-rw-r--r--Documentation/pretty-formats.txt4
-rw-r--r--Documentation/pretty-options.txt5
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile21
l---------RelNotes2
-rw-r--r--attr.c38
-rw-r--r--builtin/apply.c18
-rw-r--r--builtin/blame.c4
-rw-r--r--builtin/commit.c29
-rw-r--r--builtin/describe.c49
-rw-r--r--builtin/for-each-ref.c4
-rw-r--r--builtin/grep.c2
-rw-r--r--builtin/index-pack.c89
-rw-r--r--builtin/init-db.c2
-rw-r--r--builtin/merge-file.c2
-rw-r--r--builtin/merge-tree.c2
-rw-r--r--builtin/notes.c2
-rw-r--r--builtin/pack-objects.c13
-rw-r--r--builtin/rerere.c2
-rw-r--r--builtin/revert.c9
-rw-r--r--builtin/shortlog.c3
-rw-r--r--builtin/show-branch.c3
-rw-r--r--cache.h3
-rw-r--r--combine-diff.c5
-rw-r--r--compat/mingw.c17
-rw-r--r--compat/mingw.h3
-rw-r--r--compat/win32/pthread.h8
-rw-r--r--compat/win32mmap.c6
-rw-r--r--config.mak.in1
-rw-r--r--configure.ac6
-rwxr-xr-xcontrib/completion/git-completion.bash1
-rwxr-xr-xcontrib/hooks/post-receive-email7
-rw-r--r--date.c3
-rw-r--r--diff-no-index.c6
-rw-r--r--diff.c86
-rw-r--r--dir.c9
-rw-r--r--exec_cmd.c2
-rwxr-xr-xgit-add--interactive.perl6
-rwxr-xr-xgit-am.sh2
-rw-r--r--git-compat-util.h20
-rwxr-xr-xgit-pull.sh7
-rwxr-xr-xgit-send-email.perl48
-rwxr-xr-xgit-stash.sh2
-rw-r--r--gitweb/Makefile2
-rw-r--r--http-walker.c2
-rw-r--r--http.c159
-rw-r--r--http.h5
-rw-r--r--merge-file.c2
-rw-r--r--merge-recursive.c2
-rw-r--r--object.c4
-rw-r--r--pack-check.c15
-rw-r--r--pack.h1
-rw-r--r--pretty.c7
-rw-r--r--remote-curl.c16
-rw-r--r--remote.c2
-rw-r--r--run-command.c2
-rw-r--r--setup.c6
-rw-r--r--sha1_file.c49
-rw-r--r--shortlog.h1
-rw-r--r--t/README6
-rw-r--r--t/lib-t6000.sh (renamed from t/t6000lib.sh)0
-rwxr-xr-xt/t0000-basic.sh21
-rwxr-xr-xt/t0001-init.sh14
-rwxr-xr-xt/t0003-attributes.sh15
-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/t3307-notes-man.sh38
-rwxr-xr-xt/t3903-stash.sh150
-rwxr-xr-xt/t4124-apply-ws-rule.sh12
-rwxr-xr-xt/t4134-apply-submodule.sh38
-rwxr-xr-xt/t4201-shortlog.sh116
-rwxr-xr-xt/t5516-fetch-push.sh2
-rwxr-xr-xt/t5541-http-push.sh29
-rwxr-xr-xt/t5550-http-fetch.sh37
-rwxr-xr-xt/t5704-bundle.sh16
-rwxr-xr-xt/t5705-clone-2gb.sh12
-rwxr-xr-xt/t6002-rev-list-bisect.sh2
-rwxr-xr-xt/t6003-rev-list-topo-order.sh2
-rwxr-xr-xt/t6006-rev-list-format.sh31
-rwxr-xr-xt/t6101-rev-parse-parents.sh2
-rwxr-xr-xt/t6120-describe.sh8
-rwxr-xr-xt/t7005-editor.sh2
-rwxr-xr-xt/t7006-pager.sh151
-rwxr-xr-xt/t7502-commit.sh2
-rwxr-xr-xt/t7508-status.sh70
-rwxr-xr-xt/t7509-commit.sh46
-rw-r--r--t/test-lib.sh45
-rw-r--r--tag.c71
-rw-r--r--tag.h2
-rw-r--r--thread-utils.c16
-rw-r--r--thread-utils.h1
-rw-r--r--unpack-trees.c14
-rw-r--r--userdiff.c4
-rw-r--r--wrapper.c42
-rw-r--r--wt-status.c21
-rw-r--r--xdiff-interface.c11
-rw-r--r--xdiff-interface.h3
115 files changed, 1903 insertions, 534 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..e0386a43f0
--- /dev/null
+++ b/Documentation/RelNotes-1.7.1.1.txt
@@ -0,0 +1,67 @@
+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.
+
+ * We didn't recognize timezone "Z" as a synonym for "UTC" (75b37e70).
+
+ * "git am -3" did not show diagnosis when the patch in the message was corrupt.
+
+ * 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 bundle --stdin" segfaulted.
+
+ * "git checkout" and "git rebase" overwrote paths that are marked "assume
+ unchanged".
+
+ * "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 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.
+
+ * "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 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 pull" accepted "--dry-run", gave it to underlying "git fetch" but
+ ignored the option itself, resulting in a bogus attempt to merge
+ unrelated commit.
+
+ * "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/SubmittingPatches b/Documentation/SubmittingPatches
index abc65de946..eb53e0636e 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -41,6 +41,7 @@ Checklist (and a short version for the impatient):
maintainer (gitster@pobox.com) if (and only if) the patch
is ready for inclusion. If you use git-send-email(1),
please test it first by sending email to yourself.
+ - see below for instructions specific to your mailer
Long version:
@@ -53,6 +54,34 @@ But the patch submission requirements are a lot more relaxed
here on the technical/contents front, because the core GIT is
thousand times smaller ;-). So here is only the relevant bits.
+(0) Decide what to base your work on.
+
+In general, always base your work on the oldest branch that your
+change is relevant to.
+
+ - A bugfix should be based on 'maint' in general. If the bug is not
+ present in 'maint', base it on 'master'. For a bug that's not yet
+ in 'master', find the topic that introduces the regression, and
+ base your work on the tip of the topic.
+
+ - A new feature should be based on 'master' in general. If the new
+ feature depends on a topic that is in 'pu', but not in 'master',
+ base your work on the tip of that topic.
+
+ - Corrections and enhancements to a topic not yet in 'master' should
+ be based on the tip of that topic. If the topic has not been merged
+ to 'next', it's alright to add a note to squash minor corrections
+ into the series.
+
+ - In the exceptional case that a new feature depends on several topics
+ not in 'master', start working on 'next' or 'pu' privately and send
+ out patches for discussion. Before the final merge, you may have to
+ wait until some of the dependent topics graduate to 'master', and
+ rebase your work.
+
+To find the tip of a topic branch, run "git log --first-parent
+master..pu" and look for the merge commit. The second parent of this
+commit is the tip of the topic branch.
(1) Make separate commits for logically separate changes.
@@ -170,17 +199,16 @@ patch, format it as "multipart/signed", not a text/plain message
that starts with '-----BEGIN PGP SIGNED MESSAGE-----'. That is
not a text/plain, it's something else.
-Note that your maintainer does not necessarily read everything
-on the git mailing list. If your patch is for discussion first,
-send it "To:" the mailing list, and optionally "cc:" him. If it
-is trivially correct or after the list reached a consensus, send
-it "To:" the maintainer and optionally "cc:" the list for
-inclusion.
-
-Also note that your maintainer does not actively involve himself in
-maintaining what are in contrib/ hierarchy. When you send fixes and
-enhancements to them, do not forget to "cc: " the person who primarily
-worked on that hierarchy in contrib/.
+Unless your patch is a very trivial and an obviously correct one,
+first send it with "To:" set to the mailing list, with "cc:" listing
+people who are involved in the area you are touching (the output from
+"git blame $path" and "git shortlog --no-merges $path" would help to
+identify them), to solicit comments and reviews. After the list
+reached a consensus that it is a good idea to apply the patch, re-send
+it with "To:" set to the maintainer and optionally "cc:" the list for
+inclusion. Do not forget to add trailers such as "Acked-by:",
+"Reviewed-by:" and "Tested-by:" after your "Signed-off-by:" line as
+necessary.
(4) Sign your work
@@ -519,9 +547,27 @@ 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 any IMAP email client to connect to the google imap server, and forward
+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.
+To use "git send-email" and send your patches through the GMail SMTP server,
+edit ~/.gitconfig to specify your account settings:
+
+[sendemail]
+ smtpencryption = tls
+ smtpserver = smtp.gmail.com
+ smtpuser = user@gmail.com
+ smtppass = p4ssw0rd
+ smtpserverport = 587
+
+Once your commits are ready to be sent to the mailing list, run the
+following commands:
+
+ $ git format-patch --cover-letter -M origin/master -o outgoing/
+ $ edit outgoing/0000-*
+ $ git send-email outgoing/*
+
To submit using the IMAP interface, first, edit your ~/.gitconfig to specify your
account settings:
@@ -537,8 +583,7 @@ You might need to instead use: folder = "[Google Mail]/Drafts" if you get an err
that the "Folder doesn't exist".
Once your commits are ready to be sent to the mailing list, run the
-following command to send the patch emails to your Gmail Drafts
-folder.
+following commands:
$ git format-patch --cover-letter -M --stdout origin/master | git imap-send
@@ -546,19 +591,3 @@ Just make sure to disable line wrapping in the email client (GMail web
interface will line wrap no matter what, so you need to use a real
IMAP client).
-Alternatively, you can use "git send-email" and send your patches
-through the GMail SMTP server. edit ~/.gitconfig to specify your
-account settings:
-
-[sendemail]
- smtpencryption = tls
- smtpserver = smtp.gmail.com
- smtpuser = user@gmail.com
- smtppass = p4ssw0rd
- smtpserverport = 587
-
-Once your commits are ready to be sent to the mailing list, run the
-following commands:
-
- $ git format-patch --cover-letter -M origin/master -o outgoing/
- $ git send-email outgoing/*
diff --git a/Documentation/blame-options.txt b/Documentation/blame-options.txt
index d8205691c6..16e3c68576 100644
--- a/Documentation/blame-options.txt
+++ b/Documentation/blame-options.txt
@@ -90,9 +90,9 @@ of lines before or after the line given by <start>.
running extra passes of inspection.
+
<num> is optional but it is the lower bound on the number of
-alphanumeric characters that git must detect as moving
+alphanumeric characters that git must detect as moving/copying
within a file for it to associate those lines with the parent
-commit.
+commit. The default value is 20.
-C|<num>|::
In addition to `-M`, detect lines moved or copied from other
@@ -105,9 +105,11 @@ commit.
looks for copies from other files in any commit.
+
<num> is optional but it is the lower bound on the number of
-alphanumeric characters that git must detect as moving
+alphanumeric characters that git must detect as moving/copying
between files for it to associate those lines with the parent
-commit.
+commit. And the default value is 40. If there are more than one
+`-C` options given, the <num> argument of the last `-C` will
+take effect.
-h::
--help::
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 92f851e797..ae174c99db 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -518,18 +518,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
@@ -1359,10 +1353,6 @@ notes.rewrite.<command>::
automatically copies your notes from the original to the
rewritten commit. Defaults to `true`, but see
"notes.rewriteRef" below.
-+
-This setting can be overridden with the `GIT_NOTES_REWRITE_REF`
-environment variable, which must be a colon separated list of refs or
-globs.
notes.rewriteMode::
When copying notes during a rewrite (see the
@@ -1382,6 +1372,10 @@ notes.rewriteRef::
+
Does not have a default value; you must configure this variable to
enable note rewriting.
++
+This setting can be overridden with the `GIT_NOTES_REWRITE_REF`
+environment variable, which must be a colon separated list of refs or
+globs.
pack.window::
The size of the window used by linkgit:git-pack-objects[1] when no
@@ -1516,7 +1510,7 @@ receive.denyDeletes::
the ref. Use this to prevent such a ref deletion via a push.
receive.denyCurrentBranch::
- If set to true or "refuse", receive-pack will deny a ref update
+ If set to true or "refuse", git-receive-pack will deny a ref update
to the currently checked out branch of a non-bare repository.
Such a push is potentially dangerous because it brings the HEAD
out of sync with the index and working tree. If set to "warn",
@@ -1642,6 +1636,7 @@ sendemail.smtppass::
sendemail.suppresscc::
sendemail.suppressfrom::
sendemail.to::
+sendemail.smtpdomain::
sendemail.smtpserver::
sendemail.smtpserverport::
sendemail.smtpuser::
@@ -1681,6 +1676,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 c9c6c2b1cb..3070dddfe2 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -177,7 +177,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 37c1810e3f..a3a87fa7fd 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -136,6 +136,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 64fb458b45..69eb86e450 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-log.txt b/Documentation/git-log.txt
index fb184ba186..d7f6a9cc3e 100644
--- a/Documentation/git-log.txt
+++ b/Documentation/git-log.txt
@@ -132,6 +132,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-notes.txt b/Documentation/git-notes.txt
index 4e5113b837..de63ef0745 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
--------
@@ -20,24 +20,26 @@ SYNOPSIS
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,144 @@ 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.
-NOTES
------
+DISCUSSION
+----------
+
+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
+-------------
+
+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.
-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.
+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 0d07b1b207..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,
@@ -295,6 +299,7 @@ link:howto/revert-a-faulty-merge.txt[revert-a-faulty-merge How-To] for details).
--ignore-date::
These flags are passed to 'git am' to easily change the dates
of the rebased commits (see linkgit:git-am[1]).
+ Incompatible with the --interactive option.
-i::
--interactive::
diff --git a/Documentation/git-send-email.txt b/Documentation/git-send-email.txt
index ced35b2f53..12622fc49a 100644
--- a/Documentation/git-send-email.txt
+++ b/Documentation/git-send-email.txt
@@ -119,6 +119,13 @@ Sending
value reverts to plain SMTP. Default is the value of
'sendemail.smtpencryption'.
+--smtp-domain=<FQDN>::
+ Specifies the Fully Qualified Domain Name (FQDN) used in the
+ HELO/EHLO command to the SMTP server. Some servers require the
+ FQDN to match your IP address. If not set, git send-email attempts
+ to determine your FQDN automatically. Default is the value of
+ 'sendemail.smtpdomain'.
+
--smtp-pass[=<password>]::
Password for SMTP-AUTH. The argument is optional: If no
argument is specified, then the empty string is used as
@@ -300,6 +307,21 @@ sendemail.confirm::
in the previous section for the meaning of these values.
+Use gmail as the smtp server
+----------------------------
+
+Add the following section to the config file:
+
+ [sendemail]
+ smtpencryption = tls
+ smtpserver = smtp.gmail.com
+ smtpuser = yourname@gmail.com
+ smtpserverport = 587
+
+Note: the following perl modules are required
+ Net::SMTP::SSL, MIME::Base64 and Authen::SASL
+
+
Author
------
Written by Ryan Anderson <ryan@michonline.com>
diff --git a/Documentation/git-shortlog.txt b/Documentation/git-shortlog.txt
index dfd4d0c223..bc1ac77495 100644
--- a/Documentation/git-shortlog.txt
+++ b/Documentation/git-shortlog.txt
@@ -9,7 +9,7 @@ SYNOPSIS
--------
[verse]
git log --pretty=short | 'git shortlog' [-h] [-n] [-s] [-e] [-w]
-'git shortlog' [-n|--numbered] [-s|--summary] [-e|--email] [-w[<width>[,<indent1>[,<indent2>]]]] [<committish>...]
+'git shortlog' [-n|--numbered] [-s|--summary] [-e|--email] [-w[<width>[,<indent1>[,<indent2>]]]] <commit>...
DESCRIPTION
-----------
@@ -19,6 +19,11 @@ the first line of the commit message will be shown.
Additionally, "[PATCH]" will be stripped from the commit description.
+If no revisions are passed on the command line and either standard input
+is not a terminal or there is no current branch, 'git shortlog' will
+output a summary of the log read from standard input, without
+reference to the current repository.
+
OPTIONS
-------
@@ -39,6 +44,14 @@ OPTIONS
--email::
Show the email address of each author.
+--format[='<format>']::
+ Instead of the commit subject, use some other information to
+ describe each commit. '<format>' can be any string accepted
+ by the `--format` option of 'git log', such as '{asterisk} [%h] %s'.
+ (See the "PRETTY FORMATS" section of linkgit:git-log[1].)
+
+ Each pretty-printed commit will be rewrapped before it is shown.
+
-w[<width>[,<indent1>[,<indent2>]]]::
Linewrap the output by wrapping each line at `width`. The first
line of each entry is indented by `indent1` spaces, and the second
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/gitdiffcore.txt b/Documentation/gitdiffcore.txt
index 9de8caf5d1..5d91a7e5b3 100644
--- a/Documentation/gitdiffcore.txt
+++ b/Documentation/gitdiffcore.txt
@@ -227,8 +227,8 @@ changes that touch a specified string, and is controlled by the
commands.
When diffcore-pickaxe is in use, it checks if there are
-filepairs whose "original" side has the specified string and
-whose "result" side does not. Such a filepair represents "the
+filepairs whose "result" side has the specified string and
+whose "origin" side does not. Such a filepair represents "the
string appeared in this changeset". It also checks for the
opposite case that loses the specified string.
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 1686a54d22..c85a52c0cc 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -76,9 +76,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/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 0ad39484ec..82fd72652b 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -12,7 +12,7 @@ if test -f version
then
VN=$(cat version) || VN="$DEF_VER"
elif test -d .git -o -f .git &&
- VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
+ VN=$(git describe --match "v[0-9]*" --abbrev=4 HEAD 2>/dev/null) &&
case "$VN" in
*$LF*) (exit 1) ;;
v[0-9]*)
diff --git a/Makefile b/Makefile
index 910f4713ef..b18768e0ae 100644
--- a/Makefile
+++ b/Makefile
@@ -31,6 +31,9 @@ all::
# Define EXPATDIR=/foo/bar if your expat header and library files are in
# /foo/bar/include and /foo/bar/lib directories.
#
+# Define HAVE_PATHS_H if you have paths.h and want to use the default PATH
+# it specifies.
+#
# Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent.
#
# Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks
@@ -735,10 +738,12 @@ EXTLIBS =
ifeq ($(uname_S),Linux)
NO_STRLCPY = YesPlease
NO_MKSTEMPS = YesPlease
+ HAVE_PATHS_H = YesPlease
endif
ifeq ($(uname_S),GNU/kFreeBSD)
NO_STRLCPY = YesPlease
NO_MKSTEMPS = YesPlease
+ HAVE_PATHS_H = YesPlease
endif
ifeq ($(uname_S),UnixWare)
CC = cc
@@ -867,6 +872,7 @@ ifeq ($(uname_S),FreeBSD)
NO_STRTOUMAX = YesPlease
endif
PYTHON_PATH = /usr/local/bin/python
+ HAVE_PATHS_H = YesPlease
endif
ifeq ($(uname_S),OpenBSD)
NO_STRCASESTR = YesPlease
@@ -875,6 +881,7 @@ ifeq ($(uname_S),OpenBSD)
NEEDS_LIBICONV = YesPlease
BASIC_CFLAGS += -I/usr/local/include
BASIC_LDFLAGS += -L/usr/local/lib
+ HAVE_PATHS_H = YesPlease
endif
ifeq ($(uname_S),NetBSD)
ifeq ($(shell expr "$(uname_R)" : '[01]\.'),2)
@@ -884,8 +891,10 @@ ifeq ($(uname_S),NetBSD)
BASIC_LDFLAGS += -L/usr/pkg/lib $(CC_LD_DYNPATH)/usr/pkg/lib
USE_ST_TIMESPEC = YesPlease
NO_MKSTEMPS = YesPlease
+ HAVE_PATHS_H = YesPlease
endif
ifeq ($(uname_S),AIX)
+ DEFAULT_PAGER = more
NO_STRCASESTR=YesPlease
NO_MEMMEM = YesPlease
NO_MKDTEMP = YesPlease
@@ -904,6 +913,7 @@ ifeq ($(uname_S),GNU)
# GNU/Hurd
NO_STRLCPY=YesPlease
NO_MKSTEMPS = YesPlease
+ HAVE_PATHS_H = YesPlease
endif
ifeq ($(uname_S),IRIX)
NO_SETENV = YesPlease
@@ -1353,6 +1363,10 @@ else
LIB_OBJS += thread-utils.o
endif
+ifdef HAVE_PATHS_H
+ BASIC_CFLAGS += -DHAVE_PATHS_H
+endif
+
ifdef DIR_HAS_BSD_GROUP_SEMANTICS
COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS
endif
@@ -1996,12 +2010,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-doc:
@@ -2098,7 +2113,7 @@ clean:
$(RM) $(htmldocs).tar.gz $(manpages).tar.gz
$(MAKE) -C Documentation/ clean
ifndef NO_PERL
- $(RM) gitweb/gitweb.cgi gitweb/gitweb.min.*
+ $(MAKE) -C gitweb clean
$(MAKE) -C perl clean
endif
ifndef NO_PYTHON
diff --git a/RelNotes b/RelNotes
index 00e77229dd..136c1b6afa 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes-1.7.1.txt \ No newline at end of file
+Documentation/RelNotes-1.7.1.1.txt \ No newline at end of file
diff --git a/attr.c b/attr.c
index f5346ed32a..7467baf2d6 100644
--- a/attr.c
+++ b/attr.c
@@ -594,20 +594,25 @@ static int path_matches(const char *pathname, int pathlen,
return fnmatch(pattern, pathname + baselen, FNM_PATHNAME) == 0;
}
+static int macroexpand_one(int attr_nr, int rem);
+
static int fill_one(const char *what, struct match_attr *a, int rem)
{
struct git_attr_check *check = check_all_attr;
int i;
- for (i = 0; 0 < rem && i < a->num_attr; i++) {
+ for (i = a->num_attr - 1; 0 < rem && 0 <= i; i--) {
struct git_attr *attr = a->state[i].attr;
const char **n = &(check[attr->attr_nr].value);
const char *v = a->state[i].setto;
if (*n == ATTR__UNKNOWN) {
- debug_set(what, a->u.pattern, attr, v);
+ debug_set(what,
+ a->is_macro ? a->u.attr->name : a->u.pattern,
+ attr, v);
*n = v;
rem--;
+ rem = macroexpand_one(attr->attr_nr, rem);
}
}
return rem;
@@ -629,19 +634,27 @@ static int fill(const char *path, int pathlen, struct attr_stack *stk, int rem)
return rem;
}
-static int macroexpand(struct attr_stack *stk, int rem)
+static int macroexpand_one(int attr_nr, int rem)
{
+ struct attr_stack *stk;
+ struct match_attr *a = NULL;
int i;
- struct git_attr_check *check = check_all_attr;
- for (i = stk->num_matches - 1; 0 < rem && 0 <= i; i--) {
- struct match_attr *a = stk->attrs[i];
- if (!a->is_macro)
- continue;
- if (check[a->u.attr->attr_nr].value != ATTR__TRUE)
- continue;
+ if (check_all_attr[attr_nr].value != ATTR__TRUE)
+ return rem;
+
+ for (stk = attr_stack; !a && stk; stk = stk->prev)
+ for (i = stk->num_matches - 1; !a && 0 <= i; i--) {
+ struct match_attr *ma = stk->attrs[i];
+ if (!ma->is_macro)
+ continue;
+ if (ma->u.attr->attr_nr == attr_nr)
+ a = ma;
+ }
+
+ if (a)
rem = fill_one("expand", a, rem);
- }
+
return rem;
}
@@ -666,9 +679,6 @@ int git_checkattr(const char *path, int num, struct git_attr_check *check)
for (stk = attr_stack; 0 < rem && stk; stk = stk->prev)
rem = fill(path, pathlen, stk, rem);
- for (stk = attr_stack; 0 < rem && stk; stk = stk->prev)
- rem = macroexpand(stk, rem);
-
for (i = 0; i < num; i++) {
const char *value = check_all_attr[check[i].attr->attr_nr].value;
if (value == ATTR__UNKNOWN)
diff --git a/builtin/apply.c b/builtin/apply.c
index 771c972c55..59bbcdb132 100644
--- a/builtin/apply.c
+++ b/builtin/apply.c
@@ -1864,13 +1864,13 @@ static int match_fragment(struct image *img,
if (match_end && (preimage->nr + try_lno != img->nr))
return 0;
} else if (ws_error_action == correct_ws_error &&
- (ws_rule & WS_BLANK_AT_EOF) && match_end) {
+ (ws_rule & WS_BLANK_AT_EOF)) {
/*
- * This hunk that matches at the end extends beyond
- * the end of img, and we are removing blank lines
- * at the end of the file. This many lines from the
- * beginning of the preimage must match with img, and
- * the remainder of the preimage must be blank.
+ * This hunk extends beyond the end of img, and we are
+ * removing blank lines at the end of the file. This
+ * many lines from the beginning of the preimage must
+ * match with img, and the remainder of the preimage
+ * must be blank.
*/
preimage_limit = img->nr - try_lno;
} else {
@@ -3141,11 +3141,7 @@ static void remove_file(struct patch *patch, int rmdir_empty)
die("unable to remove %s from index", patch->old_name);
}
if (!cached) {
- if (S_ISGITLINK(patch->old_mode)) {
- if (rmdir(patch->old_name))
- warning("unable to remove submodule %s",
- patch->old_name);
- } else if (!unlink_or_warn(patch->old_name) && rmdir_empty) {
+ if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) {
remove_path(patch->old_name);
}
}
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/commit.c b/builtin/commit.c
index c5ab683d5b..278dcdfa62 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -455,15 +455,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) {
@@ -1017,6 +1023,7 @@ static int git_status_config(const char *k, const char *v, void *cb)
int cmd_status(int argc, const char **argv, const char *prefix)
{
struct wt_status s;
+ int fd;
unsigned char sha1[20];
static struct option builtin_status_options[] = {
OPT__VERBOSE(&verbose),
@@ -1050,6 +1057,14 @@ int cmd_status(int argc, const char **argv, const char *prefix)
read_cache_preload(s.pathspec);
refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, s.pathspec, NULL, NULL);
+
+ fd = hold_locked_index(&index_lock, 0);
+ if (0 <= fd) {
+ if (!write_cache(fd, active_cache, active_nr))
+ commit_locked_index(&index_lock);
+ rollback_lock_file(&index_lock);
+ }
+
s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;
s.in_merge = in_merge;
wt_status_collect(&s);
diff --git a/builtin/describe.c b/builtin/describe.c
index 71be2a9364..43caff2ffe 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -35,7 +35,8 @@ static const char *diff_index_args[] = {
struct commit_name {
struct tag *tag;
- int prio; /* annotated tag = 2, tag = 1, head = 0 */
+ unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
+ unsigned name_checked:1;
unsigned char sha1[20];
char path[FLEX_ARRAY]; /* more */
};
@@ -43,18 +44,53 @@ static const char *prio_names[] = {
"head", "lightweight", "annotated",
};
+static int replace_name(struct commit_name *e,
+ int prio,
+ const unsigned char *sha1,
+ struct tag **tag)
+{
+ if (!e || e->prio < prio)
+ return 1;
+
+ if (e->prio == 2 && prio == 2) {
+ /* Multiple annotated tags point to the same commit.
+ * Select one to keep based upon their tagger date.
+ */
+ struct tag *t;
+
+ if (!e->tag) {
+ t = lookup_tag(e->sha1);
+ if (!t || parse_tag(t))
+ return 1;
+ e->tag = t;
+ }
+
+ t = lookup_tag(sha1);
+ if (!t || parse_tag(t))
+ return 0;
+ *tag = t;
+
+ if (e->tag->date < t->date)
+ return 1;
+ }
+
+ return 0;
+}
+
static void add_to_known_names(const char *path,
struct commit *commit,
int prio,
const unsigned char *sha1)
{
struct commit_name *e = commit->util;
- if (!e || e->prio < prio) {
+ struct tag *tag = NULL;
+ if (replace_name(e, prio, sha1, &tag)) {
size_t len = strlen(path)+1;
free(e);
e = xmalloc(sizeof(struct commit_name) + len);
- e->tag = NULL;
+ e->tag = tag;
e->prio = prio;
+ e->name_checked = 0;
hashcpy(e->sha1, sha1);
memcpy(e->path, path, len);
commit->util = e;
@@ -165,10 +201,15 @@ static void display_name(struct commit_name *n)
{
if (n->prio == 2 && !n->tag) {
n->tag = lookup_tag(n->sha1);
- if (!n->tag || parse_tag(n->tag) || !n->tag->tag)
+ if (!n->tag || parse_tag(n->tag))
die("annotated tag %s not available", n->path);
+ }
+ if (n->tag && !n->name_checked) {
+ if (!n->tag->tag)
+ die("annotated tag %s has no embedded name", n->path);
if (strcmp(n->tag->tag, all ? n->path + 5 : n->path))
warning("tag '%s' is really '%s' here", n->tag->tag, n->path);
+ n->name_checked = 1;
}
if (n->tag)
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
index 62be1bbfd6..7f5011f75e 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -549,10 +549,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 8e928e2170..b194ea3cea 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -17,8 +17,8 @@
#include "dir.h"
#ifndef NO_PTHREADS
-#include "thread-utils.h"
#include <pthread.h>
+#include "thread-utils.h"
#endif
static char const * const grep_usage[] = {
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 03d0cd2f47..a89ae831dd 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -266,26 +266,23 @@ static void unlink_base_data(struct base_data *c)
static void *unpack_entry_data(unsigned long offset, unsigned long size)
{
+ int status;
z_stream stream;
void *buf = xmalloc(size);
memset(&stream, 0, sizeof(stream));
+ git_inflate_init(&stream);
stream.next_out = buf;
stream.avail_out = size;
- stream.next_in = fill(1);
- stream.avail_in = input_len;
- git_inflate_init(&stream);
- for (;;) {
- int ret = git_inflate(&stream, 0);
- use(input_len - stream.avail_in);
- if (stream.total_out == size && ret == Z_STREAM_END)
- break;
- if (ret != Z_OK)
- bad_object(offset, "inflate returned %d", ret);
+ do {
stream.next_in = fill(1);
stream.avail_in = input_len;
- }
+ status = git_inflate(&stream, 0);
+ use(input_len - stream.avail_in);
+ } while (status == Z_OK);
+ if (stream.total_out != size || status != Z_STREAM_END)
+ bad_object(offset, "inflate returned %d", status);
git_inflate_end(&stream);
return buf;
}
@@ -359,34 +356,38 @@ static void *get_data_from_pack(struct object_entry *obj)
{
off_t from = obj[0].idx.offset + obj[0].hdr_size;
unsigned long len = obj[1].idx.offset - from;
- unsigned long rdy = 0;
- unsigned char *src, *data;
+ unsigned char *data, *inbuf;
z_stream stream;
- int st;
+ int status;
- src = xmalloc(len);
- data = src;
- do {
- ssize_t n = pread(pack_fd, data + rdy, len - rdy, from + rdy);
- if (n < 0)
- die_errno("cannot pread pack file");
- if (!n)
- die("premature end of pack file, %lu bytes missing",
- len - rdy);
- rdy += n;
- } while (rdy < len);
data = xmalloc(obj->size);
+ inbuf = xmalloc((len < 64*1024) ? len : 64*1024);
+
memset(&stream, 0, sizeof(stream));
+ git_inflate_init(&stream);
stream.next_out = data;
stream.avail_out = obj->size;
- stream.next_in = src;
- stream.avail_in = len;
- git_inflate_init(&stream);
- while ((st = git_inflate(&stream, Z_FINISH)) == Z_OK);
- git_inflate_end(&stream);
- if (st != Z_STREAM_END || stream.total_out != obj->size)
+
+ do {
+ ssize_t n = (len < 64*1024) ? len : 64*1024;
+ n = pread(pack_fd, inbuf, n, from);
+ if (n < 0)
+ die_errno("cannot pread pack file");
+ if (!n)
+ die("premature end of pack file, %lu bytes missing", len);
+ from += n;
+ len -= n;
+ stream.next_in = inbuf;
+ stream.avail_in = n;
+ status = git_inflate(&stream, 0);
+ } while (len && status == Z_OK && !stream.avail_in);
+
+ /* This has been inflated OK when first encountered, so... */
+ if (status != Z_STREAM_END || stream.total_out != obj->size)
die("serious inflate inconsistency");
- free(src);
+
+ git_inflate_end(&stream);
+ free(inbuf);
return data;
}
@@ -668,25 +669,25 @@ static void parse_pack_objects(unsigned char *sha1)
static int write_compressed(struct sha1file *f, void *in, unsigned int size)
{
z_stream stream;
- unsigned long maxsize;
- void *out;
+ int status;
+ unsigned char outbuf[4096];
memset(&stream, 0, sizeof(stream));
deflateInit(&stream, zlib_compression_level);
- maxsize = deflateBound(&stream, size);
- out = xmalloc(maxsize);
-
- /* Compress it */
stream.next_in = in;
stream.avail_in = size;
- stream.next_out = out;
- stream.avail_out = maxsize;
- while (deflate(&stream, Z_FINISH) == Z_OK);
- deflateEnd(&stream);
+ do {
+ stream.next_out = outbuf;
+ stream.avail_out = sizeof(outbuf);
+ status = deflate(&stream, Z_FINISH);
+ sha1write(f, outbuf, sizeof(outbuf) - stream.avail_out);
+ } while (status == Z_OK);
+
+ if (status != Z_STREAM_END)
+ die("unable to deflate appended object (%d)", status);
size = stream.total_out;
- sha1write(f, out, size);
- free(out);
+ deflateEnd(&stream);
return size;
}
diff --git a/builtin/init-db.c b/builtin/init-db.c
index edc40ff574..0271285fad 100644
--- a/builtin/init-db.c
+++ b/builtin/init-db.c
@@ -463,7 +463,7 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
static char git_dir[PATH_MAX+1];
setenv(GIT_DIR_ENVIRONMENT,
- getcwd(git_dir, sizeof(git_dir)), 0);
+ getcwd(git_dir, sizeof(git_dir)), argc > 0);
}
if (init_shared_repository != -1)
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/notes.c b/builtin/notes.c
index 52b72fca68..26617546c8 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -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) {
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 97802585ea..214d7ef2b1 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -18,8 +18,8 @@
#include "refs.h"
#ifndef NO_PTHREADS
-#include "thread-utils.h"
#include <pthread.h>
+#include "thread-utils.h"
#endif
static const char pack_usage[] =
@@ -1522,6 +1522,13 @@ static void find_deltas(struct object_entry **list, unsigned *list_size,
#ifndef NO_PTHREADS
+static void try_to_free_from_threads(size_t size)
+{
+ read_lock();
+ release_pack_memory(size, -1);
+ read_unlock();
+}
+
/*
* 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
@@ -1552,14 +1559,16 @@ static pthread_cond_t progress_cond;
*/
static void init_threaded_search(void)
{
- pthread_mutex_init(&read_mutex, NULL);
+ init_recursive_mutex(&read_mutex);
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);
}
static void cleanup_threaded_search(void)
{
+ set_try_to_free_routine(NULL);
pthread_cond_destroy(&progress_cond);
pthread_mutex_destroy(&read_mutex);
pthread_mutex_destroy(&cache_mutex);
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/builtin/revert.c b/builtin/revert.c
index 778a56eb51..7d68ef714e 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -109,8 +109,13 @@ static int get_message(const char *raw_message, struct commit_message *out)
encoding = "UTF-8";
if (!git_commit_encoding)
git_commit_encoding = "UTF-8";
- if ((out->reencoded_message = reencode_string(raw_message,
- git_commit_encoding, encoding)))
+
+ out->reencoded_message = NULL;
+ out->message = raw_message;
+ if (strcmp(encoding, git_commit_encoding))
+ out->reencoded_message = reencode_string(raw_message,
+ git_commit_encoding, encoding);
+ if (out->reencoded_message)
out->message = out->reencoded_message;
abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
index 06320f5285..5089502800 100644
--- a/builtin/shortlog.c
+++ b/builtin/shortlog.c
@@ -162,7 +162,7 @@ void shortlog_add_commit(struct shortlog *log, struct commit *commit)
sha1_to_hex(commit->object.sha1));
if (log->user_format) {
struct pretty_print_context ctx = {0};
- ctx.abbrev = DEFAULT_ABBREV;
+ ctx.abbrev = log->abbrev;
ctx.subject = "";
ctx.after_subject = "";
ctx.date_mode = DATE_NORMAL;
@@ -290,6 +290,7 @@ parse_done:
}
log.user_format = rev.commit_format == CMIT_FMT_USERFORMAT;
+ log.abbrev = rev.abbrev;
/* assume HEAD if from a tty */
if (!nongit && !rev.pending.nr && isatty(0))
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index e20fcf3e93..e8719aa9e9 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -313,7 +313,8 @@ static void show_one_commit(struct commit *commit, int no_name)
}
else
printf("[%s] ",
- find_unique_abbrev(commit->object.sha1, 7));
+ find_unique_abbrev(commit->object.sha1,
+ DEFAULT_ABBREV));
}
puts(pretty_str);
strbuf_release(&pretty);
diff --git a/cache.h b/cache.h
index 5eb0573bcc..0d101e4913 100644
--- a/cache.h
+++ b/cache.h
@@ -905,7 +905,7 @@ struct extra_have_objects {
extern struct ref **get_remote_heads(int in, struct ref **list, int nr_match, char **match, unsigned int flags, struct extra_have_objects *);
extern int server_supports(const char *feature);
-extern struct packed_git *parse_pack_index(unsigned char *sha1);
+extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
extern void prepare_packed_git(void);
extern void reprepare_packed_git(void);
@@ -916,6 +916,7 @@ extern struct packed_git *find_sha1_pack(const unsigned char *sha1,
extern void pack_report(void);
extern int open_pack_index(struct packed_git *);
+extern void close_pack_index(struct packed_git *);
extern unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned int *);
extern void close_pack_windows(struct packed_git *);
extern void unuse_pack(struct pack_window **);
diff --git a/combine-diff.c b/combine-diff.c
index 3480dae824..655fa89d8a 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -211,7 +211,6 @@ static void combine_diff(const unsigned char *parent, unsigned int mode,
xpparam_t xpp;
xdemitconf_t xecfg;
mmfile_t parent_file;
- xdemitcb_t ecb;
struct combine_diff_state state;
unsigned long sz;
@@ -221,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;
@@ -231,7 +230,7 @@ static void combine_diff(const unsigned char *parent, unsigned int mode,
state.n = n;
xdi_diff_outf(&parent_file, result_file, consume_line, &state,
- &xpp, &xecfg, &ecb);
+ &xpp, &xecfg);
free(parent_file.ptr);
/* Assign line numbers for this parent.
diff --git a/compat/mingw.c b/compat/mingw.c
index f90a114b02..9a8e336582 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -140,6 +140,23 @@ int mingw_open (const char *filename, int oflags, ...)
return fd;
}
+#undef write
+ssize_t mingw_write(int fd, const void *buf, size_t count)
+{
+ /*
+ * While write() calls to a file on a local disk are translated
+ * into WriteFile() calls with a maximum size of 64KB on Windows
+ * XP and 256KB on Vista, no such cap is placed on writes to
+ * files over the network on Windows XP. Unfortunately, there
+ * seems to be a limit of 32MB-28KB on X64 and 64MB-32KB on x86;
+ * bigger writes fail on Windows XP.
+ * So we cap to a nice 31MB here to avoid write failures over
+ * the net without changing the number of WriteFile() calls in
+ * the local case.
+ */
+ return write(fd, buf, min(count, 31 * 1024 * 1024));
+}
+
#undef fopen
FILE *mingw_fopen (const char *filename, const char *otype)
{
diff --git a/compat/mingw.h b/compat/mingw.h
index 7c2ab64cb4..0e3e743041 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -170,6 +170,9 @@ int link(const char *oldpath, const char *newpath);
int mingw_open (const char *filename, int oflags, ...);
#define open mingw_open
+ssize_t mingw_write(int fd, const void *buf, size_t count);
+#define write mingw_write
+
FILE *mingw_fopen (const char *filename, const char *otype);
#define fopen mingw_fopen
diff --git a/compat/win32/pthread.h b/compat/win32/pthread.h
index c72f100f40..a45f8d66df 100644
--- a/compat/win32/pthread.h
+++ b/compat/win32/pthread.h
@@ -18,11 +18,17 @@
*/
#define pthread_mutex_t CRITICAL_SECTION
-#define pthread_mutex_init(a,b) InitializeCriticalSection((a))
+#define pthread_mutex_init(a,b) (InitializeCriticalSection((a)), 0)
#define pthread_mutex_destroy(a) DeleteCriticalSection((a))
#define pthread_mutex_lock EnterCriticalSection
#define pthread_mutex_unlock LeaveCriticalSection
+typedef int pthread_mutexattr_t;
+#define pthread_mutexattr_init(a) (*(a) = 0)
+#define pthread_mutexattr_destroy(a) do {} while (0)
+#define pthread_mutexattr_settype(a, t) 0
+#define PTHREAD_MUTEX_RECURSIVE 0
+
/*
* Implement simple condition variable for Windows threads, based on ACE
* implementation.
diff --git a/compat/win32mmap.c b/compat/win32mmap.c
index 1c5a14922f..b58aa69fa0 100644
--- a/compat/win32mmap.c
+++ b/compat/win32mmap.c
@@ -4,19 +4,19 @@ void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t of
{
HANDLE hmap;
void *temp;
- size_t len;
+ off_t len;
struct stat st;
uint64_t o = offset;
uint32_t l = o & 0xFFFFFFFF;
uint32_t h = (o >> 32) & 0xFFFFFFFF;
if (!fstat(fd, &st))
- len = xsize_t(st.st_size);
+ len = st.st_size;
else
die("mmap: could not determine filesize");
if ((length + offset) > len)
- length = len - offset;
+ length = xsize_t(len - offset);
if (!(flags & MAP_PRIVATE))
die("Invalid usage of mmap when built with USE_WIN32_MMAP");
diff --git a/config.mak.in b/config.mak.in
index 6008ac9f1b..0d4b64d076 100644
--- a/config.mak.in
+++ b/config.mak.in
@@ -31,6 +31,7 @@ NO_OPENSSL=@NO_OPENSSL@
NO_CURL=@NO_CURL@
NO_EXPAT=@NO_EXPAT@
NO_LIBGEN_H=@NO_LIBGEN_H@
+HAVE_PATHS_H=@HAVE_PATHS_H@
NEEDS_LIBICONV=@NEEDS_LIBICONV@
NEEDS_SOCKET=@NEEDS_SOCKET@
NEEDS_RESOLV=@NEEDS_RESOLV@
diff --git a/configure.ac b/configure.ac
index f4d7372ef8..71038fcf1c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -724,6 +724,12 @@ AC_CHECK_HEADER([libgen.h],
[NO_LIBGEN_H=YesPlease])
AC_SUBST(NO_LIBGEN_H)
#
+# Define HAVE_PATHS_H if you have paths.h.
+AC_CHECK_HEADER([paths.h],
+[HAVE_PATHS_H=YesPlease],
+[HAVE_PATHS_H=])
+AC_SUBST(HAVE_PATHS_H)
+#
# Define NO_STRCASESTR if you don't have strcasestr.
GIT_CHECK_FUNC(strcasestr,
[NO_STRCASESTR=],
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/contrib/hooks/post-receive-email b/contrib/hooks/post-receive-email
index 58a35c8287..30ae63d74d 100755
--- a/contrib/hooks/post-receive-email
+++ b/contrib/hooks/post-receive-email
@@ -23,6 +23,13 @@
# possible for the email to be from someone other than the person doing the
# push.
#
+# To help with debugging and use on pre-v1.5.1 git servers, this script will
+# also obey the interface of hooks/update, taking its arguments on the
+# command line. Unfortunately, hooks/update is called once for each ref.
+# To avoid firing one email per ref, this script just prints its output to
+# the screen when used in this mode. The output can then be redirected if
+# wanted.
+#
# Config
# ------
# hooks.mailinglist
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-no-index.c b/diff-no-index.c
index aae8e7accc..4cd9dacbe8 100644
--- a/diff-no-index.c
+++ b/diff-no-index.c
@@ -150,16 +150,14 @@ static int queue_diff(struct diff_options *o,
static int path_outside_repo(const char *path)
{
- /*
- * We have already done setup_git_directory_gently() so we
- * know we are inside a git work tree already.
- */
const char *work_tree;
size_t len;
if (!is_absolute_path(path))
return 0;
work_tree = get_git_work_tree();
+ if (!work_tree)
+ return 1;
len = strlen(work_tree);
if (strncmp(path, work_tree, len) ||
(path[len] != '\0' && path[len] != '/'))
diff --git a/diff.c b/diff.c
index d0ecbc3540..230c310952 100644
--- a/diff.c
+++ b/diff.c
@@ -700,7 +700,6 @@ static void diff_words_show(struct diff_words_data *diff_words)
{
xpparam_t xpp;
xdemitconf_t xecfg;
- xdemitcb_t ecb;
mmfile_t minus, plus;
/* special case: only removal */
@@ -718,11 +717,11 @@ 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,
- &xpp, &xecfg, &ecb);
+ &xpp, &xecfg);
free(minus.ptr);
free(plus.ptr);
if (diff_words->current_plus != diff_words->plus.text.ptr +
@@ -1650,21 +1649,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
@@ -1708,7 +1707,6 @@ static void builtin_diff(const char *name_a,
const char *diffopts = getenv("GIT_DIFF_OPTS");
xpparam_t xpp;
xdemitconf_t xecfg;
- xdemitcb_t ecb;
struct emit_callback ecbdata;
const struct userdiff_funcname *pe;
@@ -1747,7 +1745,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;
@@ -1780,7 +1778,7 @@ static void builtin_diff(const char *name_a,
}
}
xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata,
- &xpp, &xecfg, &ecb);
+ &xpp, &xecfg);
if (DIFF_OPT_TST(o, COLOR_DIFF_WORDS))
free_diff_words_data(&ecbdata);
if (textconv_one)
@@ -1833,13 +1831,12 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
/* Crazy xdl interfaces.. */
xpparam_t xpp;
xdemitconf_t xecfg;
- xdemitcb_t ecb;
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, &ecb);
+ &xpp, &xecfg);
}
free_and_return:
@@ -1881,14 +1878,13 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
/* Crazy xdl interfaces.. */
xpparam_t xpp;
xdemitconf_t xecfg;
- xdemitcb_t ecb;
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, &ecb);
+ &xpp, &xecfg);
if (data.ws_rule & WS_BLANK_AT_EOF) {
struct emit_callback ecbdata;
@@ -2323,30 +2319,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 */
@@ -2363,15 +2365,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,
@@ -2387,11 +2387,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 {
@@ -2400,6 +2395,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);
@@ -3383,7 +3388,6 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
for (i = 0; i < q->nr; i++) {
xpparam_t xpp;
xdemitconf_t xecfg;
- xdemitcb_t ecb;
mmfile_t mf1, mf2;
struct diff_filepair *p = q->queue[i];
int len1, len2;
@@ -3441,11 +3445,11 @@ 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,
- &xpp, &xecfg, &ecb);
+ &xpp, &xecfg);
}
git_SHA1_Final(sha1, &ctx);
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/exec_cmd.c b/exec_cmd.c
index b2c07c70ce..bf225706ee 100644
--- a/exec_cmd.c
+++ b/exec_cmd.c
@@ -107,7 +107,7 @@ void setup_path(void)
if (old_path)
strbuf_addstr(&new_path, old_path);
else
- strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin");
+ strbuf_addstr(&new_path, _PATH_DEFPATH);
setenv("PATH", new_path.buf, 1);
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-am.sh b/git-am.sh
index 1056075545..87ffae252b 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -740,7 +740,7 @@ do
;;
esac
- if test $apply_status = 1 && test "$threeway" = t
+ if test $apply_status != 0 && test "$threeway" = t
then
if (fall_back_3way)
then
diff --git a/git-compat-util.h b/git-compat-util.h
index 7e62b55270..c0198dde4c 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
@@ -164,6 +164,13 @@ extern char *gitbasename(char *);
#define PATH_SEP ':'
#endif
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#ifndef _PATH_DEFPATH
+#define _PATH_DEFPATH "/usr/local/bin:/usr/bin:/bin"
+#endif
+
#ifndef STRIP_EXTENSION
#define STRIP_EXTENSION ""
#endif
@@ -356,6 +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));
+
extern char *xstrdup(const char *str);
extern void *xmalloc(size_t size);
extern void *xmallocz(size_t size);
@@ -479,5 +488,14 @@ void git_qsort(void *base, size_t nmemb, size_t size,
* Always returns the return value of unlink(2).
*/
int unlink_or_warn(const char *path);
+/*
+ * Likewise for rmdir(2).
+ */
+int rmdir_or_warn(const char *path);
+/*
+ * Calls the correct function out of {unlink,rmdir}_or_warn based on
+ * the supplied file mode.
+ */
+int remove_or_warn(unsigned int mode, const char *path);
#endif
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-send-email.perl b/git-send-email.perl
index ce569a9c8f..111c981229 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -132,8 +132,6 @@ my $have_email_valid = eval { require Email::Valid; 1 };
my $have_mail_address = eval { require Mail::Address; 1 };
my $smtp;
my $auth;
-my $mail_domain_default = "localhost.localdomain";
-my $mail_domain;
sub unique_email_list(@);
sub cleanup_compose_files();
@@ -190,7 +188,7 @@ sub do_edit {
# Variables with corresponding config settings
my ($thread, $chain_reply_to, $suppress_from, $signed_off_by_cc, $cc_cmd);
my ($smtp_server, $smtp_server_port, $smtp_authuser, $smtp_encryption);
-my ($identity, $aliasfiletype, @alias_files, @smtp_host_parts);
+my ($identity, $aliasfiletype, @alias_files, @smtp_host_parts, $smtp_domain);
my ($validate, $confirm);
my (@suppress_cc);
@@ -212,6 +210,7 @@ my %config_settings = (
"smtpserverport" => \$smtp_server_port,
"smtpuser" => \$smtp_authuser,
"smtppass" => \$smtp_authpass,
+ "smtpdomain" => \$smtp_domain,
"to" => \@to,
"cc" => \@initial_cc,
"cccmd" => \$cc_cmd,
@@ -283,7 +282,7 @@ my $rc = GetOptions("sender|from=s" => \$sender,
"smtp-ssl" => sub { $smtp_encryption = 'ssl' },
"smtp-encryption=s" => \$smtp_encryption,
"smtp-debug:i" => \$debug_net_smtp,
- "smtp-domain:s" => \$mail_domain,
+ "smtp-domain:s" => \$smtp_domain,
"identity=s" => \$identity,
"annotate" => \$annotate,
"compose" => \$compose,
@@ -761,8 +760,7 @@ sub extract_valid_address {
# We'll setup a template for the message id, using the "from" address:
my ($message_id_stamp, $message_id_serial);
-sub make_message_id
-{
+sub make_message_id {
my $uniq;
if (!defined $message_id_stamp) {
$message_id_stamp = sprintf("%s-%s", time, $$);
@@ -817,8 +815,7 @@ sub is_rfc2047_quoted {
}
# use the simplest quoting being able to handle the recipient
-sub sanitize_address
-{
+sub sanitize_address {
my ($recipient) = @_;
my ($recipient_name, $recipient_addr) = ($recipient =~ /^(.*?)\s*(<.*)/);
@@ -863,21 +860,23 @@ sub sanitize_address
# This maildomain*() code is based on ideas in Perl library Test::Reporter
# /usr/share/perl5/Test/Reporter/Mail/Util.pm ==> sub _maildomain ()
-sub maildomain_net
-{
+sub valid_fqdn {
+ my $domain = shift;
+ return !($^O eq 'darwin' && $domain =~ /\.local$/) && $domain =~ /\./;
+}
+
+sub maildomain_net {
my $maildomain;
if (eval { require Net::Domain; 1 }) {
my $domain = Net::Domain::domainname();
- $maildomain = $domain
- unless $^O eq 'darwin' && $domain =~ /\.local$/;
+ $maildomain = $domain if valid_fqdn($domain);
}
return $maildomain;
}
-sub maildomain_mta
-{
+sub maildomain_mta {
my $maildomain;
if (eval { require Net::SMTP; 1 }) {
@@ -887,8 +886,7 @@ sub maildomain_mta
my $domain = $smtp->domain;
$smtp->quit;
- $maildomain = $domain
- unless $^O eq 'darwin' && $domain =~ /\.local$/;
+ $maildomain = $domain if valid_fqdn($domain);
last if $maildomain;
}
@@ -898,17 +896,15 @@ sub maildomain_mta
return $maildomain;
}
-sub maildomain
-{
- return maildomain_net() || maildomain_mta() || $mail_domain_default;
+sub maildomain {
+ return maildomain_net() || maildomain_mta() || 'localhost.localdomain';
}
# Returns 1 if the message was sent, and 0 otherwise.
# In actuality, the whole program dies when there
# is an error sending a message.
-sub send_message
-{
+sub send_message {
my @recipients = unique_email_list(@to);
@cc = (grep { my $cc = extract_valid_address($_);
not grep { $cc eq $_ } @recipients
@@ -1005,18 +1001,18 @@ X-Mailer: git-send-email $gitversion
if ($smtp_encryption eq 'ssl') {
$smtp_server_port ||= 465; # ssmtp
require Net::SMTP::SSL;
- $mail_domain ||= maildomain();
+ $smtp_domain ||= maildomain();
$smtp ||= Net::SMTP::SSL->new($smtp_server,
- Hello => $mail_domain,
+ Hello => $smtp_domain,
Port => $smtp_server_port);
}
else {
require Net::SMTP;
- $mail_domain ||= maildomain();
+ $smtp_domain ||= maildomain();
$smtp ||= Net::SMTP->new((defined $smtp_server_port)
? "$smtp_server:$smtp_server_port"
: $smtp_server,
- Hello => $mail_domain,
+ Hello => $smtp_domain,
Debug => $debug_net_smtp);
if ($smtp_encryption eq 'tls' && $smtp) {
require Net::SMTP::SSL;
@@ -1039,7 +1035,7 @@ X-Mailer: git-send-email $gitversion
die "Unable to initialize SMTP properly. Check config and use --smtp-debug. ",
"VALUES: server=$smtp_server ",
"encryption=$smtp_encryption ",
- "maildomain=$mail_domain",
+ "hello=$smtp_domain",
defined $smtp_server_port ? "port=$smtp_server_port" : "";
}
diff --git a/git-stash.sh b/git-stash.sh
index 59db3dc38e..0f858d334c 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -86,7 +86,7 @@ create_stash () {
GIT_INDEX_FILE="$TMP-index" &&
export GIT_INDEX_FILE &&
git read-tree -m $i_tree &&
- git add -u &&
+ git diff --name-only -z HEAD | git update-index -z --add --remove --stdin &&
git write-tree &&
rm -f "$TMP-index"
) ) ||
diff --git a/gitweb/Makefile b/gitweb/Makefile
index f2e1d92fbb..e7dd252773 100644
--- a/gitweb/Makefile
+++ b/gitweb/Makefile
@@ -91,7 +91,7 @@ ifdef CSSMIN
GITWEB_CSS = gitweb.min.css
all:: gitweb.min.css
gitweb.min.css: gitweb.css GITWEB-BUILD-OPTIONS
- $(QUIET_GEN)$(CSSMIN) <$ >$@
+ $(QUIET_GEN)$(CSSMIN) <$< >$@
endif
GITWEB_REPLACE = \
diff --git a/http-walker.c b/http-walker.c
index ef99ae647a..8ca76d0507 100644
--- a/http-walker.c
+++ b/http-walker.c
@@ -510,7 +510,7 @@ static int fetch_object(struct walker *walker, struct alt_base *repo, unsigned c
ret = error("File %s has bad hash", hex);
} else if (req->rename < 0) {
ret = error("unable to write sha1 filename %s",
- req->filename);
+ sha1_file_name(req->sha1));
}
release_http_object_request(req);
diff --git a/http.c b/http.c
index 4814217c64..1320c50e32 100644
--- a/http.c
+++ b/http.c
@@ -1,6 +1,7 @@
#include "http.h"
#include "pack.h"
#include "sideband.h"
+#include "run-command.h"
int data_received;
int active_requests;
@@ -720,7 +721,7 @@ static inline int hex(int v)
return 'A' + v - 10;
}
-static void end_url_with_slash(struct strbuf *buf, const char *url)
+void end_url_with_slash(struct strbuf *buf, const char *url)
{
strbuf_addstr(buf, url);
if (buf->len && buf->buf[buf->len - 1] != '/')
@@ -815,7 +816,21 @@ static int http_request(const char *url, void *result, int target, int options)
ret = HTTP_OK;
else if (missing_target(&results))
ret = HTTP_MISSING_TARGET;
- else
+ else if (results.http_code == 401) {
+ if (user_name) {
+ ret = HTTP_NOAUTH;
+ } else {
+ /*
+ * git_getpass is needed here because its very likely stdin/stdout are
+ * pipes to our parent process. So we instead need to use /dev/tty,
+ * but that is non-portable. Using git_getpass() can at least be stubbed
+ * on other platforms with a different implementation if/when necessary.
+ */
+ user_name = xstrdup(git_getpass("Username: "));
+ init_curl_http_auth(slot->curl);
+ ret = HTTP_REAUTH;
+ }
+ } else
ret = HTTP_ERROR;
} else {
error("Unable to start HTTP request for %s", url);
@@ -831,7 +846,11 @@ static int http_request(const char *url, void *result, int target, int options)
int http_get_strbuf(const char *url, struct strbuf *result, int options)
{
- return http_request(url, result, HTTP_REQUEST_STRBUF, options);
+ int http_ret = http_request(url, result, HTTP_REQUEST_STRBUF, options);
+ if (http_ret == HTTP_REAUTH) {
+ http_ret = http_request(url, result, HTTP_REQUEST_STRBUF, options);
+ }
+ return http_ret;
}
/*
@@ -896,47 +915,67 @@ int http_fetch_ref(const char *base, struct ref *ref)
}
/* Helpers for fetching packs */
-static int fetch_pack_index(unsigned char *sha1, const char *base_url)
+static char *fetch_pack_index(unsigned char *sha1, const char *base_url)
{
- int ret = 0;
- char *hex = xstrdup(sha1_to_hex(sha1));
- char *filename;
- char *url = NULL;
+ char *url, *tmp;
struct strbuf buf = STRBUF_INIT;
- if (has_pack_index(sha1)) {
- ret = 0;
- goto cleanup;
- }
-
if (http_is_verbose)
- fprintf(stderr, "Getting index for pack %s\n", hex);
+ fprintf(stderr, "Getting index for pack %s\n", sha1_to_hex(sha1));
end_url_with_slash(&buf, base_url);
- strbuf_addf(&buf, "objects/pack/pack-%s.idx", hex);
+ strbuf_addf(&buf, "objects/pack/pack-%s.idx", sha1_to_hex(sha1));
url = strbuf_detach(&buf, NULL);
- filename = sha1_pack_index_name(sha1);
- if (http_get_file(url, filename, 0) != HTTP_OK)
- ret = error("Unable to get pack index %s\n", url);
+ strbuf_addf(&buf, "%s.temp", sha1_pack_index_name(sha1));
+ tmp = strbuf_detach(&buf, NULL);
+
+ if (http_get_file(url, tmp, 0) != HTTP_OK) {
+ error("Unable to get pack index %s\n", url);
+ free(tmp);
+ tmp = NULL;
+ }
-cleanup:
- free(hex);
free(url);
- return ret;
+ return tmp;
}
static int fetch_and_setup_pack_index(struct packed_git **packs_head,
unsigned char *sha1, const char *base_url)
{
struct packed_git *new_pack;
+ char *tmp_idx = NULL;
+ int ret;
- if (fetch_pack_index(sha1, base_url))
+ if (has_pack_index(sha1)) {
+ new_pack = parse_pack_index(sha1, NULL);
+ if (!new_pack)
+ return -1; /* parse_pack_index() already issued error message */
+ goto add_pack;
+ }
+
+ tmp_idx = fetch_pack_index(sha1, base_url);
+ if (!tmp_idx)
return -1;
- new_pack = parse_pack_index(sha1);
- if (!new_pack)
+ new_pack = parse_pack_index(sha1, tmp_idx);
+ if (!new_pack) {
+ unlink(tmp_idx);
+ free(tmp_idx);
+
return -1; /* parse_pack_index() already issued error message */
+ }
+
+ ret = verify_pack_index(new_pack);
+ if (!ret) {
+ close_pack_index(new_pack);
+ ret = move_temp_to_file(tmp_idx, sha1_pack_index_name(sha1));
+ }
+ free(tmp_idx);
+ if (ret)
+ return -1;
+
+add_pack:
new_pack->next = *packs_head;
*packs_head = new_pack;
return 0;
@@ -1000,37 +1039,62 @@ void release_http_pack_request(struct http_pack_request *preq)
int finish_http_pack_request(struct http_pack_request *preq)
{
- int ret;
struct packed_git **lst;
+ struct packed_git *p = preq->target;
+ char *tmp_idx;
+ struct child_process ip;
+ const char *ip_argv[8];
- preq->target->pack_size = ftell(preq->packfile);
-
- if (preq->packfile != NULL) {
- fclose(preq->packfile);
- preq->packfile = NULL;
- preq->slot->local = NULL;
- }
+ close_pack_index(p);
- ret = move_temp_to_file(preq->tmpfile, preq->filename);
- if (ret)
- return ret;
+ fclose(preq->packfile);
+ preq->packfile = NULL;
+ preq->slot->local = NULL;
lst = preq->lst;
- while (*lst != preq->target)
+ while (*lst != p)
lst = &((*lst)->next);
*lst = (*lst)->next;
- if (verify_pack(preq->target))
+ tmp_idx = xstrdup(preq->tmpfile);
+ strcpy(tmp_idx + strlen(tmp_idx) - strlen(".pack.temp"),
+ ".idx.temp");
+
+ ip_argv[0] = "index-pack";
+ ip_argv[1] = "-o";
+ ip_argv[2] = tmp_idx;
+ ip_argv[3] = preq->tmpfile;
+ ip_argv[4] = NULL;
+
+ memset(&ip, 0, sizeof(ip));
+ ip.argv = ip_argv;
+ ip.git_cmd = 1;
+ ip.no_stdin = 1;
+ ip.no_stdout = 1;
+
+ if (run_command(&ip)) {
+ unlink(preq->tmpfile);
+ unlink(tmp_idx);
+ free(tmp_idx);
+ return -1;
+ }
+
+ unlink(sha1_pack_index_name(p->sha1));
+
+ if (move_temp_to_file(preq->tmpfile, sha1_pack_name(p->sha1))
+ || move_temp_to_file(tmp_idx, sha1_pack_index_name(p->sha1))) {
+ free(tmp_idx);
return -1;
- install_packed_git(preq->target);
+ }
+ install_packed_git(p);
+ free(tmp_idx);
return 0;
}
struct http_pack_request *new_http_pack_request(
struct packed_git *target, const char *base_url)
{
- char *filename;
long prev_posn = 0;
char range[RANGE_HEADER_SIZE];
struct strbuf buf = STRBUF_INIT;
@@ -1045,9 +1109,8 @@ struct http_pack_request *new_http_pack_request(
sha1_to_hex(target->sha1));
preq->url = strbuf_detach(&buf, NULL);
- filename = sha1_pack_name(target->sha1);
- snprintf(preq->filename, sizeof(preq->filename), "%s", filename);
- snprintf(preq->tmpfile, sizeof(preq->tmpfile), "%s.temp", filename);
+ snprintf(preq->tmpfile, sizeof(preq->tmpfile), "%s.temp",
+ sha1_pack_name(target->sha1));
preq->packfile = fopen(preq->tmpfile, "a");
if (!preq->packfile) {
error("Unable to open local file %s for pack",
@@ -1082,7 +1145,6 @@ struct http_pack_request *new_http_pack_request(
return preq;
abort:
- free(filename);
free(preq->url);
free(preq);
return NULL;
@@ -1137,7 +1199,6 @@ struct http_object_request *new_http_object_request(const char *base_url,
freq->localfile = -1;
filename = sha1_file_name(sha1);
- snprintf(freq->filename, sizeof(freq->filename), "%s", filename);
snprintf(freq->tmpfile, sizeof(freq->tmpfile),
"%s.temp", filename);
@@ -1166,8 +1227,8 @@ struct http_object_request *new_http_object_request(const char *base_url,
}
if (freq->localfile < 0) {
- error("Couldn't create temporary file %s for %s: %s",
- freq->tmpfile, freq->filename, strerror(errno));
+ error("Couldn't create temporary file %s: %s",
+ freq->tmpfile, strerror(errno));
goto abort;
}
@@ -1214,8 +1275,8 @@ struct http_object_request *new_http_object_request(const char *base_url,
prev_posn = 0;
lseek(freq->localfile, 0, SEEK_SET);
if (ftruncate(freq->localfile, 0) < 0) {
- error("Couldn't truncate temporary file %s for %s: %s",
- freq->tmpfile, freq->filename, strerror(errno));
+ error("Couldn't truncate temporary file %s: %s",
+ freq->tmpfile, strerror(errno));
goto abort;
}
}
@@ -1291,7 +1352,7 @@ int finish_http_object_request(struct http_object_request *freq)
return -1;
}
freq->rename =
- move_temp_to_file(freq->tmpfile, freq->filename);
+ move_temp_to_file(freq->tmpfile, sha1_file_name(freq->sha1));
return freq->rename;
}
diff --git a/http.h b/http.h
index 5c9441c10c..a0b5901594 100644
--- a/http.h
+++ b/http.h
@@ -117,6 +117,7 @@ extern void append_remote_object_url(struct strbuf *buf, const char *url,
int only_two_digit_prefix);
extern char *get_remote_object_url(const char *url, const char *hex,
int only_two_digit_prefix);
+extern void end_url_with_slash(struct strbuf *buf, const char *url);
/* Options for http_request_*() */
#define HTTP_NO_CACHE 1
@@ -126,6 +127,8 @@ extern char *get_remote_object_url(const char *url, const char *hex,
#define HTTP_MISSING_TARGET 1
#define HTTP_ERROR 2
#define HTTP_START_FAILED 3
+#define HTTP_REAUTH 4
+#define HTTP_NOAUTH 5
/*
* Requests an url and stores the result in a strbuf.
@@ -152,7 +155,6 @@ struct http_pack_request
struct packed_git *target;
struct packed_git **lst;
FILE *packfile;
- char filename[PATH_MAX];
char tmpfile[PATH_MAX];
struct curl_slist *range_header;
struct active_request_slot *slot;
@@ -167,7 +169,6 @@ extern void release_http_pack_request(struct http_pack_request *preq);
struct http_object_request
{
char *url;
- char filename[PATH_MAX];
char tmpfile[PATH_MAX];
int localfile;
CURLcode curl_result;
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/merge-recursive.c b/merge-recursive.c
index 917397ca7a..206c103635 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -409,7 +409,7 @@ static int remove_file(struct merge_options *o, int clean,
return -1;
}
if (update_working_directory) {
- if (remove_path(path) && errno != ENOENT)
+ if (remove_path(path))
return -1;
}
return 0;
diff --git a/object.c b/object.c
index 3ca92c4c4d..277b3ddba7 100644
--- a/object.c
+++ b/object.c
@@ -252,10 +252,10 @@ void add_object_array_with_mode(struct object *obj, const char *name, struct obj
void object_array_remove_duplicates(struct object_array *array)
{
- int ref, src, dst;
+ unsigned int ref, src, dst;
struct object_array_entry *objects = array->objects;
- for (ref = 0; ref < array->nr - 1; ref++) {
+ for (ref = 0; ref + 1 < array->nr; ref++) {
for (src = ref + 1, dst = src;
src < array->nr;
src++) {
diff --git a/pack-check.c b/pack-check.c
index 166ca703c1..395fb9527a 100644
--- a/pack-check.c
+++ b/pack-check.c
@@ -133,14 +133,13 @@ static int verify_packfile(struct packed_git *p,
return err;
}
-int verify_pack(struct packed_git *p)
+int verify_pack_index(struct packed_git *p)
{
off_t index_size;
const unsigned char *index_base;
git_SHA_CTX ctx;
unsigned char sha1[20];
int err = 0;
- struct pack_window *w_curs = NULL;
if (open_pack_index(p))
return error("packfile %s index not opened", p->pack_name);
@@ -154,8 +153,18 @@ int verify_pack(struct packed_git *p)
if (hashcmp(sha1, index_base + index_size - 20))
err = error("Packfile index for %s SHA1 mismatch",
p->pack_name);
+ return err;
+}
+
+int verify_pack(struct packed_git *p)
+{
+ int err = 0;
+ struct pack_window *w_curs = NULL;
+
+ err |= verify_pack_index(p);
+ if (!p->index_data)
+ return -1;
- /* Verify pack file */
err |= verify_packfile(p, &w_curs);
unuse_pack(&w_curs);
diff --git a/pack.h b/pack.h
index d268c014c9..bb275762b7 100644
--- a/pack.h
+++ b/pack.h
@@ -57,6 +57,7 @@ struct pack_idx_entry {
extern const char *write_idx_file(const char *index_name, struct pack_idx_entry **objects, int nr_objects, unsigned char *sha1);
extern int check_pack_crc(struct packed_git *p, struct pack_window **w_curs, off_t offset, off_t len, unsigned int nr);
+extern int verify_pack_index(struct packed_git *);
extern int verify_pack(struct packed_git *);
extern void fixup_pack_header_footer(int, unsigned char *, const char *, uint32_t, unsigned char *, off_t);
extern char *index_pack_lockfile(int fd);
diff --git a/pretty.c b/pretty.c
index 7cb3a2af50..2777d30224 100644
--- a/pretty.c
+++ b/pretty.c
@@ -716,7 +716,7 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
if (add_again(sb, &c->abbrev_commit_hash))
return 1;
strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1,
- DEFAULT_ABBREV));
+ c->pretty_ctx->abbrev));
c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
return 1;
case 'T': /* tree hash */
@@ -726,7 +726,7 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
if (add_again(sb, &c->abbrev_tree_hash))
return 1;
strbuf_addstr(sb, find_unique_abbrev(commit->tree->object.sha1,
- DEFAULT_ABBREV));
+ c->pretty_ctx->abbrev));
c->abbrev_tree_hash.len = sb->len - c->abbrev_tree_hash.off;
return 1;
case 'P': /* parent hashes */
@@ -743,7 +743,8 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
if (p != commit->parents)
strbuf_addch(sb, ' ');
strbuf_addstr(sb, find_unique_abbrev(
- p->item->object.sha1, DEFAULT_ABBREV));
+ p->item->object.sha1,
+ c->pretty_ctx->abbrev));
}
c->abbrev_parent_hashes.len = sb->len -
c->abbrev_parent_hashes.off;
diff --git a/remote-curl.c b/remote-curl.c
index b76bfcb3d3..24fbb9a9b9 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -9,7 +9,7 @@
#include "sideband.h"
static struct remote *remote;
-static const char *url;
+static const char *url; /* always ends with a trailing slash */
struct options {
int verbosity;
@@ -101,7 +101,7 @@ static struct discovery* discover_refs(const char *service)
return last;
free_discovery(last);
- strbuf_addf(&buffer, "%s/info/refs", url);
+ strbuf_addf(&buffer, "%sinfo/refs", url);
if (!prefixcmp(url, "http://") || !prefixcmp(url, "https://")) {
is_http = 1;
if (!strchr(url, '?'))
@@ -120,7 +120,7 @@ static struct discovery* discover_refs(const char *service)
strbuf_reset(&buffer);
proto_git_candidate = 0;
- strbuf_addf(&buffer, "%s/info/refs", url);
+ strbuf_addf(&buffer, "%sinfo/refs", url);
refs_url = strbuf_detach(&buffer, NULL);
http_ret = http_get_strbuf(refs_url, &buffer, HTTP_NO_CACHE);
@@ -132,6 +132,8 @@ static struct discovery* discover_refs(const char *service)
case HTTP_MISSING_TARGET:
die("%s not found: did you run git update-server-info on the"
" server?", refs_url);
+ case HTTP_NOAUTH:
+ die("Authentication failed");
default:
http_error(refs_url, http_ret);
die("HTTP request failed");
@@ -509,7 +511,7 @@ static int rpc_service(struct rpc_state *rpc, struct discovery *heads)
rpc->out = client.out;
strbuf_init(&rpc->result, 0);
- strbuf_addf(&buf, "%s/%s", url, svc);
+ strbuf_addf(&buf, "%s%s", url, svc);
rpc->service_url = strbuf_detach(&buf, NULL);
strbuf_addf(&buf, "Content-Type: application/x-%s-request", svc);
@@ -798,11 +800,13 @@ int main(int argc, const char **argv)
remote = remote_get(argv[1]);
if (argc > 2) {
- url = argv[2];
+ end_url_with_slash(&buf, argv[2]);
} else {
- url = remote->url[0];
+ end_url_with_slash(&buf, remote->url[0]);
}
+ url = strbuf_detach(&buf, NULL);
+
http_init(remote);
do {
diff --git a/remote.c b/remote.c
index c70181cdc6..26ce56046d 100644
--- a/remote.c
+++ b/remote.c
@@ -476,7 +476,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/run-command.c b/run-command.c
index eb5c575629..c7793f50fb 100644
--- a/run-command.c
+++ b/run-command.c
@@ -383,6 +383,8 @@ fail_pipe:
close(cmd->out);
if (need_err)
close_pair(fderr);
+ else if (cmd->err)
+ close(cmd->err);
errno = failed_errno;
return -1;
}
diff --git a/setup.c b/setup.c
index 5716d90b57..0e4cfe603f 100644
--- a/setup.c
+++ b/setup.c
@@ -519,6 +519,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 ff65328006..72de38909e 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,
@@ -599,6 +601,14 @@ void unuse_pack(struct pack_window **w_cursor)
}
}
+void close_pack_index(struct packed_git *p)
+{
+ if (p->index_data) {
+ munmap((void *)p->index_data, p->index_size);
+ p->index_data = NULL;
+ }
+}
+
/*
* This is used by git-repack in case a newly created pack happens to
* contain the same set of objects as an existing one. In that case
@@ -620,8 +630,7 @@ void free_pack_by_name(const char *pack_name)
close_pack_windows(p);
if (p->pack_fd != -1)
close(p->pack_fd);
- if (p->index_data)
- munmap((void *)p->index_data, p->index_size);
+ close_pack_index(p);
free(p->bad_object_sha1);
*pp = p->next;
free(p);
@@ -831,9 +840,8 @@ struct packed_git *add_packed_git(const char *path, int path_len, int local)
return p;
}
-struct packed_git *parse_pack_index(unsigned char *sha1)
+struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path)
{
- const char *idx_path = sha1_pack_index_name(sha1);
const char *path = sha1_pack_name(sha1);
struct packed_git *p = alloc_packed_git(strlen(path) + 1);
@@ -2448,6 +2456,8 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
else
ret = -1;
strbuf_release(&sbuf);
+ } else if (!size) {
+ ret = index_mem(sha1, NULL, size, write_object, type, path);
} else if (size <= SMALL_FILE_SIZE) {
char *buf = xmalloc(size);
if (size == read_in_full(fd, buf, size))
@@ -2456,12 +2466,11 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
else
ret = error("short read %s", strerror(errno));
free(buf);
- } else if (size) {
+ } else {
void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
ret = index_mem(sha1, buf, size, write_object, type, path);
munmap(buf, size);
- } else
- ret = index_mem(sha1, NULL, size, write_object, type, path);
+ }
close(fd);
return ret;
}
diff --git a/shortlog.h b/shortlog.h
index bc02cc29ef..de4f86fb97 100644
--- a/shortlog.h
+++ b/shortlog.h
@@ -12,6 +12,7 @@ struct shortlog {
int in1;
int in2;
int user_format;
+ int abbrev;
char *common_repo_prefix;
int email;
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/t0000-basic.sh b/t/t0000-basic.sh
index f4ca4fc85c..3ec9cbef2c 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -73,6 +73,27 @@ then
exit 1
fi
+clean=no
+test_expect_success 'tests clean up after themselves' '
+ test_when_finished clean=yes
+'
+
+cleaner=no
+test_expect_code 1 'tests clean up even after a failure' '
+ test_when_finished cleaner=yes &&
+ (exit 1)
+'
+
+if test $clean$cleaner != yesyes
+then
+ say "bug in test framework: cleanup commands do not work reliably"
+ exit 1
+fi
+
+test_expect_code 2 'failure to clean up causes the test to fail' '
+ test_when_finished "(exit 2)"
+'
+
################################################################
# Basics of the basics
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index 675773479a..7c0a698b92 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -310,4 +310,18 @@ test_expect_success POSIXPERM 'init notices EPERM' '
)
'
+test_expect_success 'init creates a new bare directory with global --bare' '
+ rm -rf newdir &&
+ git --bare init newdir &&
+ test -d newdir/refs
+'
+
+test_expect_success 'init prefers command line to GIT_DIR' '
+ rm -rf newdir &&
+ mkdir otherdir &&
+ GIT_DIR=otherdir git --bare init newdir &&
+ test -d newdir/refs &&
+ ! test -d otherdir/refs
+'
+
test_done
diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
index 1c77192eb3..53bd7fcc4a 100755
--- a/t/t0003-attributes.sh
+++ b/t/t0003-attributes.sh
@@ -20,8 +20,12 @@ test_expect_success 'setup' '
mkdir -p a/b/d a/c &&
(
+ echo "[attr]notest !test"
echo "f test=f"
echo "a/i test=a/i"
+ echo "onoff test -test"
+ echo "offon -test test"
+ echo "no notest"
) >.gitattributes &&
(
echo "g test=a/g" &&
@@ -30,6 +34,7 @@ test_expect_success 'setup' '
(
echo "h test=a/b/h" &&
echo "d/* test=a/b/d/*"
+ echo "d/yes notest"
) >a/b/.gitattributes
'
@@ -44,6 +49,11 @@ test_expect_success 'attribute test' '
attr_check b/g unspecified &&
attr_check a/b/h a/b/h &&
attr_check a/b/d/g "a/b/d/*"
+ attr_check onoff unset
+ attr_check offon set
+ attr_check no unspecified
+ attr_check a/b/d/no "a/b/d/*"
+ attr_check a/b/d/yes unspecified
'
@@ -58,6 +68,11 @@ a/b/g: test: a/b/g
b/g: test: unspecified
a/b/h: test: a/b/h
a/b/d/g: test: a/b/d/*
+onoff: test: unset
+offon: test: set
+no: test: unspecified
+a/b/d/no: test: a/b/d/*
+a/b/d/yes: test: unspecified
EOF
sed -e "s/:.*//" < expect | git check-attr --stdin test > actual &&
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/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/t3903-stash.sh b/t/t3903-stash.sh
index 476e5ec038..8fe14ccc54 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -228,4 +228,154 @@ test_expect_success 'stash --invalid-option' '
test bar,bar2 = $(cat file),$(cat file2)
'
+test_expect_success 'stash an added file' '
+ git reset --hard &&
+ echo new >file3 &&
+ git add file3 &&
+ git stash save "added file" &&
+ ! test -r file3 &&
+ git stash apply &&
+ test new = "$(cat file3)"
+'
+
+test_expect_success 'stash rm then recreate' '
+ git reset --hard &&
+ git rm file &&
+ echo bar7 >file &&
+ git stash save "rm then recreate" &&
+ test bar = "$(cat file)" &&
+ git stash apply &&
+ test bar7 = "$(cat file)"
+'
+
+test_expect_success 'stash rm and ignore' '
+ git reset --hard &&
+ git rm file &&
+ echo file >.gitignore &&
+ git stash save "rm and ignore" &&
+ test bar = "$(cat file)" &&
+ test file = "$(cat .gitignore)"
+ git stash apply &&
+ ! test -r file &&
+ test file = "$(cat .gitignore)"
+'
+
+test_expect_success 'stash rm and ignore (stage .gitignore)' '
+ git reset --hard &&
+ git rm file &&
+ echo file >.gitignore &&
+ git add .gitignore &&
+ git stash save "rm and ignore (stage .gitignore)" &&
+ test bar = "$(cat file)" &&
+ ! test -r .gitignore
+ git stash apply &&
+ ! test -r file &&
+ test file = "$(cat .gitignore)"
+'
+
+test_expect_success SYMLINKS 'stash file to symlink' '
+ git reset --hard &&
+ rm file &&
+ ln -s file2 file &&
+ git stash save "file to symlink" &&
+ test -f file &&
+ test bar = "$(cat file)" &&
+ git stash apply &&
+ case "$(ls -l file)" in *" file -> file2") :;; *) false;; esac
+'
+
+test_expect_success SYMLINKS 'stash file to symlink (stage rm)' '
+ git reset --hard &&
+ git rm file &&
+ ln -s file2 file &&
+ git stash save "file to symlink (stage rm)" &&
+ test -f file &&
+ test bar = "$(cat file)" &&
+ git stash apply &&
+ case "$(ls -l file)" in *" file -> file2") :;; *) false;; esac
+'
+
+test_expect_success SYMLINKS 'stash file to symlink (full stage)' '
+ git reset --hard &&
+ rm file &&
+ ln -s file2 file &&
+ git add file &&
+ git stash save "file to symlink (full stage)" &&
+ test -f file &&
+ test bar = "$(cat file)" &&
+ git stash apply &&
+ case "$(ls -l file)" in *" file -> file2") :;; *) false;; esac
+'
+
+# This test creates a commit with a symlink used for the following tests
+
+test_expect_success SYMLINKS 'stash symlink to file' '
+ git reset --hard &&
+ ln -s file filelink &&
+ git add filelink &&
+ git commit -m "Add symlink" &&
+ rm filelink &&
+ cp file filelink &&
+ git stash save "symlink to file" &&
+ test -h filelink &&
+ case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac &&
+ git stash apply &&
+ ! test -h filelink &&
+ test bar = "$(cat file)"
+'
+
+test_expect_success SYMLINKS 'stash symlink to file (stage rm)' '
+ git reset --hard &&
+ git rm filelink &&
+ cp file filelink &&
+ git stash save "symlink to file (stage rm)" &&
+ test -h filelink &&
+ case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac &&
+ git stash apply &&
+ ! test -h filelink &&
+ test bar = "$(cat file)"
+'
+
+test_expect_success SYMLINKS 'stash symlink to file (full stage)' '
+ git reset --hard &&
+ rm filelink &&
+ cp file filelink &&
+ git add filelink &&
+ git stash save "symlink to file (full stage)" &&
+ test -h filelink &&
+ case "$(ls -l filelink)" in *" filelink -> file") :;; *) false;; esac &&
+ git stash apply &&
+ ! test -h filelink &&
+ test bar = "$(cat file)"
+'
+
+test_expect_failure 'stash directory to file' '
+ git reset --hard &&
+ mkdir dir &&
+ echo foo >dir/file &&
+ git add dir/file &&
+ git commit -m "Add file in dir" &&
+ rm -fr dir &&
+ echo bar >dir &&
+ git stash save "directory to file" &&
+ test -d dir &&
+ test foo = "$(cat dir/file)" &&
+ test_must_fail git stash apply &&
+ test bar = "$(cat dir)" &&
+ git reset --soft HEAD^
+'
+
+test_expect_failure 'stash file to directory' '
+ git reset --hard &&
+ rm file &&
+ mkdir file &&
+ echo foo >file/file &&
+ git stash save "file to directory" &&
+ test -f file &&
+ test bar = "$(cat file)" &&
+ git stash apply &&
+ test -f file/file &&
+ test foo = "$(cat file/file)"
+'
+
test_done
diff --git a/t/t4124-apply-ws-rule.sh b/t/t4124-apply-ws-rule.sh
index fb9ad247bf..451d75e3fb 100755
--- a/t/t4124-apply-ws-rule.sh
+++ b/t/t4124-apply-ws-rule.sh
@@ -325,6 +325,18 @@ test_expect_success 'two missing blank lines at end with --whitespace=fix' '
test_cmp one expect
'
+test_expect_success 'missing blank line at end, insert before end, --whitespace=fix' '
+ { echo a; echo; } >one &&
+ git add one &&
+ { echo b; echo a; echo; } >one &&
+ cp one expect &&
+ git diff -- one >patch &&
+ echo a >one &&
+ test_must_fail git apply patch &&
+ git apply --whitespace=fix patch &&
+ test_cmp one expect
+'
+
test_expect_success 'shrink file with tons of missing blanks at end of file' '
{ echo a; echo b; echo c; } >one &&
cp one no-blank-lines &&
diff --git a/t/t4134-apply-submodule.sh b/t/t4134-apply-submodule.sh
new file mode 100755
index 0000000000..1b82f93cff
--- /dev/null
+++ b/t/t4134-apply-submodule.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 Peter Collingbourne
+#
+
+test_description='git apply submodule tests'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+ cat > create-sm.patch <<EOF
+diff --git a/dir/sm b/dir/sm
+new file mode 160000
+index 0000000..0123456
+--- /dev/null
++++ b/dir/sm
+@@ -0,0 +1 @@
++Subproject commit 0123456789abcdef0123456789abcdef01234567
+EOF
+ cat > remove-sm.patch <<EOF
+diff --git a/dir/sm b/dir/sm
+deleted file mode 160000
+index 0123456..0000000
+--- a/dir/sm
++++ /dev/null
+@@ -1 +0,0 @@
+-Subproject commit 0123456789abcdef0123456789abcdef01234567
+EOF
+'
+
+test_expect_success 'removing a submodule also removes all leading subdirectories' '
+ git apply --index create-sm.patch &&
+ test -d dir/sm &&
+ git apply --index remove-sm.patch &&
+ test \! -d dir
+'
+
+test_done
diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh
index a01e55bf6b..cdb70b4b33 100755
--- a/t/t4201-shortlog.sh
+++ b/t/t4201-shortlog.sh
@@ -8,30 +8,93 @@ test_description='git shortlog
. ./test-lib.sh
-echo 1 > a1
-git add a1
-tree=$(git write-tree)
-commit=$( (echo "Test"; echo) | git commit-tree $tree )
-git update-ref HEAD $commit
+test_expect_success 'setup' '
+ echo 1 >a1 &&
+ git add a1 &&
+ tree=$(git write-tree) &&
+ commit=$(printf "%s\n" "Test" "" | git commit-tree "$tree") &&
+ git update-ref HEAD "$commit" &&
+
+ echo 2 >a1 &&
+ git commit --quiet -m "This is a very, very long first line for the commit message to see if it is wrapped correctly" a1 &&
+
+ # test if the wrapping is still valid
+ # when replacing all is by treble clefs.
+ echo 3 >a1 &&
+ git commit --quiet -m "$(
+ echo "This is a very, very long first line for the commit message to see if it is wrapped correctly" |
+ sed "s/i/1234/g" |
+ tr 1234 "\360\235\204\236")" a1 &&
+
+ # now fsck up the utf8
+ git config i18n.commitencoding non-utf-8 &&
+ echo 4 >a1 &&
+ git commit --quiet -m "$(
+ echo "This is a very, very long first line for the commit message to see if it is wrapped correctly" |
+ sed "s/i/1234/g" |
+ tr 1234 "\370\235\204\236")" a1 &&
+
+ echo 5 >a1 &&
+ git commit --quiet -m "a 12 34 56 78" a1
+
+ echo 6 >a1 &&
+ git commit --quiet -m "Commit by someone else" \
+ --author="Someone else <not!me>" a1 &&
+
+ cat >expect.template <<-\EOF
+ A U Thor (5):
+ SUBJECT
+ SUBJECT
+ SUBJECT
+ SUBJECT
+ SUBJECT
+
+ Someone else (1):
+ SUBJECT
+
+ EOF
+'
-echo 2 > a1
-git commit --quiet -m "This is a very, very long first line for the commit message to see if it is wrapped correctly" a1
+fuzz() {
+ file=$1 &&
+ sed "
+ s/$_x40/OBJECT_NAME/g
+ s/$_x05/OBJID/g
+ s/^ \{6\}[CTa].*/ SUBJECT/g
+ s/^ \{8\}[^ ].*/ CONTINUATION/g
+ " <"$file" >"$file.fuzzy" &&
+ sed "/CONTINUATION/ d" <"$file.fuzzy"
+}
-# test if the wrapping is still valid when replacing all i's by treble clefs.
-echo 3 > a1
-git commit --quiet -m "$(echo "This is a very, very long first line for the commit message to see if it is wrapped correctly" | sed "s/i/1234/g" | tr 1234 '\360\235\204\236')" a1
+test_expect_success 'default output format' '
+ git shortlog HEAD >log &&
+ fuzz log >log.predictable &&
+ test_cmp expect.template log.predictable
+'
-# now fsck up the utf8
-git config i18n.commitencoding non-utf-8
-echo 4 > a1
-git commit --quiet -m "$(echo "This is a very, very long first line for the commit message to see if it is wrapped correctly" | sed "s/i/1234/g" | tr 1234 '\370\235\204\236')" a1
+test_expect_success 'pretty format' '
+ sed s/SUBJECT/OBJECT_NAME/ expect.template >expect &&
+ git shortlog --format="%H" HEAD >log &&
+ fuzz log >log.predictable &&
+ test_cmp expect log.predictable
+'
-echo 5 > a1
-git commit --quiet -m "a 12 34 56 78" a1
+test_expect_success '--abbrev' '
+ sed s/SUBJECT/OBJID/ expect.template >expect &&
+ git shortlog --format="%h" --abbrev=5 HEAD >log &&
+ fuzz log >log.predictable &&
+ test_cmp expect log.predictable
+'
-git shortlog -w HEAD > out
+test_expect_success 'output from user-defined format is re-wrapped' '
+ sed "s/SUBJECT/two lines/" expect.template >expect &&
+ git shortlog --format="two%nlines" HEAD >log &&
+ fuzz log >log.predictable &&
+ test_cmp expect log.predictable
+'
-cat > expect << EOF
+test_expect_success 'shortlog wrapping' '
+ cat >expect <<\EOF &&
A U Thor (5):
Test
This is a very, very long first line for the commit message to see if
@@ -43,14 +106,19 @@ A U Thor (5):
a 12 34
56 78
-EOF
-
-test_expect_success 'shortlog wrapping' 'test_cmp expect out'
+Someone else (1):
+ Commit by someone else
-git log HEAD > log
-GIT_DIR=non-existing git shortlog -w < log > out
+EOF
+ git shortlog -w HEAD >out &&
+ test_cmp expect out
+'
-test_expect_success 'shortlog from non-git directory' 'test_cmp expect out'
+test_expect_success 'shortlog from non-git directory' '
+ git log HEAD >log &&
+ GIT_DIR=non-existing git shortlog -w <log >out &&
+ test_cmp expect out
+'
iconvfromutf8toiso88591() {
printf "%s" "$*" | iconv -f UTF-8 -t ISO8859-1
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 2de98e6561..6a37a4d993 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -528,7 +528,7 @@ test_expect_success 'push does not update local refs on failure' '
mk_test heads/master &&
mk_child child &&
mkdir testrepo/.git/hooks &&
- echo exit 1 >testrepo/.git/hooks/pre-receive &&
+ echo "#!/no/frobnication/today" >testrepo/.git/hooks/pre-receive &&
chmod +x testrepo/.git/hooks/pre-receive &&
(cd child &&
git pull .. master
diff --git a/t/t5541-http-push.sh b/t/t5541-http-push.sh
index 795dc2bcdf..17e1bdc5a8 100755
--- a/t/t5541-http-push.sh
+++ b/t/t5541-http-push.sh
@@ -34,8 +34,34 @@ test_expect_success 'setup remote repository' '
mv test_repo.git "$HTTPD_DOCUMENT_ROOT_PATH"
'
-test_expect_success 'clone remote repository' '
+cat >exp <<EOF
+GET /smart/test_repo.git/info/refs?service=git-upload-pack HTTP/1.1 200
+POST /smart/test_repo.git/git-upload-pack HTTP/1.1 200
+EOF
+test_expect_success 'no empty path components' '
+ # In the URL, add a trailing slash, and see if git appends yet another
+ # slash.
cd "$ROOT_PATH" &&
+ git clone $HTTPD_URL/smart/test_repo.git/ test_repo_clone &&
+
+ sed -e "
+ s/^.* \"//
+ s/\"//
+ s/ [1-9][0-9]*\$//
+ s/^GET /GET /
+ " >act <"$HTTPD_ROOT_PATH"/access.log &&
+
+ # Clear the log, so that it does not affect the "used receive-pack
+ # service" test which reads the log too.
+ #
+ # We do this before the actual comparison to ensure the log is cleared.
+ echo > "$HTTPD_ROOT_PATH"/access.log &&
+
+ test_cmp exp act
+'
+
+test_expect_success 'clone remote repository' '
+ rm -rf test_repo_clone &&
git clone $HTTPD_URL/smart/test_repo.git test_repo_clone
'
@@ -68,6 +94,7 @@ test_expect_success 'create and delete remote branch' '
'
cat >exp <<EOF
+
GET /smart/test_repo.git/info/refs?service=git-upload-pack HTTP/1.1 200
POST /smart/test_repo.git/git-upload-pack HTTP/1.1 200
GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200
diff --git a/t/t5550-http-fetch.sh b/t/t5550-http-fetch.sh
index 8cfce969bc..fc675b50ad 100755
--- a/t/t5550-http-fetch.sh
+++ b/t/t5550-http-fetch.sh
@@ -55,12 +55,43 @@ test_expect_success 'http remote detects correct HEAD' '
test_expect_success 'fetch packed objects' '
cp -R "$HTTPD_DOCUMENT_ROOT_PATH"/repo.git "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git &&
- cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git &&
- git --bare repack &&
- git --bare prune-packed &&
+ (cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git &&
+ git --bare repack &&
+ git --bare prune-packed
+ ) &&
git clone $HTTPD_URL/dumb/repo_pack.git
'
+test_expect_success 'fetch notices corrupt pack' '
+ cp -R "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad1.git &&
+ (cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad1.git &&
+ p=`ls objects/pack/pack-*.pack` &&
+ chmod u+w $p &&
+ printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc
+ ) &&
+ mkdir repo_bad1.git &&
+ (cd repo_bad1.git &&
+ git --bare init &&
+ test_must_fail git --bare fetch $HTTPD_URL/dumb/repo_bad1.git &&
+ test 0 = `ls objects/pack/pack-*.pack | wc -l`
+ )
+'
+
+test_expect_success 'fetch notices corrupt idx' '
+ cp -R "$HTTPD_DOCUMENT_ROOT_PATH"/repo_pack.git "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad2.git &&
+ (cd "$HTTPD_DOCUMENT_ROOT_PATH"/repo_bad2.git &&
+ p=`ls objects/pack/pack-*.idx` &&
+ chmod u+w $p &&
+ printf %0256d 0 | dd of=$p bs=256 count=1 seek=1 conv=notrunc
+ ) &&
+ mkdir repo_bad2.git &&
+ (cd repo_bad2.git &&
+ git --bare init &&
+ test_must_fail git --bare fetch $HTTPD_URL/dumb/repo_bad2.git &&
+ test 0 = `ls objects/pack | wc -l`
+ )
+'
+
test_expect_success 'did not use upload-pack service' '
grep '/git-upload-pack' <"$HTTPD_ROOT_PATH"/access.log >act
: >exp
diff --git a/t/t5704-bundle.sh b/t/t5704-bundle.sh
index a8f4419e61..ddc3dc52f4 100755
--- a/t/t5704-bundle.sh
+++ b/t/t5704-bundle.sh
@@ -30,4 +30,20 @@ test_expect_success 'tags can be excluded by rev-list options' '
'
+test_expect_failure 'bundle --stdin' '
+
+ echo master | git bundle create stdin-bundle.bdl --stdin &&
+ git ls-remote stdin-bundle.bdl >output &&
+ grep master output
+
+'
+
+test_expect_failure 'bundle --stdin <rev-list options>' '
+
+ echo master | git bundle create hybrid-bundle.bdl --stdin tag &&
+ git ls-remote hybrid-bundle.bdl >output &&
+ grep master output
+
+'
+
test_done
diff --git a/t/t5705-clone-2gb.sh b/t/t5705-clone-2gb.sh
index adfaae8c5b..8afbdd4de2 100755
--- a/t/t5705-clone-2gb.sh
+++ b/t/t5705-clone-2gb.sh
@@ -12,7 +12,7 @@ test_expect_success 'setup' '
git config pack.compression 0 &&
git config pack.depth 0 &&
- blobsize=$((20*1024*1024)) &&
+ blobsize=$((100*1024*1024)) &&
blobcount=$((2*1024*1024*1024/$blobsize+1)) &&
i=1 &&
(while test $i -le $blobcount
@@ -36,9 +36,15 @@ test_expect_success 'setup' '
'
-test_expect_success 'clone' '
+test_expect_success 'clone - bare' '
- git clone --bare --no-hardlinks . clone
+ git clone --bare --no-hardlinks . clone-bare
+
+'
+
+test_expect_success 'clone - with worktree, file:// protocol' '
+
+ git clone file://. clone-wt
'
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/t6006-rev-list-format.sh b/t/t6006-rev-list-format.sh
index a49b7c5722..e8fde5c19c 100755
--- a/t/t6006-rev-list-format.sh
+++ b/t/t6006-rev-list-format.sh
@@ -191,6 +191,31 @@ test_expect_success 'add LF before non-empty (2)' '
grep "^$" actual
'
+test_expect_success '--abbrev' '
+ echo SHORT SHORT SHORT >expect2 &&
+ echo LONG LONG LONG >expect3 &&
+ git log -1 --format="%h %h %h" HEAD >actual1 &&
+ git log -1 --abbrev=5 --format="%h %h %h" HEAD >actual2 &&
+ git log -1 --abbrev=5 --format="%H %H %H" HEAD >actual3 &&
+ sed -e "s/$_x40/LONG/g" -e "s/$_x05/SHORT/g" <actual2 >fuzzy2 &&
+ sed -e "s/$_x40/LONG/g" -e "s/$_x05/SHORT/g" <actual3 >fuzzy3 &&
+ test_cmp expect2 fuzzy2 &&
+ test_cmp expect3 fuzzy3 &&
+ ! test_cmp actual1 actual2
+'
+
+test_expect_success '%H is not affected by --abbrev-commit' '
+ git log -1 --format=%H --abbrev-commit --abbrev=20 HEAD >actual &&
+ len=$(wc -c <actual) &&
+ test $len = 41
+'
+
+test_expect_success '%h is not affected by --abbrev-commit' '
+ git log -1 --format=%h --abbrev-commit --abbrev=20 HEAD >actual &&
+ len=$(wc -c <actual) &&
+ test $len = 21
+'
+
test_expect_success '"%h %gD: %gs" is same as git-reflog' '
git reflog >expect &&
git log -g --format="%h %gD: %gs" >actual &&
@@ -203,6 +228,12 @@ test_expect_success '"%h %gD: %gs" is same as git-reflog (with date)' '
test_cmp expect actual
'
+test_expect_success '"%h %gD: %gs" is same as git-reflog (with --abbrev)' '
+ git reflog --abbrev=13 --date=raw >expect &&
+ git log -g --abbrev=13 --format="%h %gD: %gs" --date=raw >actual &&
+ test_cmp expect actual
+'
+
test_expect_success '%gd shortens ref name' '
echo "master@{0}" >expect.gd-short &&
git log -g -1 --format=%gd refs/heads/master >actual.gd-short &&
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/t6120-describe.sh b/t/t6120-describe.sh
index 065deadc29..876d1ab743 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -8,7 +8,7 @@ test_description='test describe
o----o----o----o----o----. /
\ A c /
.------------o---o---o
- D e
+ D,R e
'
. ./test-lib.sh
@@ -68,6 +68,8 @@ test_expect_success setup '
echo D >another && git add another && git commit -m D &&
test_tick &&
git tag -a -m D D &&
+ test_tick &&
+ git tag -a -m R R &&
test_tick &&
echo DD >another && git commit -a -m another &&
@@ -89,10 +91,10 @@ test_expect_success setup '
check_describe A-* HEAD
check_describe A-* HEAD^
-check_describe D-* HEAD^^
+check_describe R-* HEAD^^
check_describe A-* HEAD^^2
check_describe B HEAD^^2^
-check_describe D-* HEAD^^^
+check_describe R-* HEAD^^^
check_describe c-* --tags HEAD
check_describe c-* --tags HEAD^
diff --git a/t/t7005-editor.sh b/t/t7005-editor.sh
index 5257f4d261..6355698c6b 100755
--- a/t/t7005-editor.sh
+++ b/t/t7005-editor.sh
@@ -13,7 +13,7 @@ test_expect_success 'determine default editor' '
'
-if ! expr "$vi" : '^[a-z]*$' >/dev/null
+if ! expr "$vi" : '[a-z]*$' >/dev/null
then
vi=
fi
diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh
index d9202d5af5..0f6b367832 100755
--- a/t/t7006-pager.sh
+++ b/t/t7006-pager.sh
@@ -4,17 +4,24 @@ test_description='Test automatic use of a pager.'
. ./test-lib.sh
-rm -f stdout_is_tty
+cleanup_fail() {
+ echo >&2 cleanup failed
+ (exit 1)
+}
+
test_expect_success 'set up terminal for tests' '
+ rm -f stdout_is_tty ||
+ cleanup_fail &&
+
if test -t 1
then
- : > stdout_is_tty
+ >stdout_is_tty
elif
test_have_prereq PERL &&
"$PERL_PATH" "$TEST_DIRECTORY"/t7006/test-terminal.perl \
sh -c "test -t 1"
then
- : > test_terminal_works
+ >test_terminal_works
fi
'
@@ -32,53 +39,68 @@ else
say no usable terminal, so skipping some tests
fi
-unset GIT_PAGER GIT_PAGER_IN_USE
-git config --unset core.pager
-PAGER='cat > paginated.out'
-export PAGER
-
test_expect_success 'setup' '
+ unset GIT_PAGER GIT_PAGER_IN_USE &&
+ test_might_fail git config --unset core.pager &&
+
+ PAGER="cat >paginated.out" &&
+ export PAGER &&
+
test_commit initial
'
-rm -f paginated.out
test_expect_success TTY 'some commands use a pager' '
+ rm -f paginated.out ||
+ cleanup_fail &&
+
test_terminal git log &&
test -e paginated.out
'
-rm -f paginated.out
test_expect_success TTY 'some commands do not use a pager' '
+ rm -f paginated.out ||
+ cleanup_fail &&
+
test_terminal git rev-list HEAD &&
! test -e paginated.out
'
-rm -f paginated.out
test_expect_success 'no pager when stdout is a pipe' '
+ rm -f paginated.out ||
+ cleanup_fail &&
+
git log | cat &&
! test -e paginated.out
'
-rm -f paginated.out
test_expect_success 'no pager when stdout is a regular file' '
- git log > file &&
+ rm -f paginated.out ||
+ cleanup_fail &&
+
+ git log >file &&
! test -e paginated.out
'
-rm -f paginated.out
test_expect_success TTY 'git --paginate rev-list uses a pager' '
+ rm -f paginated.out ||
+ cleanup_fail &&
+
test_terminal git --paginate rev-list HEAD &&
test -e paginated.out
'
-rm -f file paginated.out
test_expect_success 'no pager even with --paginate when stdout is a pipe' '
+ rm -f file paginated.out ||
+ cleanup_fail &&
+
git --paginate log | cat &&
! test -e paginated.out
'
-rm -f paginated.out
test_expect_success TTY 'no pager with --no-pager' '
+ rm -f paginated.out ||
+ cleanup_fail &&
+
test_terminal git --no-pager log &&
! test -e paginated.out
'
@@ -86,88 +108,119 @@ test_expect_success TTY 'no pager with --no-pager' '
# A colored commit log will begin with an appropriate ANSI escape
# for the first color; the text "commit" comes later.
colorful() {
- read firstline < $1
- ! expr "$firstline" : "^[a-zA-Z]" >/dev/null
+ read firstline <$1
+ ! expr "$firstline" : "[a-zA-Z]" >/dev/null
}
-rm -f colorful.log colorless.log
test_expect_success 'tests can detect color' '
- git log --no-color > colorless.log &&
- git log --color > colorful.log &&
+ rm -f colorful.log colorless.log ||
+ cleanup_fail &&
+
+ git log --no-color >colorless.log &&
+ git log --color >colorful.log &&
! colorful colorless.log &&
colorful colorful.log
'
-rm -f colorless.log
-git config color.ui auto
test_expect_success 'no color when stdout is a regular file' '
- git log > colorless.log &&
+ rm -f colorless.log &&
+ git config color.ui auto ||
+ cleanup_fail &&
+
+ git log >colorless.log &&
! colorful colorless.log
'
-rm -f paginated.out
-git config color.ui auto
test_expect_success TTY 'color when writing to a pager' '
- TERM=vt100 test_terminal git log &&
+ rm -f paginated.out &&
+ git config color.ui auto ||
+ cleanup_fail &&
+
+ (
+ TERM=vt100 &&
+ export TERM &&
+ test_terminal git log
+ ) &&
colorful paginated.out
'
-rm -f colorful.log
-git config color.ui auto
test_expect_success 'color when writing to a file intended for a pager' '
- TERM=vt100 GIT_PAGER_IN_USE=true git log > colorful.log &&
+ rm -f colorful.log &&
+ git config color.ui auto ||
+ cleanup_fail &&
+
+ (
+ TERM=vt100 &&
+ GIT_PAGER_IN_USE=true &&
+ export TERM GIT_PAGER_IN_USE &&
+ git log >colorful.log
+ ) &&
colorful colorful.log
'
-unset PAGER GIT_PAGER
-git config --unset core.pager
test_expect_success 'determine default pager' '
+ unset PAGER GIT_PAGER &&
+ test_might_fail git config --unset core.pager ||
+ cleanup_fail &&
+
less=$(git var GIT_PAGER) &&
test -n "$less"
'
-if expr "$less" : '^[a-z]*$' > /dev/null && test_have_prereq TTY
+if expr "$less" : '[a-z][a-z]*$' >/dev/null && test_have_prereq TTY
then
test_set_prereq SIMPLEPAGER
fi
-unset PAGER GIT_PAGER
-git config --unset core.pager
-rm -f default_pager_used
test_expect_success SIMPLEPAGER 'default pager is used by default' '
- cat > $less <<-EOF &&
- #!$SHELL_PATH
- wc > default_pager_used
+ unset PAGER GIT_PAGER &&
+ test_might_fail git config --unset core.pager &&
+ rm -f default_pager_used ||
+ cleanup_fail &&
+
+ cat >$less <<-\EOF &&
+ #!/bin/sh
+ wc >default_pager_used
EOF
chmod +x $less &&
- PATH=.:$PATH test_terminal git log &&
+ (
+ PATH=.:$PATH &&
+ export PATH &&
+ test_terminal git log
+ ) &&
test -e default_pager_used
'
-unset GIT_PAGER
-git config --unset core.pager
-rm -f PAGER_used
test_expect_success TTY 'PAGER overrides default pager' '
- PAGER="wc > PAGER_used" &&
+ unset GIT_PAGER &&
+ test_might_fail git config --unset core.pager &&
+ rm -f PAGER_used ||
+ cleanup_fail &&
+
+ PAGER="wc >PAGER_used" &&
export PAGER &&
test_terminal git log &&
test -e PAGER_used
'
-unset GIT_PAGER
-rm -f core.pager_used
test_expect_success TTY 'core.pager overrides PAGER' '
+ unset GIT_PAGER &&
+ rm -f core.pager_used ||
+ cleanup_fail &&
+
PAGER=wc &&
export PAGER &&
- git config core.pager "wc > core.pager_used" &&
+ git config core.pager "wc >core.pager_used" &&
test_terminal git log &&
test -e core.pager_used
'
-rm -f GIT_PAGER_used
test_expect_success TTY 'GIT_PAGER overrides core.pager' '
+ rm -f GIT_PAGER_used ||
+ cleanup_fail &&
+
git config core.pager wc &&
- GIT_PAGER="wc > GIT_PAGER_used" &&
+ GIT_PAGER="wc >GIT_PAGER_used" &&
export GIT_PAGER &&
test_terminal git log &&
test -e GIT_PAGER_used
diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh
index 844fb43c6d..95044668ee 100755
--- a/t/t7502-commit.sh
+++ b/t/t7502-commit.sh
@@ -35,7 +35,7 @@ test_expect_success 'partial' '
'
-test_expect_success 'partial modification in a subdirecotry' '
+test_expect_success 'partial modification in a subdirectory' '
test_tick &&
git commit -m "partial commit to subdirectory" not &&
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index 556d0faa77..008d5711b8 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -69,6 +69,34 @@ test_expect_success 'status (2)' '
'
cat >expect <<\EOF
+# On branch master
+# Changes to be committed:
+# new file: dir2/added
+#
+# Changed but not updated:
+# modified: dir1/modified
+#
+# Untracked files:
+# dir1/untracked
+# dir2/modified
+# dir2/untracked
+# expect
+# output
+# untracked
+EOF
+
+git config advice.statusHints false
+
+test_expect_success 'status (advice.statusHints false)' '
+
+ git status >output &&
+ test_cmp expect output
+
+'
+
+git config --unset advice.statusHints
+
+cat >expect <<\EOF
M dir1/modified
A dir2/added
?? dir1/untracked
@@ -115,6 +143,23 @@ test_expect_success 'status (status.showUntrackedFiles no)' '
test_cmp expect output
'
+cat >expect <<EOF
+# On branch master
+# Changes to be committed:
+# new file: dir2/added
+#
+# Changed but not updated:
+# modified: dir1/modified
+#
+# Untracked files not listed
+EOF
+git config advice.statusHints false
+test_expect_success 'status -uno (advice.statusHints false)' '
+ git status -uno >output &&
+ test_cmp expect output
+'
+git config --unset advice.statusHints
+
cat >expect << EOF
M dir1/modified
A dir2/added
@@ -496,6 +541,16 @@ test_expect_success 'dry-run of partial commit excluding new file in index' '
test_cmp expect output
'
+cat >expect <<EOF
+:100644 100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0000000000000000000000000000000000000000 M dir1/modified
+EOF
+test_expect_success 'status refreshes the index' '
+ touch dir2/added &&
+ git status &&
+ git diff-files >output &&
+ test_cmp expect output
+'
+
test_expect_success 'setup status submodule summary' '
test_create_repo sm && (
cd sm &&
@@ -693,4 +748,19 @@ test_expect_success 'commit --dry-run submodule summary (--amend)' '
test_cmp expect output
'
+test_expect_success POSIXPERM 'status succeeds in a read-only repository' '
+ (
+ chmod a-w .git &&
+ # make dir1/tracked stat-dirty
+ >dir1/tracked1 && mv -f dir1/tracked1 dir1/tracked &&
+ git status -s >output &&
+ ! grep dir1/tracked output &&
+ # make sure "status" succeeded without writing index out
+ git diff-files | grep dir1/tracked
+ )
+ status=$?
+ chmod 775 .git
+ (exit $status)
+'
+
test_done
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/test-lib.sh b/t/test-lib.sh
index 9234eb7561..9bfa14be7f 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -366,8 +366,10 @@ test_debug () {
}
test_run_ () {
+ test_cleanup=:
eval >&3 2>&4 "$1"
- eval_ret="$?"
+ eval_ret=$?
+ eval >&3 2>&4 "$test_cleanup"
return 0
}
@@ -528,6 +530,22 @@ test_must_fail () {
test $? -gt 0 -a $? -le 129 -o $? -gt 192
}
+# Similar to test_must_fail, but tolerates success, too. This is
+# meant to be used in contexts like:
+#
+# test_expect_success 'some command works without configuration' '
+# test_might_fail git config --unset all.configuration &&
+# do something
+# '
+#
+# Writing "git config --unset all.configuration || :" would be wrong,
+# because we want to notice if it fails due to segv.
+
+test_might_fail () {
+ "$@"
+ test $? -ge 0 -a $? -le 129 -o $? -gt 192
+}
+
# test_cmp is a helper function to compare actual and expected output.
# You can use it like:
#
@@ -545,6 +563,31 @@ test_cmp() {
$GIT_TEST_CMP "$@"
}
+# This function can be used to schedule some commands to be run
+# unconditionally at the end of the test to restore sanity:
+#
+# test_expect_success 'test core.capslock' '
+# git config core.capslock true &&
+# test_when_finished "git config --unset core.capslock" &&
+# hello world
+# '
+#
+# That would be roughly equivalent to
+#
+# test_expect_success 'test core.capslock' '
+# git config core.capslock true &&
+# hello world
+# git config --unset core.capslock
+# '
+#
+# except that the greeting and config --unset must both succeed for
+# the test to pass.
+
+test_when_finished () {
+ test_cleanup="{ $*
+ } && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup"
+}
+
# Most tests can use the created repository, but some may need to create more.
# Usage: test_create_repo <directory>
test_create_repo () {
diff --git a/tag.c b/tag.c
index 4470d2bf78..85607c219e 100644
--- a/tag.c
+++ b/tag.c
@@ -36,43 +36,50 @@ struct tag *lookup_tag(const unsigned char *sha1)
return (struct tag *) obj;
}
+static unsigned long parse_tag_date(const char *buf, const char *tail)
+{
+ const char *dateptr;
+
+ while (buf < tail && *buf++ != '>')
+ /* nada */;
+ if (buf >= tail)
+ return 0;
+ dateptr = buf;
+ while (buf < tail && *buf++ != '\n')
+ /* nada */;
+ if (buf >= tail)
+ return 0;
+ /* dateptr < buf && buf[-1] == '\n', so strtoul will stop at buf-1 */
+ return strtoul(dateptr, NULL, 10);
+}
+
int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
{
- int typelen, taglen;
unsigned char sha1[20];
- const char *type_line, *tag_line, *sig_line;
char type[20];
- const char *start = data;
+ const char *bufptr = data;
+ const char *tail = bufptr + size;
+ const char *nl;
- if (item->object.parsed)
- return 0;
- item->object.parsed = 1;
+ if (item->object.parsed)
+ return 0;
+ item->object.parsed = 1;
if (size < 64)
return -1;
- if (memcmp("object ", data, 7) || get_sha1_hex((char *) data + 7, sha1))
+ if (memcmp("object ", bufptr, 7) || get_sha1_hex(bufptr + 7, sha1) || bufptr[47] != '\n')
return -1;
+ bufptr += 48; /* "object " + sha1 + "\n" */
- type_line = (char *) data + 48;
- if (memcmp("\ntype ", type_line-1, 6))
+ if (prefixcmp(bufptr, "type "))
return -1;
-
- tag_line = memchr(type_line, '\n', size - (type_line - start));
- if (!tag_line || memcmp("tag ", ++tag_line, 4))
+ bufptr += 5;
+ nl = memchr(bufptr, '\n', tail - bufptr);
+ if (!nl || sizeof(type) <= (nl - bufptr))
return -1;
-
- sig_line = memchr(tag_line, '\n', size - (tag_line - start));
- if (!sig_line)
- return -1;
- sig_line++;
-
- typelen = tag_line - type_line - strlen("type \n");
- if (typelen >= 20)
- return -1;
- memcpy(type, type_line + 5, typelen);
- type[typelen] = '\0';
- taglen = sig_line - tag_line - strlen("tag \n");
- item->tag = xmemdupz(tag_line + 4, taglen);
+ strncpy(type, bufptr, nl - bufptr);
+ type[nl - bufptr] = '\0';
+ bufptr = nl + 1;
if (!strcmp(type, blob_type)) {
item->tagged = &lookup_blob(sha1)->object;
@@ -87,6 +94,20 @@ int parse_tag_buffer(struct tag *item, void *data, unsigned long size)
item->tagged = NULL;
}
+ if (prefixcmp(bufptr, "tag "))
+ return -1;
+ bufptr += 4;
+ nl = memchr(bufptr, '\n', tail - bufptr);
+ if (!nl)
+ return -1;
+ item->tag = xmemdupz(bufptr, nl - bufptr);
+ bufptr = nl + 1;
+
+ if (!prefixcmp(bufptr, "tagger "))
+ item->date = parse_tag_date(bufptr, tail);
+ else
+ item->date = 0;
+
return 0;
}
diff --git a/tag.h b/tag.h
index 7a0cb0070d..47662724a6 100644
--- a/tag.h
+++ b/tag.h
@@ -9,7 +9,7 @@ struct tag {
struct object object;
struct object *tagged;
char *tag;
- char *signature; /* not actually implemented */
+ unsigned long date;
};
extern struct tag *lookup_tag(const unsigned char *sha1);
diff --git a/thread-utils.c b/thread-utils.c
index 4f9c829c2d..589f838f82 100644
--- a/thread-utils.c
+++ b/thread-utils.c
@@ -1,4 +1,5 @@
#include "cache.h"
+#include <pthread.h>
#if defined(hpux) || defined(__hpux) || defined(_hpux)
# include <sys/pstat.h>
@@ -43,3 +44,18 @@ int online_cpus(void)
return 1;
}
+
+int init_recursive_mutex(pthread_mutex_t *m)
+{
+ pthread_mutexattr_t a;
+ int ret;
+
+ ret = pthread_mutexattr_init(&a);
+ if (!ret) {
+ ret = pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE);
+ if (!ret)
+ ret = pthread_mutex_init(m, &a);
+ pthread_mutexattr_destroy(&a);
+ }
+ return ret;
+}
diff --git a/thread-utils.h b/thread-utils.h
index cce4b77bd6..1727a03333 100644
--- a/thread-utils.h
+++ b/thread-utils.h
@@ -2,5 +2,6 @@
#define THREAD_COMPAT_H
extern int online_cpus(void);
+extern int init_recursive_mutex(pthread_mutex_t*);
#endif /* THREAD_COMPAT_H */
diff --git a/unpack-trees.c b/unpack-trees.c
index 75f54cac97..490cd5f6f4 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -67,16 +67,8 @@ static void unlink_entry(struct cache_entry *ce)
{
if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce)))
return;
- if (S_ISGITLINK(ce->ce_mode)) {
- if (rmdir(ce->name)) {
- warning("unable to rmdir %s: %s",
- ce->name, strerror(errno));
- return;
- }
- }
- else
- if (unlink_or_warn(ce->name))
- return;
+ if (remove_or_warn(ce->ce_mode, ce->name))
+ return;
schedule_dir_for_removal(ce->name, ce_namelen(ce));
}
@@ -862,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/userdiff.c b/userdiff.c
index df992490d5..38563daa3c 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -44,7 +44,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 9c71b21242..58201b6bcb 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -3,11 +3,23 @@
*/
#include "cache.h"
+static void try_to_free_builtin(size_t size)
+{
+ release_pack_memory(size, -1);
+}
+
+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_routine = (routine) ? routine : try_to_free_builtin;
+}
+
char *xstrdup(const char *str)
{
char *ret = strdup(str);
if (!ret) {
- release_pack_memory(strlen(str) + 1, -1);
+ try_to_free_routine(strlen(str) + 1);
ret = strdup(str);
if (!ret)
die("Out of memory, strdup failed");
@@ -21,7 +33,7 @@ void *xmalloc(size_t size)
if (!ret && !size)
ret = malloc(1);
if (!ret) {
- release_pack_memory(size, -1);
+ try_to_free_routine(size);
ret = malloc(size);
if (!ret && !size)
ret = malloc(1);
@@ -67,7 +79,7 @@ void *xrealloc(void *ptr, size_t size)
if (!ret && !size)
ret = realloc(ptr, 1);
if (!ret) {
- release_pack_memory(size, -1);
+ try_to_free_routine(size);
ret = realloc(ptr, size);
if (!ret && !size)
ret = realloc(ptr, 1);
@@ -83,7 +95,7 @@ void *xcalloc(size_t nmemb, size_t size)
if (!ret && (!nmemb || !size))
ret = calloc(1, 1);
if (!ret) {
- release_pack_memory(nmemb * size, -1);
+ try_to_free_routine(nmemb * size);
ret = calloc(nmemb, size);
if (!ret && (!nmemb || !size))
ret = calloc(1, 1);
@@ -311,18 +323,30 @@ int odb_pack_keep(char *name, size_t namesz, unsigned char *sha1)
return open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
}
-int unlink_or_warn(const char *file)
+static int warn_if_unremovable(const char *op, const char *file, int rc)
{
- int rc = unlink(file);
-
if (rc < 0) {
int err = errno;
if (ENOENT != err) {
- warning("unable to unlink %s: %s",
- file, strerror(errno));
+ warning("unable to %s %s: %s",
+ op, file, strerror(errno));
errno = err;
}
}
return rc;
}
+int unlink_or_warn(const char *file)
+{
+ return warn_if_unremovable("unlink", file, unlink(file));
+}
+
+int rmdir_or_warn(const char *file)
+{
+ return warn_if_unremovable("rmdir", file, rmdir(file));
+}
+
+int remove_or_warn(unsigned int mode, const char *file)
+{
+ return S_ISGITLINK(mode) ? rmdir_or_warn(file) : unlink_or_warn(file);
+}
diff --git a/wt-status.c b/wt-status.c
index 8ca59a2d2a..d44486c826 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -625,7 +625,9 @@ void wt_status_print(struct wt_status *s)
if (s->show_untracked_files)
wt_status_print_untracked(s);
else if (s->commitable)
- fprintf(s->fp, "# Untracked files not listed (use -u option to show untracked files)\n");
+ fprintf(s->fp, "# Untracked files not listed%s\n",
+ advice_status_hints
+ ? " (use -u option to show untracked files)" : "");
if (s->verbose)
wt_status_print_verbose(s);
@@ -635,15 +637,22 @@ void wt_status_print(struct wt_status *s)
else if (s->nowarn)
; /* nothing */
else if (s->workdir_dirty)
- printf("no changes added to commit (use \"git add\" and/or \"git commit -a\")\n");
+ printf("no changes added to commit%s\n",
+ advice_status_hints
+ ? " (use \"git add\" and/or \"git commit -a\")" : "");
else if (s->untracked.nr)
- printf("nothing added to commit but untracked files present (use \"git add\" to track)\n");
+ printf("nothing added to commit but untracked files present%s\n",
+ advice_status_hints
+ ? " (use \"git add\" to track)" : "");
else if (s->is_initial)
- printf("nothing to commit (create/copy files and use \"git add\" to track)\n");
+ printf("nothing to commit%s\n", advice_status_hints
+ ? " (create/copy files and use \"git add\" to track)" : "");
else if (!s->show_untracked_files)
- printf("nothing to commit (use -u to show untracked files)\n");
+ printf("nothing to commit%s\n", advice_status_hints
+ ? " (use -u to show untracked files)" : "");
else
- printf("nothing to commit (working directory clean)\n");
+ printf("nothing to commit%s\n", advice_status_hints
+ ? " (working directory clean)" : "");
}
}
diff --git a/xdiff-interface.c b/xdiff-interface.c
index ca5e3fbae8..cd2285de1c 100644
--- a/xdiff-interface.c
+++ b/xdiff-interface.c
@@ -138,19 +138,20 @@ int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t co
int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2,
xdiff_emit_consume_fn fn, void *consume_callback_data,
- xpparam_t const *xpp,
- xdemitconf_t const *xecfg, xdemitcb_t *xecb)
+ xpparam_t const *xpp, xdemitconf_t const *xecfg)
{
int ret;
struct xdiff_emit_state state;
+ xdemitcb_t ecb;
memset(&state, 0, sizeof(state));
state.consume = fn;
state.consume_callback_data = consume_callback_data;
- xecb->outf = xdiff_outf;
- xecb->priv = &state;
+ memset(&ecb, 0, sizeof(ecb));
+ ecb.outf = xdiff_outf;
+ ecb.priv = &state;
strbuf_init(&state.remainder, 0);
- ret = xdi_diff(mf1, mf2, xpp, xecfg, xecb);
+ ret = xdi_diff(mf1, mf2, xpp, xecfg, &ecb);
strbuf_release(&state.remainder);
return ret;
}
diff --git a/xdiff-interface.h b/xdiff-interface.h
index abba70c16b..49d1116fc3 100644
--- a/xdiff-interface.h
+++ b/xdiff-interface.h
@@ -9,8 +9,7 @@ typedef void (*xdiff_emit_hunk_consume_fn)(void *, long, long, long);
int xdi_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *ecb);
int xdi_diff_outf(mmfile_t *mf1, mmfile_t *mf2,
xdiff_emit_consume_fn fn, void *consume_callback_data,
- xpparam_t const *xpp,
- xdemitconf_t const *xecfg, xdemitcb_t *xecb);
+ xpparam_t const *xpp, xdemitconf_t const *xecfg);
int xdi_diff_hunks(mmfile_t *mf1, mmfile_t *mf2,
xdiff_emit_hunk_consume_fn fn, void *consume_callback_data,
xpparam_t const *xpp, xdemitconf_t *xecfg);