aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap1
-rw-r--r--Documentation/RelNotes-1.7.0.1.txt35
-rw-r--r--Documentation/RelNotes-1.7.0.2.txt40
-rw-r--r--Documentation/RelNotes-1.7.0.3.txt34
-rw-r--r--Documentation/config.txt11
-rw-r--r--Documentation/git-am.txt2
-rw-r--r--Documentation/git-check-ref-format.txt5
-rw-r--r--Documentation/git-clone.txt12
-rw-r--r--Documentation/git-commit.txt6
-rw-r--r--Documentation/git-describe.txt3
-rw-r--r--Documentation/git-fast-import.txt5
-rw-r--r--Documentation/git-fetch-pack.txt6
-rw-r--r--Documentation/git-grep.txt47
-rw-r--r--Documentation/git-index-pack.txt12
-rw-r--r--Documentation/git-pack-objects.txt54
-rw-r--r--Documentation/git-prune.txt2
-rw-r--r--Documentation/git-push.txt13
-rw-r--r--Documentation/git-read-tree.txt46
-rw-r--r--Documentation/git-reflog.txt2
-rw-r--r--Documentation/git-rev-parse.txt28
-rw-r--r--Documentation/git-send-pack.txt4
-rw-r--r--Documentation/git-show-branch.txt10
-rw-r--r--Documentation/git-stash.txt2
-rw-r--r--Documentation/git-var.txt2
-rw-r--r--Documentation/git.txt13
-rw-r--r--Documentation/gitattributes.txt3
-rw-r--r--Documentation/gitdiffcore.txt2
-rw-r--r--Documentation/rev-list-options.txt22
-rw-r--r--Documentation/technical/api-run-command.txt52
-rw-r--r--Documentation/urls.txt6
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile7
l---------RelNotes2
-rw-r--r--advice.c2
-rw-r--r--advice.h1
-rw-r--r--bisect.c6
-rw-r--r--builtin-blame.c2
-rw-r--r--builtin-cat-file.c5
-rw-r--r--builtin-checkout.c18
-rw-r--r--builtin-commit.c4
-rw-r--r--builtin-fetch-pack.c7
-rw-r--r--builtin-fetch.c47
-rw-r--r--builtin-grep.c36
-rw-r--r--builtin-log.c2
-rw-r--r--builtin-mailinfo.c3
-rw-r--r--builtin-pack-objects.c18
-rw-r--r--builtin-prune.c27
-rw-r--r--builtin-push.c2
-rw-r--r--builtin-receive-pack.c175
-rw-r--r--builtin-reflog.c6
-rw-r--r--builtin-rev-list.c5
-rw-r--r--builtin-rev-parse.c7
-rw-r--r--builtin-revert.c42
-rw-r--r--builtin-send-pack.c66
-rw-r--r--builtin-shortlog.c17
-rw-r--r--builtin-show-branch.c2
-rw-r--r--builtin-var.c4
-rw-r--r--cache.h15
-rw-r--r--compat/mkdtemp.c2
-rw-r--r--compat/mkstemps.c70
-rw-r--r--compat/win32/pthread.c2
-rw-r--r--connect.c16
-rwxr-xr-xcontrib/completion/git-completion.bash4
-rwxr-xr-xcontrib/fast-import/git-p45
-rwxr-xr-xcontrib/fast-import/import-directories.perl2
-rw-r--r--convert.c5
-rw-r--r--daemon.c4
-rw-r--r--diff.c27
-rw-r--r--dir.c2
-rw-r--r--environment.c17
-rw-r--r--fast-import.c174
-rwxr-xr-xgit-add--interactive.perl24
-rwxr-xr-xgit-am.sh8
-rwxr-xr-xgit-pull.sh2
-rwxr-xr-xgit-sh-setup.sh22
-rwxr-xr-xgit-stash.sh8
-rwxr-xr-xgit-submodule.sh20
-rwxr-xr-xgit-svn.perl9
-rw-r--r--git.c2
-rw-r--r--gitweb/README67
-rwxr-xr-xgitweb/gitweb.perl18
-rw-r--r--grep.c46
-rw-r--r--grep.h2
-rw-r--r--help.c2
-rw-r--r--imap-send.c40
-rw-r--r--levenshtein.h2
-rw-r--r--pager.c6
-rw-r--r--path.c81
-rw-r--r--perl/Git.pm4
-rw-r--r--refs.c24
-rw-r--r--remote-curl.c7
-rw-r--r--rerere.c9
-rw-r--r--revision.c12
-rw-r--r--run-command.c100
-rw-r--r--run-command.h11
-rw-r--r--setup.c2
-rw-r--r--sha1_file.c49
-rw-r--r--sha1_name.c35
-rw-r--r--submodule.c22
-rw-r--r--t/Makefile2
-rw-r--r--[-rwxr-xr-x]t/lib-patch-mode.sh2
-rwxr-xr-xt/t1304-default-acl.sh67
-rwxr-xr-xt/t1410-reflog.sh41
-rwxr-xr-xt/t1411-reflog-show.sh9
-rwxr-xr-xt/t1450-fsck.sh16
-rwxr-xr-xt/t2016-checkout-patch.sh8
-rwxr-xr-xt/t3301-notes.sh1
-rwxr-xr-xt/t3600-rm.sh8
-rwxr-xr-xt/t3903-stash.sh9
-rwxr-xr-xt/t4017-diff-retval.sh15
-rw-r--r--t/t5100/msg00152
-rwxr-xr-xt/t5304-prune.sh32
-rwxr-xr-xt/t5401-update-hooks.sh84
-rwxr-xr-xt/t5521-pull-options.sh85
-rw-r--r--[-rwxr-xr-x]t/t6000lib.sh2
-rwxr-xr-xt/t6030-bisect-porcelain.sh5
-rwxr-xr-xt/t7002-grep.sh43
-rwxr-xr-xt/t7006-pager.sh176
-rwxr-xr-xt/t7006/test-terminal.perl58
-rwxr-xr-xt/t7201-co.sh32
-rwxr-xr-xt/t7406-submodule-update.sh24
-rwxr-xr-xt/t8003-blame.sh20
-rwxr-xr-xt/t9400-git-cvsserver-server.sh24
-rwxr-xr-xt/t9500-gitweb-standalone-no-errors.sh18
-rw-r--r--t/test-lib.sh2
-rw-r--r--test-chmtime.c2
-rw-r--r--transport-helper.c2
-rw-r--r--transport.c5
-rw-r--r--transport.h6
-rw-r--r--tree-walk.c1
-rw-r--r--upload-pack.c7
-rw-r--r--utf8.c61
-rw-r--r--utf8.h1
-rw-r--r--wrapper.c20
134 files changed, 2075 insertions, 789 deletions
diff --git a/.mailmap b/.mailmap
index 975e6758e..88bd01e16 100644
--- a/.mailmap
+++ b/.mailmap
@@ -36,6 +36,7 @@ Li Hong <leehong@pku.edu.cn>
Lukas Sandström <lukass@etek.chalmers.se>
Martin Langhoff <martin@catalyst.net.nz>
Michael Coleman <tutufan@gmail.com>
+Michael J Gruber <git@drmicha.warpmail.net> <michaeljgruber+gmane@fastmail.fm>
Michael W. Olson <mwolson@gnu.org>
Michele Ballabio <barra_cuda@katamail.com>
Nanako Shiraishi <nanako3@bluebottle.com>
diff --git a/Documentation/RelNotes-1.7.0.1.txt b/Documentation/RelNotes-1.7.0.1.txt
new file mode 100644
index 000000000..8ff5bcada
--- /dev/null
+++ b/Documentation/RelNotes-1.7.0.1.txt
@@ -0,0 +1,35 @@
+Git v1.7.0.1 Release Notes
+==========================
+
+Fixes since v1.7.0
+------------------
+
+ * In a freshly created repository "rev-parse HEAD^0" complained that
+ it is dangling symref, even though "rev-parse HEAD" didn't.
+
+ * "git show :no-such-name" tried to access the index without bounds
+ check, leading to a potential segfault.
+
+ * Message from "git cherry-pick" was harder to read and use than necessary
+ when it stopped due to conflicting changes.
+
+ * We referred to ".git/refs/" throughout the documentation when we
+ meant to talk about abstract notion of "ref namespace". Because
+ people's repositories often have packed refs these days, this was
+ confusing.
+
+ * "git diff --output=/path/that/cannot/be/written" did not correctly
+ error out.
+
+ * "git grep -e -pattern-that-begin-with-dash paths..." could not be
+ spelled as "git grep -- -pattern-that-begin-with-dash paths..." which
+ would be a GNU way to use "--" as "end of options".
+
+ * "git grep" compiled with threading support tried to access an
+ uninitialized mutex on boxes with a single CPU.
+
+ * "git stash pop -q --index" failed because the unnecessary --index
+ option was propagated to "git stash drop" that is internally run at the
+ end.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes-1.7.0.2.txt b/Documentation/RelNotes-1.7.0.2.txt
new file mode 100644
index 000000000..fcb46ca6a
--- /dev/null
+++ b/Documentation/RelNotes-1.7.0.2.txt
@@ -0,0 +1,40 @@
+Git v1.7.0.2 Release Notes
+==========================
+
+Fixes since v1.7.0.1
+--------------------
+
+ * GIT_PAGER was not honored consistently by some scripted Porcelains, most
+ notably "git am".
+
+ * updating working tree files after telling git to add them to the
+ index and while it is still working created garbage object files in
+ the repository without diagnosing it as an error.
+
+ * "git bisect -- pathspec..." did not diagnose an error condition properly when
+ the simplification with given pathspec made the history empty.
+
+ * "git rev-list --cherry-pick A...B" now has an obvious optimization when the
+ histories haven't diverged (i.e. when one end is an ancestor of the other).
+
+ * "git diff --quiet -w" did not work as expected.
+
+ * "git fast-import" didn't work with a large input, as it lacked support
+ for producing the pack index in v2 format.
+
+ * "git imap-send" didn't use CRLF line endings over the imap protocol
+ when storing its payload to the draft box, violating RFC 3501.
+
+ * "git log --format='%w(x,y,z)%b'" and friends that rewrap message
+ has been optimized for utf-8 payload.
+
+ * Error messages generated on the receiving end did not come back to "git
+ push".
+
+ * "git status" in 1.7.0 lacked the optimization we used to have in 1.6.X series
+ to speed up scanning of large working tree.
+
+ * "gitweb" did not diagnose parsing errors properly while reading tis configuration
+ file.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes-1.7.0.3.txt b/Documentation/RelNotes-1.7.0.3.txt
new file mode 100644
index 000000000..3b355737c
--- /dev/null
+++ b/Documentation/RelNotes-1.7.0.3.txt
@@ -0,0 +1,34 @@
+Git v1.7.0.3 Release Notes
+==========================
+
+Fixes since v1.7.0.2
+--------------------
+
+ * Object files are created in a more ACL friendly way in repositories
+ where group permission is ACL controlled.
+
+ * "git add -i" didn't handle a deleted path very well.
+
+ * "git blame" padded line numbers with one extra SP when the total number
+ of lines was one less than multiple of ten due to an off-by-one error.
+
+ * "git fetch --all/--multi" used to discard information for remotes that
+ are fetched earlier.
+
+ * "git log --author=me --grep=it" tried to find commits that have "it"
+ or are written by "me", instead of the ones that have "it" _and_ are
+ written by "me".
+
+ * "git log -g branch" misbehaved when there was no entries in the reflog
+ for the named branch.
+
+ * "git mailinfo" (hence "git am") incorrectly removed initial indent from
+ paragraphs.
+
+ * "git prune" and "git reflog" (hence "git gc" as well) didn't honor
+ an instruction never to expire by setting gc.reflogexpire to never.
+
+ * "git push" misbehaved when branch.<name>.merge was configured without
+ matching branch.<name>.remote.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 4c36aa95b..437b4ac5e 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -138,6 +138,11 @@ advice.*::
Advice on how to set your identity configuration when
your information is guessed from the system username and
domain name. Default: true.
+
+ detachedHead::
+ Advice shown when you used linkgit::git-checkout[1] to
+ move to the detach HEAD state, to instruct how to create
+ a local branch after the fact. Default: true.
--
core.fileMode::
@@ -680,9 +685,7 @@ color.grep::
color.grep.match::
Use customized color for matches. The value of this variable
- may be specified as in color.branch.<slot>. It is passed using
- the environment variables 'GREP_COLOR' and 'GREP_COLORS' when
- calling an external 'grep'.
+ may be specified as in color.branch.<slot>.
color.interactive::
When set to `always`, always use colors for interactive prompts
@@ -1439,7 +1442,7 @@ receive.denyCurrentBranch::
out of sync with the index and working tree. If set to "warn",
print a warning of such a push to stderr, but allow the push to
proceed. If set to false or "ignore", allow such pushes with no
- message. Defaults to "warn".
+ message. Defaults to "refuse".
receive.denyNonFastForwards::
If set to true, git-receive-pack will deny a ref update which is
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index c66c565bb..23864df8d 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -44,7 +44,7 @@ OPTIONS
Remove everything in body before a scissors line (see
linkgit:git-mailinfo[1]).
----no-scissors::
+--no-scissors::
Ignore scissors lines (see linkgit:git-mailinfo[1]).
-q::
diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt
index e1c4320f0..379eee673 100644
--- a/Documentation/git-check-ref-format.txt
+++ b/Documentation/git-check-ref-format.txt
@@ -19,8 +19,9 @@ status if it is not.
A reference is used in git to specify branches and tags. A
branch head is stored under the `$GIT_DIR/refs/heads` directory, and
-a tag is stored under the `$GIT_DIR/refs/tags` directory. git
-imposes the following rules on how references are named:
+a tag is stored under the `$GIT_DIR/refs/tags` directory (or, if refs
+are packed by `git gc`, as entries in the `$GIT_DIR/packed-refs` file).
+git imposes the following rules on how references are named:
. They can include slash `/` for hierarchical (directory)
grouping, but no slash-separated component can begin with a
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index f43c8b2c0..d15cb17d7 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -29,7 +29,7 @@ arguments will in addition merge the remote master branch into the
current master branch, if any.
This default configuration is achieved by creating references to
-the remote branch heads under `$GIT_DIR/refs/remotes/origin` and
+the remote branch heads under `refs/remotes/origin` and
by initializing `remote.origin.url` and `remote.origin.fetch`
configuration variables.
@@ -187,7 +187,7 @@ include::urls.txt[]
Examples
--------
-Clone from upstream::
+* Clone from upstream:
+
------------
$ git clone git://git.kernel.org/pub/scm/.../linux-2.6 my2.6
@@ -196,7 +196,7 @@ $ make
------------
-Make a local clone that borrows from the current directory, without checking things out::
+* Make a local clone that borrows from the current directory, without checking things out:
+
------------
$ git clone -l -s -n . ../copy
@@ -205,7 +205,7 @@ $ git show-branch
------------
-Clone from upstream while borrowing from an existing local directory::
+* Clone from upstream while borrowing from an existing local directory:
+
------------
$ git clone --reference my2.6 \
@@ -215,14 +215,14 @@ $ cd my2.7
------------
-Create a bare repository to publish your changes to the public::
+* Create a bare repository to publish your changes to the public:
+
------------
$ git clone --bare -l /home/proj/.git /pub/scm/proj.git
------------
-Create a repository on the kernel.org machine that borrows from Linus::
+* Create a repository on the kernel.org machine that borrows from Linus:
+
------------
$ git clone --bare -l -s /pub/scm/.../torvalds/linux-2.6.git \
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index e99bb1475..64fb458b4 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -197,13 +197,13 @@ FROM UPSTREAM REBASE" section in linkgit:git-rebase[1].)
Show untracked files (Default: 'all').
+
The mode parameter is optional, and is used to specify
-the handling of untracked files. The possible options are:
+the handling of untracked files.
++
+The possible options are:
+
---
- 'no' - Show no untracked files
- 'normal' - Shows untracked files and directories
- 'all' - Also shows individual files in untracked directories.
---
+
See linkgit:git-config[1] for configuration variable
used to change the default for when the option is not
diff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt
index 6fc5323ee..7ef9d5157 100644
--- a/Documentation/git-describe.txt
+++ b/Documentation/git-describe.txt
@@ -105,6 +105,9 @@ The number of additional commits is the number
of commits which would be displayed by "git log v1.0.4..parent".
The hash suffix is "-g" + 7-char abbreviation for the tip commit
of parent (which was `2414721b194453f058079d897d13c4e377f92dc6`).
+The "g" prefix stands for "git" and is used to allow describing the version of
+a software depending on the SCM the software is managed with. This is useful
+in an environment where people may use different SCMs.
Doing a 'git describe' on a tag-name will just show the tag name:
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index 6764ff188..19082b04e 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -45,10 +45,7 @@ OPTIONS
--max-pack-size=<n>::
Maximum size of each output packfile.
- The default is 4 GiB as that is the maximum allowed
- packfile size (due to file format limitations). Some
- importers may wish to lower this, such as to ensure the
- resulting packfiles fit on CDs.
+ The default is unlimited.
--big-file-threshold=<n>::
Maximum size of a blob that fast-import will attempt to
diff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt
index e9952e821..4a8487c15 100644
--- a/Documentation/git-fetch-pack.txt
+++ b/Documentation/git-fetch-pack.txt
@@ -18,7 +18,7 @@ higher level wrapper of this command, instead.
Invokes 'git-upload-pack' on a possibly remote repository
and asks it to send objects missing from this repository, to
update the named heads. The list of commits available locally
-is found out by scanning local $GIT_DIR/refs/ and sent to
+is found out by scanning the local refs/ hierarchy and sent to
'git-upload-pack' running on the other end.
This command degenerates to download everything to complete the
@@ -44,8 +44,8 @@ OPTIONS
locked against repacking.
--thin::
- Spend extra cycles to minimize the number of objects to be sent.
- Use it on slower connection.
+ Fetch a "thin" pack, which records objects in deltified form based
+ on objects not included in the pack to reduce network traffic.
--include-tag::
If the remote side supports it, annotated tags objects will
diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt
index e019e760b..ee506e67f 100644
--- a/Documentation/git-grep.txt
+++ b/Documentation/git-grep.txt
@@ -9,8 +9,7 @@ git-grep - Print lines matching a pattern
SYNOPSIS
--------
[verse]
-'git grep' [--cached]
- [-a | --text] [-I] [-i | --ignore-case] [-w | --word-regexp]
+'git grep' [-a | --text] [-I] [-i | --ignore-case] [-w | --word-regexp]
[-v | --invert-match] [-h|-H] [--full-name]
[-E | --extended-regexp] [-G | --basic-regexp]
[-F | --fixed-strings] [-n]
@@ -21,20 +20,24 @@ SYNOPSIS
[--color | --no-color]
[-A <post-context>] [-B <pre-context>] [-C <context>]
[-f <file>] [-e] <pattern>
- [--and|--or|--not|(|)|-e <pattern>...] [<tree>...]
- [--] [<path>...]
+ [--and|--or|--not|(|)|-e <pattern>...]
+ [--cached | --no-index | <tree>...]
+ [--] [<pathspec>...]
DESCRIPTION
-----------
-Look for specified patterns in the working tree files, blobs
-registered in the index file, or given tree objects.
+Look for specified patterns in the tracked files in the work tree, blobs
+registered in the index file, or blobs in given tree objects.
OPTIONS
-------
--cached::
- Instead of searching in the working tree files, check
- the blobs registered in the index file.
+ Instead of searching tracked files in the working tree, search
+ blobs registered in the index file.
+
+--no-index::
+ Search files in the current directory, not just those tracked by git.
-a::
--text::
@@ -49,7 +52,7 @@ OPTIONS
Don't match the pattern in binary files.
--max-depth <depth>::
- For each pathspec given on command line, descend at most <depth>
+ For each <pathspec> given on command line, descend at most <depth>
levels of directories. A negative value means no limit.
-w::
@@ -98,8 +101,8 @@ OPTIONS
--files-without-match::
Instead of showing every matched line, show only the
names of files that contain (or do not contain) matches.
- For better compatibility with 'git diff', --name-only is a
- synonym for --files-with-matches.
+ For better compatibility with 'git diff', `--name-only` is a
+ synonym for `--files-with-matches`.
-z::
--null::
@@ -125,7 +128,7 @@ OPTIONS
matches.
-<num>::
- A shortcut for specifying -C<num>.
+ A shortcut for specifying `-C<num>`.
-p::
--show-function::
@@ -140,7 +143,7 @@ OPTIONS
-e::
The next parameter is the pattern. This option has to be
- used for patterns starting with - and should be used in
+ used for patterns starting with `-` and should be used in
scripts passing user input to grep. Multiple patterns are
combined by 'or'.
@@ -163,16 +166,24 @@ OPTIONS
Do not output matched lines; instead, exit with status 0 when
there is a match and with non-zero status when there isn't.
-`<tree>...`::
- Search blobs in the trees for specified patterns.
+<tree>...::
+ Instead of searching tracked files in the working tree, search
+ blobs in the given trees.
\--::
Signals the end of options; the rest of the parameters
- are <path> limiters.
+ are <pathspec> limiters.
+<pathspec>...::
+ If given, limit the search to paths matching at least one pattern.
+ Both leading paths match and glob(7) patterns are supported.
-Example
--------
+Examples
+--------
+
+git grep 'time_t' -- '*.[ch]'::
+ Looks for `time_t` in all tracked .c and .h files in the working
+ directory and its subdirectories.
git grep -e \'#define\' --and \( -e MAX_PATH -e PATH_MAX \)::
Looks for a line that has `#define` and either `MAX_PATH` or
diff --git a/Documentation/git-index-pack.txt b/Documentation/git-index-pack.txt
index 65a301bec..f3ccc72f0 100644
--- a/Documentation/git-index-pack.txt
+++ b/Documentation/git-index-pack.txt
@@ -46,14 +46,10 @@ OPTIONS
'git repack'.
--fix-thin::
- It is possible for 'git pack-objects' to build
- "thin" pack, which records objects in deltified form based on
- objects not included in the pack to reduce network traffic.
- Those objects are expected to be present on the receiving end
- and they must be included in the pack for that pack to be self
- contained and indexable. Without this option any attempt to
- index a thin pack will fail. This option only makes sense in
- conjunction with --stdin.
+ Fix a "thin" pack produced by `git pack-objects --thin` (see
+ linkgit:git-pack-objects[1] for details) by adding the
+ excluded objects the deltified objects are based on to the
+ pack. This option only makes sense in conjunction with --stdin.
--keep::
Before moving the index into its final destination
diff --git a/Documentation/git-pack-objects.txt b/Documentation/git-pack-objects.txt
index ffd5025f7..8ed09c0b3 100644
--- a/Documentation/git-pack-objects.txt
+++ b/Documentation/git-pack-objects.txt
@@ -21,16 +21,21 @@ DESCRIPTION
Reads list of objects from the standard input, and writes a packed
archive with specified base-name, or to the standard output.
-A packed archive is an efficient way to transfer set of objects
-between two repositories, and also is an archival format which
-is efficient to access. The packed archive format (.pack) is
-designed to be self contained so that it can be unpacked without
-any further information, but for fast, random access to the objects
-in the pack, a pack index file (.idx) will be generated.
-
-Placing both in the pack/ subdirectory of $GIT_OBJECT_DIRECTORY (or
+A packed archive is an efficient way to transfer a set of objects
+between two repositories as well as an access efficient archival
+format. In a packed archive, an object is either stored as a
+compressed whole or as a difference from some other object.
+The latter is often called a delta.
+
+The packed archive format (.pack) is designed to be self-contained
+so that it can be unpacked without any further information. Therefore,
+each object that a delta depends upon must be present within the pack.
+
+A pack index file (.idx) is generated for fast, random access to the
+objects in the pack. Placing both the index file (.idx) and the packed
+archive (.pack) in the pack/ subdirectory of $GIT_OBJECT_DIRECTORY (or
any of the directories on $GIT_ALTERNATE_OBJECT_DIRECTORIES)
-enables git to read from such an archive.
+enables git to read from the pack archive.
The 'git unpack-objects' command can read the packed archive and
expand the objects contained in the pack into "one-file
@@ -38,10 +43,6 @@ one-object" format; this is typically done by the smart-pull
commands when a pack is created on-the-fly for efficient network
transport by their peers.
-In a packed archive, an object is either stored as a compressed
-whole, or as a difference from some other object. The latter is
-often called a delta.
-
OPTIONS
-------
@@ -73,7 +74,7 @@ base-name::
--all::
This implies `--revs`. In addition to the list of
revision arguments read from the standard input, pretend
- as if all refs under `$GIT_DIR/refs` are specified to be
+ as if all refs under `refs/` are specified to be
included.
--include-tag::
@@ -114,18 +115,17 @@ base-name::
--honor-pack-keep::
This flag causes an object already in a local pack that
- has a .keep file to be ignored, even if it appears in the
- standard input.
+ has a .keep file to be ignored, even if it it would have
+ otherwise been packed.
--incremental::
- This flag causes an object already in a pack ignored
- even if it appears in the standard input.
+ This flag causes an object already in a pack to be ignored
+ even if it would have otherwise been packed.
--local::
- This flag is similar to `--incremental`; instead of
- ignoring all packed objects, it only ignores objects
- that are packed and/or not in the local object store
- (i.e. borrowed from an alternate).
+ This flag causes an object that is borrowed from an alternate
+ object store to be ignored even if it would have otherwise been
+ packed.
--non-empty::
Only create a packed archive if it would contain at
@@ -179,6 +179,16 @@ base-name::
Add --no-reuse-object if you want to force a uniform compression
level on all data no matter the source.
+--thin::
+ Create a "thin" pack by omitting the common objects between a
+ sender and a receiver in order to reduce network transfer. This
+ option only makes sense in conjunction with --stdout.
++
+Note: A thin pack violates the packed archive format by omitting
+required objects and is thus unusable by git without making it
+self-contained. Use `git index-pack --fix-thin`
+(see linkgit:git-index-pack[1]) to restore the self-contained property.
+
--delta-base-offset::
A packed archive can express base object of a delta as
either 20-byte object name or as an offset in the
diff --git a/Documentation/git-prune.txt b/Documentation/git-prune.txt
index 3bb730451..15cfb7a8d 100644
--- a/Documentation/git-prune.txt
+++ b/Documentation/git-prune.txt
@@ -17,7 +17,7 @@ NOTE: In most cases, users should run 'git gc', which calls
'git prune'. See the section "NOTES", below.
This runs 'git fsck --unreachable' using all the refs
-available in `$GIT_DIR/refs`, optionally with additional set of
+available in `refs/`, optionally with additional set of
objects specified on the command line, and prunes all unpacked
objects unreachable from any of these head objects from the object database.
In addition, it
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index bd79119dd..49b6bd9d9 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -69,11 +69,11 @@ nor in any Push line of the corresponding remotes file---see below).
--all::
Instead of naming each ref to push, specifies that all
- refs under `$GIT_DIR/refs/heads/` be pushed.
+ refs under `refs/heads/` be pushed.
--mirror::
Instead of naming each ref to push, specifies that all
- refs under `$GIT_DIR/refs/` (which includes but is not
+ refs under `refs/` (which includes but is not
limited to `refs/heads/`, `refs/remotes/`, and `refs/tags/`)
be mirrored to the remote repository. Newly created local
refs will be pushed to the remote end, locally updated refs
@@ -96,7 +96,7 @@ nor in any Push line of the corresponding remotes file---see below).
the same as prefixing all refs with a colon.
--tags::
- All refs under `$GIT_DIR/refs/tags` are pushed, in
+ All refs under `refs/tags` are pushed, in
addition to refspecs explicitly listed on the command
line.
@@ -141,9 +141,10 @@ useful if you write an alias or script around 'git push'.
--thin::
--no-thin::
- These options are passed to 'git send-pack'. Thin
- transfer spends extra cycles to minimize the number of
- objects to be sent and meant to be used on slower connection.
+ These options are passed to linkgit:git-send-pack[1]. A thin transfer
+ significantly reduces the amount of sent data when the sender and
+ receiver share many of the same objects in common. The default is
+ \--thin.
-v::
--verbose::
diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt
index 567671c01..f6037c4f6 100644
--- a/Documentation/git-read-tree.txt
+++ b/Documentation/git-read-tree.txt
@@ -130,7 +130,7 @@ Single Tree Merge
~~~~~~~~~~~~~~~~~
If only 1 tree is specified, 'git read-tree' operates as if the user did not
specify `-m`, except that if the original index has an entry for a
-given pathname, and the contents of the path matches with the tree
+given pathname, and the contents of the path match with the tree
being read, the stat info from the index is used. (In other words, the
index's stat()s take precedence over the merged tree's).
@@ -154,40 +154,42 @@ When two trees are specified, the user is telling 'git read-tree'
the following:
1. The current index and work tree is derived from $H, but
- the user may have local changes in them since $H;
+ the user may have local changes in them since $H.
2. The user wants to fast-forward to $M.
In this case, the `git read-tree -m $H $M` command makes sure
that no local change is lost as the result of this "merge".
-Here are the "carry forward" rules:
+Here are the "carry forward" rules, where "I" denotes the index,
+"clean" means that index and work tree coincide, and "exists"/"nothing"
+refer to the presence of a path in the specified commit:
- I (index) H M Result
+ I H M Result
-------------------------------------------------------
- 0 nothing nothing nothing (does not happen)
- 1 nothing nothing exists use M
- 2 nothing exists nothing remove path from index
- 3 nothing exists exists, use M if "initial checkout"
+ 0 nothing nothing nothing (does not happen)
+ 1 nothing nothing exists use M
+ 2 nothing exists nothing remove path from index
+ 3 nothing exists exists, use M if "initial checkout",
H == M keep index otherwise
- exists fail
+ exists, fail
H != M
clean I==H I==M
------------------
- 4 yes N/A N/A nothing nothing keep index
- 5 no N/A N/A nothing nothing keep index
+ 4 yes N/A N/A nothing nothing keep index
+ 5 no N/A N/A nothing nothing keep index
- 6 yes N/A yes nothing exists keep index
- 7 no N/A yes nothing exists keep index
- 8 yes N/A no nothing exists fail
- 9 no N/A no nothing exists fail
+ 6 yes N/A yes nothing exists keep index
+ 7 no N/A yes nothing exists keep index
+ 8 yes N/A no nothing exists fail
+ 9 no N/A no nothing exists fail
10 yes yes N/A exists nothing remove path from index
11 no yes N/A exists nothing fail
12 yes no N/A exists nothing fail
13 no no N/A exists nothing fail
- clean (H=M)
+ clean (H==M)
------
14 yes exists exists keep index
15 no exists exists keep index
@@ -202,26 +204,26 @@ Here are the "carry forward" rules:
21 no yes no exists exists fail
In all "keep index" cases, the index entry stays as in the
-original index file. If the entry were not up to date,
+original index file. If the entry is not up to date,
'git read-tree' keeps the copy in the work tree intact when
operating under the -u flag.
When this form of 'git read-tree' returns successfully, you can
-see what "local changes" you made are carried forward by running
+see which of the "local changes" that you made were carried forward by running
`git diff-index --cached $M`. Note that this does not
-necessarily match `git diff-index --cached $H` would have
+necessarily match what `git diff-index --cached $H` would have
produced before such a two tree merge. This is because of cases
18 and 19 --- if you already had the changes in $M (e.g. maybe
you picked it up via e-mail in a patch form), `git diff-index
--cached $H` would have told you about the change before this
merge, but it would not show in `git diff-index --cached $M`
-output after two-tree merge.
+output after the two-tree merge.
-Case #3 is slightly tricky and needs explanation. The result from this
+Case 3 is slightly tricky and needs explanation. The result from this
rule logically should be to remove the path if the user staged the removal
of the path and then switching to a new branch. That however will prevent
the initial checkout from happening, so the rule is modified to use M (new
-tree) only when the contents of the index is empty. Otherwise the removal
+tree) only when the content of the index is empty. Otherwise the removal
of the path is kept as long as $H and $M are the same.
3-Way Merge
diff --git a/Documentation/git-reflog.txt b/Documentation/git-reflog.txt
index 802bd5791..4eaa62b69 100644
--- a/Documentation/git-reflog.txt
+++ b/Documentation/git-reflog.txt
@@ -18,9 +18,7 @@ depending on the subcommand:
[verse]
'git reflog expire' [--dry-run] [--stale-fix] [--verbose]
[--expire=<time>] [--expire-unreachable=<time>] [--all] <refs>...
-+
'git reflog delete' ref@\{specifier\}...
-+
'git reflog' ['show'] [log-options] [<ref>]
Reflog is a mechanism to record when the tip of branches are
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index d677c72d5..8db600f6b 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -101,15 +101,14 @@ OPTIONS
abbreviation mode.
--all::
- Show all refs found in `$GIT_DIR/refs`.
+ Show all refs found in `refs/`.
--branches[=pattern]::
--tags[=pattern]::
--remotes[=pattern]::
Show all branches, tags, or remote-tracking branches,
- respectively (i.e., refs found in `$GIT_DIR/refs/heads`,
- `$GIT_DIR/refs/tags`, or `$GIT_DIR/refs/remotes`,
- respectively).
+ respectively (i.e., refs found in `refs/heads`,
+ `refs/tags`, or `refs/remotes`, respectively).
+
If a `pattern` is given, only refs matching the given shell glob are
shown. If the pattern does not contain a globbing character (`?`,
@@ -149,6 +148,12 @@ shown. If the pattern does not contain a globbing character (`?`,
--is-bare-repository::
When the repository is bare print "true", otherwise "false".
+--local-env-vars::
+ List the GIT_* environment variables that are local to the
+ repository (e.g. GIT_DIR or GIT_WORK_TREE, but not GIT_EDITOR).
+ Only the names of the variables are listed, not their value,
+ even if they are set.
+
--short::
--short=number::
Instead of outputting the full SHA1 values of object names try to
@@ -189,7 +194,7 @@ blobs contained in a commit.
`g`, and an abbreviated object name.
* A symbolic ref name. E.g. 'master' typically means the commit
- object referenced by $GIT_DIR/refs/heads/master. If you
+ object referenced by refs/heads/master. If you
happen to have both heads/master and tags/master, you can
explicitly say 'heads/master' to tell git which one you mean.
When ambiguous, a `<name>` is disambiguated by taking the
@@ -198,15 +203,15 @@ blobs contained in a commit.
. if `$GIT_DIR/<name>` exists, that is what you mean (this is usually
useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD` and `MERGE_HEAD`);
- . otherwise, `$GIT_DIR/refs/<name>` if exists;
+ . otherwise, `refs/<name>` if exists;
- . otherwise, `$GIT_DIR/refs/tags/<name>` if exists;
+ . otherwise, `refs/tags/<name>` if exists;
- . otherwise, `$GIT_DIR/refs/heads/<name>` if exists;
+ . otherwise, `refs/heads/<name>` if exists;
- . otherwise, `$GIT_DIR/refs/remotes/<name>` if exists;
+ . otherwise, `refs/remotes/<name>` if exists;
- . otherwise, `$GIT_DIR/refs/remotes/<name>/HEAD` if exists.
+ . otherwise, `refs/remotes/<name>/HEAD` if exists.
+
HEAD names the commit your changes in the working tree is based on.
FETCH_HEAD records the branch you fetched from a remote repository
@@ -217,6 +222,9 @@ you can change the tip of the branch back to the state before you ran
them easily.
MERGE_HEAD records the commit(s) you are merging into your branch
when you run 'git merge'.
++
+Note that any of the `refs/*` cases above may come either from
+the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file.
* A ref followed by the suffix '@' with a date specification
enclosed in a brace
diff --git a/Documentation/git-send-pack.txt b/Documentation/git-send-pack.txt
index 8178d9264..deaa7d965 100644
--- a/Documentation/git-send-pack.txt
+++ b/Documentation/git-send-pack.txt
@@ -48,8 +48,8 @@ OPTIONS
Run verbosely.
--thin::
- Spend extra cycles to minimize the number of objects to be sent.
- Use it on slower connection.
+ Send a "thin" pack, which records objects in deltified form based
+ on objects not included in the pack to reduce network traffic.
<host>::
A remote host to house the repository. When this
diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt
index 734336119..b9c4154e7 100644
--- a/Documentation/git-show-branch.txt
+++ b/Documentation/git-show-branch.txt
@@ -20,8 +20,8 @@ DESCRIPTION
-----------
Shows the commit ancestry graph starting from the commits named
-with <rev>s or <globs>s (or all refs under $GIT_DIR/refs/heads
-and/or $GIT_DIR/refs/tags) semi-visually.
+with <rev>s or <globs>s (or all refs under refs/heads
+and/or refs/tags) semi-visually.
It cannot show more than 29 branches and commits at a time.
@@ -37,8 +37,8 @@ OPTIONS
<glob>::
A glob pattern that matches branch or tag names under
- $GIT_DIR/refs. For example, if you have many topic
- branches under $GIT_DIR/refs/heads/topic, giving
+ refs/. For example, if you have many topic
+ branches under refs/heads/topic, giving
`topic/*` would show all of them.
-r::
@@ -176,7 +176,7 @@ EXAMPLE
-------
If you keep your primary branches immediately under
-`$GIT_DIR/refs/heads`, and topic branches in subdirectories of
+`refs/heads`, and topic branches in subdirectories of
it, having the following in the configuration file may help:
------------
diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt
index 84e555d81..473889a66 100644
--- a/Documentation/git-stash.txt
+++ b/Documentation/git-stash.txt
@@ -33,7 +33,7 @@ A stash is by default listed as "WIP on 'branchname' ...", but
you can give a more descriptive message on the command line when
you create one.
-The latest stash you created is stored in `$GIT_DIR/refs/stash`; older
+The latest stash you created is stored in `refs/stash`; older
stashes are found in the reflog of this reference and can be named using
the usual reflog syntax (e.g. `stash@\{0}` is the most recently
created stash, `stash@\{1}` is the one before it, `stash@\{2.hours.ago}`
diff --git a/Documentation/git-var.txt b/Documentation/git-var.txt
index bb981822a..458f3e275 100644
--- a/Documentation/git-var.txt
+++ b/Documentation/git-var.txt
@@ -8,7 +8,7 @@ git-var - Show a git logical variable
SYNOPSIS
--------
-'git var' [ -l | <variable> ]
+'git var' ( -l | <variable> )
DESCRIPTION
-----------
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 01c463101..4e00b315f 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -43,9 +43,12 @@ unreleased) version of git, that is available from 'master'
branch of the `git.git` repository.
Documentation for older releases are available here:
-* link:v1.7.0/git.html[documentation for release 1.7.0]
+* link:v1.7.0.3/git.html[documentation for release 1.7.0.3]
* release notes for
+ link:RelNotes-1.7.0.3.txt[1.7.0.3],
+ link:RelNotes-1.7.0.2.txt[1.7.0.2],
+ link:RelNotes-1.7.0.1.txt[1.7.0.1],
link:RelNotes-1.7.0.txt[1.7.0].
* link:v1.6.6.2/git.html[documentation for release 1.6.6.2]
@@ -229,7 +232,10 @@ help ...`.
-p::
--paginate::
- Pipe all output into 'less' (or if set, $PAGER).
+ Pipe all output into 'less' (or if set, $PAGER) if standard
+ output is a terminal. This overrides the `pager.<cmd>`
+ configuration options (see the "Configuration Mechanism" section
+ below).
--no-pager::
Do not pipe git output into a pager.
@@ -401,7 +407,8 @@ people. Here is an example:
------------
Various commands read from the configuration file and adjust
-their operation accordingly.
+their operation accordingly. See linkgit:git-config[1] for a
+list.
Identifier Terminology
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index b396a871b..d892e642e 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -511,7 +511,8 @@ command to run to merge ancestor's version (`%O`), current
version (`%A`) and the other branches' version (`%B`). These
three tokens are replaced with the names of temporary files that
hold the contents of these versions when the command line is
-built.
+built. Additionally, %L will be replaced with the conflict marker
+size (see below).
The merge driver is expected to leave the result of the merge in
the file named with `%A` by overwriting it, and exit with zero
diff --git a/Documentation/gitdiffcore.txt b/Documentation/gitdiffcore.txt
index dcdea54df..9de8caf5d 100644
--- a/Documentation/gitdiffcore.txt
+++ b/Documentation/gitdiffcore.txt
@@ -3,7 +3,7 @@ gitdiffcore(7)
NAME
----
-gitdiffcore - Tweaking diff output (June 2005)
+gitdiffcore - Tweaking diff output
SYNOPSIS
--------
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 6e9baf8b3..81c0e6f18 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -225,26 +225,26 @@ endif::git-rev-list[]
--all::
- Pretend as if all the refs in `$GIT_DIR/refs/` are listed on the
+ Pretend as if all the refs in `refs/` are listed on the
command line as '<commit>'.
--branches[=pattern]::
- Pretend as if all the refs in `$GIT_DIR/refs/heads` are listed
+ Pretend as if all the refs in `refs/heads` are listed
on the command line as '<commit>'. If `pattern` is given, limit
branches to ones matching given shell glob. If pattern lacks '?',
'*', or '[', '/*' at the end is implied.
--tags[=pattern]::
- Pretend as if all the refs in `$GIT_DIR/refs/tags` are listed
+ Pretend as if all the refs in `refs/tags` are listed
on the command line as '<commit>'. If `pattern` is given, limit
tags to ones matching given shell glob. If pattern lacks '?', '*',
or '[', '/*' at the end is implied.
--remotes[=pattern]::
- Pretend as if all the refs in `$GIT_DIR/refs/remotes` are listed
+ Pretend as if all the refs in `refs/remotes` are listed
on the command line as '<commit>'. If `pattern`is given, limit
remote tracking branches to ones matching given shell glob.
If pattern lacks '?', '*', or '[', '/*' at the end is implied.
@@ -259,9 +259,9 @@ endif::git-rev-list[]
ifndef::git-rev-list[]
--bisect::
- Pretend as if the bad bisection ref `$GIT_DIR/refs/bisect/bad`
+ Pretend as if the bad bisection ref `refs/bisect/bad`
was listed and as if it was followed by `--not` and the good
- bisection refs `$GIT_DIR/refs/bisect/good-*` on the command
+ bisection refs `refs/bisect/good-*` on the command
line.
endif::git-rev-list[]
@@ -561,10 +561,10 @@ Bisection Helpers
Limit output to the one commit object which is roughly halfway between
included and excluded commits. Note that the bad bisection ref
-`$GIT_DIR/refs/bisect/bad` is added to the included commits (if it
-exists) and the good bisection refs `$GIT_DIR/refs/bisect/good-*` are
+`refs/bisect/bad` is added to the included commits (if it
+exists) and the good bisection refs `refs/bisect/good-*` are
added to the excluded commits (if they exist). Thus, supposing there
-are no refs in `$GIT_DIR/refs/bisect/`, if
+are no refs in `refs/bisect/`, if
-----------------------------------------------------------------------
$ git rev-list --bisect foo ^bar ^baz
@@ -585,7 +585,7 @@ one.
--bisect-vars::
This calculates the same as `--bisect`, except that refs in
-`$GIT_DIR/refs/bisect/` are not used, and except that this outputs
+`refs/bisect/` are not used, and except that this outputs
text ready to be eval'ed by the shell. These lines will assign the
name of the midpoint revision to the variable `bisect_rev`, and the
expected number of commits to be tested after `bisect_rev` is tested
@@ -599,7 +599,7 @@ number of commits to be tested if `bisect_rev` turns out to be bad to
This outputs all the commit objects between the included and excluded
commits, ordered by their distance to the included and excluded
-commits. Refs in `$GIT_DIR/refs/bisect/` are not used. The farthest
+commits. Refs in `refs/bisect/` are not used. The farthest
from them is displayed first. (This is the only one displayed by
`--bisect`.)
+
diff --git a/Documentation/technical/api-run-command.txt b/Documentation/technical/api-run-command.txt
index 68bf4cad8..44876fa70 100644
--- a/Documentation/technical/api-run-command.txt
+++ b/Documentation/technical/api-run-command.txt
@@ -64,8 +64,8 @@ The functions above do the following:
`start_async`::
Run a function asynchronously. Takes a pointer to a `struct
- async` that specifies the details and returns a pipe FD
- from which the caller reads. See below for details.
+ async` that specifies the details and returns a set of pipe FDs
+ for communication with the function. See below for details.
`finish_async`::
@@ -135,7 +135,7 @@ stderr as follows:
.in: The FD must be readable; it becomes child's stdin.
.out: The FD must be writable; it becomes child's stdout.
- .err > 0 is not supported.
+ .err: The FD must be writable; it becomes child's stderr.
The specified FD is closed by start_command(), even if it fails to
run the sub-process!
@@ -180,17 +180,47 @@ The caller:
struct async variable;
2. initializes .proc and .data;
3. calls start_async();
-4. processes the data by reading from the fd in .out;
-5. closes .out;
+4. processes communicates with proc through .in and .out;
+5. closes .in and .out;
6. calls finish_async().
+The members .in, .out are used to provide a set of fd's for
+communication between the caller and the callee as follows:
+
+. Specify 0 to have no file descriptor passed. The callee will
+ receive -1 in the corresponding argument.
+
+. Specify < 0 to have a pipe allocated; start_async() replaces
+ with the pipe FD in the following way:
+
+ .in: Returns the writable pipe end into which the caller
+ writes; the readable end of the pipe becomes the function's
+ in argument.
+
+ .out: Returns the readable pipe end from which the caller
+ reads; the writable end of the pipe becomes the function's
+ out argument.
+
+ The caller of start_async() must close the returned FDs after it
+ has completed reading from/writing from them.
+
+. Specify a file descriptor > 0 to be used by the function:
+
+ .in: The FD must be readable; it becomes the function's in.
+ .out: The FD must be writable; it becomes the function's out.
+
+ The specified FD is closed by start_async(), even if it fails to
+ run the function.
+
The function pointer in .proc has the following signature:
- int proc(int fd, void *data);
+ int proc(int in, int out, void *data);
-. fd specifies a writable file descriptor to which the function must
- write the data that it produces. The function *must* close this
- descriptor before it returns.
+. in, out specifies a set of file descriptors to which the function
+ must read/write the data that it needs/produces. The function
+ *must* close these descriptors before it returns. A descriptor
+ may be -1 if the caller did not configure a descriptor for that
+ direction.
. data is the value that the caller has specified in the .data member
of struct async.
@@ -205,8 +235,8 @@ because this facility is implemented by a pipe to a forked process on
UNIX, but by a thread in the same address space on Windows:
. It cannot change the program's state (global variables, environment,
- etc.) in a way that the caller notices; in other words, .out is the
- only communication channel to the caller.
+ etc.) in a way that the caller notices; in other words, .in and .out
+ are the only communication channels to the caller.
. It must not change the program's state that the caller of the
facility also uses.
diff --git a/Documentation/urls.txt b/Documentation/urls.txt
index d813ceb72..459a394dc 100644
--- a/Documentation/urls.txt
+++ b/Documentation/urls.txt
@@ -4,7 +4,6 @@ GIT URLS[[URLS]]
One of the following notations can be used
to name the remote repository:
-===============================================================
- rsync://host.xz/path/to/repo.git/
- http://host.xz{startsb}:port{endsb}/path/to/repo.git/
- https://host.xz{startsb}:port{endsb}/path/to/repo.git/
@@ -14,7 +13,6 @@ to name the remote repository:
- ssh://{startsb}user@{endsb}host.xz/path/to/repo.git/
- ssh://{startsb}user@{endsb}host.xz/~user/path/to/repo.git/
- ssh://{startsb}user@{endsb}host.xz/~/path/to/repo.git
-===============================================================
SSH is the default transport protocol over the network. You can
optionally specify which user to log-in as, and an alternate,
@@ -23,18 +21,14 @@ username expansion, as does the native git protocol, but
only the former supports port specification. The following
three are identical to the last three above, respectively:
-===============================================================
- {startsb}user@{endsb}host.xz:/path/to/repo.git/
- {startsb}user@{endsb}host.xz:~user/path/to/repo.git/
- {startsb}user@{endsb}host.xz:path/to/repo.git
-===============================================================
To sync with a local directory, you can use:
-===============================================================
- /path/to/repo.git/
- file:///path/to/repo.git/
-===============================================================
ifndef::git-clone[]
They are mostly equivalent, except when cloning. See
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index 577e1fd20..076c18ecc 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.0
+DEF_VER=v1.7.0.3
LF='
'
diff --git a/Makefile b/Makefile
index 7bf2fca40..98372ebbf 100644
--- a/Makefile
+++ b/Makefile
@@ -317,6 +317,12 @@ SCRIPT_PYTHON =
SCRIPT_SH =
TEST_PROGRAMS =
+# Having this variable in your environment would break pipelines because
+# you cause "cd" to echo its destination to stdout. It can also take
+# scripts to unexpected places. If you like CDPATH, define it for your
+# interactive shell sessions without exporting it.
+unexport CDPATH
+
SCRIPT_SH += git-am.sh
SCRIPT_SH += git-bisect.sh
SCRIPT_SH += git-difftool--helper.sh
@@ -1200,7 +1206,6 @@ ifdef NO_MKDTEMP
endif
ifdef NO_MKSTEMPS
COMPAT_CFLAGS += -DNO_MKSTEMPS
- COMPAT_OBJS += compat/mkstemps.o
endif
ifdef NO_UNSETENV
COMPAT_CFLAGS += -DNO_UNSETENV
diff --git a/RelNotes b/RelNotes
index 7b9bde663..02e74966c 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes-1.7.0.txt \ No newline at end of file
+Documentation/RelNotes-1.7.0.3.txt \ No newline at end of file
diff --git a/advice.c b/advice.c
index 936d98ba2..0be4b5f00 100644
--- a/advice.c
+++ b/advice.c
@@ -5,6 +5,7 @@ int advice_status_hints = 1;
int advice_commit_before_merge = 1;
int advice_resolve_conflict = 1;
int advice_implicit_identity = 1;
+int advice_detached_head = 1;
static struct {
const char *name;
@@ -15,6 +16,7 @@ static struct {
{ "commitbeforemerge", &advice_commit_before_merge },
{ "resolveconflict", &advice_resolve_conflict },
{ "implicitidentity", &advice_implicit_identity },
+ { "detachedhead", &advice_detached_head },
};
int git_default_advice_config(const char *var, const char *value)
diff --git a/advice.h b/advice.h
index 9b7a3ad1c..3244ebb5c 100644
--- a/advice.h
+++ b/advice.h
@@ -8,6 +8,7 @@ extern int advice_status_hints;
extern int advice_commit_before_merge;
extern int advice_resolve_conflict;
extern int advice_implicit_identity;
+extern int advice_detached_head;
int git_default_advice_config(const char *var, const char *value);
diff --git a/bisect.c b/bisect.c
index 6dc27ee7a..b556b1161 100644
--- a/bisect.c
+++ b/bisect.c
@@ -986,6 +986,12 @@ int bisect_next_all(const char *prefix)
exit(1);
}
+ if (!all) {
+ fprintf(stderr, "No testable commit found.\n"
+ "Maybe you started with bad path parameters?\n");
+ exit(4);
+ }
+
bisect_rev = revs.commits->item->object.sha1;
memcpy(bisect_rev_hex, sha1_to_hex(bisect_rev), 41);
diff --git a/builtin-blame.c b/builtin-blame.c
index 10f7eacf6..fc1586350 100644
--- a/builtin-blame.c
+++ b/builtin-blame.c
@@ -1772,7 +1772,7 @@ static int lineno_width(int lines)
{
int i, width;
- for (width = 1, i = 10; i <= lines + 1; width++)
+ for (width = 1, i = 10; i <= lines; width++)
i *= 10;
return width;
}
diff --git a/builtin-cat-file.c b/builtin-cat-file.c
index 590684200..a933eaa04 100644
--- a/builtin-cat-file.c
+++ b/builtin-cat-file.c
@@ -219,9 +219,10 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
"exit with zero when there's no error", 'e'),
OPT_SET_INT('p', NULL, &opt, "pretty-print object's content", 'p'),
OPT_SET_INT(0, "batch", &batch,
- "show info and content of objects feeded on stdin", BATCH),
+ "show info and content of objects fed from the standard input",
+ BATCH),
OPT_SET_INT(0, "batch-check", &batch,
- "show info about objects feeded on stdin",
+ "show info about objects fed from the standard input",
BATCH_CHECK),
OPT_END()
};
diff --git a/builtin-checkout.c b/builtin-checkout.c
index 527781728..c5ab7835e 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -488,6 +488,20 @@ static void report_tracking(struct branch_info *new)
strbuf_release(&sb);
}
+static void detach_advice(const char *old_path, const char *new_name)
+{
+ const char fmt[] =
+ "Note: checking out '%s'.\n\n"
+ "You are in 'detached HEAD' state. You can look around, make experimental\n"
+ "changes and commit them, and you can discard any commits you make in this\n"
+ "state without impacting any branches by performing another checkout.\n\n"
+ "If you want to create a new branch to retain commits you create, you may\n"
+ "do so (now or later) by using -b with the checkout command again. Example:\n\n"
+ " git checkout -b new_branch_name\n\n";
+
+ fprintf(stderr, fmt, new_name);
+}
+
static void update_refs_for_switch(struct checkout_opts *opts,
struct branch_info *old,
struct branch_info *new)
@@ -522,8 +536,8 @@ static void update_refs_for_switch(struct checkout_opts *opts,
update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
REF_NODEREF, DIE_ON_ERR);
if (!opts->quiet) {
- if (old->path)
- fprintf(stderr, "Note: moving to '%s' which isn't a local branch\nIf you want to create a new branch from this checkout, you may do so\n(now or later) by using -b with the checkout command again. Example:\n git checkout -b <new_branch_name>\n", new->name);
+ if (old->path && advice_detached_head)
+ detach_advice(old->path, new->name);
describe_detached_head("HEAD is now at", new->commit);
}
}
diff --git a/builtin-commit.c b/builtin-commit.c
index 55676fd87..f4c73442c 100644
--- a/builtin-commit.c
+++ b/builtin-commit.c
@@ -41,7 +41,7 @@ static const char implicit_ident_advice[] =
"on your username and hostname. Please check that they are accurate.\n"
"You can suppress this message by setting them explicitly:\n"
"\n"
-" git config --global user.name Your Name\n"
+" git config --global user.name \"Your Name\"\n"
" git config --global user.email you@example.com\n"
"\n"
"If the identity used for this commit is wrong, you can fix it with:\n"
@@ -1046,7 +1046,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
if (*argv)
s.pathspec = get_pathspec(prefix, argv);
- read_cache();
+ read_cache_preload(s.pathspec);
refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, s.pathspec, NULL, NULL);
s.is_initial = get_sha1(s.reference, sha1) ? 1 : 0;
s.in_merge = in_merge;
diff --git a/builtin-fetch-pack.c b/builtin-fetch-pack.c
index 8ed4a6fea..dbd8b7bcc 100644
--- a/builtin-fetch-pack.c
+++ b/builtin-fetch-pack.c
@@ -586,12 +586,12 @@ static int everything_local(struct ref **refs, int nr_match, char **match)
return retval;
}
-static int sideband_demux(int fd, void *data)
+static int sideband_demux(int in, int out, void *data)
{
int *xd = data;
- int ret = recv_sideband("fetch-pack", xd[0], fd);
- close(fd);
+ int ret = recv_sideband("fetch-pack", xd[0], out);
+ close(out);
return ret;
}
@@ -613,6 +613,7 @@ static int get_pack(int xd[2], char **pack_lockfile)
*/
demux.proc = sideband_demux;
demux.data = xd;
+ demux.out = -1;
if (start_async(&demux))
die("fetch-pack: unable to fork off sideband"
" demultiplexer");
diff --git a/builtin-fetch.c b/builtin-fetch.c
index 8654fa7a2..bbc425b65 100644
--- a/builtin-fetch.c
+++ b/builtin-fetch.c
@@ -104,10 +104,8 @@ static void add_merge_config(struct ref **head,
* there is no entry in the resulting FETCH_HEAD marked
* for merging.
*/
+ memset(&refspec, 0, sizeof(refspec));
refspec.src = branch->merge[i]->src;
- refspec.dst = NULL;
- refspec.pattern = 0;
- refspec.force = 0;
get_fetch_map(remote_refs, &refspec, tail, 1);
for (rm = *old_tail; rm; rm = rm->next)
rm->merge = 1;
@@ -389,9 +387,10 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
fputc(url[i], fp);
fputc('\n', fp);
- if (ref)
+ if (ref) {
rc |= update_local_ref(ref, what, note);
- else
+ free(ref);
+ } else
sprintf(note, "* %-*s %-*s -> FETCH_HEAD",
SUMMARY_WIDTH, *kind ? kind : "branch",
REFCOL_WIDTH, *what ? what : "HEAD");
@@ -588,7 +587,7 @@ static void find_non_local_tags(struct transport *transport,
* to fetch then we can mark the ref entry in the list
* as one to ignore by setting util to NULL.
*/
- if (!strcmp(ref->name + strlen(ref->name) - 3, "^{}")) {
+ if (!suffixcmp(ref->name, "^{}")) {
if (item && !has_sha1_file(ref->old_sha1) &&
!will_fetch(head, ref->old_sha1) &&
!has_sha1_file(item->util) &&
@@ -651,6 +650,17 @@ static void check_not_current_branch(struct ref *ref_map)
"of non-bare repository", current_branch->refname);
}
+static int truncate_fetch_head(void)
+{
+ char *filename = git_path("FETCH_HEAD");
+ FILE *fp = fopen(filename, "w");
+
+ if (!fp)
+ return error("cannot open %s: %s\n", filename, strerror(errno));
+ fclose(fp);
+ return 0;
+}
+
static int do_fetch(struct transport *transport,
struct refspec *refs, int ref_count)
{
@@ -672,11 +682,9 @@ static int do_fetch(struct transport *transport,
/* if not appending, truncate FETCH_HEAD */
if (!append && !dry_run) {
- char *filename = git_path("FETCH_HEAD");
- FILE *fp = fopen(filename, "w");
- if (!fp)
- return error("cannot open %s: %s\n", filename, strerror(errno));
- fclose(fp);
+ int errcode = truncate_fetch_head();
+ if (errcode)
+ return errcode;
}
ref_map = get_ref_map(transport, refs, ref_count, tags, &autotags);
@@ -784,13 +792,19 @@ static int add_remote_or_group(const char *name, struct string_list *list)
static int fetch_multiple(struct string_list *list)
{
int i, result = 0;
- const char *argv[] = { "fetch", NULL, NULL, NULL, NULL, NULL, NULL };
- int argc = 1;
+ const char *argv[11] = { "fetch", "--append" };
+ int argc = 2;
if (dry_run)
argv[argc++] = "--dry-run";
if (prune)
argv[argc++] = "--prune";
+ if (update_head_ok)
+ argv[argc++] = "--update-head-ok";
+ if (force)
+ argv[argc++] = "--force";
+ if (keep)
+ argv[argc++] = "--keep";
if (verbosity >= 2)
argv[argc++] = "-v";
if (verbosity >= 1)
@@ -798,9 +812,16 @@ static int fetch_multiple(struct string_list *list)
else if (verbosity < 0)
argv[argc++] = "-q";
+ if (!append && !dry_run) {
+ int errcode = truncate_fetch_head();
+ if (errcode)
+ return errcode;
+ }
+
for (i = 0; i < list->nr; i++) {
const char *name = list->items[i].string;
argv[argc] = name;
+ argv[argc + 1] = NULL;
if (verbosity >= 0)
printf("Fetching %s\n", name);
if (run_command_v_opt(argv, RUN_GIT_CMD)) {
diff --git a/builtin-grep.c b/builtin-grep.c
index 26d4deb1c..371db0aa9 100644
--- a/builtin-grep.c
+++ b/builtin-grep.c
@@ -408,15 +408,25 @@ static int pathspec_matches(const char **paths, const char *name, int max_depth)
return 0;
}
+static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
+{
+ void *data;
+
+ if (use_threads) {
+ read_sha1_lock();
+ data = read_sha1_file(sha1, type, size);
+ read_sha1_unlock();
+ } else {
+ data = read_sha1_file(sha1, type, size);
+ }
+ return data;
+}
+
static void *load_sha1(const unsigned char *sha1, unsigned long *size,
const char *name)
{
enum object_type type;
- char *data;
-
- read_sha1_lock();
- data = read_sha1_file(sha1, &type, size);
- read_sha1_unlock();
+ void *data = lock_and_read_sha1_file(sha1, &type, size);
if (!data)
error("'%s': unable to read %s", name, sha1_to_hex(sha1));
@@ -605,10 +615,7 @@ static int grep_tree(struct grep_opt *opt, const char **paths,
void *data;
unsigned long size;
- read_sha1_lock();
- data = read_sha1_file(entry.sha1, &type, &size);
- read_sha1_unlock();
-
+ data = lock_and_read_sha1_file(entry.sha1, &type, &size);
if (!data)
die("unable to read tree (%s)",
sha1_to_hex(entry.sha1));
@@ -837,6 +844,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
opt.relative = 1;
opt.pathname = 1;
opt.pattern_tail = &opt.pattern_list;
+ opt.header_tail = &opt.header_list;
opt.regflags = REG_NEWLINE;
opt.max_depth = -1;
@@ -861,6 +869,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
PARSE_OPT_STOP_AT_NON_OPTION |
PARSE_OPT_NO_INTERNAL_HELP);
+ /*
+ * skip a -- separator; we know it cannot be
+ * separating revisions from pathnames if
+ * we haven't even had any patterns yet
+ */
+ if (argc > 0 && !opt.pattern_list && !strcmp(argv[0], "--")) {
+ argv++;
+ argc--;
+ }
+
/* First unrecognized non-option token */
if (argc > 0 && !opt.pattern_list) {
append_grep_pattern(&opt, argv[0], "command line", 0,
diff --git a/builtin-log.c b/builtin-log.c
index 8d16832f7..e0d5caa61 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -1089,7 +1089,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
/*
* We cannot move this anywhere earlier because we do want to
- * know if --root was given explicitly from the comand line.
+ * know if --root was given explicitly from the command line.
*/
rev.show_root_diff = 1;
diff --git a/builtin-mailinfo.c b/builtin-mailinfo.c
index a50ac2256..ce2ef6bed 100644
--- a/builtin-mailinfo.c
+++ b/builtin-mailinfo.c
@@ -779,8 +779,7 @@ static int handle_commit_msg(struct strbuf *line)
return 0;
if (still_looking) {
- strbuf_ltrim(line);
- if (!line->len)
+ if (!line->len || (line->len == 1 && line->buf[0] == '\n'))
return 0;
}
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index e1d3adf40..539e75d56 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -464,9 +464,6 @@ static int write_one(struct sha1file *f,
return 1;
}
-/* forward declaration for write_pack_file */
-static int adjust_perm(const char *path, mode_t mode);
-
static void write_pack_file(void)
{
uint32_t i = 0, j;
@@ -523,21 +520,17 @@ static void write_pack_file(void)
}
if (!pack_to_stdout) {
- mode_t mode = umask(0);
struct stat st;
const char *idx_tmp_name;
char tmpname[PATH_MAX];
- umask(mode);
- mode = 0444 & ~mode;
-
idx_tmp_name = write_idx_file(NULL, written_list,
nr_written, sha1);
snprintf(tmpname, sizeof(tmpname), "%s-%s.pack",
base_name, sha1_to_hex(sha1));
free_pack_by_name(tmpname);
- if (adjust_perm(pack_tmp_name, mode))
+ if (adjust_shared_perm(pack_tmp_name))
die_errno("unable to make temporary pack file readable");
if (rename(pack_tmp_name, tmpname))
die_errno("unable to rename temporary pack file");
@@ -565,7 +558,7 @@ static void write_pack_file(void)
snprintf(tmpname, sizeof(tmpname), "%s-%s.idx",
base_name, sha1_to_hex(sha1));
- if (adjust_perm(idx_tmp_name, mode))
+ if (adjust_shared_perm(idx_tmp_name))
die_errno("unable to make temporary index file readable");
if (rename(idx_tmp_name, tmpname))
die_errno("unable to rename temporary index file");
@@ -2125,13 +2118,6 @@ static void get_object_list(int ac, const char **av)
loosen_unused_packed_objects(&revs);
}
-static int adjust_perm(const char *path, mode_t mode)
-{
- if (chmod(path, mode))
- return -1;
- return adjust_shared_perm(path);
-}
-
int cmd_pack_objects(int argc, const char **argv, const char *prefix)
{
int use_internal_rev_list = 0;
diff --git a/builtin-prune.c b/builtin-prune.c
index 8459aec8e..81f915ec3 100644
--- a/builtin-prune.c
+++ b/builtin-prune.c
@@ -18,13 +18,11 @@ static unsigned long expire;
static int prune_tmp_object(const char *path, const char *filename)
{
const char *fullpath = mkpath("%s/%s", path, filename);
- if (expire) {
- struct stat st;
- if (lstat(fullpath, &st))
- return error("Could not stat '%s'", fullpath);
- if (st.st_mtime > expire)
- return 0;
- }
+ struct stat st;
+ if (lstat(fullpath, &st))
+ return error("Could not stat '%s'", fullpath);
+ if (st.st_mtime > expire)
+ return 0;
printf("Removing stale temporary file %s\n", fullpath);
if (!show_only)
unlink_or_warn(fullpath);
@@ -34,13 +32,11 @@ static int prune_tmp_object(const char *path, const char *filename)
static int prune_object(char *path, const char *filename, const unsigned char *sha1)
{
const char *fullpath = mkpath("%s/%s", path, filename);
- if (expire) {
- struct stat st;
- if (lstat(fullpath, &st))
- return error("Could not stat '%s'", fullpath);
- if (st.st_mtime > expire)
- return 0;
- }
+ struct stat st;
+ if (lstat(fullpath, &st))
+ return error("Could not stat '%s'", fullpath);
+ if (st.st_mtime > expire)
+ return 0;
if (show_only || verbose) {
enum object_type type = sha1_object_info(sha1, NULL);
printf("%s %s\n", sha1_to_hex(sha1),
@@ -106,7 +102,7 @@ static void prune_object_dir(const char *path)
/*
* Write errors (particularly out of space) can result in
* failed temporary packs (and more rarely indexes and other
- * files begining with "tmp_") accumulating in the object
+ * files beginning with "tmp_") accumulating in the object
* and the pack directories.
*/
static void remove_temporary_files(const char *path)
@@ -139,6 +135,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
};
char *s;
+ expire = ULONG_MAX;
save_commit_buffer = 0;
read_replace_refs = 0;
init_revisions(&revs, prefix);
diff --git a/builtin-push.c b/builtin-push.c
index 5633f0ade..f7bc2b292 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -68,7 +68,7 @@ static void setup_push_tracking(void)
struct branch *branch = branch_get(NULL);
if (!branch)
die("You are not currently on a branch.");
- if (!branch->merge_nr)
+ if (!branch->merge_nr || !branch->merge)
die("The current branch %s is not tracking anything.",
branch->name);
if (branch->merge_nr != 1)
diff --git a/builtin-receive-pack.c b/builtin-receive-pack.c
index 4320c93e7..0559fcc87 100644
--- a/builtin-receive-pack.c
+++ b/builtin-receive-pack.c
@@ -2,6 +2,7 @@
#include "pack.h"
#include "refs.h"
#include "pkt-line.h"
+#include "sideband.h"
#include "run-command.h"
#include "exec_cmd.h"
#include "commit.h"
@@ -27,11 +28,12 @@ static int receive_unpack_limit = -1;
static int transfer_unpack_limit = -1;
static int unpack_limit = 100;
static int report_status;
+static int use_sideband;
static int prefer_ofs_delta = 1;
static int auto_update_server_info;
static int auto_gc = 1;
static const char *head_name;
-static char *capabilities_to_send;
+static int sent_capabilities;
static enum deny_action parse_deny_action(const char *var, const char *value)
{
@@ -105,19 +107,21 @@ static int receive_pack_config(const char *var, const char *value, void *cb)
static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
{
- if (!capabilities_to_send)
+ if (sent_capabilities)
packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
else
- packet_write(1, "%s %s%c%s\n",
- sha1_to_hex(sha1), path, 0, capabilities_to_send);
- capabilities_to_send = NULL;
+ packet_write(1, "%s %s%c%s%s\n",
+ sha1_to_hex(sha1), path, 0,
+ " report-status delete-refs side-band-64k",
+ prefer_ofs_delta ? " ofs-delta" : "");
+ sent_capabilities = 1;
return 0;
}
static void write_head_info(void)
{
for_each_ref(show_ref, NULL);
- if (capabilities_to_send)
+ if (!sent_capabilities)
show_ref("capabilities^{}", null_sha1, 0, NULL);
}
@@ -135,11 +139,61 @@ static struct command *commands;
static const char pre_receive_hook[] = "hooks/pre-receive";
static const char post_receive_hook[] = "hooks/post-receive";
+static void rp_error(const char *err, ...) __attribute__((format (printf, 1, 2)));
+static void rp_warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
+
+static void report_message(const char *prefix, const char *err, va_list params)
+{
+ int sz = strlen(prefix);
+ char msg[4096];
+
+ strncpy(msg, prefix, sz);
+ sz += vsnprintf(msg + sz, sizeof(msg) - sz, err, params);
+ if (sz > (sizeof(msg) - 1))
+ sz = sizeof(msg) - 1;
+ msg[sz++] = '\n';
+
+ if (use_sideband)
+ send_sideband(1, 2, msg, sz, use_sideband);
+ else
+ xwrite(2, msg, sz);
+}
+
+static void rp_warning(const char *err, ...)
+{
+ va_list params;
+ va_start(params, err);
+ report_message("warning: ", err, params);
+ va_end(params);
+}
+
+static void rp_error(const char *err, ...)
+{
+ va_list params;
+ va_start(params, err);
+ report_message("error: ", err, params);
+ va_end(params);
+}
+
+static int copy_to_sideband(int in, int out, void *arg)
+{
+ char data[128];
+ while (1) {
+ ssize_t sz = xread(in, data, sizeof(data));
+ if (sz <= 0)
+ break;
+ send_sideband(1, 2, data, sz, use_sideband);
+ }
+ close(in);
+ return 0;
+}
+
static int run_receive_hook(const char *hook_name)
{
static char buf[sizeof(commands->old_sha1) * 2 + PATH_MAX + 4];
struct command *cmd;
struct child_process proc;
+ struct async muxer;
const char *argv[2];
int have_input = 0, code;
@@ -159,9 +213,23 @@ static int run_receive_hook(const char *hook_name)
proc.in = -1;
proc.stdout_to_stderr = 1;
+ if (use_sideband) {
+ memset(&muxer, 0, sizeof(muxer));
+ muxer.proc = copy_to_sideband;
+ muxer.in = -1;
+ code = start_async(&muxer);
+ if (code)
+ return code;
+ proc.err = muxer.in;
+ }
+
code = start_command(&proc);
- if (code)
+ if (code) {
+ if (use_sideband)
+ finish_async(&muxer);
return code;
+ }
+
for (cmd = commands; cmd; cmd = cmd->next) {
if (!cmd->error_string) {
size_t n = snprintf(buf, sizeof(buf), "%s %s %s\n",
@@ -173,6 +241,8 @@ static int run_receive_hook(const char *hook_name)
}
}
close(proc.in);
+ if (use_sideband)
+ finish_async(&muxer);
return finish_command(&proc);
}
@@ -180,6 +250,8 @@ static int run_update_hook(struct command *cmd)
{
static const char update_hook[] = "hooks/update";
const char *argv[5];
+ struct child_process proc;
+ int code;
if (access(update_hook, X_OK) < 0)
return 0;
@@ -190,8 +262,18 @@ static int run_update_hook(struct command *cmd)
argv[3] = sha1_to_hex(cmd->new_sha1);
argv[4] = NULL;
- return run_command_v_opt(argv, RUN_COMMAND_NO_STDIN |
- RUN_COMMAND_STDOUT_TO_STDERR);
+ memset(&proc, 0, sizeof(proc));
+ proc.no_stdin = 1;
+ proc.stdout_to_stderr = 1;
+ proc.err = use_sideband ? -1 : 0;
+ proc.argv = argv;
+
+ code = start_command(&proc);
+ if (code)
+ return code;
+ if (use_sideband)
+ copy_to_sideband(proc.err, -1, NULL);
+ return finish_command(&proc);
}
static int is_ref_checked_out(const char *ref)
@@ -224,7 +306,7 @@ static void refuse_unconfigured_deny(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(refuse_unconfigured_deny_msg); i++)
- error("%s", refuse_unconfigured_deny_msg[i]);
+ rp_error("%s", refuse_unconfigured_deny_msg[i]);
}
static char *refuse_unconfigured_deny_delete_current_msg[] = {
@@ -244,7 +326,7 @@ static void refuse_unconfigured_deny_delete_current(void)
for (i = 0;
i < ARRAY_SIZE(refuse_unconfigured_deny_delete_current_msg);
i++)
- error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
+ rp_error("%s", refuse_unconfigured_deny_delete_current_msg[i]);
}
static const char *update(struct command *cmd)
@@ -256,7 +338,7 @@ static const char *update(struct command *cmd)
/* only refs/... are allowed */
if (prefixcmp(name, "refs/") || check_ref_format(name + 5)) {
- error("refusing to create funny ref '%s' remotely", name);
+ rp_error("refusing to create funny ref '%s' remotely", name);
return "funny refname";
}
@@ -265,11 +347,11 @@ static const char *update(struct command *cmd)
case DENY_IGNORE:
break;
case DENY_WARN:
- warning("updating the current branch");
+ rp_warning("updating the current branch");
break;
case DENY_REFUSE:
case DENY_UNCONFIGURED:
- error("refusing to update checked out branch: %s", name);
+ rp_error("refusing to update checked out branch: %s", name);
if (deny_current_branch == DENY_UNCONFIGURED)
refuse_unconfigured_deny();
return "branch is currently checked out";
@@ -284,7 +366,7 @@ static const char *update(struct command *cmd)
if (!is_null_sha1(old_sha1) && is_null_sha1(new_sha1)) {
if (deny_deletes && !prefixcmp(name, "refs/heads/")) {
- error("denying ref deletion for %s", name);
+ rp_error("denying ref deletion for %s", name);
return "deletion prohibited";
}
@@ -293,13 +375,13 @@ static const char *update(struct command *cmd)
case DENY_IGNORE:
break;
case DENY_WARN:
- warning("deleting the current branch");
+ rp_warning("deleting the current branch");
break;
case DENY_REFUSE:
case DENY_UNCONFIGURED:
if (deny_delete_current == DENY_UNCONFIGURED)
refuse_unconfigured_deny_delete_current();
- error("refusing to delete the current branch: %s", name);
+ rp_error("refusing to delete the current branch: %s", name);
return "deletion of the current branch prohibited";
}
}
@@ -329,23 +411,23 @@ static const char *update(struct command *cmd)
break;
free_commit_list(bases);
if (!ent) {
- error("denying non-fast-forward %s"
- " (you should pull first)", name);
+ rp_error("denying non-fast-forward %s"
+ " (you should pull first)", name);
return "non-fast-forward";
}
}
if (run_update_hook(cmd)) {
- error("hook declined to update %s", name);
+ rp_error("hook declined to update %s", name);
return "hook declined";
}
if (is_null_sha1(new_sha1)) {
if (!parse_object(old_sha1)) {
- warning ("Allowing deletion of corrupt ref.");
+ rp_warning("Allowing deletion of corrupt ref.");
old_sha1 = NULL;
}
if (delete_ref(name, old_sha1, 0)) {
- error("failed to delete %s", name);
+ rp_error("failed to delete %s", name);
return "failed to delete";
}
return NULL; /* good */
@@ -353,7 +435,7 @@ static const char *update(struct command *cmd)
else {
lock = lock_any_ref_for_update(name, old_sha1, 0);
if (!lock) {
- error("failed to lock %s", name);
+ rp_error("failed to lock %s", name);
return "failed to lock";
}
if (write_ref_sha1(lock, new_sha1, "push")) {
@@ -368,8 +450,9 @@ static char update_post_hook[] = "hooks/post-update";
static void run_update_post_hook(struct command *cmd)
{
struct command *cmd_p;
- int argc, status;
+ int argc;
const char **argv;
+ struct child_process proc;
for (argc = 0, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
if (cmd_p->error_string)
@@ -391,8 +474,18 @@ static void run_update_post_hook(struct command *cmd)
argc++;
}
argv[argc] = NULL;
- status = run_command_v_opt(argv, RUN_COMMAND_NO_STDIN
- | RUN_COMMAND_STDOUT_TO_STDERR);
+
+ memset(&proc, 0, sizeof(proc));
+ proc.no_stdin = 1;
+ proc.stdout_to_stderr = 1;
+ proc.err = use_sideband ? -1 : 0;
+ proc.argv = argv;
+
+ if (!start_command(&proc)) {
+ if (use_sideband)
+ copy_to_sideband(proc.err, -1, NULL);
+ finish_command(&proc);
+ }
}
static void execute_commands(const char *unpacker_error)
@@ -452,6 +545,8 @@ static void read_head_info(void)
if (reflen + 82 < len) {
if (strstr(refname + reflen + 1, "report-status"))
report_status = 1;
+ if (strstr(refname + reflen + 1, "side-band-64k"))
+ use_sideband = LARGE_PACKET_MAX;
}
cmd = xmalloc(sizeof(struct command) + len - 80);
hashcpy(cmd->old_sha1, old_sha1);
@@ -551,17 +646,25 @@ static const char *unpack(void)
static void report(const char *unpack_status)
{
struct command *cmd;
- packet_write(1, "unpack %s\n",
- unpack_status ? unpack_status : "ok");
+ struct strbuf buf = STRBUF_INIT;
+
+ packet_buf_write(&buf, "unpack %s\n",
+ unpack_status ? unpack_status : "ok");
for (cmd = commands; cmd; cmd = cmd->next) {
if (!cmd->error_string)
- packet_write(1, "ok %s\n",
- cmd->ref_name);
+ packet_buf_write(&buf, "ok %s\n",
+ cmd->ref_name);
else
- packet_write(1, "ng %s %s\n",
- cmd->ref_name, cmd->error_string);
+ packet_buf_write(&buf, "ng %s %s\n",
+ cmd->ref_name, cmd->error_string);
}
- packet_flush(1);
+ packet_buf_flush(&buf);
+
+ if (use_sideband)
+ send_sideband(1, 1, buf.buf, buf.len, use_sideband);
+ else
+ safe_write(1, buf.buf, buf.len);
+ strbuf_release(&buf);
}
static int delete_only(struct command *cmd)
@@ -658,10 +761,6 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
else if (0 <= receive_unpack_limit)
unpack_limit = receive_unpack_limit;
- capabilities_to_send = (prefer_ofs_delta) ?
- " report-status delete-refs ofs-delta " :
- " report-status delete-refs ";
-
if (advertise_refs || !stateless_rpc) {
add_alternate_refs();
write_head_info();
@@ -695,5 +794,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
if (auto_update_server_info)
update_server_info(0);
}
+ if (use_sideband)
+ packet_flush(1);
return 0;
}
diff --git a/builtin-reflog.c b/builtin-reflog.c
index 749821078..64e45bd81 100644
--- a/builtin-reflog.c
+++ b/builtin-reflog.c
@@ -530,16 +530,14 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
int i, status, do_all;
int explicit_expiry = 0;
+ default_reflog_expire_unreachable = now - 30 * 24 * 3600;
+ default_reflog_expire = now - 90 * 24 * 3600;
git_config(reflog_expire_config, NULL);
save_commit_buffer = 0;
do_all = status = 0;
memset(&cb, 0, sizeof(cb));
- if (!default_reflog_expire_unreachable)
- default_reflog_expire_unreachable = now - 30 * 24 * 3600;
- if (!default_reflog_expire)
- default_reflog_expire = now - 90 * 24 * 3600;
cb.expire_total = default_reflog_expire;
cb.expire_unreachable = default_reflog_expire_unreachable;
diff --git a/builtin-rev-list.c b/builtin-rev-list.c
index c924b3a2c..5679170e8 100644
--- a/builtin-rev-list.c
+++ b/builtin-rev-list.c
@@ -371,8 +371,9 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
revs.diff)
usage(rev_list_usage);
- save_commit_buffer = revs.verbose_header ||
- revs.grep_filter.pattern_list;
+ save_commit_buffer = (revs.verbose_header ||
+ revs.grep_filter.pattern_list ||
+ revs.grep_filter.header_list);
if (bisect_list)
revs.limited = 1;
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index a8c5043de..b76f205e6 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -455,6 +455,13 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
if (argc > 1 && !strcmp("--sq-quote", argv[1]))
return cmd_sq_quote(argc - 2, argv + 2);
+ if (argc == 2 && !strcmp("--local-env-vars", argv[1])) {
+ int i;
+ for (i = 0; local_repo_env[i]; i++)
+ printf("%s\n", local_repo_env[i]);
+ return 0;
+ }
+
if (argc > 1 && !strcmp("-h", argv[1]))
usage(builtin_rev_parse_usage);
diff --git a/builtin-revert.c b/builtin-revert.c
index 8ac86f094..eff52687a 100644
--- a/builtin-revert.c
+++ b/builtin-revert.c
@@ -38,6 +38,7 @@ static const char * const cherry_pick_usage[] = {
static int edit, no_replay, no_commit, mainline, signoff;
static enum { REVERT, CHERRY_PICK } action;
static struct commit *commit;
+static const char *commit_name;
static int allow_rerere_auto;
static const char *me;
@@ -49,7 +50,6 @@ static void parse_args(int argc, const char **argv)
const char * const * usage_str =
action == REVERT ? revert_usage : cherry_pick_usage;
unsigned char sha1[20];
- const char *arg;
int noop;
struct option options[] = {
OPT_BOOLEAN('n', "no-commit", &no_commit, "don't automatically commit"),
@@ -64,19 +64,13 @@ static void parse_args(int argc, const char **argv)
if (parse_options(argc, argv, NULL, options, usage_str, 0) != 1)
usage_with_options(usage_str, options);
- arg = argv[0];
- if (get_sha1(arg, sha1))
- die ("Cannot find '%s'", arg);
- commit = (struct commit *)parse_object(sha1);
+ commit_name = argv[0];
+ if (get_sha1(commit_name, sha1))
+ die ("Cannot find '%s'", commit_name);
+ commit = lookup_commit_reference(sha1);
if (!commit)
- die ("Could not find %s", sha1_to_hex(sha1));
- if (commit->object.type == OBJ_TAG) {
- commit = (struct commit *)
- deref_tag((struct object *)commit, arg, strlen(arg));
- }
- if (commit->object.type != OBJ_COMMIT)
- die ("'%s' does not point to a commit", arg);
+ exit(1);
}
static char *get_oneline(const char *message)
@@ -204,25 +198,27 @@ static void set_author_ident_env(const char *message)
sha1_to_hex(commit->object.sha1));
}
-static char *help_msg(const unsigned char *sha1)
+static char *help_msg(const char *name)
{
- static char helpbuf[1024];
+ struct strbuf helpbuf = STRBUF_INIT;
char *msg = getenv("GIT_CHERRY_PICK_HELP");
if (msg)
return msg;
- strcpy(helpbuf, " After resolving the conflicts,\n"
- "mark the corrected paths with 'git add <paths>' "
- "or 'git rm <paths>' and commit the result.");
+ strbuf_addstr(&helpbuf, " After resolving the conflicts,\n"
+ "mark the corrected paths with 'git add <paths>' or 'git rm <paths>'\n"
+ "and commit the result");
if (action == CHERRY_PICK) {
- sprintf(helpbuf + strlen(helpbuf),
- "\nWhen commiting, use the option "
- "'-c %s' to retain authorship and message.",
- find_unique_abbrev(sha1, DEFAULT_ABBREV));
+ strbuf_addf(&helpbuf, " with: \n"
+ "\n"
+ " git commit -c %s\n",
+ name);
}
- return helpbuf;
+ else
+ strbuf_addch(&helpbuf, '.');
+ return strbuf_detach(&helpbuf, NULL);
}
static struct tree *empty_tree(void)
@@ -409,7 +405,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)
if (commit_lock_file(&msg_file) < 0)
die ("Error wrapping up %s", defmsg);
fprintf(stderr, "Automatic %s failed.%s\n",
- me, help_msg(commit->object.sha1));
+ me, help_msg(commit_name));
rerere(allow_rerere_auto);
exit(1);
}
diff --git a/builtin-send-pack.c b/builtin-send-pack.c
index 76c72065d..2183a4705 100644
--- a/builtin-send-pack.c
+++ b/builtin-send-pack.c
@@ -372,6 +372,14 @@ static void print_helper_status(struct ref *ref)
strbuf_release(&buf);
}
+static int sideband_demux(int in, int out, void *data)
+{
+ int *fd = data;
+ int ret = recv_sideband("send-pack", fd[0], out);
+ close(out);
+ return ret;
+}
+
int send_pack(struct send_pack_args *args,
int fd[], struct child_process *conn,
struct ref *remote_refs,
@@ -382,18 +390,22 @@ int send_pack(struct send_pack_args *args,
struct strbuf req_buf = STRBUF_INIT;
struct ref *ref;
int new_refs;
- int ask_for_status_report = 0;
int allow_deleting_refs = 0;
- int expect_status_report = 0;
+ int status_report = 0;
+ int use_sideband = 0;
+ unsigned cmds_sent = 0;
int ret;
+ struct async demux;
/* Does the other end support the reporting? */
if (server_supports("report-status"))
- ask_for_status_report = 1;
+ status_report = 1;
if (server_supports("delete-refs"))
allow_deleting_refs = 1;
if (server_supports("ofs-delta"))
args->use_ofs_delta = 1;
+ if (server_supports("side-band-64k"))
+ use_sideband = 1;
if (!remote_refs) {
fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
@@ -426,28 +438,30 @@ int send_pack(struct send_pack_args *args,
if (!ref->deletion)
new_refs++;
- if (!args->dry_run) {
+ if (args->dry_run) {
+ ref->status = REF_STATUS_OK;
+ } else {
char *old_hex = sha1_to_hex(ref->old_sha1);
char *new_hex = sha1_to_hex(ref->new_sha1);
- if (ask_for_status_report) {
- packet_buf_write(&req_buf, "%s %s %s%c%s",
+ if (!cmds_sent && (status_report || use_sideband)) {
+ packet_buf_write(&req_buf, "%s %s %s%c%s%s",
old_hex, new_hex, ref->name, 0,
- "report-status");
- ask_for_status_report = 0;
- expect_status_report = 1;
+ status_report ? " report-status" : "",
+ use_sideband ? " side-band-64k" : "");
}
else
packet_buf_write(&req_buf, "%s %s %s",
old_hex, new_hex, ref->name);
+ ref->status = status_report ?
+ REF_STATUS_EXPECTING_REPORT :
+ REF_STATUS_OK;
+ cmds_sent++;
}
- ref->status = expect_status_report ?
- REF_STATUS_EXPECTING_REPORT :
- REF_STATUS_OK;
}
if (args->stateless_rpc) {
- if (!args->dry_run) {
+ if (!args->dry_run && cmds_sent) {
packet_buf_flush(&req_buf);
send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
}
@@ -457,23 +471,43 @@ int send_pack(struct send_pack_args *args,
}
strbuf_release(&req_buf);
- if (new_refs && !args->dry_run) {
+ if (use_sideband && cmds_sent) {
+ memset(&demux, 0, sizeof(demux));
+ demux.proc = sideband_demux;
+ demux.data = fd;
+ demux.out = -1;
+ if (start_async(&demux))
+ die("receive-pack: unable to fork off sideband demultiplexer");
+ in = demux.out;
+ }
+
+ if (new_refs && cmds_sent) {
if (pack_objects(out, remote_refs, extra_have, args) < 0) {
for (ref = remote_refs; ref; ref = ref->next)
ref->status = REF_STATUS_NONE;
+ if (use_sideband)
+ finish_async(&demux);
return -1;
}
}
- if (args->stateless_rpc && !args->dry_run)
+ if (args->stateless_rpc && cmds_sent)
packet_flush(out);
- if (expect_status_report)
+ if (status_report && cmds_sent)
ret = receive_status(in, remote_refs);
else
ret = 0;
if (args->stateless_rpc)
packet_flush(out);
+ if (use_sideband && cmds_sent) {
+ if (finish_async(&demux)) {
+ error("error in sideband demultiplexer");
+ ret = -1;
+ }
+ close(demux.out);
+ }
+
if (ret < 0)
return ret;
for (ref = remote_refs; ref; ref = ref->next) {
diff --git a/builtin-shortlog.c b/builtin-shortlog.c
index b3b055f68..ecd2d45a0 100644
--- a/builtin-shortlog.c
+++ b/builtin-shortlog.c
@@ -304,9 +304,19 @@ parse_done:
return 0;
}
+static void add_wrapped_shortlog_msg(struct strbuf *sb, const char *s,
+ const struct shortlog *log)
+{
+ int col = strbuf_add_wrapped_text(sb, s, log->in1, log->in2, log->wrap);
+ if (col != log->wrap)
+ strbuf_addch(sb, '\n');
+}
+
void shortlog_output(struct shortlog *log)
{
int i, j;
+ struct strbuf sb = STRBUF_INIT;
+
if (log->sort_by_number)
qsort(log->list.items, log->list.nr, sizeof(struct string_list_item),
compare_by_number);
@@ -321,9 +331,9 @@ void shortlog_output(struct shortlog *log)
const char *msg = onelines->items[j].string;
if (log->wrap_lines) {
- int col = print_wrapped_text(msg, log->in1, log->in2, log->wrap);
- if (col != log->wrap)
- putchar('\n');
+ strbuf_reset(&sb);
+ add_wrapped_shortlog_msg(&sb, msg, log);
+ fwrite(sb.buf, sb.len, 1, stdout);
}
else
printf(" %s\n", msg);
@@ -337,6 +347,7 @@ void shortlog_output(struct shortlog *log)
log->list.items[i].util = NULL;
}
+ strbuf_release(&sb);
log->list.strdup_strings = 1;
string_list_clear(&log->list, 1);
clear_mailmap(&log->mailmap);
diff --git a/builtin-show-branch.c b/builtin-show-branch.c
index 9f13caa76..35a709e63 100644
--- a/builtin-show-branch.c
+++ b/builtin-show-branch.c
@@ -567,7 +567,7 @@ static int git_show_branch_config(const char *var, const char *value, void *cb)
return config_error_nonbool(var);
/*
* default_arg is now passed to parse_options(), so we need to
- * mimick the real argv a bit better.
+ * mimic the real argv a bit better.
*/
if (!default_num) {
default_alloc = 20;
diff --git a/builtin-var.c b/builtin-var.c
index 228051819..70fdb4dec 100644
--- a/builtin-var.c
+++ b/builtin-var.c
@@ -6,7 +6,7 @@
#include "cache.h"
#include "exec_cmd.h"
-static const char var_usage[] = "git var [-l | <variable>]";
+static const char var_usage[] = "git var (-l | <variable>)";
static const char *editor(int flag)
{
@@ -20,7 +20,7 @@ static const char *editor(int flag)
static const char *pager(int flag)
{
- const char *pgm = git_pager();
+ const char *pgm = git_pager(1);
if (!pgm)
pgm = "cat";
diff --git a/cache.h b/cache.h
index d478eff1f..6e5499325 100644
--- a/cache.h
+++ b/cache.h
@@ -388,6 +388,15 @@ static inline enum object_type object_type(unsigned int mode)
#define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF"
#define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
+/*
+ * Repository-local GIT_* environment variables
+ * The array is NULL-terminated to simplify its usage in contexts such
+ * environment creation or simple walk of the list.
+ * The number of non-NULL entries is available as a macro.
+ */
+#define LOCAL_REPO_ENV_SIZE 8
+extern const char *const local_repo_env[LOCAL_REPO_ENV_SIZE + 1];
+
extern int is_bare_repository_cfg;
extern int is_bare_repository(void);
extern int is_inside_git_dir(void);
@@ -641,6 +650,10 @@ int git_mkstemp(char *path, size_t n, const char *template);
int git_mkstemps(char *path, size_t n, const char *template, int suffix_len);
+/* set default permissions by passing mode arguments to open(2) */
+int git_mkstemps_mode(char *pattern, int suffix_len, int mode);
+int git_mkstemp_mode(char *pattern, int mode);
+
/*
* NOTE NOTE NOTE!!
*
@@ -775,7 +788,7 @@ extern const char *git_committer_info(int);
extern const char *fmt_ident(const char *name, const char *email, const char *date_str, int);
extern const char *fmt_name(const char *name, const char *email);
extern const char *git_editor(void);
-extern const char *git_pager(void);
+extern const char *git_pager(int stdout_is_tty);
struct checkout {
const char *base_dir;
diff --git a/compat/mkdtemp.c b/compat/mkdtemp.c
index 34d4b4981..113611959 100644
--- a/compat/mkdtemp.c
+++ b/compat/mkdtemp.c
@@ -2,7 +2,7 @@
char *gitmkdtemp(char *template)
{
- if (!mktemp(template) || mkdir(template, 0700))
+ if (!*mktemp(template) || mkdir(template, 0700))
return NULL;
return template;
}
diff --git a/compat/mkstemps.c b/compat/mkstemps.c
deleted file mode 100644
index 14179c8e6..000000000
--- a/compat/mkstemps.c
+++ /dev/null
@@ -1,70 +0,0 @@
-#include "../git-compat-util.h"
-
-/* Adapted from libiberty's mkstemp.c. */
-
-#undef TMP_MAX
-#define TMP_MAX 16384
-
-int gitmkstemps(char *pattern, int suffix_len)
-{
- static const char letters[] =
- "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "0123456789";
- static const int num_letters = 62;
- uint64_t value;
- struct timeval tv;
- char *template;
- size_t len;
- int fd, count;
-
- len = strlen(pattern);
-
- if (len < 6 + suffix_len) {
- errno = EINVAL;
- return -1;
- }
-
- if (strncmp(&pattern[len - 6 - suffix_len], "XXXXXX", 6)) {
- errno = EINVAL;
- return -1;
- }
-
- /*
- * Replace pattern's XXXXXX characters with randomness.
- * Try TMP_MAX different filenames.
- */
- gettimeofday(&tv, NULL);
- value = ((size_t)(tv.tv_usec << 16)) ^ tv.tv_sec ^ getpid();
- template = &pattern[len - 6 - suffix_len];
- for (count = 0; count < TMP_MAX; ++count) {
- uint64_t v = value;
- /* Fill in the random bits. */
- template[0] = letters[v % num_letters]; v /= num_letters;
- template[1] = letters[v % num_letters]; v /= num_letters;
- template[2] = letters[v % num_letters]; v /= num_letters;
- template[3] = letters[v % num_letters]; v /= num_letters;
- template[4] = letters[v % num_letters]; v /= num_letters;
- template[5] = letters[v % num_letters]; v /= num_letters;
-
- fd = open(pattern, O_CREAT | O_EXCL | O_RDWR, 0600);
- if (fd > 0)
- return fd;
- /*
- * Fatal error (EPERM, ENOSPC etc).
- * It doesn't make sense to loop.
- */
- if (errno != EEXIST)
- break;
- /*
- * This is a random value. It is only necessary that
- * the next TMP_MAX values generated by adding 7777 to
- * VALUE are different with (module 2^32).
- */
- value += 7777;
- }
- /* We return the null string if we can't find a unique file name. */
- pattern[0] = '\0';
- errno = EINVAL;
- return -1;
-}
diff --git a/compat/win32/pthread.c b/compat/win32/pthread.c
index 5fc1670be..0f949fc42 100644
--- a/compat/win32/pthread.c
+++ b/compat/win32/pthread.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2009 Andrzej K. Haczewski <ahaczewski@gmail.com>
*
- * DISCLAMER: The implementation is Git-specific, it is subset of original
+ * DISCLAIMER: The implementation is Git-specific, it is subset of original
* Pthreads API, without lots of other features that Git doesn't use.
* Git also makes sure that the passed arguments are valid, so there's
* no need for double-checking.
diff --git a/connect.c b/connect.c
index 20054e4d0..beaff987c 100644
--- a/connect.c
+++ b/connect.c
@@ -504,7 +504,7 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
/*
* Don't do destructive transforms with git:// as that
- * protocol code does '[]' dewrapping of its own.
+ * protocol code does '[]' unwrapping of its own.
*/
if (host[0] == '[') {
end = strchr(host + 1, ']');
@@ -607,18 +607,8 @@ struct child_process *git_connect(int fd[2], const char *url_orig,
*arg++ = host;
}
else {
- /* remove these from the environment */
- const char *env[] = {
- ALTERNATE_DB_ENVIRONMENT,
- DB_ENVIRONMENT,
- GIT_DIR_ENVIRONMENT,
- GIT_WORK_TREE_ENVIRONMENT,
- GRAFT_ENVIRONMENT,
- INDEX_ENVIRONMENT,
- NO_REPLACE_OBJECTS_ENVIRONMENT,
- NULL
- };
- conn->env = env;
+ /* remove repo-local variables from the environment */
+ conn->env = local_repo_env;
conn->use_shell = 1;
}
*arg++ = cmd.buf;
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index fe93747c9..733ac39a3 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -250,7 +250,9 @@ __git_refs ()
refs="${cur%/*}"
;;
*)
- if [ -e "$dir/HEAD" ]; then echo HEAD; fi
+ for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do
+ if [ -e "$dir/$i" ]; then echo $i; fi
+ done
format="refname:short"
refs="refs/tags refs/heads refs/remotes"
;;
diff --git a/contrib/fast-import/git-p4 b/contrib/fast-import/git-p4
index e7c48144e..cd96c6f81 100755
--- a/contrib/fast-import/git-p4
+++ b/contrib/fast-import/git-p4
@@ -967,9 +967,8 @@ class P4Sync(Command):
elif file["type"] == "symlink":
mode = "120000"
# p4 print on a symlink contains "target\n", so strip it off
- last = contents.pop()
- last = last[:-1]
- contents.append(last)
+ data = ''.join(contents)
+ contents = [data[:-1]]
if self.isWindows and file["type"].endswith("text"):
mangled = []
diff --git a/contrib/fast-import/import-directories.perl b/contrib/fast-import/import-directories.perl
index 5782d80e2..3a5da4ab0 100755
--- a/contrib/fast-import/import-directories.perl
+++ b/contrib/fast-import/import-directories.perl
@@ -344,7 +344,7 @@ sub parsekeyvaluepair
Key and value strings may be enclosed in quotes, in which case
whitespace inside the quotes is preserved. Additionally, an equal
-sign may be included in the key by preceeding it with a backslash.
+sign may be included in the key by preceding it with a backslash.
For example:
"key1 "=value1
diff --git a/convert.c b/convert.c
index 27acce58b..4f8fcb7bb 100644
--- a/convert.c
+++ b/convert.c
@@ -241,7 +241,7 @@ struct filter_params {
const char *cmd;
};
-static int filter_buffer(int fd, void *data)
+static int filter_buffer(int in, int out, void *data)
{
/*
* Spawn cmd and feed the buffer contents through its stdin.
@@ -255,7 +255,7 @@ static int filter_buffer(int fd, void *data)
child_process.argv = argv;
child_process.use_shell = 1;
child_process.in = -1;
- child_process.out = fd;
+ child_process.out = out;
if (start_command(&child_process))
return error("cannot fork to run external filter %s", params->cmd);
@@ -292,6 +292,7 @@ static int apply_filter(const char *path, const char *src, size_t len,
memset(&async, 0, sizeof(async));
async.proc = filter_buffer;
async.data = &params;
+ async.out = -1;
params.src = src;
params.size = len;
params.cmd = cmd;
diff --git a/daemon.c b/daemon.c
index 6c2bd9771..7d9e1c03e 100644
--- a/daemon.c
+++ b/daemon.c
@@ -407,7 +407,7 @@ static void parse_host_and_port(char *hostport, char **host,
end = strchr(hostport, ']');
if (!end)
- die("Invalid reqeuest ('[' without ']')");
+ die("Invalid request ('[' without ']')");
*end = '\0';
*host = hostport + 1;
if (!end[1])
@@ -420,7 +420,7 @@ static void parse_host_and_port(char *hostport, char **host,
*host = hostport;
*port = strrchr(hostport, ':');
if (*port) {
- *port = '\0';
+ **port = '\0';
++*port;
}
}
diff --git a/diff.c b/diff.c
index 381cc8d4f..0d465faa1 100644
--- a/diff.c
+++ b/diff.c
@@ -2893,6 +2893,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
;
else if (!prefixcmp(arg, "--output=")) {
options->file = fopen(arg + strlen("--output="), "w");
+ if (!options->file)
+ die_errno("Could not open '%s'", arg + strlen("--output="));
options->close_file = 1;
} else
return 0;
@@ -3520,6 +3522,29 @@ void diff_flush(struct diff_options *options)
separator++;
}
+ if (output_format & DIFF_FORMAT_NO_OUTPUT &&
+ DIFF_OPT_TST(options, EXIT_WITH_STATUS) &&
+ DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) {
+ /*
+ * run diff_flush_patch for the exit status. setting
+ * options->file to /dev/null should be safe, becaue we
+ * aren't supposed to produce any output anyway.
+ */
+ if (options->close_file)
+ fclose(options->file);
+ options->file = fopen("/dev/null", "w");
+ if (!options->file)
+ die_errno("Could not open /dev/null");
+ options->close_file = 1;
+ for (i = 0; i < q->nr; i++) {
+ struct diff_filepair *p = q->queue[i];
+ if (check_pair_status(p))
+ diff_flush_patch(p, options);
+ if (options->found_changes)
+ break;
+ }
+ }
+
if (output_format & DIFF_FORMAT_PATCH) {
if (separator) {
putc(options->line_termination, options->file);
@@ -3642,7 +3667,7 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
struct diff_filepair *p = q->queue[i];
/*
- * 1. Entries that come from stat info dirtyness
+ * 1. Entries that come from stat info dirtiness
* always have both sides (iow, not create/delete),
* one side of the object name is unknown, with
* the same mode and size. Keep the ones that
diff --git a/dir.c b/dir.c
index 67c3af6a1..133c333df 100644
--- a/dir.c
+++ b/dir.c
@@ -1044,7 +1044,7 @@ int remove_path(const char *name)
slash = dirs + (slash - name);
do {
*slash = '\0';
- } while (rmdir(dirs) && (slash = strrchr(dirs, '/')));
+ } while (rmdir(dirs) == 0 && (slash = strrchr(dirs, '/')));
free(dirs);
}
return 0;
diff --git a/environment.c b/environment.c
index 739ec2704..876c5e534 100644
--- a/environment.c
+++ b/environment.c
@@ -63,6 +63,23 @@ static char *work_tree;
static const char *git_dir;
static char *git_object_dir, *git_index_file, *git_refs_dir, *git_graft_file;
+/*
+ * Repository-local GIT_* environment variables
+ * Remember to update local_repo_env_size in cache.h when
+ * the size of the list changes
+ */
+const char * const local_repo_env[LOCAL_REPO_ENV_SIZE + 1] = {
+ ALTERNATE_DB_ENVIRONMENT,
+ CONFIG_ENVIRONMENT,
+ DB_ENVIRONMENT,
+ GIT_DIR_ENVIRONMENT,
+ GIT_WORK_TREE_ENVIRONMENT,
+ GRAFT_ENVIRONMENT,
+ INDEX_ENVIRONMENT,
+ NO_REPLACE_OBJECTS_ENVIRONMENT,
+ NULL
+};
+
static void setup_git_env(void)
{
git_dir = getenv(GIT_DIR_ENVIRONMENT);
diff --git a/fast-import.c b/fast-import.c
index b477dc6a8..74f08bd55 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -164,12 +164,11 @@ Format of STDIN stream:
struct object_entry
{
+ struct pack_idx_entry idx;
struct object_entry *next;
- uint32_t offset;
uint32_t type : TYPE_BITS,
pack_id : PACK_ID_BITS,
depth : DEPTH_BITS;
- unsigned char sha1[20];
};
struct object_entry_pool
@@ -192,7 +191,7 @@ struct mark_set
struct last_object
{
struct strbuf data;
- uint32_t offset;
+ off_t offset;
unsigned int depth;
unsigned no_swap : 1;
};
@@ -280,7 +279,7 @@ struct recent_command
/* Configured limits on output */
static unsigned long max_depth = 10;
-static off_t max_packsize = (1LL << 32) - 1;
+static off_t max_packsize;
static uintmax_t big_file_threshold = 512 * 1024 * 1024;
static int force_update;
static int pack_compression_level = Z_DEFAULT_COMPRESSION;
@@ -313,9 +312,10 @@ static struct atom_str **atom_table;
/* The .pack file being generated */
static unsigned int pack_id;
+static struct sha1file *pack_file;
static struct packed_git *pack_data;
static struct packed_git **all_packs;
-static unsigned long pack_size;
+static off_t pack_size;
/* Table of objects we've written. */
static unsigned int object_entry_alloc = 5000;
@@ -521,7 +521,7 @@ static struct object_entry *new_object(unsigned char *sha1)
alloc_objects(object_entry_alloc);
e = blocks->next_free++;
- hashcpy(e->sha1, sha1);
+ hashcpy(e->idx.sha1, sha1);
return e;
}
@@ -530,7 +530,7 @@ static struct object_entry *find_object(unsigned char *sha1)
unsigned int h = sha1[0] << 8 | sha1[1];
struct object_entry *e;
for (e = object_table[h]; e; e = e->next)
- if (!hashcmp(sha1, e->sha1))
+ if (!hashcmp(sha1, e->idx.sha1))
return e;
return NULL;
}
@@ -542,7 +542,7 @@ static struct object_entry *insert_object(unsigned char *sha1)
struct object_entry *p = NULL;
while (e) {
- if (!hashcmp(sha1, e->sha1))
+ if (!hashcmp(sha1, e->idx.sha1))
return e;
p = e;
e = e->next;
@@ -550,7 +550,7 @@ static struct object_entry *insert_object(unsigned char *sha1)
e = new_object(sha1);
e->next = NULL;
- e->offset = 0;
+ e->idx.offset = 0;
if (p)
p->next = e;
else
@@ -839,11 +839,12 @@ static void start_packfile(void)
p = xcalloc(1, sizeof(*p) + strlen(tmpfile) + 2);
strcpy(p->pack_name, tmpfile);
p->pack_fd = pack_fd;
+ pack_file = sha1fd(pack_fd, p->pack_name);
hdr.hdr_signature = htonl(PACK_SIGNATURE);
hdr.hdr_version = htonl(2);
hdr.hdr_entries = 0;
- write_or_die(p->pack_fd, &hdr, sizeof(hdr));
+ sha1write(pack_file, &hdr, sizeof(hdr));
pack_data = p;
pack_size = sizeof(hdr);
@@ -853,67 +854,30 @@ static void start_packfile(void)
all_packs[pack_id] = p;
}
-static int oecmp (const void *a_, const void *b_)
-{
- struct object_entry *a = *((struct object_entry**)a_);
- struct object_entry *b = *((struct object_entry**)b_);
- return hashcmp(a->sha1, b->sha1);
-}
-
-static char *create_index(void)
+static const char *create_index(void)
{
- static char tmpfile[PATH_MAX];
- git_SHA_CTX ctx;
- struct sha1file *f;
- struct object_entry **idx, **c, **last, *e;
+ const char *tmpfile;
+ struct pack_idx_entry **idx, **c, **last;
+ struct object_entry *e;
struct object_entry_pool *o;
- uint32_t array[256];
- int i, idx_fd;
- /* Build the sorted table of object IDs. */
- idx = xmalloc(object_count * sizeof(struct object_entry*));
+ /* Build the table of object IDs. */
+ idx = xmalloc(object_count * sizeof(*idx));
c = idx;
for (o = blocks; o; o = o->next_pool)
for (e = o->next_free; e-- != o->entries;)
if (pack_id == e->pack_id)
- *c++ = e;
+ *c++ = &e->idx;
last = idx + object_count;
if (c != last)
die("internal consistency error creating the index");
- qsort(idx, object_count, sizeof(struct object_entry*), oecmp);
- /* Generate the fan-out array. */
- c = idx;
- for (i = 0; i < 256; i++) {
- struct object_entry **next = c;
- while (next < last) {
- if ((*next)->sha1[0] != i)
- break;
- next++;
- }
- array[i] = htonl(next - idx);
- c = next;
- }
-
- idx_fd = odb_mkstemp(tmpfile, sizeof(tmpfile),
- "pack/tmp_idx_XXXXXX");
- f = sha1fd(idx_fd, tmpfile);
- sha1write(f, array, 256 * sizeof(int));
- git_SHA1_Init(&ctx);
- for (c = idx; c != last; c++) {
- uint32_t offset = htonl((*c)->offset);
- sha1write(f, &offset, 4);
- sha1write(f, (*c)->sha1, sizeof((*c)->sha1));
- git_SHA1_Update(&ctx, (*c)->sha1, 20);
- }
- sha1write(f, pack_data->sha1, sizeof(pack_data->sha1));
- sha1close(f, NULL, CSUM_FSYNC);
+ tmpfile = write_idx_file(NULL, idx, object_count, pack_data->sha1);
free(idx);
- git_SHA1_Final(pack_data->sha1, &ctx);
return tmpfile;
}
-static char *keep_pack(char *curr_index_name)
+static char *keep_pack(const char *curr_index_name)
{
static char name[PATH_MAX];
static const char *keep_msg = "fast-import";
@@ -935,6 +899,7 @@ static char *keep_pack(char *curr_index_name)
get_object_directory(), sha1_to_hex(pack_data->sha1));
if (move_temp_to_file(curr_index_name, name))
die("cannot store index file");
+ free((void *)curr_index_name);
return name;
}
@@ -957,15 +922,17 @@ static void end_packfile(void)
clear_delta_base_cache();
if (object_count) {
+ unsigned char cur_pack_sha1[20];
char *idx_name;
int i;
struct branch *b;
struct tag *t;
close_pack_windows(pack_data);
+ sha1close(pack_file, cur_pack_sha1, 0);
fixup_pack_header_footer(pack_data->pack_fd, pack_data->sha1,
pack_data->pack_name, object_count,
- NULL, 0);
+ cur_pack_sha1, pack_size);
close(pack_data->pack_fd);
idx_name = keep_pack(create_index());
@@ -1063,25 +1030,21 @@ static int store_object(
e = insert_object(sha1);
if (mark)
insert_mark(mark, e);
- if (e->offset) {
+ if (e->idx.offset) {
duplicate_count_by_type[type]++;
return 1;
} else if (find_sha1_pack(sha1, packed_git)) {
e->type = type;
e->pack_id = MAX_PACK_ID;
- e->offset = 1; /* just not zero! */
+ e->idx.offset = 1; /* just not zero! */
duplicate_count_by_type[type]++;
return 1;
}
- if (last && last->data.buf && last->depth < max_depth) {
+ if (last && last->data.buf && last->depth < max_depth && dat->len > 20) {
delta = diff_delta(last->data.buf, last->data.len,
dat->buf, dat->len,
- &deltalen, 0);
- if (delta && deltalen >= dat->len) {
- free(delta);
- delta = NULL;
- }
+ &deltalen, dat->len - 20);
} else
delta = NULL;
@@ -1101,7 +1064,7 @@ static int store_object(
deflateEnd(&s);
/* Determine if we should auto-checkpoint. */
- if ((pack_size + 60 + s.total_out) > max_packsize
+ if ((max_packsize && (pack_size + 60 + s.total_out) > max_packsize)
|| (pack_size + 60 + s.total_out) < pack_size) {
/* This new object needs to *not* have the current pack_id. */
@@ -1127,36 +1090,40 @@ static int store_object(
e->type = type;
e->pack_id = pack_id;
- e->offset = pack_size;
+ e->idx.offset = pack_size;
object_count++;
object_count_by_type[type]++;
+ crc32_begin(pack_file);
+
if (delta) {
- unsigned long ofs = e->offset - last->offset;
+ off_t ofs = e->idx.offset - last->offset;
unsigned pos = sizeof(hdr) - 1;
delta_count_by_type[type]++;
e->depth = last->depth + 1;
hdrlen = encode_header(OBJ_OFS_DELTA, deltalen, hdr);
- write_or_die(pack_data->pack_fd, hdr, hdrlen);
+ sha1write(pack_file, hdr, hdrlen);
pack_size += hdrlen;
hdr[pos] = ofs & 127;
while (ofs >>= 7)
hdr[--pos] = 128 | (--ofs & 127);
- write_or_die(pack_data->pack_fd, hdr + pos, sizeof(hdr) - pos);
+ sha1write(pack_file, hdr + pos, sizeof(hdr) - pos);
pack_size += sizeof(hdr) - pos;
} else {
e->depth = 0;
hdrlen = encode_header(type, dat->len, hdr);
- write_or_die(pack_data->pack_fd, hdr, hdrlen);
+ sha1write(pack_file, hdr, hdrlen);
pack_size += hdrlen;
}
- write_or_die(pack_data->pack_fd, out, s.total_out);
+ sha1write(pack_file, out, s.total_out);
pack_size += s.total_out;
+ e->idx.crc32 = crc32_end(pack_file);
+
free(out);
free(delta);
if (last) {
@@ -1165,18 +1132,23 @@ static int store_object(
} else {
strbuf_swap(&last->data, dat);
}
- last->offset = e->offset;
+ last->offset = e->idx.offset;
last->depth = e->depth;
}
return 0;
}
-static void truncate_pack(off_t to)
+static void truncate_pack(off_t to, git_SHA_CTX *ctx)
{
if (ftruncate(pack_data->pack_fd, to)
|| lseek(pack_data->pack_fd, to, SEEK_SET) != to)
die_errno("cannot truncate pack to skip duplicate");
pack_size = to;
+
+ /* yes this is a layering violation */
+ pack_file->total = to;
+ pack_file->offset = 0;
+ pack_file->ctx = *ctx;
}
static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)
@@ -1189,16 +1161,21 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)
unsigned long hdrlen;
off_t offset;
git_SHA_CTX c;
+ git_SHA_CTX pack_file_ctx;
z_stream s;
int status = Z_OK;
/* Determine if we should auto-checkpoint. */
- if ((pack_size + 60 + len) > max_packsize
+ if ((max_packsize && (pack_size + 60 + len) > max_packsize)
|| (pack_size + 60 + len) < pack_size)
cycle_packfile();
offset = pack_size;
+ /* preserve the pack_file SHA1 ctx in case we have to truncate later */
+ sha1flush(pack_file);
+ pack_file_ctx = pack_file->ctx;
+
hdrlen = snprintf((char *)out_buf, out_sz, "blob %" PRIuMAX, len) + 1;
if (out_sz <= hdrlen)
die("impossibly large object header");
@@ -1206,6 +1183,8 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)
git_SHA1_Init(&c);
git_SHA1_Update(&c, out_buf, hdrlen);
+ crc32_begin(pack_file);
+
memset(&s, 0, sizeof(s));
deflateInit(&s, pack_compression_level);
@@ -1233,7 +1212,7 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)
if (!s.avail_out || status == Z_STREAM_END) {
size_t n = s.next_out - out_buf;
- write_or_die(pack_data->pack_fd, out_buf, n);
+ sha1write(pack_file, out_buf, n);
pack_size += n;
s.next_out = out_buf;
s.avail_out = out_sz;
@@ -1259,22 +1238,23 @@ static void stream_blob(uintmax_t len, unsigned char *sha1out, uintmax_t mark)
if (mark)
insert_mark(mark, e);
- if (e->offset) {
+ if (e->idx.offset) {
duplicate_count_by_type[OBJ_BLOB]++;
- truncate_pack(offset);
+ truncate_pack(offset, &pack_file_ctx);
} else if (find_sha1_pack(sha1, packed_git)) {
e->type = OBJ_BLOB;
e->pack_id = MAX_PACK_ID;
- e->offset = 1; /* just not zero! */
+ e->idx.offset = 1; /* just not zero! */
duplicate_count_by_type[OBJ_BLOB]++;
- truncate_pack(offset);
+ truncate_pack(offset, &pack_file_ctx);
} else {
e->depth = 0;
e->type = OBJ_BLOB;
e->pack_id = pack_id;
- e->offset = offset;
+ e->idx.offset = offset;
+ e->idx.crc32 = crc32_end(pack_file);
object_count++;
object_count_by_type[OBJ_BLOB]++;
}
@@ -1317,6 +1297,7 @@ static void *gfi_unpack_entry(
* the newly written data.
*/
close_pack_windows(p);
+ sha1flush(pack_file);
/* We have to offer 20 bytes additional on the end of
* the packfile as the core unpacker code assumes the
@@ -1326,7 +1307,7 @@ static void *gfi_unpack_entry(
*/
p->pack_size = pack_size + 20;
}
- return unpack_entry(p, oe->offset, &type, sizep);
+ return unpack_entry(p, oe->idx.offset, &type, sizep);
}
static const char *get_mode(const char *str, uint16_t *modep)
@@ -1457,7 +1438,7 @@ static void store_tree(struct tree_entry *root)
if (S_ISDIR(root->versions[0].mode) && le && le->pack_id == pack_id) {
mktree(t, 0, &old_tree);
lo.data = old_tree;
- lo.offset = le->offset;
+ lo.offset = le->idx.offset;
lo.depth = t->delta_depth;
}
@@ -1715,7 +1696,7 @@ static void dump_marks_helper(FILE *f,
for (k = 0; k < 1024; k++) {
if (m->data.marked[k])
fprintf(f, ":%" PRIuMAX " %s\n", base + k,
- sha1_to_hex(m->data.marked[k]->sha1));
+ sha1_to_hex(m->data.marked[k]->idx.sha1));
}
}
}
@@ -1798,7 +1779,7 @@ static void read_marks(void)
e = insert_object(sha1);
e->type = type;
e->pack_id = MAX_PACK_ID;
- e->offset = 1; /* just not zero! */
+ e->idx.offset = 1; /* just not zero! */
}
insert_mark(mark, e);
}
@@ -2183,7 +2164,7 @@ static void file_change_m(struct branch *b)
if (*p == ':') {
char *x;
oe = find_mark(strtoumax(p + 1, &x, 10));
- hashcpy(sha1, oe->sha1);
+ hashcpy(sha1, oe->idx.sha1);
p = x;
} else if (!prefixcmp(p, "inline")) {
inline_data = 1;
@@ -2316,7 +2297,7 @@ static void note_change_n(struct branch *b, unsigned char old_fanout)
if (*p == ':') {
char *x;
oe = find_mark(strtoumax(p + 1, &x, 10));
- hashcpy(sha1, oe->sha1);
+ hashcpy(sha1, oe->idx.sha1);
p = x;
} else if (!prefixcmp(p, "inline")) {
inline_data = 1;
@@ -2339,7 +2320,7 @@ static void note_change_n(struct branch *b, unsigned char old_fanout)
struct object_entry *commit_oe = find_mark(commit_mark);
if (commit_oe->type != OBJ_COMMIT)
die("Mark :%" PRIuMAX " not a commit", commit_mark);
- hashcpy(commit_sha1, commit_oe->sha1);
+ hashcpy(commit_sha1, commit_oe->idx.sha1);
} else if (!get_sha1(p, commit_sha1)) {
unsigned long size;
char *buf = read_object_with_reference(commit_sha1,
@@ -2446,7 +2427,7 @@ static int parse_from(struct branch *b)
struct object_entry *oe = find_mark(idnum);
if (oe->type != OBJ_COMMIT)
die("Mark :%" PRIuMAX " not a commit", idnum);
- hashcpy(b->sha1, oe->sha1);
+ hashcpy(b->sha1, oe->idx.sha1);
if (oe->pack_id != MAX_PACK_ID) {
unsigned long size;
char *buf = gfi_unpack_entry(oe, &size);
@@ -2481,7 +2462,7 @@ static struct hash_list *parse_merge(unsigned int *count)
struct object_entry *oe = find_mark(idnum);
if (oe->type != OBJ_COMMIT)
die("Mark :%" PRIuMAX " not a commit", idnum);
- hashcpy(n->sha1, oe->sha1);
+ hashcpy(n->sha1, oe->idx.sha1);
} else if (!get_sha1(from, n->sha1)) {
unsigned long size;
char *buf = read_object_with_reference(n->sha1,
@@ -2639,7 +2620,7 @@ static void parse_new_tag(void)
from_mark = strtoumax(from + 1, NULL, 10);
oe = find_mark(from_mark);
type = oe->type;
- hashcpy(sha1, oe->sha1);
+ hashcpy(sha1, oe->idx.sha1);
} else if (!get_sha1(from, sha1)) {
unsigned long size;
char *buf;
@@ -2891,6 +2872,17 @@ static int git_pack_config(const char *k, const char *v, void *cb)
pack_compression_seen = 1;
return 0;
}
+ if (!strcmp(k, "pack.indexversion")) {
+ pack_idx_default_version = git_config_int(k, v);
+ if (pack_idx_default_version > 2)
+ die("bad pack.indexversion=%"PRIu32,
+ pack_idx_default_version);
+ return 0;
+ }
+ if (!strcmp(k, "pack.packsizelimit")) {
+ max_packsize = git_config_ulong(k, v);
+ return 0;
+ }
if (!strcmp(k, "core.bigfilethreshold")) {
long n = git_config_int(k, v);
big_file_threshold = 0 < n ? n : 0;
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index cd43c3491..21f1330a5 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -957,6 +957,28 @@ sub coalesce_overlapping_hunks {
return @out;
}
+sub reassemble_patch {
+ my $head = shift;
+ my @patch;
+
+ # Include everything in the header except the beginning of the diff.
+ push @patch, (grep { !/^[-+]{3}/ } @$head);
+
+ # Then include any headers from the hunk lines, which must
+ # come before any actual hunk.
+ while (@_ && $_[0] !~ /^@/) {
+ push @patch, shift;
+ }
+
+ # Then begin the diff.
+ push @patch, grep { /^[-+]{3}/ } @$head;
+
+ # And then the actual hunks.
+ push @patch, @_;
+
+ return @patch;
+}
+
sub color_diff {
return map {
colored((/^@/ ? $fraginfo_color :
@@ -1453,7 +1475,7 @@ sub patch_update_file {
if (@result) {
my $fh;
- my @patch = (@{$head->{TEXT}}, @result);
+ my @patch = reassemble_patch($head->{TEXT}, @result);
my $apply_routine = $patch_mode_flavour{APPLY};
&$apply_routine(@patch);
refresh();
diff --git a/git-am.sh b/git-am.sh
index 3c08d5316..9df951a59 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -663,10 +663,7 @@ do
[eE]*) git_editor "$dotest/final-commit"
action=again ;;
[vV]*) action=again
- : ${GIT_PAGER=$(git var GIT_PAGER)}
- : ${LESS=-FRSX}
- export LESS
- $GIT_PAGER "$dotest/patch" ;;
+ git_pager "$dotest/patch" ;;
*) action=again ;;
esac
done
@@ -776,6 +773,5 @@ do
go_next
done
-git gc --auto
-
rm -fr "$dotest"
+git gc --auto
diff --git a/git-pull.sh b/git-pull.sh
index 38331a861..246a3a4b3 100755
--- a/git-pull.sh
+++ b/git-pull.sh
@@ -41,7 +41,7 @@ strategy_args= diffstat= no_commit= squash= no_ff= ff_only=
log_arg= verbosity=
merge_args=
curr_branch=$(git symbolic-ref -q HEAD)
-curr_branch_short=$(echo "$curr_branch" | sed "s|refs/heads/||")
+curr_branch_short="${curr_branch#refs/heads/}"
rebase=$(git config --bool branch.$curr_branch_short.rebase)
while :
do
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index d56426dd3..613167086 100755
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -107,6 +107,19 @@ git_editor() {
eval "$GIT_EDITOR" '"$@"'
}
+git_pager() {
+ if test -t 1
+ then
+ GIT_PAGER=$(git var GIT_PAGER)
+ else
+ GIT_PAGER=cat
+ fi
+ : ${LESS=-FRSX}
+ export LESS
+
+ eval "$GIT_PAGER" '"$@"'
+}
+
sane_grep () {
GREP_OPTIONS= LC_ALL=C grep "$@"
}
@@ -128,7 +141,7 @@ cd_to_toplevel () {
}
require_work_tree () {
- test $(git rev-parse --is-inside-work-tree) = true ||
+ test "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = true ||
die "fatal: $0 cannot be used without a working tree."
}
@@ -159,6 +172,13 @@ get_author_ident_from_commit () {
LANG=C LC_ALL=C sed -ne "$pick_author_script"
}
+# Clear repo-local GIT_* environment variables. Useful when switching to
+# another repository (e.g. when entering a submodule). See also the env
+# list in git_connect()
+clear_local_git_env() {
+ unset $(git rev-parse --local-env-vars)
+}
+
# Make sure we are in a valid repository of a vintage we understand,
# if we require to be in a git repository.
if test -z "$NONGIT_OK"
diff --git a/git-stash.sh b/git-stash.sh
index 3a0685f18..aa47e541e 100755
--- a/git-stash.sh
+++ b/git-stash.sh
@@ -151,6 +151,7 @@ save_stash () {
;;
-*)
echo "error: unknown option for 'stash save': $1"
+ echo " To provide a message, use git stash save -- '$1'"
usage
;;
*)
@@ -221,6 +222,7 @@ show_stash () {
}
apply_stash () {
+ applied_stash=
unstash_index=
while test $# != 0
@@ -242,6 +244,9 @@ apply_stash () {
if test $# = 0
then
have_stash || die 'Nothing to apply'
+ applied_stash="$ref_stash@{0}"
+ else
+ applied_stash="$*"
fi
# stash records the work tree, and is a merge between the
@@ -415,8 +420,7 @@ pop)
shift
if apply_stash "$@"
then
- test -z "$unstash_index" || shift
- drop_stash "$@"
+ drop_stash "$applied_stash"
fi
;;
branch)
diff --git a/git-submodule.sh b/git-submodule.sh
index 664f21721..e2082fd14 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -222,7 +222,7 @@ cmd_add()
module_clone "$path" "$realrepo" "$reference" || exit
(
- unset GIT_DIR
+ clear_local_git_env
cd "$path" &&
# ash fails to wordsplit ${branch:+-b "$branch"...}
case "$branch" in
@@ -278,7 +278,7 @@ cmd_foreach()
name=$(module_name "$path")
(
prefix="$prefix$path/"
- unset GIT_DIR
+ clear_local_git_env
cd "$path" &&
eval "$@" &&
if test -n "$recursive"
@@ -434,7 +434,7 @@ cmd_update()
module_clone "$path" "$url" "$reference"|| exit
subsha1=
else
- subsha1=$(unset GIT_DIR; cd "$path" &&
+ subsha1=$(clear_local_git_env; cd "$path" &&
git rev-parse --verify HEAD) ||
die "Unable to find current revision in submodule path '$path'"
fi
@@ -454,7 +454,7 @@ cmd_update()
if test -z "$nofetch"
then
- (unset GIT_DIR; cd "$path" &&
+ (clear_local_git_env; cd "$path" &&
git-fetch) ||
die "Unable to fetch in submodule path '$path'"
fi
@@ -477,14 +477,14 @@ cmd_update()
;;
esac
- (unset GIT_DIR; cd "$path" && $command "$sha1") ||
+ (clear_local_git_env; cd "$path" && $command "$sha1") ||
die "Unable to $action '$sha1' in submodule path '$path'"
say "Submodule path '$path': $msg '$sha1'"
fi
if test -n "$recursive"
then
- (unset GIT_DIR; cd "$path" && cmd_update $orig_args) ||
+ (clear_local_git_env; cd "$path" && cmd_update $orig_args) ||
die "Failed to recurse into submodule path '$path'"
fi
done
@@ -492,7 +492,7 @@ cmd_update()
set_name_rev () {
revname=$( (
- unset GIT_DIR
+ clear_local_git_env
cd "$1" && {
git describe "$2" 2>/dev/null ||
git describe --tags "$2" 2>/dev/null ||
@@ -757,7 +757,7 @@ cmd_status()
else
if test -z "$cached"
then
- sha1=$(unset GIT_DIR; cd "$path" && git rev-parse --verify HEAD)
+ sha1=$(clear_local_git_env; cd "$path" && git rev-parse --verify HEAD)
set_name_rev "$path" "$sha1"
fi
say "+$sha1 $displaypath$revname"
@@ -767,7 +767,7 @@ cmd_status()
then
(
prefix="$displaypath/"
- unset GIT_DIR
+ clear_local_git_env
cd "$path" &&
cmd_status $orig_args
) ||
@@ -818,7 +818,7 @@ cmd_sync()
if test -e "$path"/.git
then
(
- unset GIT_DIR
+ clear_local_git_env
cd "$path"
remote=$(get_default_remote)
say "Synchronizing submodule url for '$name'"
diff --git a/git-svn.perl b/git-svn.perl
index 265852f45..473a0b9d5 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -5459,7 +5459,12 @@ sub git_svn_log_cmd {
# adapted from pager.c
sub config_pager {
- chomp(my $pager = command_oneline(qw(var GIT_PAGER)));
+ if (! -t *STDOUT) {
+ $ENV{GIT_PAGER_IN_USE} = 'false';
+ $pager = undef;
+ return;
+ }
+ chomp($pager = command_oneline(qw(var GIT_PAGER)));
if ($pager eq 'cat') {
$pager = undef;
}
@@ -5467,7 +5472,7 @@ sub config_pager {
}
sub run_pager {
- return unless -t *STDOUT && defined $pager;
+ return unless defined $pager;
pipe my ($rfd, $wfd) or return;
defined(my $pid = fork) or ::fatal "Can't fork: $!";
if (!$pid) {
diff --git a/git.c b/git.c
index 4c3028c09..c445d7bcc 100644
--- a/git.c
+++ b/git.c
@@ -527,7 +527,7 @@ int main(int argc, const char **argv)
break;
if (was_alias) {
fprintf(stderr, "Expansion of alias '%s' failed; "
- "'%s' is not a git-command\n",
+ "'%s' is not a git command\n",
cmd, argv[0]);
exit(1);
}
diff --git a/gitweb/README b/gitweb/README
index 6c2c8e125..ad6a04c46 100644
--- a/gitweb/README
+++ b/gitweb/README
@@ -312,12 +312,16 @@ If you want to have one URL for both gitweb and your http://
repositories, you can configure apache like this:
<VirtualHost *:80>
- ServerName git.example.org
- DocumentRoot /pub/git
- SetEnv GITWEB_CONFIG /etc/gitweb.conf
+ ServerName git.example.org
+ DocumentRoot /pub/git
+ SetEnv GITWEB_CONFIG /etc/gitweb.conf
+
+ # turning on mod rewrite
RewriteEngine on
+
# make the front page an internal rewrite to the gitweb script
RewriteRule ^/$ /cgi-bin/gitweb.cgi
+
# make access for "dumb clients" work
RewriteRule ^/(.*\.git/(?!/?(HEAD|info|objects|refs)).*)?$ /cgi-bin/gitweb.cgi%{REQUEST_URI} [L,PT]
</VirtualHost>
@@ -343,6 +347,63 @@ something like the following in your gitweb.conf (or gitweb_config.perl) file:
$home_link = "/";
+Webserver configuration with multiple projects' root
+----------------------------------------------------
+
+If you want to use gitweb with several project roots you can edit your apache
+virtual host and gitweb.conf configuration files like this :
+
+virtual host configuration :
+
+<VirtualHost *:80>
+ ServerName git.example.org
+ DocumentRoot /pub/git
+ SetEnv GITWEB_CONFIG /etc/gitweb.conf
+
+ # turning on mod rewrite
+ RewriteEngine on
+
+ # make the front page an internal rewrite to the gitweb script
+ RewriteRule ^/$ /cgi-bin/gitweb.cgi [QSA,L,PT]
+
+ # look for a public_git folder in unix users' home
+ # http://git.example.org/~<user>/
+ RewriteRule ^/\~([^\/]+)(/|/gitweb.cgi)?$ /cgi-bin/gitweb.cgi [QSA,E=GITWEB_PROJECTROOT:/home/$1/public_git/,L,PT]
+
+ # http://git.example.org/+<user>/
+ #RewriteRule ^/\+([^\/]+)(/|/gitweb.cgi)?$ /cgi-bin/gitweb.cgi [QSA,E=GITWEB_PROJECTROOT:/home/$1/public_git/,L,PT]
+
+ # http://git.example.org/user/<user>/
+ #RewriteRule ^/user/([^\/]+)/(gitweb.cgi)?$ /cgi-bin/gitweb.cgi [QSA,E=GITWEB_PROJECTROOT:/home/$1/public_git/,L,PT]
+
+ # defined list of project roots
+ RewriteRule ^/scm(/|/gitweb.cgi)?$ /cgi-bin/gitweb.cgi [QSA,E=GITWEB_PROJECTROOT:/pub/scm/,L,PT]
+ RewriteRule ^/var(/|/gitweb.cgi)?$ /cgi-bin/gitweb.cgi [QSA,E=GITWEB_PROJECTROOT:/var/git/,L,PT]
+
+ # make access for "dumb clients" work
+ RewriteRule ^/(.*\.git/(?!/?(HEAD|info|objects|refs)).*)?$ /cgi-bin/gitweb.cgi%{REQUEST_URI} [L,PT]
+</VirtualHost>
+
+gitweb.conf configuration :
+
+$projectroot = $ENV{'GITWEB_PROJECTROOT'} || "/pub/git";
+
+These configurations enable two things. First, each unix user (<user>) of the
+server will be able to browse through gitweb git repositories found in
+~/public_git/ with the following url : http://git.example.org/~<user>/
+
+If you do not want this feature on your server just remove the second rewrite rule.
+
+If you already use mod_userdir in your virtual host or you don't want to use
+the '~' as first character just comment or remove the second rewrite rule and
+uncomment one of the following according to what you want.
+
+Second, repositories found in /pub/scm/ and /var/git/ will be accesible
+through http://git.example.org/scm/ and http://git.example.org/var/.
+You can add as many project roots as you want by adding rewrite rules like the
+third and the fourth.
+
+
PATH_INFO usage
-----------------------
If you enable PATH_INFO usage in gitweb by putting
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 1f6978ac1..3d80deba0 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -454,7 +454,11 @@ sub gitweb_get_feature {
$feature{$name}{'sub'},
$feature{$name}{'override'},
@{$feature{$name}{'default'}});
- if (!$override) { return @defaults; }
+ # project specific override is possible only if we have project
+ our $git_dir; # global variable, declared later
+ if (!$override || !defined $git_dir) {
+ return @defaults;
+ }
if (!defined $sub) {
warn "feature $name is not overridable";
return @defaults;
@@ -550,11 +554,14 @@ sub filter_snapshot_fmts {
}
our $GITWEB_CONFIG = $ENV{'GITWEB_CONFIG'} || "++GITWEB_CONFIG++";
+our $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "++GITWEB_CONFIG_SYSTEM++";
+# die if there are errors parsing config file
if (-e $GITWEB_CONFIG) {
do $GITWEB_CONFIG;
-} else {
- our $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "++GITWEB_CONFIG_SYSTEM++";
- do $GITWEB_CONFIG_SYSTEM if -e $GITWEB_CONFIG_SYSTEM;
+ die $@ if $@;
+} elsif (-e $GITWEB_CONFIG_SYSTEM) {
+ do $GITWEB_CONFIG_SYSTEM;
+ die $@ if $@;
}
# Get loadavg of system, to compare against $maxload.
@@ -2202,6 +2209,9 @@ sub config_to_multi {
sub git_get_project_config {
my ($key, $type) = @_;
+ # do we have project
+ return unless (defined $project && defined $git_dir);
+
# key sanity check
return unless ($key);
$key =~ s/^gitweb\.//;
diff --git a/grep.c b/grep.c
index a0864f1cb..90a063a98 100644
--- a/grep.c
+++ b/grep.c
@@ -11,8 +11,8 @@ void append_header_grep_pattern(struct grep_opt *opt, enum grep_header_field fie
p->no = 0;
p->token = GREP_PATTERN_HEAD;
p->field = field;
- *opt->pattern_tail = p;
- opt->pattern_tail = &p->next;
+ *opt->header_tail = p;
+ opt->header_tail = &p->next;
p->next = NULL;
}
@@ -184,9 +184,26 @@ static struct grep_expr *compile_pattern_expr(struct grep_pat **list)
void compile_grep_patterns(struct grep_opt *opt)
{
struct grep_pat *p;
-
- if (opt->all_match)
- opt->extended = 1;
+ struct grep_expr *header_expr = NULL;
+
+ if (opt->header_list) {
+ p = opt->header_list;
+ header_expr = compile_pattern_expr(&p);
+ if (p)
+ die("incomplete pattern expression: %s", p->pattern);
+ for (p = opt->header_list; p; p = p->next) {
+ switch (p->token) {
+ case GREP_PATTERN: /* atom */
+ case GREP_PATTERN_HEAD:
+ case GREP_PATTERN_BODY:
+ compile_regexp(p, opt);
+ break;
+ default:
+ opt->extended = 1;
+ break;
+ }
+ }
+ }
for (p = opt->pattern_list; p; p = p->next) {
switch (p->token) {
@@ -201,7 +218,9 @@ void compile_grep_patterns(struct grep_opt *opt)
}
}
- if (!opt->extended)
+ if (opt->all_match || header_expr)
+ opt->extended = 1;
+ else if (!opt->extended)
return;
/* Then bundle them up in an expression.
@@ -212,6 +231,21 @@ void compile_grep_patterns(struct grep_opt *opt)
opt->pattern_expression = compile_pattern_expr(&p);
if (p)
die("incomplete pattern expression: %s", p->pattern);
+
+ if (!header_expr)
+ return;
+
+ if (opt->pattern_expression) {
+ struct grep_expr *z;
+ z = xcalloc(1, sizeof(*z));
+ z->node = GREP_NODE_OR;
+ z->u.binary.left = opt->pattern_expression;
+ z->u.binary.right = header_expr;
+ opt->pattern_expression = z;
+ } else {
+ opt->pattern_expression = header_expr;
+ }
+ opt->all_match = 1;
}
static void free_pattern_expr(struct grep_expr *x)
diff --git a/grep.h b/grep.h
index 970308799..d35bc29bf 100644
--- a/grep.h
+++ b/grep.h
@@ -59,6 +59,8 @@ struct grep_expr {
struct grep_opt {
struct grep_pat *pattern_list;
struct grep_pat **pattern_tail;
+ struct grep_pat *header_list;
+ struct grep_pat **header_tail;
struct grep_expr *pattern_expression;
const char *prefix;
int prefix_length;
diff --git a/help.c b/help.c
index 9da97d746..7f4928e45 100644
--- a/help.c
+++ b/help.c
@@ -350,7 +350,7 @@ const char *help_unknown_cmd(const char *cmd)
return assumed;
}
- fprintf(stderr, "git: '%s' is not a git-command. See 'git --help'.\n", cmd);
+ fprintf(stderr, "git: '%s' is not a git command. See 'git --help'.\n", cmd);
if (SIMILAR_ENOUGH(best_similarity)) {
fprintf(stderr, "\nDid you mean %s?\n",
diff --git a/imap-send.c b/imap-send.c
index ba72fa4b6..5631930bc 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -91,7 +91,6 @@ struct msg_data {
char *data;
int len;
unsigned char flags;
- unsigned int crlf:1;
};
static const char imap_send_usage[] = "git imap-send < <mbox>";
@@ -1162,6 +1161,44 @@ static int imap_make_flags(int flags, char *buf)
return d;
}
+static void lf_to_crlf(struct msg_data *msg)
+{
+ char *new;
+ int i, j, lfnum = 0;
+
+ if (msg->data[0] == '\n')
+ lfnum++;
+ for (i = 1; i < msg->len; i++) {
+ if (msg->data[i - 1] != '\r' && msg->data[i] == '\n')
+ lfnum++;
+ }
+
+ new = xmalloc(msg->len + lfnum);
+ if (msg->data[0] == '\n') {
+ new[0] = '\r';
+ new[1] = '\n';
+ i = 1;
+ j = 2;
+ } else {
+ new[0] = msg->data[0];
+ i = 1;
+ j = 1;
+ }
+ for ( ; i < msg->len; i++) {
+ if (msg->data[i] != '\n') {
+ new[j++] = msg->data[i];
+ continue;
+ }
+ if (msg->data[i - 1] != '\r')
+ new[j++] = '\r';
+ /* otherwise it already had CR before */
+ new[j++] = '\n';
+ }
+ msg->len += lfnum;
+ free(msg->data);
+ msg->data = new;
+}
+
static int imap_store_msg(struct store *gctx, struct msg_data *data)
{
struct imap_store *ctx = (struct imap_store *)gctx;
@@ -1171,6 +1208,7 @@ static int imap_store_msg(struct store *gctx, struct msg_data *data)
int ret, d;
char flagstr[128];
+ lf_to_crlf(data);
memset(&cb, 0, sizeof(cb));
cb.dlen = data->len;
diff --git a/levenshtein.h b/levenshtein.h
index 0173abeef..4105bf354 100644
--- a/levenshtein.h
+++ b/levenshtein.h
@@ -2,7 +2,7 @@
#define LEVENSHTEIN_H
int levenshtein(const char *string1, const char *string2,
- int swap_penalty, int substition_penalty,
+ int swap_penalty, int substitution_penalty,
int insertion_penalty, int deletion_penalty);
#endif
diff --git a/pager.c b/pager.c
index 2c7e8ecb3..dac358f04 100644
--- a/pager.c
+++ b/pager.c
@@ -48,11 +48,11 @@ static void wait_for_pager_signal(int signo)
raise(signo);
}
-const char *git_pager(void)
+const char *git_pager(int stdout_is_tty)
{
const char *pager;
- if (!isatty(1))
+ if (!stdout_is_tty)
return NULL;
pager = getenv("GIT_PAGER");
@@ -73,7 +73,7 @@ const char *git_pager(void)
void setup_pager(void)
{
- const char *pager = git_pager();
+ const char *pager = git_pager(isatty(1));
if (!pager)
return;
diff --git a/path.c b/path.c
index 79aa10471..aaa9345eb 100644
--- a/path.c
+++ b/path.c
@@ -157,6 +157,85 @@ int git_mkstemps(char *path, size_t len, const char *template, int suffix_len)
return mkstemps(path, suffix_len);
}
+/* Adapted from libiberty's mkstemp.c. */
+
+#undef TMP_MAX
+#define TMP_MAX 16384
+
+int git_mkstemps_mode(char *pattern, int suffix_len, int mode)
+{
+ static const char letters[] =
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789";
+ static const int num_letters = 62;
+ uint64_t value;
+ struct timeval tv;
+ char *template;
+ size_t len;
+ int fd, count;
+
+ len = strlen(pattern);
+
+ if (len < 6 + suffix_len) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (strncmp(&pattern[len - 6 - suffix_len], "XXXXXX", 6)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * Replace pattern's XXXXXX characters with randomness.
+ * Try TMP_MAX different filenames.
+ */
+ gettimeofday(&tv, NULL);
+ value = ((size_t)(tv.tv_usec << 16)) ^ tv.tv_sec ^ getpid();
+ template = &pattern[len - 6 - suffix_len];
+ for (count = 0; count < TMP_MAX; ++count) {
+ uint64_t v = value;
+ /* Fill in the random bits. */
+ template[0] = letters[v % num_letters]; v /= num_letters;
+ template[1] = letters[v % num_letters]; v /= num_letters;
+ template[2] = letters[v % num_letters]; v /= num_letters;
+ template[3] = letters[v % num_letters]; v /= num_letters;
+ template[4] = letters[v % num_letters]; v /= num_letters;
+ template[5] = letters[v % num_letters]; v /= num_letters;
+
+ fd = open(pattern, O_CREAT | O_EXCL | O_RDWR, mode);
+ if (fd > 0)
+ return fd;
+ /*
+ * Fatal error (EPERM, ENOSPC etc).
+ * It doesn't make sense to loop.
+ */
+ if (errno != EEXIST)
+ break;
+ /*
+ * This is a random value. It is only necessary that
+ * the next TMP_MAX values generated by adding 7777 to
+ * VALUE are different with (module 2^32).
+ */
+ value += 7777;
+ }
+ /* We return the null string if we can't find a unique file name. */
+ pattern[0] = '\0';
+ return -1;
+}
+
+int git_mkstemp_mode(char *pattern, int mode)
+{
+ /* mkstemp is just mkstemps with no suffix */
+ return git_mkstemps_mode(pattern, 0, mode);
+}
+
+int gitmkstemps(char *pattern, int suffix_len)
+{
+ return git_mkstemps_mode(pattern, suffix_len, 0600);
+}
+
int validate_headref(const char *path)
{
struct stat st;
@@ -610,7 +689,7 @@ int daemon_avoid_alias(const char *p)
/*
* This resurrects the belts and suspenders paranoia check by HPA
* done in <435560F7.4080006@zytor.com> thread, now enter_repo()
- * does not do getcwd() based path canonicalizations.
+ * does not do getcwd() based path canonicalization.
*
* sl becomes true immediately after seeing '/' and continues to
* be true as long as dots continue after that without intervening
diff --git a/perl/Git.pm b/perl/Git.pm
index e8df55d2f..970fe434e 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -204,14 +204,14 @@ sub repository {
$dir = $opts{Directory};
unless (-d "$dir/refs" and -d "$dir/objects" and -e "$dir/HEAD") {
- # Mimick git-rev-parse --git-dir error message:
+ # Mimic git-rev-parse --git-dir error message:
throw Error::Simple("fatal: Not a git repository: $dir");
}
my $search = Git->repository(Repository => $dir);
try {
$search->command('symbolic-ref', 'HEAD');
} catch Git::Error::Command with {
- # Mimick git-rev-parse --git-dir error message:
+ # Mimic git-rev-parse --git-dir error message:
throw Error::Simple("fatal: Not a git repository: $dir");
}
diff --git a/refs.c b/refs.c
index 503a8c2bd..63e30d74a 100644
--- a/refs.c
+++ b/refs.c
@@ -706,7 +706,7 @@ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
has_glob_specials = strpbrk(pattern, "?*[");
if (!has_glob_specials) {
- /* Append impiled '/' '*' if not present. */
+ /* Append implied '/' '*' if not present. */
if (real_pattern.buf[real_pattern.len - 1] != '/')
strbuf_addch(&real_pattern, '/');
/* No need to check for '*', there is none. */
@@ -1574,7 +1574,7 @@ int for_each_recent_reflog_ent(const char *ref, each_reflog_ent_fn fn, long ofs,
{
const char *logfile;
FILE *logfp;
- char buf[1024];
+ struct strbuf sb = STRBUF_INIT;
int ret = 0;
logfile = git_path("logs/%s", ref);
@@ -1587,24 +1587,24 @@ int for_each_recent_reflog_ent(const char *ref, each_reflog_ent_fn fn, long ofs,
if (fstat(fileno(logfp), &statbuf) ||
statbuf.st_size < ofs ||
fseek(logfp, -ofs, SEEK_END) ||
- fgets(buf, sizeof(buf), logfp)) {
+ strbuf_getwholeline(&sb, logfp, '\n')) {
fclose(logfp);
+ strbuf_release(&sb);
return -1;
}
}
- while (fgets(buf, sizeof(buf), logfp)) {
+ while (!strbuf_getwholeline(&sb, logfp, '\n')) {
unsigned char osha1[20], nsha1[20];
char *email_end, *message;
unsigned long timestamp;
- int len, tz;
+ int tz;
/* old SP new SP name <email> SP time TAB msg LF */
- len = strlen(buf);
- if (len < 83 || buf[len-1] != '\n' ||
- get_sha1_hex(buf, osha1) || buf[40] != ' ' ||
- get_sha1_hex(buf + 41, nsha1) || buf[81] != ' ' ||
- !(email_end = strchr(buf + 82, '>')) ||
+ if (sb.len < 83 || sb.buf[sb.len - 1] != '\n' ||
+ get_sha1_hex(sb.buf, osha1) || sb.buf[40] != ' ' ||
+ get_sha1_hex(sb.buf + 41, nsha1) || sb.buf[81] != ' ' ||
+ !(email_end = strchr(sb.buf + 82, '>')) ||
email_end[1] != ' ' ||
!(timestamp = strtoul(email_end + 2, &message, 10)) ||
!message || message[0] != ' ' ||
@@ -1618,11 +1618,13 @@ int for_each_recent_reflog_ent(const char *ref, each_reflog_ent_fn fn, long ofs,
message += 6;
else
message += 7;
- ret = fn(osha1, nsha1, buf+82, timestamp, tz, message, cb_data);
+ ret = fn(osha1, nsha1, sb.buf + 82, timestamp, tz, message,
+ cb_data);
if (ret)
break;
}
fclose(logfp);
+ strbuf_release(&sb);
return ret;
}
diff --git a/remote-curl.c b/remote-curl.c
index a904164e4..d38812085 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -184,13 +184,13 @@ static struct discovery* discover_refs(const char *service)
return last;
}
-static int write_discovery(int fd, void *data)
+static int write_discovery(int in, int out, void *data)
{
struct discovery *heads = data;
int err = 0;
- if (write_in_full(fd, heads->buf, heads->len) != heads->len)
+ if (write_in_full(out, heads->buf, heads->len) != heads->len)
err = 1;
- close(fd);
+ close(out);
return err;
}
@@ -202,6 +202,7 @@ static struct ref *parse_git_refs(struct discovery *heads)
memset(&async, 0, sizeof(async));
async.proc = write_discovery;
async.data = heads;
+ async.out = -1;
if (start_async(&async))
die("cannot start thread to parse advertised refs");
diff --git a/rerere.c b/rerere.c
index d1d3e7539..a59f74f76 100644
--- a/rerere.c
+++ b/rerere.c
@@ -364,7 +364,7 @@ static int find_conflict(struct string_list *conflict)
static int merge(const char *name, const char *path)
{
int ret;
- mmfile_t cur, base, other;
+ mmfile_t cur = {NULL, 0}, base = {NULL, 0}, other = {NULL, 0};
mmbuffer_t result = {NULL, 0};
if (handle_file(path, NULL, rerere_path(name, "thisimage")) < 0)
@@ -372,8 +372,10 @@ static int merge(const char *name, const char *path)
if (read_mmfile(&cur, rerere_path(name, "thisimage")) ||
read_mmfile(&base, rerere_path(name, "preimage")) ||
- read_mmfile(&other, rerere_path(name, "postimage")))
- return 1;
+ read_mmfile(&other, rerere_path(name, "postimage"))) {
+ ret = 1;
+ goto out;
+ }
ret = ll_merge(&result, path, &base, &cur, "", &other, "", 0);
if (!ret) {
FILE *f = fopen(path, "w");
@@ -387,6 +389,7 @@ static int merge(const char *name, const char *path)
strerror(errno));
}
+out:
free(cur.ptr);
free(base.ptr);
free(other.ptr);
diff --git a/revision.c b/revision.c
index 3ba6d991f..490b48408 100644
--- a/revision.c
+++ b/revision.c
@@ -547,6 +547,9 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)
right_count++;
}
+ if (!left_count || !right_count)
+ return;
+
left_first = left_count < right_count;
init_patch_ids(&ids);
if (revs->diffopt.nr_paths) {
@@ -823,6 +826,7 @@ void init_revisions(struct rev_info *revs, const char *prefix)
revs->grep_filter.status_only = 1;
revs->grep_filter.pattern_tail = &(revs->grep_filter.pattern_list);
+ revs->grep_filter.header_tail = &(revs->grep_filter.header_list);
revs->grep_filter.regflags = REG_NEWLINE;
diff_setup(&revs->diffopt);
@@ -1330,7 +1334,7 @@ static void append_prune_data(const char ***prune_data, const char **av)
*/
int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def)
{
- int i, flags, left, seen_dashdash, read_from_stdin;
+ int i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0;
const char **prune_data = NULL;
/* First, search for "--" */
@@ -1456,6 +1460,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
append_prune_data(&prune_data, argv + i);
break;
}
+ else
+ got_rev_arg = 1;
}
if (prune_data)
@@ -1465,7 +1471,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
revs->def = def;
if (revs->show_merge)
prepare_show_merge(revs);
- if (revs->def && !revs->pending.nr) {
+ if (revs->def && !revs->pending.nr && !got_rev_arg) {
unsigned char sha1[20];
struct object *object;
unsigned mode;
@@ -1801,7 +1807,7 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit)
static int commit_match(struct commit *commit, struct rev_info *opt)
{
- if (!opt->grep_filter.pattern_list)
+ if (!opt->grep_filter.pattern_list && !opt->grep_filter.header_list)
return 1;
return grep_buffer(&opt->grep_filter,
NULL, /* we say nothing, not even filename */
diff --git a/run-command.c b/run-command.c
index 2feb49395..c8d53795e 100644
--- a/run-command.c
+++ b/run-command.c
@@ -67,19 +67,21 @@ static int child_notifier = -1;
static void notify_parent(void)
{
- write(child_notifier, "", 1);
+ ssize_t unused;
+ unused = write(child_notifier, "", 1);
}
static NORETURN void die_child(const char *err, va_list params)
{
char msg[4096];
+ ssize_t unused;
int len = vsnprintf(msg, sizeof(msg), err, params);
if (len > sizeof(msg))
len = sizeof(msg);
- write(child_err, "fatal: ", 7);
- write(child_err, msg, len);
- write(child_err, "\n", 1);
+ unused = write(child_err, "fatal: ", 7);
+ unused = write(child_err, msg, len);
+ unused = write(child_err, "\n", 1);
exit(128);
}
@@ -233,6 +235,9 @@ fail_pipe:
else if (need_err) {
dup2(fderr[1], 2);
close_pair(fderr);
+ } else if (cmd->err > 1) {
+ dup2(cmd->err, 2);
+ close(cmd->err);
}
if (cmd->no_stdout)
@@ -325,6 +330,8 @@ fail_pipe:
fherr = open("/dev/null", O_RDWR);
else if (need_err)
fherr = dup(fderr[1]);
+ else if (cmd->err > 2)
+ fherr = dup(cmd->err);
if (cmd->no_stdout)
fhout = open("/dev/null", O_RDWR);
@@ -394,6 +401,8 @@ fail_pipe:
if (need_err)
close(fderr[1]);
+ else if (cmd->err)
+ close(cmd->err);
return 0;
}
@@ -444,17 +453,51 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
static unsigned __stdcall run_thread(void *data)
{
struct async *async = data;
- return async->proc(async->fd_for_proc, async->data);
+ return async->proc(async->proc_in, async->proc_out, async->data);
}
#endif
int start_async(struct async *async)
{
- int pipe_out[2];
+ int need_in, need_out;
+ int fdin[2], fdout[2];
+ int proc_in, proc_out;
- if (pipe(pipe_out) < 0)
- return error("cannot create pipe: %s", strerror(errno));
- async->out = pipe_out[0];
+ need_in = async->in < 0;
+ if (need_in) {
+ if (pipe(fdin) < 0) {
+ if (async->out > 0)
+ close(async->out);
+ return error("cannot create pipe: %s", strerror(errno));
+ }
+ async->in = fdin[1];
+ }
+
+ need_out = async->out < 0;
+ if (need_out) {
+ if (pipe(fdout) < 0) {
+ if (need_in)
+ close_pair(fdin);
+ else if (async->in)
+ close(async->in);
+ return error("cannot create pipe: %s", strerror(errno));
+ }
+ async->out = fdout[0];
+ }
+
+ if (need_in)
+ proc_in = fdin[0];
+ else if (async->in)
+ proc_in = async->in;
+ else
+ proc_in = -1;
+
+ if (need_out)
+ proc_out = fdout[1];
+ else if (async->out)
+ proc_out = async->out;
+ else
+ proc_out = -1;
#ifndef WIN32
/* Flush stdio before fork() to avoid cloning buffers */
@@ -463,24 +506,47 @@ int start_async(struct async *async)
async->pid = fork();
if (async->pid < 0) {
error("fork (async) failed: %s", strerror(errno));
- close_pair(pipe_out);
- return -1;
+ goto error;
}
if (!async->pid) {
- close(pipe_out[0]);
- exit(!!async->proc(pipe_out[1], async->data));
+ if (need_in)
+ close(fdin[1]);
+ if (need_out)
+ close(fdout[0]);
+ exit(!!async->proc(proc_in, proc_out, async->data));
}
- close(pipe_out[1]);
+
+ if (need_in)
+ close(fdin[0]);
+ else if (async->in)
+ close(async->in);
+
+ if (need_out)
+ close(fdout[1]);
+ else if (async->out)
+ close(async->out);
#else
- async->fd_for_proc = pipe_out[1];
+ async->proc_in = proc_in;
+ async->proc_out = proc_out;
async->tid = (HANDLE) _beginthreadex(NULL, 0, run_thread, async, 0, NULL);
if (!async->tid) {
error("cannot create thread: %s", strerror(errno));
- close_pair(pipe_out);
- return -1;
+ goto error;
}
#endif
return 0;
+
+error:
+ if (need_in)
+ close_pair(fdin);
+ else if (async->in)
+ close(async->in);
+
+ if (need_out)
+ close_pair(fdout);
+ else if (async->out)
+ close(async->out);
+ return -1;
}
int finish_async(struct async *async)
diff --git a/run-command.h b/run-command.h
index 967ba8cc0..94619f52d 100644
--- a/run-command.h
+++ b/run-command.h
@@ -18,7 +18,7 @@ struct child_process {
* - Specify > 0 to set a channel to a particular FD as follows:
* .in: a readable FD, becomes child's stdin
* .out: a writable FD, becomes child's stdout/stderr
- * .err > 0 not supported
+ * .err: a writable FD, becomes child's stderr
* The specified FD is closed by start_command(), even in case
* of errors!
*/
@@ -66,17 +66,20 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
*/
struct async {
/*
- * proc writes to fd and closes it;
+ * proc reads from in; closes it before return
+ * proc writes to out; closes it before return
* returns 0 on success, non-zero on failure
*/
- int (*proc)(int fd, void *data);
+ int (*proc)(int in, int out, void *data);
void *data;
+ int in; /* caller writes here and closes it */
int out; /* caller reads from here and closes it */
#ifndef WIN32
pid_t pid;
#else
HANDLE tid;
- int fd_for_proc;
+ int proc_in;
+ int proc_out;
#endif
};
diff --git a/setup.c b/setup.c
index 710e2f300..fac34f77a 100644
--- a/setup.c
+++ b/setup.c
@@ -206,7 +206,7 @@ int is_inside_work_tree(void)
}
/*
- * set_work_tree() is only ever called if you set GIT_DIR explicitely.
+ * set_work_tree() is only ever called if you set GIT_DIR explicitly.
* The old behaviour (which we retain here) is to set the work tree root
* to the cwd, unless overridden by the config, the command line, or
* GIT_WORK_TREE.
diff --git a/sha1_file.c b/sha1_file.c
index 657825e14..c23cc5e6e 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -2206,7 +2206,7 @@ int move_temp_to_file(const char *tmpfile, const char *filename)
}
out:
- if (set_shared_perm(filename, (S_IFREG|0444)))
+ if (adjust_shared_perm(filename))
return error("unable to set permission to '%s'", filename);
return 0;
}
@@ -2262,7 +2262,7 @@ static int create_tmpfile(char *buffer, size_t bufsiz, const char *filename)
}
memcpy(buffer, filename, dirlen);
strcpy(buffer + dirlen, "tmp_obj_XXXXXX");
- fd = mkstemp(buffer);
+ fd = git_mkstemp_mode(buffer, 0444);
if (fd < 0 && dirlen && errno == ENOENT) {
/* Make sure the directory exists */
memcpy(buffer, filename, dirlen);
@@ -2272,7 +2272,7 @@ static int create_tmpfile(char *buffer, size_t bufsiz, const char *filename)
/* Try again */
strcpy(buffer + dirlen - 1, "/tmp_obj_XXXXXX");
- fd = mkstemp(buffer);
+ fd = git_mkstemp_mode(buffer, 0444);
}
return fd;
}
@@ -2281,9 +2281,10 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
void *buf, unsigned long len, time_t mtime)
{
int fd, ret;
- size_t size;
- unsigned char *compressed;
+ unsigned char compressed[4096];
z_stream stream;
+ git_SHA_CTX c;
+ unsigned char parano_sha1[20];
char *filename;
static char tmpfile[PATH_MAX];
@@ -2301,36 +2302,40 @@ static int write_loose_object(const unsigned char *sha1, char *hdr, int hdrlen,
/* Set it up */
memset(&stream, 0, sizeof(stream));
deflateInit(&stream, zlib_compression_level);
- size = 8 + deflateBound(&stream, len+hdrlen);
- compressed = xmalloc(size);
-
- /* Compress it */
stream.next_out = compressed;
- stream.avail_out = size;
+ stream.avail_out = sizeof(compressed);
+ git_SHA1_Init(&c);
/* First header.. */
stream.next_in = (unsigned char *)hdr;
stream.avail_in = hdrlen;
while (deflate(&stream, 0) == Z_OK)
/* nothing */;
+ git_SHA1_Update(&c, hdr, hdrlen);
/* Then the data itself.. */
stream.next_in = buf;
stream.avail_in = len;
- ret = deflate(&stream, Z_FINISH);
+ do {
+ unsigned char *in0 = stream.next_in;
+ ret = deflate(&stream, Z_FINISH);
+ git_SHA1_Update(&c, in0, stream.next_in - in0);
+ if (write_buffer(fd, compressed, stream.next_out - compressed) < 0)
+ die("unable to write sha1 file");
+ stream.next_out = compressed;
+ stream.avail_out = sizeof(compressed);
+ } while (ret == Z_OK);
+
if (ret != Z_STREAM_END)
die("unable to deflate new object %s (%d)", sha1_to_hex(sha1), ret);
-
ret = deflateEnd(&stream);
if (ret != Z_OK)
die("deflateEnd on object %s failed (%d)", sha1_to_hex(sha1), ret);
+ git_SHA1_Final(parano_sha1, &c);
+ if (hashcmp(sha1, parano_sha1) != 0)
+ die("confused by unstable object source data for %s", sha1_to_hex(sha1));
- size = stream.total_out;
-
- if (write_buffer(fd, compressed, size) < 0)
- die("unable to write sha1 file");
close_sha1_file(fd);
- free(compressed);
if (mtime) {
struct utimbuf utb;
@@ -2434,6 +2439,8 @@ static int index_mem(unsigned char *sha1, void *buf, size_t size,
return ret;
}
+#define SMALL_FILE_SIZE (32*1024)
+
int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
enum object_type type, const char *path)
{
@@ -2448,6 +2455,14 @@ int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object,
else
ret = -1;
strbuf_release(&sbuf);
+ } else if (size <= SMALL_FILE_SIZE) {
+ char *buf = xmalloc(size);
+ if (size == read_in_full(fd, buf, size))
+ ret = index_mem(sha1, buf, size, write_object, type,
+ path);
+ else
+ ret = error("short read %s", strerror(errno));
+ free(buf);
} else if (size) {
void *buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
ret = index_mem(sha1, buf, size, write_object, type, path);
diff --git a/sha1_name.c b/sha1_name.c
index 77299257b..bf9241783 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -280,8 +280,7 @@ int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)
*ref = xstrdup(r);
if (!warn_ambiguous_refs)
break;
- } else if ((flag & REF_ISSYMREF) &&
- (len != 4 || strcmp(str, "HEAD")))
+ } else if ((flag & REF_ISSYMREF) && strcmp(fullref, "HEAD"))
warning("ignoring dangling symref %s.", fullref);
}
free(last_branch);
@@ -993,13 +992,15 @@ static void diagnose_invalid_index_path(int stage,
pos = cache_name_pos(filename, namelen);
if (pos < 0)
pos = -pos - 1;
- ce = active_cache[pos];
- if (ce_namelen(ce) == namelen &&
- !memcmp(ce->name, filename, namelen))
- die("Path '%s' is in the index, but not at stage %d.\n"
- "Did you mean ':%d:%s'?",
- filename, stage,
- ce_stage(ce), filename);
+ if (pos < active_nr) {
+ ce = active_cache[pos];
+ if (ce_namelen(ce) == namelen &&
+ !memcmp(ce->name, filename, namelen))
+ die("Path '%s' is in the index, but not at stage %d.\n"
+ "Did you mean ':%d:%s'?",
+ filename, stage,
+ ce_stage(ce), filename);
+ }
/* Confusion between relative and absolute filenames? */
fullnamelen = namelen + strlen(prefix);
@@ -1009,13 +1010,15 @@ static void diagnose_invalid_index_path(int stage,
pos = cache_name_pos(fullname, fullnamelen);
if (pos < 0)
pos = -pos - 1;
- ce = active_cache[pos];
- if (ce_namelen(ce) == fullnamelen &&
- !memcmp(ce->name, fullname, fullnamelen))
- die("Path '%s' is in the index, but not '%s'.\n"
- "Did you mean ':%d:%s'?",
- fullname, filename,
- ce_stage(ce), fullname);
+ if (pos < active_nr) {
+ ce = active_cache[pos];
+ if (ce_namelen(ce) == fullnamelen &&
+ !memcmp(ce->name, fullname, fullnamelen))
+ die("Path '%s' is in the index, but not '%s'.\n"
+ "Did you mean ':%d:%s'?",
+ fullname, filename,
+ ce_stage(ce), fullname);
+ }
if (!lstat(filename, &st))
die("Path '%s' exists on disk, but not in the index.", filename);
diff --git a/submodule.c b/submodule.c
index 7d70c4f7b..5d286e409 100644
--- a/submodule.c
+++ b/submodule.c
@@ -123,16 +123,19 @@ void show_submodule_summary(FILE *f, const char *path,
int is_submodule_modified(const char *path)
{
- int len;
+ int len, i;
struct child_process cp;
const char *argv[] = {
"status",
"--porcelain",
NULL,
};
- char *env[4];
+ const char *env[LOCAL_REPO_ENV_SIZE + 3];
struct strbuf buf = STRBUF_INIT;
+ for (i = 0; i < LOCAL_REPO_ENV_SIZE; i++)
+ env[i] = local_repo_env[i];
+
strbuf_addf(&buf, "%s/.git/", path);
if (!is_directory(buf.buf)) {
strbuf_release(&buf);
@@ -143,16 +146,14 @@ int is_submodule_modified(const char *path)
strbuf_reset(&buf);
strbuf_addf(&buf, "GIT_WORK_TREE=%s", path);
- env[0] = strbuf_detach(&buf, NULL);
+ env[i++] = strbuf_detach(&buf, NULL);
strbuf_addf(&buf, "GIT_DIR=%s/.git", path);
- env[1] = strbuf_detach(&buf, NULL);
- strbuf_addf(&buf, "GIT_INDEX_FILE");
- env[2] = strbuf_detach(&buf, NULL);
- env[3] = NULL;
+ env[i++] = strbuf_detach(&buf, NULL);
+ env[i] = NULL;
memset(&cp, 0, sizeof(cp));
cp.argv = argv;
- cp.env = (const char *const *)env;
+ cp.env = env;
cp.git_cmd = 1;
cp.no_stdin = 1;
cp.out = -1;
@@ -165,9 +166,8 @@ int is_submodule_modified(const char *path)
if (finish_command(&cp))
die("git status --porcelain failed");
- free(env[0]);
- free(env[1]);
- free(env[2]);
+ for (i = LOCAL_REPO_ENV_SIZE; env[i]; i++)
+ free((char *)env[i]);
strbuf_release(&buf);
return len != 0;
}
diff --git a/t/Makefile b/t/Makefile
index bd09390d3..25c559bb4 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -27,6 +27,8 @@ pre-clean:
clean:
$(RM) -r 'trash directory'.* test-results
+ $(RM) t????/cvsroot/CVSROOT/?*
+ $(RM) -r valgrind/bin
aggregate-results-and-cleanup: $(T)
$(MAKE) aggregate-results
diff --git a/t/lib-patch-mode.sh b/t/lib-patch-mode.sh
index 75a3ee283..ce36f34d0 100755..100644
--- a/t/lib-patch-mode.sh
+++ b/t/lib-patch-mode.sh
@@ -1,3 +1,5 @@
+: included from t2016 and others
+
. ./test-lib.sh
if ! test_have_prereq PERL; then
diff --git a/t/t1304-default-acl.sh b/t/t1304-default-acl.sh
new file mode 100755
index 000000000..cc30be4a6
--- /dev/null
+++ b/t/t1304-default-acl.sh
@@ -0,0 +1,67 @@
+#!/bin/sh
+#
+# Copyright (c) 2010 Matthieu Moy
+#
+
+test_description='Test repository with default ACL'
+
+# Create the test repo with restrictive umask
+# => this must come before . ./test-lib.sh
+umask 077
+
+. ./test-lib.sh
+
+# We need an arbitrary other user give permission to using ACLs. root
+# is a good candidate: exists on all unices, and it has permission
+# anyway, so we don't create a security hole running the testsuite.
+
+if ! setfacl -m u:root:rwx .; then
+ say "Skipping ACL tests: unable to use setfacl"
+ test_done
+fi
+
+modebits () {
+ ls -l "$1" | sed -e 's|^\(..........\).*|\1|'
+}
+
+check_perms_and_acl () {
+ actual=$(modebits "$1") &&
+ case "$actual" in
+ -r--r-----*)
+ : happy
+ ;;
+ *)
+ echo "Got permission '$actual', expected '-r--r-----'"
+ false
+ ;;
+ esac &&
+ getfacl "$1" > actual &&
+ grep -q "user:root:rwx" actual &&
+ grep -q "user:${LOGNAME}:rwx" actual &&
+ grep -q "mask::r--" actual &&
+ grep -q "group::---" actual || false
+}
+
+dirs_to_set="./ .git/ .git/objects/ .git/objects/pack/"
+
+test_expect_success 'Setup test repo' '
+ setfacl -m u:root:rwx $dirs_to_set &&
+ setfacl -d -m u:"$LOGNAME":rwx $dirs_to_set &&
+ setfacl -d -m u:root:rwx $dirs_to_set &&
+
+ touch file.txt &&
+ git add file.txt &&
+ git commit -m "init"
+'
+
+test_expect_success 'Objects creation does not break ACLs with restrictive umask' '
+ # SHA1 for empty blob
+ check_perms_and_acl .git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
+'
+
+test_expect_success 'git gc does not break ACLs with restrictive umask' '
+ git gc &&
+ check_perms_and_acl .git/objects/pack/*.pack
+'
+
+test_done
diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh
index 80af6b9b7..25046c420 100755
--- a/t/t1410-reflog.sh
+++ b/t/t1410-reflog.sh
@@ -214,4 +214,45 @@ test_expect_success 'delete' '
'
+test_expect_success 'rewind2' '
+
+ test_tick && git reset --hard HEAD~2 &&
+ loglen=$(wc -l <.git/logs/refs/heads/master) &&
+ test $loglen = 4
+
+'
+
+test_expect_success '--expire=never' '
+
+ git reflog expire --verbose \
+ --expire=never \
+ --expire-unreachable=never \
+ --all &&
+ loglen=$(wc -l <.git/logs/refs/heads/master) &&
+ test $loglen = 4
+
+'
+
+test_expect_success 'gc.reflogexpire=never' '
+
+ git config gc.reflogexpire never &&
+ git config gc.reflogexpireunreachable never &&
+ git reflog expire --verbose --all &&
+ loglen=$(wc -l <.git/logs/refs/heads/master) &&
+ test $loglen = 4
+'
+
+test_expect_success 'gc.reflogexpire=false' '
+
+ git config gc.reflogexpire false &&
+ git config gc.reflogexpireunreachable false &&
+ git reflog expire --verbose --all &&
+ loglen=$(wc -l <.git/logs/refs/heads/master) &&
+ test $loglen = 4 &&
+
+ git config --unset gc.reflogexpire &&
+ git config --unset gc.reflogexpireunreachable
+
+'
+
test_done
diff --git a/t/t1411-reflog-show.sh b/t/t1411-reflog-show.sh
index c18ed8edf..ba25ff354 100755
--- a/t/t1411-reflog-show.sh
+++ b/t/t1411-reflog-show.sh
@@ -64,4 +64,13 @@ test_expect_success 'using --date= shows reflog date (oneline)' '
test_cmp expect actual
'
+: >expect
+test_expect_success 'empty reflog file' '
+ git branch empty &&
+ : >.git/logs/refs/heads/empty &&
+
+ git log -g empty >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index a22632f48..49cae3ed5 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -66,12 +66,12 @@ tagger T A Gger <tagger@example.com> 1234567890 -0000
This is an invalid tag.
EOF
-test_expect_failure 'tag pointing to nonexistent' '
- tag=$(git hash-object -w --stdin < invalid-tag) &&
+test_expect_success 'tag pointing to nonexistent' '
+ tag=$(git hash-object -t tag -w --stdin < invalid-tag) &&
echo $tag > .git/refs/tags/invalid &&
- git fsck --tags 2>out &&
+ test_must_fail git fsck --tags >out &&
cat out &&
- grep "could not load tagged object" out &&
+ grep "broken link" out &&
rm .git/refs/tags/invalid
'
@@ -84,12 +84,12 @@ tagger T A Gger <tagger@example.com> 1234567890 -0000
This is an invalid tag.
EOF
-test_expect_failure 'tag pointing to something else than its type' '
- tag=$(git hash-object -w --stdin < wrong-tag) &&
+test_expect_success 'tag pointing to something else than its type' '
+ tag=$(git hash-object -t tag -w --stdin < wrong-tag) &&
echo $tag > .git/refs/tags/wrong &&
- git fsck --tags 2>out &&
+ test_must_fail git fsck --tags 2>out &&
cat out &&
- grep "some sane error message" out &&
+ grep "error in tag.*broken links" out &&
rm .git/refs/tags/wrong
'
diff --git a/t/t2016-checkout-patch.sh b/t/t2016-checkout-patch.sh
index 4d1c2e9e0..2144184d7 100755
--- a/t/t2016-checkout-patch.sh
+++ b/t/t2016-checkout-patch.sh
@@ -66,6 +66,14 @@ test_expect_success 'git checkout -p HEAD^' '
verify_state dir/foo parent parent
'
+test_expect_success 'git checkout -p handles deletion' '
+ set_state dir/foo work index &&
+ rm dir/foo &&
+ (echo n; echo y) | git checkout -p &&
+ verify_saved_state bar &&
+ verify_state dir/foo index index
+'
+
# The idea in the rest is that bar sorts first, so we always say 'y'
# first and if the path limiter fails it'll apply to bar instead of
# dir/foo. There's always an extra 'n' to reject edits to dir/foo in
diff --git a/t/t3301-notes.sh b/t/t3301-notes.sh
index 5d9604b81..714626d2d 100755
--- a/t/t3301-notes.sh
+++ b/t/t3301-notes.sh
@@ -8,6 +8,7 @@ test_description='Test commit notes'
. ./test-lib.sh
cat > fake_editor.sh << \EOF
+#!/bin/sh
echo "$MSG" > "$1"
echo "$MSG" >& 2
EOF
diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh
index 76b1bb454..0aaf0ad84 100755
--- a/t/t3600-rm.sh
+++ b/t/t3600-rm.sh
@@ -271,4 +271,12 @@ test_expect_success 'choking "git rm" should not let it die with cruft' '
test "$status" != 0
'
+test_expect_success 'rm removes subdirectories recursively' '
+ mkdir -p dir/subdir/subsubdir &&
+ echo content >dir/subdir/subsubdir/file &&
+ git add dir/subdir/subsubdir/file &&
+ git rm -f dir/subdir/subsubdir/file &&
+ ! test -d dir
+'
+
test_done
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 5514f74b3..476e5ec03 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -194,6 +194,15 @@ test_expect_success 'pop -q is quiet' '
test ! -s output.out
'
+test_expect_success 'pop -q --index works and is quiet' '
+ echo foo > file &&
+ git add file &&
+ git stash save --quiet &&
+ git stash pop -q --index > output.out 2>&1 &&
+ test foo = "$(git show :file)" &&
+ test ! -s output.out
+'
+
test_expect_success 'drop -q is quiet' '
git stash &&
git stash drop -q > output.out 2>&1 &&
diff --git a/t/t4017-diff-retval.sh b/t/t4017-diff-retval.sh
index 60dd2014d..0391a5827 100755
--- a/t/t4017-diff-retval.sh
+++ b/t/t4017-diff-retval.sh
@@ -5,6 +5,9 @@ test_description='Return value of diffs'
. ./test-lib.sh
test_expect_success 'setup' '
+ echo "1 " >a &&
+ git add . &&
+ git commit -m zeroth &&
echo 1 >a &&
git add . &&
git commit -m first &&
@@ -13,6 +16,18 @@ test_expect_success 'setup' '
git commit -a -m second
'
+test_expect_success 'git diff --quiet -w HEAD^^ HEAD^' '
+ git diff --quiet -w HEAD^^ HEAD^
+'
+
+test_expect_success 'git diff --quiet HEAD^^ HEAD^' '
+ test_must_fail git diff --quiet HEAD^^ HEAD^
+'
+
+test_expect_success 'git diff --quiet -w HEAD^ HEAD' '
+ test_must_fail git diff --quiet -w HEAD^ HEAD
+'
+
test_expect_success 'git diff-tree HEAD^ HEAD' '
git diff-tree --exit-code HEAD^ HEAD
test $? = 1
diff --git a/t/t5100/msg0015 b/t/t5100/msg0015
index 957723868..4abb3d5c6 100644
--- a/t/t5100/msg0015
+++ b/t/t5100/msg0015
@@ -1,2 +1,2 @@
-- a list
+ - a list
- of stuff
diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh
index 3c6687abe..e2ed13dba 100755
--- a/t/t5304-prune.sh
+++ b/t/t5304-prune.sh
@@ -148,6 +148,38 @@ test_expect_success 'gc --prune=<date>' '
'
+test_expect_success 'gc --prune=never' '
+
+ add_blob &&
+ git gc --prune=never &&
+ test -f $BLOB_FILE &&
+ git gc --prune=now &&
+ test ! -f $BLOB_FILE
+
+'
+
+test_expect_success 'gc respects gc.pruneExpire=never' '
+
+ git config gc.pruneExpire never &&
+ add_blob &&
+ git gc &&
+ test -f $BLOB_FILE &&
+ git config gc.pruneExpire now &&
+ git gc &&
+ test ! -f $BLOB_FILE
+
+'
+
+test_expect_success 'prune --expire=never' '
+
+ add_blob &&
+ git prune --expire=never &&
+ test -f $BLOB_FILE &&
+ git prune &&
+ test ! -f $BLOB_FILE
+
+'
+
test_expect_success 'gc: prune old objects after local clone' '
add_blob &&
test-chmtime =-$((2*$week+1)) $BLOB_FILE &&
diff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh
index 325714e52..17bcb0b04 100755
--- a/t/t5401-update-hooks.sh
+++ b/t/t5401-update-hooks.sh
@@ -17,23 +17,22 @@ test_expect_success setup '
commit1=$(echo modify | git commit-tree $tree1 -p $commit0) &&
git update-ref refs/heads/master $commit0 &&
git update-ref refs/heads/tofail $commit1 &&
- git clone ./. victim &&
- GIT_DIR=victim/.git git config receive.denyCurrentBranch warn &&
- GIT_DIR=victim/.git git update-ref refs/heads/tofail $commit1 &&
+ git clone --bare ./. victim.git &&
+ GIT_DIR=victim.git git update-ref refs/heads/tofail $commit1 &&
git update-ref refs/heads/master $commit1 &&
git update-ref refs/heads/tofail $commit0
'
-cat >victim/.git/hooks/pre-receive <<'EOF'
+cat >victim.git/hooks/pre-receive <<'EOF'
#!/bin/sh
printf %s "$@" >>$GIT_DIR/pre-receive.args
cat - >$GIT_DIR/pre-receive.stdin
echo STDOUT pre-receive
echo STDERR pre-receive >&2
EOF
-chmod u+x victim/.git/hooks/pre-receive
+chmod u+x victim.git/hooks/pre-receive
-cat >victim/.git/hooks/update <<'EOF'
+cat >victim.git/hooks/update <<'EOF'
#!/bin/sh
echo "$@" >>$GIT_DIR/update.args
read x; printf %s "$x" >$GIT_DIR/update.stdin
@@ -41,77 +40,77 @@ echo STDOUT update $1
echo STDERR update $1 >&2
test "$1" = refs/heads/master || exit
EOF
-chmod u+x victim/.git/hooks/update
+chmod u+x victim.git/hooks/update
-cat >victim/.git/hooks/post-receive <<'EOF'
+cat >victim.git/hooks/post-receive <<'EOF'
#!/bin/sh
printf %s "$@" >>$GIT_DIR/post-receive.args
cat - >$GIT_DIR/post-receive.stdin
echo STDOUT post-receive
echo STDERR post-receive >&2
EOF
-chmod u+x victim/.git/hooks/post-receive
+chmod u+x victim.git/hooks/post-receive
-cat >victim/.git/hooks/post-update <<'EOF'
+cat >victim.git/hooks/post-update <<'EOF'
#!/bin/sh
echo "$@" >>$GIT_DIR/post-update.args
read x; printf %s "$x" >$GIT_DIR/post-update.stdin
echo STDOUT post-update
echo STDERR post-update >&2
EOF
-chmod u+x victim/.git/hooks/post-update
+chmod u+x victim.git/hooks/post-update
test_expect_success push '
- test_must_fail git send-pack --force ./victim/.git \
+ test_must_fail git send-pack --force ./victim.git \
master tofail >send.out 2>send.err
'
test_expect_success 'updated as expected' '
- test $(GIT_DIR=victim/.git git rev-parse master) = $commit1 &&
- test $(GIT_DIR=victim/.git git rev-parse tofail) = $commit1
+ test $(GIT_DIR=victim.git git rev-parse master) = $commit1 &&
+ test $(GIT_DIR=victim.git git rev-parse tofail) = $commit1
'
test_expect_success 'hooks ran' '
- test -f victim/.git/pre-receive.args &&
- test -f victim/.git/pre-receive.stdin &&
- test -f victim/.git/update.args &&
- test -f victim/.git/update.stdin &&
- test -f victim/.git/post-receive.args &&
- test -f victim/.git/post-receive.stdin &&
- test -f victim/.git/post-update.args &&
- test -f victim/.git/post-update.stdin
+ test -f victim.git/pre-receive.args &&
+ test -f victim.git/pre-receive.stdin &&
+ test -f victim.git/update.args &&
+ test -f victim.git/update.stdin &&
+ test -f victim.git/post-receive.args &&
+ test -f victim.git/post-receive.stdin &&
+ test -f victim.git/post-update.args &&
+ test -f victim.git/post-update.stdin
'
test_expect_success 'pre-receive hook input' '
(echo $commit0 $commit1 refs/heads/master;
echo $commit1 $commit0 refs/heads/tofail
- ) | test_cmp - victim/.git/pre-receive.stdin
+ ) | test_cmp - victim.git/pre-receive.stdin
'
test_expect_success 'update hook arguments' '
(echo refs/heads/master $commit0 $commit1;
echo refs/heads/tofail $commit1 $commit0
- ) | test_cmp - victim/.git/update.args
+ ) | test_cmp - victim.git/update.args
'
test_expect_success 'post-receive hook input' '
echo $commit0 $commit1 refs/heads/master |
- test_cmp - victim/.git/post-receive.stdin
+ test_cmp - victim.git/post-receive.stdin
'
test_expect_success 'post-update hook arguments' '
echo refs/heads/master |
- test_cmp - victim/.git/post-update.args
+ test_cmp - victim.git/post-update.args
'
test_expect_success 'all hook stdin is /dev/null' '
- ! test -s victim/.git/update.stdin &&
- ! test -s victim/.git/post-update.stdin
+ ! test -s victim.git/update.stdin &&
+ ! test -s victim.git/post-update.stdin
'
test_expect_success 'all *-receive hook args are empty' '
- ! test -s victim/.git/pre-receive.args &&
- ! test -s victim/.git/post-receive.args
+ ! test -s victim.git/pre-receive.args &&
+ ! test -s victim.git/post-receive.args
'
test_expect_success 'send-pack produced no output' '
@@ -119,20 +118,21 @@ test_expect_success 'send-pack produced no output' '
'
cat <<EOF >expect
-STDOUT pre-receive
-STDERR pre-receive
-STDOUT update refs/heads/master
-STDERR update refs/heads/master
-STDOUT update refs/heads/tofail
-STDERR update refs/heads/tofail
-STDOUT post-receive
-STDERR post-receive
-STDOUT post-update
-STDERR post-update
+remote: STDOUT pre-receive
+remote: STDERR pre-receive
+remote: STDOUT update refs/heads/master
+remote: STDERR update refs/heads/master
+remote: STDOUT update refs/heads/tofail
+remote: STDERR update refs/heads/tofail
+remote: error: hook declined to update refs/heads/tofail
+remote: STDOUT post-receive
+remote: STDERR post-receive
+remote: STDOUT post-update
+remote: STDERR post-update
EOF
test_expect_success 'send-pack stderr contains hook messages' '
- grep ^STD send.err >actual &&
- test_cmp - actual <expect
+ grep ^remote: send.err | sed "s/ *\$//" >actual &&
+ test_cmp expect actual
'
test_done
diff --git a/t/t5521-pull-options.sh b/t/t5521-pull-options.sh
index 83e2e8ab8..1b06691bb 100755
--- a/t/t5521-pull-options.sh
+++ b/t/t5521-pull-options.sh
@@ -4,8 +4,6 @@ test_description='pull options'
. ./test-lib.sh
-D=`pwd`
-
test_expect_success 'setup' '
mkdir parent &&
(cd parent && git init &&
@@ -13,48 +11,83 @@ test_expect_success 'setup' '
git commit -m one)
'
-cd "$D"
-
test_expect_success 'git pull -q' '
mkdir clonedq &&
- cd clonedq &&
- git pull -q "$D/parent" >out 2>err &&
- test ! -s out
+ (cd clonedq && git init &&
+ git pull -q "../parent" >out 2>err &&
+ test ! -s err &&
+ test ! -s out)
'
-cd "$D"
-
test_expect_success 'git pull' '
mkdir cloned &&
- cd cloned &&
- git pull "$D/parent" >out 2>err &&
- test -s out
+ (cd cloned && git init &&
+ git pull "../parent" >out 2>err &&
+ test -s err &&
+ test ! -s out)
'
-cd "$D"
test_expect_success 'git pull -v' '
mkdir clonedv &&
- cd clonedv &&
- git pull -v "$D/parent" >out 2>err &&
- test -s out
+ (cd clonedv && git init &&
+ git pull -v "../parent" >out 2>err &&
+ test -s err &&
+ test ! -s out)
'
-cd "$D"
-
test_expect_success 'git pull -v -q' '
mkdir clonedvq &&
- cd clonedvq &&
- git pull -v -q "$D/parent" >out 2>err &&
- test ! -s out
+ (cd clonedvq && git init &&
+ git pull -v -q "../parent" >out 2>err &&
+ test ! -s out &&
+ test ! -s err)
'
-cd "$D"
-
test_expect_success 'git pull -q -v' '
mkdir clonedqv &&
- cd clonedqv &&
- git pull -q -v "$D/parent" >out 2>err &&
- test -s out
+ (cd clonedqv && git init &&
+ git pull -q -v "../parent" >out 2>err &&
+ test ! -s out &&
+ test -s err)
+'
+
+test_expect_success 'git pull --force' '
+ mkdir clonedoldstyle &&
+ (cd clonedoldstyle && git init &&
+ cat >>.git/config <<-\EOF &&
+ [remote "one"]
+ url = ../parent
+ fetch = refs/heads/master:refs/heads/mirror
+ [remote "two"]
+ url = ../parent
+ fetch = refs/heads/master:refs/heads/origin
+ [branch "master"]
+ remote = two
+ merge = refs/heads/master
+ EOF
+ git pull two &&
+ test_commit A &&
+ git branch -f origin &&
+ git pull --all --force
+ )
+'
+
+test_expect_success 'git pull --all' '
+ mkdir clonedmulti &&
+ (cd clonedmulti && git init &&
+ cat >>.git/config <<-\EOF &&
+ [remote "one"]
+ url = ../parent
+ fetch = refs/heads/*:refs/remotes/one/*
+ [remote "two"]
+ url = ../parent
+ fetch = refs/heads/*:refs/remotes/two/*
+ [branch "master"]
+ remote = one
+ merge = refs/heads/master
+ EOF
+ git pull --all
+ )
'
test_done
diff --git a/t/t6000lib.sh b/t/t6000lib.sh
index f55627b64..985d517a1 100755..100644
--- a/t/t6000lib.sh
+++ b/t/t6000lib.sh
@@ -1,3 +1,5 @@
+: included from 6002 and others
+
[ -d .git/refs/tags ] || mkdir -p .git/refs/tags
:> sed.script
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index c51865fdb..3b042aacd 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -567,6 +567,11 @@ test_expect_success 'skipping away from skipped commit' '
test "$para3" = "$PARA_HASH3"
'
+test_expect_success 'erroring out when using bad path parameters' '
+ test_must_fail git bisect start $PARA_HASH7 $HASH1 -- foobar 2> error.txt &&
+ grep "bad path parameters" error.txt
+'
+
#
#
test_done
diff --git a/t/t7002-grep.sh b/t/t7002-grep.sh
index 7144f815c..af63d6ec6 100755
--- a/t/t7002-grep.sh
+++ b/t/t7002-grep.sh
@@ -353,7 +353,7 @@ test_expect_success 'log grep (4)' '
'
test_expect_success 'log grep (5)' '
- git log --author=Thor -F --grep=Thu --pretty=tformat:%s >actual &&
+ git log --author=Thor -F --pretty=tformat:%s >actual &&
( echo third ; echo initial ) >expect &&
test_cmp expect actual
'
@@ -364,6 +364,14 @@ test_expect_success 'log grep (6)' '
test_cmp expect actual
'
+test_expect_success 'log --grep --author implicitly uses all-match' '
+ # grep matches initial and second but not third
+ # author matches only initial and third
+ git log --author="A U Thor" --grep=s --grep=l --format=%s >actual &&
+ echo initial >expect &&
+ test_cmp expect actual
+'
+
test_expect_success 'grep with CE_VALID file' '
git update-index --assume-unchanged t/t &&
rm t/t &&
@@ -434,4 +442,37 @@ test_expect_success 'grep -Fi' '
test_cmp expected actual
'
+test_expect_success 'setup double-dash tests' '
+cat >double-dash <<EOF &&
+--
+->
+other
+EOF
+git add double-dash
+'
+
+cat >expected <<EOF
+double-dash:->
+EOF
+test_expect_success 'grep -- pattern' '
+ git grep -- "->" >actual &&
+ test_cmp expected actual
+'
+test_expect_success 'grep -- pattern -- pathspec' '
+ git grep -- "->" -- double-dash >actual &&
+ test_cmp expected actual
+'
+test_expect_success 'grep -e pattern -- path' '
+ git grep -e "->" -- double-dash >actual &&
+ test_cmp expected actual
+'
+
+cat >expected <<EOF
+double-dash:--
+EOF
+test_expect_success 'grep -e -- -- path' '
+ git grep -e -- -- double-dash >actual &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t7006-pager.sh b/t/t7006-pager.sh
new file mode 100755
index 000000000..d9202d5af
--- /dev/null
+++ b/t/t7006-pager.sh
@@ -0,0 +1,176 @@
+#!/bin/sh
+
+test_description='Test automatic use of a pager.'
+
+. ./test-lib.sh
+
+rm -f stdout_is_tty
+test_expect_success 'set up terminal for tests' '
+ if test -t 1
+ then
+ : > stdout_is_tty
+ elif
+ test_have_prereq PERL &&
+ "$PERL_PATH" "$TEST_DIRECTORY"/t7006/test-terminal.perl \
+ sh -c "test -t 1"
+ then
+ : > test_terminal_works
+ fi
+'
+
+if test -e stdout_is_tty
+then
+ test_terminal() { "$@"; }
+ test_set_prereq TTY
+elif test -e test_terminal_works
+then
+ test_terminal() {
+ "$PERL_PATH" "$TEST_DIRECTORY"/t7006/test-terminal.perl "$@"
+ }
+ test_set_prereq TTY
+else
+ say no usable terminal, so skipping some tests
+fi
+
+unset GIT_PAGER GIT_PAGER_IN_USE
+git config --unset core.pager
+PAGER='cat > paginated.out'
+export PAGER
+
+test_expect_success 'setup' '
+ test_commit initial
+'
+
+rm -f paginated.out
+test_expect_success TTY 'some commands use a pager' '
+ test_terminal git log &&
+ test -e paginated.out
+'
+
+rm -f paginated.out
+test_expect_success TTY 'some commands do not use a pager' '
+ test_terminal git rev-list HEAD &&
+ ! test -e paginated.out
+'
+
+rm -f paginated.out
+test_expect_success 'no pager when stdout is a pipe' '
+ 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 &&
+ ! test -e paginated.out
+'
+
+rm -f paginated.out
+test_expect_success TTY 'git --paginate rev-list uses a pager' '
+ 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' '
+ git --paginate log | cat &&
+ ! test -e paginated.out
+'
+
+rm -f paginated.out
+test_expect_success TTY 'no pager with --no-pager' '
+ test_terminal git --no-pager log &&
+ ! test -e paginated.out
+'
+
+# 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
+}
+
+rm -f colorful.log colorless.log
+test_expect_success 'tests can detect color' '
+ 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 &&
+ ! 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 &&
+ 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 &&
+ colorful colorful.log
+'
+
+unset PAGER GIT_PAGER
+git config --unset core.pager
+test_expect_success 'determine default pager' '
+ less=$(git var GIT_PAGER) &&
+ test -n "$less"
+'
+
+if expr "$less" : '^[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
+ EOF
+ chmod +x $less &&
+ PATH=.:$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" &&
+ 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' '
+ PAGER=wc &&
+ export PAGER &&
+ 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' '
+ git config core.pager wc &&
+ GIT_PAGER="wc > GIT_PAGER_used" &&
+ export GIT_PAGER &&
+ test_terminal git log &&
+ test -e GIT_PAGER_used
+'
+
+test_done
diff --git a/t/t7006/test-terminal.perl b/t/t7006/test-terminal.perl
new file mode 100755
index 000000000..73ff80937
--- /dev/null
+++ b/t/t7006/test-terminal.perl
@@ -0,0 +1,58 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use IO::Pty;
+use File::Copy;
+
+# Run @$argv in the background with stdout redirected to $out.
+sub start_child {
+ my ($argv, $out) = @_;
+ my $pid = fork;
+ if (not defined $pid) {
+ die "fork failed: $!"
+ } elsif ($pid == 0) {
+ open STDOUT, ">&", $out;
+ close $out;
+ exec(@$argv) or die "cannot exec '$argv->[0]': $!"
+ }
+ return $pid;
+}
+
+# Wait for $pid to finish.
+sub finish_child {
+ # Simplified from wait_or_whine() in run-command.c.
+ my ($pid) = @_;
+
+ my $waiting = waitpid($pid, 0);
+ if ($waiting < 0) {
+ die "waitpid failed: $!";
+ } elsif ($? & 127) {
+ my $code = $? & 127;
+ warn "died of signal $code";
+ return $code - 128;
+ } else {
+ return $? >> 8;
+ }
+}
+
+sub xsendfile {
+ my ($out, $in) = @_;
+
+ # Note: the real sendfile() cannot read from a terminal.
+
+ # It is unspecified by POSIX whether reads
+ # from a disconnected terminal will return
+ # EIO (as in AIX 4.x, IRIX, and Linux) or
+ # end-of-file. Either is fine.
+ copy($in, $out, 4096) or $!{EIO} or die "cannot copy from child: $!";
+}
+
+if ($#ARGV < 1) {
+ die "usage: test-terminal program args";
+}
+my $master = new IO::Pty;
+my $slave = $master->slave;
+my $pid = start_child(\@ARGV, $slave);
+close $slave;
+xsendfile(\*STDOUT, $master);
+exit(finish_child($pid));
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index 6442f710b..d20ed61b4 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -166,19 +166,31 @@ test_expect_success 'checkout -m with merge conflict' '
! test -s current
'
-test_expect_success 'checkout to detach HEAD' '
+test_expect_success 'checkout to detach HEAD (with advice declined)' '
+ git config advice.detachedHead false &&
git checkout -f renamer && git clean -f &&
git checkout renamer^ 2>messages &&
- (cat >messages.expect <<EOF
-Note: moving to '\''renamer^'\'' which isn'\''t a local branch
-If you want to create a new branch from this checkout, you may do so
-(now or later) by using -b with the checkout command again. Example:
- git checkout -b <new_branch_name>
-HEAD is now at 7329388... Initial A one, A two
-EOF
-) &&
- test_cmp messages.expect messages &&
+ grep "HEAD is now at 7329388" messages &&
+ test 1 -eq $(wc -l <messages) &&
+ H=$(git rev-parse --verify HEAD) &&
+ M=$(git show-ref -s --verify refs/heads/master) &&
+ test "z$H" = "z$M" &&
+ if git symbolic-ref HEAD >/dev/null 2>&1
+ then
+ echo "OOPS, HEAD is still symbolic???"
+ false
+ else
+ : happy
+ fi
+'
+
+test_expect_success 'checkout to detach HEAD' '
+ git config advice.detachedHead true &&
+ git checkout -f renamer && git clean -f &&
+ git checkout renamer^ 2>messages &&
+ grep "HEAD is now at 7329388" messages &&
+ test 1 -lt $(wc -l <messages) &&
H=$(git rev-parse --verify HEAD) &&
M=$(git show-ref -s --verify refs/heads/master) &&
test "z$H" = "z$M" &&
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index 8e2449d24..1382a8e58 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -28,6 +28,8 @@ test_expect_success 'setup a submodule tree' '
git commit -m upstream
git clone . super &&
git clone super submodule &&
+ git clone super rebasing &&
+ git clone super merging &&
(cd super &&
git submodule add ../submodule submodule &&
test_tick &&
@@ -45,6 +47,16 @@ test_expect_success 'setup a submodule tree' '
) &&
git add submodule &&
git commit -m "submodule update"
+ ) &&
+ (cd super &&
+ git submodule add ../rebasing rebasing &&
+ test_tick &&
+ git commit -m "rebasing"
+ ) &&
+ (cd super &&
+ git submodule add ../merging merging &&
+ test_tick &&
+ git commit -m "rebasing"
)
'
@@ -177,21 +189,17 @@ test_expect_success 'submodule update - checkout in .git/config' '
test_expect_success 'submodule init picks up rebase' '
(cd super &&
- git config submodule.rebasing.url git://non-existing/git &&
- git config submodule.rebasing.path does-not-matter &&
- git config submodule.rebasing.update rebase &&
+ git config -f .gitmodules submodule.rebasing.update rebase &&
git submodule init rebasing &&
- test "rebase" = $(git config submodule.rebasing.update)
+ test "rebase" = "$(git config submodule.rebasing.update)"
)
'
test_expect_success 'submodule init picks up merge' '
(cd super &&
- git config submodule.merging.url git://non-existing/git &&
- git config submodule.merging.path does-not-matter &&
- git config submodule.merging.update merge &&
+ git config -f .gitmodules submodule.merging.update merge &&
git submodule init merging &&
- test "merge" = $(git config submodule.merging.update)
+ test "merge" = "$(git config submodule.merging.update)"
)
'
diff --git a/t/t8003-blame.sh b/t/t8003-blame.sh
index 3bbddd03c..230143cf3 100755
--- a/t/t8003-blame.sh
+++ b/t/t8003-blame.sh
@@ -11,7 +11,15 @@ test_expect_success setup '
echo B B B B B >two &&
echo C C C C C >tres &&
echo ABC >mouse &&
- git add one two tres mouse &&
+ for i in 1 2 3 4 5 6 7 8 9
+ do
+ echo $i
+ done >nine_lines &&
+ for i in 1 2 3 4 5 6 7 8 9 a
+ do
+ echo $i
+ done >ten_lines &&
+ git add one two tres mouse nine_lines ten_lines &&
test_tick &&
GIT_AUTHOR_NAME=Initial git commit -m Initial &&
@@ -167,4 +175,14 @@ test_expect_success 'blame -L with invalid end' '
grep "has only 2 lines" errors
'
+test_expect_success 'indent of line numbers, nine lines' '
+ git blame nine_lines >actual &&
+ test $(grep -c " " actual) = 0
+'
+
+test_expect_success 'indent of line numbers, ten lines' '
+ git blame ten_lines >actual &&
+ test $(grep -c " " actual) = 9
+'
+
test_done
diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh
index 4327eb8ba..daef2d6c2 100755
--- a/t/t9400-git-cvsserver-server.sh
+++ b/t/t9400-git-cvsserver-server.sh
@@ -226,7 +226,7 @@ test_expect_success 'gitcvs.ext.enabled = true' \
'GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled true &&
GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled false &&
GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 master >cvs.log 2>&1 &&
- diff -q cvswork cvswork2'
+ test_cmp cvswork cvswork2'
rm -fr cvswork2
test_expect_success 'gitcvs.ext.enabled = false' \
@@ -247,7 +247,7 @@ test_expect_success 'gitcvs.dbname' \
'GIT_DIR="$SERVERDIR" git config --bool gitcvs.ext.enabled true &&
GIT_DIR="$SERVERDIR" git config gitcvs.dbname %Ggitcvs.%a.%m.sqlite &&
GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 master >cvs.log 2>&1 &&
- diff -q cvswork cvswork2 &&
+ test_cmp cvswork cvswork2 &&
test -f "$SERVERDIR/gitcvs.ext.master.sqlite" &&
cmp "$SERVERDIR/gitcvs.master.sqlite" "$SERVERDIR/gitcvs.ext.master.sqlite"'
@@ -257,7 +257,7 @@ test_expect_success 'gitcvs.ext.dbname' \
GIT_DIR="$SERVERDIR" git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite &&
GIT_DIR="$SERVERDIR" git config gitcvs.dbname %Ggitcvs2.%a.%m.sqlite &&
GIT_CONFIG="$git_config" cvs -Q co -d cvswork2 master >cvs.log 2>&1 &&
- diff -q cvswork cvswork2 &&
+ test_cmp cvswork cvswork2 &&
test -f "$SERVERDIR/gitcvs1.ext.master.sqlite" &&
test ! -f "$SERVERDIR/gitcvs2.ext.master.sqlite" &&
cmp "$SERVERDIR/gitcvs.master.sqlite" "$SERVERDIR/gitcvs1.ext.master.sqlite"'
@@ -282,7 +282,7 @@ test_expect_success 'cvs update (create new file)' \
cd cvswork &&
GIT_CONFIG="$git_config" cvs -Q update &&
test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.1/" &&
- diff -q testfile1 ../testfile1'
+ test_cmp testfile1 ../testfile1'
cd "$WORKDIR"
test_expect_success 'cvs update (update existing file)' \
@@ -293,7 +293,7 @@ test_expect_success 'cvs update (update existing file)' \
cd cvswork &&
GIT_CONFIG="$git_config" cvs -Q update &&
test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.2/" &&
- diff -q testfile1 ../testfile1'
+ test_cmp testfile1 ../testfile1'
cd "$WORKDIR"
#TODO: cvsserver doesn't support update w/o -d
@@ -322,7 +322,7 @@ test_expect_success 'cvs update (subdirectories)' \
(for dir in A A/B A/B/C A/D E; do
filename="file_in_$(echo $dir|sed -e "s#/# #g")" &&
if test "$(echo $(grep -v ^D $dir/CVS/Entries|cut -d/ -f2,3,5))" = "$filename/1.1/" &&
- diff -q "$dir/$filename" "../$dir/$filename"; then
+ test_cmp "$dir/$filename" "../$dir/$filename"; then
:
else
echo >failure
@@ -349,7 +349,7 @@ test_expect_success 'cvs update (re-add deleted file)' \
cd cvswork &&
GIT_CONFIG="$git_config" cvs -Q update &&
test "$(echo $(grep testfile1 CVS/Entries|cut -d/ -f2,3,5))" = "testfile1/1.4/" &&
- diff -q testfile1 ../testfile1'
+ test_cmp testfile1 ../testfile1'
cd "$WORKDIR"
test_expect_success 'cvs update (merge)' \
@@ -366,7 +366,7 @@ test_expect_success 'cvs update (merge)' \
cd cvswork &&
GIT_CONFIG="$git_config" cvs -Q update &&
test "$(echo $(grep merge CVS/Entries|cut -d/ -f2,3,5))" = "merge/1.1/" &&
- diff -q merge ../merge &&
+ test_cmp merge ../merge &&
( echo Line 0; cat merge ) >merge.tmp &&
mv merge.tmp merge &&
cd "$WORKDIR" &&
@@ -377,7 +377,7 @@ test_expect_success 'cvs update (merge)' \
cd cvswork &&
sleep 1 && touch merge &&
GIT_CONFIG="$git_config" cvs -Q update &&
- diff -q merge ../expected'
+ test_cmp merge ../expected'
cd "$WORKDIR"
@@ -402,13 +402,13 @@ test_expect_success 'cvs update (conflict merge)' \
git push gitcvs.git >/dev/null &&
cd cvswork &&
GIT_CONFIG="$git_config" cvs -Q update &&
- diff -q merge ../expected.C'
+ test_cmp merge ../expected.C'
cd "$WORKDIR"
test_expect_success 'cvs update (-C)' \
'cd cvswork &&
GIT_CONFIG="$git_config" cvs -Q update -C &&
- diff -q merge ../merge'
+ test_cmp merge ../merge'
cd "$WORKDIR"
test_expect_success 'cvs update (merge no-op)' \
@@ -420,7 +420,7 @@ test_expect_success 'cvs update (merge no-op)' \
cd cvswork &&
sleep 1 && touch merge &&
GIT_CONFIG="$git_config" cvs -Q update &&
- diff -q merge ../merge'
+ test_cmp merge ../merge'
cd "$WORKDIR"
test_expect_success 'cvs update (-p)' '
diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh
index 2fc7fdb12..63b6b060e 100755
--- a/t/t9500-gitweb-standalone-no-errors.sh
+++ b/t/t9500-gitweb-standalone-no-errors.sh
@@ -591,14 +591,22 @@ test_debug 'cat gitweb.log'
# ----------------------------------------------------------------------
# gitweb config and repo config
-cat >>gitweb_config.perl <<EOF
-
-\$feature{'blame'}{'override'} = 1;
-\$feature{'snapshot'}{'override'} = 1;
-\$feature{'avatar'}{'override'} = 1;
+cat >>gitweb_config.perl <<\EOF
+
+# turn on override for each overridable feature
+foreach my $key (keys %feature) {
+ if ($feature{$key}{'sub'}) {
+ $feature{$key}{'override'} = 1;
+ }
+}
EOF
test_expect_success \
+ 'config override: projects list (implicit)' \
+ 'gitweb_run'
+test_debug 'cat gitweb.log'
+
+test_expect_success \
'config override: tree view, features not overridden in repo config' \
'gitweb_run "p=.git;a=tree"'
test_debug 'cat gitweb.log'
diff --git a/t/test-lib.sh b/t/test-lib.sh
index afd3053f9..a0e396a95 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -65,6 +65,8 @@ GIT_TEST_CMP=${GIT_TEST_CMP:-diff -u}
# CDPATH into the environment
unset CDPATH
+unset GREP_OPTIONS
+
case $(echo $GIT_TRACE |tr "[A-Z]" "[a-z]") in
1|2|true)
echo "* warning: Some tests will not work if GIT_TRACE" \
diff --git a/test-chmtime.c b/test-chmtime.c
index fe476cb61..92713d16d 100644
--- a/test-chmtime.c
+++ b/test-chmtime.c
@@ -1,7 +1,7 @@
/*
* This program can either change modification time of the given
* file(s) or just print it. The program does not change atime nor
- * ctime (their values are explicitely preserved).
+ * ctime (their values are explicitly preserved).
*
* The mtime can be changed to an absolute value:
*
diff --git a/transport-helper.c b/transport-helper.c
index 107742891..f82297202 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -171,7 +171,7 @@ static struct child_process *get_helper(struct transport *transport)
} else if (!strcmp(capname, "connect")) {
data->connect = 1;
} else if (mandatory) {
- die("Unknown madatory capability %s. This remote "
+ die("Unknown mandatory capability %s. This remote "
"helper probably needs newer version of Git.\n",
capname);
}
diff --git a/transport.c b/transport.c
index 3846aacb4..08e4fa035 100644
--- a/transport.c
+++ b/transport.c
@@ -918,6 +918,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
if (!remote)
die("No remote provided to transport_get()");
+ ret->got_remote_refs = 0;
ret->remote = remote;
helper = remote->foreign_vcs;
@@ -1079,8 +1080,10 @@ int transport_push(struct transport *transport,
const struct ref *transport_get_remote_refs(struct transport *transport)
{
- if (!transport->remote_refs)
+ if (!transport->got_remote_refs) {
transport->remote_refs = transport->get_refs_list(transport, 0);
+ transport->got_remote_refs = 1;
+ }
return transport->remote_refs;
}
diff --git a/transport.h b/transport.h
index 7cea5cc72..6dd9ae182 100644
--- a/transport.h
+++ b/transport.h
@@ -20,6 +20,12 @@ struct transport {
const struct ref *remote_refs;
/**
+ * Indicates whether we already called get_refs_list(); set by
+ * transport.c::transport_get_remote_refs().
+ */
+ unsigned got_remote_refs : 1;
+
+ /**
* Returns 0 if successful, positive if the option is not
* recognized or is inapplicable, and negative if the option
* is applicable but the value is invalid.
diff --git a/tree-walk.c b/tree-walk.c
index 08796c232..67a9a0c5a 100644
--- a/tree-walk.c
+++ b/tree-walk.c
@@ -441,6 +441,7 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch
if (name[0] == '\0') {
hashcpy(sha1, root);
+ free(tree);
return 0;
}
diff --git a/upload-pack.c b/upload-pack.c
index df151813f..dc464d78b 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -105,12 +105,12 @@ static void show_edge(struct commit *commit)
fprintf(pack_pipe, "-%s\n", sha1_to_hex(commit->object.sha1));
}
-static int do_rev_list(int fd, void *create_full_pack)
+static int do_rev_list(int in, int out, void *create_full_pack)
{
int i;
struct rev_info revs;
- pack_pipe = xfdopen(fd, "w");
+ pack_pipe = xfdopen(out, "w");
init_revisions(&revs, NULL);
revs.tag_objects = 1;
revs.tree_objects = 1;
@@ -162,8 +162,9 @@ static void create_pack_file(void)
int arg = 0;
if (shallow_nr) {
+ memset(&rev_list, 0, sizeof(rev_list));
rev_list.proc = do_rev_list;
- rev_list.data = 0;
+ rev_list.out = -1;
if (start_async(&rev_list))
die("git upload-pack: unable to fork git-rev-list");
argv[arg++] = "pack-objects";
diff --git a/utf8.c b/utf8.c
index ab326ac83..84cfc72e6 100644
--- a/utf8.c
+++ b/utf8.c
@@ -280,22 +280,11 @@ int is_utf8(const char *text)
return 1;
}
-static inline void strbuf_write(struct strbuf *sb, const char *buf, int len)
+static void strbuf_addchars(struct strbuf *sb, int c, size_t n)
{
- if (sb)
- strbuf_insert(sb, sb->len, buf, len);
- else
- fwrite(buf, len, 1, stdout);
-}
-
-static void print_spaces(struct strbuf *buf, int count)
-{
- static const char s[] = " ";
- while (count >= sizeof(s)) {
- strbuf_write(buf, s, sizeof(s) - 1);
- count -= sizeof(s) - 1;
- }
- strbuf_write(buf, s, count);
+ strbuf_grow(sb, n);
+ memset(sb->buf + sb->len, c, n);
+ strbuf_setlen(sb, sb->len + n);
}
static void strbuf_add_indented_text(struct strbuf *buf, const char *text,
@@ -307,8 +296,8 @@ static void strbuf_add_indented_text(struct strbuf *buf, const char *text,
const char *eol = strchrnul(text, '\n');
if (*eol == '\n')
eol++;
- print_spaces(buf, indent);
- strbuf_write(buf, text, eol - text);
+ strbuf_addchars(buf, ' ', indent);
+ strbuf_add(buf, text, eol - text);
text = eol;
indent = indent2;
}
@@ -335,16 +324,21 @@ static size_t display_mode_esc_sequence_len(const char *s)
* consumed (and no extra indent is necessary for the first line).
*/
int strbuf_add_wrapped_text(struct strbuf *buf,
- const char *text, int indent, int indent2, int width)
+ const char *text, int indent1, int indent2, int width)
{
- int w = indent, assume_utf8 = is_utf8(text);
- const char *bol = text, *space = NULL;
+ int indent, w, assume_utf8 = 1;
+ const char *bol, *space, *start = text;
+ size_t orig_len = buf->len;
if (width <= 0) {
- strbuf_add_indented_text(buf, text, indent, indent2);
+ strbuf_add_indented_text(buf, text, indent1, indent2);
return 1;
}
+retry:
+ bol = text;
+ w = indent = indent1;
+ space = NULL;
if (indent < 0) {
w = -indent;
space = text;
@@ -366,8 +360,8 @@ int strbuf_add_wrapped_text(struct strbuf *buf,
if (space)
start = space;
else
- print_spaces(buf, indent);
- strbuf_write(buf, start, text - start);
+ strbuf_addchars(buf, ' ', indent);
+ strbuf_add(buf, start, text - start);
if (!c)
return w;
space = text;
@@ -376,40 +370,41 @@ int strbuf_add_wrapped_text(struct strbuf *buf,
else if (c == '\n') {
space++;
if (*space == '\n') {
- strbuf_write(buf, "\n", 1);
+ strbuf_addch(buf, '\n');
goto new_line;
}
else if (!isalnum(*space))
goto new_line;
else
- strbuf_write(buf, " ", 1);
+ strbuf_addch(buf, ' ');
}
w++;
text++;
}
else {
new_line:
- strbuf_write(buf, "\n", 1);
+ strbuf_addch(buf, '\n');
text = bol = space + isspace(*space);
space = NULL;
w = indent = indent2;
}
continue;
}
- if (assume_utf8)
+ if (assume_utf8) {
w += utf8_width(&text, NULL);
- else {
+ if (!text) {
+ assume_utf8 = 0;
+ text = start;
+ strbuf_setlen(buf, orig_len);
+ goto retry;
+ }
+ } else {
w++;
text++;
}
}
}
-int print_wrapped_text(const char *text, int indent, int indent2, int width)
-{
- return strbuf_add_wrapped_text(NULL, text, indent, indent2, width);
-}
-
int is_encoding_utf8(const char *name)
{
if (!name)
diff --git a/utf8.h b/utf8.h
index c9738d83d..ebc4d2fa8 100644
--- a/utf8.h
+++ b/utf8.h
@@ -8,7 +8,6 @@ int utf8_strwidth(const char *string);
int is_utf8(const char *text);
int is_encoding_utf8(const char *name);
-int print_wrapped_text(const char *text, int indent, int indent2, int len);
int strbuf_add_wrapped_text(struct strbuf *buf,
const char *text, int indent, int indent2, int width);
diff --git a/wrapper.c b/wrapper.c
index 0e3e20a3f..9c71b2124 100644
--- a/wrapper.c
+++ b/wrapper.c
@@ -204,6 +204,16 @@ int xmkstemp(char *template)
return fd;
}
+int xmkstemp_mode(char *template, int mode)
+{
+ int fd;
+
+ fd = git_mkstemp_mode(template, mode);
+ if (fd < 0)
+ die_errno("Unable to create temporary file");
+ return fd;
+}
+
/*
* zlib wrappers to make sure we don't silently miss errors
* at init time.
@@ -267,10 +277,14 @@ int git_inflate(z_streamp strm, int flush)
int odb_mkstemp(char *template, size_t limit, const char *pattern)
{
int fd;
-
+ /*
+ * we let the umask do its job, don't try to be more
+ * restrictive except to remove write permission.
+ */
+ int mode = 0444;
snprintf(template, limit, "%s/%s",
get_object_directory(), pattern);
- fd = mkstemp(template);
+ fd = git_mkstemp_mode(template, mode);
if (0 <= fd)
return fd;
@@ -279,7 +293,7 @@ int odb_mkstemp(char *template, size_t limit, const char *pattern)
snprintf(template, limit, "%s/%s",
get_object_directory(), pattern);
safe_create_leading_directories(template);
- return xmkstemp(template);
+ return xmkstemp_mode(template, mode);
}
int odb_pack_keep(char *name, size_t namesz, unsigned char *sha1)